func (c *Client) User(name string) (User, error) {
	c.mu.RLock()
	defer c.mu.RUnlock()
	for _, u := range c.cacheData.Users {
		if u.Name == name {
			return &u, nil
		}
	}
	return nil, ErrUserNotFound
}
User returns the user with the given name, or ErrUserNotFound.
package meta
import (
	"bytes"
	crand "crypto/rand"
	"crypto/sha256"
	"errors"
	"io"
	"io/ioutil"
	"math/rand"
	"net/http"
	"os"
	"path/filepath"
	"sort"
	"sync"
	"time"
	"github.com/influxdata/influxdb"
	"github.com/influxdata/influxdb/logger"
	"github.com/influxdata/influxql"
	"go.uber.org/zap"
	"golang.org/x/crypto/bcrypt"
)
const (
	SaltBytes = 32
	metaFile = "meta.db"
	ShardGroupDeletedExpiration = -2 * 7 * 24 * time.Hour
)
var (
	ErrServiceUnavailable = errors.New("meta service unavailable")
	ErrService = errors.New("meta service error")
)
type Client struct {
	logger *zap.Logger
	mu        sync.RWMutex
	closing   chan struct{}
	changed   chan struct{}
	cacheData *Data
	authCache map[string]authUser
	path string
	retentionAutoCreate bool
}
type authUser struct {
	bhash string
	salt  []byte
	hash  []byte
}
func NewClient(config *Config) *Client {
	return &Client{
		cacheData: &Data{
			ClusterID: uint64(rand.Int63()),
			Index:     1,
		},
		closing:             make(chan struct{}),
		changed:             make(chan struct{}),
		logger:              zap.NewNop(),
		authCache:           make(map[string]authUser),
		path:                config.Dir,
		retentionAutoCreate: config.RetentionAutoCreate,
	}
}
func (c *Client) Open() error {
	c.mu.Lock()
	defer c.mu.Unlock()
	if err := c.Load(); err != nil {
		return err
	}
	if c.cacheData.Index == 1 {
		if err := snapshot(c.path, c.cacheData); err != nil {
			return err
		}
	}
	return nil
}
func (c *Client) Close() error {
	c.mu.Lock()
	defer c.mu.Unlock()
	if t, ok := http.DefaultTransport.(*http.Transport); ok {
		t.CloseIdleConnections()
	}
	select {
	case <-c.closing:
		return nil
	default:
		close(c.closing)
	}
	return nil
}
func (c *Client) AcquireLease(name string) (*Lease, error) {
	l := Lease{
		Name:       name,
		Expiration: time.Now().Add(DefaultLeaseDuration),
	}
	return &l, nil
}
func (c *Client) ClusterID() uint64 {
	c.mu.RLock()
	defer c.mu.RUnlock()
	return c.cacheData.ClusterID
}
func (c *Client) Database(name string) *DatabaseInfo {
	c.mu.RLock()
	defer c.mu.RUnlock()
	for _, d := range c.cacheData.Databases {
		if d.Name == name {
			return &d
		}
	}
	return nil
}
func (c *Client) Databases() []DatabaseInfo {
	c.mu.RLock()
	defer c.mu.RUnlock()
	dbs := c.cacheData.Databases
	if dbs == nil {
		return []DatabaseInfo{}
	}
	return dbs
}
func (c *Client) CreateDatabase(name string) (*DatabaseInfo, error) {
	c.mu.Lock()
	defer c.mu.Unlock()
	data := c.cacheData.Clone()
	if db := data.Database(name); db != nil {
		return db, nil
	}
	if err := data.CreateDatabase(name); err != nil {
		return nil, err
	}
	if c.retentionAutoCreate {
		rpi := DefaultRetentionPolicyInfo()
		if err := data.CreateRetentionPolicy(name, rpi, true); err != nil {
			return nil, err
		}
	}
	db := data.Database(name)
	if err := c.commit(data); err != nil {
		return nil, err
	}
	return db, nil
}
func (c *Client) CreateDatabaseWithRetentionPolicy(name string, spec *RetentionPolicySpec) (*DatabaseInfo, error) {
	if spec == nil {
		return nil, errors.New("CreateDatabaseWithRetentionPolicy called with nil spec")
	}
	c.mu.Lock()
	defer c.mu.Unlock()
	data := c.cacheData.Clone()
	if spec.Duration != nil && *spec.Duration < MinRetentionPolicyDuration && *spec.Duration != 0 {
		return nil, ErrRetentionPolicyDurationTooLow
	}
	db := data.Database(name)
	if db == nil {
		if err := data.CreateDatabase(name); err != nil {
			return nil, err
		}
		db = data.Database(name)
	}
	rpi := spec.NewRetentionPolicyInfo()
	if len(db.RetentionPolicies) == 0 {
		if err := data.CreateRetentionPolicy(name, rpi, true); err != nil {
			return nil, err
		}
	} else if !spec.Matches(db.RetentionPolicy(rpi.Name)) {
		return nil, ErrRetentionPolicyConflict
	}
	if db.DefaultRetentionPolicy != rpi.Name {
		return nil, ErrRetentionPolicyConflict
	}
	if err := c.commit(data); err != nil {
		return nil, err
	}
	db = data.Database(name)
	return db, nil
}
func (c *Client) DropDatabase(name string) error {
	c.mu.Lock()
	defer c.mu.Unlock()
	data := c.cacheData.Clone()
	if err := data.DropDatabase(name); err != nil {
		return err
	}
	if err := c.commit(data); err != nil {
		return err
	}
	return nil
}
func (c *Client) CreateRetentionPolicy(database string, spec *RetentionPolicySpec, makeDefault bool) (*RetentionPolicyInfo, error) {
	c.mu.Lock()
	defer c.mu.Unlock()
	data := c.cacheData.Clone()
	if spec.Duration != nil && *spec.Duration < MinRetentionPolicyDuration && *spec.Duration != 0 {
		return nil, ErrRetentionPolicyDurationTooLow
	}
	rp := spec.NewRetentionPolicyInfo()
	if err := data.CreateRetentionPolicy(database, rp, makeDefault); err != nil {
		return nil, err
	}
	if err := c.commit(data); err != nil {
		return nil, err
	}
	return rp, nil
}
func (c *Client) RetentionPolicy(database, name string) (rpi *RetentionPolicyInfo, err error) {
	c.mu.RLock()
	defer c.mu.RUnlock()
	db := c.cacheData.Database(database)
	if db == nil {
		return nil, influxdb.ErrDatabaseNotFound(database)
	}
	return db.RetentionPolicy(name), nil
}
func (c *Client) DropRetentionPolicy(database, name string) error {
	c.mu.Lock()
	defer c.mu.Unlock()
	data := c.cacheData.Clone()
	if err := data.DropRetentionPolicy(database, name); err != nil {
		return err
	}
	if err := c.commit(data); err != nil {
		return err
	}
	return nil
}
func (c *Client) UpdateRetentionPolicy(database, name string, rpu *RetentionPolicyUpdate, makeDefault bool) error {
	c.mu.Lock()
	defer c.mu.Unlock()
	data := c.cacheData.Clone()
	if err := data.UpdateRetentionPolicy(database, name, rpu, makeDefault); err != nil {
		return err
	}
	if err := c.commit(data); err != nil {
		return err
	}
	return nil
}
func (c *Client) Users() []UserInfo {
	c.mu.RLock()
	defer c.mu.RUnlock()
	users := c.cacheData.Users
	if users == nil {
		return []UserInfo{}
	}
	return users
}