func isHaltErr(ctx context.Context, err error) bool {
	if ctx != nil && ctx.Err() != nil {
		return true
	}
	if err == nil {
		return false
	}
	ev, _ := status.FromError(err)
	// Unavailable codes mean the system will be right back.
	// (e.g., can't connect, lost leader)
	// Treat Internal codes as if something failed, leaving the
	// system in an inconsistent state, but retrying could make progress.
	// (e.g., failed in middle of send, corrupted frame)
	// TODO: are permanent Internal errors possible from grpc?
	return ev.Code() != codes.Unavailable && ev.Code() != codes.Internal
}

// isHaltErr returns true if the given error and context indicate no forward
// progress can be made, even after reconnecting.

isHaltErr returns true if the given error and context indicate no forward progress can be made even after reconnecting .


func NewLease(l clientv3.Lease, prefix string) clientv3.Lease {
	return &leasePrefix{l, []byte(prefix)}
}

func NewLease ( l clientv3 . Lease , prefix string ) clientv3 . Lease { return & leasePrefix { l , [ ] byte ( prefix ) } }

// NewLease wraps a Lease interface to filter for only keys with a prefix
// and remove that prefix when fetching attached keys through TimeToLive.

NewLease wraps a Lease interface to filter for only keys with a prefix and remove that prefix when fetching attached keys through TimeToLive .


func (e *Event) IsCreate() bool {
	return e.Type == EventTypePut && e.Kv.CreateRevision == e.Kv.ModRevision
}

func ( e * Event ) IsCreate ( ) bool { return e . Type == EventTypePut && e . Kv . CreateRevision == e . Kv . ModRevision }

// IsCreate returns true if the event tells that the key is newly created.

IsCreate returns true if the event tells that the key is newly created .


func (wr *WatchResponse) Err() error {
	switch {
	case wr.closeErr != nil:
		return v3rpc.Error(wr.closeErr)
	case wr.CompactRevision != 0:
		return v3rpc.ErrCompacted
	case wr.Canceled:
		if len(wr.cancelReason) != 0 {
			return v3rpc.Error(status.Error(codes.FailedPrecondition, wr.cancelReason))
		}
		return v3rpc.ErrFutureRev
	}
	return nil
}

func ( wr * WatchResponse ) Err ( ) error { switch { case wr . closeErr != nil : return v3rpc . Error ( wr . closeErr ) case wr . CompactRevision != 0 : return v3rpc . ErrCompacted case wr . Canceled : if len ( wr . cancelReason ) != 0 { return v3rpc . Error ( status . Error ( codes . FailedPrecondition , wr . cancelReason ) ) } return v3rpc . ErrFutureRev } return nil }

// Err is the error value if this WatchResponse holds an error.

Err is the error value if this WatchResponse holds an error .


func (wr *WatchResponse) IsProgressNotify() bool {
	return len(wr.Events) == 0 && !wr.Canceled && !wr.Created && wr.CompactRevision == 0 && wr.Header.Revision != 0
}

func ( wr * WatchResponse ) IsProgressNotify ( ) bool { return len ( wr . Events ) == 0 && ! wr . Canceled && ! wr . Created && wr . CompactRevision == 0 && wr . Header . Revision != 0 }

// IsProgressNotify returns true if the WatchResponse is progress notification.

IsProgressNotify returns true if the WatchResponse is progress notification .


func (w *watcher) RequestProgress(ctx context.Context) (err error) {
	ctxKey := streamKeyFromCtx(ctx)

	w.mu.Lock()
	if w.streams == nil {
		return fmt.Errorf("no stream found for context")
	}
	wgs := w.streams[ctxKey]
	if wgs == nil {
		wgs = w.newWatcherGrpcStream(ctx)
		w.streams[ctxKey] = wgs
	}
	donec := wgs.donec
	reqc := wgs.reqc
	w.mu.Unlock()

	pr := &progressRequest{}

	select {
	case reqc <- pr:
		return nil
	case <-ctx.Done():
		if err == nil {
			return ctx.Err()
		}
		return err
	case <-donec:
		if wgs.closeErr != nil {
			return wgs.closeErr
		}
		// retry; may have dropped stream from no ctxs
		return w.RequestProgress(ctx)
	}
}

// RequestProgress requests a progress notify response be sent in all watch channels.

RequestProgress requests a progress notify response be sent in all watch channels .


func (w *watchGrpcStream) nextResume() *watcherStream {
	for len(w.resuming) != 0 {
		if w.resuming[0] != nil {
			return w.resuming[0]
		}
		w.resuming = w.resuming[1:len(w.resuming)]
	}
	return nil
}

func ( w * watchGrpcStream ) nextResume ( ) * watcherStream { for len ( w . resuming ) != 0 { if w . resuming [ 0 ] != nil { return w . resuming [ 0 ] } w . resuming = w . resuming [ 1 : len ( w . resuming ) ] } return nil }

// nextResume chooses the next resuming to register with the grpc stream. Abandoned
// streams are marked as nil in the queue since the head must wait for its inflight registration.

nextResume chooses the next resuming to register with the grpc stream . Abandoned streams are marked as nil in the queue since the head must wait for its inflight registration .


func (w *watchGrpcStream) dispatchEvent(pbresp *pb.WatchResponse) bool {
	events := make([]*Event, len(pbresp.Events))
	for i, ev := range pbresp.Events {
		events[i] = (*Event)(ev)
	}
	// TODO: return watch ID?
	wr := &WatchResponse{
		Header:          *pbresp.Header,
		Events:          events,
		CompactRevision: pbresp.CompactRevision,
		Created:         pbresp.Created,
		Canceled:        pbresp.Canceled,
		cancelReason:    pbresp.CancelReason,
	}

	// watch IDs are zero indexed, so request notify watch responses are assigned a watch ID of -1 to
	// indicate they should be broadcast.
	if wr.IsProgressNotify() && pbresp.WatchId == -1 {
		return w.broadcastResponse(wr)
	}

	return w.unicastResponse(wr, pbresp.WatchId)

}

// dispatchEvent sends a WatchResponse to the appropriate watcher stream


func (w *watchGrpcStream) broadcastResponse(wr *WatchResponse) bool {
	for _, ws := range w.substreams {
		select {
		case ws.recvc <- wr:
		case <-ws.donec:
		}
	}
	return true
}

func ( w * watchGrpcStream ) broadcastResponse ( wr * WatchResponse ) bool { for _ , ws := range w . substreams { select { case ws . recvc <- wr : case <- ws . donec : } } return true }

// broadcastResponse send a watch response to all watch substreams.

broadcastResponse send a watch response to all watch substreams .


func (w *watchGrpcStream) unicastResponse(wr *WatchResponse, watchId int64) bool {
	ws, ok := w.substreams[watchId]
	if !ok {
		return false
	}
	select {
	case ws.recvc <- wr:
	case <-ws.donec:
		return false
	}
	return true
}

func ( w * watchGrpcStream ) unicastResponse ( wr * WatchResponse , watchId int64 ) bool { ws , ok := w . substreams [ watchId ] if ! ok { return false } select { case ws . recvc <- wr : case <- ws . donec : return false } return true }

// unicastResponse sends a watch response to a specific watch substream.

unicastResponse sends a watch response to a specific watch substream .


func (w *watchGrpcStream) joinSubstreams() {
	for _, ws := range w.substreams {
		<-ws.donec
	}
	for _, ws := range w.resuming {
		if ws != nil {
			<-ws.donec
		}
	}
}

func ( w * watchGrpcStream ) joinSubstreams ( ) { for _ , ws := range w . substreams { <- ws . donec } for _ , ws := range w . resuming { if ws != nil { <- ws . donec } } }

// joinSubstreams waits for all substream goroutines to complete.

joinSubstreams waits for all substream goroutines to complete .


func (wr *watchRequest) toPB() *pb.WatchRequest {
	req := &pb.WatchCreateRequest{
		StartRevision:  wr.rev,
		Key:            []byte(wr.key),
		RangeEnd:       []byte(wr.end),
		ProgressNotify: wr.progressNotify,
		Filters:        wr.filters,
		PrevKv:         wr.prevKV,
		Fragment:       wr.fragment,
	}
	cr := &pb.WatchRequest_CreateRequest{CreateRequest: req}
	return &pb.WatchRequest{RequestUnion: cr}
}

func ( wr * watchRequest ) toPB ( ) * pb . WatchRequest { req := & pb . WatchCreateRequest { StartRevision : wr . rev , Key : [ ] byte ( wr . key ) , RangeEnd : [ ] byte ( wr . end ) , ProgressNotify : wr . progressNotify , Filters : wr . filters , PrevKv : wr . prevKV , Fragment : wr . fragment , } cr := & pb . WatchRequest_CreateRequest { CreateRequest : req } return & pb . WatchRequest { RequestUnion : cr } }

// toPB converts an internal watch request structure to its protobuf WatchRequest structure.

toPB converts an internal watch request structure to its protobuf WatchRequest structure .


func (pr *progressRequest) toPB() *pb.WatchRequest {
	req := &pb.WatchProgressRequest{}
	cr := &pb.WatchRequest_ProgressRequest{ProgressRequest: req}
	return &pb.WatchRequest{RequestUnion: cr}
}

func ( pr * progressRequest ) toPB ( ) * pb . WatchRequest { req := & pb . WatchProgressRequest { } cr := & pb . WatchRequest_ProgressRequest { ProgressRequest : req } return & pb . WatchRequest { RequestUnion : cr } }

// toPB converts an internal progress request structure to its protobuf WatchRequest structure.

toPB converts an internal progress request structure to its protobuf WatchRequest structure .


func (us *unsafeSet) Contains(value string) (exists bool) {
	_, exists = us.d[value]
	return exists
}

func ( us * unsafeSet ) Contains ( value string ) ( exists bool ) { _ , exists = us . d [ value ] return exists }

// Contains returns whether the set contains the given value


func (us *unsafeSet) ContainsAll(values []string) bool {
	for _, s := range values {
		if !us.Contains(s) {
			return false
		}
	}
	return true
}

func ( us * unsafeSet ) ContainsAll ( values [ ] string ) bool { for _ , s := range values { if ! us . Contains ( s ) { return false } } return true }

// ContainsAll returns whether the set contains all given values


func (us *unsafeSet) Equals(other Set) bool {
	v1 := sort.StringSlice(us.Values())
	v2 := sort.StringSlice(other.Values())
	v1.Sort()
	v2.Sort()
	return reflect.DeepEqual(v1, v2)
}

func ( us * unsafeSet ) Equals ( other Set ) bool { v1 := sort . StringSlice ( us . Values ( ) ) v2 := sort . StringSlice ( other . Values ( ) ) v1 . Sort ( ) v2 . Sort ( ) return reflect . DeepEqual ( v1 , v2 ) }

// Equals returns whether the contents of two sets are identical


func (us *unsafeSet) Values() (values []string) {
	values = make([]string, 0)
	for val := range us.d {
		values = append(values, val)
	}
	return values
}

func ( us * unsafeSet ) Values ( ) ( values [ ] string ) { values = make ( [ ] string , 0 ) for val := range us . d { values = append ( values , val ) } return values }

// Values returns the values of the Set in an unspecified order.

Values returns the values of the Set in an unspecified order .


func (us *unsafeSet) Copy() Set {
	cp := NewUnsafeSet()
	for val := range us.d {
		cp.Add(val)
	}

	return cp
}

func ( us * unsafeSet ) Copy ( ) Set { cp := NewUnsafeSet ( ) for val := range us . d { cp . Add ( val ) } return cp }

// Copy creates a new Set containing the values of the first


func (us *unsafeSet) Sub(other Set) Set {
	oValues := other.Values()
	result := us.Copy().(*unsafeSet)

	for _, val := range oValues {
		if _, ok := result.d[val]; !ok {
			continue
		}
		delete(result.d, val)
	}

	return result
}

func ( us * unsafeSet ) Sub ( other Set ) Set { oValues := other . Values ( ) result := us . Copy ( ) . ( * unsafeSet ) for _ , val := range oValues { if _ , ok := result . d [ val ] ; ! ok { continue } delete ( result . d , val ) } return result }

// Sub removes all elements in other from the set


func v2MembersURL(ep url.URL) *url.URL {
	ep.Path = path.Join(ep.Path, defaultV2MembersPrefix)
	return &ep
}

func v2MembersURL ( ep url . URL ) * url . URL { ep . Path = path . Join ( ep . Path , defaultV2MembersPrefix ) return & ep }

// v2MembersURL add the necessary path to the provided endpoint
// to route requests to the default v2 members API.

v2MembersURL add the necessary path to the provided endpoint to route requests to the default v2 members API .


func NewMigrateCommand() *cobra.Command {
	mc := &cobra.Command{
		Use:   "migrate",
		Short: "Migrates keys in a v2 store to a mvcc store",
		Run:   migrateCommandFunc,
	}

	mc.Flags().BoolVar(&migrateExcludeTTLKey, "no-ttl", false, "Do not convert TTL keys")
	mc.Flags().StringVar(&migrateDatadir, "data-dir", "", "Path to the data directory")
	mc.Flags().StringVar(&migrateWALdir, "wal-dir", "", "Path to the WAL directory")
	mc.Flags().StringVar(&migrateTransformer, "transformer", "", "Path to the user-provided transformer program")
	return mc
}

func NewMigrateCommand ( ) * cobra . Command { mc := & cobra . Command { Use : " " , Short : " " , Run : migrateCommandFunc , } mc . Flags ( ) . BoolVar ( & migrateExcludeTTLKey , " " , false , " " ) mc . Flags ( ) . StringVar ( & migrateDatadir , " " , " " , " " ) mc . Flags ( ) . StringVar ( & migrateWALdir , " " , " " , " " ) mc . Flags ( ) . StringVar ( & migrateTransformer , " " , " " , " " ) return mc }

// NewMigrateCommand returns the cobra command for "migrate".

NewMigrateCommand returns the cobra command for migrate .


func (rc *raftNode) publishEntries(ents []raftpb.Entry) bool {
	for i := range ents {
		switch ents[i].Type {
		case raftpb.EntryNormal:
			if len(ents[i].Data) == 0 {
				// ignore empty messages
				break
			}
			s := string(ents[i].Data)
			select {
			case rc.commitC <- &s:
			case <-rc.stopc:
				return false
			}

		case raftpb.EntryConfChange:
			var cc raftpb.ConfChange
			cc.Unmarshal(ents[i].Data)
			rc.confState = *rc.node.ApplyConfChange(cc)
			switch cc.Type {
			case raftpb.ConfChangeAddNode:
				if len(cc.Context) > 0 {
					rc.transport.AddPeer(types.ID(cc.NodeID), []string{string(cc.Context)})
				}
			case raftpb.ConfChangeRemoveNode:
				if cc.NodeID == uint64(rc.id) {
					log.Println("I've been removed from the cluster! Shutting down.")
					return false
				}
				rc.transport.RemovePeer(types.ID(cc.NodeID))
			}
		}

		// after commit, update appliedIndex
		rc.appliedIndex = ents[i].Index

		// special nil commit to signal replay has finished
		if ents[i].Index == rc.lastIndex {
			select {
			case rc.commitC <- nil:
			case <-rc.stopc:
				return false
			}
		}
	}
	return true
}

// publishEntries writes committed log entries to commit channel and returns
// whether all entries could be published.

publishEntries writes committed log entries to commit channel and returns whether all entries could be published .


func (rc *raftNode) openWAL(snapshot *raftpb.Snapshot) *wal.WAL {
	if !wal.Exist(rc.waldir) {
		if err := os.Mkdir(rc.waldir, 0750); err != nil {
			log.Fatalf("raftexample: cannot create dir for wal (%v)", err)
		}

		w, err := wal.Create(zap.NewExample(), rc.waldir, nil)
		if err != nil {
			log.Fatalf("raftexample: create wal error (%v)", err)
		}
		w.Close()
	}

	walsnap := walpb.Snapshot{}
	if snapshot != nil {
		walsnap.Index, walsnap.Term = snapshot.Metadata.Index, snapshot.Metadata.Term
	}
	log.Printf("loading WAL at term %d and index %d", walsnap.Term, walsnap.Index)
	w, err := wal.Open(zap.NewExample(), rc.waldir, walsnap)
	if err != nil {
		log.Fatalf("raftexample: error loading wal (%v)", err)
	}

	return w
}

func ( rc * raftNode ) openWAL ( snapshot * raftpb . Snapshot ) * wal . WAL { if ! wal . Exist ( rc . waldir ) { if err := os . Mkdir ( rc . waldir , 0750 ) ; err != nil { log . Fatalf ( " " , err ) } w , err := wal . Create ( zap . NewExample ( ) , rc . waldir , nil ) if err != nil { log . Fatalf ( " " , err ) } w . Close ( ) } walsnap := walpb . Snapshot { } if snapshot != nil { walsnap . Index , walsnap . Term = snapshot . Metadata . Index , snapshot . Metadata . Term } log . Printf ( " " , walsnap . Term , walsnap . Index ) w , err := wal . Open ( zap . NewExample ( ) , rc . waldir , walsnap ) if err != nil { log . Fatalf ( " " , err ) } return w }

// openWAL returns a WAL ready for reading.

openWAL returns a WAL ready for reading .


func (rc *raftNode) replayWAL() *wal.WAL {
	log.Printf("replaying WAL of member %d", rc.id)
	snapshot := rc.loadSnapshot()
	w := rc.openWAL(snapshot)
	_, st, ents, err := w.ReadAll()
	if err != nil {
		log.Fatalf("raftexample: failed to read WAL (%v)", err)
	}
	rc.raftStorage = raft.NewMemoryStorage()
	if snapshot != nil {
		rc.raftStorage.ApplySnapshot(*snapshot)
	}
	rc.raftStorage.SetHardState(st)

	// append to storage so raft starts at the right place in log
	rc.raftStorage.Append(ents)
	// send nil once lastIndex is published so client knows commit channel is current
	if len(ents) > 0 {
		rc.lastIndex = ents[len(ents)-1].Index
	} else {
		rc.commitC <- nil
	}
	return w
}

// replayWAL replays WAL entries into the raft instance.

replayWAL replays WAL entries into the raft instance .


func (rc *raftNode) stop() {
	rc.stopHTTP()
	close(rc.commitC)
	close(rc.errorC)
	rc.node.Stop()
}

func ( rc * raftNode ) stop ( ) { rc . stopHTTP ( ) close ( rc . commitC ) close ( rc . errorC ) rc . node . Stop ( ) }

// stop closes http, closes all channels, and stops raft.

stop closes http closes all channels and stops raft .


func NewWatchCommand() *cobra.Command {
	cmd := &cobra.Command{
		Use:   "watch [options] [key or prefix] [range_end] [--] [exec-command arg1 arg2 ...]",
		Short: "Watches events stream on keys or prefixes",
		Run:   watchCommandFunc,
	}

	cmd.Flags().BoolVarP(&watchInteractive, "interactive", "i", false, "Interactive mode")
	cmd.Flags().BoolVar(&watchPrefix, "prefix", false, "Watch on a prefix if prefix is set")
	cmd.Flags().Int64Var(&watchRev, "rev", 0, "Revision to start watching")
	cmd.Flags().BoolVar(&watchPrevKey, "prev-kv", false, "get the previous key-value pair before the event happens")

	return cmd
}

func NewWatchCommand ( ) * cobra . Command { cmd := & cobra . Command { Use : " " , Short : " " , Run : watchCommandFunc , } cmd . Flags ( ) . BoolVarP ( & watchInteractive , " " , " " , false , " " ) cmd . Flags ( ) . BoolVar ( & watchPrefix , " " , false , " " ) cmd . Flags ( ) . Int64Var ( & watchRev , " " , 0 , " " ) cmd . Flags ( ) . BoolVar ( & watchPrevKey , " " , false , " " ) return cmd }

// NewWatchCommand returns the cobra command for "watch".

NewWatchCommand returns the cobra command for watch .


func (ms *MemoryStorage) InitialState() (pb.HardState, pb.ConfState, error) {
	return ms.hardState, ms.snapshot.Metadata.ConfState, nil
}

func ( ms * MemoryStorage ) InitialState ( ) ( pb . HardState , pb . ConfState , error ) { return ms . hardState , ms . snapshot . Metadata . ConfState , nil }

// InitialState implements the Storage interface.

InitialState implements the Storage interface .


func (ms *MemoryStorage) SetHardState(st pb.HardState) error {
	ms.Lock()
	defer ms.Unlock()
	ms.hardState = st
	return nil
}

func ( ms * MemoryStorage ) SetHardState ( st pb . HardState ) error { ms . Lock ( ) defer ms . Unlock ( ) ms . hardState = st return nil }

// SetHardState saves the current HardState.

SetHardState saves the current HardState .


func (ms *MemoryStorage) Entries(lo, hi, maxSize uint64) ([]pb.Entry, error) {
	ms.Lock()
	defer ms.Unlock()
	offset := ms.ents[0].Index
	if lo <= offset {
		return nil, ErrCompacted
	}
	if hi > ms.lastIndex()+1 {
		raftLogger.Panicf("entries' hi(%d) is out of bound lastindex(%d)", hi, ms.lastIndex())
	}
	// only contains dummy entries.
	if len(ms.ents) == 1 {
		return nil, ErrUnavailable
	}

	ents := ms.ents[lo-offset : hi-offset]
	return limitSize(ents, maxSize), nil
}

func
(
ms
*
MemoryStorage
)
Entries
(
lo
,
hi
,
maxSize
uint64
)
(
[
]
pb
.
Entry
,
error
)
{
ms
.
Lock
(
)
defer
ms
.
Unlock
(
)
offset
:=
ms
.
ents
[
0
]
.
Index
if
lo
<=
offset
{
return
,
ErrCompacted
}
if
hi
>
ms
.
lastIndex
(
)
+
1
{
raftLogger
.
Panicf
(
"
"
,
hi
,
ms
.
lastIndex
(
)
)
}
// only contains dummy entries.
if
len
(
ms
.
ents
)
==
1
{
return
,
ErrUnavailable
}
ents
:=
ms
.
ents
[
lo
offset
:
hi
offset
]
return
limitSize
(
ents
,
maxSize
)
,
}

// Entries implements the Storage interface.

Entries implements the Storage interface .


func (ms *MemoryStorage) Term(i uint64) (uint64, error) {
	ms.Lock()
	defer ms.Unlock()
	offset := ms.ents[0].Index
	if i < offset {
		return 0, ErrCompacted
	}
	if int(i-offset) >= len(ms.ents) {
		return 0, ErrUnavailable
	}
	return ms.ents[i-offset].Term, nil
}

func ( ms * MemoryStorage ) Term ( i uint64 ) ( uint64 , error ) { ms . Lock ( ) defer ms . Unlock ( ) offset := ms . ents [ 0 ] . Index if i < offset { return 0 , ErrCompacted } if int ( i - offset ) >= len ( ms . ents ) { return 0 , ErrUnavailable } return ms . ents [ i - offset ] . Term , nil }

// Term implements the Storage interface.


func (ms *MemoryStorage) LastIndex() (uint64, error) {
	ms.Lock()
	defer ms.Unlock()
	return ms.lastIndex(), nil
}

func ( ms * MemoryStorage ) LastIndex ( ) ( uint64 , error ) { ms . Lock ( ) defer ms . Unlock ( ) return ms . lastIndex ( ) , nil }

// LastIndex implements the Storage interface.

LastIndex implements the Storage interface .


func (ms *MemoryStorage) FirstIndex() (uint64, error) {
	ms.Lock()
	defer ms.Unlock()
	return ms.firstIndex(), nil
}

func ( ms * MemoryStorage ) FirstIndex ( ) ( uint64 , error ) { ms . Lock ( ) defer ms . Unlock ( ) return ms . firstIndex ( ) , nil }

// FirstIndex implements the Storage interface.

FirstIndex implements the Storage interface .


func (ms *MemoryStorage) Snapshot() (pb.Snapshot, error) {
	ms.Lock()
	defer ms.Unlock()
	return ms.snapshot, nil
}

func ( ms * MemoryStorage ) Snapshot ( ) ( pb . Snapshot , error ) { ms . Lock ( ) defer ms . Unlock ( ) return ms . snapshot , nil }

// Snapshot implements the Storage interface.

Snapshot implements the Storage interface .


func (ms *MemoryStorage) ApplySnapshot(snap pb.Snapshot) error {
	ms.Lock()
	defer ms.Unlock()

	//handle check for old snapshot being applied
	msIndex := ms.snapshot.Metadata.Index
	snapIndex := snap.Metadata.Index
	if msIndex >= snapIndex {
		return ErrSnapOutOfDate
	}

	ms.snapshot = snap
	ms.ents = []pb.Entry{{Term: snap.Metadata.Term, Index: snap.Metadata.Index}}
	return nil
}

// ApplySnapshot overwrites the contents of this Storage object with
// those of the given snapshot.

ApplySnapshot overwrites the contents of this Storage object with those of the given snapshot .


func (ms *MemoryStorage) Compact(compactIndex uint64) error {
	ms.Lock()
	defer ms.Unlock()
	offset := ms.ents[0].Index
	if compactIndex <= offset {
		return ErrCompacted
	}
	if compactIndex > ms.lastIndex() {
		raftLogger.Panicf("compact %d is out of bound lastindex(%d)", compactIndex, ms.lastIndex())
	}

	i := compactIndex - offset
	ents := make([]pb.Entry, 1, 1+uint64(len(ms.ents))-i)
	ents[0].Index = ms.ents[i].Index
	ents[0].Term = ms.ents[i].Term
	ents = append(ents, ms.ents[i+1:]...)
	ms.ents = ents
	return nil
}

func ( ms * MemoryStorage ) Compact ( compactIndex uint64 ) error { ms . Lock ( ) defer ms . Unlock ( ) offset := ms . ents [ 0 ] . Index if compactIndex <= offset { return ErrCompacted } if compactIndex > ms . lastIndex ( ) { raftLogger . Panicf ( " " , compactIndex , ms . lastIndex ( ) ) } i := compactIndex - offset ents := make ( [ ] pb . Entry , 1 , 1 + uint64 ( len ( ms . ents ) ) - i ) ents [ 0 ] . Index = ms . ents [ i ] . Index ents [ 0 ] . Term = ms . ents [ i ] . Term ents = append ( ents , ms . ents [ i + 1 : ] ... ) ms . ents = ents return nil }

// Compact discards all log entries prior to compactIndex.
// It is the application's responsibility to not attempt to compact an index
// greater than raftLog.applied.

Compact discards all log entries prior to compactIndex . It is the application s responsibility to not attempt to compact an index greater than raftLog . applied .


func (p *urlPicker) unreachable(u url.URL) {
	p.mu.Lock()
	defer p.mu.Unlock()
	if u == p.urls[p.picked] {
		p.picked = (p.picked + 1) % len(p.urls)
	}
}

func ( p * urlPicker ) unreachable ( u url . URL ) { p . mu . Lock ( ) defer p . mu . Unlock ( ) if u == p . urls [ p . picked ] { p . picked = ( p . picked + 1 ) % len ( p . urls ) } }

// unreachable notices the picker that the given url is unreachable,
// and it should use other possible urls.

unreachable notices the picker that the given url is unreachable and it should use other possible urls .


func NewEndpointCommand() *cobra.Command {
	ec := &cobra.Command{
		Use:   "endpoint <subcommand>",
		Short: "Endpoint related commands",
	}

	ec.PersistentFlags().BoolVar(&epClusterEndpoints, "cluster", false, "use all endpoints from the cluster member list")
	ec.AddCommand(newEpHealthCommand())
	ec.AddCommand(newEpStatusCommand())
	ec.AddCommand(newEpHashKVCommand())

	return ec
}

func NewEndpointCommand ( ) * cobra . Command { ec := & cobra . Command { Use : " " , Short : " " , } ec . PersistentFlags ( ) . BoolVar ( & epClusterEndpoints , " " , false , " " ) ec . AddCommand ( newEpHealthCommand ( ) ) ec . AddCommand ( newEpStatusCommand ( ) ) ec . AddCommand ( newEpHashKVCommand ( ) ) return ec }

// NewEndpointCommand returns the cobra command for "endpoint".

NewEndpointCommand returns the cobra command for endpoint .


func epHealthCommandFunc(cmd *cobra.Command, args []string) {
	flags.SetPflagsFromEnv("ETCDCTL", cmd.InheritedFlags())
	initDisplayFromCmd(cmd)

	sec := secureCfgFromCmd(cmd)
	dt := dialTimeoutFromCmd(cmd)
	ka := keepAliveTimeFromCmd(cmd)
	kat := keepAliveTimeoutFromCmd(cmd)
	auth := authCfgFromCmd(cmd)
	cfgs := []*v3.Config{}
	for _, ep := range endpointsFromCluster(cmd) {
		cfg, err := newClientCfg([]string{ep}, dt, ka, kat, sec, auth)
		if err != nil {
			ExitWithError(ExitBadArgs, err)
		}
		cfgs = append(cfgs, cfg)
	}

	var wg sync.WaitGroup
	hch := make(chan epHealth, len(cfgs))
	for _, cfg := range cfgs {
		wg.Add(1)
		go func(cfg *v3.Config) {
			defer wg.Done()
			ep := cfg.Endpoints[0]
			cli, err := v3.New(*cfg)
			if err != nil {
				hch <- epHealth{Ep: ep, Health: false, Error: err.Error()}
				return
			}
			st := time.Now()
			// get a random key. As long as we can get the response without an error, the
			// endpoint is health.
			ctx, cancel := commandCtx(cmd)
			_, err = cli.Get(ctx, "health")
			cancel()
			eh := epHealth{Ep: ep, Health: false, Took: time.Since(st).String()}
			// permission denied is OK since proposal goes through consensus to get it
			if err == nil || err == rpctypes.ErrPermissionDenied {
				eh.Health = true
			} else {
				eh.Error = err.Error()
			}
			hch <- eh
		}(cfg)
	}

	wg.Wait()
	close(hch)

	errs := false
	healthList := []epHealth{}
	for h := range hch {
		healthList = append(healthList, h)
		if h.Error != "" {
			errs = true
		}
	}
	display.EndpointHealth(healthList)
	if errs {
		ExitWithError(ExitError, fmt.Errorf("unhealthy cluster"))
	}
}

// epHealthCommandFunc executes the "endpoint-health" command.

epHealthCommandFunc executes the endpoint - health command .


func NewElectCommand() *cobra.Command {
	cmd := &cobra.Command{
		Use:   "elect <election-name> [proposal]",
		Short: "Observes and participates in leader election",
		Run:   electCommandFunc,
	}
	cmd.Flags().BoolVarP(&electListen, "listen", "l", false, "observation mode")
	return cmd
}

func NewElectCommand ( ) * cobra . Command { cmd := & cobra . Command { Use : " " , Short : " " , Run : electCommandFunc , } cmd . Flags ( ) . BoolVarP ( & electListen , " " , " " , false , " " ) return cmd }

// NewElectCommand returns the cobra command for "elect".

NewElectCommand returns the cobra command for elect .


func NewDefragCommand() *cobra.Command {
	cmd := &cobra.Command{
		Use:   "defrag",
		Short: "Defragments the storage of the etcd members with given endpoints",
		Run:   defragCommandFunc,
	}
	cmd.PersistentFlags().BoolVar(&epClusterEndpoints, "cluster", false, "use all endpoints from the cluster member list")
	cmd.Flags().StringVar(&defragDataDir, "data-dir", "", "Optional. If present, defragments a data directory not in use by etcd.")
	return cmd
}

func NewDefragCommand ( ) * cobra . Command { cmd := & cobra . Command { Use : " " , Short : " " , Run : defragCommandFunc , } cmd . PersistentFlags ( ) . BoolVar ( & epClusterEndpoints , " " , false , " " ) cmd . Flags ( ) . StringVar ( & defragDataDir , " " , " " , " " ) return cmd }

// NewDefragCommand returns the cobra command for "Defrag".

NewDefragCommand returns the cobra command for Defrag .


func RegisterBuilder(cfg Config) {
	bb := &builder{cfg}
	balancer.Register(bb)

	bb.cfg.Logger.Debug(
		"registered balancer",
		zap.String("policy", bb.cfg.Policy.String()),
		zap.String("name", bb.cfg.Name),
	)
}

func RegisterBuilder ( cfg Config ) { bb := & builder { cfg } balancer . Register ( bb ) bb . cfg . Logger . Debug ( " " , zap . String ( " " , bb . cfg . Policy . String ( ) ) , zap . String ( " " , bb . cfg . Name ) , ) }

// RegisterBuilder creates and registers a builder. Since this function calls balancer.Register, it
// must be invoked at initialization time.

RegisterBuilder creates and registers a builder . Since this function calls balancer . Register it must be invoked at initialization time .


func (b *builder) Build(cc balancer.ClientConn, opt balancer.BuildOptions) balancer.Balancer {
	bb := &baseBalancer{
		id:     strconv.FormatInt(time.Now().UnixNano(), 36),
		policy: b.cfg.Policy,
		name:   b.cfg.Name,
		lg:     b.cfg.Logger,

		addrToSc: make(map[resolver.Address]balancer.SubConn),
		scToAddr: make(map[balancer.SubConn]resolver.Address),
		scToSt:   make(map[balancer.SubConn]connectivity.State),

		currentConn: nil,
		csEvltr:     &connectivityStateEvaluator{},

		// initialize picker always returns "ErrNoSubConnAvailable"
		Picker: picker.NewErr(balancer.ErrNoSubConnAvailable),
	}
	if bb.lg == nil {
		bb.lg = zap.NewNop()
	}

	// TODO: support multiple connections
	bb.mu.Lock()
	bb.currentConn = cc
	bb.mu.Unlock()

	bb.lg.Info(
		"built balancer",
		zap.String("balancer-id", bb.id),
		zap.String("policy", bb.policy.String()),
		zap.String("resolver-target", cc.Target()),
	)
	return bb
}

// Build is called initially when creating "ccBalancerWrapper".
// "grpc.Dial" is called to this client connection.
// Then, resolved addresses will be handled via "HandleResolvedAddrs".

Build is called initially when creating ccBalancerWrapper . grpc . Dial is called to this client connection . Then resolved addresses will be handled via HandleResolvedAddrs .


func (cse *connectivityStateEvaluator) recordTransition(oldState, newState connectivity.State) connectivity.State {
	// Update counters.
	for idx, state := range []connectivity.State{oldState, newState} {
		updateVal := 2*uint64(idx) - 1 // -1 for oldState and +1 for new.
		switch state {
		case connectivity.Ready:
			cse.numReady += updateVal
		case connectivity.Connecting:
			cse.numConnecting += updateVal
		case connectivity.TransientFailure:
			cse.numTransientFailure += updateVal
		}
	}

	// Evaluate.
	if cse.numReady > 0 {
		return connectivity.Ready
	}
	if cse.numConnecting > 0 {
		return connectivity.Connecting
	}
	return connectivity.TransientFailure
}

func
(
cse
*
connectivityStateEvaluator
)
recordTransition
(
oldState
,
newState
connectivity
.
State
)
connectivity
.
State
{
// Update counters.
for
idx
,
state
:=
range
[
]
connectivity
.
State
{
oldState
,
newState
}
{
updateVal
:=
2
*
uint64
(
idx
)
1
// -1 for oldState and +1 for new.
switch
state
{
case
connectivity
.
Ready
:
cse
.
numReady
+=
updateVal
case
connectivity
.
Connecting
:
cse
.
numConnecting
+=
updateVal
case
connectivity
.
TransientFailure
:
cse
.
numTransientFailure
+=
updateVal
}
}
// Evaluate.
if
cse
.
numReady
>
0
{
return
connectivity
.
Ready
}
if
cse
.
numConnecting
>
0
{
return
connectivity
.
Connecting
}
return
connectivity
.
TransientFailure
}

// recordTransition records state change happening in every subConn and based on
// that it evaluates what aggregated state should be.
// It can only transition between Ready, Connecting and TransientFailure. Other states,
// Idle and Shutdown are transitioned into by ClientConn; in the beginning of the connection
// before any subConn is created ClientConn is in idle state. In the end when ClientConn
// closes it is in Shutdown state.
//
// recordTransition should only be called synchronously from the same goroutine.

recordTransition records state change happening in every subConn and based on that it evaluates what aggregated state should be . It can only transition between Ready Connecting and TransientFailure . Other states Idle and Shutdown are transitioned into by ClientConn ; in the beginning of the connection before any subConn is created ClientConn is in idle state . In the end when ClientConn closes it is in Shutdown state . recordTransition should only be called synchronously from the same goroutine .


func (s *EtcdServer) doSerialize(ctx context.Context, chk func(*auth.AuthInfo) error, get func()) error {
	ai, err := s.AuthInfoFromCtx(ctx)
	if err != nil {
		return err
	}
	if ai == nil {
		// chk expects non-nil AuthInfo; use empty credentials
		ai = &auth.AuthInfo{}
	}
	if err = chk(ai); err != nil {
		return err
	}
	// fetch response for serialized request
	get()
	// check for stale token revision in case the auth store was updated while
	// the request has been handled.
	if ai.Revision != 0 && ai.Revision != s.authStore.Revision() {
		return auth.ErrAuthOldRevision
	}
	return nil
}

// doSerialize handles the auth logic, with permissions checked by "chk", for a serialized request "get". Returns a non-nil error on authentication failure.

doSerialize handles the auth logic with permissions checked by chk for a serialized request get . Returns a non - nil error on authentication failure .


func (w *watcher) send(wr clientv3.WatchResponse) {
	if wr.IsProgressNotify() && !w.progress {
		return
	}
	if w.nextrev > wr.Header.Revision && len(wr.Events) > 0 {
		return
	}
	if w.nextrev == 0 {
		// current watch; expect updates following this revision
		w.nextrev = wr.Header.Revision + 1
	}

	events := make([]*mvccpb.Event, 0, len(wr.Events))

	var lastRev int64
	for i := range wr.Events {
		ev := (*mvccpb.Event)(wr.Events[i])
		if ev.Kv.ModRevision < w.nextrev {
			continue
		} else {
			// We cannot update w.rev here.
			// txn can have multiple events with the same rev.
			// If w.nextrev updates here, it would skip events in the same txn.
			lastRev = ev.Kv.ModRevision
		}

		filtered := false
		for _, filter := range w.filters {
			if filter(*ev) {
				filtered = true
				break
			}
		}
		if filtered {
			continue
		}

		if !w.prevKV {
			evCopy := *ev
			evCopy.PrevKv = nil
			ev = &evCopy
		}
		events = append(events, ev)
	}

	if lastRev >= w.nextrev {
		w.nextrev = lastRev + 1
	}

	// all events are filtered out?
	if !wr.IsProgressNotify() && !wr.Created && len(events) == 0 && wr.CompactRevision == 0 {
		return
	}

	w.lastHeader = wr.Header
	w.post(&pb.WatchResponse{
		Header:          &wr.Header,
		Created:         wr.Created,
		CompactRevision: wr.CompactRevision,
		Canceled:        wr.Canceled,
		WatchId:         w.id,
		Events:          events,
	})
}

// send filters out repeated events by discarding revisions older
// than the last one sent over the watch channel.

send filters out repeated events by discarding revisions older than the last one sent over the watch channel .


func (w *watcher) post(wr *pb.WatchResponse) bool {
	select {
	case w.wps.watchCh <- wr:
	case <-time.After(50 * time.Millisecond):
		w.wps.cancel()
		return false
	}
	return true
}

func ( w * watcher ) post ( wr * pb . WatchResponse ) bool { select { case w . wps . watchCh <- wr : case <- time . After ( 50 * time . Millisecond ) : w . wps . cancel ( ) return false } return true }

// post puts a watch response on the watcher's proxy stream channel

post puts a watch response on the watcher s proxy stream channel


func (ac *AccessController) OriginAllowed(origin string) bool {
	ac.corsMu.RLock()
	defer ac.corsMu.RUnlock()
	if len(ac.CORS) == 0 { // allow all
		return true
	}
	_, ok := ac.CORS["*"]
	if ok {
		return true
	}
	_, ok = ac.CORS[origin]
	return ok
}

func
(
ac
*
AccessController
)
OriginAllowed
(
origin
string
)
bool
{
ac
.
corsMu
.
RLock
(
)
defer
ac
.
corsMu
.
RUnlock
(
)
if
len
(
ac
.
CORS
)
==
0
{
// allow all
return
true
}
_
,
ok
:=
ac
.
CORS
[
"
"
]
if
ok
{
return
true
}
_
,
ok
=
ac
.
CORS
[
origin
]
return
ok
}

// OriginAllowed determines whether the server will allow a given CORS origin.
// If CORS is empty, allow all.

OriginAllowed determines whether the server will allow a given CORS origin . If CORS is empty allow all .


func (ac *AccessController) IsHostWhitelisted(host string) bool {
	ac.hostWhitelistMu.RLock()
	defer ac.hostWhitelistMu.RUnlock()
	if len(ac.HostWhitelist) == 0 { // allow all
		return true
	}
	_, ok := ac.HostWhitelist["*"]
	if ok {
		return true
	}
	_, ok = ac.HostWhitelist[host]
	return ok
}

func
(
ac
*
AccessController
)
IsHostWhitelisted
(
host
string
)
bool
{
ac
.
hostWhitelistMu
.
RLock
(
)
defer
ac
.
hostWhitelistMu
.
RUnlock
(
)
if
len
(
ac
.
HostWhitelist
)
==
0
{
// allow all
return
true
}
_
,
ok
:=
ac
.
HostWhitelist
[
"
"
]
if
ok
{
return
true
}
_
,
ok
=
ac
.
HostWhitelist
[
host
]
return
ok
}

// IsHostWhitelisted returns true if the host is whitelisted.
// If whitelist is empty, allow all.

IsHostWhitelisted returns true if the host is whitelisted . If whitelist is empty allow all .


func (ss *SelectiveStringValue) Valids() []string {
	s := make([]string, 0, len(ss.valids))
	for k := range ss.valids {
		s = append(s, k)
	}
	sort.Strings(s)
	return s
}

func ( ss * SelectiveStringValue ) Valids ( ) [ ] string { s := make ( [ ] string , 0 , len ( ss . valids ) ) for k := range ss . valids { s = append ( s , k ) } sort . Strings ( s ) return s }

// Valids returns the list of valid strings.

Valids returns the list of valid strings .


func NewSelectiveStringsValue(valids ...string) *SelectiveStringsValue {
	vm := make(map[string]struct{})
	for _, v := range valids {
		vm[v] = struct{}{}
	}
	return &SelectiveStringsValue{valids: vm, vs: []string{}}
}

func NewSelectiveStringsValue ( valids ... string ) * SelectiveStringsValue { vm := make ( map [ string ] struct { } ) for _ , v := range valids { vm [ v ] = struct { } { } } return & SelectiveStringsValue { valids : vm , vs : [ ] string { } } }

// NewSelectiveStringsValue creates a new string slice flag
// for which any one of the given strings is a valid value,
// and any other value is an error.

NewSelectiveStringsValue creates a new string slice flag for which any one of the given strings is a valid value and any other value is an error .


func NewKV(kv clientv3.KV, prefix string) clientv3.KV {
	return &kvPrefix{kv, prefix}
}

func NewKV ( kv clientv3 . KV , prefix string ) clientv3 . KV { return & kvPrefix { kv , prefix } }

// NewKV wraps a KV instance so that all requests
// are prefixed with a given string.

NewKV wraps a KV instance so that all requests are prefixed with a given string .


func NewURLsValue(s string) *URLsValue {
	if s == "" {
		return &URLsValue{}
	}
	v := &URLsValue{}
	if err := v.Set(s); err != nil {
		plog.Panicf("new URLsValue should never fail: %v", err)
	}
	return v
}

func NewURLsValue ( s string ) * URLsValue { if s == " " { return & URLsValue { } } v := & URLsValue { } if err := v . Set ( s ) ; err != nil { plog . Panicf ( " " , err ) } return v }

// NewURLsValue implements "url.URL" slice as flag.Value interface.
// Given value is to be separated by comma.

NewURLsValue implements url . URL slice as flag . Value interface . Given value is to be separated by comma .


func URLsFromFlag(fs *flag.FlagSet, urlsFlagName string) []url.URL {
	return []url.URL(*fs.Lookup(urlsFlagName).Value.(*URLsValue))
}

func URLsFromFlag ( fs * flag . FlagSet , urlsFlagName string ) [ ] url . URL { return [ ] url . URL ( * fs . Lookup ( urlsFlagName ) . Value . ( * URLsValue ) ) }

// URLsFromFlag returns a slices from url got from the flag.

URLsFromFlag returns a slices from url got from the flag .


func (e *Etcd) servePeers() (err error) {
	ph := etcdhttp.NewPeerHandler(e.GetLogger(), e.Server)
	var peerTLScfg *tls.Config
	if !e.cfg.PeerTLSInfo.Empty() {
		if peerTLScfg, err = e.cfg.PeerTLSInfo.ServerConfig(); err != nil {
			return err
		}
	}

	for _, p := range e.Peers {
		u := p.Listener.Addr().String()
		gs := v3rpc.Server(e.Server, peerTLScfg)
		m := cmux.New(p.Listener)
		go gs.Serve(m.Match(cmux.HTTP2()))
		srv := &http.Server{
			Handler:     grpcHandlerFunc(gs, ph),
			ReadTimeout: 5 * time.Minute,
			ErrorLog:    defaultLog.New(ioutil.Discard, "", 0), // do not log user error
		}
		go srv.Serve(m.Match(cmux.Any()))
		p.serve = func() error { return m.Serve() }
		p.close = func(ctx context.Context) error {
			// gracefully shutdown http.Server
			// close open listeners, idle connections
			// until context cancel or time-out
			if e.cfg.logger != nil {
				e.cfg.logger.Info(
					"stopping serving peer traffic",
					zap.String("address", u),
				)
			}
			stopServers(ctx, &servers{secure: peerTLScfg != nil, grpc: gs, http: srv})
			if e.cfg.logger != nil {
				e.cfg.logger.Info(
					"stopped serving peer traffic",
					zap.String("address", u),
				)
			}
			return nil
		}
	}

	// start peer servers in a goroutine
	for _, pl := range e.Peers {
		go func(l *peerListener) {
			u := l.Addr().String()
			if e.cfg.logger != nil {
				e.cfg.logger.Info(
					"serving peer traffic",
					zap.String("address", u),
				)
			} else {
				plog.Info("listening for peers on ", u)
			}
			e.errHandler(l.serve())
		}(pl)
	}
	return nil
}

// configure peer handlers after rafthttp.Transport started

configure peer handlers after rafthttp . Transport started


func NewStore(lg *zap.Logger, b backend.Backend, le lease.Lessor, ig ConsistentIndexGetter) *store {
	s := &store{
		b:       b,
		ig:      ig,
		kvindex: newTreeIndex(lg),

		le: le,

		currentRev:     1,
		compactMainRev: -1,

		bytesBuf8: make([]byte, 8),
		fifoSched: schedule.NewFIFOScheduler(),

		stopc: make(chan struct{}),

		lg: lg,
	}
	s.ReadView = &readView{s}
	s.WriteView = &writeView{s}
	if s.le != nil {
		s.le.SetRangeDeleter(func() lease.TxnDelete { return s.Write() })
	}

	tx := s.b.BatchTx()
	tx.Lock()
	tx.UnsafeCreateBucket(keyBucketName)
	tx.UnsafeCreateBucket(metaBucketName)
	tx.Unlock()
	s.b.ForceCommit()

	s.mu.Lock()
	defer s.mu.Unlock()
	if err := s.restore(); err != nil {
		// TODO: return the error instead of panic here?
		panic("failed to recover store from backend")
	}

	return s
}

// NewStore returns a new store. It is useful to create a store inside
// mvcc pkg. It should only be used for testing externally.

NewStore returns a new store . It is useful to create a store inside mvcc pkg . It should only be used for testing externally .


func appendMarkTombstone(lg *zap.Logger, b []byte) []byte {
	if len(b) != revBytesLen {
		if lg != nil {
			lg.Panic(
				"cannot append tombstone mark to non-normal revision bytes",
				zap.Int("expected-revision-bytes-size", revBytesLen),
				zap.Int("given-revision-bytes-size", len(b)),
			)
		} else {
			plog.Panicf("cannot append mark to non normal revision bytes")
		}
	}
	return append(b, markTombstone)
}

func appendMarkTombstone ( lg * zap . Logger , b [ ] byte ) [ ] byte { if len ( b ) != revBytesLen { if lg != nil { lg . Panic ( " " , zap . Int ( " " , revBytesLen ) , zap . Int ( " " , len ( b ) ) , ) } else { plog . Panicf ( " " ) } } return append ( b , markTombstone ) }

// appendMarkTombstone appends tombstone mark to normal revision bytes.

appendMarkTombstone appends tombstone mark to normal revision bytes .


func IsDirWriteable(dir string) error {
	f := filepath.Join(dir, ".touch")
	if err := ioutil.WriteFile(f, []byte(""), PrivateFileMode); err != nil {
		return err
	}
	return os.Remove(f)
}

func IsDirWriteable ( dir string ) error { f := filepath . Join ( dir , " " ) if err := ioutil . WriteFile ( f , [ ] byte ( " " ) , PrivateFileMode ) ; err != nil { return err } return os . Remove ( f ) }

// IsDirWriteable checks if dir is writable by writing and removing a file
// to dir. It returns nil if dir is writable.

IsDirWriteable checks if dir is writable by writing and removing a file to dir . It returns nil if dir is writable .


func TouchDirAll(dir string) error {
	// If path is already a directory, MkdirAll does nothing
	// and returns nil.
	err := os.MkdirAll(dir, PrivateDirMode)
	if err != nil {
		// if mkdirAll("a/text") and "text" is not
		// a directory, this will return syscall.ENOTDIR
		return err
	}
	return IsDirWriteable(dir)
}

// TouchDirAll is similar to os.MkdirAll. It creates directories with 0700 permission if any directory
// does not exists. TouchDirAll also ensures the given directory is writable.

TouchDirAll is similar to os . MkdirAll . It creates directories with 0700 permission if any directory does not exists . TouchDirAll also ensures the given directory is writable .


func CreateDirAll(dir string) error {
	err := TouchDirAll(dir)
	if err == nil {
		var ns []string
		ns, err = ReadDir(dir)
		if err != nil {
			return err
		}
		if len(ns) != 0 {
			err = fmt.Errorf("expected %q to be empty, got %q", dir, ns)
		}
	}
	return err
}

func CreateDirAll ( dir string ) error { err := TouchDirAll ( dir ) if err == nil { var ns [ ] string ns , err = ReadDir ( dir ) if err != nil { return err } if len ( ns ) != 0 { err = fmt . Errorf ( " " , dir , ns ) } } return err }

// CreateDirAll is similar to TouchDirAll but returns error
// if the deepest directory was not empty.

CreateDirAll is similar to TouchDirAll but returns error if the deepest directory was not empty .


func ZeroToEnd(f *os.File) error {
	// TODO: support FALLOC_FL_ZERO_RANGE
	off, err := f.Seek(0, io.SeekCurrent)
	if err != nil {
		return err
	}
	lenf, lerr := f.Seek(0, io.SeekEnd)
	if lerr != nil {
		return lerr
	}
	if err = f.Truncate(off); err != nil {
		return err
	}
	// make sure blocks remain allocated
	if err = Preallocate(f, lenf, true); err != nil {
		return err
	}
	_, err = f.Seek(off, io.SeekStart)
	return err
}

func
ZeroToEnd
(
f
*
os
.
File
)
error
{
// TODO: support FALLOC_FL_ZERO_RANGE
off
,
err
:=
f
.
Seek
(
0
,
io
.
SeekCurrent
)
if
err
!=
{
return
err
}
lenf
,
lerr
:=
f
.
Seek
(
0
,
io
.
SeekEnd
)
if
lerr
!=
{
return
lerr
}
if
err
=
f
.
Truncate
(
off
)
;
err
!=
{
return
err
}
// make sure blocks remain allocated
if
err
=
Preallocate
(
f
,
lenf
,
true
)
;
err
!=
{
return
err
}
_
,
err
=
f
.
Seek
(
off
,
io
.
SeekStart
)
return
err
}

// ZeroToEnd zeros a file starting from SEEK_CUR to its SEEK_END. May temporarily
// shorten the length of the file.

ZeroToEnd zeros a file starting from SEEK_CUR to its SEEK_END . May temporarily shorten the length of the file .


func (fp *filePipeline) Open() (f *fileutil.LockedFile, err error) {
	select {
	case f = <-fp.filec:
	case err = <-fp.errc:
	}
	return f, err
}

func ( fp * filePipeline ) Open ( ) ( f * fileutil . LockedFile , err error ) { select { case f = <- fp . filec : case err = <- fp . errc : } return f , err }

// Open returns a fresh file for writing. Rename the file before calling
// Open again or there will be file collisions.

Open returns a fresh file for writing . Rename the file before calling Open again or there will be file collisions .


func NewRaftLoggerFromZapCore(cr zapcore.Core, syncer zapcore.WriteSyncer) raft.Logger {
	// "AddCallerSkip" to annotate caller outside of "logutil"
	lg := zap.New(cr, zap.AddCaller(), zap.AddCallerSkip(1), zap.ErrorOutput(syncer))
	return &zapRaftLogger{lg: lg, sugar: lg.Sugar()}
}

// NewRaftLoggerFromZapCore creates "raft.Logger" from "zap.Core"
// and "zapcore.WriteSyncer".

NewRaftLoggerFromZapCore creates raft . Logger from zap . Core and zapcore . WriteSyncer .


func NewConfig(fpath string) (*clientv3.Config, error) {
	b, err := ioutil.ReadFile(fpath)
	if err != nil {
		return nil, err
	}

	yc := &yamlConfig{}

	err = yaml.Unmarshal(b, yc)
	if err != nil {
		return nil, err
	}

	if yc.InsecureTransport {
		return &yc.Config, nil
	}

	var (
		cert *tls.Certificate
		cp   *x509.CertPool
	)

	if yc.Certfile != "" && yc.Keyfile != "" {
		cert, err = tlsutil.NewCert(yc.Certfile, yc.Keyfile, nil)
		if err != nil {
			return nil, err
		}
	}

	if yc.TrustedCAfile != "" {
		cp, err = tlsutil.NewCertPool([]string{yc.TrustedCAfile})
		if err != nil {
			return nil, err
		}
	}

	tlscfg := &tls.Config{
		MinVersion:         tls.VersionTLS12,
		InsecureSkipVerify: yc.InsecureSkipTLSVerify,
		RootCAs:            cp,
	}
	if cert != nil {
		tlscfg.Certificates = []tls.Certificate{*cert}
	}
	yc.Config.TLS = tlscfg

	return &yc.Config, nil
}

func NewConfig ( fpath string ) ( * clientv3 . Config , error ) { b , err := ioutil . ReadFile ( fpath ) if err != nil { return nil , err } yc := & yamlConfig { } err = yaml . Unmarshal ( b , yc ) if err != nil { return nil , err } if yc . InsecureTransport { return & yc . Config , nil } var ( cert * tls . Certificate cp * x509 . CertPool ) if yc . Certfile != " " && yc . Keyfile != " " { cert , err = tlsutil . NewCert ( yc . Certfile , yc . Keyfile , nil ) if err != nil { return nil , err } } if yc . TrustedCAfile != " " { cp , err = tlsutil . NewCertPool ( [ ] string { yc . TrustedCAfile } ) if err != nil { return nil , err } } tlscfg := & tls . Config { MinVersion : tls . VersionTLS12 , InsecureSkipVerify : yc . InsecureSkipTLSVerify , RootCAs : cp , } if cert != nil { tlscfg . Certificates = [ ] tls . Certificate { * cert } } yc . Config . TLS = tlscfg return & yc . Config , nil }

// NewConfig creates a new clientv3.Config from a yaml file.

NewConfig creates a new clientv3 . Config from a yaml file .


func RegisterElectionHandler(ctx context.Context, mux *runtime.ServeMux, conn *grpc.ClientConn) error {
	return RegisterElectionHandlerClient(ctx, mux, v3electionpb.NewElectionClient(conn))
}

func RegisterElectionHandler ( ctx context . Context , mux * runtime . ServeMux , conn * grpc . ClientConn ) error { return RegisterElectionHandlerClient ( ctx , mux , v3electionpb . NewElectionClient ( conn ) ) }

// RegisterElectionHandler registers the http handlers for service Election to "mux".
// The handlers forward requests to the grpc endpoint over "conn".

RegisterElectionHandler registers the http handlers for service Election to mux . The handlers forward requests to the grpc endpoint over conn .


func UpdateCapability(lg *zap.Logger, v *semver.Version) {
	if v == nil {
		// if recovered but version was never set by cluster
		return
	}
	enableMapMu.Lock()
	if curVersion != nil && !curVersion.LessThan(*v) {
		enableMapMu.Unlock()
		return
	}
	curVersion = v
	enabledMap = capabilityMaps[curVersion.String()]
	enableMapMu.Unlock()

	if lg != nil {
		lg.Info(
			"enabled capabilities for version",
			zap.String("cluster-version", version.Cluster(v.String())),
		)
	} else {
		plog.Infof("enabled capabilities for version %s", version.Cluster(v.String()))
	}
}

// UpdateCapability updates the enabledMap when the cluster version increases.

UpdateCapability updates the enabledMap when the cluster version increases .


func NewLockCommand() *cobra.Command {
	c := &cobra.Command{
		Use:   "lock <lockname> [exec-command arg1 arg2 ...]",
		Short: "Acquires a named lock",
		Run:   lockCommandFunc,
	}
	c.Flags().IntVarP(&lockTTL, "ttl", "", lockTTL, "timeout for session")
	return c
}

func NewLockCommand ( ) * cobra . Command { c := & cobra . Command { Use : " " , Short : " " , Run : lockCommandFunc , } c . Flags ( ) . IntVarP ( & lockTTL , " " , " " , lockTTL , " " ) return c }

// NewLockCommand returns the cobra command for "lock".

NewLockCommand returns the cobra command for lock .


func (r *raftNode) tick() {
	r.tickMu.Lock()
	r.Tick()
	r.tickMu.Unlock()
}

func ( r * raftNode ) tick ( ) { r . tickMu . Lock ( ) r . Tick ( ) r . tickMu . Unlock ( ) }

// raft.Node does not have locks in Raft package

raft . Node does not have locks in Raft package


func (r *raftNode) advanceTicks(ticks int) {
	for i := 0; i < ticks; i++ {
		r.tick()
	}
}

func ( r * raftNode ) advanceTicks ( ticks int ) { for i := 0 ; i < ticks ; i ++ { r . tick ( ) } }

// advanceTicks advances ticks of Raft node.
// This can be used for fast-forwarding election
// ticks in multi data-center deployments, thus
// speeding up election process.

advanceTicks advances ticks of Raft node . This can be used for fast - forwarding election ticks in multi data - center deployments thus speeding up election process .


func NewAuthCommand() *cobra.Command {
	ac := &cobra.Command{
		Use:   "auth <enable or disable>",
		Short: "Enable or disable authentication",
	}

	ac.AddCommand(newAuthEnableCommand())
	ac.AddCommand(newAuthDisableCommand())

	return ac
}

func NewAuthCommand ( ) * cobra . Command { ac := & cobra . Command { Use : " " , Short : " " , } ac . AddCommand ( newAuthEnableCommand ( ) ) ac . AddCommand ( newAuthDisableCommand ( ) ) return ac }

// NewAuthCommand returns the cobra command for "auth".

NewAuthCommand returns the cobra command for auth .


func authEnableCommandFunc(cmd *cobra.Command, args []string) {
	if len(args) != 0 {
		ExitWithError(ExitBadArgs, fmt.Errorf("auth enable command does not accept any arguments"))
	}

	ctx, cancel := commandCtx(cmd)
	cli := mustClientFromCmd(cmd)
	var err error
	for err == nil {
		if _, err = cli.AuthEnable(ctx); err == nil {
			break
		}
		if err == rpctypes.ErrRootRoleNotExist {
			if _, err = cli.RoleAdd(ctx, "root"); err != nil {
				break
			}
			if _, err = cli.UserGrantRole(ctx, "root", "root"); err != nil {
				break
			}
		}
	}
	cancel()
	if err != nil {
		ExitWithError(ExitError, err)
	}

	fmt.Println("Authentication Enabled")
}

func authEnableCommandFunc ( cmd * cobra . Command , args [ ] string ) { if len ( args ) != 0 { ExitWithError ( ExitBadArgs , fmt . Errorf ( " " ) ) } ctx , cancel := commandCtx ( cmd ) cli := mustClientFromCmd ( cmd ) var err error for err == nil { if _ , err = cli . AuthEnable ( ctx ) ; err == nil { break } if err == rpctypes . ErrRootRoleNotExist { if _ , err = cli . RoleAdd ( ctx , " " ) ; err != nil { break } if _ , err = cli . UserGrantRole ( ctx , " " , " " ) ; err != nil { break } } } cancel ( ) if err != nil { ExitWithError ( ExitError , err ) } fmt . Println ( " " ) }

// authEnableCommandFunc executes the "auth enable" command.

authEnableCommandFunc executes the auth enable command .


func authDisableCommandFunc(cmd *cobra.Command, args []string) {
	if len(args) != 0 {
		ExitWithError(ExitBadArgs, fmt.Errorf("auth disable command does not accept any arguments"))
	}

	ctx, cancel := commandCtx(cmd)
	_, err := mustClientFromCmd(cmd).Auth.AuthDisable(ctx)
	cancel()
	if err != nil {
		ExitWithError(ExitError, err)
	}

	fmt.Println("Authentication Disabled")
}

func authDisableCommandFunc ( cmd * cobra . Command , args [ ] string ) { if len ( args ) != 0 { ExitWithError ( ExitBadArgs , fmt . Errorf ( " " ) ) } ctx , cancel := commandCtx ( cmd ) _ , err := mustClientFromCmd ( cmd ) . Auth . AuthDisable ( ctx ) cancel ( ) if err != nil { ExitWithError ( ExitError , err ) } fmt . Println ( " " ) }

// authDisableCommandFunc executes the "auth disable" command.

authDisableCommandFunc executes the auth disable command .


func RetryKVClient(c *Client) pb.KVClient {
	return &retryKVClient{
		kc: pb.NewKVClient(c.conn),
	}
}

func RetryKVClient ( c * Client ) pb . KVClient { return & retryKVClient { kc : pb . NewKVClient ( c . conn ) , } }


func RetryLeaseClient(c *Client) pb.LeaseClient {
	return &retryLeaseClient{
		lc: pb.NewLeaseClient(c.conn),
	}
}

func RetryLeaseClient ( c * Client ) pb . LeaseClient { return & retryLeaseClient { lc : pb . NewLeaseClient ( c . conn ) , } }

// RetryLeaseClient implements a LeaseClient.

RetryLeaseClient implements a LeaseClient .


func RetryClusterClient(c *Client) pb.ClusterClient {
	return &retryClusterClient{
		cc: pb.NewClusterClient(c.conn),
	}
}

func RetryClusterClient ( c * Client ) pb . ClusterClient { return & retryClusterClient { cc : pb . NewClusterClient ( c . conn ) , } }

// RetryClusterClient implements a ClusterClient.

RetryClusterClient implements a ClusterClient .


func RetryMaintenanceClient(c *Client, conn *grpc.ClientConn) pb.MaintenanceClient {
	return &retryMaintenanceClient{
		mc: pb.NewMaintenanceClient(conn),
	}
}

func RetryMaintenanceClient ( c * Client , conn * grpc . ClientConn ) pb . MaintenanceClient { return & retryMaintenanceClient { mc : pb . NewMaintenanceClient ( conn ) , } }

// RetryMaintenanceClient implements a Maintenance.

RetryMaintenanceClient implements a Maintenance .


func RetryAuthClient(c *Client) pb.AuthClient {
	return &retryAuthClient{
		ac: pb.NewAuthClient(c.conn),
	}
}

func RetryAuthClient ( c * Client ) pb . AuthClient { return & retryAuthClient { ac : pb . NewAuthClient ( c . conn ) , } }

// RetryAuthClient implements a AuthClient.

RetryAuthClient implements a AuthClient .


func NewSetDirCommand() cli.Command {
	return cli.Command{
		Name:      "setdir",
		Usage:     "create a new directory or update an existing directory TTL",
		ArgsUsage: "<key>",
		Flags: []cli.Flag{
			cli.IntFlag{Name: "ttl", Value: 0, Usage: "key time-to-live in seconds"},
		},
		Action: func(c *cli.Context) error {
			mkdirCommandFunc(c, mustNewKeyAPI(c), client.PrevIgnore)
			return nil
		},
	}
}

func NewSetDirCommand ( ) cli . Command { return cli . Command { Name : " " , Usage : " " , ArgsUsage : " " , Flags : [ ] cli . Flag { cli . IntFlag { Name : " " , Value : 0 , Usage : " " } , } , Action : func ( c * cli . Context ) error { mkdirCommandFunc ( c , mustNewKeyAPI ( c ) , client . PrevIgnore ) return nil } , } }

// NewSetDirCommand returns the CLI command for "setDir".

NewSetDirCommand returns the CLI command for setDir .


func (b *DoubleBarrier) Enter() error {
	client := b.s.Client()
	ek, err := newUniqueEphemeralKey(b.s, b.key+"/waiters")
	if err != nil {
		return err
	}
	b.myKey = ek

	resp, err := client.Get(b.ctx, b.key+"/waiters", clientv3.WithPrefix())
	if err != nil {
		return err
	}

	if len(resp.Kvs) > b.count {
		return ErrTooManyClients
	}

	if len(resp.Kvs) == b.count {
		// unblock waiters
		_, err = client.Put(b.ctx, b.key+"/ready", "")
		return err
	}

	_, err = WaitEvents(
		client,
		b.key+"/ready",
		ek.Revision(),
		[]mvccpb.Event_EventType{mvccpb.PUT})
	return err
}

func
(
b
*
DoubleBarrier
)
Enter
(
)
error
{
client
:=
b
.
s
.
Client
(
)
ek
,
err
:=
newUniqueEphemeralKey
(
b
.
s
,
b
.
key
+
"
"
)
if
err
!=
{
return
err
}
b
.
myKey
=
ek
resp
,
err
:=
client
.
Get
(
b
.
ctx
,
b
.
key
+
"
"
,
clientv3
.
WithPrefix
(
)
)
if
err
!=
{
return
err
}
if
len
(
resp
.
Kvs
)
>
b
.
count
{
return
ErrTooManyClients
}
if
len
(
resp
.
Kvs
)
==
b
.
count
{
// unblock waiters
_
,
err
=
client
.
Put
(
b
.
ctx
,
b
.
key
+
"
"
,
"
"
)
return
err
}
_
,
err
=
WaitEvents
(
client
,
b
.
key
+
"
"
,
ek
.
Revision
(
)
,
[
]
mvccpb
.
Event_EventType
{
mvccpb
.
PUT
}
)
return
err
}

// Enter waits for "count" processes to enter the barrier then returns

Enter waits for count processes to enter the barrier then returns


func (b *DoubleBarrier) Leave() error {
	client := b.s.Client()
	resp, err := client.Get(b.ctx, b.key+"/waiters", clientv3.WithPrefix())
	if err != nil {
		return err
	}
	if len(resp.Kvs) == 0 {
		return nil
	}

	lowest, highest := resp.Kvs[0], resp.Kvs[0]
	for _, k := range resp.Kvs {
		if k.ModRevision < lowest.ModRevision {
			lowest = k
		}
		if k.ModRevision > highest.ModRevision {
			highest = k
		}
	}
	isLowest := string(lowest.Key) == b.myKey.Key()

	if len(resp.Kvs) == 1 {
		// this is the only node in the barrier; finish up
		if _, err = client.Delete(b.ctx, b.key+"/ready"); err != nil {
			return err
		}
		return b.myKey.Delete()
	}

	// this ensures that if a process fails, the ephemeral lease will be
	// revoked, its barrier key is removed, and the barrier can resume

	// lowest process in node => wait on highest process
	if isLowest {
		_, err = WaitEvents(
			client,
			string(highest.Key),
			highest.ModRevision,
			[]mvccpb.Event_EventType{mvccpb.DELETE})
		if err != nil {
			return err
		}
		return b.Leave()
	}

	// delete self and wait on lowest process
	if err = b.myKey.Delete(); err != nil {
		return err
	}

	key := string(lowest.Key)
	_, err = WaitEvents(
		client,
		key,
		lowest.ModRevision,
		[]mvccpb.Event_EventType{mvccpb.DELETE})
	if err != nil {
		return err
	}
	return b.Leave()
}

// Leave waits for "count" processes to leave the barrier then returns

Leave waits for count processes to leave the barrier then returns


func HandleBasic(mux *http.ServeMux, server etcdserver.ServerPeer) {
	mux.HandleFunc(varsPath, serveVars)

	// TODO: deprecate '/config/local/log' in v3.5
	mux.HandleFunc(configPath+"/local/log", logHandleFunc)

	HandleMetricsHealth(mux, server)
	mux.HandleFunc(versionPath, versionHandler(server.Cluster(), serveVersion))
}

// HandleBasic adds handlers to a mux for serving JSON etcd client requests
// that do not access the v2 store.

HandleBasic adds handlers to a mux for serving JSON etcd client requests that do not access the v2 store .


func WriteError(lg *zap.Logger, w http.ResponseWriter, r *http.Request, err error) {
	if err == nil {
		return
	}
	switch e := err.(type) {
	case *v2error.Error:
		e.WriteTo(w)

	case *httptypes.HTTPError:
		if et := e.WriteTo(w); et != nil {
			if lg != nil {
				lg.Debug(
					"failed to write v2 HTTP error",
					zap.String("remote-addr", r.RemoteAddr),
					zap.String("internal-server-error", e.Error()),
					zap.Error(et),
				)
			} else {
				plog.Debugf("error writing HTTPError (%v) to %s", et, r.RemoteAddr)
			}
		}

	default:
		switch err {
		case etcdserver.ErrTimeoutDueToLeaderFail, etcdserver.ErrTimeoutDueToConnectionLost, etcdserver.ErrNotEnoughStartedMembers,
			etcdserver.ErrUnhealthy:
			if lg != nil {
				lg.Warn(
					"v2 response error",
					zap.String("remote-addr", r.RemoteAddr),
					zap.String("internal-server-error", err.Error()),
				)
			} else {
				mlog.MergeError(err)
			}

		default:
			if lg != nil {
				lg.Warn(
					"unexpected v2 response error",
					zap.String("remote-addr", r.RemoteAddr),
					zap.String("internal-server-error", err.Error()),
				)
			} else {
				mlog.MergeErrorf("got unexpected response error (%v)", err)
			}
		}

		herr := httptypes.NewHTTPError(http.StatusInternalServerError, "Internal Server Error")
		if et := herr.WriteTo(w); et != nil {
			if lg != nil {
				lg.Debug(
					"failed to write v2 HTTP error",
					zap.String("remote-addr", r.RemoteAddr),
					zap.String("internal-server-error", err.Error()),
					zap.Error(et),
				)
			} else {
				plog.Debugf("error writing HTTPError (%v) to %s", et, r.RemoteAddr)
			}
		}
	}
}

func WriteError ( lg * zap . Logger , w http . ResponseWriter , r * http . Request , err error ) { if err == nil { return } switch e := err . ( type ) { case * v2error . Error : e . WriteTo ( w ) case * httptypes . HTTPError : if et := e . WriteTo ( w ) ; et != nil { if lg != nil { lg . Debug ( " " , zap . String ( " " , r . RemoteAddr ) , zap . String ( " " , e . Error ( ) ) , zap . Error ( et ) , ) } else { plog . Debugf ( " " , et , r . RemoteAddr ) } } default : switch err { case etcdserver . ErrTimeoutDueToLeaderFail , etcdserver . ErrTimeoutDueToConnectionLost , etcdserver . ErrNotEnoughStartedMembers , etcdserver . ErrUnhealthy : if lg != nil { lg . Warn ( " " , zap . String ( " " , r . RemoteAddr ) , zap . String ( " " , err . Error ( ) ) , ) } else { mlog . MergeError ( err ) } default : if lg != nil { lg . Warn ( " " , zap . String ( " " , r . RemoteAddr ) , zap . String ( " " , err . Error ( ) ) , ) } else { mlog . MergeErrorf ( " " , err ) } } herr := httptypes . NewHTTPError ( http . StatusInternalServerError , " " ) if et := herr . WriteTo ( w ) ; et != nil { if lg != nil { lg . Debug ( " " , zap . String ( " " , r . RemoteAddr ) , zap . String ( " " , err . Error ( ) ) , zap . Error ( et ) , ) } else { plog . Debugf ( " " , et , r . RemoteAddr ) } } } }

// WriteError logs and writes the given Error to the ResponseWriter
// If Error is an etcdErr, it is rendered to the ResponseWriter
// Otherwise, it is assumed to be a StatusInternalServerError

WriteError logs and writes the given Error to the ResponseWriter If Error is an etcdErr it is rendered to the ResponseWriter Otherwise it is assumed to be a StatusInternalServerError


func (c *RaftCluster) MemberByName(name string) *Member {
	c.Lock()
	defer c.Unlock()
	var memb *Member
	for _, m := range c.members {
		if m.Name == name {
			if memb != nil {
				if c.lg != nil {
					c.lg.Panic("two member with same name found", zap.String("name", name))
				} else {
					plog.Panicf("two members with the given name %q exist", name)
				}
			}
			memb = m
		}
	}
	return memb.Clone()
}

func ( c * RaftCluster ) MemberByName ( name string ) * Member { c . Lock ( ) defer c . Unlock ( ) var memb * Member for _ , m := range c . members { if m . Name == name { if memb != nil { if c . lg != nil { c . lg . Panic ( " " , zap . String ( " " , name ) ) } else { plog . Panicf ( " " , name ) } } memb = m } } return memb . Clone ( ) }

// MemberByName returns a Member with the given name if exists.
// If more than one member has the given name, it will panic.

MemberByName returns a Member with the given name if exists . If more than one member has the given name it will panic .


func (c *RaftCluster) PeerURLs() []string {
	c.Lock()
	defer c.Unlock()
	urls := make([]string, 0)
	for _, p := range c.members {
		urls = append(urls, p.PeerURLs...)
	}
	sort.Strings(urls)
	return urls
}

func ( c * RaftCluster ) PeerURLs ( ) [ ] string { c . Lock ( ) defer c . Unlock ( ) urls := make ( [ ] string , 0 ) for _ , p := range c . members { urls = append ( urls , p . PeerURLs ... ) } sort . Strings ( urls ) return urls }

// PeerURLs returns a list of all peer addresses.
// The returned list is sorted in ascending lexicographical order.

PeerURLs returns a list of all peer addresses . The returned list is sorted in ascending lexicographical order .


func (c *RaftCluster) ValidateConfigurationChange(cc raftpb.ConfChange) error {
	members, removed := membersFromStore(c.lg, c.v2store)
	id := types.ID(cc.NodeID)
	if removed[id] {
		return ErrIDRemoved
	}
	switch cc.Type {
	case raftpb.ConfChangeAddNode:
		if members[id] != nil {
			return ErrIDExists
		}
		urls := make(map[string]bool)
		for _, m := range members {
			for _, u := range m.PeerURLs {
				urls[u] = true
			}
		}
		m := new(Member)
		if err := json.Unmarshal(cc.Context, m); err != nil {
			if c.lg != nil {
				c.lg.Panic("failed to unmarshal member", zap.Error(err))
			} else {
				plog.Panicf("unmarshal member should never fail: %v", err)
			}
		}
		for _, u := range m.PeerURLs {
			if urls[u] {
				return ErrPeerURLexists
			}
		}

	case raftpb.ConfChangeRemoveNode:
		if members[id] == nil {
			return ErrIDNotFound
		}

	case raftpb.ConfChangeUpdateNode:
		if members[id] == nil {
			return ErrIDNotFound
		}
		urls := make(map[string]bool)
		for _, m := range members {
			if m.ID == id {
				continue
			}
			for _, u := range m.PeerURLs {
				urls[u] = true
			}
		}
		m := new(Member)
		if err := json.Unmarshal(cc.Context, m); err != nil {
			if c.lg != nil {
				c.lg.Panic("failed to unmarshal member", zap.Error(err))
			} else {
				plog.Panicf("unmarshal member should never fail: %v", err)
			}
		}
		for _, u := range m.PeerURLs {
			if urls[u] {
				return ErrPeerURLexists
			}
		}

	default:
		if c.lg != nil {
			c.lg.Panic("unknown ConfChange type", zap.String("type", cc.Type.String()))
		} else {
			plog.Panicf("ConfChange type should be either AddNode, RemoveNode or UpdateNode")
		}
	}
	return nil
}

func ( c * RaftCluster ) ValidateConfigurationChange ( cc raftpb . ConfChange ) error { members , removed := membersFromStore ( c . lg , c . v2store ) id := types . ID ( cc . NodeID ) if removed [ id ] { return ErrIDRemoved } switch cc . Type { case raftpb . ConfChangeAddNode : if members [ id ] != nil { return ErrIDExists } urls := make ( map [ string ] bool ) for _ , m := range members { for _ , u := range m . PeerURLs { urls [ u ] = true } } m := new ( Member ) if err := json . Unmarshal ( cc . Context , m ) ; err != nil { if c . lg != nil { c . lg . Panic ( " " , zap . Error ( err ) ) } else { plog . Panicf ( " " , err ) } } for _ , u := range m . PeerURLs { if urls [ u ] { return ErrPeerURLexists } } case raftpb . ConfChangeRemoveNode : if members [ id ] == nil { return ErrIDNotFound } case raftpb . ConfChangeUpdateNode : if members [ id ] == nil { return ErrIDNotFound } urls := make ( map [ string ] bool ) for _ , m := range members { if m . ID == id { continue } for _ , u := range m . PeerURLs { urls [ u ] = true } } m := new ( Member ) if err := json . Unmarshal ( cc . Context , m ) ; err != nil { if c . lg != nil { c . lg . Panic ( " " , zap . Error ( err ) ) } else { plog . Panicf ( " " , err ) } } for _ , u := range m . PeerURLs { if urls [ u ] { return ErrPeerURLexists } } default : if c . lg != nil { c . lg . Panic ( " " , zap . String ( " " , cc . Type . String ( ) ) ) } else { plog . Panicf ( " " ) } } return nil }

// ValidateConfigurationChange takes a proposed ConfChange and
// ensures that it is still valid.

ValidateConfigurationChange takes a proposed ConfChange and ensures that it is still valid .


func (c *RaftCluster) AddMember(m *Member) {
	c.Lock()
	defer c.Unlock()
	if c.v2store != nil {
		mustSaveMemberToStore(c.v2store, m)
	}
	if c.be != nil {
		mustSaveMemberToBackend(c.be, m)
	}

	c.members[m.ID] = m

	if c.lg != nil {
		c.lg.Info(
			"added member",
			zap.String("cluster-id", c.cid.String()),
			zap.String("local-member-id", c.localID.String()),
			zap.String("added-peer-id", m.ID.String()),
			zap.Strings("added-peer-peer-urls", m.PeerURLs),
		)
	} else {
		plog.Infof("added member %s %v to cluster %s", m.ID, m.PeerURLs, c.cid)
	}
}

func ( c * RaftCluster ) AddMember ( m * Member ) { c . Lock ( ) defer c . Unlock ( ) if c . v2store != nil { mustSaveMemberToStore ( c . v2store , m ) } if c . be != nil { mustSaveMemberToBackend ( c . be , m ) } c . members [ m . ID ] = m if c . lg != nil { c . lg . Info ( " " , zap . String ( " " , c . cid . String ( ) ) , zap . String ( " " , c . localID . String ( ) ) , zap . String ( " " , m . ID . String ( ) ) , zap . Strings ( " " , m . PeerURLs ) , ) } else { plog . Infof ( " " , m . ID , m . PeerURLs , c . cid ) } }

// AddMember adds a new Member into the cluster, and saves the given member's
// raftAttributes into the store. The given member should have empty attributes.
// A Member with a matching id must not exist.

AddMember adds a new Member into the cluster and saves the given member s raftAttributes into the store . The given member should have empty attributes . A Member with a matching id must not exist .


func (c *RaftCluster) RemoveMember(id types.ID) {
	c.Lock()
	defer c.Unlock()
	if c.v2store != nil {
		mustDeleteMemberFromStore(c.v2store, id)
	}
	if c.be != nil {
		mustDeleteMemberFromBackend(c.be, id)
	}

	m, ok := c.members[id]
	delete(c.members, id)
	c.removed[id] = true

	if c.lg != nil {
		if ok {
			c.lg.Info(
				"removed member",
				zap.String("cluster-id", c.cid.String()),
				zap.String("local-member-id", c.localID.String()),
				zap.String("removed-remote-peer-id", id.String()),
				zap.Strings("removed-remote-peer-urls", m.PeerURLs),
			)
		} else {
			c.lg.Warn(
				"skipped removing already removed member",
				zap.String("cluster-id", c.cid.String()),
				zap.String("local-member-id", c.localID.String()),
				zap.String("removed-remote-peer-id", id.String()),
			)
		}
	} else {
		plog.Infof("removed member %s from cluster %s", id, c.cid)
	}
}

func ( c * RaftCluster ) RemoveMember ( id types . ID ) { c . Lock ( ) defer c . Unlock ( ) if c . v2store != nil { mustDeleteMemberFromStore ( c . v2store , id ) } if c . be != nil { mustDeleteMemberFromBackend ( c . be , id ) } m , ok := c . members [ id ] delete ( c . members , id ) c . removed [ id ] = true if c . lg != nil { if ok { c . lg . Info ( " " , zap . String ( " " , c . cid . String ( ) ) , zap . String ( " " , c . localID . String ( ) ) , zap . String ( " " , id . String ( ) ) , zap . Strings ( " " , m . PeerURLs ) , ) } else { c . lg . Warn ( " " , zap . String ( " " , c . cid . String ( ) ) , zap . String ( " " , c . localID . String ( ) ) , zap . String ( " " , id . String ( ) ) , ) } } else { plog . Infof ( " " , id , c . cid ) } }

// RemoveMember removes a member from the store.
// The given id MUST exist, or the function panics.

RemoveMember removes a member from the store . The given id MUST exist or the function panics .


func ValidateClusterAndAssignIDs(lg *zap.Logger, local *RaftCluster, existing *RaftCluster) error {
	ems := existing.Members()
	lms := local.Members()
	if len(ems) != len(lms) {
		return fmt.Errorf("member count is unequal")
	}
	sort.Sort(MembersByPeerURLs(ems))
	sort.Sort(MembersByPeerURLs(lms))

	ctx, cancel := context.WithTimeout(context.TODO(), 30*time.Second)
	defer cancel()
	for i := range ems {
		if ok, err := netutil.URLStringsEqual(ctx, lg, ems[i].PeerURLs, lms[i].PeerURLs); !ok {
			return fmt.Errorf("unmatched member while checking PeerURLs (%v)", err)
		}
		lms[i].ID = ems[i].ID
	}
	local.members = make(map[types.ID]*Member)
	for _, m := range lms {
		local.members[m.ID] = m
	}
	return nil
}

func ValidateClusterAndAssignIDs ( lg * zap . Logger , local * RaftCluster , existing * RaftCluster ) error { ems := existing . Members ( ) lms := local . Members ( ) if len ( ems ) != len ( lms ) { return fmt . Errorf ( " " ) } sort . Sort ( MembersByPeerURLs ( ems ) ) sort . Sort ( MembersByPeerURLs ( lms ) ) ctx , cancel := context . WithTimeout ( context . TODO ( ) , 30 * time . Second ) defer cancel ( ) for i := range ems { if ok , err := netutil . URLStringsEqual ( ctx , lg , ems [ i ] . PeerURLs , lms [ i ] . PeerURLs ) ; ! ok { return fmt . Errorf ( " " , err ) } lms [ i ] . ID = ems [ i ] . ID } local . members = make ( map [ types . ID ] * Member ) for _ , m := range lms { local . members [ m . ID ] = m } return nil }

// ValidateClusterAndAssignIDs validates the local cluster by matching the PeerURLs
// with the existing cluster. If the validation succeeds, it assigns the IDs
// from the existing cluster to the local cluster.
// If the validation fails, an error will be returned.

ValidateClusterAndAssignIDs validates the local cluster by matching the PeerURLs with the existing cluster . If the validation succeeds it assigns the IDs from the existing cluster to the local cluster . If the validation fails an error will be returned .


func (ti *treeIndex) Keep(rev int64) map[revision]struct{} {
	available := make(map[revision]struct{})
	ti.RLock()
	defer ti.RUnlock()
	ti.tree.Ascend(func(i btree.Item) bool {
		keyi := i.(*keyIndex)
		keyi.keep(rev, available)
		return true
	})
	return available
}

func ( ti * treeIndex ) Keep ( rev int64 ) map [ revision ] struct { } { available := make ( map [ revision ] struct { } ) ti . RLock ( ) defer ti . RUnlock ( ) ti . tree . Ascend ( func ( i btree . Item ) bool { keyi := i . ( * keyIndex ) keyi . keep ( rev , available ) return true } ) return available }

// Keep finds all revisions to be kept for a Compaction at the given rev.

Keep finds all revisions to be kept for a Compaction at the given rev .


func (l *lessor) closeRequireLeader() {
	l.mu.Lock()
	defer l.mu.Unlock()
	for _, ka := range l.keepAlives {
		reqIdxs := 0
		// find all required leader channels, close, mark as nil
		for i, ctx := range ka.ctxs {
			md, ok := metadata.FromOutgoingContext(ctx)
			if !ok {
				continue
			}
			ks := md[rpctypes.MetadataRequireLeaderKey]
			if len(ks) < 1 || ks[0] != rpctypes.MetadataHasLeader {
				continue
			}
			close(ka.chs[i])
			ka.chs[i] = nil
			reqIdxs++
		}
		if reqIdxs == 0 {
			continue
		}
		// remove all channels that required a leader from keepalive
		newChs := make([]chan<- *LeaseKeepAliveResponse, len(ka.chs)-reqIdxs)
		newCtxs := make([]context.Context, len(newChs))
		newIdx := 0
		for i := range ka.chs {
			if ka.chs[i] == nil {
				continue
			}
			newChs[newIdx], newCtxs[newIdx] = ka.chs[i], ka.ctxs[newIdx]
			newIdx++
		}
		ka.chs, ka.ctxs = newChs, newCtxs
	}
}

// closeRequireLeader scans keepAlives for ctxs that have require leader
// and closes the associated channels.

closeRequireLeader scans keepAlives for ctxs that have require leader and closes the associated channels .


func (l *lessor) resetRecv() (pb.Lease_LeaseKeepAliveClient, error) {
	sctx, cancel := context.WithCancel(l.stopCtx)
	stream, err := l.remote.LeaseKeepAlive(sctx, append(l.callOpts, withMax(0))...)
	if err != nil {
		cancel()
		return nil, err
	}

	l.mu.Lock()
	defer l.mu.Unlock()
	if l.stream != nil && l.streamCancel != nil {
		l.streamCancel()
	}

	l.streamCancel = cancel
	l.stream = stream

	go l.sendKeepAliveLoop(stream)
	return stream, nil
}

func ( l * lessor ) resetRecv ( ) ( pb . Lease_LeaseKeepAliveClient , error ) { sctx , cancel := context . WithCancel ( l . stopCtx ) stream , err := l . remote . LeaseKeepAlive ( sctx , append ( l . callOpts , withMax ( 0 ) ) ... ) if err != nil { cancel ( ) return nil , err } l . mu . Lock ( ) defer l . mu . Unlock ( ) if l . stream != nil && l . streamCancel != nil { l . streamCancel ( ) } l . streamCancel = cancel l . stream = stream go l . sendKeepAliveLoop ( stream ) return stream , nil }

// resetRecv opens a new lease stream and starts sending keep alive requests.

resetRecv opens a new lease stream and starts sending keep alive requests .


func (l *lessor) recvKeepAlive(resp *pb.LeaseKeepAliveResponse) {
	karesp := &LeaseKeepAliveResponse{
		ResponseHeader: resp.GetHeader(),
		ID:             LeaseID(resp.ID),
		TTL:            resp.TTL,
	}

	l.mu.Lock()
	defer l.mu.Unlock()

	ka, ok := l.keepAlives[karesp.ID]
	if !ok {
		return
	}

	if karesp.TTL <= 0 {
		// lease expired; close all keep alive channels
		delete(l.keepAlives, karesp.ID)
		ka.close()
		return
	}

	// send update to all channels
	nextKeepAlive := time.Now().Add((time.Duration(karesp.TTL) * time.Second) / 3.0)
	ka.deadline = time.Now().Add(time.Duration(karesp.TTL) * time.Second)
	for _, ch := range ka.chs {
		select {
		case ch <- karesp:
		default:
			if l.lg != nil {
				l.lg.Warn("lease keepalive response queue is full; dropping response send",
					zap.Int("queue-size", len(ch)),
					zap.Int("queue-capacity", cap(ch)),
				)
			}
		}
		// still advance in order to rate-limit keep-alive sends
		ka.nextKeepAlive = nextKeepAlive
	}
}

// recvKeepAlive updates a lease based on its LeaseKeepAliveResponse


func (l *lessor) deadlineLoop() {
	for {
		select {
		case <-time.After(time.Second):
		case <-l.donec:
			return
		}
		now := time.Now()
		l.mu.Lock()
		for id, ka := range l.keepAlives {
			if ka.deadline.Before(now) {
				// waited too long for response; lease may be expired
				ka.close()
				delete(l.keepAlives, id)
			}
		}
		l.mu.Unlock()
	}
}

// deadlineLoop reaps any keep alive channels that have not received a response
// within the lease TTL

deadlineLoop reaps any keep alive channels that have not received a response within the lease TTL


func (l *lessor) sendKeepAliveLoop(stream pb.Lease_LeaseKeepAliveClient) {
	for {
		var tosend []LeaseID

		now := time.Now()
		l.mu.Lock()
		for id, ka := range l.keepAlives {
			if ka.nextKeepAlive.Before(now) {
				tosend = append(tosend, id)
			}
		}
		l.mu.Unlock()

		for _, id := range tosend {
			r := &pb.LeaseKeepAliveRequest{ID: int64(id)}
			if err := stream.Send(r); err != nil {
				// TODO do something with this error?
				return
			}
		}

		select {
		case <-time.After(retryConnWait):
		case <-stream.Context().Done():
			return
		case <-l.donec:
			return
		case <-l.stopCtx.Done():
			return
		}
	}
}

func
(
l
*
lessor
)
sendKeepAliveLoop
(
stream
pb
.
Lease_LeaseKeepAliveClient
)
{
for
{
var
tosend
[
]
LeaseID
now
:=
time
.
Now
(
)
l
.
mu
.
Lock
(
)
for
id
,
ka
:=
range
l
.
keepAlives
{
if
ka
.
nextKeepAlive
.
Before
(
now
)
{
tosend
=
append
(
tosend
,
id
)
}
}
l
.
mu
.
Unlock
(
)
for
_
,
id
:=
range
tosend
{
r
:=
&
pb
.
LeaseKeepAliveRequest
{
ID
:
int64
(
id
)
}
if
err
:=
stream
.
Send
(
r
)
;
err
!=
{
// TODO do something with this error?
return
}
}
select
{
case
<-
time
.
After
(
retryConnWait
)
:
case
<-
stream
.
Context
(
)
.
Done
(
)
:
return
case
<-
l
.
donec
:
return
case
<-
l
.
stopCtx
.
Done
(
)
:
return
}
}
}

// sendKeepAliveLoop sends keep alive requests for the lifetime of the given stream.

sendKeepAliveLoop sends keep alive requests for the lifetime of the given stream .


func NewKV(cl *v3.Client, pfx string, opts ...concurrency.SessionOption) (v3.KV, func(), error) {
	cctx, cancel := context.WithCancel(cl.Ctx())
	lkv := &leasingKV{
		cl:          cl,
		kv:          cl.KV,
		pfx:         pfx,
		leases:      leaseCache{revokes: make(map[string]time.Time)},
		ctx:         cctx,
		cancel:      cancel,
		sessionOpts: opts,
		sessionc:    make(chan struct{}),
	}
	lkv.wg.Add(2)
	go func() {
		defer lkv.wg.Done()
		lkv.monitorSession()
	}()
	go func() {
		defer lkv.wg.Done()
		lkv.leases.clearOldRevokes(cctx)
	}()
	return lkv, lkv.Close, lkv.waitSession(cctx)
}

func NewKV ( cl * v3 . Client , pfx string , opts ... concurrency . SessionOption ) ( v3 . KV , func ( ) , error ) { cctx , cancel := context . WithCancel ( cl . Ctx ( ) ) lkv := & leasingKV { cl : cl , kv : cl . KV , pfx : pfx , leases : leaseCache { revokes : make ( map [ string ] time . Time ) } , ctx : cctx , cancel : cancel , sessionOpts : opts , sessionc : make ( chan struct { } ) , } lkv . wg . Add ( 2 ) go func ( ) { defer lkv . wg . Done ( ) lkv . monitorSession ( ) } ( ) go func ( ) { defer lkv . wg . Done ( ) lkv . leases . clearOldRevokes ( cctx ) } ( ) return lkv , lkv . Close , lkv . waitSession ( cctx ) }

// NewKV wraps a KV instance so that all requests are wired through a leasing protocol.

NewKV wraps a KV instance so that all requests are wired through a leasing protocol .


func (lkv *leasingKV) rescind(ctx context.Context, key string, rev int64) {
	if lkv.leases.Evict(key) > rev {
		return
	}
	cmp := v3.Compare(v3.CreateRevision(lkv.pfx+key), "<", rev)
	op := v3.OpDelete(lkv.pfx + key)
	for ctx.Err() == nil {
		if _, err := lkv.kv.Txn(ctx).If(cmp).Then(op).Commit(); err == nil {
			return
		}
	}
}

func ( lkv * leasingKV ) rescind ( ctx context . Context , key string , rev int64 ) { if lkv . leases . Evict ( key ) > rev { return } cmp := v3 . Compare ( v3 . CreateRevision ( lkv . pfx + key ) , " " , rev ) op := v3 . OpDelete ( lkv . pfx + key ) for ctx . Err ( ) == nil { if _ , err := lkv . kv . Txn ( ctx ) . If ( cmp ) . Then ( op ) . Commit ( ) ; err == nil { return } } }

// rescind releases a lease from this client.

rescind releases a lease from this client .


func LeaseValue(key string) Cmp {
	return Cmp{Key: []byte(key), Target: pb.Compare_LEASE}
}

func LeaseValue ( key string ) Cmp { return Cmp { Key : [ ] byte ( key ) , Target : pb . Compare_LEASE } }

// LeaseValue compares a key's LeaseID to a value of your choosing. The empty
// LeaseID is 0, otherwise known as `NoLease`.

LeaseValue compares a key s LeaseID to a value of your choosing . The empty LeaseID is 0 otherwise known as NoLease .


func (cmp *Cmp) ValueBytes() []byte {
	if tu, ok := cmp.TargetUnion.(*pb.Compare_Value); ok {
		return tu.Value
	}
	return nil
}

func ( cmp * Cmp ) ValueBytes ( ) [ ] byte { if tu , ok := cmp . TargetUnion . ( * pb . Compare_Value ) ; ok { return tu . Value } return nil }

// ValueBytes returns the byte slice holding the comparison value, if any.

ValueBytes returns the byte slice holding the comparison value if any .


func (cmp Cmp) WithRange(end string) Cmp {
	cmp.RangeEnd = []byte(end)
	return cmp
}

func ( cmp Cmp ) WithRange ( end string ) Cmp { cmp . RangeEnd = [ ] byte ( end ) return cmp }

// WithRange sets the comparison to scan the range [key, end).

WithRange sets the comparison to scan the range [ key end ) .


func (cmp Cmp) WithPrefix() Cmp {
	cmp.RangeEnd = getPrefix(cmp.Key)
	return cmp
}

func ( cmp Cmp ) WithPrefix ( ) Cmp { cmp . RangeEnd = getPrefix ( cmp . Key ) return cmp }

// WithPrefix sets the comparison to scan all keys prefixed by the key.

WithPrefix sets the comparison to scan all keys prefixed by the key .


func mustInt64(val interface{}) int64 {
	if v, ok := val.(int64); ok {
		return v
	}
	if v, ok := val.(int); ok {
		return int64(v)
	}
	panic("bad value")
}

func mustInt64 ( val interface { } ) int64 { if v , ok := val . ( int64 ) ; ok { return v } if v , ok := val . ( int ) ; ok { return int64 ( v ) } panic ( " " ) }

// mustInt64 panics if val isn't an int or int64. It returns an int64 otherwise.

mustInt64 panics if val isn t an int or int64 . It returns an int64 otherwise .


func mustInt64orLeaseID(val interface{}) int64 {
	if v, ok := val.(LeaseID); ok {
		return int64(v)
	}
	return mustInt64(val)
}

func mustInt64orLeaseID ( val interface { } ) int64 { if v , ok := val . ( LeaseID ) ; ok { return int64 ( v ) } return mustInt64 ( val ) }

// mustInt64orLeaseID panics if val isn't a LeaseID, int or int64. It returns an
// int64 otherwise.

mustInt64orLeaseID panics if val isn t a LeaseID int or int64 . It returns an int64 otherwise .


func (gw *gRPCWatcher) Next() ([]*naming.Update, error) {
	if gw.wch == nil {
		// first Next() returns all addresses
		return gw.firstNext()
	}
	if gw.err != nil {
		return nil, gw.err
	}

	// process new events on target/*
	wr, ok := <-gw.wch
	if !ok {
		gw.err = status.Error(codes.Unavailable, ErrWatcherClosed.Error())
		return nil, gw.err
	}
	if gw.err = wr.Err(); gw.err != nil {
		return nil, gw.err
	}

	updates := make([]*naming.Update, 0, len(wr.Events))
	for _, e := range wr.Events {
		var jupdate naming.Update
		var err error
		switch e.Type {
		case etcd.EventTypePut:
			err = json.Unmarshal(e.Kv.Value, &jupdate)
			jupdate.Op = naming.Add
		case etcd.EventTypeDelete:
			err = json.Unmarshal(e.PrevKv.Value, &jupdate)
			jupdate.Op = naming.Delete
		default:
			continue
		}
		if err == nil {
			updates = append(updates, &jupdate)
		}
	}
	return updates, nil
}

func
(
gw
*
gRPCWatcher
)
Next
(
)
(
[
]
*
naming
.
Update
,
error
)
{
if
gw
.
wch
==
{
// first Next() returns all addresses
return
gw
.
firstNext
(
)
}
if
gw
.
err
!=
{
return
,
gw
.
err
}
// process new events on target/*
wr
,
ok
:=
<-
gw
.
wch
if
!
ok
{
gw
.
err
=
status
.
Error
(
codes
.
Unavailable
,
ErrWatcherClosed
.
Error
(
)
)
return
,
gw
.
err
}
if
gw
.
err
=
wr
.
Err
(
)
;
gw
.
err
!=
{
return
,
gw
.
err
}
updates
:=
make
(
[
]
*
naming
.
Update
,
0
,
len
(
wr
.
Events
)
)
for
_
,
e
:=
range
wr
.
Events
{
var
jupdate
naming
.
Update
var
err
error
switch
e
.
Type
{
case
etcd
.
EventTypePut
:
err
=
json
.
Unmarshal
(
e
.
Kv
.
Value
,
&
jupdate
)
jupdate
.
Op
=
naming
.
Add
case
etcd
.
EventTypeDelete
:
err
=
json
.
Unmarshal
(
e
.
PrevKv
.
Value
,
&
jupdate
)
jupdate
.
Op
=
naming
.
Delete
default
:
continue
}
if
err
==
{
updates
=
append
(
updates
,
&
jupdate
)
}
}
return
updates
,
}

// Next gets the next set of updates from the etcd resolver.
// Calls to Next should be serialized; concurrent calls are not safe since
// there is no way to reconcile the update ordering.

Next gets the next set of updates from the etcd resolver . Calls to Next should be serialized ; concurrent calls are not safe since there is no way to reconcile the update ordering .


func getJournalWriteSyncer() (zapcore.WriteSyncer, error) {
	jw, err := logutil.NewJournalWriter(os.Stderr)
	if err != nil {
		return nil, fmt.Errorf("can't find journal (%v)", err)
	}
	return zapcore.AddSync(jw), nil
}

func getJournalWriteSyncer ( ) ( zapcore . WriteSyncer , error ) { jw , err := logutil . NewJournalWriter ( os . Stderr ) if err != nil { return nil , fmt . Errorf ( " " , err ) } return zapcore . AddSync ( jw ) , nil }


func newKV(store *store, nodePath string, value string, createdIndex uint64, parent *node, expireTime time.Time) *node {
	return &node{
		Path:          nodePath,
		CreatedIndex:  createdIndex,
		ModifiedIndex: createdIndex,
		Parent:        parent,
		store:         store,
		ExpireTime:    expireTime,
		Value:         value,
	}
}

func newKV ( store * store , nodePath string , value string , createdIndex uint64 , parent * node , expireTime time . Time ) * node { return & node { Path : nodePath , CreatedIndex : createdIndex , ModifiedIndex : createdIndex , Parent : parent , store : store , ExpireTime : expireTime , Value : value , } }


func newDir(store *store, nodePath string, createdIndex uint64, parent *node, expireTime time.Time) *node {
	return &node{
		Path:          nodePath,
		CreatedIndex:  createdIndex,
		ModifiedIndex: createdIndex,
		Parent:        parent,
		ExpireTime:    expireTime,
		Children:      make(map[string]*node),
		store:         store,
	}
}

func newDir ( store * store , nodePath string , createdIndex uint64 , parent * node , expireTime time . Time ) * node { return & node { Path : nodePath , CreatedIndex : createdIndex , ModifiedIndex : createdIndex , Parent : parent , ExpireTime : expireTime , Children : make ( map [ string ] * node ) , store : store , } }


func (n *node) Read() (string, *v2error.Error) {
	if n.IsDir() {
		return "", v2error.NewError(v2error.EcodeNotFile, "", n.store.CurrentIndex)
	}

	return n.Value, nil
}

func ( n * node ) Read ( ) ( string , * v2error . Error ) { if n . IsDir ( ) { return " " , v2error . NewError ( v2error . EcodeNotFile , " " , n . store . CurrentIndex ) } return n . Value , nil }

// Read function gets the value of the node.
// If the receiver node is not a key-value pair, a "Not A File" error will be returned.

Read function gets the value of the node . If the receiver node is not a key - value pair a Not A File error will be returned .


func (n *node) Write(value string, index uint64) *v2error.Error {
	if n.IsDir() {
		return v2error.NewError(v2error.EcodeNotFile, "", n.store.CurrentIndex)
	}

	n.Value = value
	n.ModifiedIndex = index

	return nil
}

func ( n * node ) Write ( value string , index uint64 ) * v2error . Error { if n . IsDir ( ) { return v2error . NewError ( v2error . EcodeNotFile , " " , n . store . CurrentIndex ) } n . Value = value n . ModifiedIndex = index return nil }

// Write function set the value of the node to the given value.
// If the receiver node is a directory, a "Not A File" error will be returned.

Write function set the value of the node to the given value . If the receiver node is a directory a Not A File error will be returned .


func (n *node) List() ([]*node, *v2error.Error) {
	if !n.IsDir() {
		return nil, v2error.NewError(v2error.EcodeNotDir, "", n.store.CurrentIndex)
	}

	nodes := make([]*node, len(n.Children))

	i := 0
	for _, node := range n.Children {
		nodes[i] = node
		i++
	}

	return nodes, nil
}

func ( n * node ) List ( ) ( [ ] * node , * v2error . Error ) { if ! n . IsDir ( ) { return nil , v2error . NewError ( v2error . EcodeNotDir , " " , n . store . CurrentIndex ) } nodes := make ( [ ] * node , len ( n . Children ) ) i := 0 for _ , node := range n . Children { nodes [ i ] = node i ++ } return nodes , nil }

// List function return a slice of nodes under the receiver node.
// If the receiver node is not a directory, a "Not A Directory" error will be returned.

List function return a slice of nodes under the receiver node . If the receiver node is not a directory a Not A Directory error will be returned .


func (n *node) GetChild(name string) (*node, *v2error.Error) {
	if !n.IsDir() {
		return nil, v2error.NewError(v2error.EcodeNotDir, n.Path, n.store.CurrentIndex)
	}

	child, ok := n.Children[name]

	if ok {
		return child, nil
	}

	return nil, nil
}

func ( n * node ) GetChild ( name string ) ( * node , * v2error . Error ) { if ! n . IsDir ( ) { return nil , v2error . NewError ( v2error . EcodeNotDir , n . Path , n . store . CurrentIndex ) } child , ok := n . Children [ name ] if ok { return child , nil } return nil , nil }

// GetChild function returns the child node under the directory node.
// On success, it returns the file node

GetChild function returns the child node under the directory node . On success it returns the file node


func (n *node) Add(child *node) *v2error.Error {
	if !n.IsDir() {
		return v2error.NewError(v2error.EcodeNotDir, "", n.store.CurrentIndex)
	}

	_, name := path.Split(child.Path)

	if _, ok := n.Children[name]; ok {
		return v2error.NewError(v2error.EcodeNodeExist, "", n.store.CurrentIndex)
	}

	n.Children[name] = child

	return nil
}

func ( n * node ) Add ( child * node ) * v2error . Error { if ! n . IsDir ( ) { return v2error . NewError ( v2error . EcodeNotDir , " " , n . store . CurrentIndex ) } _ , name := path . Split ( child . Path ) if _ , ok := n . Children [ name ] ; ok { return v2error . NewError ( v2error . EcodeNodeExist , " " , n . store . CurrentIndex ) } n . Children [ name ] = child return nil }

// Add function adds a node to the receiver node.
// If the receiver is not a directory, a "Not A Directory" error will be returned.
// If there is an existing node with the same name under the directory, a "Already Exist"
// error will be returned

Add function adds a node to the receiver node . If the receiver is not a directory a Not A Directory error will be returned . If there is an existing node with the same name under the directory a Already Exist error will be returned


func (n *node) Remove(dir, recursive bool, callback func(path string)) *v2error.Error {
	if !n.IsDir() { // key-value pair
		_, name := path.Split(n.Path)

		// find its parent and remove the node from the map
		if n.Parent != nil && n.Parent.Children[name] == n {
			delete(n.Parent.Children, name)
		}

		if callback != nil {
			callback(n.Path)
		}

		if !n.IsPermanent() {
			n.store.ttlKeyHeap.remove(n)
		}

		return nil
	}

	if !dir {
		// cannot delete a directory without dir set to true
		return v2error.NewError(v2error.EcodeNotFile, n.Path, n.store.CurrentIndex)
	}

	if len(n.Children) != 0 && !recursive {
		// cannot delete a directory if it is not empty and the operation
		// is not recursive
		return v2error.NewError(v2error.EcodeDirNotEmpty, n.Path, n.store.CurrentIndex)
	}

	for _, child := range n.Children { // delete all children
		child.Remove(true, true, callback)
	}

	// delete self
	_, name := path.Split(n.Path)
	if n.Parent != nil && n.Parent.Children[name] == n {
		delete(n.Parent.Children, name)

		if callback != nil {
			callback(n.Path)
		}

		if !n.IsPermanent() {
			n.store.ttlKeyHeap.remove(n)
		}
	}

	return nil
}


func (n *node) Compare(prevValue string, prevIndex uint64) (ok bool, which int) {
	indexMatch := prevIndex == 0 || n.ModifiedIndex == prevIndex
	valueMatch := prevValue == "" || n.Value == prevValue
	ok = valueMatch && indexMatch
	switch {
	case valueMatch && indexMatch:
		which = CompareMatch
	case indexMatch && !valueMatch:
		which = CompareValueNotMatch
	case valueMatch && !indexMatch:
		which = CompareIndexNotMatch
	default:
		which = CompareNotMatch
	}
	return ok, which
}

func ( n * node ) Compare ( prevValue string , prevIndex uint64 ) ( ok bool , which int ) { indexMatch := prevIndex == 0 || n . ModifiedIndex == prevIndex valueMatch := prevValue == " " || n . Value == prevValue ok = valueMatch && indexMatch switch { case valueMatch && indexMatch : which = CompareMatch case indexMatch && ! valueMatch : which = CompareValueNotMatch case valueMatch && ! indexMatch : which = CompareIndexNotMatch default : which = CompareNotMatch } return ok , which }

// Compare function compares node index and value with provided ones.
// second result value explains result and equals to one of Compare.. constants

Compare function compares node index and value with provided ones . second result value explains result and equals to one of Compare .. constants


func (n *node) Clone() *node {
	if !n.IsDir() {
		newkv := newKV(n.store, n.Path, n.Value, n.CreatedIndex, n.Parent, n.ExpireTime)
		newkv.ModifiedIndex = n.ModifiedIndex
		return newkv
	}

	clone := newDir(n.store, n.Path, n.CreatedIndex, n.Parent, n.ExpireTime)
	clone.ModifiedIndex = n.ModifiedIndex

	for key, child := range n.Children {
		clone.Children[key] = child.Clone()
	}

	return clone
}

func ( n * node ) Clone ( ) * node { if ! n . IsDir ( ) { newkv := newKV ( n . store , n . Path , n . Value , n . CreatedIndex , n . Parent , n . ExpireTime ) newkv . ModifiedIndex = n . ModifiedIndex return newkv } clone := newDir ( n . store , n . Path , n . CreatedIndex , n . Parent , n . ExpireTime ) clone . ModifiedIndex = n . ModifiedIndex for key , child := range n . Children { clone . Children [ key ] = child . Clone ( ) } return clone }

// Clone function clone the node recursively and return the new node.
// If the node is a directory, it will clone all the content under this directory.
// If the node is a key-value pair, it will clone the pair.

Clone function clone the node recursively and return the new node . If the node is a directory it will clone all the content under this directory . If the node is a key - value pair it will clone the pair .


func isConnectedToQuorumSince(transport rafthttp.Transporter, since time.Time, self types.ID, members []*membership.Member) bool {
	return numConnectedSince(transport, since, self, members) >= (len(members)/2)+1
}

func isConnectedToQuorumSince ( transport rafthttp . Transporter , since time . Time , self types . ID , members [ ] * membership . Member ) bool { return numConnectedSince ( transport , since , self , members ) >= ( len ( members ) / 2 ) + 1 }

// isConnectedToQuorumSince checks whether the local member is connected to the
// quorum of the cluster since the given time.

isConnectedToQuorumSince checks whether the local member is connected to the quorum of the cluster since the given time .


func isConnectedSince(transport rafthttp.Transporter, since time.Time, remote types.ID) bool {
	t := transport.ActiveSince(remote)
	return !t.IsZero() && t.Before(since)
}

func isConnectedSince ( transport rafthttp . Transporter , since time . Time , remote types . ID ) bool { t := transport . ActiveSince ( remote ) return ! t . IsZero ( ) && t . Before ( since ) }

// isConnectedSince checks whether the local member is connected to the
// remote member since the given time.

isConnectedSince checks whether the local member is connected to the remote member since the given time .


func numConnectedSince(transport rafthttp.Transporter, since time.Time, self types.ID, members []*membership.Member) int {
	connectedNum := 0
	for _, m := range members {
		if m.ID == self || isConnectedSince(transport, since, m.ID) {
			connectedNum++
		}
	}
	return connectedNum
}

func numConnectedSince ( transport rafthttp . Transporter , since time . Time , self types . ID , members [ ] * membership . Member ) int { connectedNum := 0 for _ , m := range members { if m . ID == self || isConnectedSince ( transport , since , m . ID ) { connectedNum ++ } } return connectedNum }

// numConnectedSince counts how many members are connected to the local member
// since the given time.

numConnectedSince counts how many members are connected to the local member since the given time .