github.com/vescale/zgraph@v0.0.0-20230410094002-959c02d50f95/storage/memdb.go (about)

     1  // Copyright 2022 zGraph Authors. All rights reserved.
     2  //
     3  // Copyright 2020 PingCAP, Inc.
     4  //
     5  // Licensed under the Apache License, Version 2.0 (the "License");
     6  // you may not use this file except in compliance with the License.
     7  // You may obtain a copy of the License at
     8  //
     9  //     http://www.apache.org/licenses/LICENSE-2.0
    10  //
    11  // Unless required by applicable law or agreed to in writing, software
    12  // distributed under the License is distributed on an "AS IS" BASIS,
    13  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    14  // See the License for the specific language governing permissions and
    15  // limitations under the License.
    16  
    17  package storage
    18  
    19  import (
    20  	"bytes"
    21  	"context"
    22  	"math"
    23  	"reflect"
    24  	"sync"
    25  	"unsafe"
    26  
    27  	"github.com/vescale/zgraph/storage/kv"
    28  	"github.com/vescale/zgraph/storage/mvcc"
    29  )
    30  
    31  var tombstone = []byte{}
    32  
    33  // IsTombstone returns whether the value is a tombstone.
    34  func IsTombstone(val []byte) bool { return len(val) == 0 }
    35  
    36  // MemKeyHandle represents a pointer for key in MemBuffer.
    37  type MemKeyHandle struct {
    38  	idx uint16
    39  	off uint32
    40  	// Fields are used for 2pc prepare stage.
    41  	op    mvcc.Op
    42  	flags kv.KeyFlags
    43  }
    44  
    45  func (h MemKeyHandle) toAddr() memdbArenaAddr {
    46  	return memdbArenaAddr{idx: uint32(h.idx), off: h.off}
    47  }
    48  
    49  // MemDB is rollbackable Red-Black Tree optimized for TiDB's transaction states buffer use scenario.
    50  // You can think MemDB is a combination of two separate tree map, one for key => value and another for key => keyFlags.
    51  //
    52  // The value map is rollbackable, that means you can use the `Staging`, `Release` and `Cleanup` API to safely modify KVs.
    53  //
    54  // The flags map is not rollbackable. There are two types of flag, persistent and non-persistent.
    55  // When discarding a newly added KV in `Cleanup`, the non-persistent flags will be cleared.
    56  // If there are persistent flags associated with key, we will keep this key in node without value.
    57  type MemDB struct {
    58  	// This RWMutex only used to ensure memdbSnapGetter.Get will not race with
    59  	// concurrent memdb.Set, memdb.SetWithFlags, memdb.Delete and memdb.UpdateFlags.
    60  	sync.RWMutex
    61  	root      memdbArenaAddr
    62  	allocator nodeAllocator
    63  	vlog      memdbVlog
    64  
    65  	entrySizeLimit  uint64
    66  	bufferSizeLimit uint64
    67  	count           int
    68  	size            int
    69  
    70  	vlogInvalid bool
    71  	dirty       bool
    72  	stages      []MemDBCheckpoint
    73  }
    74  
    75  func newMemDB() *MemDB {
    76  	db := new(MemDB)
    77  	db.allocator.init()
    78  	db.root = nullAddr
    79  	db.stages = make([]MemDBCheckpoint, 0, 2)
    80  	db.entrySizeLimit = math.MaxUint64
    81  	db.bufferSizeLimit = math.MaxUint64
    82  	db.vlog.memdb = db
    83  	return db
    84  }
    85  
    86  // Staging create a new staging buffer inside the MemBuffer.
    87  // Subsequent writes will be temporarily stored in this new staging buffer.
    88  // When you think all modifications looks good, you can call `Release` to public all of them to the upper level buffer.
    89  func (db *MemDB) Staging() int {
    90  	db.Lock()
    91  	defer db.Unlock()
    92  
    93  	db.stages = append(db.stages, db.vlog.checkpoint())
    94  	return len(db.stages)
    95  }
    96  
    97  // Release publish all modifications in the latest staging buffer to upper level.
    98  func (db *MemDB) Release(h int) {
    99  	db.Lock()
   100  	defer db.Unlock()
   101  
   102  	if h != len(db.stages) {
   103  		// This should never happens in production environment.
   104  		// Use panic to make debug easier.
   105  		panic("cannot release staging buffer")
   106  	}
   107  
   108  	if h == 1 {
   109  		tail := db.vlog.checkpoint()
   110  		if !db.stages[0].isSamePosition(&tail) {
   111  			db.dirty = true
   112  		}
   113  	}
   114  	db.stages = db.stages[:h-1]
   115  }
   116  
   117  // Cleanup cleanup the resources referenced by the StagingHandle.
   118  // If the changes are not published by `Release`, they will be discarded.
   119  func (db *MemDB) Cleanup(h int) {
   120  	db.Lock()
   121  	defer db.Unlock()
   122  
   123  	if h > len(db.stages) {
   124  		return
   125  	}
   126  	if h < len(db.stages) {
   127  		// This should never happens in production environment.
   128  		// Use panic to make debug easier.
   129  		panic("cannot cleanup staging buffer")
   130  	}
   131  
   132  	cp := &db.stages[h-1]
   133  	if !db.vlogInvalid {
   134  		curr := db.vlog.checkpoint()
   135  		if !curr.isSamePosition(cp) {
   136  			db.vlog.revertToCheckpoint(db, cp)
   137  			db.vlog.truncate(cp)
   138  		}
   139  	}
   140  	db.stages = db.stages[:h-1]
   141  }
   142  
   143  // Checkpoint returns a checkpoint of MemDB.
   144  func (db *MemDB) Checkpoint() *MemDBCheckpoint {
   145  	cp := db.vlog.checkpoint()
   146  	return &cp
   147  }
   148  
   149  // RevertToCheckpoint reverts the MemDB to the checkpoint.
   150  func (db *MemDB) RevertToCheckpoint(cp *MemDBCheckpoint) {
   151  	db.vlog.revertToCheckpoint(db, cp)
   152  	db.vlog.truncate(cp)
   153  }
   154  
   155  // Reset resets the MemBuffer to initial states.
   156  func (db *MemDB) Reset() {
   157  	db.root = nullAddr
   158  	db.stages = db.stages[:0]
   159  	db.dirty = false
   160  	db.vlogInvalid = false
   161  	db.size = 0
   162  	db.count = 0
   163  	db.vlog.reset()
   164  	db.allocator.reset()
   165  }
   166  
   167  // DiscardValues releases the memory used by all values.
   168  // NOTE: any operation need value will panic after this function.
   169  func (db *MemDB) DiscardValues() {
   170  	db.vlogInvalid = true
   171  	db.vlog.reset()
   172  }
   173  
   174  // InspectStage used to inspect the value updates in the given stage.
   175  func (db *MemDB) InspectStage(handle int, f func([]byte, kv.KeyFlags, []byte)) {
   176  	idx := handle - 1
   177  	tail := db.vlog.checkpoint()
   178  	head := db.stages[idx]
   179  	db.vlog.inspectKVInLog(db, &head, &tail, f)
   180  }
   181  
   182  // Get gets the value for key k from kv store.
   183  // If corresponding kv pair does not exist, it returns nil and ErrNotExist.
   184  func (db *MemDB) Get(_ context.Context, key kv.Key) ([]byte, error) {
   185  	if db.vlogInvalid {
   186  		// panic for easier debugging.
   187  		panic("vlog is resetted")
   188  	}
   189  
   190  	x := db.traverse(key, false)
   191  	if x.isNull() {
   192  		return nil, kv.ErrNotExist
   193  	}
   194  	if x.vptr.isNull() {
   195  		// A flag only key, act as value not exists
   196  		return nil, kv.ErrNotExist
   197  	}
   198  	return db.vlog.getValue(x.vptr), nil
   199  }
   200  
   201  // SelectValueHistory select the latest value which makes `predicate` returns true from the modification history.
   202  func (db *MemDB) SelectValueHistory(key []byte, predicate func(value []byte) bool) ([]byte, error) {
   203  	x := db.traverse(key, false)
   204  	if x.isNull() {
   205  		return nil, kv.ErrNotExist
   206  	}
   207  	if x.vptr.isNull() {
   208  		// A flag only key, act as value not exists
   209  		return nil, kv.ErrNotExist
   210  	}
   211  	result := db.vlog.selectValueHistory(x.vptr, func(addr memdbArenaAddr) bool {
   212  		return predicate(db.vlog.getValue(addr))
   213  	})
   214  	if result.isNull() {
   215  		return nil, nil
   216  	}
   217  	return db.vlog.getValue(result), nil
   218  }
   219  
   220  // GetFlags returns the latest flags associated with key.
   221  func (db *MemDB) GetFlags(key []byte) (kv.KeyFlags, error) {
   222  	x := db.traverse(key, false)
   223  	if x.isNull() {
   224  		return 0, kv.ErrNotExist
   225  	}
   226  	return x.getKeyFlags(), nil
   227  }
   228  
   229  // UpdateFlags update the flags associated with key.
   230  func (db *MemDB) UpdateFlags(key []byte, ops ...kv.FlagsOp) {
   231  	err := db.set(key, nil, ops...)
   232  	_ = err // set without value will never fail
   233  }
   234  
   235  // Set sets the value for key k as v into kv store.
   236  // v must NOT be nil or empty, otherwise it returns ErrCannotSetNilValue.
   237  func (db *MemDB) Set(key []byte, value []byte) error {
   238  	if len(value) == 0 {
   239  		return kv.ErrCannotSetNilValue
   240  	}
   241  	return db.set(key, value)
   242  }
   243  
   244  // SetWithFlags put key-value into the last active staging buffer with the given KeyFlags.
   245  func (db *MemDB) SetWithFlags(key []byte, value []byte, ops ...kv.FlagsOp) error {
   246  	if len(value) == 0 {
   247  		return kv.ErrCannotSetNilValue
   248  	}
   249  	return db.set(key, value, ops...)
   250  }
   251  
   252  // Delete removes the entry for key k from kv store.
   253  func (db *MemDB) Delete(key kv.Key) error {
   254  	return db.set(key, tombstone)
   255  }
   256  
   257  // DeleteWithFlags delete key with the given KeyFlags
   258  func (db *MemDB) DeleteWithFlags(key []byte, ops ...kv.FlagsOp) error {
   259  	return db.set(key, tombstone, ops...)
   260  }
   261  
   262  // GetKeyByHandle returns key by handle.
   263  func (db *MemDB) GetKeyByHandle(handle MemKeyHandle) []byte {
   264  	x := db.getNode(handle.toAddr())
   265  	return x.getKey()
   266  }
   267  
   268  // GetValueByHandle returns value by handle.
   269  func (db *MemDB) GetValueByHandle(handle MemKeyHandle) ([]byte, bool) {
   270  	if db.vlogInvalid {
   271  		return nil, false
   272  	}
   273  	x := db.getNode(handle.toAddr())
   274  	if x.vptr.isNull() {
   275  		return nil, false
   276  	}
   277  	return db.vlog.getValue(x.vptr), true
   278  }
   279  
   280  // Len returns the number of entries in the DB.
   281  func (db *MemDB) Len() int {
   282  	return db.count
   283  }
   284  
   285  // Size returns sum of keys and values length.
   286  func (db *MemDB) Size() int {
   287  	return db.size
   288  }
   289  
   290  // Dirty returns whether the root staging buffer is updated.
   291  func (db *MemDB) Dirty() bool {
   292  	return db.dirty
   293  }
   294  
   295  func (db *MemDB) set(key []byte, value []byte, ops ...kv.FlagsOp) error {
   296  	db.Lock()
   297  	defer db.Unlock()
   298  
   299  	if db.vlogInvalid {
   300  		// panic for easier debugging.
   301  		panic("vlog is resetted")
   302  	}
   303  
   304  	if value != nil {
   305  		if size := uint64(len(key) + len(value)); size > db.entrySizeLimit {
   306  			return &kv.ErrEntryTooLarge{
   307  				Limit: db.entrySizeLimit,
   308  				Size:  size,
   309  			}
   310  		}
   311  	}
   312  
   313  	if len(db.stages) == 0 {
   314  		db.dirty = true
   315  	}
   316  	x := db.traverse(key, true)
   317  
   318  	// the NeedConstraintCheckInPrewrite flag is temporary,
   319  	// every write to the node removes the flag unless it's explicitly set.
   320  	// This set must be in the latest stage so no special processing is needed.
   321  	var flags kv.KeyFlags
   322  	if value != nil {
   323  		flags = kv.ApplyFlagsOps(x.getKeyFlags(), append([]kv.FlagsOp{kv.DelNeedConstraintCheckInPrewrite}, ops...)...)
   324  	} else {
   325  		// an UpdateFlag operation, do not delete the NeedConstraintCheckInPrewrite flag.
   326  		flags = kv.ApplyFlagsOps(x.getKeyFlags(), ops...)
   327  	}
   328  	if flags.AndPersistent() != 0 {
   329  		db.dirty = true
   330  	}
   331  	x.setKeyFlags(flags)
   332  
   333  	if value == nil {
   334  		return nil
   335  	}
   336  
   337  	db.setValue(x, value)
   338  	if uint64(db.Size()) > db.bufferSizeLimit {
   339  		return &kv.ErrTxnTooLarge{Size: db.Size()}
   340  	}
   341  	return nil
   342  }
   343  
   344  func (db *MemDB) setValue(x memdbNodeAddr, value []byte) {
   345  	var activeCp *MemDBCheckpoint
   346  	if len(db.stages) > 0 {
   347  		activeCp = &db.stages[len(db.stages)-1]
   348  	}
   349  
   350  	var oldVal []byte
   351  	if !x.vptr.isNull() {
   352  		oldVal = db.vlog.getValue(x.vptr)
   353  	}
   354  
   355  	if len(oldVal) > 0 && db.vlog.canModify(activeCp, x.vptr) {
   356  		// For easier to implement, we only consider this case.
   357  		// It is the most common usage in TiDB's transaction buffers.
   358  		if len(oldVal) == len(value) {
   359  			copy(oldVal, value)
   360  			return
   361  		}
   362  	}
   363  	x.vptr = db.vlog.appendValue(x.addr, x.vptr, value)
   364  	db.size = db.size - len(oldVal) + len(value)
   365  }
   366  
   367  // traverse search for and if not found and insert is true, will add a new node in.
   368  // Returns a pointer to the new node, or the node found.
   369  func (db *MemDB) traverse(key []byte, insert bool) memdbNodeAddr {
   370  	x := db.getRoot()
   371  	y := memdbNodeAddr{nil, nullAddr}
   372  	found := false
   373  
   374  	// walk x down the tree
   375  	for !x.isNull() && !found {
   376  		y = x
   377  		cmp := bytes.Compare(key, x.getKey())
   378  		if cmp < 0 {
   379  			x = x.getLeft(db)
   380  		} else if cmp > 0 {
   381  			x = x.getRight(db)
   382  		} else {
   383  			found = true
   384  		}
   385  	}
   386  
   387  	if found || !insert {
   388  		return x
   389  	}
   390  
   391  	z := db.allocNode(key)
   392  	z.up = y.addr
   393  
   394  	if y.isNull() {
   395  		db.root = z.addr
   396  	} else {
   397  		cmp := bytes.Compare(z.getKey(), y.getKey())
   398  		if cmp < 0 {
   399  			y.left = z.addr
   400  		} else {
   401  			y.right = z.addr
   402  		}
   403  	}
   404  
   405  	z.left = nullAddr
   406  	z.right = nullAddr
   407  
   408  	// colour this new node red
   409  	z.setRed()
   410  
   411  	// Having added a red node, we must now walk back up the tree balancing it,
   412  	// by a series of rotations and changing of colours
   413  	x = z
   414  
   415  	// While we are not at the top and our parent node is red
   416  	// NOTE: Since the root node is guaranteed black, then we
   417  	// are also going to stop if we are the child of the root
   418  
   419  	for x.addr != db.root {
   420  		xUp := x.getUp(db)
   421  		if xUp.isBlack() {
   422  			break
   423  		}
   424  
   425  		xUpUp := xUp.getUp(db)
   426  		// if our parent is on the left side of our grandparent
   427  		if x.up == xUpUp.left {
   428  			// get the right side of our grandparent (uncle?)
   429  			y = xUpUp.getRight(db)
   430  			if y.isRed() {
   431  				// make our parent black
   432  				xUp.setBlack()
   433  				// make our uncle black
   434  				y.setBlack()
   435  				// make our grandparent red
   436  				xUpUp.setRed()
   437  				// now consider our grandparent
   438  				x = xUp.getUp(db)
   439  			} else {
   440  				// if we are on the right side of our parent
   441  				if x.addr == xUp.right {
   442  					// Move up to our parent
   443  					x = x.getUp(db)
   444  					db.leftRotate(x)
   445  					xUp = x.getUp(db)
   446  					xUpUp = xUp.getUp(db)
   447  				}
   448  
   449  				xUp.setBlack()
   450  				xUpUp.setRed()
   451  				db.rightRotate(xUpUp)
   452  			}
   453  		} else {
   454  			// everything here is the same as above, but exchanging left for right
   455  			y = xUpUp.getLeft(db)
   456  			if y.isRed() {
   457  				xUp.setBlack()
   458  				y.setBlack()
   459  				xUpUp.setRed()
   460  
   461  				x = xUp.getUp(db)
   462  			} else {
   463  				if x.addr == xUp.left {
   464  					x = x.getUp(db)
   465  					db.rightRotate(x)
   466  					xUp = x.getUp(db)
   467  					xUpUp = xUp.getUp(db)
   468  				}
   469  
   470  				xUp.setBlack()
   471  				xUpUp.setRed()
   472  				db.leftRotate(xUpUp)
   473  			}
   474  		}
   475  	}
   476  
   477  	// Set the root node black
   478  	db.getRoot().setBlack()
   479  
   480  	return z
   481  }
   482  
   483  //
   484  // Rotate our tree thus:-
   485  //
   486  //             X        leftRotate(X)--->           Y
   487  //           /   \                                /   \
   488  //          A     Y     <---rightRotate(Y)       X     C
   489  //              /   \                          /   \
   490  //             B     C                        A     B
   491  //
   492  // NOTE: This does not change the ordering.
   493  //
   494  // We assume that neither X nor Y is NULL
   495  //
   496  
   497  func (db *MemDB) leftRotate(x memdbNodeAddr) {
   498  	y := x.getRight(db)
   499  
   500  	// Turn Y's left subtree into X's right subtree (move B)
   501  	x.right = y.left
   502  
   503  	// If B is not null, set it's parent to be X
   504  	if !y.left.isNull() {
   505  		left := y.getLeft(db)
   506  		left.up = x.addr
   507  	}
   508  
   509  	// Set Y's parent to be what X's parent was
   510  	y.up = x.up
   511  
   512  	// if X was the root
   513  	if x.up.isNull() {
   514  		db.root = y.addr
   515  	} else {
   516  		xUp := x.getUp(db)
   517  		// Set X's parent's left or right pointer to be Y
   518  		if x.addr == xUp.left {
   519  			xUp.left = y.addr
   520  		} else {
   521  			xUp.right = y.addr
   522  		}
   523  	}
   524  
   525  	// Put X on Y's left
   526  	y.left = x.addr
   527  	// Set X's parent to be Y
   528  	x.up = y.addr
   529  }
   530  
   531  func (db *MemDB) rightRotate(y memdbNodeAddr) {
   532  	x := y.getLeft(db)
   533  
   534  	// Turn X's right subtree into Y's left subtree (move B)
   535  	y.left = x.right
   536  
   537  	// If B is not null, set it's parent to be Y
   538  	if !x.right.isNull() {
   539  		right := x.getRight(db)
   540  		right.up = y.addr
   541  	}
   542  
   543  	// Set X's parent to be what Y's parent was
   544  	x.up = y.up
   545  
   546  	// if Y was the root
   547  	if y.up.isNull() {
   548  		db.root = x.addr
   549  	} else {
   550  		yUp := y.getUp(db)
   551  		// Set Y's parent's left or right pointer to be X
   552  		if y.addr == yUp.left {
   553  			yUp.left = x.addr
   554  		} else {
   555  			yUp.right = x.addr
   556  		}
   557  	}
   558  
   559  	// Put Y on X's right
   560  	x.right = y.addr
   561  	// Set Y's parent to be X
   562  	y.up = x.addr
   563  }
   564  
   565  func (db *MemDB) deleteNode(z memdbNodeAddr) {
   566  	var x, y memdbNodeAddr
   567  
   568  	db.count--
   569  	db.size -= int(z.klen)
   570  
   571  	if z.left.isNull() || z.right.isNull() {
   572  		y = z
   573  	} else {
   574  		y = db.successor(z)
   575  	}
   576  
   577  	if !y.left.isNull() {
   578  		x = y.getLeft(db)
   579  	} else {
   580  		x = y.getRight(db)
   581  	}
   582  	x.up = y.up
   583  
   584  	if y.up.isNull() {
   585  		db.root = x.addr
   586  	} else {
   587  		yUp := y.getUp(db)
   588  		if y.addr == yUp.left {
   589  			yUp.left = x.addr
   590  		} else {
   591  			yUp.right = x.addr
   592  		}
   593  	}
   594  
   595  	needFix := y.isBlack()
   596  
   597  	// NOTE: traditional red-black tree will copy key from Y to Z and free Y.
   598  	// We cannot do the same thing here, due to Y's pointer is stored in vlog and the space in Z may not suitable for Y.
   599  	// So we need to copy states from Z to Y, and relink all nodes formerly connected to Z.
   600  	if y != z {
   601  		db.replaceNode(z, y)
   602  	}
   603  
   604  	if needFix {
   605  		db.deleteNodeFix(x)
   606  	}
   607  
   608  	db.allocator.freeNode(z.addr)
   609  }
   610  
   611  func (db *MemDB) replaceNode(old memdbNodeAddr, new memdbNodeAddr) {
   612  	if !old.up.isNull() {
   613  		oldUp := old.getUp(db)
   614  		if old.addr == oldUp.left {
   615  			oldUp.left = new.addr
   616  		} else {
   617  			oldUp.right = new.addr
   618  		}
   619  	} else {
   620  		db.root = new.addr
   621  	}
   622  	new.up = old.up
   623  
   624  	left := old.getLeft(db)
   625  	left.up = new.addr
   626  	new.left = old.left
   627  
   628  	right := old.getRight(db)
   629  	right.up = new.addr
   630  	new.right = old.right
   631  
   632  	if old.isBlack() {
   633  		new.setBlack()
   634  	} else {
   635  		new.setRed()
   636  	}
   637  }
   638  
   639  func (db *MemDB) deleteNodeFix(x memdbNodeAddr) {
   640  	for x.addr != db.root && x.isBlack() {
   641  		xUp := x.getUp(db)
   642  		if x.addr == xUp.left {
   643  			w := xUp.getRight(db)
   644  			if w.isRed() {
   645  				w.setBlack()
   646  				xUp.setRed()
   647  				db.leftRotate(xUp)
   648  				w = x.getUp(db).getRight(db)
   649  			}
   650  
   651  			if w.getLeft(db).isBlack() && w.getRight(db).isBlack() {
   652  				w.setRed()
   653  				x = x.getUp(db)
   654  			} else {
   655  				if w.getRight(db).isBlack() {
   656  					w.getLeft(db).setBlack()
   657  					w.setRed()
   658  					db.rightRotate(w)
   659  					w = x.getUp(db).getRight(db)
   660  				}
   661  
   662  				xUp := x.getUp(db)
   663  				if xUp.isBlack() {
   664  					w.setBlack()
   665  				} else {
   666  					w.setRed()
   667  				}
   668  				xUp.setBlack()
   669  				w.getRight(db).setBlack()
   670  				db.leftRotate(xUp)
   671  				x = db.getRoot()
   672  			}
   673  		} else {
   674  			w := xUp.getLeft(db)
   675  			if w.isRed() {
   676  				w.setBlack()
   677  				xUp.setRed()
   678  				db.rightRotate(xUp)
   679  				w = x.getUp(db).getLeft(db)
   680  			}
   681  
   682  			if w.getRight(db).isBlack() && w.getLeft(db).isBlack() {
   683  				w.setRed()
   684  				x = x.getUp(db)
   685  			} else {
   686  				if w.getLeft(db).isBlack() {
   687  					w.getRight(db).setBlack()
   688  					w.setRed()
   689  					db.leftRotate(w)
   690  					w = x.getUp(db).getLeft(db)
   691  				}
   692  
   693  				xUp := x.getUp(db)
   694  				if xUp.isBlack() {
   695  					w.setBlack()
   696  				} else {
   697  					w.setRed()
   698  				}
   699  				xUp.setBlack()
   700  				w.getLeft(db).setBlack()
   701  				db.rightRotate(xUp)
   702  				x = db.getRoot()
   703  			}
   704  		}
   705  	}
   706  	x.setBlack()
   707  }
   708  
   709  func (db *MemDB) successor(x memdbNodeAddr) (y memdbNodeAddr) {
   710  	if !x.right.isNull() {
   711  		// If right is not NULL then go right one and
   712  		// then keep going left until we find a node with
   713  		// no left pointer.
   714  
   715  		y = x.getRight(db)
   716  		for !y.left.isNull() {
   717  			y = y.getLeft(db)
   718  		}
   719  		return
   720  	}
   721  
   722  	// Go up the tree until we get to a node that is on the
   723  	// left of its parent (or the root) and then return the
   724  	// parent.
   725  
   726  	y = x.getUp(db)
   727  	for !y.isNull() && x.addr == y.right {
   728  		x = y
   729  		y = y.getUp(db)
   730  	}
   731  	return y
   732  }
   733  
   734  func (db *MemDB) predecessor(x memdbNodeAddr) (y memdbNodeAddr) {
   735  	if !x.left.isNull() {
   736  		// If left is not NULL then go left one and
   737  		// then keep going right until we find a node with
   738  		// no right pointer.
   739  
   740  		y = x.getLeft(db)
   741  		for !y.right.isNull() {
   742  			y = y.getRight(db)
   743  		}
   744  		return
   745  	}
   746  
   747  	// Go up the tree until we get to a node that is on the
   748  	// right of its parent (or the root) and then return the
   749  	// parent.
   750  
   751  	y = x.getUp(db)
   752  	for !y.isNull() && x.addr == y.left {
   753  		x = y
   754  		y = y.getUp(db)
   755  	}
   756  	return y
   757  }
   758  
   759  func (db *MemDB) getNode(x memdbArenaAddr) memdbNodeAddr {
   760  	return memdbNodeAddr{db.allocator.getNode(x), x}
   761  }
   762  
   763  func (db *MemDB) getRoot() memdbNodeAddr {
   764  	return db.getNode(db.root)
   765  }
   766  
   767  func (db *MemDB) allocNode(key []byte) memdbNodeAddr {
   768  	db.size += len(key)
   769  	db.count++
   770  	x, xn := db.allocator.allocNode(key)
   771  	return memdbNodeAddr{xn, x}
   772  }
   773  
   774  type memdbNodeAddr struct {
   775  	*memdbNode
   776  	addr memdbArenaAddr
   777  }
   778  
   779  func (a *memdbNodeAddr) isNull() bool {
   780  	return a.addr.isNull()
   781  }
   782  
   783  func (a memdbNodeAddr) getUp(db *MemDB) memdbNodeAddr {
   784  	return db.getNode(a.up)
   785  }
   786  
   787  func (a memdbNodeAddr) getLeft(db *MemDB) memdbNodeAddr {
   788  	return db.getNode(a.left)
   789  }
   790  
   791  func (a memdbNodeAddr) getRight(db *MemDB) memdbNodeAddr {
   792  	return db.getNode(a.right)
   793  }
   794  
   795  type memdbNode struct {
   796  	up    memdbArenaAddr
   797  	left  memdbArenaAddr
   798  	right memdbArenaAddr
   799  	vptr  memdbArenaAddr
   800  	klen  uint16
   801  	flags uint16
   802  }
   803  
   804  func (n *memdbNode) isRed() bool {
   805  	return n.flags&nodeColorBit != 0
   806  }
   807  
   808  func (n *memdbNode) isBlack() bool {
   809  	return !n.isRed()
   810  }
   811  
   812  func (n *memdbNode) setRed() {
   813  	n.flags |= nodeColorBit
   814  }
   815  
   816  func (n *memdbNode) setBlack() {
   817  	n.flags &= ^nodeColorBit
   818  }
   819  
   820  func (n *memdbNode) getKey() []byte {
   821  	var ret []byte
   822  	hdr := (*reflect.SliceHeader)(unsafe.Pointer(&ret))
   823  	hdr.Data = uintptr(unsafe.Pointer(&n.flags)) + kv.FlagBytes
   824  	hdr.Len = int(n.klen)
   825  	hdr.Cap = int(n.klen)
   826  	return ret
   827  }
   828  
   829  const (
   830  	// bit 1 => red, bit 0 => black
   831  	nodeColorBit  uint16 = 0x8000
   832  	nodeFlagsMask        = ^nodeColorBit
   833  )
   834  
   835  func (n *memdbNode) getKeyFlags() kv.KeyFlags {
   836  	return kv.KeyFlags(n.flags & nodeFlagsMask)
   837  }
   838  
   839  func (n *memdbNode) setKeyFlags(f kv.KeyFlags) {
   840  	n.flags = (^nodeFlagsMask & n.flags) | uint16(f)
   841  }
   842  
   843  // RemoveFromBuffer removes a record from the mem buffer. It should be only used for test.
   844  func (db *MemDB) RemoveFromBuffer(key []byte) {
   845  	x := db.traverse(key, false)
   846  	if x.isNull() {
   847  		return
   848  	}
   849  	db.size -= len(db.vlog.getValue(x.vptr))
   850  	db.deleteNode(x)
   851  }
   852  
   853  // SetMemoryFootprintChangeHook sets the hook function that is triggered when memdb grows.
   854  func (db *MemDB) SetMemoryFootprintChangeHook(hook func(uint64)) {
   855  	innerHook := func() {
   856  		hook(db.allocator.capacity + db.vlog.capacity)
   857  	}
   858  	db.allocator.memChangeHook = innerHook
   859  	db.vlog.memChangeHook = innerHook
   860  }
   861  
   862  // Mem returns the current memory footprint
   863  func (db *MemDB) Mem() uint64 {
   864  	return db.allocator.capacity + db.vlog.capacity
   865  }