mirror of
				https://github.com/k3s-io/kubernetes.git
				synced 2025-11-04 07:49:35 +00:00 
			
		
		
		
	Move deps from _workspace/ to vendor/
godep restore pushd $GOPATH/src/github.com/appc/spec git co master popd go get go4.org/errorutil rm -rf Godeps godep save ./... git add vendor git add -f $(git ls-files --other vendor/) git co -- Godeps/LICENSES Godeps/.license_file_state Godeps/OWNERS
This commit is contained in:
		
							
								
								
									
										25
									
								
								vendor/github.com/samuel/go-zookeeper/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								vendor/github.com/samuel/go-zookeeper/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,25 @@
 | 
			
		||||
Copyright (c) 2013, Samuel Stauffer <samuel@descolada.com>
 | 
			
		||||
All rights reserved.
 | 
			
		||||
 | 
			
		||||
Redistribution and use in source and binary forms, with or without
 | 
			
		||||
modification, are permitted provided that the following conditions are met:
 | 
			
		||||
 | 
			
		||||
* Redistributions of source code must retain the above copyright
 | 
			
		||||
  notice, this list of conditions and the following disclaimer.
 | 
			
		||||
* Redistributions in binary form must reproduce the above copyright
 | 
			
		||||
  notice, this list of conditions and the following disclaimer in the
 | 
			
		||||
  documentation and/or other materials provided with the distribution.
 | 
			
		||||
* Neither the name of the author nor the
 | 
			
		||||
  names of its contributors may be used to endorse or promote products
 | 
			
		||||
  derived from this software without specific prior written permission.
 | 
			
		||||
 | 
			
		||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 | 
			
		||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 | 
			
		||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 | 
			
		||||
DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
 | 
			
		||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 | 
			
		||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 | 
			
		||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 | 
			
		||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 | 
			
		||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 | 
			
		||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | 
			
		||||
							
								
								
									
										868
									
								
								vendor/github.com/samuel/go-zookeeper/zk/conn.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										868
									
								
								vendor/github.com/samuel/go-zookeeper/zk/conn.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,868 @@
 | 
			
		||||
// Package zk is a native Go client library for the ZooKeeper orchestration service.
 | 
			
		||||
package zk
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
TODO:
 | 
			
		||||
* make sure a ping response comes back in a reasonable time
 | 
			
		||||
 | 
			
		||||
Possible watcher events:
 | 
			
		||||
* Event{Type: EventNotWatching, State: StateDisconnected, Path: path, Err: err}
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"crypto/rand"
 | 
			
		||||
	"encoding/binary"
 | 
			
		||||
	"errors"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"io"
 | 
			
		||||
	"net"
 | 
			
		||||
	"strconv"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"sync"
 | 
			
		||||
	"sync/atomic"
 | 
			
		||||
	"time"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// ErrNoServer indicates that an operation cannot be completed
 | 
			
		||||
// because attempts to connect to all servers in the list failed.
 | 
			
		||||
var ErrNoServer = errors.New("zk: could not connect to a server")
 | 
			
		||||
 | 
			
		||||
// ErrInvalidPath indicates that an operation was being attempted on
 | 
			
		||||
// an invalid path. (e.g. empty path)
 | 
			
		||||
var ErrInvalidPath = errors.New("zk: invalid path")
 | 
			
		||||
 | 
			
		||||
// DefaultLogger uses the stdlib log package for logging.
 | 
			
		||||
var DefaultLogger Logger = defaultLogger{}
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	bufferSize      = 1536 * 1024
 | 
			
		||||
	eventChanSize   = 6
 | 
			
		||||
	sendChanSize    = 16
 | 
			
		||||
	protectedPrefix = "_c_"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type watchType int
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	watchTypeData  = iota
 | 
			
		||||
	watchTypeExist = iota
 | 
			
		||||
	watchTypeChild = iota
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type watchPathType struct {
 | 
			
		||||
	path  string
 | 
			
		||||
	wType watchType
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type Dialer func(network, address string, timeout time.Duration) (net.Conn, error)
 | 
			
		||||
 | 
			
		||||
// Logger is an interface that can be implemented to provide custom log output.
 | 
			
		||||
type Logger interface {
 | 
			
		||||
	Printf(string, ...interface{})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type Conn struct {
 | 
			
		||||
	lastZxid  int64
 | 
			
		||||
	sessionID int64
 | 
			
		||||
	state     State // must be 32-bit aligned
 | 
			
		||||
	xid       uint32
 | 
			
		||||
	timeout   int32 // session timeout in milliseconds
 | 
			
		||||
	passwd    []byte
 | 
			
		||||
 | 
			
		||||
	dialer          Dialer
 | 
			
		||||
	servers         []string
 | 
			
		||||
	serverIndex     int // remember last server that was tried during connect to round-robin attempts to servers
 | 
			
		||||
	lastServerIndex int // index of the last server that was successfully connected to and authenticated with
 | 
			
		||||
	conn            net.Conn
 | 
			
		||||
	eventChan       chan Event
 | 
			
		||||
	shouldQuit      chan struct{}
 | 
			
		||||
	pingInterval    time.Duration
 | 
			
		||||
	recvTimeout     time.Duration
 | 
			
		||||
	connectTimeout  time.Duration
 | 
			
		||||
 | 
			
		||||
	sendChan     chan *request
 | 
			
		||||
	requests     map[int32]*request // Xid -> pending request
 | 
			
		||||
	requestsLock sync.Mutex
 | 
			
		||||
	watchers     map[watchPathType][]chan Event
 | 
			
		||||
	watchersLock sync.Mutex
 | 
			
		||||
 | 
			
		||||
	// Debug (used by unit tests)
 | 
			
		||||
	reconnectDelay time.Duration
 | 
			
		||||
 | 
			
		||||
	logger Logger
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type request struct {
 | 
			
		||||
	xid        int32
 | 
			
		||||
	opcode     int32
 | 
			
		||||
	pkt        interface{}
 | 
			
		||||
	recvStruct interface{}
 | 
			
		||||
	recvChan   chan response
 | 
			
		||||
 | 
			
		||||
	// Because sending and receiving happen in separate go routines, there's
 | 
			
		||||
	// a possible race condition when creating watches from outside the read
 | 
			
		||||
	// loop. We must ensure that a watcher gets added to the list synchronously
 | 
			
		||||
	// with the response from the server on any request that creates a watch.
 | 
			
		||||
	// In order to not hard code the watch logic for each opcode in the recv
 | 
			
		||||
	// loop the caller can use recvFunc to insert some synchronously code
 | 
			
		||||
	// after a response.
 | 
			
		||||
	recvFunc func(*request, *responseHeader, error)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type response struct {
 | 
			
		||||
	zxid int64
 | 
			
		||||
	err  error
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type Event struct {
 | 
			
		||||
	Type   EventType
 | 
			
		||||
	State  State
 | 
			
		||||
	Path   string // For non-session events, the path of the watched node.
 | 
			
		||||
	Err    error
 | 
			
		||||
	Server string // For connection events
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Connect establishes a new connection to a pool of zookeeper servers
 | 
			
		||||
// using the default net.Dialer. See ConnectWithDialer for further
 | 
			
		||||
// information about session timeout.
 | 
			
		||||
func Connect(servers []string, sessionTimeout time.Duration) (*Conn, <-chan Event, error) {
 | 
			
		||||
	return ConnectWithDialer(servers, sessionTimeout, nil)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ConnectWithDialer establishes a new connection to a pool of zookeeper
 | 
			
		||||
// servers. The provided session timeout sets the amount of time for which
 | 
			
		||||
// a session is considered valid after losing connection to a server. Within
 | 
			
		||||
// the session timeout it's possible to reestablish a connection to a different
 | 
			
		||||
// server and keep the same session. This is means any ephemeral nodes and
 | 
			
		||||
// watches are maintained.
 | 
			
		||||
func ConnectWithDialer(servers []string, sessionTimeout time.Duration, dialer Dialer) (*Conn, <-chan Event, error) {
 | 
			
		||||
	if len(servers) == 0 {
 | 
			
		||||
		return nil, nil, errors.New("zk: server list must not be empty")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	recvTimeout := sessionTimeout * 2 / 3
 | 
			
		||||
 | 
			
		||||
	srvs := make([]string, len(servers))
 | 
			
		||||
 | 
			
		||||
	for i, addr := range servers {
 | 
			
		||||
		if strings.Contains(addr, ":") {
 | 
			
		||||
			srvs[i] = addr
 | 
			
		||||
		} else {
 | 
			
		||||
			srvs[i] = addr + ":" + strconv.Itoa(DefaultPort)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Randomize the order of the servers to avoid creating hotspots
 | 
			
		||||
	stringShuffle(srvs)
 | 
			
		||||
 | 
			
		||||
	ec := make(chan Event, eventChanSize)
 | 
			
		||||
	if dialer == nil {
 | 
			
		||||
		dialer = net.DialTimeout
 | 
			
		||||
	}
 | 
			
		||||
	conn := Conn{
 | 
			
		||||
		dialer:          dialer,
 | 
			
		||||
		servers:         srvs,
 | 
			
		||||
		serverIndex:     0,
 | 
			
		||||
		lastServerIndex: -1,
 | 
			
		||||
		conn:            nil,
 | 
			
		||||
		state:           StateDisconnected,
 | 
			
		||||
		eventChan:       ec,
 | 
			
		||||
		shouldQuit:      make(chan struct{}),
 | 
			
		||||
		recvTimeout:     recvTimeout,
 | 
			
		||||
		pingInterval:    recvTimeout / 2,
 | 
			
		||||
		connectTimeout:  1 * time.Second,
 | 
			
		||||
		sendChan:        make(chan *request, sendChanSize),
 | 
			
		||||
		requests:        make(map[int32]*request),
 | 
			
		||||
		watchers:        make(map[watchPathType][]chan Event),
 | 
			
		||||
		passwd:          emptyPassword,
 | 
			
		||||
		timeout:         int32(sessionTimeout.Nanoseconds() / 1e6),
 | 
			
		||||
		logger:          DefaultLogger,
 | 
			
		||||
 | 
			
		||||
		// Debug
 | 
			
		||||
		reconnectDelay: 0,
 | 
			
		||||
	}
 | 
			
		||||
	go func() {
 | 
			
		||||
		conn.loop()
 | 
			
		||||
		conn.flushRequests(ErrClosing)
 | 
			
		||||
		conn.invalidateWatches(ErrClosing)
 | 
			
		||||
		close(conn.eventChan)
 | 
			
		||||
	}()
 | 
			
		||||
	return &conn, ec, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *Conn) Close() {
 | 
			
		||||
	close(c.shouldQuit)
 | 
			
		||||
 | 
			
		||||
	select {
 | 
			
		||||
	case <-c.queueRequest(opClose, &closeRequest{}, &closeResponse{}, nil):
 | 
			
		||||
	case <-time.After(time.Second):
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// States returns the current state of the connection.
 | 
			
		||||
func (c *Conn) State() State {
 | 
			
		||||
	return State(atomic.LoadInt32((*int32)(&c.state)))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SetLogger sets the logger to be used for printing errors.
 | 
			
		||||
// Logger is an interface provided by this package.
 | 
			
		||||
func (c *Conn) SetLogger(l Logger) {
 | 
			
		||||
	c.logger = l
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *Conn) setState(state State) {
 | 
			
		||||
	atomic.StoreInt32((*int32)(&c.state), int32(state))
 | 
			
		||||
	select {
 | 
			
		||||
	case c.eventChan <- Event{Type: EventSession, State: state, Server: c.servers[c.serverIndex]}:
 | 
			
		||||
	default:
 | 
			
		||||
		// panic("zk: event channel full - it must be monitored and never allowed to be full")
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *Conn) connect() error {
 | 
			
		||||
	c.setState(StateConnecting)
 | 
			
		||||
	for {
 | 
			
		||||
		c.serverIndex = (c.serverIndex + 1) % len(c.servers)
 | 
			
		||||
		if c.serverIndex == c.lastServerIndex {
 | 
			
		||||
			c.flushUnsentRequests(ErrNoServer)
 | 
			
		||||
			select {
 | 
			
		||||
			case <-time.After(time.Second):
 | 
			
		||||
				// pass
 | 
			
		||||
			case <-c.shouldQuit:
 | 
			
		||||
				c.setState(StateDisconnected)
 | 
			
		||||
				c.flushUnsentRequests(ErrClosing)
 | 
			
		||||
				return ErrClosing
 | 
			
		||||
			}
 | 
			
		||||
		} else if c.lastServerIndex < 0 {
 | 
			
		||||
			// lastServerIndex defaults to -1 to avoid a delay on the initial connect
 | 
			
		||||
			c.lastServerIndex = 0
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		zkConn, err := c.dialer("tcp", c.servers[c.serverIndex], c.connectTimeout)
 | 
			
		||||
		if err == nil {
 | 
			
		||||
			c.conn = zkConn
 | 
			
		||||
			c.setState(StateConnected)
 | 
			
		||||
			return nil
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		c.logger.Printf("Failed to connect to %s: %+v", c.servers[c.serverIndex], err)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *Conn) loop() {
 | 
			
		||||
	for {
 | 
			
		||||
		if err := c.connect(); err != nil {
 | 
			
		||||
			// c.Close() was called
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		err := c.authenticate()
 | 
			
		||||
		switch {
 | 
			
		||||
		case err == ErrSessionExpired:
 | 
			
		||||
			c.invalidateWatches(err)
 | 
			
		||||
		case err != nil && c.conn != nil:
 | 
			
		||||
			c.conn.Close()
 | 
			
		||||
		case err == nil:
 | 
			
		||||
			c.lastServerIndex = c.serverIndex
 | 
			
		||||
			closeChan := make(chan struct{}) // channel to tell send loop stop
 | 
			
		||||
			var wg sync.WaitGroup
 | 
			
		||||
 | 
			
		||||
			wg.Add(1)
 | 
			
		||||
			go func() {
 | 
			
		||||
				c.sendLoop(c.conn, closeChan)
 | 
			
		||||
				c.conn.Close() // causes recv loop to EOF/exit
 | 
			
		||||
				wg.Done()
 | 
			
		||||
			}()
 | 
			
		||||
 | 
			
		||||
			wg.Add(1)
 | 
			
		||||
			go func() {
 | 
			
		||||
				err = c.recvLoop(c.conn)
 | 
			
		||||
				if err == nil {
 | 
			
		||||
					panic("zk: recvLoop should never return nil error")
 | 
			
		||||
				}
 | 
			
		||||
				close(closeChan) // tell send loop to exit
 | 
			
		||||
				wg.Done()
 | 
			
		||||
			}()
 | 
			
		||||
 | 
			
		||||
			wg.Wait()
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		c.setState(StateDisconnected)
 | 
			
		||||
 | 
			
		||||
		// Yeesh
 | 
			
		||||
		if err != io.EOF && err != ErrSessionExpired && !strings.Contains(err.Error(), "use of closed network connection") {
 | 
			
		||||
			c.logger.Printf(err.Error())
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		select {
 | 
			
		||||
		case <-c.shouldQuit:
 | 
			
		||||
			c.flushRequests(ErrClosing)
 | 
			
		||||
			return
 | 
			
		||||
		default:
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if err != ErrSessionExpired {
 | 
			
		||||
			err = ErrConnectionClosed
 | 
			
		||||
		}
 | 
			
		||||
		c.flushRequests(err)
 | 
			
		||||
 | 
			
		||||
		if c.reconnectDelay > 0 {
 | 
			
		||||
			select {
 | 
			
		||||
			case <-c.shouldQuit:
 | 
			
		||||
				return
 | 
			
		||||
			case <-time.After(c.reconnectDelay):
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *Conn) flushUnsentRequests(err error) {
 | 
			
		||||
	for {
 | 
			
		||||
		select {
 | 
			
		||||
		default:
 | 
			
		||||
			return
 | 
			
		||||
		case req := <-c.sendChan:
 | 
			
		||||
			req.recvChan <- response{-1, err}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Send error to all pending requests and clear request map
 | 
			
		||||
func (c *Conn) flushRequests(err error) {
 | 
			
		||||
	c.requestsLock.Lock()
 | 
			
		||||
	for _, req := range c.requests {
 | 
			
		||||
		req.recvChan <- response{-1, err}
 | 
			
		||||
	}
 | 
			
		||||
	c.requests = make(map[int32]*request)
 | 
			
		||||
	c.requestsLock.Unlock()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Send error to all watchers and clear watchers map
 | 
			
		||||
func (c *Conn) invalidateWatches(err error) {
 | 
			
		||||
	c.watchersLock.Lock()
 | 
			
		||||
	defer c.watchersLock.Unlock()
 | 
			
		||||
 | 
			
		||||
	if len(c.watchers) >= 0 {
 | 
			
		||||
		for pathType, watchers := range c.watchers {
 | 
			
		||||
			ev := Event{Type: EventNotWatching, State: StateDisconnected, Path: pathType.path, Err: err}
 | 
			
		||||
			for _, ch := range watchers {
 | 
			
		||||
				ch <- ev
 | 
			
		||||
				close(ch)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		c.watchers = make(map[watchPathType][]chan Event)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *Conn) sendSetWatches() {
 | 
			
		||||
	c.watchersLock.Lock()
 | 
			
		||||
	defer c.watchersLock.Unlock()
 | 
			
		||||
 | 
			
		||||
	if len(c.watchers) == 0 {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	req := &setWatchesRequest{
 | 
			
		||||
		RelativeZxid: c.lastZxid,
 | 
			
		||||
		DataWatches:  make([]string, 0),
 | 
			
		||||
		ExistWatches: make([]string, 0),
 | 
			
		||||
		ChildWatches: make([]string, 0),
 | 
			
		||||
	}
 | 
			
		||||
	n := 0
 | 
			
		||||
	for pathType, watchers := range c.watchers {
 | 
			
		||||
		if len(watchers) == 0 {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		switch pathType.wType {
 | 
			
		||||
		case watchTypeData:
 | 
			
		||||
			req.DataWatches = append(req.DataWatches, pathType.path)
 | 
			
		||||
		case watchTypeExist:
 | 
			
		||||
			req.ExistWatches = append(req.ExistWatches, pathType.path)
 | 
			
		||||
		case watchTypeChild:
 | 
			
		||||
			req.ChildWatches = append(req.ChildWatches, pathType.path)
 | 
			
		||||
		}
 | 
			
		||||
		n++
 | 
			
		||||
	}
 | 
			
		||||
	if n == 0 {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	go func() {
 | 
			
		||||
		res := &setWatchesResponse{}
 | 
			
		||||
		_, err := c.request(opSetWatches, req, res, nil)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			c.logger.Printf("Failed to set previous watches: %s", err.Error())
 | 
			
		||||
		}
 | 
			
		||||
	}()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *Conn) authenticate() error {
 | 
			
		||||
	buf := make([]byte, 256)
 | 
			
		||||
 | 
			
		||||
	// connect request
 | 
			
		||||
 | 
			
		||||
	n, err := encodePacket(buf[4:], &connectRequest{
 | 
			
		||||
		ProtocolVersion: protocolVersion,
 | 
			
		||||
		LastZxidSeen:    c.lastZxid,
 | 
			
		||||
		TimeOut:         c.timeout,
 | 
			
		||||
		SessionID:       c.sessionID,
 | 
			
		||||
		Passwd:          c.passwd,
 | 
			
		||||
	})
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	binary.BigEndian.PutUint32(buf[:4], uint32(n))
 | 
			
		||||
 | 
			
		||||
	c.conn.SetWriteDeadline(time.Now().Add(c.recvTimeout * 10))
 | 
			
		||||
	_, err = c.conn.Write(buf[:n+4])
 | 
			
		||||
	c.conn.SetWriteDeadline(time.Time{})
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	c.sendSetWatches()
 | 
			
		||||
 | 
			
		||||
	// connect response
 | 
			
		||||
 | 
			
		||||
	// package length
 | 
			
		||||
	c.conn.SetReadDeadline(time.Now().Add(c.recvTimeout * 10))
 | 
			
		||||
	_, err = io.ReadFull(c.conn, buf[:4])
 | 
			
		||||
	c.conn.SetReadDeadline(time.Time{})
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		// Sometimes zookeeper just drops connection on invalid session data,
 | 
			
		||||
		// we prefer to drop session and start from scratch when that event
 | 
			
		||||
		// occurs instead of dropping into loop of connect/disconnect attempts
 | 
			
		||||
		c.sessionID = 0
 | 
			
		||||
		c.passwd = emptyPassword
 | 
			
		||||
		c.lastZxid = 0
 | 
			
		||||
		c.setState(StateExpired)
 | 
			
		||||
		return ErrSessionExpired
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	blen := int(binary.BigEndian.Uint32(buf[:4]))
 | 
			
		||||
	if cap(buf) < blen {
 | 
			
		||||
		buf = make([]byte, blen)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	_, err = io.ReadFull(c.conn, buf[:blen])
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	r := connectResponse{}
 | 
			
		||||
	_, err = decodePacket(buf[:blen], &r)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	if r.SessionID == 0 {
 | 
			
		||||
		c.sessionID = 0
 | 
			
		||||
		c.passwd = emptyPassword
 | 
			
		||||
		c.lastZxid = 0
 | 
			
		||||
		c.setState(StateExpired)
 | 
			
		||||
		return ErrSessionExpired
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	c.timeout = r.TimeOut
 | 
			
		||||
	c.sessionID = r.SessionID
 | 
			
		||||
	c.passwd = r.Passwd
 | 
			
		||||
	c.setState(StateHasSession)
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *Conn) sendLoop(conn net.Conn, closeChan <-chan struct{}) error {
 | 
			
		||||
	pingTicker := time.NewTicker(c.pingInterval)
 | 
			
		||||
	defer pingTicker.Stop()
 | 
			
		||||
 | 
			
		||||
	buf := make([]byte, bufferSize)
 | 
			
		||||
	for {
 | 
			
		||||
		select {
 | 
			
		||||
		case req := <-c.sendChan:
 | 
			
		||||
			header := &requestHeader{req.xid, req.opcode}
 | 
			
		||||
			n, err := encodePacket(buf[4:], header)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				req.recvChan <- response{-1, err}
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			n2, err := encodePacket(buf[4+n:], req.pkt)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				req.recvChan <- response{-1, err}
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			n += n2
 | 
			
		||||
 | 
			
		||||
			binary.BigEndian.PutUint32(buf[:4], uint32(n))
 | 
			
		||||
 | 
			
		||||
			c.requestsLock.Lock()
 | 
			
		||||
			select {
 | 
			
		||||
			case <-closeChan:
 | 
			
		||||
				req.recvChan <- response{-1, ErrConnectionClosed}
 | 
			
		||||
				c.requestsLock.Unlock()
 | 
			
		||||
				return ErrConnectionClosed
 | 
			
		||||
			default:
 | 
			
		||||
			}
 | 
			
		||||
			c.requests[req.xid] = req
 | 
			
		||||
			c.requestsLock.Unlock()
 | 
			
		||||
 | 
			
		||||
			conn.SetWriteDeadline(time.Now().Add(c.recvTimeout))
 | 
			
		||||
			_, err = conn.Write(buf[:n+4])
 | 
			
		||||
			conn.SetWriteDeadline(time.Time{})
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				req.recvChan <- response{-1, err}
 | 
			
		||||
				conn.Close()
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
		case <-pingTicker.C:
 | 
			
		||||
			n, err := encodePacket(buf[4:], &requestHeader{Xid: -2, Opcode: opPing})
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				panic("zk: opPing should never fail to serialize")
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			binary.BigEndian.PutUint32(buf[:4], uint32(n))
 | 
			
		||||
 | 
			
		||||
			conn.SetWriteDeadline(time.Now().Add(c.recvTimeout))
 | 
			
		||||
			_, err = conn.Write(buf[:n+4])
 | 
			
		||||
			conn.SetWriteDeadline(time.Time{})
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				conn.Close()
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
		case <-closeChan:
 | 
			
		||||
			return nil
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *Conn) recvLoop(conn net.Conn) error {
 | 
			
		||||
	buf := make([]byte, bufferSize)
 | 
			
		||||
	for {
 | 
			
		||||
		// package length
 | 
			
		||||
		conn.SetReadDeadline(time.Now().Add(c.recvTimeout))
 | 
			
		||||
		_, err := io.ReadFull(conn, buf[:4])
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		blen := int(binary.BigEndian.Uint32(buf[:4]))
 | 
			
		||||
		if cap(buf) < blen {
 | 
			
		||||
			buf = make([]byte, blen)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		_, err = io.ReadFull(conn, buf[:blen])
 | 
			
		||||
		conn.SetReadDeadline(time.Time{})
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		res := responseHeader{}
 | 
			
		||||
		_, err = decodePacket(buf[:16], &res)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if res.Xid == -1 {
 | 
			
		||||
			res := &watcherEvent{}
 | 
			
		||||
			_, err := decodePacket(buf[16:16+blen], res)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
			ev := Event{
 | 
			
		||||
				Type:  res.Type,
 | 
			
		||||
				State: res.State,
 | 
			
		||||
				Path:  res.Path,
 | 
			
		||||
				Err:   nil,
 | 
			
		||||
			}
 | 
			
		||||
			select {
 | 
			
		||||
			case c.eventChan <- ev:
 | 
			
		||||
			default:
 | 
			
		||||
			}
 | 
			
		||||
			wTypes := make([]watchType, 0, 2)
 | 
			
		||||
			switch res.Type {
 | 
			
		||||
			case EventNodeCreated:
 | 
			
		||||
				wTypes = append(wTypes, watchTypeExist)
 | 
			
		||||
			case EventNodeDeleted, EventNodeDataChanged:
 | 
			
		||||
				wTypes = append(wTypes, watchTypeExist, watchTypeData, watchTypeChild)
 | 
			
		||||
			case EventNodeChildrenChanged:
 | 
			
		||||
				wTypes = append(wTypes, watchTypeChild)
 | 
			
		||||
			}
 | 
			
		||||
			c.watchersLock.Lock()
 | 
			
		||||
			for _, t := range wTypes {
 | 
			
		||||
				wpt := watchPathType{res.Path, t}
 | 
			
		||||
				if watchers := c.watchers[wpt]; watchers != nil && len(watchers) > 0 {
 | 
			
		||||
					for _, ch := range watchers {
 | 
			
		||||
						ch <- ev
 | 
			
		||||
						close(ch)
 | 
			
		||||
					}
 | 
			
		||||
					delete(c.watchers, wpt)
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			c.watchersLock.Unlock()
 | 
			
		||||
		} else if res.Xid == -2 {
 | 
			
		||||
			// Ping response. Ignore.
 | 
			
		||||
		} else if res.Xid < 0 {
 | 
			
		||||
			c.logger.Printf("Xid < 0 (%d) but not ping or watcher event", res.Xid)
 | 
			
		||||
		} else {
 | 
			
		||||
			if res.Zxid > 0 {
 | 
			
		||||
				c.lastZxid = res.Zxid
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			c.requestsLock.Lock()
 | 
			
		||||
			req, ok := c.requests[res.Xid]
 | 
			
		||||
			if ok {
 | 
			
		||||
				delete(c.requests, res.Xid)
 | 
			
		||||
			}
 | 
			
		||||
			c.requestsLock.Unlock()
 | 
			
		||||
 | 
			
		||||
			if !ok {
 | 
			
		||||
				c.logger.Printf("Response for unknown request with xid %d", res.Xid)
 | 
			
		||||
			} else {
 | 
			
		||||
				if res.Err != 0 {
 | 
			
		||||
					err = res.Err.toError()
 | 
			
		||||
				} else {
 | 
			
		||||
					_, err = decodePacket(buf[16:16+blen], req.recvStruct)
 | 
			
		||||
				}
 | 
			
		||||
				if req.recvFunc != nil {
 | 
			
		||||
					req.recvFunc(req, &res, err)
 | 
			
		||||
				}
 | 
			
		||||
				req.recvChan <- response{res.Zxid, err}
 | 
			
		||||
				if req.opcode == opClose {
 | 
			
		||||
					return io.EOF
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *Conn) nextXid() int32 {
 | 
			
		||||
	return int32(atomic.AddUint32(&c.xid, 1) & 0x7fffffff)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *Conn) addWatcher(path string, watchType watchType) <-chan Event {
 | 
			
		||||
	c.watchersLock.Lock()
 | 
			
		||||
	defer c.watchersLock.Unlock()
 | 
			
		||||
 | 
			
		||||
	ch := make(chan Event, 1)
 | 
			
		||||
	wpt := watchPathType{path, watchType}
 | 
			
		||||
	c.watchers[wpt] = append(c.watchers[wpt], ch)
 | 
			
		||||
	return ch
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *Conn) queueRequest(opcode int32, req interface{}, res interface{}, recvFunc func(*request, *responseHeader, error)) <-chan response {
 | 
			
		||||
	rq := &request{
 | 
			
		||||
		xid:        c.nextXid(),
 | 
			
		||||
		opcode:     opcode,
 | 
			
		||||
		pkt:        req,
 | 
			
		||||
		recvStruct: res,
 | 
			
		||||
		recvChan:   make(chan response, 1),
 | 
			
		||||
		recvFunc:   recvFunc,
 | 
			
		||||
	}
 | 
			
		||||
	c.sendChan <- rq
 | 
			
		||||
	return rq.recvChan
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *Conn) request(opcode int32, req interface{}, res interface{}, recvFunc func(*request, *responseHeader, error)) (int64, error) {
 | 
			
		||||
	r := <-c.queueRequest(opcode, req, res, recvFunc)
 | 
			
		||||
	return r.zxid, r.err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *Conn) AddAuth(scheme string, auth []byte) error {
 | 
			
		||||
	_, err := c.request(opSetAuth, &setAuthRequest{Type: 0, Scheme: scheme, Auth: auth}, &setAuthResponse{}, nil)
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *Conn) Children(path string) ([]string, *Stat, error) {
 | 
			
		||||
	res := &getChildren2Response{}
 | 
			
		||||
	_, err := c.request(opGetChildren2, &getChildren2Request{Path: path, Watch: false}, res, nil)
 | 
			
		||||
	return res.Children, &res.Stat, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *Conn) ChildrenW(path string) ([]string, *Stat, <-chan Event, error) {
 | 
			
		||||
	var ech <-chan Event
 | 
			
		||||
	res := &getChildren2Response{}
 | 
			
		||||
	_, err := c.request(opGetChildren2, &getChildren2Request{Path: path, Watch: true}, res, func(req *request, res *responseHeader, err error) {
 | 
			
		||||
		if err == nil {
 | 
			
		||||
			ech = c.addWatcher(path, watchTypeChild)
 | 
			
		||||
		}
 | 
			
		||||
	})
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, nil, nil, err
 | 
			
		||||
	}
 | 
			
		||||
	return res.Children, &res.Stat, ech, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *Conn) Get(path string) ([]byte, *Stat, error) {
 | 
			
		||||
	res := &getDataResponse{}
 | 
			
		||||
	_, err := c.request(opGetData, &getDataRequest{Path: path, Watch: false}, res, nil)
 | 
			
		||||
	return res.Data, &res.Stat, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetW returns the contents of a znode and sets a watch
 | 
			
		||||
func (c *Conn) GetW(path string) ([]byte, *Stat, <-chan Event, error) {
 | 
			
		||||
	var ech <-chan Event
 | 
			
		||||
	res := &getDataResponse{}
 | 
			
		||||
	_, err := c.request(opGetData, &getDataRequest{Path: path, Watch: true}, res, func(req *request, res *responseHeader, err error) {
 | 
			
		||||
		if err == nil {
 | 
			
		||||
			ech = c.addWatcher(path, watchTypeData)
 | 
			
		||||
		}
 | 
			
		||||
	})
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, nil, nil, err
 | 
			
		||||
	}
 | 
			
		||||
	return res.Data, &res.Stat, ech, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *Conn) Set(path string, data []byte, version int32) (*Stat, error) {
 | 
			
		||||
	if path == "" {
 | 
			
		||||
		return nil, ErrInvalidPath
 | 
			
		||||
	}
 | 
			
		||||
	res := &setDataResponse{}
 | 
			
		||||
	_, err := c.request(opSetData, &SetDataRequest{path, data, version}, res, nil)
 | 
			
		||||
	return &res.Stat, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *Conn) Create(path string, data []byte, flags int32, acl []ACL) (string, error) {
 | 
			
		||||
	res := &createResponse{}
 | 
			
		||||
	_, err := c.request(opCreate, &CreateRequest{path, data, acl, flags}, res, nil)
 | 
			
		||||
	return res.Path, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// CreateProtectedEphemeralSequential fixes a race condition if the server crashes
 | 
			
		||||
// after it creates the node. On reconnect the session may still be valid so the
 | 
			
		||||
// ephemeral node still exists. Therefore, on reconnect we need to check if a node
 | 
			
		||||
// with a GUID generated on create exists.
 | 
			
		||||
func (c *Conn) CreateProtectedEphemeralSequential(path string, data []byte, acl []ACL) (string, error) {
 | 
			
		||||
	var guid [16]byte
 | 
			
		||||
	_, err := io.ReadFull(rand.Reader, guid[:16])
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return "", err
 | 
			
		||||
	}
 | 
			
		||||
	guidStr := fmt.Sprintf("%x", guid)
 | 
			
		||||
 | 
			
		||||
	parts := strings.Split(path, "/")
 | 
			
		||||
	parts[len(parts)-1] = fmt.Sprintf("%s%s-%s", protectedPrefix, guidStr, parts[len(parts)-1])
 | 
			
		||||
	rootPath := strings.Join(parts[:len(parts)-1], "/")
 | 
			
		||||
	protectedPath := strings.Join(parts, "/")
 | 
			
		||||
 | 
			
		||||
	var newPath string
 | 
			
		||||
	for i := 0; i < 3; i++ {
 | 
			
		||||
		newPath, err = c.Create(protectedPath, data, FlagEphemeral|FlagSequence, acl)
 | 
			
		||||
		switch err {
 | 
			
		||||
		case ErrSessionExpired:
 | 
			
		||||
			// No need to search for the node since it can't exist. Just try again.
 | 
			
		||||
		case ErrConnectionClosed:
 | 
			
		||||
			children, _, err := c.Children(rootPath)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return "", err
 | 
			
		||||
			}
 | 
			
		||||
			for _, p := range children {
 | 
			
		||||
				parts := strings.Split(p, "/")
 | 
			
		||||
				if pth := parts[len(parts)-1]; strings.HasPrefix(pth, protectedPrefix) {
 | 
			
		||||
					if g := pth[len(protectedPrefix) : len(protectedPrefix)+32]; g == guidStr {
 | 
			
		||||
						return rootPath + "/" + p, nil
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		case nil:
 | 
			
		||||
			return newPath, nil
 | 
			
		||||
		default:
 | 
			
		||||
			return "", err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return "", err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *Conn) Delete(path string, version int32) error {
 | 
			
		||||
	_, err := c.request(opDelete, &DeleteRequest{path, version}, &deleteResponse{}, nil)
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *Conn) Exists(path string) (bool, *Stat, error) {
 | 
			
		||||
	res := &existsResponse{}
 | 
			
		||||
	_, err := c.request(opExists, &existsRequest{Path: path, Watch: false}, res, nil)
 | 
			
		||||
	exists := true
 | 
			
		||||
	if err == ErrNoNode {
 | 
			
		||||
		exists = false
 | 
			
		||||
		err = nil
 | 
			
		||||
	}
 | 
			
		||||
	return exists, &res.Stat, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *Conn) ExistsW(path string) (bool, *Stat, <-chan Event, error) {
 | 
			
		||||
	var ech <-chan Event
 | 
			
		||||
	res := &existsResponse{}
 | 
			
		||||
	_, err := c.request(opExists, &existsRequest{Path: path, Watch: true}, res, func(req *request, res *responseHeader, err error) {
 | 
			
		||||
		if err == nil {
 | 
			
		||||
			ech = c.addWatcher(path, watchTypeData)
 | 
			
		||||
		} else if err == ErrNoNode {
 | 
			
		||||
			ech = c.addWatcher(path, watchTypeExist)
 | 
			
		||||
		}
 | 
			
		||||
	})
 | 
			
		||||
	exists := true
 | 
			
		||||
	if err == ErrNoNode {
 | 
			
		||||
		exists = false
 | 
			
		||||
		err = nil
 | 
			
		||||
	}
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return false, nil, nil, err
 | 
			
		||||
	}
 | 
			
		||||
	return exists, &res.Stat, ech, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *Conn) GetACL(path string) ([]ACL, *Stat, error) {
 | 
			
		||||
	res := &getAclResponse{}
 | 
			
		||||
	_, err := c.request(opGetAcl, &getAclRequest{Path: path}, res, nil)
 | 
			
		||||
	return res.Acl, &res.Stat, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *Conn) SetACL(path string, acl []ACL, version int32) (*Stat, error) {
 | 
			
		||||
	res := &setAclResponse{}
 | 
			
		||||
	_, err := c.request(opSetAcl, &setAclRequest{Path: path, Acl: acl, Version: version}, res, nil)
 | 
			
		||||
	return &res.Stat, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *Conn) Sync(path string) (string, error) {
 | 
			
		||||
	res := &syncResponse{}
 | 
			
		||||
	_, err := c.request(opSync, &syncRequest{Path: path}, res, nil)
 | 
			
		||||
	return res.Path, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type MultiResponse struct {
 | 
			
		||||
	Stat   *Stat
 | 
			
		||||
	String string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Multi executes multiple ZooKeeper operations or none of them. The provided
 | 
			
		||||
// ops must be one of *CreateRequest, *DeleteRequest, *SetDataRequest, or
 | 
			
		||||
// *CheckVersionRequest.
 | 
			
		||||
func (c *Conn) Multi(ops ...interface{}) ([]MultiResponse, error) {
 | 
			
		||||
	req := &multiRequest{
 | 
			
		||||
		Ops:        make([]multiRequestOp, 0, len(ops)),
 | 
			
		||||
		DoneHeader: multiHeader{Type: -1, Done: true, Err: -1},
 | 
			
		||||
	}
 | 
			
		||||
	for _, op := range ops {
 | 
			
		||||
		var opCode int32
 | 
			
		||||
		switch op.(type) {
 | 
			
		||||
		case *CreateRequest:
 | 
			
		||||
			opCode = opCreate
 | 
			
		||||
		case *SetDataRequest:
 | 
			
		||||
			opCode = opSetData
 | 
			
		||||
		case *DeleteRequest:
 | 
			
		||||
			opCode = opDelete
 | 
			
		||||
		case *CheckVersionRequest:
 | 
			
		||||
			opCode = opCheck
 | 
			
		||||
		default:
 | 
			
		||||
			return nil, fmt.Errorf("uknown operation type %T", op)
 | 
			
		||||
		}
 | 
			
		||||
		req.Ops = append(req.Ops, multiRequestOp{multiHeader{opCode, false, -1}, op})
 | 
			
		||||
	}
 | 
			
		||||
	res := &multiResponse{}
 | 
			
		||||
	_, err := c.request(opMulti, req, res, nil)
 | 
			
		||||
	mr := make([]MultiResponse, len(res.Ops))
 | 
			
		||||
	for i, op := range res.Ops {
 | 
			
		||||
		mr[i] = MultiResponse{Stat: op.Stat, String: op.String}
 | 
			
		||||
	}
 | 
			
		||||
	return mr, err
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										240
									
								
								vendor/github.com/samuel/go-zookeeper/zk/constants.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										240
									
								
								vendor/github.com/samuel/go-zookeeper/zk/constants.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,240 @@
 | 
			
		||||
package zk
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"errors"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	protocolVersion = 0
 | 
			
		||||
 | 
			
		||||
	DefaultPort = 2181
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	opNotify       = 0
 | 
			
		||||
	opCreate       = 1
 | 
			
		||||
	opDelete       = 2
 | 
			
		||||
	opExists       = 3
 | 
			
		||||
	opGetData      = 4
 | 
			
		||||
	opSetData      = 5
 | 
			
		||||
	opGetAcl       = 6
 | 
			
		||||
	opSetAcl       = 7
 | 
			
		||||
	opGetChildren  = 8
 | 
			
		||||
	opSync         = 9
 | 
			
		||||
	opPing         = 11
 | 
			
		||||
	opGetChildren2 = 12
 | 
			
		||||
	opCheck        = 13
 | 
			
		||||
	opMulti        = 14
 | 
			
		||||
	opClose        = -11
 | 
			
		||||
	opSetAuth      = 100
 | 
			
		||||
	opSetWatches   = 101
 | 
			
		||||
	// Not in protocol, used internally
 | 
			
		||||
	opWatcherEvent = -2
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	EventNodeCreated         = EventType(1)
 | 
			
		||||
	EventNodeDeleted         = EventType(2)
 | 
			
		||||
	EventNodeDataChanged     = EventType(3)
 | 
			
		||||
	EventNodeChildrenChanged = EventType(4)
 | 
			
		||||
 | 
			
		||||
	EventSession     = EventType(-1)
 | 
			
		||||
	EventNotWatching = EventType(-2)
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	eventNames = map[EventType]string{
 | 
			
		||||
		EventNodeCreated:         "EventNodeCreated",
 | 
			
		||||
		EventNodeDeleted:         "EventNodeDeleted",
 | 
			
		||||
		EventNodeDataChanged:     "EventNodeDataChanged",
 | 
			
		||||
		EventNodeChildrenChanged: "EventNodeChildrenChanged",
 | 
			
		||||
		EventSession:             "EventSession",
 | 
			
		||||
		EventNotWatching:         "EventNotWatching",
 | 
			
		||||
	}
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	StateUnknown           = State(-1)
 | 
			
		||||
	StateDisconnected      = State(0)
 | 
			
		||||
	StateConnecting        = State(1)
 | 
			
		||||
	StateAuthFailed        = State(4)
 | 
			
		||||
	StateConnectedReadOnly = State(5)
 | 
			
		||||
	StateSaslAuthenticated = State(6)
 | 
			
		||||
	StateExpired           = State(-112)
 | 
			
		||||
	// StateAuthFailed        = State(-113)
 | 
			
		||||
 | 
			
		||||
	StateConnected  = State(100)
 | 
			
		||||
	StateHasSession = State(101)
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	FlagEphemeral = 1
 | 
			
		||||
	FlagSequence  = 2
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	stateNames = map[State]string{
 | 
			
		||||
		StateUnknown:           "StateUnknown",
 | 
			
		||||
		StateDisconnected:      "StateDisconnected",
 | 
			
		||||
		StateConnectedReadOnly: "StateConnectedReadOnly",
 | 
			
		||||
		StateSaslAuthenticated: "StateSaslAuthenticated",
 | 
			
		||||
		StateExpired:           "StateExpired",
 | 
			
		||||
		StateAuthFailed:        "StateAuthFailed",
 | 
			
		||||
		StateConnecting:        "StateConnecting",
 | 
			
		||||
		StateConnected:         "StateConnected",
 | 
			
		||||
		StateHasSession:        "StateHasSession",
 | 
			
		||||
	}
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type State int32
 | 
			
		||||
 | 
			
		||||
func (s State) String() string {
 | 
			
		||||
	if name := stateNames[s]; name != "" {
 | 
			
		||||
		return name
 | 
			
		||||
	}
 | 
			
		||||
	return "Unknown"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type ErrCode int32
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	ErrConnectionClosed        = errors.New("zk: connection closed")
 | 
			
		||||
	ErrUnknown                 = errors.New("zk: unknown error")
 | 
			
		||||
	ErrAPIError                = errors.New("zk: api error")
 | 
			
		||||
	ErrNoNode                  = errors.New("zk: node does not exist")
 | 
			
		||||
	ErrNoAuth                  = errors.New("zk: not authenticated")
 | 
			
		||||
	ErrBadVersion              = errors.New("zk: version conflict")
 | 
			
		||||
	ErrNoChildrenForEphemerals = errors.New("zk: ephemeral nodes may not have children")
 | 
			
		||||
	ErrNodeExists              = errors.New("zk: node already exists")
 | 
			
		||||
	ErrNotEmpty                = errors.New("zk: node has children")
 | 
			
		||||
	ErrSessionExpired          = errors.New("zk: session has been expired by the server")
 | 
			
		||||
	ErrInvalidACL              = errors.New("zk: invalid ACL specified")
 | 
			
		||||
	ErrAuthFailed              = errors.New("zk: client authentication failed")
 | 
			
		||||
	ErrClosing                 = errors.New("zk: zookeeper is closing")
 | 
			
		||||
	ErrNothing                 = errors.New("zk: no server responsees to process")
 | 
			
		||||
	ErrSessionMoved            = errors.New("zk: session moved to another server, so operation is ignored")
 | 
			
		||||
 | 
			
		||||
	// ErrInvalidCallback         = errors.New("zk: invalid callback specified")
 | 
			
		||||
	errCodeToError = map[ErrCode]error{
 | 
			
		||||
		0:                          nil,
 | 
			
		||||
		errAPIError:                ErrAPIError,
 | 
			
		||||
		errNoNode:                  ErrNoNode,
 | 
			
		||||
		errNoAuth:                  ErrNoAuth,
 | 
			
		||||
		errBadVersion:              ErrBadVersion,
 | 
			
		||||
		errNoChildrenForEphemerals: ErrNoChildrenForEphemerals,
 | 
			
		||||
		errNodeExists:              ErrNodeExists,
 | 
			
		||||
		errNotEmpty:                ErrNotEmpty,
 | 
			
		||||
		errSessionExpired:          ErrSessionExpired,
 | 
			
		||||
		// errInvalidCallback:         ErrInvalidCallback,
 | 
			
		||||
		errInvalidAcl:   ErrInvalidACL,
 | 
			
		||||
		errAuthFailed:   ErrAuthFailed,
 | 
			
		||||
		errClosing:      ErrClosing,
 | 
			
		||||
		errNothing:      ErrNothing,
 | 
			
		||||
		errSessionMoved: ErrSessionMoved,
 | 
			
		||||
	}
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func (e ErrCode) toError() error {
 | 
			
		||||
	if err, ok := errCodeToError[e]; ok {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	return ErrUnknown
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	errOk = 0
 | 
			
		||||
	// System and server-side errors
 | 
			
		||||
	errSystemError          = -1
 | 
			
		||||
	errRuntimeInconsistency = -2
 | 
			
		||||
	errDataInconsistency    = -3
 | 
			
		||||
	errConnectionLoss       = -4
 | 
			
		||||
	errMarshallingError     = -5
 | 
			
		||||
	errUnimplemented        = -6
 | 
			
		||||
	errOperationTimeout     = -7
 | 
			
		||||
	errBadArguments         = -8
 | 
			
		||||
	errInvalidState         = -9
 | 
			
		||||
	// API errors
 | 
			
		||||
	errAPIError                = ErrCode(-100)
 | 
			
		||||
	errNoNode                  = ErrCode(-101) // *
 | 
			
		||||
	errNoAuth                  = ErrCode(-102)
 | 
			
		||||
	errBadVersion              = ErrCode(-103) // *
 | 
			
		||||
	errNoChildrenForEphemerals = ErrCode(-108)
 | 
			
		||||
	errNodeExists              = ErrCode(-110) // *
 | 
			
		||||
	errNotEmpty                = ErrCode(-111)
 | 
			
		||||
	errSessionExpired          = ErrCode(-112)
 | 
			
		||||
	errInvalidCallback         = ErrCode(-113)
 | 
			
		||||
	errInvalidAcl              = ErrCode(-114)
 | 
			
		||||
	errAuthFailed              = ErrCode(-115)
 | 
			
		||||
	errClosing                 = ErrCode(-116)
 | 
			
		||||
	errNothing                 = ErrCode(-117)
 | 
			
		||||
	errSessionMoved            = ErrCode(-118)
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Constants for ACL permissions
 | 
			
		||||
const (
 | 
			
		||||
	PermRead = 1 << iota
 | 
			
		||||
	PermWrite
 | 
			
		||||
	PermCreate
 | 
			
		||||
	PermDelete
 | 
			
		||||
	PermAdmin
 | 
			
		||||
	PermAll = 0x1f
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	emptyPassword = []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
 | 
			
		||||
	opNames       = map[int32]string{
 | 
			
		||||
		opNotify:       "notify",
 | 
			
		||||
		opCreate:       "create",
 | 
			
		||||
		opDelete:       "delete",
 | 
			
		||||
		opExists:       "exists",
 | 
			
		||||
		opGetData:      "getData",
 | 
			
		||||
		opSetData:      "setData",
 | 
			
		||||
		opGetAcl:       "getACL",
 | 
			
		||||
		opSetAcl:       "setACL",
 | 
			
		||||
		opGetChildren:  "getChildren",
 | 
			
		||||
		opSync:         "sync",
 | 
			
		||||
		opPing:         "ping",
 | 
			
		||||
		opGetChildren2: "getChildren2",
 | 
			
		||||
		opCheck:        "check",
 | 
			
		||||
		opMulti:        "multi",
 | 
			
		||||
		opClose:        "close",
 | 
			
		||||
		opSetAuth:      "setAuth",
 | 
			
		||||
		opSetWatches:   "setWatches",
 | 
			
		||||
 | 
			
		||||
		opWatcherEvent: "watcherEvent",
 | 
			
		||||
	}
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type EventType int32
 | 
			
		||||
 | 
			
		||||
func (t EventType) String() string {
 | 
			
		||||
	if name := eventNames[t]; name != "" {
 | 
			
		||||
		return name
 | 
			
		||||
	}
 | 
			
		||||
	return "Unknown"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Mode is used to build custom server modes (leader|follower|standalone).
 | 
			
		||||
type Mode uint8
 | 
			
		||||
 | 
			
		||||
func (m Mode) String() string {
 | 
			
		||||
	if name := modeNames[m]; name != "" {
 | 
			
		||||
		return name
 | 
			
		||||
	}
 | 
			
		||||
	return "unknown"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	ModeUnknown    Mode = iota
 | 
			
		||||
	ModeLeader     Mode = iota
 | 
			
		||||
	ModeFollower   Mode = iota
 | 
			
		||||
	ModeStandalone Mode = iota
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	modeNames = map[Mode]string{
 | 
			
		||||
		ModeLeader:     "leader",
 | 
			
		||||
		ModeFollower:   "follower",
 | 
			
		||||
		ModeStandalone: "standalone",
 | 
			
		||||
	}
 | 
			
		||||
)
 | 
			
		||||
							
								
								
									
										290
									
								
								vendor/github.com/samuel/go-zookeeper/zk/flw.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										290
									
								
								vendor/github.com/samuel/go-zookeeper/zk/flw.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,290 @@
 | 
			
		||||
package zk
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bufio"
 | 
			
		||||
	"bytes"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"io/ioutil"
 | 
			
		||||
	"math/big"
 | 
			
		||||
	"net"
 | 
			
		||||
	"regexp"
 | 
			
		||||
	"strconv"
 | 
			
		||||
	"time"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// FLWSrvr is a FourLetterWord helper function. In particular, this function pulls the srvr output
 | 
			
		||||
// from the zookeeper instances and parses the output. A slice of *ServerStats structs are returned
 | 
			
		||||
// as well as a boolean value to indicate whether this function processed successfully.
 | 
			
		||||
//
 | 
			
		||||
// If the boolean value is false there was a problem. If the *ServerStats slice is empty or nil,
 | 
			
		||||
// then the error happened before we started to obtain 'srvr' values. Otherwise, one of the
 | 
			
		||||
// servers had an issue and the "Error" value in the struct should be inspected to determine
 | 
			
		||||
// which server had the issue.
 | 
			
		||||
func FLWSrvr(servers []string, timeout time.Duration) ([]*ServerStats, bool) {
 | 
			
		||||
	// different parts of the regular expression that are required to parse the srvr output
 | 
			
		||||
	var (
 | 
			
		||||
		zrVer   = `^Zookeeper version: ([A-Za-z0-9\.\-]+), built on (\d\d/\d\d/\d\d\d\d \d\d:\d\d [A-Za-z0-9:\+\-]+)`
 | 
			
		||||
		zrLat   = `^Latency min/avg/max: (\d+)/(\d+)/(\d+)`
 | 
			
		||||
		zrNet   = `^Received: (\d+).*\n^Sent: (\d+).*\n^Connections: (\d+).*\n^Outstanding: (\d+)`
 | 
			
		||||
		zrState = `^Zxid: (0x[A-Za-z0-9]+).*\n^Mode: (\w+).*\n^Node count: (\d+)`
 | 
			
		||||
	)
 | 
			
		||||
 | 
			
		||||
	// build the regex from the pieces above
 | 
			
		||||
	re, err := regexp.Compile(fmt.Sprintf(`(?m:\A%v.*\n%v.*\n%v.*\n%v)`, zrVer, zrLat, zrNet, zrState))
 | 
			
		||||
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, false
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	imOk := true
 | 
			
		||||
	servers = FormatServers(servers)
 | 
			
		||||
	ss := make([]*ServerStats, len(servers))
 | 
			
		||||
 | 
			
		||||
	for i := range ss {
 | 
			
		||||
		response, err := fourLetterWord(servers[i], "srvr", timeout)
 | 
			
		||||
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			ss[i] = &ServerStats{Error: err}
 | 
			
		||||
			imOk = false
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		matches := re.FindAllStringSubmatch(string(response), -1)
 | 
			
		||||
 | 
			
		||||
		if matches == nil {
 | 
			
		||||
			err := fmt.Errorf("unable to parse fields from zookeeper response (no regex matches)")
 | 
			
		||||
			ss[i] = &ServerStats{Error: err}
 | 
			
		||||
			imOk = false
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		match := matches[0][1:]
 | 
			
		||||
 | 
			
		||||
		// determine current server
 | 
			
		||||
		var srvrMode Mode
 | 
			
		||||
		switch match[10] {
 | 
			
		||||
		case "leader":
 | 
			
		||||
			srvrMode = ModeLeader
 | 
			
		||||
		case "follower":
 | 
			
		||||
			srvrMode = ModeFollower
 | 
			
		||||
		case "standalone":
 | 
			
		||||
			srvrMode = ModeStandalone
 | 
			
		||||
		default:
 | 
			
		||||
			srvrMode = ModeUnknown
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		buildTime, err := time.Parse("01/02/2006 15:04 MST", match[1])
 | 
			
		||||
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			ss[i] = &ServerStats{Error: err}
 | 
			
		||||
			imOk = false
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		parsedInt, err := strconv.ParseInt(match[9], 0, 64)
 | 
			
		||||
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			ss[i] = &ServerStats{Error: err}
 | 
			
		||||
			imOk = false
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// the ZxID value is an int64 with two int32s packed inside
 | 
			
		||||
		// the high int32 is the epoch (i.e., number of leader elections)
 | 
			
		||||
		// the low int32 is the counter
 | 
			
		||||
		epoch := int32(parsedInt >> 32)
 | 
			
		||||
		counter := int32(parsedInt & 0xFFFFFFFF)
 | 
			
		||||
 | 
			
		||||
		// within the regex above, these values must be numerical
 | 
			
		||||
		// so we can avoid useless checking of the error return value
 | 
			
		||||
		minLatency, _ := strconv.ParseInt(match[2], 0, 64)
 | 
			
		||||
		avgLatency, _ := strconv.ParseInt(match[3], 0, 64)
 | 
			
		||||
		maxLatency, _ := strconv.ParseInt(match[4], 0, 64)
 | 
			
		||||
		recv, _ := strconv.ParseInt(match[5], 0, 64)
 | 
			
		||||
		sent, _ := strconv.ParseInt(match[6], 0, 64)
 | 
			
		||||
		cons, _ := strconv.ParseInt(match[7], 0, 64)
 | 
			
		||||
		outs, _ := strconv.ParseInt(match[8], 0, 64)
 | 
			
		||||
		ncnt, _ := strconv.ParseInt(match[11], 0, 64)
 | 
			
		||||
 | 
			
		||||
		ss[i] = &ServerStats{
 | 
			
		||||
			Sent:        sent,
 | 
			
		||||
			Received:    recv,
 | 
			
		||||
			NodeCount:   ncnt,
 | 
			
		||||
			MinLatency:  minLatency,
 | 
			
		||||
			AvgLatency:  avgLatency,
 | 
			
		||||
			MaxLatency:  maxLatency,
 | 
			
		||||
			Connections: cons,
 | 
			
		||||
			Outstanding: outs,
 | 
			
		||||
			Epoch:       epoch,
 | 
			
		||||
			Counter:     counter,
 | 
			
		||||
			BuildTime:   buildTime,
 | 
			
		||||
			Mode:        srvrMode,
 | 
			
		||||
			Version:     match[0],
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return ss, imOk
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// FLWRuok is a FourLetterWord helper function. In particular, this function
 | 
			
		||||
// pulls the ruok output from each server.
 | 
			
		||||
func FLWRuok(servers []string, timeout time.Duration) []bool {
 | 
			
		||||
	servers = FormatServers(servers)
 | 
			
		||||
	oks := make([]bool, len(servers))
 | 
			
		||||
 | 
			
		||||
	for i := range oks {
 | 
			
		||||
		response, err := fourLetterWord(servers[i], "ruok", timeout)
 | 
			
		||||
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if bytes.Equal(response[:4], []byte("imok")) {
 | 
			
		||||
			oks[i] = true
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return oks
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// FLWCons is a FourLetterWord helper function. In particular, this function
 | 
			
		||||
// pulls the ruok output from each server.
 | 
			
		||||
//
 | 
			
		||||
// As with FLWSrvr, the boolean value indicates whether one of the requests had
 | 
			
		||||
// an issue. The Clients struct has an Error value that can be checked.
 | 
			
		||||
func FLWCons(servers []string, timeout time.Duration) ([]*ServerClients, bool) {
 | 
			
		||||
	var (
 | 
			
		||||
		zrAddr = `^ /((?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?):(?:\d+))\[\d+\]`
 | 
			
		||||
		zrPac  = `\(queued=(\d+),recved=(\d+),sent=(\d+),sid=(0x[A-Za-z0-9]+),lop=(\w+),est=(\d+),to=(\d+),`
 | 
			
		||||
		zrSesh = `lcxid=(0x[A-Za-z0-9]+),lzxid=(0x[A-Za-z0-9]+),lresp=(\d+),llat=(\d+),minlat=(\d+),avglat=(\d+),maxlat=(\d+)\)`
 | 
			
		||||
	)
 | 
			
		||||
 | 
			
		||||
	re, err := regexp.Compile(fmt.Sprintf("%v%v%v", zrAddr, zrPac, zrSesh))
 | 
			
		||||
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, false
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	servers = FormatServers(servers)
 | 
			
		||||
	sc := make([]*ServerClients, len(servers))
 | 
			
		||||
	imOk := true
 | 
			
		||||
 | 
			
		||||
	for i := range sc {
 | 
			
		||||
		response, err := fourLetterWord(servers[i], "cons", timeout)
 | 
			
		||||
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			sc[i] = &ServerClients{Error: err}
 | 
			
		||||
			imOk = false
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		scan := bufio.NewScanner(bytes.NewReader(response))
 | 
			
		||||
 | 
			
		||||
		var clients []*ServerClient
 | 
			
		||||
 | 
			
		||||
		for scan.Scan() {
 | 
			
		||||
			line := scan.Bytes()
 | 
			
		||||
 | 
			
		||||
			if len(line) == 0 {
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			m := re.FindAllStringSubmatch(string(line), -1)
 | 
			
		||||
 | 
			
		||||
			if m == nil {
 | 
			
		||||
				err := fmt.Errorf("unable to parse fields from zookeeper response (no regex matches)")
 | 
			
		||||
				sc[i] = &ServerClients{Error: err}
 | 
			
		||||
				imOk = false
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			match := m[0][1:]
 | 
			
		||||
 | 
			
		||||
			queued, _ := strconv.ParseInt(match[1], 0, 64)
 | 
			
		||||
			recvd, _ := strconv.ParseInt(match[2], 0, 64)
 | 
			
		||||
			sent, _ := strconv.ParseInt(match[3], 0, 64)
 | 
			
		||||
			sid, _ := strconv.ParseInt(match[4], 0, 64)
 | 
			
		||||
			est, _ := strconv.ParseInt(match[6], 0, 64)
 | 
			
		||||
			timeout, _ := strconv.ParseInt(match[7], 0, 32)
 | 
			
		||||
			lresp, _ := strconv.ParseInt(match[10], 0, 64)
 | 
			
		||||
			llat, _ := strconv.ParseInt(match[11], 0, 32)
 | 
			
		||||
			minlat, _ := strconv.ParseInt(match[12], 0, 32)
 | 
			
		||||
			avglat, _ := strconv.ParseInt(match[13], 0, 32)
 | 
			
		||||
			maxlat, _ := strconv.ParseInt(match[14], 0, 32)
 | 
			
		||||
 | 
			
		||||
			// zookeeper returns a value, '0xffffffffffffffff', as the
 | 
			
		||||
			// Lzxid for PING requests in the 'cons' output.
 | 
			
		||||
			// unfortunately, in Go that is an invalid int64 and is not represented
 | 
			
		||||
			// as -1.
 | 
			
		||||
			// However, converting the string value to a big.Int and then back to
 | 
			
		||||
			// and int64 properly sets the value to -1
 | 
			
		||||
			lzxid, ok := new(big.Int).SetString(match[9], 0)
 | 
			
		||||
 | 
			
		||||
			var errVal error
 | 
			
		||||
 | 
			
		||||
			if !ok {
 | 
			
		||||
				errVal = fmt.Errorf("failed to convert lzxid value to big.Int")
 | 
			
		||||
				imOk = false
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			lcxid, ok := new(big.Int).SetString(match[8], 0)
 | 
			
		||||
 | 
			
		||||
			if !ok && errVal == nil {
 | 
			
		||||
				errVal = fmt.Errorf("failed to convert lcxid value to big.Int")
 | 
			
		||||
				imOk = false
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			clients = append(clients, &ServerClient{
 | 
			
		||||
				Queued:        queued,
 | 
			
		||||
				Received:      recvd,
 | 
			
		||||
				Sent:          sent,
 | 
			
		||||
				SessionID:     sid,
 | 
			
		||||
				Lcxid:         lcxid.Int64(),
 | 
			
		||||
				Lzxid:         lzxid.Int64(),
 | 
			
		||||
				Timeout:       int32(timeout),
 | 
			
		||||
				LastLatency:   int32(llat),
 | 
			
		||||
				MinLatency:    int32(minlat),
 | 
			
		||||
				AvgLatency:    int32(avglat),
 | 
			
		||||
				MaxLatency:    int32(maxlat),
 | 
			
		||||
				Established:   time.Unix(est, 0),
 | 
			
		||||
				LastResponse:  time.Unix(lresp, 0),
 | 
			
		||||
				Addr:          match[0],
 | 
			
		||||
				LastOperation: match[5],
 | 
			
		||||
				Error:         errVal,
 | 
			
		||||
			})
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		sc[i] = &ServerClients{Clients: clients}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return sc, imOk
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func fourLetterWord(server, command string, timeout time.Duration) ([]byte, error) {
 | 
			
		||||
	conn, err := net.DialTimeout("tcp", server, timeout)
 | 
			
		||||
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// the zookeeper server should automatically close this socket
 | 
			
		||||
	// once the command has been processed, but better safe than sorry
 | 
			
		||||
	defer conn.Close()
 | 
			
		||||
 | 
			
		||||
	conn.SetWriteDeadline(time.Now().Add(timeout))
 | 
			
		||||
 | 
			
		||||
	_, err = conn.Write([]byte(command))
 | 
			
		||||
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	conn.SetReadDeadline(time.Now().Add(timeout))
 | 
			
		||||
 | 
			
		||||
	resp, err := ioutil.ReadAll(conn)
 | 
			
		||||
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return resp, nil
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										142
									
								
								vendor/github.com/samuel/go-zookeeper/zk/lock.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										142
									
								
								vendor/github.com/samuel/go-zookeeper/zk/lock.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,142 @@
 | 
			
		||||
package zk
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"errors"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"strconv"
 | 
			
		||||
	"strings"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	// ErrDeadlock is returned by Lock when trying to lock twice without unlocking first
 | 
			
		||||
	ErrDeadlock = errors.New("zk: trying to acquire a lock twice")
 | 
			
		||||
	// ErrNotLocked is returned by Unlock when trying to release a lock that has not first be acquired.
 | 
			
		||||
	ErrNotLocked = errors.New("zk: not locked")
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Lock is a mutual exclusion lock.
 | 
			
		||||
type Lock struct {
 | 
			
		||||
	c        *Conn
 | 
			
		||||
	path     string
 | 
			
		||||
	acl      []ACL
 | 
			
		||||
	lockPath string
 | 
			
		||||
	seq      int
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewLock creates a new lock instance using the provided connection, path, and acl.
 | 
			
		||||
// The path must be a node that is only used by this lock. A lock instances starts
 | 
			
		||||
// unlocked until Lock() is called.
 | 
			
		||||
func NewLock(c *Conn, path string, acl []ACL) *Lock {
 | 
			
		||||
	return &Lock{
 | 
			
		||||
		c:    c,
 | 
			
		||||
		path: path,
 | 
			
		||||
		acl:  acl,
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func parseSeq(path string) (int, error) {
 | 
			
		||||
	parts := strings.Split(path, "-")
 | 
			
		||||
	return strconv.Atoi(parts[len(parts)-1])
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Lock attempts to acquire the lock. It will wait to return until the lock
 | 
			
		||||
// is acquired or an error occurs. If this instance already has the lock
 | 
			
		||||
// then ErrDeadlock is returned.
 | 
			
		||||
func (l *Lock) Lock() error {
 | 
			
		||||
	if l.lockPath != "" {
 | 
			
		||||
		return ErrDeadlock
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	prefix := fmt.Sprintf("%s/lock-", l.path)
 | 
			
		||||
 | 
			
		||||
	path := ""
 | 
			
		||||
	var err error
 | 
			
		||||
	for i := 0; i < 3; i++ {
 | 
			
		||||
		path, err = l.c.CreateProtectedEphemeralSequential(prefix, []byte{}, l.acl)
 | 
			
		||||
		if err == ErrNoNode {
 | 
			
		||||
			// Create parent node.
 | 
			
		||||
			parts := strings.Split(l.path, "/")
 | 
			
		||||
			pth := ""
 | 
			
		||||
			for _, p := range parts[1:] {
 | 
			
		||||
				pth += "/" + p
 | 
			
		||||
				_, err := l.c.Create(pth, []byte{}, 0, l.acl)
 | 
			
		||||
				if err != nil && err != ErrNodeExists {
 | 
			
		||||
					return err
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		} else if err == nil {
 | 
			
		||||
			break
 | 
			
		||||
		} else {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	seq, err := parseSeq(path)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for {
 | 
			
		||||
		children, _, err := l.c.Children(l.path)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		lowestSeq := seq
 | 
			
		||||
		prevSeq := 0
 | 
			
		||||
		prevSeqPath := ""
 | 
			
		||||
		for _, p := range children {
 | 
			
		||||
			s, err := parseSeq(p)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
			if s < lowestSeq {
 | 
			
		||||
				lowestSeq = s
 | 
			
		||||
			}
 | 
			
		||||
			if s < seq && s > prevSeq {
 | 
			
		||||
				prevSeq = s
 | 
			
		||||
				prevSeqPath = p
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if seq == lowestSeq {
 | 
			
		||||
			// Acquired the lock
 | 
			
		||||
			break
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// Wait on the node next in line for the lock
 | 
			
		||||
		_, _, ch, err := l.c.GetW(l.path + "/" + prevSeqPath)
 | 
			
		||||
		if err != nil && err != ErrNoNode {
 | 
			
		||||
			return err
 | 
			
		||||
		} else if err != nil && err == ErrNoNode {
 | 
			
		||||
			// try again
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		ev := <-ch
 | 
			
		||||
		if ev.Err != nil {
 | 
			
		||||
			return ev.Err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	l.seq = seq
 | 
			
		||||
	l.lockPath = path
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Unlock releases an acquired lock. If the lock is not currently acquired by
 | 
			
		||||
// this Lock instance than ErrNotLocked is returned.
 | 
			
		||||
func (l *Lock) Unlock() error {
 | 
			
		||||
	if l.lockPath == "" {
 | 
			
		||||
		return ErrNotLocked
 | 
			
		||||
	}
 | 
			
		||||
	if err := l.c.Delete(l.lockPath, -1); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	l.lockPath = ""
 | 
			
		||||
	l.seq = 0
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										119
									
								
								vendor/github.com/samuel/go-zookeeper/zk/server_help.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										119
									
								
								vendor/github.com/samuel/go-zookeeper/zk/server_help.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,119 @@
 | 
			
		||||
package zk
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"io"
 | 
			
		||||
	"io/ioutil"
 | 
			
		||||
	"math/rand"
 | 
			
		||||
	"os"
 | 
			
		||||
	"path/filepath"
 | 
			
		||||
	"time"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type TestServer struct {
 | 
			
		||||
	Port int
 | 
			
		||||
	Path string
 | 
			
		||||
	Srv  *Server
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type TestCluster struct {
 | 
			
		||||
	Path    string
 | 
			
		||||
	Servers []TestServer
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func StartTestCluster(size int, stdout, stderr io.Writer) (*TestCluster, error) {
 | 
			
		||||
	tmpPath, err := ioutil.TempDir("", "gozk")
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	success := false
 | 
			
		||||
	startPort := int(rand.Int31n(6000) + 10000)
 | 
			
		||||
	cluster := &TestCluster{Path: tmpPath}
 | 
			
		||||
	defer func() {
 | 
			
		||||
		if !success {
 | 
			
		||||
			cluster.Stop()
 | 
			
		||||
		}
 | 
			
		||||
	}()
 | 
			
		||||
	for serverN := 0; serverN < size; serverN++ {
 | 
			
		||||
		srvPath := filepath.Join(tmpPath, fmt.Sprintf("srv%d", serverN))
 | 
			
		||||
		if err := os.Mkdir(srvPath, 0700); err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
		port := startPort + serverN*3
 | 
			
		||||
		cfg := ServerConfig{
 | 
			
		||||
			ClientPort: port,
 | 
			
		||||
			DataDir:    srvPath,
 | 
			
		||||
		}
 | 
			
		||||
		for i := 0; i < size; i++ {
 | 
			
		||||
			cfg.Servers = append(cfg.Servers, ServerConfigServer{
 | 
			
		||||
				ID:                 i + 1,
 | 
			
		||||
				Host:               "127.0.0.1",
 | 
			
		||||
				PeerPort:           startPort + i*3 + 1,
 | 
			
		||||
				LeaderElectionPort: startPort + i*3 + 2,
 | 
			
		||||
			})
 | 
			
		||||
		}
 | 
			
		||||
		cfgPath := filepath.Join(srvPath, "zoo.cfg")
 | 
			
		||||
		fi, err := os.Create(cfgPath)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
		err = cfg.Marshall(fi)
 | 
			
		||||
		fi.Close()
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		fi, err = os.Create(filepath.Join(srvPath, "myid"))
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
		_, err = fmt.Fprintf(fi, "%d\n", serverN+1)
 | 
			
		||||
		fi.Close()
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		srv := &Server{
 | 
			
		||||
			ConfigPath: cfgPath,
 | 
			
		||||
			Stdout:     stdout,
 | 
			
		||||
			Stderr:     stderr,
 | 
			
		||||
		}
 | 
			
		||||
		if err := srv.Start(); err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
		cluster.Servers = append(cluster.Servers, TestServer{
 | 
			
		||||
			Path: srvPath,
 | 
			
		||||
			Port: cfg.ClientPort,
 | 
			
		||||
			Srv:  srv,
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
	success = true
 | 
			
		||||
	time.Sleep(time.Second) // Give the server time to become active. Should probably actually attempt to connect to verify.
 | 
			
		||||
	return cluster, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (ts *TestCluster) Connect(idx int) (*Conn, error) {
 | 
			
		||||
	zk, _, err := Connect([]string{fmt.Sprintf("127.0.0.1:%d", ts.Servers[idx].Port)}, time.Second*15)
 | 
			
		||||
	return zk, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (ts *TestCluster) ConnectAll() (*Conn, <-chan Event, error) {
 | 
			
		||||
	return ts.ConnectAllTimeout(time.Second * 15)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (ts *TestCluster) ConnectAllTimeout(sessionTimeout time.Duration) (*Conn, <-chan Event, error) {
 | 
			
		||||
	hosts := make([]string, len(ts.Servers))
 | 
			
		||||
	for i, srv := range ts.Servers {
 | 
			
		||||
		hosts[i] = fmt.Sprintf("127.0.0.1:%d", srv.Port)
 | 
			
		||||
	}
 | 
			
		||||
	zk, ch, err := Connect(hosts, sessionTimeout)
 | 
			
		||||
	return zk, ch, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (ts *TestCluster) Stop() error {
 | 
			
		||||
	for _, srv := range ts.Servers {
 | 
			
		||||
		srv.Srv.Stop()
 | 
			
		||||
	}
 | 
			
		||||
	defer os.RemoveAll(ts.Path)
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										136
									
								
								vendor/github.com/samuel/go-zookeeper/zk/server_java.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										136
									
								
								vendor/github.com/samuel/go-zookeeper/zk/server_java.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,136 @@
 | 
			
		||||
package zk
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"io"
 | 
			
		||||
	"os"
 | 
			
		||||
	"os/exec"
 | 
			
		||||
	"path/filepath"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type ErrMissingServerConfigField string
 | 
			
		||||
 | 
			
		||||
func (e ErrMissingServerConfigField) Error() string {
 | 
			
		||||
	return fmt.Sprintf("zk: missing server config field '%s'", string(e))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	DefaultServerTickTime                 = 2000
 | 
			
		||||
	DefaultServerInitLimit                = 10
 | 
			
		||||
	DefaultServerSyncLimit                = 5
 | 
			
		||||
	DefaultServerAutoPurgeSnapRetainCount = 3
 | 
			
		||||
	DefaultPeerPort                       = 2888
 | 
			
		||||
	DefaultLeaderElectionPort             = 3888
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type ServerConfigServer struct {
 | 
			
		||||
	ID                 int
 | 
			
		||||
	Host               string
 | 
			
		||||
	PeerPort           int
 | 
			
		||||
	LeaderElectionPort int
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type ServerConfig struct {
 | 
			
		||||
	TickTime                 int    // Number of milliseconds of each tick
 | 
			
		||||
	InitLimit                int    // Number of ticks that the initial synchronization phase can take
 | 
			
		||||
	SyncLimit                int    // Number of ticks that can pass between sending a request and getting an acknowledgement
 | 
			
		||||
	DataDir                  string // Direcrory where the snapshot is stored
 | 
			
		||||
	ClientPort               int    // Port at which clients will connect
 | 
			
		||||
	AutoPurgeSnapRetainCount int    // Number of snapshots to retain in dataDir
 | 
			
		||||
	AutoPurgePurgeInterval   int    // Purge task internal in hours (0 to disable auto purge)
 | 
			
		||||
	Servers                  []ServerConfigServer
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (sc ServerConfig) Marshall(w io.Writer) error {
 | 
			
		||||
	if sc.DataDir == "" {
 | 
			
		||||
		return ErrMissingServerConfigField("dataDir")
 | 
			
		||||
	}
 | 
			
		||||
	fmt.Fprintf(w, "dataDir=%s\n", sc.DataDir)
 | 
			
		||||
	if sc.TickTime <= 0 {
 | 
			
		||||
		sc.TickTime = DefaultServerTickTime
 | 
			
		||||
	}
 | 
			
		||||
	fmt.Fprintf(w, "tickTime=%d\n", sc.TickTime)
 | 
			
		||||
	if sc.InitLimit <= 0 {
 | 
			
		||||
		sc.InitLimit = DefaultServerInitLimit
 | 
			
		||||
	}
 | 
			
		||||
	fmt.Fprintf(w, "initLimit=%d\n", sc.InitLimit)
 | 
			
		||||
	if sc.SyncLimit <= 0 {
 | 
			
		||||
		sc.SyncLimit = DefaultServerSyncLimit
 | 
			
		||||
	}
 | 
			
		||||
	fmt.Fprintf(w, "syncLimit=%d\n", sc.SyncLimit)
 | 
			
		||||
	if sc.ClientPort <= 0 {
 | 
			
		||||
		sc.ClientPort = DefaultPort
 | 
			
		||||
	}
 | 
			
		||||
	fmt.Fprintf(w, "clientPort=%d\n", sc.ClientPort)
 | 
			
		||||
	if sc.AutoPurgePurgeInterval > 0 {
 | 
			
		||||
		if sc.AutoPurgeSnapRetainCount <= 0 {
 | 
			
		||||
			sc.AutoPurgeSnapRetainCount = DefaultServerAutoPurgeSnapRetainCount
 | 
			
		||||
		}
 | 
			
		||||
		fmt.Fprintf(w, "autopurge.snapRetainCount=%d\n", sc.AutoPurgeSnapRetainCount)
 | 
			
		||||
		fmt.Fprintf(w, "autopurge.purgeInterval=%d\n", sc.AutoPurgePurgeInterval)
 | 
			
		||||
	}
 | 
			
		||||
	if len(sc.Servers) > 0 {
 | 
			
		||||
		for _, srv := range sc.Servers {
 | 
			
		||||
			if srv.PeerPort <= 0 {
 | 
			
		||||
				srv.PeerPort = DefaultPeerPort
 | 
			
		||||
			}
 | 
			
		||||
			if srv.LeaderElectionPort <= 0 {
 | 
			
		||||
				srv.LeaderElectionPort = DefaultLeaderElectionPort
 | 
			
		||||
			}
 | 
			
		||||
			fmt.Fprintf(w, "server.%d=%s:%d:%d\n", srv.ID, srv.Host, srv.PeerPort, srv.LeaderElectionPort)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var jarSearchPaths = []string{
 | 
			
		||||
	"zookeeper-*/contrib/fatjar/zookeeper-*-fatjar.jar",
 | 
			
		||||
	"../zookeeper-*/contrib/fatjar/zookeeper-*-fatjar.jar",
 | 
			
		||||
	"/usr/share/java/zookeeper-*.jar",
 | 
			
		||||
	"/usr/local/zookeeper-*/contrib/fatjar/zookeeper-*-fatjar.jar",
 | 
			
		||||
	"/usr/local/Cellar/zookeeper/*/libexec/contrib/fatjar/zookeeper-*-fatjar.jar",
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func findZookeeperFatJar() string {
 | 
			
		||||
	var paths []string
 | 
			
		||||
	zkPath := os.Getenv("ZOOKEEPER_PATH")
 | 
			
		||||
	if zkPath == "" {
 | 
			
		||||
		paths = jarSearchPaths
 | 
			
		||||
	} else {
 | 
			
		||||
		paths = []string{filepath.Join(zkPath, "contrib/fatjar/zookeeper-*-fatjar.jar")}
 | 
			
		||||
	}
 | 
			
		||||
	for _, path := range paths {
 | 
			
		||||
		matches, _ := filepath.Glob(path)
 | 
			
		||||
		// TODO: could sort by version and pick latest
 | 
			
		||||
		if len(matches) > 0 {
 | 
			
		||||
			return matches[0]
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return ""
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type Server struct {
 | 
			
		||||
	JarPath        string
 | 
			
		||||
	ConfigPath     string
 | 
			
		||||
	Stdout, Stderr io.Writer
 | 
			
		||||
 | 
			
		||||
	cmd *exec.Cmd
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (srv *Server) Start() error {
 | 
			
		||||
	if srv.JarPath == "" {
 | 
			
		||||
		srv.JarPath = findZookeeperFatJar()
 | 
			
		||||
		if srv.JarPath == "" {
 | 
			
		||||
			return fmt.Errorf("zk: unable to find server jar")
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	srv.cmd = exec.Command("java", "-jar", srv.JarPath, "server", srv.ConfigPath)
 | 
			
		||||
	srv.cmd.Stdout = srv.Stdout
 | 
			
		||||
	srv.cmd.Stderr = srv.Stderr
 | 
			
		||||
	return srv.cmd.Start()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (srv *Server) Stop() error {
 | 
			
		||||
	srv.cmd.Process.Signal(os.Kill)
 | 
			
		||||
	return srv.cmd.Wait()
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										640
									
								
								vendor/github.com/samuel/go-zookeeper/zk/structs.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										640
									
								
								vendor/github.com/samuel/go-zookeeper/zk/structs.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,640 @@
 | 
			
		||||
package zk
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"encoding/binary"
 | 
			
		||||
	"errors"
 | 
			
		||||
	"log"
 | 
			
		||||
	"reflect"
 | 
			
		||||
	"runtime"
 | 
			
		||||
	"time"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	ErrUnhandledFieldType = errors.New("zk: unhandled field type")
 | 
			
		||||
	ErrPtrExpected        = errors.New("zk: encode/decode expect a non-nil pointer to struct")
 | 
			
		||||
	ErrShortBuffer        = errors.New("zk: buffer too small")
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type defaultLogger struct{}
 | 
			
		||||
 | 
			
		||||
func (defaultLogger) Printf(format string, a ...interface{}) {
 | 
			
		||||
	log.Printf(format, a...)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type ACL struct {
 | 
			
		||||
	Perms  int32
 | 
			
		||||
	Scheme string
 | 
			
		||||
	ID     string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type Stat struct {
 | 
			
		||||
	Czxid          int64 // The zxid of the change that caused this znode to be created.
 | 
			
		||||
	Mzxid          int64 // The zxid of the change that last modified this znode.
 | 
			
		||||
	Ctime          int64 // The time in milliseconds from epoch when this znode was created.
 | 
			
		||||
	Mtime          int64 // The time in milliseconds from epoch when this znode was last modified.
 | 
			
		||||
	Version        int32 // The number of changes to the data of this znode.
 | 
			
		||||
	Cversion       int32 // The number of changes to the children of this znode.
 | 
			
		||||
	Aversion       int32 // The number of changes to the ACL of this znode.
 | 
			
		||||
	EphemeralOwner int64 // The session id of the owner of this znode if the znode is an ephemeral node. If it is not an ephemeral node, it will be zero.
 | 
			
		||||
	DataLength     int32 // The length of the data field of this znode.
 | 
			
		||||
	NumChildren    int32 // The number of children of this znode.
 | 
			
		||||
	Pzxid          int64 // last modified children
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ServerClient is the information for a single Zookeeper client and its session.
 | 
			
		||||
// This is used to parse/extract the output fo the `cons` command.
 | 
			
		||||
type ServerClient struct {
 | 
			
		||||
	Queued        int64
 | 
			
		||||
	Received      int64
 | 
			
		||||
	Sent          int64
 | 
			
		||||
	SessionID     int64
 | 
			
		||||
	Lcxid         int64
 | 
			
		||||
	Lzxid         int64
 | 
			
		||||
	Timeout       int32
 | 
			
		||||
	LastLatency   int32
 | 
			
		||||
	MinLatency    int32
 | 
			
		||||
	AvgLatency    int32
 | 
			
		||||
	MaxLatency    int32
 | 
			
		||||
	Established   time.Time
 | 
			
		||||
	LastResponse  time.Time
 | 
			
		||||
	Addr          string
 | 
			
		||||
	LastOperation string // maybe?
 | 
			
		||||
	Error         error
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ServerClients is a struct for the FLWCons() function. It's used to provide
 | 
			
		||||
// the list of Clients.
 | 
			
		||||
//
 | 
			
		||||
// This is needed because FLWCons() takes multiple servers.
 | 
			
		||||
type ServerClients struct {
 | 
			
		||||
	Clients []*ServerClient
 | 
			
		||||
	Error   error
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ServerStats is the information pulled from the Zookeeper `stat` command.
 | 
			
		||||
type ServerStats struct {
 | 
			
		||||
	Sent        int64
 | 
			
		||||
	Received    int64
 | 
			
		||||
	NodeCount   int64
 | 
			
		||||
	MinLatency  int64
 | 
			
		||||
	AvgLatency  int64
 | 
			
		||||
	MaxLatency  int64
 | 
			
		||||
	Connections int64
 | 
			
		||||
	Outstanding int64
 | 
			
		||||
	Epoch       int32
 | 
			
		||||
	Counter     int32
 | 
			
		||||
	BuildTime   time.Time
 | 
			
		||||
	Mode        Mode
 | 
			
		||||
	Version     string
 | 
			
		||||
	Error       error
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type requestHeader struct {
 | 
			
		||||
	Xid    int32
 | 
			
		||||
	Opcode int32
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type responseHeader struct {
 | 
			
		||||
	Xid  int32
 | 
			
		||||
	Zxid int64
 | 
			
		||||
	Err  ErrCode
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type multiHeader struct {
 | 
			
		||||
	Type int32
 | 
			
		||||
	Done bool
 | 
			
		||||
	Err  ErrCode
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type auth struct {
 | 
			
		||||
	Type   int32
 | 
			
		||||
	Scheme string
 | 
			
		||||
	Auth   []byte
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Generic request structs
 | 
			
		||||
 | 
			
		||||
type pathRequest struct {
 | 
			
		||||
	Path string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type PathVersionRequest struct {
 | 
			
		||||
	Path    string
 | 
			
		||||
	Version int32
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type pathWatchRequest struct {
 | 
			
		||||
	Path  string
 | 
			
		||||
	Watch bool
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type pathResponse struct {
 | 
			
		||||
	Path string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type statResponse struct {
 | 
			
		||||
	Stat Stat
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//
 | 
			
		||||
 | 
			
		||||
type CheckVersionRequest PathVersionRequest
 | 
			
		||||
type closeRequest struct{}
 | 
			
		||||
type closeResponse struct{}
 | 
			
		||||
 | 
			
		||||
type connectRequest struct {
 | 
			
		||||
	ProtocolVersion int32
 | 
			
		||||
	LastZxidSeen    int64
 | 
			
		||||
	TimeOut         int32
 | 
			
		||||
	SessionID       int64
 | 
			
		||||
	Passwd          []byte
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type connectResponse struct {
 | 
			
		||||
	ProtocolVersion int32
 | 
			
		||||
	TimeOut         int32
 | 
			
		||||
	SessionID       int64
 | 
			
		||||
	Passwd          []byte
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type CreateRequest struct {
 | 
			
		||||
	Path  string
 | 
			
		||||
	Data  []byte
 | 
			
		||||
	Acl   []ACL
 | 
			
		||||
	Flags int32
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type createResponse pathResponse
 | 
			
		||||
type DeleteRequest PathVersionRequest
 | 
			
		||||
type deleteResponse struct{}
 | 
			
		||||
 | 
			
		||||
type errorResponse struct {
 | 
			
		||||
	Err int32
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type existsRequest pathWatchRequest
 | 
			
		||||
type existsResponse statResponse
 | 
			
		||||
type getAclRequest pathRequest
 | 
			
		||||
 | 
			
		||||
type getAclResponse struct {
 | 
			
		||||
	Acl  []ACL
 | 
			
		||||
	Stat Stat
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type getChildrenRequest pathRequest
 | 
			
		||||
 | 
			
		||||
type getChildrenResponse struct {
 | 
			
		||||
	Children []string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type getChildren2Request pathWatchRequest
 | 
			
		||||
 | 
			
		||||
type getChildren2Response struct {
 | 
			
		||||
	Children []string
 | 
			
		||||
	Stat     Stat
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type getDataRequest pathWatchRequest
 | 
			
		||||
 | 
			
		||||
type getDataResponse struct {
 | 
			
		||||
	Data []byte
 | 
			
		||||
	Stat Stat
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type getMaxChildrenRequest pathRequest
 | 
			
		||||
 | 
			
		||||
type getMaxChildrenResponse struct {
 | 
			
		||||
	Max int32
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type getSaslRequest struct {
 | 
			
		||||
	Token []byte
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type pingRequest struct{}
 | 
			
		||||
type pingResponse struct{}
 | 
			
		||||
 | 
			
		||||
type setAclRequest struct {
 | 
			
		||||
	Path    string
 | 
			
		||||
	Acl     []ACL
 | 
			
		||||
	Version int32
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type setAclResponse statResponse
 | 
			
		||||
 | 
			
		||||
type SetDataRequest struct {
 | 
			
		||||
	Path    string
 | 
			
		||||
	Data    []byte
 | 
			
		||||
	Version int32
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type setDataResponse statResponse
 | 
			
		||||
 | 
			
		||||
type setMaxChildren struct {
 | 
			
		||||
	Path string
 | 
			
		||||
	Max  int32
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type setSaslRequest struct {
 | 
			
		||||
	Token string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type setSaslResponse struct {
 | 
			
		||||
	Token string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type setWatchesRequest struct {
 | 
			
		||||
	RelativeZxid int64
 | 
			
		||||
	DataWatches  []string
 | 
			
		||||
	ExistWatches []string
 | 
			
		||||
	ChildWatches []string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type setWatchesResponse struct{}
 | 
			
		||||
 | 
			
		||||
type syncRequest pathRequest
 | 
			
		||||
type syncResponse pathResponse
 | 
			
		||||
 | 
			
		||||
type setAuthRequest auth
 | 
			
		||||
type setAuthResponse struct{}
 | 
			
		||||
 | 
			
		||||
type multiRequestOp struct {
 | 
			
		||||
	Header multiHeader
 | 
			
		||||
	Op     interface{}
 | 
			
		||||
}
 | 
			
		||||
type multiRequest struct {
 | 
			
		||||
	Ops        []multiRequestOp
 | 
			
		||||
	DoneHeader multiHeader
 | 
			
		||||
}
 | 
			
		||||
type multiResponseOp struct {
 | 
			
		||||
	Header multiHeader
 | 
			
		||||
	String string
 | 
			
		||||
	Stat   *Stat
 | 
			
		||||
}
 | 
			
		||||
type multiResponse struct {
 | 
			
		||||
	Ops        []multiResponseOp
 | 
			
		||||
	DoneHeader multiHeader
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *multiRequest) Encode(buf []byte) (int, error) {
 | 
			
		||||
	total := 0
 | 
			
		||||
	for _, op := range r.Ops {
 | 
			
		||||
		op.Header.Done = false
 | 
			
		||||
		n, err := encodePacketValue(buf[total:], reflect.ValueOf(op))
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return total, err
 | 
			
		||||
		}
 | 
			
		||||
		total += n
 | 
			
		||||
	}
 | 
			
		||||
	r.DoneHeader.Done = true
 | 
			
		||||
	n, err := encodePacketValue(buf[total:], reflect.ValueOf(r.DoneHeader))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return total, err
 | 
			
		||||
	}
 | 
			
		||||
	total += n
 | 
			
		||||
 | 
			
		||||
	return total, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *multiRequest) Decode(buf []byte) (int, error) {
 | 
			
		||||
	r.Ops = make([]multiRequestOp, 0)
 | 
			
		||||
	r.DoneHeader = multiHeader{-1, true, -1}
 | 
			
		||||
	total := 0
 | 
			
		||||
	for {
 | 
			
		||||
		header := &multiHeader{}
 | 
			
		||||
		n, err := decodePacketValue(buf[total:], reflect.ValueOf(header))
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return total, err
 | 
			
		||||
		}
 | 
			
		||||
		total += n
 | 
			
		||||
		if header.Done {
 | 
			
		||||
			r.DoneHeader = *header
 | 
			
		||||
			break
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		req := requestStructForOp(header.Type)
 | 
			
		||||
		if req == nil {
 | 
			
		||||
			return total, ErrAPIError
 | 
			
		||||
		}
 | 
			
		||||
		n, err = decodePacketValue(buf[total:], reflect.ValueOf(req))
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return total, err
 | 
			
		||||
		}
 | 
			
		||||
		total += n
 | 
			
		||||
		r.Ops = append(r.Ops, multiRequestOp{*header, req})
 | 
			
		||||
	}
 | 
			
		||||
	return total, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *multiResponse) Decode(buf []byte) (int, error) {
 | 
			
		||||
	r.Ops = make([]multiResponseOp, 0)
 | 
			
		||||
	r.DoneHeader = multiHeader{-1, true, -1}
 | 
			
		||||
	total := 0
 | 
			
		||||
	for {
 | 
			
		||||
		header := &multiHeader{}
 | 
			
		||||
		n, err := decodePacketValue(buf[total:], reflect.ValueOf(header))
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return total, err
 | 
			
		||||
		}
 | 
			
		||||
		total += n
 | 
			
		||||
		if header.Done {
 | 
			
		||||
			r.DoneHeader = *header
 | 
			
		||||
			break
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		res := multiResponseOp{Header: *header}
 | 
			
		||||
		var w reflect.Value
 | 
			
		||||
		switch header.Type {
 | 
			
		||||
		default:
 | 
			
		||||
			return total, ErrAPIError
 | 
			
		||||
		case opCreate:
 | 
			
		||||
			w = reflect.ValueOf(&res.String)
 | 
			
		||||
		case opSetData:
 | 
			
		||||
			res.Stat = new(Stat)
 | 
			
		||||
			w = reflect.ValueOf(res.Stat)
 | 
			
		||||
		case opCheck, opDelete:
 | 
			
		||||
		}
 | 
			
		||||
		if w.IsValid() {
 | 
			
		||||
			n, err := decodePacketValue(buf[total:], w)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return total, err
 | 
			
		||||
			}
 | 
			
		||||
			total += n
 | 
			
		||||
		}
 | 
			
		||||
		r.Ops = append(r.Ops, res)
 | 
			
		||||
	}
 | 
			
		||||
	return total, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type watcherEvent struct {
 | 
			
		||||
	Type  EventType
 | 
			
		||||
	State State
 | 
			
		||||
	Path  string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type decoder interface {
 | 
			
		||||
	Decode(buf []byte) (int, error)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type encoder interface {
 | 
			
		||||
	Encode(buf []byte) (int, error)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func decodePacket(buf []byte, st interface{}) (n int, err error) {
 | 
			
		||||
	defer func() {
 | 
			
		||||
		if r := recover(); r != nil {
 | 
			
		||||
			if e, ok := r.(runtime.Error); ok && e.Error() == "runtime error: slice bounds out of range" {
 | 
			
		||||
				err = ErrShortBuffer
 | 
			
		||||
			} else {
 | 
			
		||||
				panic(r)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}()
 | 
			
		||||
 | 
			
		||||
	v := reflect.ValueOf(st)
 | 
			
		||||
	if v.Kind() != reflect.Ptr || v.IsNil() {
 | 
			
		||||
		return 0, ErrPtrExpected
 | 
			
		||||
	}
 | 
			
		||||
	return decodePacketValue(buf, v)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func decodePacketValue(buf []byte, v reflect.Value) (int, error) {
 | 
			
		||||
	rv := v
 | 
			
		||||
	kind := v.Kind()
 | 
			
		||||
	if kind == reflect.Ptr {
 | 
			
		||||
		if v.IsNil() {
 | 
			
		||||
			v.Set(reflect.New(v.Type().Elem()))
 | 
			
		||||
		}
 | 
			
		||||
		v = v.Elem()
 | 
			
		||||
		kind = v.Kind()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	n := 0
 | 
			
		||||
	switch kind {
 | 
			
		||||
	default:
 | 
			
		||||
		return n, ErrUnhandledFieldType
 | 
			
		||||
	case reflect.Struct:
 | 
			
		||||
		if de, ok := rv.Interface().(decoder); ok {
 | 
			
		||||
			return de.Decode(buf)
 | 
			
		||||
		} else if de, ok := v.Interface().(decoder); ok {
 | 
			
		||||
			return de.Decode(buf)
 | 
			
		||||
		} else {
 | 
			
		||||
			for i := 0; i < v.NumField(); i++ {
 | 
			
		||||
				field := v.Field(i)
 | 
			
		||||
				n2, err := decodePacketValue(buf[n:], field)
 | 
			
		||||
				n += n2
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					return n, err
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	case reflect.Bool:
 | 
			
		||||
		v.SetBool(buf[n] != 0)
 | 
			
		||||
		n++
 | 
			
		||||
	case reflect.Int32:
 | 
			
		||||
		v.SetInt(int64(binary.BigEndian.Uint32(buf[n : n+4])))
 | 
			
		||||
		n += 4
 | 
			
		||||
	case reflect.Int64:
 | 
			
		||||
		v.SetInt(int64(binary.BigEndian.Uint64(buf[n : n+8])))
 | 
			
		||||
		n += 8
 | 
			
		||||
	case reflect.String:
 | 
			
		||||
		ln := int(binary.BigEndian.Uint32(buf[n : n+4]))
 | 
			
		||||
		v.SetString(string(buf[n+4 : n+4+ln]))
 | 
			
		||||
		n += 4 + ln
 | 
			
		||||
	case reflect.Slice:
 | 
			
		||||
		switch v.Type().Elem().Kind() {
 | 
			
		||||
		default:
 | 
			
		||||
			count := int(binary.BigEndian.Uint32(buf[n : n+4]))
 | 
			
		||||
			n += 4
 | 
			
		||||
			values := reflect.MakeSlice(v.Type(), count, count)
 | 
			
		||||
			v.Set(values)
 | 
			
		||||
			for i := 0; i < count; i++ {
 | 
			
		||||
				n2, err := decodePacketValue(buf[n:], values.Index(i))
 | 
			
		||||
				n += n2
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					return n, err
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		case reflect.Uint8:
 | 
			
		||||
			ln := int(int32(binary.BigEndian.Uint32(buf[n : n+4])))
 | 
			
		||||
			if ln < 0 {
 | 
			
		||||
				n += 4
 | 
			
		||||
				v.SetBytes(nil)
 | 
			
		||||
			} else {
 | 
			
		||||
				bytes := make([]byte, ln)
 | 
			
		||||
				copy(bytes, buf[n+4:n+4+ln])
 | 
			
		||||
				v.SetBytes(bytes)
 | 
			
		||||
				n += 4 + ln
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return n, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func encodePacket(buf []byte, st interface{}) (n int, err error) {
 | 
			
		||||
	defer func() {
 | 
			
		||||
		if r := recover(); r != nil {
 | 
			
		||||
			if e, ok := r.(runtime.Error); ok && e.Error() == "runtime error: slice bounds out of range" {
 | 
			
		||||
				err = ErrShortBuffer
 | 
			
		||||
			} else {
 | 
			
		||||
				panic(r)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}()
 | 
			
		||||
 | 
			
		||||
	v := reflect.ValueOf(st)
 | 
			
		||||
	if v.Kind() != reflect.Ptr || v.IsNil() {
 | 
			
		||||
		return 0, ErrPtrExpected
 | 
			
		||||
	}
 | 
			
		||||
	return encodePacketValue(buf, v)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func encodePacketValue(buf []byte, v reflect.Value) (int, error) {
 | 
			
		||||
	rv := v
 | 
			
		||||
	for v.Kind() == reflect.Ptr || v.Kind() == reflect.Interface {
 | 
			
		||||
		v = v.Elem()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	n := 0
 | 
			
		||||
	switch v.Kind() {
 | 
			
		||||
	default:
 | 
			
		||||
		return n, ErrUnhandledFieldType
 | 
			
		||||
	case reflect.Struct:
 | 
			
		||||
		if en, ok := rv.Interface().(encoder); ok {
 | 
			
		||||
			return en.Encode(buf)
 | 
			
		||||
		} else if en, ok := v.Interface().(encoder); ok {
 | 
			
		||||
			return en.Encode(buf)
 | 
			
		||||
		} else {
 | 
			
		||||
			for i := 0; i < v.NumField(); i++ {
 | 
			
		||||
				field := v.Field(i)
 | 
			
		||||
				n2, err := encodePacketValue(buf[n:], field)
 | 
			
		||||
				n += n2
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					return n, err
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	case reflect.Bool:
 | 
			
		||||
		if v.Bool() {
 | 
			
		||||
			buf[n] = 1
 | 
			
		||||
		} else {
 | 
			
		||||
			buf[n] = 0
 | 
			
		||||
		}
 | 
			
		||||
		n++
 | 
			
		||||
	case reflect.Int32:
 | 
			
		||||
		binary.BigEndian.PutUint32(buf[n:n+4], uint32(v.Int()))
 | 
			
		||||
		n += 4
 | 
			
		||||
	case reflect.Int64:
 | 
			
		||||
		binary.BigEndian.PutUint64(buf[n:n+8], uint64(v.Int()))
 | 
			
		||||
		n += 8
 | 
			
		||||
	case reflect.String:
 | 
			
		||||
		str := v.String()
 | 
			
		||||
		binary.BigEndian.PutUint32(buf[n:n+4], uint32(len(str)))
 | 
			
		||||
		copy(buf[n+4:n+4+len(str)], []byte(str))
 | 
			
		||||
		n += 4 + len(str)
 | 
			
		||||
	case reflect.Slice:
 | 
			
		||||
		switch v.Type().Elem().Kind() {
 | 
			
		||||
		default:
 | 
			
		||||
			count := v.Len()
 | 
			
		||||
			startN := n
 | 
			
		||||
			n += 4
 | 
			
		||||
			for i := 0; i < count; i++ {
 | 
			
		||||
				n2, err := encodePacketValue(buf[n:], v.Index(i))
 | 
			
		||||
				n += n2
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					return n, err
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			binary.BigEndian.PutUint32(buf[startN:startN+4], uint32(count))
 | 
			
		||||
		case reflect.Uint8:
 | 
			
		||||
			if v.IsNil() {
 | 
			
		||||
				binary.BigEndian.PutUint32(buf[n:n+4], uint32(0xffffffff))
 | 
			
		||||
				n += 4
 | 
			
		||||
			} else {
 | 
			
		||||
				bytes := v.Bytes()
 | 
			
		||||
				binary.BigEndian.PutUint32(buf[n:n+4], uint32(len(bytes)))
 | 
			
		||||
				copy(buf[n+4:n+4+len(bytes)], bytes)
 | 
			
		||||
				n += 4 + len(bytes)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return n, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func requestStructForOp(op int32) interface{} {
 | 
			
		||||
	switch op {
 | 
			
		||||
	case opClose:
 | 
			
		||||
		return &closeRequest{}
 | 
			
		||||
	case opCreate:
 | 
			
		||||
		return &CreateRequest{}
 | 
			
		||||
	case opDelete:
 | 
			
		||||
		return &DeleteRequest{}
 | 
			
		||||
	case opExists:
 | 
			
		||||
		return &existsRequest{}
 | 
			
		||||
	case opGetAcl:
 | 
			
		||||
		return &getAclRequest{}
 | 
			
		||||
	case opGetChildren:
 | 
			
		||||
		return &getChildrenRequest{}
 | 
			
		||||
	case opGetChildren2:
 | 
			
		||||
		return &getChildren2Request{}
 | 
			
		||||
	case opGetData:
 | 
			
		||||
		return &getDataRequest{}
 | 
			
		||||
	case opPing:
 | 
			
		||||
		return &pingRequest{}
 | 
			
		||||
	case opSetAcl:
 | 
			
		||||
		return &setAclRequest{}
 | 
			
		||||
	case opSetData:
 | 
			
		||||
		return &SetDataRequest{}
 | 
			
		||||
	case opSetWatches:
 | 
			
		||||
		return &setWatchesRequest{}
 | 
			
		||||
	case opSync:
 | 
			
		||||
		return &syncRequest{}
 | 
			
		||||
	case opSetAuth:
 | 
			
		||||
		return &setAuthRequest{}
 | 
			
		||||
	case opCheck:
 | 
			
		||||
		return &CheckVersionRequest{}
 | 
			
		||||
	case opMulti:
 | 
			
		||||
		return &multiRequest{}
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func responseStructForOp(op int32) interface{} {
 | 
			
		||||
	switch op {
 | 
			
		||||
	case opClose:
 | 
			
		||||
		return &closeResponse{}
 | 
			
		||||
	case opCreate:
 | 
			
		||||
		return &createResponse{}
 | 
			
		||||
	case opDelete:
 | 
			
		||||
		return &deleteResponse{}
 | 
			
		||||
	case opExists:
 | 
			
		||||
		return &existsResponse{}
 | 
			
		||||
	case opGetAcl:
 | 
			
		||||
		return &getAclResponse{}
 | 
			
		||||
	case opGetChildren:
 | 
			
		||||
		return &getChildrenResponse{}
 | 
			
		||||
	case opGetChildren2:
 | 
			
		||||
		return &getChildren2Response{}
 | 
			
		||||
	case opGetData:
 | 
			
		||||
		return &getDataResponse{}
 | 
			
		||||
	case opPing:
 | 
			
		||||
		return &pingResponse{}
 | 
			
		||||
	case opSetAcl:
 | 
			
		||||
		return &setAclResponse{}
 | 
			
		||||
	case opSetData:
 | 
			
		||||
		return &setDataResponse{}
 | 
			
		||||
	case opSetWatches:
 | 
			
		||||
		return &setWatchesResponse{}
 | 
			
		||||
	case opSync:
 | 
			
		||||
		return &syncResponse{}
 | 
			
		||||
	case opWatcherEvent:
 | 
			
		||||
		return &watcherEvent{}
 | 
			
		||||
	case opSetAuth:
 | 
			
		||||
		return &setAuthResponse{}
 | 
			
		||||
	// case opCheck:
 | 
			
		||||
	// 	return &checkVersionResponse{}
 | 
			
		||||
	case opMulti:
 | 
			
		||||
		return &multiResponse{}
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										148
									
								
								vendor/github.com/samuel/go-zookeeper/zk/tracer.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										148
									
								
								vendor/github.com/samuel/go-zookeeper/zk/tracer.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,148 @@
 | 
			
		||||
package zk
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"encoding/binary"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"io"
 | 
			
		||||
	"net"
 | 
			
		||||
	"sync"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	requests     = make(map[int32]int32) // Map of Xid -> Opcode
 | 
			
		||||
	requestsLock = &sync.Mutex{}
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func trace(conn1, conn2 net.Conn, client bool) {
 | 
			
		||||
	defer conn1.Close()
 | 
			
		||||
	defer conn2.Close()
 | 
			
		||||
	buf := make([]byte, 10*1024)
 | 
			
		||||
	init := true
 | 
			
		||||
	for {
 | 
			
		||||
		_, err := io.ReadFull(conn1, buf[:4])
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			fmt.Println("1>", client, err)
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		blen := int(binary.BigEndian.Uint32(buf[:4]))
 | 
			
		||||
 | 
			
		||||
		_, err = io.ReadFull(conn1, buf[4:4+blen])
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			fmt.Println("2>", client, err)
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		var cr interface{}
 | 
			
		||||
		opcode := int32(-1)
 | 
			
		||||
		readHeader := true
 | 
			
		||||
		if client {
 | 
			
		||||
			if init {
 | 
			
		||||
				cr = &connectRequest{}
 | 
			
		||||
				readHeader = false
 | 
			
		||||
			} else {
 | 
			
		||||
				xid := int32(binary.BigEndian.Uint32(buf[4:8]))
 | 
			
		||||
				opcode = int32(binary.BigEndian.Uint32(buf[8:12]))
 | 
			
		||||
				requestsLock.Lock()
 | 
			
		||||
				requests[xid] = opcode
 | 
			
		||||
				requestsLock.Unlock()
 | 
			
		||||
				cr = requestStructForOp(opcode)
 | 
			
		||||
				if cr == nil {
 | 
			
		||||
					fmt.Printf("Unknown opcode %d\n", opcode)
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		} else {
 | 
			
		||||
			if init {
 | 
			
		||||
				cr = &connectResponse{}
 | 
			
		||||
				readHeader = false
 | 
			
		||||
			} else {
 | 
			
		||||
				xid := int32(binary.BigEndian.Uint32(buf[4:8]))
 | 
			
		||||
				zxid := int64(binary.BigEndian.Uint64(buf[8:16]))
 | 
			
		||||
				errnum := int32(binary.BigEndian.Uint32(buf[16:20]))
 | 
			
		||||
				if xid != -1 || zxid != -1 {
 | 
			
		||||
					requestsLock.Lock()
 | 
			
		||||
					found := false
 | 
			
		||||
					opcode, found = requests[xid]
 | 
			
		||||
					if !found {
 | 
			
		||||
						opcode = 0
 | 
			
		||||
					}
 | 
			
		||||
					delete(requests, xid)
 | 
			
		||||
					requestsLock.Unlock()
 | 
			
		||||
				} else {
 | 
			
		||||
					opcode = opWatcherEvent
 | 
			
		||||
				}
 | 
			
		||||
				cr = responseStructForOp(opcode)
 | 
			
		||||
				if cr == nil {
 | 
			
		||||
					fmt.Printf("Unknown opcode %d\n", opcode)
 | 
			
		||||
				}
 | 
			
		||||
				if errnum != 0 {
 | 
			
		||||
					cr = &struct{}{}
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		opname := "."
 | 
			
		||||
		if opcode != -1 {
 | 
			
		||||
			opname = opNames[opcode]
 | 
			
		||||
		}
 | 
			
		||||
		if cr == nil {
 | 
			
		||||
			fmt.Printf("%+v %s %+v\n", client, opname, buf[4:4+blen])
 | 
			
		||||
		} else {
 | 
			
		||||
			n := 4
 | 
			
		||||
			hdrStr := ""
 | 
			
		||||
			if readHeader {
 | 
			
		||||
				var hdr interface{}
 | 
			
		||||
				if client {
 | 
			
		||||
					hdr = &requestHeader{}
 | 
			
		||||
				} else {
 | 
			
		||||
					hdr = &responseHeader{}
 | 
			
		||||
				}
 | 
			
		||||
				if n2, err := decodePacket(buf[n:n+blen], hdr); err != nil {
 | 
			
		||||
					fmt.Println(err)
 | 
			
		||||
				} else {
 | 
			
		||||
					n += n2
 | 
			
		||||
				}
 | 
			
		||||
				hdrStr = fmt.Sprintf(" %+v", hdr)
 | 
			
		||||
			}
 | 
			
		||||
			if _, err := decodePacket(buf[n:n+blen], cr); err != nil {
 | 
			
		||||
				fmt.Println(err)
 | 
			
		||||
			}
 | 
			
		||||
			fmt.Printf("%+v %s%s %+v\n", client, opname, hdrStr, cr)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		init = false
 | 
			
		||||
 | 
			
		||||
		written, err := conn2.Write(buf[:4+blen])
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			fmt.Println("3>", client, err)
 | 
			
		||||
			return
 | 
			
		||||
		} else if written != 4+blen {
 | 
			
		||||
			fmt.Printf("Written != read: %d != %d\n", written, blen)
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func handleConnection(addr string, conn net.Conn) {
 | 
			
		||||
	zkConn, err := net.Dial("tcp", addr)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		fmt.Println(err)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	go trace(conn, zkConn, true)
 | 
			
		||||
	trace(zkConn, conn, false)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func StartTracer(listenAddr, serverAddr string) {
 | 
			
		||||
	ln, err := net.Listen("tcp", listenAddr)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		panic(err)
 | 
			
		||||
	}
 | 
			
		||||
	for {
 | 
			
		||||
		conn, err := ln.Accept()
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			fmt.Println(err)
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		go handleConnection(serverAddr, conn)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										54
									
								
								vendor/github.com/samuel/go-zookeeper/zk/util.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								vendor/github.com/samuel/go-zookeeper/zk/util.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,54 @@
 | 
			
		||||
package zk
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"crypto/sha1"
 | 
			
		||||
	"encoding/base64"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"math/rand"
 | 
			
		||||
	"strconv"
 | 
			
		||||
	"strings"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// AuthACL produces an ACL list containing a single ACL which uses the
 | 
			
		||||
// provided permissions, with the scheme "auth", and ID "", which is used
 | 
			
		||||
// by ZooKeeper to represent any authenticated user.
 | 
			
		||||
func AuthACL(perms int32) []ACL {
 | 
			
		||||
	return []ACL{{perms, "auth", ""}}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// WorldACL produces an ACL list containing a single ACL which uses the
 | 
			
		||||
// provided permissions, with the scheme "world", and ID "anyone", which
 | 
			
		||||
// is used by ZooKeeper to represent any user at all.
 | 
			
		||||
func WorldACL(perms int32) []ACL {
 | 
			
		||||
	return []ACL{{perms, "world", "anyone"}}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func DigestACL(perms int32, user, password string) []ACL {
 | 
			
		||||
	userPass := []byte(fmt.Sprintf("%s:%s", user, password))
 | 
			
		||||
	h := sha1.New()
 | 
			
		||||
	if n, err := h.Write(userPass); err != nil || n != len(userPass) {
 | 
			
		||||
		panic("SHA1 failed")
 | 
			
		||||
	}
 | 
			
		||||
	digest := base64.StdEncoding.EncodeToString(h.Sum(nil))
 | 
			
		||||
	return []ACL{{perms, "digest", fmt.Sprintf("%s:%s", user, digest)}}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// FormatServers takes a slice of addresses, and makes sure they are in a format
 | 
			
		||||
// that resembles <addr>:<port>. If the server has no port provided, the
 | 
			
		||||
// DefaultPort constant is added to the end.
 | 
			
		||||
func FormatServers(servers []string) []string {
 | 
			
		||||
	for i := range servers {
 | 
			
		||||
		if !strings.Contains(servers[i], ":") {
 | 
			
		||||
			servers[i] = servers[i] + ":" + strconv.Itoa(DefaultPort)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return servers
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// stringShuffle performs a Fisher-Yates shuffle on a slice of strings
 | 
			
		||||
func stringShuffle(s []string) {
 | 
			
		||||
	for i := len(s) - 1; i > 0; i-- {
 | 
			
		||||
		j := rand.Intn(i + 1)
 | 
			
		||||
		s[i], s[j] = s[j], s[i]
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user