github.com/gnolang/gno@v0.0.0-20240520182011-228e9d0192ce/tm2/pkg/iavl/tree_test.go (about) 1 package iavl 2 3 import ( 4 "bytes" 5 "flag" 6 "fmt" 7 "os" 8 "runtime" 9 "strconv" 10 "testing" 11 12 "github.com/stretchr/testify/assert" 13 "github.com/stretchr/testify/require" 14 15 "github.com/gnolang/gno/tm2/pkg/db" 16 "github.com/gnolang/gno/tm2/pkg/db/goleveldb" 17 "github.com/gnolang/gno/tm2/pkg/db/memdb" 18 "github.com/gnolang/gno/tm2/pkg/random" 19 ) 20 21 var ( 22 testLevelDB bool 23 testFuzzIterations int 24 rnd *random.Rand 25 ) 26 27 // NOTE see https://github.com/golang/go/issues/31859 28 var _ = func() bool { 29 testing.Init() 30 return true 31 }() 32 33 func init() { 34 rnd = random.NewRand() 35 rnd.Seed(0) // for determinism 36 flag.BoolVar(&testLevelDB, "test.leveldb", false, "test leveldb backend") 37 flag.IntVar(&testFuzzIterations, "test.fuzz-iterations", 100000, "number of fuzz testing iterations") 38 flag.Parse() 39 } 40 41 func getTestDB() (db.DB, func()) { 42 if testLevelDB { 43 d, err := goleveldb.NewGoLevelDB("test", ".") 44 if err != nil { 45 panic(err) 46 } 47 return d, func() { 48 d.Close() 49 os.RemoveAll("./test.db") 50 } 51 } 52 return memdb.NewMemDB(), func() {} 53 } 54 55 func TestVersionedRandomTree(t *testing.T) { 56 t.Parallel() 57 58 require := require.New(t) 59 60 d, closeDB := getTestDB() 61 defer closeDB() 62 63 tree := NewMutableTree(d, 100) 64 versions := 50 65 keysPerVersion := 30 66 67 // Create a tree of size 1000 with 100 versions. 68 for i := 1; i <= versions; i++ { 69 for j := 0; j < keysPerVersion; j++ { 70 k := []byte(rnd.Str(8)) 71 v := []byte(rnd.Str(8)) 72 tree.Set(k, v) 73 } 74 tree.SaveVersion() 75 } 76 require.Equal(versions, len(tree.ndb.roots()), "wrong number of roots") 77 require.Equal(versions*keysPerVersion, len(tree.ndb.leafNodes()), "wrong number of nodes") 78 79 // Before deleting old versions, we should have equal or more nodes in the 80 // db than in the current tree version. 81 require.True(len(tree.ndb.nodes()) >= tree.nodeSize()) 82 83 // Ensure it returns all versions in sorted order 84 available := zip(tree.AvailableVersions()) 85 assert.Equal(t, versions, len(available)) 86 assert.Equal(t, int64(1), available[0]) 87 assert.Equal(t, int64(versions), available[len(available)-1]) 88 89 for i := 1; i < versions; i++ { 90 tree.DeleteVersion(int64(i)) 91 } 92 available = zip(tree.AvailableVersions()) 93 94 require.Len(available, 1, "tree must have one version left") 95 tr, err := tree.GetImmutable(int64(versions)) 96 require.NoError(err, "GetImmutable should not error for version %d", versions) 97 require.Equal(tr.root, tree.root) 98 99 // we should only have one available version now 100 available = zip(tree.AvailableVersions()) 101 assert.Equal(t, 1, len(available)) 102 assert.Equal(t, int64(versions), available[0]) 103 104 // After cleaning up all previous versions, we should have as many nodes 105 // in the db as in the current tree version. 106 require.Len(tree.ndb.leafNodes(), int(tree.Size())) 107 108 require.Equal(tree.nodeSize(), len(tree.ndb.nodes())) 109 } 110 111 func TestVersionedRandomTreeSmallKeys(t *testing.T) { 112 t.Parallel() 113 114 require := require.New(t) 115 d, closeDB := getTestDB() 116 defer closeDB() 117 118 tree := NewMutableTree(d, 100) 119 singleVersionTree := NewMutableTree(memdb.NewMemDB(), 0) 120 versions := 20 121 keysPerVersion := 50 122 123 for i := 1; i <= versions; i++ { 124 for j := 0; j < keysPerVersion; j++ { 125 // Keys of size one are likely to be overwritten. 126 k := []byte(rnd.Str(1)) 127 v := []byte(rnd.Str(8)) 128 tree.Set(k, v) 129 singleVersionTree.Set(k, v) 130 } 131 tree.SaveVersion() 132 } 133 singleVersionTree.SaveVersion() 134 135 for i := 1; i < versions; i++ { 136 tree.DeleteVersion(int64(i)) 137 } 138 139 // After cleaning up all previous versions, we should have as many nodes 140 // in the db as in the current tree version. The simple tree must be equal 141 // too. 142 require.Len(tree.ndb.leafNodes(), int(tree.Size())) 143 require.Len(tree.ndb.nodes(), tree.nodeSize()) 144 require.Len(tree.ndb.nodes(), singleVersionTree.nodeSize()) 145 146 // Try getting random keys. 147 for i := 0; i < keysPerVersion; i++ { 148 _, val := tree.Get([]byte(rnd.Str(1))) 149 require.NotNil(val) 150 require.NotEmpty(val) 151 } 152 } 153 154 func TestVersionedRandomTreeSmallKeysRandomDeletes(t *testing.T) { 155 t.Parallel() 156 157 require := require.New(t) 158 d, closeDB := getTestDB() 159 defer closeDB() 160 161 tree := NewMutableTree(d, 100) 162 singleVersionTree := NewMutableTree(memdb.NewMemDB(), 0) 163 versions := 30 164 keysPerVersion := 50 165 166 for i := 1; i <= versions; i++ { 167 for j := 0; j < keysPerVersion; j++ { 168 // Keys of size one are likely to be overwritten. 169 k := []byte(rnd.Str(1)) 170 v := []byte(rnd.Str(8)) 171 tree.Set(k, v) 172 singleVersionTree.Set(k, v) 173 } 174 tree.SaveVersion() 175 } 176 singleVersionTree.SaveVersion() 177 178 for _, i := range rnd.Perm(versions - 1) { 179 tree.DeleteVersion(int64(i + 1)) 180 } 181 182 // After cleaning up all previous versions, we should have as many nodes 183 // in the db as in the current tree version. The simple tree must be equal 184 // too. 185 require.Len(tree.ndb.leafNodes(), int(tree.Size())) 186 require.Len(tree.ndb.nodes(), tree.nodeSize()) 187 require.Len(tree.ndb.nodes(), singleVersionTree.nodeSize()) 188 189 // Try getting random keys. 190 for i := 0; i < keysPerVersion; i++ { 191 _, val := tree.Get([]byte(rnd.Str(1))) 192 require.NotNil(val) 193 require.NotEmpty(val) 194 } 195 } 196 197 func TestVersionedTreeSpecial1(t *testing.T) { 198 t.Parallel() 199 200 tree := NewMutableTree(memdb.NewMemDB(), 100) 201 202 tree.Set([]byte("C"), []byte("so43QQFN")) 203 tree.SaveVersion() 204 205 tree.Set([]byte("A"), []byte("ut7sTTAO")) 206 tree.SaveVersion() 207 208 tree.Set([]byte("X"), []byte("AoWWC1kN")) 209 tree.SaveVersion() 210 211 tree.Set([]byte("T"), []byte("MhkWjkVy")) 212 tree.SaveVersion() 213 214 tree.DeleteVersion(1) 215 tree.DeleteVersion(2) 216 tree.DeleteVersion(3) 217 218 require.Equal(t, tree.nodeSize(), len(tree.ndb.nodes())) 219 } 220 221 func TestVersionedRandomTreeSpecial2(t *testing.T) { 222 t.Parallel() 223 224 require := require.New(t) 225 tree := NewMutableTree(memdb.NewMemDB(), 100) 226 227 tree.Set([]byte("OFMe2Yvm"), []byte("ez2OtQtE")) 228 tree.Set([]byte("WEN4iN7Y"), []byte("kQNyUalI")) 229 tree.SaveVersion() 230 231 tree.Set([]byte("1yY3pXHr"), []byte("udYznpII")) 232 tree.Set([]byte("7OSHNE7k"), []byte("ff181M2d")) 233 tree.SaveVersion() 234 235 tree.DeleteVersion(1) 236 require.Len(tree.ndb.nodes(), tree.nodeSize()) 237 } 238 239 func TestVersionedEmptyTree(t *testing.T) { 240 t.Parallel() 241 242 require := require.New(t) 243 d, closeDB := getTestDB() 244 defer closeDB() 245 246 tree := NewMutableTree(d, 0) 247 248 hash, v, err := tree.SaveVersion() 249 require.Nil(hash) 250 require.EqualValues(1, v) 251 require.NoError(err) 252 253 hash, v, err = tree.SaveVersion() 254 require.Nil(hash) 255 require.EqualValues(2, v) 256 require.NoError(err) 257 258 hash, v, err = tree.SaveVersion() 259 require.Nil(hash) 260 require.EqualValues(3, v) 261 require.NoError(err) 262 263 hash, v, err = tree.SaveVersion() 264 require.Nil(hash) 265 require.EqualValues(4, v) 266 require.NoError(err) 267 268 require.EqualValues(4, tree.Version()) 269 270 require.True(tree.VersionExists(1)) 271 require.True(tree.VersionExists(3)) 272 273 require.NoError(tree.DeleteVersion(1)) 274 require.NoError(tree.DeleteVersion(3)) 275 276 require.False(tree.VersionExists(1)) 277 require.False(tree.VersionExists(3)) 278 279 tree.Set([]byte("k"), []byte("v")) 280 require.EqualValues(5, tree.root.version) 281 282 // Now reload the tree. 283 284 tree = NewMutableTree(d, 0) 285 tree.Load() 286 287 require.False(tree.VersionExists(1)) 288 require.True(tree.VersionExists(2)) 289 require.False(tree.VersionExists(3)) 290 291 t2, err := tree.GetImmutable(2) 292 require.NoError(err, "GetImmutable should not fail for version 2") 293 294 require.Empty(t2.root) 295 } 296 297 func TestVersionedTree(t *testing.T) { 298 t.Parallel() 299 300 require := require.New(t) 301 d, closeDB := getTestDB() 302 defer closeDB() 303 304 tree := NewMutableTree(d, 0) 305 306 // We start with zero keys in the databse. 307 require.Equal(0, tree.ndb.size()) 308 require.True(tree.IsEmpty()) 309 310 // version 0 311 312 tree.Set([]byte("key1"), []byte("val0")) 313 tree.Set([]byte("key2"), []byte("val0")) 314 315 // Still zero keys, since we haven't written them. 316 require.Len(tree.ndb.leafNodes(), 0) 317 require.False(tree.IsEmpty()) 318 319 // Now let's write the keys to storage. 320 hash1, v, err := tree.SaveVersion() 321 require.NoError(err) 322 require.False(tree.IsEmpty()) 323 require.EqualValues(1, v) 324 325 // -----1----- 326 // key1 = val0 version=1 327 // key2 = val0 version=1 328 // key2 (root) version=1 329 // ----------- 330 331 nodes1 := tree.ndb.leafNodes() 332 require.Len(nodes1, 2, "db should have a size of 2") 333 334 // version 1 335 336 tree.Set([]byte("key1"), []byte("val1")) 337 tree.Set([]byte("key2"), []byte("val1")) 338 tree.Set([]byte("key3"), []byte("val1")) 339 require.Len(tree.ndb.leafNodes(), len(nodes1)) 340 341 hash2, v2, err := tree.SaveVersion() 342 require.NoError(err) 343 require.False(bytes.Equal(hash1, hash2)) 344 require.EqualValues(v+1, v2) 345 346 // Recreate a new tree and load it, to make sure it works in this 347 // scenario. 348 tree = NewMutableTree(d, 100) 349 _, err = tree.Load() 350 require.NoError(err) 351 available := zip(tree.AvailableVersions()) 352 353 require.Len(available, 2, "wrong number of versions") 354 require.EqualValues(v2, tree.Version()) 355 356 // -----1----- 357 // key1 = val0 <orphaned> 358 // key2 = val0 <orphaned> 359 // -----2----- 360 // key1 = val1 361 // key2 = val1 362 // key3 = val1 363 // ----------- 364 365 nodes2 := tree.ndb.leafNodes() 366 require.Len(nodes2, 5, "db should have grown in size") 367 require.Len(tree.ndb.orphans(), 3, "db should have three orphans") 368 369 // Create two more orphans. 370 tree.Remove([]byte("key1")) 371 tree.Set([]byte("key2"), []byte("val2")) 372 373 hash3, v3, _ := tree.SaveVersion() 374 require.EqualValues(3, v3) 375 376 // -----1----- 377 // key1 = val0 <orphaned> (replaced) 378 // key2 = val0 <orphaned> (replaced) 379 // -----2----- 380 // key1 = val1 <orphaned> (removed) 381 // key2 = val1 <orphaned> (replaced) 382 // key3 = val1 383 // -----3----- 384 // key2 = val2 385 // ----------- 386 387 nodes3 := tree.ndb.leafNodes() 388 require.Len(nodes3, 6, "wrong number of nodes") 389 require.Len(tree.ndb.orphans(), 6, "wrong number of orphans") 390 391 hash4, _, _ := tree.SaveVersion() 392 require.EqualValues(hash3, hash4) 393 require.NotNil(hash4) 394 395 tree = NewMutableTree(d, 100) 396 _, err = tree.Load() 397 require.NoError(err) 398 399 // ------------ 400 // DB UNCHANGED 401 // ------------ 402 403 nodes4 := tree.ndb.leafNodes() 404 require.Len(nodes4, len(nodes3), "db should not have changed in size") 405 406 tree.Set([]byte("key1"), []byte("val0")) 407 408 // "key2" 409 _, val := tree.GetVersioned([]byte("key2"), 0) 410 require.Nil(val) 411 412 _, val = tree.GetVersioned([]byte("key2"), 1) 413 require.Equal("val0", string(val)) 414 415 _, val = tree.GetVersioned([]byte("key2"), 2) 416 require.Equal("val1", string(val)) 417 418 _, val = tree.Get([]byte("key2")) 419 require.Equal("val2", string(val)) 420 421 // "key1" 422 _, val = tree.GetVersioned([]byte("key1"), 1) 423 require.Equal("val0", string(val)) 424 425 _, val = tree.GetVersioned([]byte("key1"), 2) 426 require.Equal("val1", string(val)) 427 428 _, val = tree.GetVersioned([]byte("key1"), 3) 429 require.Nil(val) 430 431 _, val = tree.GetVersioned([]byte("key1"), 4) 432 require.Nil(val) 433 434 _, val = tree.Get([]byte("key1")) 435 require.Equal("val0", string(val)) 436 437 // "key3" 438 _, val = tree.GetVersioned([]byte("key3"), 0) 439 require.Nil(val) 440 441 _, val = tree.GetVersioned([]byte("key3"), 2) 442 require.Equal("val1", string(val)) 443 444 _, val = tree.GetVersioned([]byte("key3"), 3) 445 require.Equal("val1", string(val)) 446 447 // Delete a version. After this the keys in that version should not be found. 448 449 tree.DeleteVersion(2) 450 451 // -----1----- 452 // key1 = val0 453 // key2 = val0 454 // -----2----- 455 // key3 = val1 456 // -----3----- 457 // key2 = val2 458 // ----------- 459 460 nodes5 := tree.ndb.leafNodes() 461 require.True(len(nodes5) < len(nodes4), "db should have shrunk after delete %d !< %d", len(nodes5), len(nodes4)) 462 463 _, val = tree.GetVersioned([]byte("key2"), 2) 464 require.Nil(val) 465 466 _, val = tree.GetVersioned([]byte("key3"), 2) 467 require.Nil(val) 468 469 // But they should still exist in the latest version. 470 471 _, val = tree.Get([]byte("key2")) 472 require.Equal("val2", string(val)) 473 474 _, val = tree.Get([]byte("key3")) 475 require.Equal("val1", string(val)) 476 477 // Version 1 should still be available. 478 479 _, val = tree.GetVersioned([]byte("key1"), 1) 480 require.Equal("val0", string(val)) 481 482 _, val = tree.GetVersioned([]byte("key2"), 1) 483 require.Equal("val0", string(val)) 484 } 485 486 func TestVersionedTreeVersionDeletingEfficiency(t *testing.T) { 487 t.Parallel() 488 489 d, closeDB := getTestDB() 490 defer closeDB() 491 492 tree := NewMutableTree(d, 0) 493 494 tree.Set([]byte("key0"), []byte("val0")) 495 tree.Set([]byte("key1"), []byte("val0")) 496 tree.Set([]byte("key2"), []byte("val0")) 497 tree.SaveVersion() 498 499 require.Len(t, tree.ndb.leafNodes(), 3) 500 501 tree.Set([]byte("key1"), []byte("val1")) 502 tree.Set([]byte("key2"), []byte("val1")) 503 tree.Set([]byte("key3"), []byte("val1")) 504 tree.SaveVersion() 505 506 require.Len(t, tree.ndb.leafNodes(), 6) 507 508 tree.Set([]byte("key0"), []byte("val2")) 509 tree.Remove([]byte("key1")) 510 tree.Set([]byte("key2"), []byte("val2")) 511 tree.SaveVersion() 512 513 require.Len(t, tree.ndb.leafNodes(), 8) 514 515 tree.DeleteVersion(2) 516 517 require.Len(t, tree.ndb.leafNodes(), 6) 518 519 tree.DeleteVersion(1) 520 521 require.Len(t, tree.ndb.leafNodes(), 3) 522 523 tree2 := NewMutableTree(memdb.NewMemDB(), 0) 524 tree2.Set([]byte("key0"), []byte("val2")) 525 tree2.Set([]byte("key2"), []byte("val2")) 526 tree2.Set([]byte("key3"), []byte("val1")) 527 tree2.SaveVersion() 528 529 require.Equal(t, tree2.nodeSize(), tree.nodeSize()) 530 } 531 532 func TestVersionedTreeOrphanDeleting(t *testing.T) { 533 t.Parallel() 534 535 mdb := memdb.NewMemDB() 536 tree := NewMutableTree(mdb, 0) 537 538 tree.Set([]byte("key0"), []byte("val0")) 539 tree.Set([]byte("key1"), []byte("val0")) 540 tree.Set([]byte("key2"), []byte("val0")) 541 tree.SaveVersion() 542 543 tree.Set([]byte("key1"), []byte("val1")) 544 tree.Set([]byte("key2"), []byte("val1")) 545 tree.Set([]byte("key3"), []byte("val1")) 546 tree.SaveVersion() 547 548 tree.Set([]byte("key0"), []byte("val2")) 549 tree.Remove([]byte("key1")) 550 tree.Set([]byte("key2"), []byte("val2")) 551 tree.SaveVersion() 552 553 tree.DeleteVersion(2) 554 555 _, val := tree.Get([]byte("key0")) 556 require.Equal(t, val, []byte("val2")) 557 558 _, val = tree.Get([]byte("key1")) 559 require.Nil(t, val) 560 561 _, val = tree.Get([]byte("key2")) 562 require.Equal(t, val, []byte("val2")) 563 564 _, val = tree.Get([]byte("key3")) 565 require.Equal(t, val, []byte("val1")) 566 567 tree.DeleteVersion(1) 568 569 require.Len(t, tree.ndb.leafNodes(), 3) 570 } 571 572 func TestVersionedTreeSpecialCase(t *testing.T) { 573 t.Parallel() 574 575 require := require.New(t) 576 tree := NewMutableTree(memdb.NewMemDB(), 100) 577 578 tree.Set([]byte("key1"), []byte("val0")) 579 tree.Set([]byte("key2"), []byte("val0")) 580 tree.SaveVersion() 581 582 tree.Set([]byte("key1"), []byte("val1")) 583 tree.Set([]byte("key2"), []byte("val1")) 584 tree.SaveVersion() 585 586 tree.Set([]byte("key2"), []byte("val2")) 587 tree.SaveVersion() 588 589 tree.DeleteVersion(2) 590 591 _, val := tree.GetVersioned([]byte("key2"), 1) 592 require.Equal("val0", string(val)) 593 } 594 595 func TestVersionedTreeSpecialCase2(t *testing.T) { 596 t.Parallel() 597 598 require := require.New(t) 599 d := memdb.NewMemDB() 600 601 tree := NewMutableTree(d, 100) 602 603 tree.Set([]byte("key1"), []byte("val0")) 604 tree.Set([]byte("key2"), []byte("val0")) 605 tree.SaveVersion() 606 607 tree.Set([]byte("key1"), []byte("val1")) 608 tree.Set([]byte("key2"), []byte("val1")) 609 tree.SaveVersion() 610 611 tree.Set([]byte("key2"), []byte("val2")) 612 tree.SaveVersion() 613 614 tree = NewMutableTree(d, 100) 615 _, err := tree.Load() 616 require.NoError(err) 617 618 require.NoError(tree.DeleteVersion(2)) 619 620 _, val := tree.GetVersioned([]byte("key2"), 1) 621 require.Equal("val0", string(val)) 622 } 623 624 func TestVersionedTreeSpecialCase3(t *testing.T) { 625 t.Parallel() 626 627 require := require.New(t) 628 tree := NewMutableTree(memdb.NewMemDB(), 0) 629 630 tree.Set([]byte("m"), []byte("liWT0U6G")) 631 tree.Set([]byte("G"), []byte("7PxRXwUA")) 632 tree.SaveVersion() 633 634 tree.Set([]byte("7"), []byte("XRLXgf8C")) 635 tree.SaveVersion() 636 637 tree.Set([]byte("r"), []byte("bBEmIXBU")) 638 tree.SaveVersion() 639 640 tree.Set([]byte("i"), []byte("kkIS35te")) 641 tree.SaveVersion() 642 643 tree.Set([]byte("k"), []byte("CpEnpzKJ")) 644 tree.SaveVersion() 645 646 tree.DeleteVersion(1) 647 tree.DeleteVersion(2) 648 tree.DeleteVersion(3) 649 tree.DeleteVersion(4) 650 651 require.Equal(tree.nodeSize(), len(tree.ndb.nodes())) 652 } 653 654 func TestVersionedTreeSaveAndLoad(t *testing.T) { 655 t.Parallel() 656 657 require := require.New(t) 658 d := memdb.NewMemDB() 659 tree := NewMutableTree(d, 0) 660 661 // Loading with an empty root is a no-op. 662 tree.Load() 663 664 tree.Set([]byte("C"), []byte("so43QQFN")) 665 tree.SaveVersion() 666 667 tree.Set([]byte("A"), []byte("ut7sTTAO")) 668 tree.SaveVersion() 669 670 tree.Set([]byte("X"), []byte("AoWWC1kN")) 671 tree.SaveVersion() 672 673 tree.SaveVersion() 674 tree.SaveVersion() 675 tree.SaveVersion() 676 677 preHash := tree.Hash() 678 require.NotNil(preHash) 679 680 require.Equal(int64(6), tree.Version()) 681 682 // Reload the tree, to test that roots and orphans are properly loaded. 683 ntree := NewMutableTree(d, 0) 684 ntree.Load() 685 686 require.False(ntree.IsEmpty()) 687 require.Equal(int64(6), ntree.Version()) 688 689 postHash := ntree.Hash() 690 require.Equal(preHash, postHash) 691 692 ntree.Set([]byte("T"), []byte("MhkWjkVy")) 693 ntree.SaveVersion() 694 695 ntree.DeleteVersion(6) 696 ntree.DeleteVersion(5) 697 ntree.DeleteVersion(1) 698 ntree.DeleteVersion(2) 699 ntree.DeleteVersion(4) 700 ntree.DeleteVersion(3) 701 702 require.False(ntree.IsEmpty()) 703 require.Equal(int64(4), ntree.Size()) 704 require.Len(ntree.ndb.nodes(), ntree.nodeSize()) 705 } 706 707 func TestVersionedTreeErrors(t *testing.T) { 708 t.Parallel() 709 710 require := require.New(t) 711 tree := NewMutableTree(memdb.NewMemDB(), 100) 712 713 // Can't delete non-existent versions. 714 require.Error(tree.DeleteVersion(1)) 715 require.Error(tree.DeleteVersion(99)) 716 717 tree.Set([]byte("key"), []byte("val")) 718 719 // Saving with content is ok. 720 _, _, err := tree.SaveVersion() 721 require.NoError(err) 722 723 // Can't delete current version. 724 require.Error(tree.DeleteVersion(1)) 725 726 // Trying to get a key from a version which doesn't exist. 727 _, val := tree.GetVersioned([]byte("key"), 404) 728 require.Nil(val) 729 730 // Same thing with proof. We get an error because a proof couldn't be 731 // constructed. 732 val, proof, err := tree.GetVersionedWithProof([]byte("key"), 404) 733 require.Nil(val) 734 require.Empty(proof) 735 require.Error(err) 736 } 737 738 func TestVersionedCheckpoints(t *testing.T) { 739 t.Parallel() 740 741 require := require.New(t) 742 d, closeDB := getTestDB() 743 defer closeDB() 744 745 tree := NewMutableTree(d, 100) 746 versions := 50 747 keysPerVersion := 10 748 versionsPerCheckpoint := 5 749 keys := map[int64]([][]byte){} 750 751 for i := 1; i <= versions; i++ { 752 for j := 0; j < keysPerVersion; j++ { 753 k := []byte(rnd.Str(1)) 754 v := []byte(rnd.Str(8)) 755 keys[int64(i)] = append(keys[int64(i)], k) 756 tree.Set(k, v) 757 } 758 tree.SaveVersion() 759 } 760 761 for i := 1; i <= versions; i++ { 762 if i%versionsPerCheckpoint != 0 { 763 tree.DeleteVersion(int64(i)) 764 } 765 } 766 767 // Make sure all keys exist at least once. 768 for _, ks := range keys { 769 for _, k := range ks { 770 _, val := tree.Get(k) 771 require.NotEmpty(val) 772 } 773 } 774 775 // Make sure all keys from deleted versions aren't present. 776 for i := 1; i <= versions; i++ { 777 if i%versionsPerCheckpoint != 0 { 778 for _, k := range keys[int64(i)] { 779 _, val := tree.GetVersioned(k, int64(i)) 780 require.Nil(val) 781 } 782 } 783 } 784 785 // Make sure all keys exist at all checkpoints. 786 for i := 1; i <= versions; i++ { 787 for _, k := range keys[int64(i)] { 788 if i%versionsPerCheckpoint == 0 { 789 _, val := tree.GetVersioned(k, int64(i)) 790 require.NotEmpty(val) 791 } 792 } 793 } 794 } 795 796 func TestVersionedCheckpointsSpecialCase(t *testing.T) { 797 t.Parallel() 798 799 require := require.New(t) 800 tree := NewMutableTree(memdb.NewMemDB(), 0) 801 key := []byte("k") 802 803 tree.Set(key, []byte("val1")) 804 805 tree.SaveVersion() 806 // ... 807 tree.SaveVersion() 808 // ... 809 tree.SaveVersion() 810 // ... 811 // This orphans "k" at version 1. 812 tree.Set(key, []byte("val2")) 813 tree.SaveVersion() 814 815 // When version 1 is deleted, the orphans should move to the next 816 // checkpoint, which is version 10. 817 tree.DeleteVersion(1) 818 819 _, val := tree.GetVersioned(key, 2) 820 require.NotEmpty(val) 821 require.Equal([]byte("val1"), val) 822 } 823 824 func TestVersionedCheckpointsSpecialCase2(t *testing.T) { 825 t.Parallel() 826 827 tree := NewMutableTree(memdb.NewMemDB(), 0) 828 829 tree.Set([]byte("U"), []byte("XamDUtiJ")) 830 tree.Set([]byte("A"), []byte("UkZBuYIU")) 831 tree.Set([]byte("H"), []byte("7a9En4uw")) 832 tree.Set([]byte("V"), []byte("5HXU3pSI")) 833 tree.SaveVersion() 834 835 tree.Set([]byte("U"), []byte("Replaced")) 836 tree.Set([]byte("A"), []byte("Replaced")) 837 tree.SaveVersion() 838 839 tree.Set([]byte("X"), []byte("New")) 840 tree.SaveVersion() 841 842 tree.DeleteVersion(1) 843 tree.DeleteVersion(2) 844 } 845 846 func TestVersionedCheckpointsSpecialCase3(t *testing.T) { 847 t.Parallel() 848 849 tree := NewMutableTree(memdb.NewMemDB(), 0) 850 851 tree.Set([]byte("n"), []byte("2wUCUs8q")) 852 tree.Set([]byte("l"), []byte("WQ7mvMbc")) 853 tree.SaveVersion() 854 855 tree.Set([]byte("N"), []byte("ved29IqU")) 856 tree.Set([]byte("v"), []byte("01jquVXU")) 857 tree.SaveVersion() 858 859 tree.Set([]byte("l"), []byte("bhIpltPM")) 860 tree.Set([]byte("B"), []byte("rj97IKZh")) 861 tree.SaveVersion() 862 863 tree.DeleteVersion(2) 864 865 tree.GetVersioned([]byte("m"), 1) 866 } 867 868 func TestVersionedCheckpointsSpecialCase4(t *testing.T) { 869 t.Parallel() 870 871 tree := NewMutableTree(memdb.NewMemDB(), 0) 872 873 tree.Set([]byte("U"), []byte("XamDUtiJ")) 874 tree.Set([]byte("A"), []byte("UkZBuYIU")) 875 tree.Set([]byte("H"), []byte("7a9En4uw")) 876 tree.Set([]byte("V"), []byte("5HXU3pSI")) 877 tree.SaveVersion() 878 879 tree.Remove([]byte("U")) 880 tree.Remove([]byte("A")) 881 tree.SaveVersion() 882 883 tree.Set([]byte("X"), []byte("New")) 884 tree.SaveVersion() 885 886 _, val := tree.GetVersioned([]byte("A"), 2) 887 require.Nil(t, val) 888 889 _, val = tree.GetVersioned([]byte("A"), 1) 890 require.NotEmpty(t, val) 891 892 tree.DeleteVersion(1) 893 tree.DeleteVersion(2) 894 895 _, val = tree.GetVersioned([]byte("A"), 2) 896 require.Nil(t, val) 897 898 _, val = tree.GetVersioned([]byte("A"), 1) 899 require.Nil(t, val) 900 } 901 902 func TestVersionedCheckpointsSpecialCase5(t *testing.T) { 903 t.Parallel() 904 905 tree := NewMutableTree(memdb.NewMemDB(), 0) 906 907 tree.Set([]byte("R"), []byte("ygZlIzeW")) 908 tree.SaveVersion() 909 910 tree.Set([]byte("j"), []byte("ZgmCWyo2")) 911 tree.SaveVersion() 912 913 tree.Set([]byte("R"), []byte("vQDaoz6Z")) 914 tree.SaveVersion() 915 916 tree.DeleteVersion(1) 917 918 tree.GetVersioned([]byte("R"), 2) 919 } 920 921 func TestVersionedCheckpointsSpecialCase6(t *testing.T) { 922 t.Parallel() 923 924 tree := NewMutableTree(memdb.NewMemDB(), 0) 925 926 tree.Set([]byte("Y"), []byte("MW79JQeV")) 927 tree.Set([]byte("7"), []byte("Kp0ToUJB")) 928 tree.Set([]byte("Z"), []byte("I26B1jPG")) 929 tree.Set([]byte("6"), []byte("ZG0iXq3h")) 930 tree.Set([]byte("2"), []byte("WOR27LdW")) 931 tree.Set([]byte("4"), []byte("MKMvc6cn")) 932 tree.SaveVersion() 933 934 tree.Set([]byte("1"), []byte("208dOu40")) 935 tree.Set([]byte("G"), []byte("7isI9OQH")) 936 tree.Set([]byte("8"), []byte("zMC1YwpH")) 937 tree.SaveVersion() 938 939 tree.Set([]byte("7"), []byte("bn62vWbq")) 940 tree.Set([]byte("5"), []byte("wZuLGDkZ")) 941 tree.SaveVersion() 942 943 tree.DeleteVersion(1) 944 tree.DeleteVersion(2) 945 946 tree.GetVersioned([]byte("Y"), 1) 947 tree.GetVersioned([]byte("7"), 1) 948 tree.GetVersioned([]byte("Z"), 1) 949 tree.GetVersioned([]byte("6"), 1) 950 tree.GetVersioned([]byte("s"), 1) 951 tree.GetVersioned([]byte("2"), 1) 952 tree.GetVersioned([]byte("4"), 1) 953 } 954 955 func TestVersionedCheckpointsSpecialCase7(t *testing.T) { 956 t.Parallel() 957 958 tree := NewMutableTree(memdb.NewMemDB(), 100) 959 960 tree.Set([]byte("n"), []byte("OtqD3nyn")) 961 tree.Set([]byte("W"), []byte("kMdhJjF5")) 962 tree.Set([]byte("A"), []byte("BM3BnrIb")) 963 tree.Set([]byte("I"), []byte("QvtCH970")) 964 tree.Set([]byte("L"), []byte("txKgOTqD")) 965 tree.Set([]byte("Y"), []byte("NAl7PC5L")) 966 tree.SaveVersion() 967 968 tree.Set([]byte("7"), []byte("qWcEAlyX")) 969 tree.SaveVersion() 970 971 tree.Set([]byte("M"), []byte("HdQwzA64")) 972 tree.Set([]byte("3"), []byte("2Naa77fo")) 973 tree.Set([]byte("A"), []byte("SRuwKOTm")) 974 tree.Set([]byte("I"), []byte("oMX4aAOy")) 975 tree.Set([]byte("4"), []byte("dKfvbEOc")) 976 tree.SaveVersion() 977 978 tree.Set([]byte("D"), []byte("3U4QbXCC")) 979 tree.Set([]byte("B"), []byte("FxExhiDq")) 980 tree.SaveVersion() 981 982 tree.Set([]byte("A"), []byte("tWQgbFCY")) 983 tree.SaveVersion() 984 985 tree.DeleteVersion(4) 986 987 tree.GetVersioned([]byte("A"), 3) 988 } 989 990 func TestVersionedTreeEfficiency(t *testing.T) { 991 t.Parallel() 992 993 require := require.New(t) 994 tree := NewMutableTree(memdb.NewMemDB(), 0) 995 versions := 20 996 keysPerVersion := 100 997 keysAddedPerVersion := map[int]int{} 998 999 keysAdded := 0 1000 for i := 1; i <= versions; i++ { 1001 for j := 0; j < keysPerVersion; j++ { 1002 // Keys of size one are likely to be overwritten. 1003 tree.Set([]byte(rnd.Str(1)), []byte(rnd.Str(8))) 1004 } 1005 sizeBefore := len(tree.ndb.nodes()) 1006 tree.SaveVersion() 1007 sizeAfter := len(tree.ndb.nodes()) 1008 change := sizeAfter - sizeBefore 1009 keysAddedPerVersion[i] = change 1010 keysAdded += change 1011 } 1012 1013 keysDeleted := 0 1014 for i := 1; i < versions; i++ { 1015 sizeBefore := len(tree.ndb.nodes()) 1016 tree.DeleteVersion(int64(i)) 1017 sizeAfter := len(tree.ndb.nodes()) 1018 1019 change := sizeBefore - sizeAfter 1020 keysDeleted += change 1021 1022 require.InDelta(change, keysAddedPerVersion[i], float64(keysPerVersion)/5) 1023 } 1024 require.Equal(keysAdded-tree.nodeSize(), keysDeleted) 1025 } 1026 1027 func TestVersionedTreeProofs(t *testing.T) { 1028 t.Parallel() 1029 1030 require := require.New(t) 1031 tree := NewMutableTree(memdb.NewMemDB(), 0) 1032 1033 tree.Set([]byte("k1"), []byte("v1")) 1034 tree.Set([]byte("k2"), []byte("v1")) 1035 tree.Set([]byte("k3"), []byte("v1")) 1036 tree.SaveVersion() 1037 1038 // fmt.Println("TREE VERSION 1") 1039 // printNode(tree.ndb, tree.root, 0) 1040 // fmt.Println("TREE VERSION 1 END") 1041 1042 root1 := tree.Hash() 1043 1044 tree.Set([]byte("k2"), []byte("v2")) 1045 tree.Set([]byte("k4"), []byte("v2")) 1046 tree.SaveVersion() 1047 1048 // fmt.Println("TREE VERSION 2") 1049 // printNode(tree.ndb, tree.root, 0) 1050 // fmt.Println("TREE VERSION END") 1051 1052 root2 := tree.Hash() 1053 require.NotEqual(root1, root2) 1054 1055 tree.Remove([]byte("k2")) 1056 tree.SaveVersion() 1057 1058 // fmt.Println("TREE VERSION 3") 1059 // printNode(tree.ndb, tree.root, 0) 1060 // fmt.Println("TREE VERSION END") 1061 1062 root3 := tree.Hash() 1063 require.NotEqual(root2, root3) 1064 1065 val, proof, err := tree.GetVersionedWithProof([]byte("k2"), 1) 1066 require.NoError(err) 1067 require.EqualValues(val, []byte("v1")) 1068 require.NoError(proof.Verify(root1), proof.String()) 1069 require.NoError(proof.VerifyItem([]byte("k2"), val)) 1070 1071 val, proof, err = tree.GetVersionedWithProof([]byte("k4"), 1) 1072 require.NoError(err) 1073 require.Nil(val) 1074 require.NoError(proof.Verify(root1)) 1075 require.NoError(proof.VerifyAbsence([]byte("k4"))) 1076 1077 val, proof, err = tree.GetVersionedWithProof([]byte("k2"), 2) 1078 require.NoError(err) 1079 require.EqualValues(val, []byte("v2")) 1080 require.NoError(proof.Verify(root2), proof.String()) 1081 require.NoError(proof.VerifyItem([]byte("k2"), val)) 1082 1083 val, proof, err = tree.GetVersionedWithProof([]byte("k1"), 2) 1084 require.NoError(err) 1085 require.EqualValues(val, []byte("v1")) 1086 require.NoError(proof.Verify(root2)) 1087 require.NoError(proof.VerifyItem([]byte("k1"), val)) 1088 1089 val, proof, err = tree.GetVersionedWithProof([]byte("k2"), 3) 1090 1091 require.NoError(err) 1092 require.Nil(val) 1093 require.NoError(proof.Verify(root3)) 1094 require.NoError(proof.VerifyAbsence([]byte("k2"))) 1095 require.Error(proof.Verify(root1)) 1096 require.Error(proof.Verify(root2)) 1097 } 1098 1099 func TestOrphans(t *testing.T) { 1100 t.Parallel() 1101 1102 // If you create a sequence of saved versions 1103 // Then randomly delete versions other than the first and last until only those two remain 1104 // Any remaining orphan nodes should be constrained to just the first version 1105 require := require.New(t) 1106 tree := NewMutableTree(memdb.NewMemDB(), 100) 1107 1108 NUMVERSIONS := 100 1109 NUMUPDATES := 100 1110 1111 for i := 0; i < NUMVERSIONS; i++ { 1112 for j := 1; j < NUMUPDATES; j++ { 1113 tree.Set(randBytes(2), randBytes(2)) 1114 } 1115 _, _, err := tree.SaveVersion() 1116 require.NoError(err, "SaveVersion should not error") 1117 } 1118 1119 idx := rnd.Perm(NUMVERSIONS - 2) 1120 for i := range idx { 1121 err := tree.DeleteVersion(int64(i + 2)) 1122 require.NoError(err, "DeleteVersion should not error") 1123 } 1124 1125 tree.ndb.traverseOrphans(func(k, v []byte) { 1126 var fromVersion, toVersion int64 1127 orphanKeyFormat.Scan(k, &toVersion, &fromVersion) 1128 require.Equal(fromVersion, int64(1), "fromVersion should be 1") 1129 require.Equal(toVersion, int64(1), "toVersion should be 1") 1130 }) 1131 } 1132 1133 func TestVersionedTreeHash(t *testing.T) { 1134 t.Parallel() 1135 1136 require := require.New(t) 1137 tree := NewMutableTree(memdb.NewMemDB(), 0) 1138 1139 require.Nil(tree.Hash()) 1140 tree.Set([]byte("I"), []byte("D")) 1141 require.Nil(tree.Hash()) 1142 1143 hash1, _, _ := tree.SaveVersion() 1144 1145 tree.Set([]byte("I"), []byte("F")) 1146 require.EqualValues(hash1, tree.Hash()) 1147 1148 hash2, _, _ := tree.SaveVersion() 1149 1150 val, proof, err := tree.GetVersionedWithProof([]byte("I"), 2) 1151 require.NoError(err) 1152 require.EqualValues(val, []byte("F")) 1153 require.NoError(proof.Verify(hash2)) 1154 require.NoError(proof.VerifyItem([]byte("I"), val)) 1155 } 1156 1157 func TestNilValueSemantics(t *testing.T) { 1158 t.Parallel() 1159 1160 require := require.New(t) 1161 tree := NewMutableTree(memdb.NewMemDB(), 0) 1162 1163 require.Panics(func() { 1164 tree.Set([]byte("k"), nil) 1165 }) 1166 } 1167 1168 func TestCopyValueSemantics(t *testing.T) { 1169 t.Parallel() 1170 1171 require := require.New(t) 1172 1173 tree := NewMutableTree(memdb.NewMemDB(), 0) 1174 1175 val := []byte("v1") 1176 1177 tree.Set([]byte("k"), val) 1178 _, v := tree.Get([]byte("k")) 1179 require.Equal([]byte("v1"), v) 1180 1181 val[1] = '2' 1182 1183 _, val = tree.Get([]byte("k")) 1184 require.Equal([]byte("v2"), val) 1185 } 1186 1187 func TestRollback(t *testing.T) { 1188 t.Parallel() 1189 1190 require := require.New(t) 1191 1192 tree := NewMutableTree(memdb.NewMemDB(), 0) 1193 1194 tree.Set([]byte("k"), []byte("v")) 1195 tree.SaveVersion() 1196 1197 tree.Set([]byte("r"), []byte("v")) 1198 tree.Set([]byte("s"), []byte("v")) 1199 1200 tree.Rollback() 1201 1202 tree.Set([]byte("t"), []byte("v")) 1203 1204 tree.SaveVersion() 1205 1206 require.Equal(int64(2), tree.Size()) 1207 1208 _, val := tree.Get([]byte("r")) 1209 require.Nil(val) 1210 1211 _, val = tree.Get([]byte("s")) 1212 require.Nil(val) 1213 1214 _, val = tree.Get([]byte("t")) 1215 require.Equal([]byte("v"), val) 1216 } 1217 1218 func TestLazyLoadVersion(t *testing.T) { 1219 t.Parallel() 1220 1221 mdb := memdb.NewMemDB() 1222 tree := NewMutableTree(mdb, 0) 1223 maxVersions := 10 1224 1225 version, err := tree.LazyLoadVersion(0) 1226 require.NoError(t, err, "unexpected error") 1227 require.Equal(t, version, int64(0), "expected latest version to be zero") 1228 1229 for i := 0; i < maxVersions; i++ { 1230 tree.Set([]byte(fmt.Sprintf("key_%d", i+1)), []byte(fmt.Sprintf("value_%d", i+1))) 1231 1232 _, _, err := tree.SaveVersion() 1233 require.NoError(t, err, "SaveVersion should not fail") 1234 } 1235 1236 // require the ability to lazy load the latest version 1237 version, err = tree.LazyLoadVersion(int64(maxVersions)) 1238 require.NoError(t, err, "unexpected error when lazy loading version") 1239 require.Equal(t, version, int64(maxVersions)) 1240 1241 _, value := tree.Get([]byte(fmt.Sprintf("key_%d", maxVersions))) 1242 require.Equal(t, value, []byte(fmt.Sprintf("value_%d", maxVersions)), "unexpected value") 1243 1244 // require the ability to lazy load an older version 1245 version, err = tree.LazyLoadVersion(int64(maxVersions - 1)) 1246 require.NoError(t, err, "unexpected error when lazy loading version") 1247 require.Equal(t, version, int64(maxVersions-1)) 1248 1249 _, value = tree.Get([]byte(fmt.Sprintf("key_%d", maxVersions-1))) 1250 require.Equal(t, value, []byte(fmt.Sprintf("value_%d", maxVersions-1)), "unexpected value") 1251 1252 // require the inability to lazy load a non-valid version 1253 version, err = tree.LazyLoadVersion(int64(maxVersions + 1)) 1254 require.Error(t, err, "expected error when lazy loading version") 1255 require.Equal(t, version, int64(maxVersions)) 1256 } 1257 1258 func TestOverwrite(t *testing.T) { 1259 t.Parallel() 1260 1261 require := require.New(t) 1262 1263 mdb := memdb.NewMemDB() 1264 tree := NewMutableTree(mdb, 0) 1265 1266 // Set one kv pair and save version 1 1267 tree.Set([]byte("key1"), []byte("value1")) 1268 _, _, err := tree.SaveVersion() 1269 require.NoError(err, "SaveVersion should not fail") 1270 1271 // Set another kv pair and save version 2 1272 tree.Set([]byte("key2"), []byte("value2")) 1273 _, _, err = tree.SaveVersion() 1274 require.NoError(err, "SaveVersion should not fail") 1275 1276 // Reload tree at version 1 1277 tree = NewMutableTree(mdb, 0) 1278 _, err = tree.LoadVersion(int64(1)) 1279 require.NoError(err, "LoadVersion should not fail") 1280 1281 // Attempt to put a different kv pair into the tree and save 1282 tree.Set([]byte("key2"), []byte("different value 2")) 1283 _, _, err = tree.SaveVersion() 1284 require.Error(err, "SaveVersion should fail because of changed value") 1285 1286 // Replay the original transition from version 1 to version 2 and attempt to save 1287 tree.Set([]byte("key2"), []byte("value2")) 1288 _, _, err = tree.SaveVersion() 1289 require.NoError(err, "SaveVersion should not fail, overwrite was idempotent") 1290 } 1291 1292 func TestLoadVersionForOverwriting(t *testing.T) { 1293 t.Parallel() 1294 1295 require := require.New(t) 1296 1297 mdb := memdb.NewMemDB() 1298 tree := NewMutableTree(mdb, 0) 1299 1300 maxLength := 100 1301 for count := 1; count <= maxLength; count++ { 1302 countStr := strconv.Itoa(count) 1303 // Set one kv pair and save version 1304 tree.Set([]byte("key"+countStr), []byte("value"+countStr)) 1305 _, _, err := tree.SaveVersion() 1306 require.NoError(err, "SaveVersion should not fail") 1307 } 1308 1309 tree = NewMutableTree(mdb, 0) 1310 targetVersion, _ := tree.LoadVersionForOverwriting(int64(maxLength * 2)) 1311 require.Equal(targetVersion, int64(maxLength), "targetVersion shouldn't larger than the actual tree latest version") 1312 1313 tree = NewMutableTree(mdb, 0) 1314 _, err := tree.LoadVersionForOverwriting(int64(maxLength / 2)) 1315 require.NoError(err, "LoadVersion should not fail") 1316 1317 for version := 1; version <= maxLength/2; version++ { 1318 exist := tree.VersionExists(int64(version)) 1319 require.True(exist, "versions no more than 50 should exist") 1320 } 1321 1322 for version := (maxLength / 2) + 1; version <= maxLength; version++ { 1323 exist := tree.VersionExists(int64(version)) 1324 require.False(exist, "versions more than 50 should have been deleted") 1325 } 1326 1327 tree.Set([]byte("key49"), []byte("value49 different")) 1328 _, _, err = tree.SaveVersion() 1329 require.NoError(err, "SaveVersion should not fail, overwrite was allowed") 1330 1331 tree.Set([]byte("key50"), []byte("value50 different")) 1332 _, _, err = tree.SaveVersion() 1333 require.NoError(err, "SaveVersion should not fail, overwrite was allowed") 1334 1335 // Reload tree at version 50, the latest tree version is 52 1336 tree = NewMutableTree(mdb, 0) 1337 _, err = tree.LoadVersion(int64(maxLength / 2)) 1338 require.NoError(err, "LoadVersion should not fail") 1339 1340 tree.Set([]byte("key49"), []byte("value49 different")) 1341 _, _, err = tree.SaveVersion() 1342 require.NoError(err, "SaveVersion should not fail, write the same value") 1343 1344 tree.Set([]byte("key50"), []byte("value50 different different")) 1345 _, _, err = tree.SaveVersion() 1346 require.Error(err, "SaveVersion should fail, overwrite was not allowed") 1347 1348 tree.Set([]byte("key50"), []byte("value50 different")) 1349 _, _, err = tree.SaveVersion() 1350 require.NoError(err, "SaveVersion should not fail, write the same value") 1351 1352 // The tree version now is 52 which is equal to latest version. 1353 // Now any key value can be written into the tree 1354 tree.Set([]byte("key any value"), []byte("value any value")) 1355 _, _, err = tree.SaveVersion() 1356 require.NoError(err, "SaveVersion should not fail.") 1357 } 1358 1359 // ----------- BENCHMARKS // ----------- 1360 1361 func BenchmarkTreeLoadAndDelete(b *testing.B) { 1362 if testing.Short() { 1363 b.Skip("skipping testing in short mode") 1364 } 1365 1366 numVersions := 5000 1367 numKeysPerVersion := 10 1368 1369 d, err := goleveldb.NewGoLevelDB("bench", ".") 1370 if err != nil { 1371 panic(err) 1372 } 1373 defer d.Close() 1374 defer os.RemoveAll("./bench.db") 1375 1376 tree := NewMutableTree(d, 0) 1377 for v := 1; v < numVersions; v++ { 1378 for i := 0; i < numKeysPerVersion; i++ { 1379 tree.Set([]byte(rnd.Str(16)), rnd.Bytes(32)) 1380 } 1381 tree.SaveVersion() 1382 } 1383 1384 b.Run("LoadAndDelete", func(b *testing.B) { 1385 for n := 0; n < b.N; n++ { 1386 b.StopTimer() 1387 tree = NewMutableTree(d, 0) 1388 runtime.GC() 1389 b.StartTimer() 1390 1391 // Load the tree from disk. 1392 tree.Load() 1393 1394 // Delete about 10% of the versions randomly. 1395 // The trade-off is usually between load efficiency and delete 1396 // efficiency, which is why we do both in this benchmark. 1397 // If we can load quickly into a data-structure that allows for 1398 // efficient deletes, we are golden. 1399 for v := 0; v < numVersions/10; v++ { 1400 version := (rnd.Int() % numVersions) + 1 1401 tree.DeleteVersion(int64(version)) 1402 } 1403 } 1404 }) 1405 } 1406 1407 func zip(av <-chan int64) []int64 { 1408 res := []int64{} 1409 for ver := range av { 1410 res = append(res, ver) 1411 } 1412 return res 1413 }