func (db *DB) buildHistogram(keyPrefix []byte) *sizeHistogram {
	txn := db.NewTransaction(false)
	defer txn.Discard()

	itr := txn.NewIterator(DefaultIteratorOptions)
	defer itr.Close()

	badgerHistogram := newSizeHistogram()

	// Collect key and value sizes.
	for itr.Seek(keyPrefix); itr.ValidForPrefix(keyPrefix); itr.Next() {
		item := itr.Item()
		badgerHistogram.keySizeHistogram.Update(item.KeySize())
		badgerHistogram.valueSizeHistogram.Update(item.ValueSize())
	}
	return badgerHistogram
}

func
(
db
*
DB
)
buildHistogram
(
keyPrefix
[
]
byte
)
*
sizeHistogram
{
txn
:=
db
.
NewTransaction
(
false
)
defer
txn
.
Discard
(
)
itr
:=
txn
.
NewIterator
(
DefaultIteratorOptions
)
defer
itr
.
Close
(
)
badgerHistogram
:=
newSizeHistogram
(
)
// Collect key and value sizes.
for
itr
.
Seek
(
keyPrefix
)
;
itr
.
ValidForPrefix
(
keyPrefix
)
;
itr
.
Next
(
)
{
item
:=
itr
.
Item
(
)
badgerHistogram
.
keySizeHistogram
.
Update
(
item
.
KeySize
(
)
)
badgerHistogram
.
valueSizeHistogram
.
Update
(
item
.
ValueSize
(
)
)
}
return
badgerHistogram
}

// buildHistogram builds the key-value size histogram.
// When keyPrefix is set, only the keys that have prefix "keyPrefix" are
// considered for creating the histogram

buildHistogram builds the key - value size histogram . When keyPrefix is set only the keys that have prefix keyPrefix are considered for creating the histogram


func (histogram histogramData) printHistogram() {
	fmt.Printf("Total count: %d\n", histogram.totalCount)
	fmt.Printf("Min value: %d\n", histogram.min)
	fmt.Printf("Max value: %d\n", histogram.max)
	fmt.Printf("Mean: %.2f\n", float64(histogram.sum)/float64(histogram.totalCount))
	fmt.Printf("%24s %9s\n", "Range", "Count")

	numBins := len(histogram.bins)
	for index, count := range histogram.countPerBin {
		if count == 0 {
			continue
		}

		// The last bin represents the bin that contains the range from
		// the last bin up to infinity so it's processed differently than the
		// other bins.
		if index == len(histogram.countPerBin)-1 {
			lowerBound := int(histogram.bins[numBins-1])
			fmt.Printf("[%10d, %10s) %9d\n", lowerBound, "infinity", count)
			continue
		}

		upperBound := int(histogram.bins[index])
		lowerBound := 0
		if index > 0 {
			lowerBound = int(histogram.bins[index-1])
		}

		fmt.Printf("[%10d, %10d) %9d\n", lowerBound, upperBound, count)
	}
	fmt.Println()
}

// printHistogram prints the histogram data in a human-readable format.

printHistogram prints the histogram data in a human - readable format .


func (w *WaterMark) Init(closer *Closer) {
	w.markCh = make(chan mark, 100)
	w.elog = trace.NewEventLog("Watermark", w.Name)
	go w.process(closer)
}

func ( w * WaterMark ) Init ( closer * Closer ) { w . markCh = make ( chan mark , 100 ) w . elog = trace . NewEventLog ( " " , w . Name ) go w . process ( closer ) }

// Init initializes a WaterMark struct. MUST be called before using it.

Init initializes a WaterMark struct . MUST be called before using it .


func (w *WaterMark) Begin(index uint64) {
	atomic.StoreUint64(&w.lastIndex, index)
	w.markCh <- mark{index: index, done: false}
}

func ( w * WaterMark ) Begin ( index uint64 ) { atomic . StoreUint64 ( & w . lastIndex , index ) w . markCh <- mark { index : index , done : false } }

// Begin sets the last index to the given value.

Begin sets the last index to the given value .


func (w *WaterMark) BeginMany(indices []uint64) {
	atomic.StoreUint64(&w.lastIndex, indices[len(indices)-1])
	w.markCh <- mark{index: 0, indices: indices, done: false}
}

func ( w * WaterMark ) BeginMany ( indices [ ] uint64 ) { atomic . StoreUint64 ( & w . lastIndex , indices [ len ( indices ) - 1 ] ) w . markCh <- mark { index : 0 , indices : indices , done : false } }

// BeginMany works like Begin but accepts multiple indices.

BeginMany works like Begin but accepts multiple indices .


func (w *WaterMark) Done(index uint64) {
	w.markCh <- mark{index: index, done: true}
}

func ( w * WaterMark ) Done ( index uint64 ) { w . markCh <- mark { index : index , done : true } }


func (w *WaterMark) DoneMany(indices []uint64) {
	w.markCh <- mark{index: 0, indices: indices, done: true}
}

func ( w * WaterMark ) DoneMany ( indices [ ] uint64 ) { w . markCh <- mark { index : 0 , indices : indices , done : true } }

// DoneMany works like Done but accepts multiple indices.

DoneMany works like Done but accepts multiple indices .


func (w *WaterMark) SetDoneUntil(val uint64) {
	atomic.StoreUint64(&w.doneUntil, val)
}

func ( w * WaterMark ) SetDoneUntil ( val uint64 ) { atomic . StoreUint64 ( & w . doneUntil , val ) }

// SetDoneUntil sets the maximum index that has the property that all indices
// less than or equal to it are done.

SetDoneUntil sets the maximum index that has the property that all indices less than or equal to it are done .


func (w *WaterMark) WaitForMark(ctx context.Context, index uint64) error {
	if w.DoneUntil() >= index {
		return nil
	}
	waitCh := make(chan struct{})
	w.markCh <- mark{index: index, waiter: waitCh}

	select {
	case <-ctx.Done():
		return ctx.Err()
	case <-waitCh:
		return nil
	}
}

func ( w * WaterMark ) WaitForMark ( ctx context . Context , index uint64 ) error { if w . DoneUntil ( ) >= index { return nil } waitCh := make ( chan struct { } ) w . markCh <- mark { index : index , waiter : waitCh } select { case <- ctx . Done ( ) : return ctx . Err ( ) case <- waitCh : return nil } }

// WaitForMark waits until the given index is marked as done.

WaitForMark waits until the given index is marked as done .


func (h header) Encode(b []byte) {
	binary.BigEndian.PutUint16(b[0:2], h.plen)
	binary.BigEndian.PutUint16(b[2:4], h.klen)
	binary.BigEndian.PutUint16(b[4:6], h.vlen)
	binary.BigEndian.PutUint32(b[6:10], h.prev)
}

func ( h header ) Encode ( b [ ] byte ) { binary . BigEndian . PutUint16 ( b [ 0 : 2 ] , h . plen ) binary . BigEndian . PutUint16 ( b [ 2 : 4 ] , h . klen ) binary . BigEndian . PutUint16 ( b [ 4 : 6 ] , h . vlen ) binary . BigEndian . PutUint32 ( b [ 6 : 10 ] , h . prev ) }


func (h *header) Decode(buf []byte) int {
	h.plen = binary.BigEndian.Uint16(buf[0:2])
	h.klen = binary.BigEndian.Uint16(buf[2:4])
	h.vlen = binary.BigEndian.Uint16(buf[4:6])
	h.prev = binary.BigEndian.Uint32(buf[6:10])
	return h.Size()
}

func ( h * header ) Decode ( buf [ ] byte ) int { h . plen = binary . BigEndian . Uint16 ( buf [ 0 : 2 ] ) h . klen = binary . BigEndian . Uint16 ( buf [ 2 : 4 ] ) h . vlen = binary . BigEndian . Uint16 ( buf [ 4 : 6 ] ) h . prev = binary . BigEndian . Uint32 ( buf [ 6 : 10 ] ) return h . Size ( ) }


func NewTableBuilder() *Builder {
	return &Builder{
		keyBuf:     newBuffer(1 << 20),
		buf:        newBuffer(1 << 20),
		prevOffset: math.MaxUint32, // Used for the first element!
	}
}

func
NewTableBuilder
(
)
*
Builder
{
return
&
Builder
{
keyBuf
:
newBuffer
(
1
<<
20
)
,
buf
:
newBuffer
(
1
<<
20
)
,
prevOffset
:
math
.
MaxUint32
,
// Used for the first element!
}
}

// NewTableBuilder makes a new TableBuilder.

NewTableBuilder makes a new TableBuilder .


func (b Builder) keyDiff(newKey []byte) []byte {
	var i int
	for i = 0; i < len(newKey) && i < len(b.baseKey); i++ {
		if newKey[i] != b.baseKey[i] {
			break
		}
	}
	return newKey[i:]
}

func ( b Builder ) keyDiff ( newKey [ ] byte ) [ ] byte { var i int for i = 0 ; i < len ( newKey ) && i < len ( b . baseKey ) ; i ++ { if newKey [ i ] != b . baseKey [ i ] { break } } return newKey [ i : ] }

// keyDiff returns a suffix of newKey that is different from b.baseKey.

keyDiff returns a suffix of newKey that is different from b . baseKey .


func (b *Builder) Add(key []byte, value y.ValueStruct) error {
	if b.counter >= restartInterval {
		b.finishBlock()
		// Start a new block. Initialize the block.
		b.restarts = append(b.restarts, uint32(b.buf.Len()))
		b.counter = 0
		b.baseKey = []byte{}
		b.baseOffset = uint32(b.buf.Len())
		b.prevOffset = math.MaxUint32 // First key-value pair of block has header.prev=MaxInt.
	}
	b.addHelper(key, value)
	return nil // Currently, there is no meaningful error.
}

// Add adds a key-value pair to the block.
// If doNotRestart is true, we will not restart even if b.counter >= restartInterval.

Add adds a key - value pair to the block . If doNotRestart is true we will not restart even if b . counter > = restartInterval .


func (b *Builder) blockIndex() []byte {
	// Store the end offset, so we know the length of the final block.
	b.restarts = append(b.restarts, uint32(b.buf.Len()))

	// Add 4 because we want to write out number of restarts at the end.
	sz := 4*len(b.restarts) + 4
	out := make([]byte, sz)
	buf := out
	for _, r := range b.restarts {
		binary.BigEndian.PutUint32(buf[:4], r)
		buf = buf[4:]
	}
	binary.BigEndian.PutUint32(buf[:4], uint32(len(b.restarts)))
	return out
}

// blockIndex generates the block index for the table.
// It is mainly a list of all the block base offsets.

blockIndex generates the block index for the table . It is mainly a list of all the block base offsets .


func (b *Builder) Finish() []byte {
	bf := bbloom.New(float64(b.keyCount), 0.01)
	var klen [2]byte
	key := make([]byte, 1024)
	for {
		if _, err := b.keyBuf.Read(klen[:]); err == io.EOF {
			break
		} else if err != nil {
			y.Check(err)
		}
		kl := int(binary.BigEndian.Uint16(klen[:]))
		if cap(key) < kl {
			key = make([]byte, 2*int(kl)) // 2 * uint16 will overflow
		}
		key = key[:kl]
		y.Check2(b.keyBuf.Read(key))
		bf.Add(key)
	}

	b.finishBlock() // This will never start a new block.
	index := b.blockIndex()
	b.buf.Write(index)

	// Write bloom filter.
	bdata := bf.JSONMarshal()
	n, err := b.buf.Write(bdata)
	y.Check(err)
	var buf [4]byte
	binary.BigEndian.PutUint32(buf[:], uint32(n))
	b.buf.Write(buf[:])

	return b.buf.Bytes()
}

func
(
b
*
Builder
)
Finish
(
)
[
]
byte
{
bf
:=
bbloom
.
New
(
float64
(
b
.
keyCount
)
,
0.01
)
var
klen
[
2
]
byte
key
:=
make
(
[
]
byte
,
1024
)
for
{
if
_
,
err
:=
b
.
keyBuf
.
Read
(
klen
[
:
]
)
;
err
==
io
.
EOF
{
break
}
else
if
err
!=
{
y
.
Check
(
err
)
}
kl
:=
int
(
binary
.
BigEndian
.
Uint16
(
klen
[
:
]
)
)
if
cap
(
key
)
<
kl
{
key
=
make
(
[
]
byte
,
2
*
int
(
kl
)
)
// 2 * uint16 will overflow
}
key
=
key
[
:
kl
]
y
.
Check2
(
b
.
keyBuf
.
Read
(
key
)
)
bf
.
Add
(
key
)
}
b
.
finishBlock
(
)
// This will never start a new block.
index
:=
b
.
blockIndex
(
)
b
.
buf
.
Write
(
index
)
// Write bloom filter.
bdata
:=
bf
.
JSONMarshal
(
)
n
,
err
:=
b
.
buf
.
Write
(
bdata
)
y
.
Check
(
err
)
var
buf
[
4
]
byte
binary
.
BigEndian
.
PutUint32
(
buf
[
:
]
,
uint32
(
n
)
)
b
.
buf
.
Write
(
buf
[
:
]
)
return
b
.
buf
.
Bytes
(
)
}

// Finish finishes the table by appending the index.

Finish finishes the table by appending the index .


func (opt *Options) Errorf(format string, v ...interface{}) {
	if opt.Logger == nil {
		return
	}
	opt.Logger.Errorf(format, v...)
}

func ( opt * Options ) Errorf ( format string , v ... interface { } ) { if opt . Logger == nil { return } opt . Logger . Errorf ( format , v ... ) }

// Errorf logs an ERROR log message to the logger specified in opts or to the
// global logger if no logger is specified in opts.

Errorf logs an ERROR log message to the logger specified in opts or to the global logger if no logger is specified in opts .


func (opt *Options) Infof(format string, v ...interface{}) {
	if opt.Logger == nil {
		return
	}
	opt.Logger.Infof(format, v...)
}

func ( opt * Options ) Infof ( format string , v ... interface { } ) { if opt . Logger == nil { return } opt . Logger . Infof ( format , v ... ) }

// Infof logs an INFO message to the logger specified in opts.

Infof logs an INFO message to the logger specified in opts .


func (s *Skiplist) DecrRef() {
	newRef := atomic.AddInt32(&s.ref, -1)
	if newRef > 0 {
		return
	}

	s.arena.reset()
	// Indicate we are closed. Good for testing.  Also, lets GC reclaim memory. Race condition
	// here would suggest we are accessing skiplist when we are supposed to have no reference!
	s.arena = nil
}

// DecrRef decrements the refcount, deallocating the Skiplist when done using it

DecrRef decrements the refcount deallocating the Skiplist when done using it


func NewSkiplist(arenaSize int64) *Skiplist {
	arena := newArena(arenaSize)
	head := newNode(arena, nil, y.ValueStruct{}, maxHeight)
	return &Skiplist{
		height: 1,
		head:   head,
		arena:  arena,
		ref:    1,
	}
}

func NewSkiplist ( arenaSize int64 ) * Skiplist { arena := newArena ( arenaSize ) head := newNode ( arena , nil , y . ValueStruct { } , maxHeight ) return & Skiplist { height : 1 , head : head , arena : arena , ref : 1 , } }

// NewSkiplist makes a new empty skiplist, with a given arena size

NewSkiplist makes a new empty skiplist with a given arena size


func (s *Skiplist) Put(key []byte, v y.ValueStruct) {
	// Since we allow overwrite, we may not need to create a new node. We might not even need to
	// increase the height. Let's defer these actions.

	listHeight := s.getHeight()
	var prev [maxHeight + 1]*node
	var next [maxHeight + 1]*node
	prev[listHeight] = s.head
	next[listHeight] = nil
	for i := int(listHeight) - 1; i >= 0; i-- {
		// Use higher level to speed up for current level.
		prev[i], next[i] = s.findSpliceForLevel(key, prev[i+1], i)
		if prev[i] == next[i] {
			prev[i].setValue(s.arena, v)
			return
		}
	}

	// We do need to create a new node.
	height := randomHeight()
	x := newNode(s.arena, key, v, height)

	// Try to increase s.height via CAS.
	listHeight = s.getHeight()
	for height > int(listHeight) {
		if atomic.CompareAndSwapInt32(&s.height, listHeight, int32(height)) {
			// Successfully increased skiplist.height.
			break
		}
		listHeight = s.getHeight()
	}

	// We always insert from the base level and up. After you add a node in base level, we cannot
	// create a node in the level above because it would have discovered the node in the base level.
	for i := 0; i < height; i++ {
		for {
			if prev[i] == nil {
				y.AssertTrue(i > 1) // This cannot happen in base level.
				// We haven't computed prev, next for this level because height exceeds old listHeight.
				// For these levels, we expect the lists to be sparse, so we can just search from head.
				prev[i], next[i] = s.findSpliceForLevel(key, s.head, i)
				// Someone adds the exact same key before we are able to do so. This can only happen on
				// the base level. But we know we are not on the base level.
				y.AssertTrue(prev[i] != next[i])
			}
			nextOffset := s.arena.getNodeOffset(next[i])
			x.tower[i] = nextOffset
			if prev[i].casNextOffset(i, nextOffset, s.arena.getNodeOffset(x)) {
				// Managed to insert x between prev[i] and next[i]. Go to the next level.
				break
			}
			// CAS failed. We need to recompute prev and next.
			// It is unlikely to be helpful to try to use a different level as we redo the search,
			// because it is unlikely that lots of nodes are inserted between prev[i] and next[i].
			prev[i], next[i] = s.findSpliceForLevel(key, prev[i], i)
			if prev[i] == next[i] {
				y.AssertTruef(i == 0, "Equality can happen only on base level: %d", i)
				prev[i].setValue(s.arena, v)
				return
			}
		}
	}
}


func (s *Skiplist) Get(key []byte) y.ValueStruct {
	n, _ := s.findNear(key, false, true) // findGreaterOrEqual.
	if n == nil {
		return y.ValueStruct{}
	}

	nextKey := s.arena.getKey(n.keyOffset, n.keySize)
	if !y.SameKey(key, nextKey) {
		return y.ValueStruct{}
	}

	valOffset, valSize := n.getValueOffset()
	vs := s.arena.getVal(valOffset, valSize)
	vs.Version = y.ParseTs(nextKey)
	return vs
}

func
(
s
*
Skiplist
)
Get
(
key
[
]
byte
)
y
.
ValueStruct
{
n
,
_
:=
s
.
findNear
(
key
,
false
,
true
)
// findGreaterOrEqual.
if
n
==
{
return
y
.
ValueStruct
{
}
}
nextKey
:=
s
.
arena
.
getKey
(
n
.
keyOffset
,
n
.
keySize
)
if
!
y
.
SameKey
(
key
,
nextKey
)
{
return
y
.
ValueStruct
{
}
}
valOffset
,
valSize
:=
n
.
getValueOffset
(
)
vs
:=
s
.
arena
.
getVal
(
valOffset
,
valSize
)
vs
.
Version
=
y
.
ParseTs
(
nextKey
)
return
vs
}

// Get gets the value associated with the key. It returns a valid value if it finds equal or earlier
// version of the same key.

Get gets the value associated with the key . It returns a valid value if it finds equal or earlier version of the same key .


func (s *Iterator) Key() []byte {
	return s.list.arena.getKey(s.n.keyOffset, s.n.keySize)
}

func ( s * Iterator ) Key ( ) [ ] byte { return s . list . arena . getKey ( s . n . keyOffset , s . n . keySize ) }

// Key returns the key at the current position.

Key returns the key at the current position .


func (s *Iterator) Value() y.ValueStruct {
	valOffset, valSize := s.n.getValueOffset()
	return s.list.arena.getVal(valOffset, valSize)
}

func ( s * Iterator ) Value ( ) y . ValueStruct { valOffset , valSize := s . n . getValueOffset ( ) return s . list . arena . getVal ( valOffset , valSize ) }


func (s *Iterator) Next() {
	y.AssertTrue(s.Valid())
	s.n = s.list.getNext(s.n, 0)
}

func ( s * Iterator ) Next ( ) { y . AssertTrue ( s . Valid ( ) ) s . n = s . list . getNext ( s . n , 0 ) }


func (s *Iterator) Prev() {
	y.AssertTrue(s.Valid())
	s.n, _ = s.list.findNear(s.Key(), true, false) // find <. No equality allowed.
}

func
(
s
*
Iterator
)
Prev
(
)
{
y
.
AssertTrue
(
s
.
Valid
(
)
)
s
.
n
,
_
=
s
.
list
.
findNear
(
s
.
Key
(
)
,
true
,
false
)
// find <. No equality allowed.
}

// Prev advances to the previous position.

Prev advances to the previous position .


func (s *Iterator) Seek(target []byte) {
	s.n, _ = s.list.findNear(target, false, true) // find >=.
}

func
(
s
*
Iterator
)
Seek
(
target
[
]
byte
)
{
s
.
n
,
_
=
s
.
list
.
findNear
(
target
,
false
,
true
)
// find >=.
}

// Seek advances to the first entry with a key >= target.

Seek advances to the first entry with a key > = target .


func (s *Iterator) SeekForPrev(target []byte) {
	s.n, _ = s.list.findNear(target, true, true) // find <=.
}

func
(
s
*
Iterator
)
SeekForPrev
(
target
[
]
byte
)
{
s
.
n
,
_
=
s
.
list
.
findNear
(
target
,
true
,
true
)
// find <=.
}

// SeekForPrev finds an entry with key <= target.

SeekForPrev finds an entry with key < = target .


func (s *Skiplist) NewUniIterator(reversed bool) *UniIterator {
	return &UniIterator{
		iter:     s.NewIterator(),
		reversed: reversed,
	}
}

func ( s * Skiplist ) NewUniIterator ( reversed bool ) * UniIterator { return & UniIterator { iter : s . NewIterator ( ) , reversed : reversed , } }

// NewUniIterator returns a UniIterator.


func (s *UniIterator) Next() {
	if !s.reversed {
		s.iter.Next()
	} else {
		s.iter.Prev()
	}
}

func ( s * UniIterator ) Next ( ) { if ! s . reversed { s . iter . Next ( ) } else { s . iter . Prev ( ) } }


func (s *UniIterator) Seek(key []byte) {
	if !s.reversed {
		s.iter.Seek(key)
	} else {
		s.iter.SeekForPrev(key)
	}
}

func ( s * UniIterator ) Seek ( key [ ] byte ) { if ! s . reversed { s . iter . Seek ( key ) } else { s . iter . SeekForPrev ( key ) } }


func (m *Manifest) asChanges() []*pb.ManifestChange {
	changes := make([]*pb.ManifestChange, 0, len(m.Tables))
	for id, tm := range m.Tables {
		changes = append(changes, newCreateChange(id, int(tm.Level), tm.Checksum))
	}
	return changes
}

func ( m * Manifest ) asChanges ( ) [ ] * pb . ManifestChange { changes := make ( [ ] * pb . ManifestChange , 0 , len ( m . Tables ) ) for id , tm := range m . Tables { changes = append ( changes , newCreateChange ( id , int ( tm . Level ) , tm . Checksum ) ) } return changes }

// asChanges returns a sequence of changes that could be used to recreate the Manifest in its
// present state.

asChanges returns a sequence of changes that could be used to recreate the Manifest in its present state .


func (mf *manifestFile) rewrite() error {
	// In Windows the files should be closed before doing a Rename.
	if err := mf.fp.Close(); err != nil {
		return err
	}
	fp, netCreations, err := helpRewrite(mf.directory, &mf.manifest)
	if err != nil {
		return err
	}
	mf.fp = fp
	mf.manifest.Creations = netCreations
	mf.manifest.Deletions = 0

	return nil
}

// Must be called while appendLock is held.

Must be called while appendLock is held .


func (s *levelHandler) validate() error {
	if s.level == 0 {
		return nil
	}

	s.RLock()
	defer s.RUnlock()
	numTables := len(s.tables)
	for j := 1; j < numTables; j++ {
		if j >= len(s.tables) {
			return errors.Errorf("Level %d, j=%d numTables=%d", s.level, j, numTables)
		}

		if y.CompareKeys(s.tables[j-1].Biggest(), s.tables[j].Smallest()) >= 0 {
			return errors.Errorf(
				"Inter: Biggest(j-1) \n%s\n vs Smallest(j): \n%s\n: level=%d j=%d numTables=%d",
				hex.Dump(s.tables[j-1].Biggest()), hex.Dump(s.tables[j].Smallest()),
				s.level, j, numTables)
		}

		if y.CompareKeys(s.tables[j].Smallest(), s.tables[j].Biggest()) > 0 {
			return errors.Errorf(
				"Intra: %q vs %q: level=%d j=%d numTables=%d",
				s.tables[j].Smallest(), s.tables[j].Biggest(), s.level, j, numTables)
		}
	}
	return nil
}

func ( s * levelHandler ) validate ( ) error { if s . level == 0 { return nil } s . RLock ( ) defer s . RUnlock ( ) numTables := len ( s . tables ) for j := 1 ; j < numTables ; j ++ { if j >= len ( s . tables ) { return errors . Errorf ( " " , s . level , j , numTables ) } if y . CompareKeys ( s . tables [ j - 1 ] . Biggest ( ) , s . tables [ j ] . Smallest ( ) ) >= 0 { return errors . Errorf ( " \n \n \n \n " , hex . Dump ( s . tables [ j - 1 ] . Biggest ( ) ) , hex . Dump ( s . tables [ j ] . Smallest ( ) ) , s . level , j , numTables ) } if y . CompareKeys ( s . tables [ j ] . Smallest ( ) , s . tables [ j ] . Biggest ( ) ) > 0 { return errors . Errorf ( " " , s . tables [ j ] . Smallest ( ) , s . tables [ j ] . Biggest ( ) , s . level , j , numTables ) } } return nil }

// Check does some sanity check on one level of data or in-memory index.

Check does some sanity check on one level of data or in - memory index .


func acquireDirectoryLock(dirPath string, pidFileName string, readOnly bool) (*directoryLockGuard, error) {
	if readOnly {
		return nil, ErrWindowsNotSupported
	}

	// Convert to absolute path so that Release still works even if we do an unbalanced
	// chdir in the meantime.
	absLockFilePath, err := filepath.Abs(filepath.Join(dirPath, pidFileName))
	if err != nil {
		return nil, errors.Wrap(err, "Cannot get absolute path for pid lock file")
	}

	// This call creates a file handler in memory that only one process can use at a time. When
	// that process ends, the file is deleted by the system.
	// FILE_ATTRIBUTE_TEMPORARY is used to tell Windows to try to create the handle in memory.
	// FILE_FLAG_DELETE_ON_CLOSE is not specified in syscall_windows.go but tells Windows to delete
	// the file when all processes holding the handler are closed.
	// XXX: this works but it's a bit klunky. i'd prefer to use LockFileEx but it needs unsafe pkg.
	h, err := syscall.CreateFile(
		syscall.StringToUTF16Ptr(absLockFilePath), 0, 0, nil,
		syscall.OPEN_ALWAYS,
		uint32(FILE_ATTRIBUTE_TEMPORARY|FILE_FLAG_DELETE_ON_CLOSE),
		0)
	if err != nil {
		return nil, errors.Wrapf(err,
			"Cannot create lock file %q.  Another process is using this Badger database",
			absLockFilePath)
	}

	return &directoryLockGuard{h: h, path: absLockFilePath}, nil
}

// AcquireDirectoryLock acquires exclusive access to a directory.

AcquireDirectoryLock acquires exclusive access to a directory .


func (g *directoryLockGuard) release() error {
	g.path = ""
	return syscall.CloseHandle(g.h)
}

func ( g * directoryLockGuard ) release ( ) error { g . path = " " return syscall . CloseHandle ( g . h ) }


func AssertTruef(b bool, format string, args ...interface{}) {
	if !b {
		log.Fatalf("%+v", errors.Errorf(format, args...))
	}
}

func AssertTruef ( b bool , format string , args ... interface { } ) { if ! b { log . Fatalf ( " " , errors . Errorf ( format , args ... ) ) } }

// AssertTruef is AssertTrue with extra info.

AssertTruef is AssertTrue with extra info .


func Wrapf(err error, format string, args ...interface{}) error {
	if !debugMode {
		if err == nil {
			return nil
		}
		return fmt.Errorf(format+" error: %+v", append(args, err)...)
	}
	return errors.Wrapf(err, format, args...)
}

func Wrapf ( err error , format string , args ... interface { } ) error { if ! debugMode { if err == nil { return nil } return fmt . Errorf ( format + " " , append ( args , err ) ... ) } return errors . Wrapf ( err , format , args ... ) }


func (s *levelHandler) initTables(tables []*table.Table) {
	s.Lock()
	defer s.Unlock()

	s.tables = tables
	s.totalSize = 0
	for _, t := range tables {
		s.totalSize += t.Size()
	}

	if s.level == 0 {
		// Key range will overlap. Just sort by fileID in ascending order
		// because newer tables are at the end of level 0.
		sort.Slice(s.tables, func(i, j int) bool {
			return s.tables[i].ID() < s.tables[j].ID()
		})
	} else {
		// Sort tables by keys.
		sort.Slice(s.tables, func(i, j int) bool {
			return y.CompareKeys(s.tables[i].Smallest(), s.tables[j].Smallest()) < 0
		})
	}
}

// initTables replaces s.tables with given tables. This is done during loading.

initTables replaces s . tables with given tables . This is done during loading .


func (s *levelHandler) deleteTables(toDel []*table.Table) error {
	s.Lock() // s.Unlock() below

	toDelMap := make(map[uint64]struct{})
	for _, t := range toDel {
		toDelMap[t.ID()] = struct{}{}
	}

	// Make a copy as iterators might be keeping a slice of tables.
	var newTables []*table.Table
	for _, t := range s.tables {
		_, found := toDelMap[t.ID()]
		if !found {
			newTables = append(newTables, t)
			continue
		}
		s.totalSize -= t.Size()
	}
	s.tables = newTables

	s.Unlock() // Unlock s _before_ we DecrRef our tables, which can be slow.

	return decrRefs(toDel)
}

// deleteTables remove tables idx0, ..., idx1-1.


func (s *levelHandler) tryAddLevel0Table(t *table.Table) bool {
	y.AssertTrue(s.level == 0)
	// Need lock as we may be deleting the first table during a level 0 compaction.
	s.Lock()
	defer s.Unlock()
	if len(s.tables) >= s.db.opt.NumLevelZeroTablesStall {
		return false
	}

	s.tables = append(s.tables, t)
	t.IncrRef()
	s.totalSize += t.Size()

	return true
}

// tryAddLevel0Table returns true if ok and no stalling.

tryAddLevel0Table returns true if ok and no stalling .


func (s *levelHandler) getTableForKey(key []byte) ([]*table.Table, func() error) {
	s.RLock()
	defer s.RUnlock()

	if s.level == 0 {
		// For level 0, we need to check every table. Remember to make a copy as s.tables may change
		// once we exit this function, and we don't want to lock s.tables while seeking in tables.
		// CAUTION: Reverse the tables.
		out := make([]*table.Table, 0, len(s.tables))
		for i := len(s.tables) - 1; i >= 0; i-- {
			out = append(out, s.tables[i])
			s.tables[i].IncrRef()
		}
		return out, func() error {
			for _, t := range out {
				if err := t.DecrRef(); err != nil {
					return err
				}
			}
			return nil
		}
	}
	// For level >= 1, we can do a binary search as key range does not overlap.
	idx := sort.Search(len(s.tables), func(i int) bool {
		return y.CompareKeys(s.tables[i].Biggest(), key) >= 0
	})
	if idx >= len(s.tables) {
		// Given key is strictly > than every element we have.
		return nil, func() error { return nil }
	}
	tbl := s.tables[idx]
	tbl.IncrRef()
	return []*table.Table{tbl}, tbl.DecrRef
}

// getTableForKey acquires a read-lock to access s.tables. It returns a list of tableHandlers.

getTableForKey acquires a read - lock to access s . tables . It returns a list of tableHandlers .


func (s *levelHandler) get(key []byte) (y.ValueStruct, error) {
	tables, decr := s.getTableForKey(key)
	keyNoTs := y.ParseKey(key)

	var maxVs y.ValueStruct
	for _, th := range tables {
		if th.DoesNotHave(keyNoTs) {
			y.NumLSMBloomHits.Add(s.strLevel, 1)
			continue
		}

		it := th.NewIterator(false)
		defer it.Close()

		y.NumLSMGets.Add(s.strLevel, 1)
		it.Seek(key)
		if !it.Valid() {
			continue
		}
		if y.SameKey(key, it.Key()) {
			if version := y.ParseTs(it.Key()); maxVs.Version < version {
				maxVs = it.Value()
				maxVs.Version = version
			}
		}
	}
	return maxVs, decr()
}

func ( s * levelHandler ) get ( key [ ] byte ) ( y . ValueStruct , error ) { tables , decr := s . getTableForKey ( key ) keyNoTs := y . ParseKey ( key ) var maxVs y . ValueStruct for _ , th := range tables { if th . DoesNotHave ( keyNoTs ) { y . NumLSMBloomHits . Add ( s . strLevel , 1 ) continue } it := th . NewIterator ( false ) defer it . Close ( ) y . NumLSMGets . Add ( s . strLevel , 1 ) it . Seek ( key ) if ! it . Valid ( ) { continue } if y . SameKey ( key , it . Key ( ) ) { if version := y . ParseTs ( it . Key ( ) ) ; maxVs . Version < version { maxVs = it . Value ( ) maxVs . Version = version } } } return maxVs , decr ( ) }

// get returns value for a given key or the key after that. If not found, return nil.

get returns value for a given key or the key after that . If not found return nil .


func (s *levelHandler) overlappingTables(_ levelHandlerRLocked, kr keyRange) (int, int) {
	if len(kr.left) == 0 || len(kr.right) == 0 {
		return 0, 0
	}
	left := sort.Search(len(s.tables), func(i int) bool {
		return y.CompareKeys(kr.left, s.tables[i].Biggest()) <= 0
	})
	right := sort.Search(len(s.tables), func(i int) bool {
		return y.CompareKeys(kr.right, s.tables[i].Smallest()) < 0
	})
	return left, right
}

func ( s * levelHandler ) overlappingTables ( _ levelHandlerRLocked , kr keyRange ) ( int , int ) { if len ( kr . left ) == 0 || len ( kr . right ) == 0 { return 0 , 0 } left := sort . Search ( len ( s . tables ) , func ( i int ) bool { return y . CompareKeys ( kr . left , s . tables [ i ] . Biggest ( ) ) <= 0 } ) right := sort . Search ( len ( s . tables ) , func ( i int ) bool { return y . CompareKeys ( kr . right , s . tables [ i ] . Smallest ( ) ) < 0 } ) return left , right }

// overlappingTables returns the tables that intersect with key range. Returns a half-interval.
// This function should already have acquired a read lock, and this is so important the caller must
// pass an empty parameter declaring such.

overlappingTables returns the tables that intersect with key range . Returns a half - interval . This function should already have acquired a read lock and this is so important the caller must pass an empty parameter declaring such .


func (item *Item) String() string {
	return fmt.Sprintf("key=%q, version=%d, meta=%x", item.Key(), item.Version(), item.meta)
}

func ( item * Item ) String ( ) string { return fmt . Sprintf ( " " , item . Key ( ) , item . Version ( ) , item . meta ) }

// String returns a string representation of Item


func (item *Item) KeyCopy(dst []byte) []byte {
	return y.SafeCopy(dst, item.key)
}

func ( item * Item ) KeyCopy ( dst [ ] byte ) [ ] byte { return y . SafeCopy ( dst , item . key ) }

// KeyCopy returns a copy of the key of the item, writing it to dst slice.
// If nil is passed, or capacity of dst isn't sufficient, a new slice would be allocated and
// returned.

KeyCopy returns a copy of the key of the item writing it to dst slice . If nil is passed or capacity of dst isn t sufficient a new slice would be allocated and returned .


func (item *Item) ValueSize() int64 {
	if !item.hasValue() {
		return 0
	}
	if (item.meta & bitValuePointer) == 0 {
		return int64(len(item.vptr))
	}
	var vp valuePointer
	vp.Decode(item.vptr)

	klen := int64(len(item.key) + 8) // 8 bytes for timestamp.
	return int64(vp.Len) - klen - headerBufSize - crc32.Size
}

func
(
item
*
Item
)
ValueSize
(
)
int64
{
if
!
item
.
hasValue
(
)
{
return
0
}
if
(
item
.
meta
&
bitValuePointer
)
==
0
{
return
int64
(
len
(
item
.
vptr
)
)
}
var
vp
valuePointer
vp
.
Decode
(
item
.
vptr
)
klen
:=
int64
(
len
(
item
.
key
)
+
8
)
// 8 bytes for timestamp.
return
int64
(
vp
.
Len
)
klen
headerBufSize
crc32
.
Size
}

// ValueSize returns the exact size of the value.
//
// This can be called to quickly estimate the size of a value without fetching
// it.

ValueSize returns the exact size of the value . This can be called to quickly estimate the size of a value without fetching it .


func (txn *Txn) NewKeyIterator(key []byte, opt IteratorOptions) *Iterator {
	if len(opt.Prefix) > 0 {
		panic("opt.Prefix should be nil for NewKeyIterator.")
	}
	opt.Prefix = key // This key must be without the timestamp.
	opt.prefixIsKey = true
	return txn.NewIterator(opt)
}

// NewKeyIterator is just like NewIterator, but allows the user to iterate over all versions of a
// single key. Internally, it sets the Prefix option in provided opt, and uses that prefix to
// additionally run bloom filter lookups before picking tables from the LSM tree.

NewKeyIterator is just like NewIterator but allows the user to iterate over all versions of a single key . Internally it sets the Prefix option in provided opt and uses that prefix to additionally run bloom filter lookups before picking tables from the LSM tree .


func (it *Iterator) Valid() bool {
	if it.item == nil {
		return false
	}
	return bytes.HasPrefix(it.item.key, it.opt.Prefix)
}

func ( it * Iterator ) Valid ( ) bool { if it . item == nil { return false } return bytes . HasPrefix ( it . item . key , it . opt . Prefix ) }

// Valid returns false when iteration is done.

Valid returns false when iteration is done .


func (it *Iterator) ValidForPrefix(prefix []byte) bool {
	return it.Valid() && bytes.HasPrefix(it.item.key, prefix)
}

func ( it * Iterator ) ValidForPrefix ( prefix [ ] byte ) bool { return it . Valid ( ) && bytes . HasPrefix ( it . item . key , prefix ) }

// ValidForPrefix returns false when iteration is done
// or when the current key is not prefixed by the specified prefix.

ValidForPrefix returns false when iteration is done or when the current key is not prefixed by the specified prefix .


func (it *Iterator) Close() {
	if it.closed {
		return
	}
	it.closed = true

	it.iitr.Close()
	// It is important to wait for the fill goroutines to finish. Otherwise, we might leave zombie
	// goroutines behind, which are waiting to acquire file read locks after DB has been closed.
	waitFor := func(l list) {
		item := l.pop()
		for item != nil {
			item.wg.Wait()
			item = l.pop()
		}
	}
	waitFor(it.waste)
	waitFor(it.data)

	// TODO: We could handle this error.
	_ = it.txn.db.vlog.decrIteratorCount()
	atomic.AddInt32(&it.txn.numIterators, -1)
}

// Close would close the iterator. It is important to call this when you're done with iteration.

Close would close the iterator . It is important to call this when you re done with iteration .


func (it *Iterator) parseItem() bool {
	mi := it.iitr
	key := mi.Key()

	setItem := func(item *Item) {
		if it.item == nil {
			it.item = item
		} else {
			it.data.push(item)
		}
	}

	// Skip badger keys.
	if !it.opt.internalAccess && bytes.HasPrefix(key, badgerPrefix) {
		mi.Next()
		return false
	}

	// Skip any versions which are beyond the readTs.
	version := y.ParseTs(key)
	if version > it.readTs {
		mi.Next()
		return false
	}

	if it.opt.AllVersions {
		// Return deleted or expired values also, otherwise user can't figure out
		// whether the key was deleted.
		item := it.newItem()
		it.fill(item)
		setItem(item)
		mi.Next()
		return true
	}

	// If iterating in forward direction, then just checking the last key against current key would
	// be sufficient.
	if !it.opt.Reverse {
		if y.SameKey(it.lastKey, key) {
			mi.Next()
			return false
		}
		// Only track in forward direction.
		// We should update lastKey as soon as we find a different key in our snapshot.
		// Consider keys: a 5, b 7 (del), b 5. When iterating, lastKey = a.
		// Then we see b 7, which is deleted. If we don't store lastKey = b, we'll then return b 5,
		// which is wrong. Therefore, update lastKey here.
		it.lastKey = y.SafeCopy(it.lastKey, mi.Key())
	}

FILL:
	// If deleted, advance and return.
	vs := mi.Value()
	if isDeletedOrExpired(vs.Meta, vs.ExpiresAt) {
		mi.Next()
		return false
	}

	item := it.newItem()
	it.fill(item)
	// fill item based on current cursor position. All Next calls have returned, so reaching here
	// means no Next was called.

	mi.Next()                           // Advance but no fill item yet.
	if !it.opt.Reverse || !mi.Valid() { // Forward direction, or invalid.
		setItem(item)
		return true
	}

	// Reverse direction.
	nextTs := y.ParseTs(mi.Key())
	mik := y.ParseKey(mi.Key())
	if nextTs <= it.readTs && bytes.Equal(mik, item.key) {
		// This is a valid potential candidate.
		goto FILL
	}
	// Ignore the next candidate. Return the current one.
	setItem(item)
	return true
}

// parseItem is a complex function because it needs to handle both forward and reverse iteration
// implementation. We store keys such that their versions are sorted in descending order. This makes
// forward iteration efficient, but revese iteration complicated. This tradeoff is better because
// forward iteration is more common than reverse.
//
// This function advances the iterator.

parseItem is a complex function because it needs to handle both forward and reverse iteration implementation . We store keys such that their versions are sorted in descending order . This makes forward iteration efficient but revese iteration complicated . This tradeoff is better because forward iteration is more common than reverse . This function advances the iterator .


func (it *Iterator) Seek(key []byte) {
	for i := it.data.pop(); i != nil; i = it.data.pop() {
		i.wg.Wait()
		it.waste.push(i)
	}

	it.lastKey = it.lastKey[:0]
	if len(key) == 0 {
		key = it.opt.Prefix
	}
	if len(key) == 0 {
		it.iitr.Rewind()
		it.prefetch()
		return
	}

	if !it.opt.Reverse {
		key = y.KeyWithTs(key, it.txn.readTs)
	} else {
		key = y.KeyWithTs(key, 0)
	}
	it.iitr.Seek(key)
	it.prefetch()
}

func ( it * Iterator ) Seek ( key [ ] byte ) { for i := it . data . pop ( ) ; i != nil ; i = it . data . pop ( ) { i . wg . Wait ( ) it . waste . push ( i ) } it . lastKey = it . lastKey [ : 0 ] if len ( key ) == 0 { key = it . opt . Prefix } if len ( key ) == 0 { it . iitr . Rewind ( ) it . prefetch ( ) return } if ! it . opt . Reverse { key = y . KeyWithTs ( key , it . txn . readTs ) } else { key = y . KeyWithTs ( key , 0 ) } it . iitr . Seek ( key ) it . prefetch ( ) }

// Seek would seek to the provided key if present. If absent, it would seek to the next smallest key
// greater than the provided key if iterating in the forward direction. Behavior would be reversed if
// iterating backwards.

Seek would seek to the provided key if present . If absent it would seek to the next smallest key greater than the provided key if iterating in the forward direction . Behavior would be reversed if iterating backwards .


func (db *DB) GetMergeOperator(key []byte,
	f MergeFunc, dur time.Duration) *MergeOperator {
	op := &MergeOperator{
		f:      f,
		db:     db,
		key:    key,
		closer: y.NewCloser(1),
	}

	go op.runCompactions(dur)
	return op
}

func ( db * DB ) GetMergeOperator ( key [ ] byte , f MergeFunc , dur time . Duration ) * MergeOperator { op := & MergeOperator { f : f , db : db , key : key , closer : y . NewCloser ( 1 ) , } go op . runCompactions ( dur ) return op }

// GetMergeOperator creates a new MergeOperator for a given key and returns a
// pointer to it. It also fires off a goroutine that performs a compaction using
// the merge function that runs periodically, as specified by dur.

GetMergeOperator creates a new MergeOperator for a given key and returns a pointer to it . It also fires off a goroutine that performs a compaction using the merge function that runs periodically as specified by dur .


func (op *MergeOperator) Get() ([]byte, error) {
	op.RLock()
	defer op.RUnlock()
	var existing []byte
	err := op.db.View(func(txn *Txn) (err error) {
		existing, err = op.iterateAndMerge(txn)
		return err
	})
	if err == errNoMerge {
		return existing, nil
	}
	return existing, err
}

func ( op * MergeOperator ) Get ( ) ( [ ] byte , error ) { op . RLock ( ) defer op . RUnlock ( ) var existing [ ] byte err := op . db . View ( func ( txn * Txn ) ( err error ) { existing , err = op . iterateAndMerge ( txn ) return err } ) if err == errNoMerge { return existing , nil } return existing , err }

// Get returns the latest value for the merge operator, which is derived by
// applying the merge function to all the values added so far.
//
// If Add has not been called even once, Get will return ErrKeyNotFound.

Get returns the latest value for the merge operator which is derived by applying the merge function to all the values added so far . If Add has not been called even once Get will return ErrKeyNotFound .


func (cs *compactStatus) compareAndAdd(_ thisAndNextLevelRLocked, cd compactDef) bool {
	cs.Lock()
	defer cs.Unlock()

	level := cd.thisLevel.level

	y.AssertTruef(level < len(cs.levels)-1, "Got level %d. Max levels: %d", level, len(cs.levels))
	thisLevel := cs.levels[level]
	nextLevel := cs.levels[level+1]

	if thisLevel.overlapsWith(cd.thisRange) {
		return false
	}
	if nextLevel.overlapsWith(cd.nextRange) {
		return false
	}
	// Check whether this level really needs compaction or not. Otherwise, we'll end up
	// running parallel compactions for the same level.
	// Update: We should not be checking size here. Compaction priority already did the size checks.
	// Here we should just be executing the wish of others.

	thisLevel.ranges = append(thisLevel.ranges, cd.thisRange)
	nextLevel.ranges = append(nextLevel.ranges, cd.nextRange)
	thisLevel.delSize += cd.thisSize
	return true
}

// compareAndAdd will check whether we can run this compactDef. That it doesn't overlap with any
// other running compaction. If it can be run, it would store this run in the compactStatus state.

compareAndAdd will check whether we can run this compactDef . That it doesn t overlap with any other running compaction . If it can be run it would store this run in the compactStatus state .


func newArena(n int64) *Arena {
	// Don't store data at position 0 in order to reserve offset=0 as a kind
	// of nil pointer.
	out := &Arena{
		n:   1,
		buf: make([]byte, n),
	}
	return out
}


func (s *Arena) putNode(height int) uint32 {
	// Compute the amount of the tower that will never be used, since the height
	// is less than maxHeight.
	unusedSize := (maxHeight - height) * offsetSize

	// Pad the allocation with enough bytes to ensure pointer alignment.
	l := uint32(MaxNodeSize - unusedSize + nodeAlign)
	n := atomic.AddUint32(&s.n, l)
	y.AssertTruef(int(n) <= len(s.buf),
		"Arena too small, toWrite:%d newTotal:%d limit:%d",
		l, n, len(s.buf))

	// Return the aligned offset.
	m := (n - l + uint32(nodeAlign)) & ^uint32(nodeAlign)
	return m
}

// putNode allocates a node in the arena. The node is aligned on a pointer-sized
// boundary. The arena offset of the node is returned.

putNode allocates a node in the arena . The node is aligned on a pointer - sized boundary . The arena offset of the node is returned .


func (s *Arena) getNode(offset uint32) *node {
	if offset == 0 {
		return nil
	}

	return (*node)(unsafe.Pointer(&s.buf[offset]))
}

func ( s * Arena ) getNode ( offset uint32 ) * node { if offset == 0 { return nil } return ( * node ) ( unsafe . Pointer ( & s . buf [ offset ] ) ) }

// getNode returns a pointer to the node located at offset. If the offset is
// zero, then the nil node pointer is returned.

getNode returns a pointer to the node located at offset . If the offset is zero then the nil node pointer is returned .


func (s *Arena) getKey(offset uint32, size uint16) []byte {
	return s.buf[offset : offset+uint32(size)]
}

func ( s * Arena ) getKey ( offset uint32 , size uint16 ) [ ] byte { return s . buf [ offset : offset + uint32 ( size ) ] }


func (s *Arena) getVal(offset uint32, size uint16) (ret y.ValueStruct) {
	ret.Decode(s.buf[offset : offset+uint32(size)])
	return
}

func ( s * Arena ) getVal ( offset uint32 , size uint16 ) ( ret y . ValueStruct ) { ret . Decode ( s . buf [ offset : offset + uint32 ( size ) ] ) return }

// getVal returns byte slice at offset. The given size should be just the value
// size and should NOT include the meta bytes.

getVal returns byte slice at offset . The given size should be just the value size and should NOT include the meta bytes .


func (s *Arena) getNodeOffset(nd *node) uint32 {
	if nd == nil {
		return 0
	}

	return uint32(uintptr(unsafe.Pointer(nd)) - uintptr(unsafe.Pointer(&s.buf[0])))
}

func ( s * Arena ) getNodeOffset ( nd * node ) uint32 { if nd == nil { return 0 } return uint32 ( uintptr ( unsafe . Pointer ( nd ) ) - uintptr ( unsafe . Pointer ( & s . buf [ 0 ] ) ) ) }

// getNodeOffset returns the offset of node in the arena. If the node pointer is
// nil, then the zero offset is returned.

getNodeOffset returns the offset of node in the arena . If the node pointer is nil then the zero offset is returned .


func init() {
	NumReads = expvar.NewInt("badger_disk_reads_total")
	NumWrites = expvar.NewInt("badger_disk_writes_total")
	NumBytesRead = expvar.NewInt("badger_read_bytes")
	NumBytesWritten = expvar.NewInt("badger_written_bytes")
	NumLSMGets = expvar.NewMap("badger_lsm_level_gets_total")
	NumLSMBloomHits = expvar.NewMap("badger_lsm_bloom_hits_total")
	NumGets = expvar.NewInt("badger_gets_total")
	NumPuts = expvar.NewInt("badger_puts_total")
	NumBlockedPuts = expvar.NewInt("badger_blocked_puts_total")
	NumMemtableGets = expvar.NewInt("badger_memtable_gets_total")
	LSMSize = expvar.NewMap("badger_lsm_size_bytes")
	VlogSize = expvar.NewMap("badger_vlog_size_bytes")
	PendingWrites = expvar.NewMap("badger_pending_writes_total")
}

func init ( ) { NumReads = expvar . NewInt ( " " ) NumWrites = expvar . NewInt ( " " ) NumBytesRead = expvar . NewInt ( " " ) NumBytesWritten = expvar . NewInt ( " " ) NumLSMGets = expvar . NewMap ( " " ) NumLSMBloomHits = expvar . NewMap ( " " ) NumGets = expvar . NewInt ( " " ) NumPuts = expvar . NewInt ( " " ) NumBlockedPuts = expvar . NewInt ( " " ) NumMemtableGets = expvar . NewInt ( " " ) LSMSize = expvar . NewMap ( " " ) VlogSize = expvar . NewMap ( " " ) PendingWrites = expvar . NewMap ( " " ) }

// These variables are global and have cumulative values for all kv stores.

These variables are global and have cumulative values for all kv stores .


func revertToManifest(kv *DB, mf *Manifest, idMap map[uint64]struct{}) error {
	// 1. Check all files in manifest exist.
	for id := range mf.Tables {
		if _, ok := idMap[id]; !ok {
			return fmt.Errorf("file does not exist for table %d", id)
		}
	}

	// 2. Delete files that shouldn't exist.
	for id := range idMap {
		if _, ok := mf.Tables[id]; !ok {
			kv.elog.Printf("Table file %d not referenced in MANIFEST\n", id)
			filename := table.NewFilename(id, kv.opt.Dir)
			if err := os.Remove(filename); err != nil {
				return y.Wrapf(err, "While removing table %d", id)
			}
		}
	}

	return nil
}

// revertToManifest checks that all necessary table files exist and removes all table files not
// referenced by the manifest.  idMap is a set of table file id's that were read from the directory
// listing.

revertToManifest checks that all necessary table files exist and removes all table files not referenced by the manifest . idMap is a set of table file id s that were read from the directory listing .


func (s *levelsController) dropTree() (int, error) {
	// First pick all tables, so we can create a manifest changelog.
	var all []*table.Table
	for _, l := range s.levels {
		l.RLock()
		all = append(all, l.tables...)
		l.RUnlock()
	}
	if len(all) == 0 {
		return 0, nil
	}

	// Generate the manifest changes.
	changes := []*pb.ManifestChange{}
	for _, table := range all {
		changes = append(changes, newDeleteChange(table.ID()))
	}
	changeSet := pb.ManifestChangeSet{Changes: changes}
	if err := s.kv.manifest.addChanges(changeSet.Changes); err != nil {
		return 0, err
	}

	// Now that manifest has been successfully written, we can delete the tables.
	for _, l := range s.levels {
		l.Lock()
		l.totalSize = 0
		l.tables = l.tables[:0]
		l.Unlock()
	}
	for _, table := range all {
		if err := table.DecrRef(); err != nil {
			return 0, err
		}
	}
	return len(all), nil
}

// dropTree picks all tables from all levels, creates a manifest changeset,
// applies it, and then decrements the refs of these tables, which would result
// in their deletion.

dropTree picks all tables from all levels creates a manifest changeset applies it and then decrements the refs of these tables which would result in their deletion .


func (s *levelsController) dropPrefix(prefix []byte) error {
	opt := s.kv.opt
	for _, l := range s.levels {
		l.RLock()
		if l.level == 0 {
			size := len(l.tables)
			l.RUnlock()

			if size > 0 {
				cp := compactionPriority{
					level: 0,
					score: 1.74,
					// A unique number greater than 1.0 does two things. Helps identify this
					// function in logs, and forces a compaction.
					dropPrefix: prefix,
				}
				if err := s.doCompact(cp); err != nil {
					opt.Warningf("While compacting level 0: %v", err)
					return nil
				}
			}
			continue
		}

		var tables []*table.Table
		for _, table := range l.tables {
			var absent bool
			switch {
			case bytes.HasPrefix(table.Smallest(), prefix):
			case bytes.HasPrefix(table.Biggest(), prefix):
			case bytes.Compare(prefix, table.Smallest()) > 0 &&
				bytes.Compare(prefix, table.Biggest()) < 0:
			default:
				absent = true
			}
			if !absent {
				tables = append(tables, table)
			}
		}
		l.RUnlock()
		if len(tables) == 0 {
			continue
		}

		cd := compactDef{
			elog:       trace.New(fmt.Sprintf("Badger.L%d", l.level), "Compact"),
			thisLevel:  l,
			nextLevel:  l,
			top:        []*table.Table{},
			bot:        tables,
			dropPrefix: prefix,
		}
		if err := s.runCompactDef(l.level, cd); err != nil {
			opt.Warningf("While running compact def: %+v. Error: %v", cd, err)
			return err
		}
	}
	return nil
}

// dropPrefix runs a L0->L1 compaction, and then runs same level compaction on the rest of the
// levels. For L0->L1 compaction, it runs compactions normally, but skips over all the keys with the
// provided prefix. For Li->Li compactions, it picks up the tables which would have the prefix. The
// tables who only have keys with this prefix are quickly dropped. The ones which have other keys
// are run through MergeIterator and compacted to create new tables. All the mechanisms of
// compactions apply, i.e. level sizes and MANIFEST are updated as in the normal flow.

dropPrefix runs a L0 - > L1 compaction and then runs same level compaction on the rest of the levels . For L0 - > L1 compaction it runs compactions normally but skips over all the keys with the provided prefix . For Li - > Li compactions it picks up the tables which would have the prefix . The tables who only have keys with this prefix are quickly dropped . The ones which have other keys are run through MergeIterator and compacted to create new tables . All the mechanisms of compactions apply i . e . level sizes and MANIFEST are updated as in the normal flow .


func (s *levelsController) isLevel0Compactable() bool {
	return s.levels[0].numTables() >= s.kv.opt.NumLevelZeroTables
}

func ( s * levelsController ) isLevel0Compactable ( ) bool { return s . levels [ 0 ] . numTables ( ) >= s . kv . opt . NumLevelZeroTables }

// Returns true if level zero may be compacted, without accounting for compactions that already
// might be happening.

Returns true if level zero may be compacted without accounting for compactions that already might be happening .


func (s *levelsController) doCompact(p compactionPriority) error {
	l := p.level
	y.AssertTrue(l+1 < s.kv.opt.MaxLevels) // Sanity check.

	cd := compactDef{
		elog:       trace.New(fmt.Sprintf("Badger.L%d", l), "Compact"),
		thisLevel:  s.levels[l],
		nextLevel:  s.levels[l+1],
		dropPrefix: p.dropPrefix,
	}
	cd.elog.SetMaxEvents(100)
	defer cd.elog.Finish()

	s.kv.opt.Infof("Got compaction priority: %+v", p)

	// While picking tables to be compacted, both levels' tables are expected to
	// remain unchanged.
	if l == 0 {
		if !s.fillTablesL0(&cd) {
			return errFillTables
		}

	} else {
		if !s.fillTables(&cd) {
			return errFillTables
		}
	}
	defer s.cstatus.delete(cd) // Remove the ranges from compaction status.

	s.kv.opt.Infof("Running for level: %d\n", cd.thisLevel.level)
	s.cstatus.toLog(cd.elog)
	if err := s.runCompactDef(l, cd); err != nil {
		// This compaction couldn't be done successfully.
		s.kv.opt.Warningf("LOG Compact FAILED with error: %+v: %+v", err, cd)
		return err
	}

	s.cstatus.toLog(cd.elog)
	s.kv.opt.Infof("Compaction for level: %d DONE", cd.thisLevel.level)
	return nil
}

// doCompact picks some table on level l and compacts it away to the next level.

doCompact picks some table on level l and compacts it away to the next level .


func (s *levelsController) get(key []byte, maxVs *y.ValueStruct) (y.ValueStruct, error) {
	// It's important that we iterate the levels from 0 on upward.  The reason is, if we iterated
	// in opposite order, or in parallel (naively calling all the h.RLock() in some order) we could
	// read level L's tables post-compaction and level L+1's tables pre-compaction.  (If we do
	// parallelize this, we will need to call the h.RLock() function by increasing order of level
	// number.)
	version := y.ParseTs(key)
	for _, h := range s.levels {
		vs, err := h.get(key) // Calls h.RLock() and h.RUnlock().
		if err != nil {
			return y.ValueStruct{}, errors.Wrapf(err, "get key: %q", key)
		}
		if vs.Value == nil && vs.Meta == 0 {
			continue
		}
		if maxVs == nil || vs.Version == version {
			return vs, nil
		}
		if maxVs.Version < vs.Version {
			*maxVs = vs
		}
	}
	if maxVs != nil {
		return *maxVs, nil
	}
	return y.ValueStruct{}, nil
}

// get returns the found value if any. If not found, we return nil.

get returns the found value if any . If not found we return nil .


func seekTotal(txn *badger.Txn) ([]account, error) {
	expected := uint64(numAccounts) * uint64(initialBal)
	var accounts []account

	var total uint64
	for i := 0; i < numAccounts; i++ {
		item, err := txn.Get(key(i))
		if err != nil {
			log.Printf("Error for account: %d. err=%v. key=%q\n", i, err, key(i))
			return accounts, err
		}
		val, err := item.ValueCopy(nil)
		if err != nil {
			return accounts, err
		}
		acc := account{
			Id:  i,
			Bal: toUint64(val),
		}
		accounts = append(accounts, acc)
		total += acc.Bal
	}
	if total != expected {
		log.Printf("Balance did NOT match up. Expected: %d. Received: %d",
			expected, total)
		atomic.AddInt32(&stopAll, 1)
		return accounts, errFailure
	}
	return accounts, nil
}

func seekTotal ( txn * badger . Txn ) ( [ ] account , error ) { expected := uint64 ( numAccounts ) * uint64 ( initialBal ) var accounts [ ] account var total uint64 for i := 0 ; i < numAccounts ; i ++ { item , err := txn . Get ( key ( i ) ) if err != nil { log . Printf ( " \n " , i , err , key ( i ) ) return accounts , err } val , err := item . ValueCopy ( nil ) if err != nil { return accounts , err } acc := account { Id : i , Bal : toUint64 ( val ) , } accounts = append ( accounts , acc ) total += acc . Bal } if total != expected { log . Printf ( " " , expected , total ) atomic . AddInt32 ( & stopAll , 1 ) return accounts , errFailure } return accounts , nil }

// seekTotal retrives the total of all accounts by seeking for each account key.

seekTotal retrives the total of all accounts by seeking for each account key .


func findFirstInvalidTxn(db *badger.DB, lowTs, highTs uint64) uint64 {
	checkAt := func(ts uint64) error {
		txn := db.NewTransactionAt(ts, false)
		_, err := seekTotal(txn)
		txn.Discard()
		return err
	}

	if highTs-lowTs < 1 {
		log.Printf("Checking at lowTs: %d\n", lowTs)
		err := checkAt(lowTs)
		if err == errFailure {
			fmt.Printf("Violation at ts: %d\n", lowTs)
			return lowTs
		} else if err != nil {
			log.Printf("Error at lowTs: %d. Err=%v\n", lowTs, err)
			return 0
		}
		fmt.Printf("No violation found at ts: %d\n", lowTs)
		return 0
	}

	midTs := (lowTs + highTs) / 2
	log.Println()
	log.Printf("Checking. low=%d. high=%d. mid=%d\n", lowTs, highTs, midTs)
	err := checkAt(midTs)
	if err == badger.ErrKeyNotFound || err == nil {
		// If no failure, move to higher ts.
		return findFirstInvalidTxn(db, midTs+1, highTs)
	}
	// Found an error.
	return findFirstInvalidTxn(db, lowTs, midTs)
}

func
findFirstInvalidTxn
(
db
*
badger
.
DB
,
lowTs
,
highTs
uint64
)
uint64
{
checkAt
:=
func
(
ts
uint64
)
error
{
txn
:=
db
.
NewTransactionAt
(
ts
,
false
)
_
,
err
:=
seekTotal
(
txn
)
txn
.
Discard
(
)
return
err
}
if
highTs
lowTs
<
1
{
log
.
Printf
(
"
\n
"
,
lowTs
)
err
:=
checkAt
(
lowTs
)
if
err
==
errFailure
{
fmt
.
Printf
(
"
\n
"
,
lowTs
)
return
lowTs
}
else
if
err
!=
{
log
.
Printf
(
"
\n
"
,
lowTs
,
err
)
return
0
}
fmt
.
Printf
(
"
\n
"
,
lowTs
)
return
0
}
midTs
:=
(
lowTs
+
highTs
)
/
2
log
.
Println
(
)
log
.
Printf
(
"
\n
"
,
lowTs
,
highTs
,
midTs
)
err
:=
checkAt
(
midTs
)
if
err
==
badger
.
ErrKeyNotFound
||
err
==
{
// If no failure, move to higher ts.
return
findFirstInvalidTxn
(
db
,
midTs
+
1
,
highTs
)
}
// Found an error.
return
findFirstInvalidTxn
(
db
,
lowTs
,
midTs
)
}


func (m *InmemSnapshotStore) Create(version SnapshotVersion, index, term uint64,
	configuration Configuration, configurationIndex uint64, trans Transport) (SnapshotSink, error) {
	// We only support version 1 snapshots at this time.
	if version != 1 {
		return nil, fmt.Errorf("unsupported snapshot version %d", version)
	}

	name := snapshotName(term, index)

	m.Lock()
	defer m.Unlock()

	sink := &InmemSnapshotSink{
		meta: SnapshotMeta{
			Version:            version,
			ID:                 name,
			Index:              index,
			Term:               term,
			Peers:              encodePeers(configuration, trans),
			Configuration:      configuration,
			ConfigurationIndex: configurationIndex,
		},
		contents: &bytes.Buffer{},
	}
	m.hasSnapshot = true
	m.latest = sink

	return sink, nil
}

// Create replaces the stored snapshot with a new one using the given args


func (m *InmemSnapshotStore) List() ([]*SnapshotMeta, error) {
	m.RLock()
	defer m.RUnlock()

	if !m.hasSnapshot {
		return []*SnapshotMeta{}, nil
	}
	return []*SnapshotMeta{&m.latest.meta}, nil
}

func ( m * InmemSnapshotStore ) List ( ) ( [ ] * SnapshotMeta , error ) { m . RLock ( ) defer m . RUnlock ( ) if ! m . hasSnapshot { return [ ] * SnapshotMeta { } , nil } return [ ] * SnapshotMeta { & m . latest . meta } , nil }

// List returns the latest snapshot taken


func (m *InmemSnapshotStore) Open(id string) (*SnapshotMeta, io.ReadCloser, error) {
	m.RLock()
	defer m.RUnlock()

	if m.latest.meta.ID != id {
		return nil, nil, fmt.Errorf("[ERR] snapshot: failed to open snapshot id: %s", id)
	}

	return &m.latest.meta, ioutil.NopCloser(m.latest.contents), nil
}

func ( m * InmemSnapshotStore ) Open ( id string ) ( * SnapshotMeta , io . ReadCloser , error ) { m . RLock ( ) defer m . RUnlock ( ) if m . latest . meta . ID != id { return nil , nil , fmt . Errorf ( " " , id ) } return & m . latest . meta , ioutil . NopCloser ( m . latest . contents ) , nil }

// Open wraps an io.ReadCloser around the snapshot contents

Open wraps an io . ReadCloser around the snapshot contents


func (s *InmemSnapshotSink) Write(p []byte) (n int, err error) {
	written, err := io.Copy(s.contents, bytes.NewReader(p))
	s.meta.Size += written
	return int(written), err
}

func ( s * InmemSnapshotSink ) Write ( p [ ] byte ) ( n int , err error ) { written , err := io . Copy ( s . contents , bytes . NewReader ( p ) ) s . meta . Size += written return int ( written ) , err }

// Write appends the given bytes to the snapshot contents


func NewFileSnapshotStoreWithLogger(base string, retain int, logger *log.Logger) (*FileSnapshotStore, error) {
	if retain < 1 {
		return nil, fmt.Errorf("must retain at least one snapshot")
	}
	if logger == nil {
		logger = log.New(os.Stderr, "", log.LstdFlags)
	}

	// Ensure our path exists
	path := filepath.Join(base, snapPath)
	if err := os.MkdirAll(path, 0755); err != nil && !os.IsExist(err) {
		return nil, fmt.Errorf("snapshot path not accessible: %v", err)
	}

	// Setup the store
	store := &FileSnapshotStore{
		path:   path,
		retain: retain,
		logger: logger,
	}

	// Do a permissions test
	if err := store.testPermissions(); err != nil {
		return nil, fmt.Errorf("permissions test failed: %v", err)
	}
	return store, nil
}

func
NewFileSnapshotStoreWithLogger
(
base
string
,
retain
int
,
logger
*
log
.
Logger
)
(
*
FileSnapshotStore
,
error
)
{
if
retain
<
1
{
return
,
fmt
.
Errorf
(
"
"
)
}
if
logger
==
{
logger
=
log
.
New
(
os
.
Stderr
,
"
"
,
log
.
LstdFlags
)
}
// Ensure our path exists
path
:=
filepath
.
Join
(
base
,
snapPath
)
if
err
:=
os
.
MkdirAll
(
path
,
0755
)
;
err
!=
&&
!
os
.
IsExist
(
err
)
{
return
,
fmt
.
Errorf
(
"
"
,
err
)
}
// Setup the store
store
:=
&
FileSnapshotStore
{
path
:
path
,
retain
:
retain
,
logger
:
logger
,
}
// Do a permissions test
if
err
:=
store
.
testPermissions
(
)
;
err
!=
{
return
,
fmt
.
Errorf
(
"
"
,
err
)
}
return
store
,
}

// NewFileSnapshotStoreWithLogger creates a new FileSnapshotStore based
// on a base directory. The `retain` parameter controls how many
// snapshots are retained. Must be at least 1.

NewFileSnapshotStoreWithLogger creates a new FileSnapshotStore based on a base directory . The retain parameter controls how many snapshots are retained . Must be at least 1 .


func NewFileSnapshotStore(base string, retain int, logOutput io.Writer) (*FileSnapshotStore, error) {
	if logOutput == nil {
		logOutput = os.Stderr
	}
	return NewFileSnapshotStoreWithLogger(base, retain, log.New(logOutput, "", log.LstdFlags))
}

func NewFileSnapshotStore ( base string , retain int , logOutput io . Writer ) ( * FileSnapshotStore , error ) { if logOutput == nil { logOutput = os . Stderr } return NewFileSnapshotStoreWithLogger ( base , retain , log . New ( logOutput , " " , log . LstdFlags ) ) }

// NewFileSnapshotStore creates a new FileSnapshotStore based
// on a base directory. The `retain` parameter controls how many
// snapshots are retained. Must be at least 1.

NewFileSnapshotStore creates a new FileSnapshotStore based on a base directory . The retain parameter controls how many snapshots are retained . Must be at least 1 .


func snapshotName(term, index uint64) string {
	now := time.Now()
	msec := now.UnixNano() / int64(time.Millisecond)
	return fmt.Sprintf("%d-%d-%d", term, index, msec)
}

func snapshotName ( term , index uint64 ) string { now := time . Now ( ) msec := now . UnixNano ( ) / int64 ( time . Millisecond ) return fmt . Sprintf ( " " , term , index , msec ) }

// snapshotName generates a name for the snapshot.

snapshotName generates a name for the snapshot .


func (f *FileSnapshotStore) Create(version SnapshotVersion, index, term uint64,
	configuration Configuration, configurationIndex uint64, trans Transport) (SnapshotSink, error) {
	// We only support version 1 snapshots at this time.
	if version != 1 {
		return nil, fmt.Errorf("unsupported snapshot version %d", version)
	}

	// Create a new path
	name := snapshotName(term, index)
	path := filepath.Join(f.path, name+tmpSuffix)
	f.logger.Printf("[INFO] snapshot: Creating new snapshot at %s", path)

	// Make the directory
	if err := os.MkdirAll(path, 0755); err != nil {
		f.logger.Printf("[ERR] snapshot: Failed to make snapshot directory: %v", err)
		return nil, err
	}

	// Create the sink
	sink := &FileSnapshotSink{
		store:     f,
		logger:    f.logger,
		dir:       path,
		parentDir: f.path,
		meta: fileSnapshotMeta{
			SnapshotMeta: SnapshotMeta{
				Version:            version,
				ID:                 name,
				Index:              index,
				Term:               term,
				Peers:              encodePeers(configuration, trans),
				Configuration:      configuration,
				ConfigurationIndex: configurationIndex,
			},
			CRC: nil,
		},
	}

	// Write out the meta data
	if err := sink.writeMeta(); err != nil {
		f.logger.Printf("[ERR] snapshot: Failed to write metadata: %v", err)
		return nil, err
	}

	// Open the state file
	statePath := filepath.Join(path, stateFilePath)
	fh, err := os.Create(statePath)
	if err != nil {
		f.logger.Printf("[ERR] snapshot: Failed to create state file: %v", err)
		return nil, err
	}
	sink.stateFile = fh

	// Create a CRC64 hash
	sink.stateHash = crc64.New(crc64.MakeTable(crc64.ECMA))

	// Wrap both the hash and file in a MultiWriter with buffering
	multi := io.MultiWriter(sink.stateFile, sink.stateHash)
	sink.buffered = bufio.NewWriter(multi)

	// Done
	return sink, nil
}

// Create is used to start a new snapshot


func (f *FileSnapshotStore) List() ([]*SnapshotMeta, error) {
	// Get the eligible snapshots
	snapshots, err := f.getSnapshots()
	if err != nil {
		f.logger.Printf("[ERR] snapshot: Failed to get snapshots: %v", err)
		return nil, err
	}

	var snapMeta []*SnapshotMeta
	for _, meta := range snapshots {
		snapMeta = append(snapMeta, &meta.SnapshotMeta)
		if len(snapMeta) == f.retain {
			break
		}
	}
	return snapMeta, nil
}

func
(
f
*
FileSnapshotStore
)
List
(
)
(
[
]
*
SnapshotMeta
,
error
)
{
// Get the eligible snapshots
snapshots
,
err
:=
f
.
getSnapshots
(
)
if
err
!=
{
f
.
logger
.
Printf
(
"
"
,
err
)
return
,
err
}
var
snapMeta
[
]
*
SnapshotMeta
for
_
,
meta
:=
range
snapshots
{
snapMeta
=
append
(
snapMeta
,
&
meta
.
SnapshotMeta
)
if
len
(
snapMeta
)
==
f
.
retain
{
break
}
}
return
snapMeta
,
}

// List returns available snapshots in the store.

List returns available snapshots in the store .


func (f *FileSnapshotStore) getSnapshots() ([]*fileSnapshotMeta, error) {
	// Get the eligible snapshots
	snapshots, err := ioutil.ReadDir(f.path)
	if err != nil {
		f.logger.Printf("[ERR] snapshot: Failed to scan snapshot dir: %v", err)
		return nil, err
	}

	// Populate the metadata
	var snapMeta []*fileSnapshotMeta
	for _, snap := range snapshots {
		// Ignore any files
		if !snap.IsDir() {
			continue
		}

		// Ignore any temporary snapshots
		dirName := snap.Name()
		if strings.HasSuffix(dirName, tmpSuffix) {
			f.logger.Printf("[WARN] snapshot: Found temporary snapshot: %v", dirName)
			continue
		}

		// Try to read the meta data
		meta, err := f.readMeta(dirName)
		if err != nil {
			f.logger.Printf("[WARN] snapshot: Failed to read metadata for %v: %v", dirName, err)
			continue
		}

		// Make sure we can understand this version.
		if meta.Version < SnapshotVersionMin || meta.Version > SnapshotVersionMax {
			f.logger.Printf("[WARN] snapshot: Snapshot version for %v not supported: %d", dirName, meta.Version)
			continue
		}

		// Append, but only return up to the retain count
		snapMeta = append(snapMeta, meta)
	}

	// Sort the snapshot, reverse so we get new -> old
	sort.Sort(sort.Reverse(snapMetaSlice(snapMeta)))

	return snapMeta, nil
}

// getSnapshots returns all the known snapshots.

getSnapshots returns all the known snapshots .


func (f *FileSnapshotStore) readMeta(name string) (*fileSnapshotMeta, error) {
	// Open the meta file
	metaPath := filepath.Join(f.path, name, metaFilePath)
	fh, err := os.Open(metaPath)
	if err != nil {
		return nil, err
	}
	defer fh.Close()

	// Buffer the file IO
	buffered := bufio.NewReader(fh)

	// Read in the JSON
	meta := &fileSnapshotMeta{}
	dec := json.NewDecoder(buffered)
	if err := dec.Decode(meta); err != nil {
		return nil, err
	}
	return meta, nil
}

func
(
f
*
FileSnapshotStore
)
readMeta
(
name
string
)
(
*
fileSnapshotMeta
,
error
)
{
// Open the meta file
metaPath
:=
filepath
.
Join
(
f
.
path
,
name
,
metaFilePath
)
fh
,
err
:=
os
.
Open
(
metaPath
)
if
err
!=
{
return
,
err
}
defer
fh
.
Close
(
)
// Buffer the file IO
buffered
:=
bufio
.
NewReader
(
fh
)
// Read in the JSON
meta
:=
&
fileSnapshotMeta
{
}
dec
:=
json
.
NewDecoder
(
buffered
)
if
err
:=
dec
.
Decode
(
meta
)
;
err
!=
{
return
,
err
}
return
meta
,
}

// readMeta is used to read the meta data for a given named backup


func (f *FileSnapshotStore) Open(id string) (*SnapshotMeta, io.ReadCloser, error) {
	// Get the metadata
	meta, err := f.readMeta(id)
	if err != nil {
		f.logger.Printf("[ERR] snapshot: Failed to get meta data to open snapshot: %v", err)
		return nil, nil, err
	}

	// Open the state file
	statePath := filepath.Join(f.path, id, stateFilePath)
	fh, err := os.Open(statePath)
	if err != nil {
		f.logger.Printf("[ERR] snapshot: Failed to open state file: %v", err)
		return nil, nil, err
	}

	// Create a CRC64 hash
	stateHash := crc64.New(crc64.MakeTable(crc64.ECMA))

	// Compute the hash
	_, err = io.Copy(stateHash, fh)
	if err != nil {
		f.logger.Printf("[ERR] snapshot: Failed to read state file: %v", err)
		fh.Close()
		return nil, nil, err
	}

	// Verify the hash
	computed := stateHash.Sum(nil)
	if bytes.Compare(meta.CRC, computed) != 0 {
		f.logger.Printf("[ERR] snapshot: CRC checksum failed (stored: %v computed: %v)",
			meta.CRC, computed)
		fh.Close()
		return nil, nil, fmt.Errorf("CRC mismatch")
	}

	// Seek to the start
	if _, err := fh.Seek(0, 0); err != nil {
		f.logger.Printf("[ERR] snapshot: State file seek failed: %v", err)
		fh.Close()
		return nil, nil, err
	}

	// Return a buffered file
	buffered := &bufferedFile{
		bh: bufio.NewReader(fh),
		fh: fh,
	}

	return &meta.SnapshotMeta, buffered, nil
}

func
(
f
*
FileSnapshotStore
)
Open
(
id
string
)
(
*
SnapshotMeta
,
io
.
ReadCloser
,
error
)
{
// Get the metadata
meta
,
err
:=
f
.
readMeta
(
id
)
if
err
!=
{
f
.
logger
.
Printf
(
"
"
,
err
)
return
,
,
err
}
// Open the state file
statePath
:=
filepath
.
Join
(
f
.
path
,
id
,
stateFilePath
)
fh
,
err
:=
os
.
Open
(
statePath
)
if
err
!=
{
f
.
logger
.
Printf
(
"
"
,
err
)
return
,
,
err
}
// Create a CRC64 hash
stateHash
:=
crc64
.
New
(
crc64
.
MakeTable
(
crc64
.
ECMA
)
)
// Compute the hash
_
,
err
=
io
.
Copy
(
stateHash
,
fh
)
if
err
!=
{
f
.
logger
.
Printf
(
"
"
,
err
)
fh
.
Close
(
)
return
,
,
err
}
// Verify the hash
computed
:=
stateHash
.
Sum
(
)
if
bytes
.
Compare
(
meta
.
CRC
,
computed
)
!=
0
{
f
.
logger
.
Printf
(
"
"
,
meta
.
CRC
,
computed
)
fh
.
Close
(
)
return
,
,
fmt
.
Errorf
(
"
"
)
}
// Seek to the start
if
_
,
err
:=
fh
.
Seek
(
0
,
0
)
;
err
!=
{
f
.
logger
.
Printf
(
"
"
,
err
)
fh
.
Close
(
)
return
,
,
err
}
// Return a buffered file
buffered
:=
&
bufferedFile
{
bh
:
bufio
.
NewReader
(
fh
)
,
fh
:
fh
,
}
return
&
meta
.
SnapshotMeta
,
buffered
,
}

// Open takes a snapshot ID and returns a ReadCloser for that snapshot.

Open takes a snapshot ID and returns a ReadCloser for that snapshot .


func (f *FileSnapshotStore) ReapSnapshots() error {
	snapshots, err := f.getSnapshots()
	if err != nil {
		f.logger.Printf("[ERR] snapshot: Failed to get snapshots: %v", err)
		return err
	}

	for i := f.retain; i < len(snapshots); i++ {
		path := filepath.Join(f.path, snapshots[i].ID)
		f.logger.Printf("[INFO] snapshot: reaping snapshot %v", path)
		if err := os.RemoveAll(path); err != nil {
			f.logger.Printf("[ERR] snapshot: Failed to reap snapshot %v: %v", path, err)
			return err
		}
	}
	return nil
}

func ( f * FileSnapshotStore ) ReapSnapshots ( ) error { snapshots , err := f . getSnapshots ( ) if err != nil { f . logger . Printf ( " " , err ) return err } for i := f . retain ; i < len ( snapshots ) ; i ++ { path := filepath . Join ( f . path , snapshots [ i ] . ID ) f . logger . Printf ( " " , path ) if err := os . RemoveAll ( path ) ; err != nil { f . logger . Printf ( " " , path , err ) return err } } return nil }

// ReapSnapshots reaps any snapshots beyond the retain count.

ReapSnapshots reaps any snapshots beyond the retain count .


func (s *FileSnapshotSink) Write(b []byte) (int, error) {
	return s.buffered.Write(b)
}

func ( s * FileSnapshotSink ) Write ( b [ ] byte ) ( int , error ) { return s . buffered . Write ( b ) }

// Write is used to append to the state file. We write to the
// buffered IO object to reduce the amount of context switches.

Write is used to append to the state file . We write to the buffered IO object to reduce the amount of context switches .


func (s *FileSnapshotSink) Close() error {
	// Make sure close is idempotent
	if s.closed {
		return nil
	}
	s.closed = true

	// Close the open handles
	if err := s.finalize(); err != nil {
		s.logger.Printf("[ERR] snapshot: Failed to finalize snapshot: %v", err)
		if delErr := os.RemoveAll(s.dir); delErr != nil {
			s.logger.Printf("[ERR] snapshot: Failed to delete temporary snapshot directory at path %v: %v", s.dir, delErr)
			return delErr
		}
		return err
	}

	// Write out the meta data
	if err := s.writeMeta(); err != nil {
		s.logger.Printf("[ERR] snapshot: Failed to write metadata: %v", err)
		return err
	}

	// Move the directory into place
	newPath := strings.TrimSuffix(s.dir, tmpSuffix)
	if err := os.Rename(s.dir, newPath); err != nil {
		s.logger.Printf("[ERR] snapshot: Failed to move snapshot into place: %v", err)
		return err
	}

	if runtime.GOOS != "windows" { //skipping fsync for directory entry edits on Windows, only needed for *nix style file systems
		parentFH, err := os.Open(s.parentDir)
		defer parentFH.Close()
		if err != nil {
			s.logger.Printf("[ERR] snapshot: Failed to open snapshot parent directory %v, error: %v", s.parentDir, err)
			return err
		}

		if err = parentFH.Sync(); err != nil {
			s.logger.Printf("[ERR] snapshot: Failed syncing parent directory %v, error: %v", s.parentDir, err)
			return err
		}
	}

	// Reap any old snapshots
	if err := s.store.ReapSnapshots(); err != nil {
		return err
	}

	return nil
}

// Close is used to indicate a successful end.

Close is used to indicate a successful end .


func (s *FileSnapshotSink) Cancel() error {
	// Make sure close is idempotent
	if s.closed {
		return nil
	}
	s.closed = true

	// Close the open handles
	if err := s.finalize(); err != nil {
		s.logger.Printf("[ERR] snapshot: Failed to finalize snapshot: %v", err)
		return err
	}

	// Attempt to remove all artifacts
	return os.RemoveAll(s.dir)
}

func
(
s
*
FileSnapshotSink
)
Cancel
(
)
error
{
// Make sure close is idempotent
if
s
.
closed
{
return
}
s
.
closed
=
true
// Close the open handles
if
err
:=
s
.
finalize
(
)
;
err
!=
{
s
.
logger
.
Printf
(
"
"
,
err
)
return
err
}
// Attempt to remove all artifacts
return
os
.
RemoveAll
(
s
.
dir
)
}

// Cancel is used to indicate an unsuccessful end.

Cancel is used to indicate an unsuccessful end .


func (s *FileSnapshotSink) finalize() error {
	// Flush any remaining data
	if err := s.buffered.Flush(); err != nil {
		return err
	}

	// Sync to force fsync to disk
	if err := s.stateFile.Sync(); err != nil {
		return err
	}

	// Get the file size
	stat, statErr := s.stateFile.Stat()

	// Close the file
	if err := s.stateFile.Close(); err != nil {
		return err
	}

	// Set the file size, check after we close
	if statErr != nil {
		return statErr
	}
	s.meta.Size = stat.Size()

	// Set the CRC
	s.meta.CRC = s.stateHash.Sum(nil)
	return nil
}

// finalize is used to close all of our resources.

finalize is used to close all of our resources .


func (s *FileSnapshotSink) writeMeta() error {
	// Open the meta file
	metaPath := filepath.Join(s.dir, metaFilePath)
	fh, err := os.Create(metaPath)
	if err != nil {
		return err
	}
	defer fh.Close()

	// Buffer the file IO
	buffered := bufio.NewWriter(fh)

	// Write out as JSON
	enc := json.NewEncoder(buffered)
	if err := enc.Encode(&s.meta); err != nil {
		return err
	}

	if err = buffered.Flush(); err != nil {
		return err
	}

	if err = fh.Sync(); err != nil {
		return err
	}

	return nil
}

func
(
s
*
FileSnapshotSink
)
writeMeta
(
)
error
{
// Open the meta file
metaPath
:=
filepath
.
Join
(
s
.
dir
,
metaFilePath
)
fh
,
err
:=
os
.
Create
(
metaPath
)
if
err
!=
{
return
err
}
defer
fh
.
Close
(
)
// Buffer the file IO
buffered
:=
bufio
.
NewWriter
(
fh
)
// Write out as JSON
enc
:=
json
.
NewEncoder
(
buffered
)
if
err
:=
enc
.
Encode
(
&
s
.
meta
)
;
err
!=
{
return
err
}
if
err
=
buffered
.
Flush
(
)
;
err
!=
{
return
err
}
if
err
=
fh
.
Sync
(
)
;
err
!=
{
return
err
}
return
}

// writeMeta is used to write out the metadata we have.

writeMeta is used to write out the metadata we have .


func NewNetworkTransportWithConfig(
	config *NetworkTransportConfig,
) *NetworkTransport {
	if config.Logger == nil {
		config.Logger = log.New(os.Stderr, "", log.LstdFlags)
	}
	trans := &NetworkTransport{
		connPool:              make(map[ServerAddress][]*netConn),
		consumeCh:             make(chan RPC),
		logger:                config.Logger,
		maxPool:               config.MaxPool,
		shutdownCh:            make(chan struct{}),
		stream:                config.Stream,
		timeout:               config.Timeout,
		TimeoutScale:          DefaultTimeoutScale,
		serverAddressProvider: config.ServerAddressProvider,
	}

	// Create the connection context and then start our listener.
	trans.setupStreamContext()
	go trans.listen()

	return trans
}

// NewNetworkTransportWithConfig creates a new network transport with the given config struct


func (n *NetworkTransport) setupStreamContext() {
	ctx, cancel := context.WithCancel(context.Background())
	n.streamCtx = ctx
	n.streamCancel = cancel
}

func ( n * NetworkTransport ) setupStreamContext ( ) { ctx , cancel := context . WithCancel ( context . Background ( ) ) n . streamCtx = ctx n . streamCancel = cancel }

// setupStreamContext is used to create a new stream context. This should be
// called with the stream lock held.

setupStreamContext is used to create a new stream context . This should be called with the stream lock held .


func (n *NetworkTransport) getStreamContext() context.Context {
	n.streamCtxLock.RLock()
	defer n.streamCtxLock.RUnlock()
	return n.streamCtx
}

func ( n * NetworkTransport ) getStreamContext ( ) context . Context { n . streamCtxLock . RLock ( ) defer n . streamCtxLock . RUnlock ( ) return n . streamCtx }

// getStreamContext is used retrieve the current stream context.

getStreamContext is used retrieve the current stream context .


func (n *NetworkTransport) SetHeartbeatHandler(cb func(rpc RPC)) {
	n.heartbeatFnLock.Lock()
	defer n.heartbeatFnLock.Unlock()
	n.heartbeatFn = cb
}

func ( n * NetworkTransport ) SetHeartbeatHandler ( cb func ( rpc RPC ) ) { n . heartbeatFnLock . Lock ( ) defer n . heartbeatFnLock . Unlock ( ) n . heartbeatFn = cb }

// SetHeartbeatHandler is used to setup a heartbeat handler
// as a fast-pass. This is to avoid head-of-line blocking from
// disk IO.

SetHeartbeatHandler is used to setup a heartbeat handler as a fast - pass . This is to avoid head - of - line blocking from disk IO .


func (n *NetworkTransport) CloseStreams() {
	n.connPoolLock.Lock()
	defer n.connPoolLock.Unlock()

	// Close all the connections in the connection pool and then remove their
	// entry.
	for k, e := range n.connPool {
		for _, conn := range e {
			conn.Release()
		}

		delete(n.connPool, k)
	}

	// Cancel the existing connections and create a new context. Both these
	// operations must always be done with the lock held otherwise we can create
	// connection handlers that are holding a context that will never be
	// cancelable.
	n.streamCtxLock.Lock()
	n.streamCancel()
	n.setupStreamContext()
	n.streamCtxLock.Unlock()
}

// CloseStreams closes the current streams.

CloseStreams closes the current streams .


func (n *NetworkTransport) Close() error {
	n.shutdownLock.Lock()
	defer n.shutdownLock.Unlock()

	if !n.shutdown {
		close(n.shutdownCh)
		n.stream.Close()
		n.shutdown = true
	}
	return nil
}

func ( n * NetworkTransport ) Close ( ) error { n . shutdownLock . Lock ( ) defer n . shutdownLock . Unlock ( ) if ! n . shutdown { close ( n . shutdownCh ) n . stream . Close ( ) n . shutdown = true } return nil }

// Close is used to stop the network transport.

Close is used to stop the network transport .


func (n *NetworkTransport) getPooledConn(target ServerAddress) *netConn {
	n.connPoolLock.Lock()
	defer n.connPoolLock.Unlock()

	conns, ok := n.connPool[target]
	if !ok || len(conns) == 0 {
		return nil
	}

	var conn *netConn
	num := len(conns)
	conn, conns[num-1] = conns[num-1], nil
	n.connPool[target] = conns[:num-1]
	return conn
}

func ( n * NetworkTransport ) getPooledConn ( target ServerAddress ) * netConn { n . connPoolLock . Lock ( ) defer n . connPoolLock . Unlock ( ) conns , ok := n . connPool [ target ] if ! ok || len ( conns ) == 0 { return nil } var conn * netConn num := len ( conns ) conn , conns [ num - 1 ] = conns [ num - 1 ] , nil n . connPool [ target ] = conns [ : num - 1 ] return conn }

// getExistingConn is used to grab a pooled connection.

getExistingConn is used to grab a pooled connection .


func (n *NetworkTransport) getConnFromAddressProvider(id ServerID, target ServerAddress) (*netConn, error) {
	address := n.getProviderAddressOrFallback(id, target)
	return n.getConn(address)
}

func ( n * NetworkTransport ) getConnFromAddressProvider ( id ServerID , target ServerAddress ) ( * netConn , error ) { address := n . getProviderAddressOrFallback ( id , target ) return n . getConn ( address ) }

// getConnFromAddressProvider returns a connection from the server address provider if available, or defaults to a connection using the target server address

getConnFromAddressProvider returns a connection from the server address provider if available or defaults to a connection using the target server address


func (n *NetworkTransport) getConn(target ServerAddress) (*netConn, error) {
	// Check for a pooled conn
	if conn := n.getPooledConn(target); conn != nil {
		return conn, nil
	}

	// Dial a new connection
	conn, err := n.stream.Dial(target, n.timeout)
	if err != nil {
		return nil, err
	}

	// Wrap the conn
	netConn := &netConn{
		target: target,
		conn:   conn,
		r:      bufio.NewReader(conn),
		w:      bufio.NewWriter(conn),
	}

	// Setup encoder/decoders
	netConn.dec = codec.NewDecoder(netConn.r, &codec.MsgpackHandle{})
	netConn.enc = codec.NewEncoder(netConn.w, &codec.MsgpackHandle{})

	// Done
	return netConn, nil
}

func
(
n
*
NetworkTransport
)
getConn
(
target
ServerAddress
)
(
*
netConn
,
error
)
{
// Check for a pooled conn
if
conn
:=
n
.
getPooledConn
(
target
)
;
conn
!=
{
return
conn
,
}
// Dial a new connection
conn
,
err
:=
n
.
stream
.
Dial
(
target
,
n
.
timeout
)
if
err
!=
{
return
,
err
}
// Wrap the conn
netConn
:=
&
netConn
{
target
:
target
,
conn
:
conn
,
r
:
bufio
.
NewReader
(
conn
)
,
w
:
bufio
.
NewWriter
(
conn
)
,
}
// Setup encoder/decoders
netConn
.
dec
=
codec
.
NewDecoder
(
netConn
.
r
,
&
codec
.
MsgpackHandle
{
}
)
netConn
.
enc
=
codec
.
NewEncoder
(
netConn
.
w
,
&
codec
.
MsgpackHandle
{
}
)
// Done
return
netConn
,
}

// getConn is used to get a connection from the pool.

getConn is used to get a connection from the pool .


func (n *NetworkTransport) returnConn(conn *netConn) {
	n.connPoolLock.Lock()
	defer n.connPoolLock.Unlock()

	key := conn.target
	conns, _ := n.connPool[key]

	if !n.IsShutdown() && len(conns) < n.maxPool {
		n.connPool[key] = append(conns, conn)
	} else {
		conn.Release()
	}
}

func ( n * NetworkTransport ) returnConn ( conn * netConn ) { n . connPoolLock . Lock ( ) defer n . connPoolLock . Unlock ( ) key := conn . target conns , _ := n . connPool [ key ] if ! n . IsShutdown ( ) && len ( conns ) < n . maxPool { n . connPool [ key ] = append ( conns , conn ) } else { conn . Release ( ) } }

// returnConn returns a connection back to the pool.

returnConn returns a connection back to the pool .


func (n *NetworkTransport) listen() {
	const baseDelay = 5 * time.Millisecond
	const maxDelay = 1 * time.Second

	var loopDelay time.Duration
	for {
		// Accept incoming connections
		conn, err := n.stream.Accept()
		if err != nil {
			if loopDelay == 0 {
				loopDelay = baseDelay
			} else {
				loopDelay *= 2
			}

			if loopDelay > maxDelay {
				loopDelay = maxDelay
			}

			if !n.IsShutdown() {
				n.logger.Printf("[ERR] raft-net: Failed to accept connection: %v", err)
			}

			select {
			case <-n.shutdownCh:
				return
			case <-time.After(loopDelay):
				continue
			}
		}
		// No error, reset loop delay
		loopDelay = 0

		n.logger.Printf("[DEBUG] raft-net: %v accepted connection from: %v", n.LocalAddr(), conn.RemoteAddr())

		// Handle the connection in dedicated routine
		go n.handleConn(n.getStreamContext(), conn)
	}
}

// listen is used to handling incoming connections.

listen is used to handling incoming connections .


func (n *NetworkTransport) handleConn(connCtx context.Context, conn net.Conn) {
	defer conn.Close()
	r := bufio.NewReader(conn)
	w := bufio.NewWriter(conn)
	dec := codec.NewDecoder(r, &codec.MsgpackHandle{})
	enc := codec.NewEncoder(w, &codec.MsgpackHandle{})

	for {
		select {
		case <-connCtx.Done():
			n.logger.Println("[DEBUG] raft-net: stream layer is closed")
			return
		default:
		}

		if err := n.handleCommand(r, dec, enc); err != nil {
			if err != io.EOF {
				n.logger.Printf("[ERR] raft-net: Failed to decode incoming command: %v", err)
			}
			return
		}
		if err := w.Flush(); err != nil {
			n.logger.Printf("[ERR] raft-net: Failed to flush response: %v", err)
			return
		}
	}
}

func ( n * NetworkTransport ) handleConn ( connCtx context . Context , conn net . Conn ) { defer conn . Close ( ) r := bufio . NewReader ( conn ) w := bufio . NewWriter ( conn ) dec := codec . NewDecoder ( r , & codec . MsgpackHandle { } ) enc := codec . NewEncoder ( w , & codec . MsgpackHandle { } ) for { select { case <- connCtx . Done ( ) : n . logger . Println ( " " ) return default : } if err := n . handleCommand ( r , dec , enc ) ; err != nil { if err != io . EOF { n . logger . Printf ( " " , err ) } return } if err := w . Flush ( ) ; err != nil { n . logger . Printf ( " " , err ) return } } }

// handleConn is used to handle an inbound connection for its lifespan. The
// handler will exit when the passed context is cancelled or the connection is
// closed.

handleConn is used to handle an inbound connection for its lifespan . The handler will exit when the passed context is cancelled or the connection is closed .


func (n *NetworkTransport) handleCommand(r *bufio.Reader, dec *codec.Decoder, enc *codec.Encoder) error {
	// Get the rpc type
	rpcType, err := r.ReadByte()
	if err != nil {
		return err
	}

	// Create the RPC object
	respCh := make(chan RPCResponse, 1)
	rpc := RPC{
		RespChan: respCh,
	}

	// Decode the command
	isHeartbeat := false
	switch rpcType {
	case rpcAppendEntries:
		var req AppendEntriesRequest
		if err := dec.Decode(&req); err != nil {
			return err
		}
		rpc.Command = &req

		// Check if this is a heartbeat
		if req.Term != 0 && req.Leader != nil &&
			req.PrevLogEntry == 0 && req.PrevLogTerm == 0 &&
			len(req.Entries) == 0 && req.LeaderCommitIndex == 0 {
			isHeartbeat = true
		}

	case rpcRequestVote:
		var req RequestVoteRequest
		if err := dec.Decode(&req); err != nil {
			return err
		}
		rpc.Command = &req

	case rpcInstallSnapshot:
		var req InstallSnapshotRequest
		if err := dec.Decode(&req); err != nil {
			return err
		}
		rpc.Command = &req
		rpc.Reader = io.LimitReader(r, req.Size)

	default:
		return fmt.Errorf("unknown rpc type %d", rpcType)
	}

	// Check for heartbeat fast-path
	if isHeartbeat {
		n.heartbeatFnLock.Lock()
		fn := n.heartbeatFn
		n.heartbeatFnLock.Unlock()
		if fn != nil {
			fn(rpc)
			goto RESP
		}
	}

	// Dispatch the RPC
	select {
	case n.consumeCh <- rpc:
	case <-n.shutdownCh:
		return ErrTransportShutdown
	}

	// Wait for response
RESP:
	select {
	case resp := <-respCh:
		// Send the error first
		respErr := ""
		if resp.Error != nil {
			respErr = resp.Error.Error()
		}
		if err := enc.Encode(respErr); err != nil {
			return err
		}

		// Send the response
		if err := enc.Encode(resp.Response); err != nil {
			return err
		}
	case <-n.shutdownCh:
		return ErrTransportShutdown
	}
	return nil
}

func
(
n
*
NetworkTransport
)
handleCommand
(
r
*
bufio
.
Reader
,
dec
*
codec
.
Decoder
,
enc
*
codec
.
Encoder
)
error
{
// Get the rpc type
rpcType
,
err
:=
r
.
ReadByte
(
)
if
err
!=
{
return
err
}
// Create the RPC object
respCh
:=
make
(
chan
RPCResponse
,
1
)
rpc
:=
RPC
{
RespChan
:
respCh
,
}
// Decode the command
isHeartbeat
:=
false
switch
rpcType
{
case
rpcAppendEntries
:
var
req
AppendEntriesRequest
if
err
:=
dec
.
Decode
(
&
req
)
;
err
!=
{
return
err
}
rpc
.
Command
=
&
req
// Check if this is a heartbeat
if
req
.
Term
!=
0
&&
req
.
Leader
!=
&&
req
.
PrevLogEntry
==
0
&&
req
.
PrevLogTerm
==
0
&&
len
(
req
.
Entries
)
==
0
&&
req
.
LeaderCommitIndex
==
0
{
isHeartbeat
=
true
}
case
rpcRequestVote
:
var
req
RequestVoteRequest
if
err
:=
dec
.
Decode
(
&
req
)
;
err
!=
{
return
err
}
rpc
.
Command
=
&
req
case
rpcInstallSnapshot
:
var
req
InstallSnapshotRequest
if
err
:=
dec
.
Decode
(
&
req
)
;
err
!=
{
return
err
}
rpc
.
Command
=
&
req
rpc
.
Reader
=
io
.
LimitReader
(
r
,
req
.
Size
)
default
:
return
fmt
.
Errorf
(
"
"
,
rpcType
)
}
// Check for heartbeat fast-path
if
isHeartbeat
{
n
.
heartbeatFnLock
.
Lock
(
)
fn
:=
n
.
heartbeatFn
n
.
heartbeatFnLock
.
Unlock
(
)
if
fn
!=
{
fn
(
rpc
)
goto
RESP
}
}
// Dispatch the RPC
select
{
case
n
.
consumeCh
<-
rpc
:
case
<-
n
.
shutdownCh
:
return
ErrTransportShutdown
}
// Wait for response
RESP
:
select
{
case
resp
:=
<-
respCh
:
// Send the error first
respErr
:=
"
"
if
resp
.
Error
!=
{
respErr
=
resp
.
Error
.
Error
(
)
}
if
err
:=
enc
.
Encode
(
respErr
)
;
err
!=
{
return
err
}
// Send the response
if
err
:=
enc
.
Encode
(
resp
.
Response
)
;
err
!=
{
return
err
}
case
<-
n
.
shutdownCh
:
return
ErrTransportShutdown
}
return
}

// handleCommand is used to decode and dispatch a single command.

handleCommand is used to decode and dispatch a single command .


func decodeResponse(conn *netConn, resp interface{}) (bool, error) {
	// Decode the error if any
	var rpcError string
	if err := conn.dec.Decode(&rpcError); err != nil {
		conn.Release()
		return false, err
	}

	// Decode the response
	if err := conn.dec.Decode(resp); err != nil {
		conn.Release()
		return false, err
	}

	// Format an error if any
	if rpcError != "" {
		return true, fmt.Errorf(rpcError)
	}
	return true, nil
}

func
decodeResponse
(
conn
*
netConn
,
resp
interface
{
}
)
(
bool
,
error
)
{
// Decode the error if any
var
rpcError
string
if
err
:=
conn
.
dec
.
Decode
(
&
rpcError
)
;
err
!=
{
conn
.
Release
(
)
return
false
,
err
}
// Decode the response
if
err
:=
conn
.
dec
.
Decode
(
resp
)
;
err
!=
{
conn
.
Release
(
)
return
false
,
err
}
// Format an error if any
if
rpcError
!=
"
"
{
return
true
,
fmt
.
Errorf
(
rpcError
)
}
return
true
,
}

// decodeResponse is used to decode an RPC response and reports whether
// the connection can be reused.

decodeResponse is used to decode an RPC response and reports whether the connection can be reused .


func sendRPC(conn *netConn, rpcType uint8, args interface{}) error {
	// Write the request type
	if err := conn.w.WriteByte(rpcType); err != nil {
		conn.Release()
		return err
	}

	// Send the request
	if err := conn.enc.Encode(args); err != nil {
		conn.Release()
		return err
	}

	// Flush
	if err := conn.w.Flush(); err != nil {
		conn.Release()
		return err
	}
	return nil
}

func
sendRPC
(
conn
*
netConn
,
rpcType
uint8
,
args
interface
{
}
)
error
{
// Write the request type
if
err
:=
conn
.
w
.
WriteByte
(
rpcType
)
;
err
!=
{
conn
.
Release
(
)
return
err
}
// Send the request
if
err
:=
conn
.
enc
.
Encode
(
args
)
;
err
!=
{
conn
.
Release
(
)
return
err
}
// Flush
if
err
:=
conn
.
w
.
Flush
(
)
;
err
!=
{
conn
.
Release
(
)
return
err
}
return
}

// sendRPC is used to encode and send the RPC.

sendRPC is used to encode and send the RPC .


func newNetPipeline(trans *NetworkTransport, conn *netConn) *netPipeline {
	n := &netPipeline{
		conn:         conn,
		trans:        trans,
		doneCh:       make(chan AppendFuture, rpcMaxPipeline),
		inprogressCh: make(chan *appendFuture, rpcMaxPipeline),
		shutdownCh:   make(chan struct{}),
	}
	go n.decodeResponses()
	return n
}

func newNetPipeline ( trans * NetworkTransport , conn * netConn ) * netPipeline { n := & netPipeline { conn : conn , trans : trans , doneCh : make ( chan AppendFuture , rpcMaxPipeline ) , inprogressCh : make ( chan * appendFuture , rpcMaxPipeline ) , shutdownCh : make ( chan struct { } ) , } go n . decodeResponses ( ) return n }

// newNetPipeline is used to construct a netPipeline from a given
// transport and connection.

newNetPipeline is used to construct a netPipeline from a given transport and connection .


func (n *netPipeline) decodeResponses() {
	timeout := n.trans.timeout
	for {
		select {
		case future := <-n.inprogressCh:
			if timeout > 0 {
				n.conn.conn.SetReadDeadline(time.Now().Add(timeout))
			}

			_, err := decodeResponse(n.conn, future.resp)
			future.respond(err)
			select {
			case n.doneCh <- future:
			case <-n.shutdownCh:
				return
			}
		case <-n.shutdownCh:
			return
		}
	}
}

func ( n * netPipeline ) decodeResponses ( ) { timeout := n . trans . timeout for { select { case future := <- n . inprogressCh : if timeout > 0 { n . conn . conn . SetReadDeadline ( time . Now ( ) . Add ( timeout ) ) } _ , err := decodeResponse ( n . conn , future . resp ) future . respond ( err ) select { case n . doneCh <- future : case <- n . shutdownCh : return } case <- n . shutdownCh : return } } }

// decodeResponses is a long running routine that decodes the responses
// sent on the connection.

decodeResponses is a long running routine that decodes the responses sent on the connection .


func (n *netPipeline) AppendEntries(args *AppendEntriesRequest, resp *AppendEntriesResponse) (AppendFuture, error) {
	// Create a new future
	future := &appendFuture{
		start: time.Now(),
		args:  args,
		resp:  resp,
	}
	future.init()

	// Add a send timeout
	if timeout := n.trans.timeout; timeout > 0 {
		n.conn.conn.SetWriteDeadline(time.Now().Add(timeout))
	}

	// Send the RPC
	if err := sendRPC(n.conn, rpcAppendEntries, future.args); err != nil {
		return nil, err
	}

	// Hand-off for decoding, this can also cause back-pressure
	// to prevent too many inflight requests
	select {
	case n.inprogressCh <- future:
		return future, nil
	case <-n.shutdownCh:
		return nil, ErrPipelineShutdown
	}
}

// AppendEntries is used to pipeline a new append entries request.

AppendEntries is used to pipeline a new append entries request .


func (n *netPipeline) Close() error {
	n.shutdownLock.Lock()
	defer n.shutdownLock.Unlock()
	if n.shutdown {
		return nil
	}

	// Release the connection
	n.conn.Release()

	n.shutdown = true
	close(n.shutdownCh)
	return nil
}

func
(
n
*
netPipeline
)
Close
(
)
error
{
n
.
shutdownLock
.
Lock
(
)
defer
n
.
shutdownLock
.
Unlock
(
)
if
n
.
shutdown
{
return
}
// Release the connection
n
.
conn
.
Release
(
)
n
.
shutdown
=
true
close
(
n
.
shutdownCh
)
return
}

// Closed is used to shutdown the pipeline connection.

Closed is used to shutdown the pipeline connection .


func NewObserver(channel chan Observation, blocking bool, filter FilterFn) *Observer {
	return &Observer{
		channel:  channel,
		blocking: blocking,
		filter:   filter,
		id:       atomic.AddUint64(&nextObserverID, 1),
	}
}

func NewObserver ( channel chan Observation , blocking bool , filter FilterFn ) * Observer { return & Observer { channel : channel , blocking : blocking , filter : filter , id : atomic . AddUint64 ( & nextObserverID , 1 ) , } }

// NewObserver creates a new observer that can be registered
// to make observations on a Raft instance. Observations
// will be sent on the given channel if they satisfy the
// given filter.
//
// If blocking is true, the observer will block when it can't
// send on the channel, otherwise it may discard events.

NewObserver creates a new observer that can be registered to make observations on a Raft instance . Observations will be sent on the given channel if they satisfy the given filter . If blocking is true the observer will block when it can t send on the channel otherwise it may discard events .


func (r *Raft) RegisterObserver(or *Observer) {
	r.observersLock.Lock()
	defer r.observersLock.Unlock()
	r.observers[or.id] = or
}

func ( r * Raft ) RegisterObserver ( or * Observer ) { r . observersLock . Lock ( ) defer r . observersLock . Unlock ( ) r . observers [ or . id ] = or }

// RegisterObserver registers a new observer.

RegisterObserver registers a new observer .


func (r *Raft) DeregisterObserver(or *Observer) {
	r.observersLock.Lock()
	defer r.observersLock.Unlock()
	delete(r.observers, or.id)
}

func ( r * Raft ) DeregisterObserver ( or * Observer ) { r . observersLock . Lock ( ) defer r . observersLock . Unlock ( ) delete ( r . observers , or . id ) }

// DeregisterObserver deregisters an observer.

DeregisterObserver deregisters an observer .


func (r *Raft) observe(o interface{}) {
	// In general observers should not block. But in any case this isn't
	// disastrous as we only hold a read lock, which merely prevents
	// registration / deregistration of observers.
	r.observersLock.RLock()
	defer r.observersLock.RUnlock()
	for _, or := range r.observers {
		// It's wasteful to do this in the loop, but for the common case
		// where there are no observers we won't create any objects.
		ob := Observation{Raft: r, Data: o}
		if or.filter != nil && !or.filter(&ob) {
			continue
		}
		if or.channel == nil {
			continue
		}
		if or.blocking {
			or.channel <- ob
			atomic.AddUint64(&or.numObserved, 1)
		} else {
			select {
			case or.channel <- ob:
				atomic.AddUint64(&or.numObserved, 1)
			default:
				atomic.AddUint64(&or.numDropped, 1)
			}
		}
	}
}

// observe sends an observation to every observer.

observe sends an observation to every observer .


func NewInmemStore() *InmemStore {
	i := &InmemStore{
		logs:  make(map[uint64]*Log),
		kv:    make(map[string][]byte),
		kvInt: make(map[string]uint64),
	}
	return i
}

func NewInmemStore ( ) * InmemStore { i := & InmemStore { logs : make ( map [ uint64 ] * Log ) , kv : make ( map [ string ] [ ] byte ) , kvInt : make ( map [ string ] uint64 ) , } return i }

// NewInmemStore returns a new in-memory backend. Do not ever
// use for production. Only for testing.

NewInmemStore returns a new in - memory backend . Do not ever use for production . Only for testing .


func (i *InmemStore) FirstIndex() (uint64, error) {
	i.l.RLock()
	defer i.l.RUnlock()
	return i.lowIndex, nil
}

func ( i * InmemStore ) FirstIndex ( ) ( uint64 , error ) { i . l . RLock ( ) defer i . l . RUnlock ( ) return i . lowIndex , nil }

// FirstIndex implements the LogStore interface.

FirstIndex implements the LogStore interface .


func (i *InmemStore) LastIndex() (uint64, error) {
	i.l.RLock()
	defer i.l.RUnlock()
	return i.highIndex, nil
}

func ( i * InmemStore ) LastIndex ( ) ( uint64 , error ) { i . l . RLock ( ) defer i . l . RUnlock ( ) return i . highIndex , nil }

// LastIndex implements the LogStore interface.

LastIndex implements the LogStore interface .


func (i *InmemStore) GetLog(index uint64, log *Log) error {
	i.l.RLock()
	defer i.l.RUnlock()
	l, ok := i.logs[index]
	if !ok {
		return ErrLogNotFound
	}
	*log = *l
	return nil
}

func ( i * InmemStore ) GetLog ( index uint64 , log * Log ) error { i . l . RLock ( ) defer i . l . RUnlock ( ) l , ok := i . logs [ index ] if ! ok { return ErrLogNotFound } * log = * l return nil }

// GetLog implements the LogStore interface.

GetLog implements the LogStore interface .


func (i *InmemStore) StoreLog(log *Log) error {
	return i.StoreLogs([]*Log{log})
}

func ( i * InmemStore ) StoreLog ( log * Log ) error { return i . StoreLogs ( [ ] * Log { log } ) }

// StoreLog implements the LogStore interface.

StoreLog implements the LogStore interface .