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 }