func (c *Client) MetaNodeByAddr(addr string) *meta.NodeInfo {
	for _, n := range c.data().MetaNodes {
		if n.Host == addr {
			return &n
		}
	}
	return nil
}
MetaNodeByAddr returns the meta node's info.
package meta
import (
	"bytes"
	crand "crypto/rand"
	"crypto/sha256"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"os"
	"path/filepath"
	"sort"
	"sync"
	"time"
	"github.com/influxdata/influxdb"
	"github.com/influxdata/influxdb/logger"
	"github.com/influxdata/influxdb/pkg/file"
	"github.com/influxdata/influxdb/services/meta"
	"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
)
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 *meta.Config) *Client {
	return &Client{
		cacheData: &Data{
			Data: meta.Data{
				ClusterID: 0,
				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) Print() {
	fmt.Printf("%+v\n", c.cacheData)
}
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) ClusterID() uint64 {
	c.mu.RLock()
	defer c.mu.RUnlock()
	return c.cacheData.ClusterID
}
func (c *Client) data() *Data {
	return c.cacheData
}
func (c *Client) DataNode(id uint64) (*meta.NodeInfo, error) {
	c.mu.Lock()
	defer c.mu.Unlock()
	for _, n := range c.data().DataNodes {
		if n.ID == id {
			return &n, nil
		}
	}
	return nil, ErrNodeNotFound
}
func (c *Client) DataNodes() ([]meta.NodeInfo, error) {
	return c.data().DataNodes, nil
}
func (c *Client) CreateDataNode(httpAddr, tcpAddr string) (*meta.NodeInfo, error) {
	c.mu.Lock()
	defer c.mu.Unlock()
	err := c.data().CreateDataNode(httpAddr, tcpAddr)
	if err != nil {
		return nil, err
	}
	n, err := c.DataNodeByTCPHost(tcpAddr)
	if err != nil {
		return nil, err
	}
	if err := c.commit(c.data()); err != nil {
		return nil, err
	}
	return n, nil
}
func (c *Client) DataNodeByHTTPHost(httpAddr string) (*meta.NodeInfo, error) {
	nodes, _ := c.DataNodes()
	for _, n := range nodes {
		if n.Host == httpAddr {
			return &n, nil
		}
	}
	return nil, ErrNodeNotFound
}
func (c *Client) DataNodeByTCPHost(tcpAddr string) (*meta.NodeInfo, error) {
	nodes, _ := c.DataNodes()
	for _, n := range nodes {
		if n.TCPHost == tcpAddr {
			return &n, nil
		}
	}
	return nil, ErrNodeNotFound
}
func (c *Client) DeleteDataNode(id uint64) error {
	c.mu.Lock()
	defer c.mu.Unlock()
	err := c.cacheData.DeleteDataNode(id)
	if err != nil {
		return err
	}
	if err := c.commit(c.cacheData); err != nil {
		return err
	}
	return nil
}
func (c *Client) MetaNodes() ([]meta.NodeInfo, error) {
	return c.data().MetaNodes, nil
}