github.com/MetalBlockchain/metalgo@v1.11.9/database/test_database.go (about) 1 // Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved. 2 // See the file LICENSE for licensing terms. 3 4 package database 5 6 import ( 7 "bytes" 8 "io" 9 "math" 10 "math/rand" 11 "slices" 12 "testing" 13 14 "github.com/stretchr/testify/require" 15 "go.uber.org/mock/gomock" 16 "golang.org/x/exp/maps" 17 "golang.org/x/sync/errgroup" 18 19 "github.com/MetalBlockchain/metalgo/utils" 20 "github.com/MetalBlockchain/metalgo/utils/units" 21 ) 22 23 // Tests is a list of all database tests 24 var Tests = map[string]func(t *testing.T, db Database){ 25 "SimpleKeyValue": TestSimpleKeyValue, 26 "OverwriteKeyValue": TestOverwriteKeyValue, 27 "EmptyKey": TestEmptyKey, 28 "KeyEmptyValue": TestKeyEmptyValue, 29 "SimpleKeyValueClosed": TestSimpleKeyValueClosed, 30 "NewBatchClosed": TestNewBatchClosed, 31 "BatchPut": TestBatchPut, 32 "BatchDelete": TestBatchDelete, 33 "BatchReset": TestBatchReset, 34 "BatchReuse": TestBatchReuse, 35 "BatchRewrite": TestBatchRewrite, 36 "BatchReplay": TestBatchReplay, 37 "BatchReplayPropagateError": TestBatchReplayPropagateError, 38 "BatchInner": TestBatchInner, 39 "BatchLargeSize": TestBatchLargeSize, 40 "IteratorSnapshot": TestIteratorSnapshot, 41 "Iterator": TestIterator, 42 "IteratorStart": TestIteratorStart, 43 "IteratorPrefix": TestIteratorPrefix, 44 "IteratorStartPrefix": TestIteratorStartPrefix, 45 "IteratorMemorySafety": TestIteratorMemorySafety, 46 "IteratorClosed": TestIteratorClosed, 47 "IteratorError": TestIteratorError, 48 "IteratorErrorAfterRelease": TestIteratorErrorAfterRelease, 49 "CompactNoPanic": TestCompactNoPanic, 50 "MemorySafetyDatabase": TestMemorySafetyDatabase, 51 "MemorySafetyBatch": TestMemorySafetyBatch, 52 "AtomicClear": TestAtomicClear, 53 "Clear": TestClear, 54 "AtomicClearPrefix": TestAtomicClearPrefix, 55 "ClearPrefix": TestClearPrefix, 56 "ModifyValueAfterPut": TestModifyValueAfterPut, 57 "ModifyValueAfterBatchPut": TestModifyValueAfterBatchPut, 58 "ModifyValueAfterBatchPutReplay": TestModifyValueAfterBatchPutReplay, 59 "ConcurrentBatches": TestConcurrentBatches, 60 "ManySmallConcurrentKVPairBatches": TestManySmallConcurrentKVPairBatches, 61 "PutGetEmpty": TestPutGetEmpty, 62 } 63 64 // TestSimpleKeyValue tests to make sure that simple Put + Get + Delete + Has 65 // calls return the expected values. 66 func TestSimpleKeyValue(t *testing.T, db Database) { 67 require := require.New(t) 68 69 key := []byte("hello") 70 value := []byte("world") 71 72 has, err := db.Has(key) 73 require.NoError(err) 74 require.False(has) 75 76 _, err = db.Get(key) 77 require.Equal(ErrNotFound, err) 78 79 require.NoError(db.Delete(key)) 80 require.NoError(db.Put(key, value)) 81 82 has, err = db.Has(key) 83 require.NoError(err) 84 require.True(has) 85 86 v, err := db.Get(key) 87 require.NoError(err) 88 require.Equal(value, v) 89 90 require.NoError(db.Delete(key)) 91 92 has, err = db.Has(key) 93 require.NoError(err) 94 require.False(has) 95 96 _, err = db.Get(key) 97 require.Equal(ErrNotFound, err) 98 99 require.NoError(db.Delete(key)) 100 } 101 102 func TestOverwriteKeyValue(t *testing.T, db Database) { 103 require := require.New(t) 104 105 key := []byte("hello") 106 value1 := []byte("world1") 107 value2 := []byte("world2") 108 109 require.NoError(db.Put(key, value1)) 110 111 require.NoError(db.Put(key, value2)) 112 113 gotValue, err := db.Get(key) 114 require.NoError(err) 115 require.Equal(value2, gotValue) 116 } 117 118 func TestKeyEmptyValue(t *testing.T, db Database) { 119 require := require.New(t) 120 121 key := []byte("hello") 122 val := []byte(nil) 123 124 _, err := db.Get(key) 125 require.Equal(ErrNotFound, err) 126 127 require.NoError(db.Put(key, val)) 128 129 value, err := db.Get(key) 130 require.NoError(err) 131 require.Empty(value) 132 } 133 134 func TestEmptyKey(t *testing.T, db Database) { 135 require := require.New(t) 136 137 var ( 138 nilKey = []byte(nil) 139 emptyKey = []byte{} 140 val1 = []byte("hi") 141 val2 = []byte("hello") 142 ) 143 144 // Test that nil key can be retrieved by empty key 145 _, err := db.Get(nilKey) 146 require.Equal(ErrNotFound, err) 147 148 require.NoError(db.Put(nilKey, val1)) 149 150 value, err := db.Get(emptyKey) 151 require.NoError(err) 152 require.Equal(value, val1) 153 154 // Test that empty key can be retrieved by nil key 155 require.NoError(db.Put(emptyKey, val2)) 156 157 value, err = db.Get(nilKey) 158 require.NoError(err) 159 require.Equal(value, val2) 160 } 161 162 // TestSimpleKeyValueClosed tests to make sure that Put + Get + Delete + Has 163 // calls return the correct error when the database has been closed. 164 func TestSimpleKeyValueClosed(t *testing.T, db Database) { 165 require := require.New(t) 166 167 key := []byte("hello") 168 value := []byte("world") 169 170 has, err := db.Has(key) 171 require.NoError(err) 172 require.False(has) 173 174 _, err = db.Get(key) 175 require.Equal(ErrNotFound, err) 176 177 require.NoError(db.Delete(key)) 178 require.NoError(db.Put(key, value)) 179 180 has, err = db.Has(key) 181 require.NoError(err) 182 require.True(has) 183 184 v, err := db.Get(key) 185 require.NoError(err) 186 require.Equal(value, v) 187 188 require.NoError(db.Close()) 189 190 _, err = db.Has(key) 191 require.Equal(ErrClosed, err) 192 193 _, err = db.Get(key) 194 require.Equal(ErrClosed, err) 195 196 require.Equal(ErrClosed, db.Put(key, value)) 197 require.Equal(ErrClosed, db.Delete(key)) 198 require.Equal(ErrClosed, db.Close()) 199 } 200 201 // TestMemorySafetyDatabase ensures it is safe to modify a key after passing it 202 // to Database.Put and Database.Get. 203 func TestMemorySafetyDatabase(t *testing.T, db Database) { 204 require := require.New(t) 205 206 key := []byte("1key") 207 keyCopy := slices.Clone(key) 208 value := []byte("value") 209 key2 := []byte("2key") 210 value2 := []byte("value2") 211 212 // Put both K/V pairs in the database 213 require.NoError(db.Put(key, value)) 214 require.NoError(db.Put(key2, value2)) 215 216 // Get the value for [key] 217 gotVal, err := db.Get(key) 218 require.NoError(err) 219 require.Equal(value, gotVal) 220 221 // Modify [key]; make sure the value we got before hasn't changed 222 key[0] = key2[0] 223 gotVal2, err := db.Get(key) 224 require.NoError(err) 225 require.Equal(value2, gotVal2) 226 require.Equal(value, gotVal) 227 228 // Reset [key] to its original value and make sure it's correct 229 key[0] = keyCopy[0] 230 gotVal, err = db.Get(key) 231 require.NoError(err) 232 require.Equal(value, gotVal) 233 } 234 235 // TestNewBatchClosed tests to make sure that calling NewBatch on a closed 236 // database returns a batch that errors correctly. 237 func TestNewBatchClosed(t *testing.T, db Database) { 238 require := require.New(t) 239 240 require.NoError(db.Close()) 241 242 batch := db.NewBatch() 243 require.NotNil(batch) 244 245 key := []byte("hello") 246 value := []byte("world") 247 248 require.NoError(batch.Put(key, value)) 249 require.Positive(batch.Size()) 250 require.Equal(ErrClosed, batch.Write()) 251 } 252 253 // TestBatchPut tests to make sure that batched writes work as expected. 254 func TestBatchPut(t *testing.T, db Database) { 255 require := require.New(t) 256 257 key := []byte("hello") 258 value := []byte("world") 259 260 batch := db.NewBatch() 261 require.NotNil(batch) 262 263 require.NoError(batch.Put(key, value)) 264 require.Positive(batch.Size()) 265 require.NoError(batch.Write()) 266 267 has, err := db.Has(key) 268 require.NoError(err) 269 require.True(has) 270 271 v, err := db.Get(key) 272 require.NoError(err) 273 require.Equal(value, v) 274 275 require.NoError(db.Delete(key)) 276 277 batch = db.NewBatch() 278 require.NotNil(batch) 279 280 require.NoError(batch.Put(key, value)) 281 require.NoError(db.Close()) 282 require.Equal(ErrClosed, batch.Write()) 283 } 284 285 // TestBatchDelete tests to make sure that batched deletes work as expected. 286 func TestBatchDelete(t *testing.T, db Database) { 287 require := require.New(t) 288 289 key := []byte("hello") 290 value := []byte("world") 291 292 require.NoError(db.Put(key, value)) 293 294 batch := db.NewBatch() 295 require.NotNil(batch) 296 297 require.NoError(batch.Delete(key)) 298 require.NoError(batch.Write()) 299 300 has, err := db.Has(key) 301 require.NoError(err) 302 require.False(has) 303 304 _, err = db.Get(key) 305 require.Equal(ErrNotFound, err) 306 307 require.NoError(db.Delete(key)) 308 } 309 310 // TestMemorySafetyBatch ensures it is safe to modify a key after passing it 311 // to Batch.Put. 312 func TestMemorySafetyBatch(t *testing.T, db Database) { 313 require := require.New(t) 314 315 key := []byte("hello") 316 keyCopy := slices.Clone(key) 317 value := []byte("world") 318 valueCopy := slices.Clone(value) 319 320 batch := db.NewBatch() 321 require.NotNil(batch) 322 323 // Put a key in the batch 324 require.NoError(batch.Put(key, value)) 325 require.Positive(batch.Size()) 326 327 // Modify the key 328 key[0] = 'j' 329 require.NoError(batch.Write()) 330 331 // Make sure the original key was written to the database 332 has, err := db.Has(keyCopy) 333 require.NoError(err) 334 require.True(has) 335 336 v, err := db.Get(keyCopy) 337 require.NoError(err) 338 require.Equal(valueCopy, v) 339 340 // Make sure the new key wasn't written to the database 341 has, err = db.Has(key) 342 require.NoError(err) 343 require.False(has) 344 } 345 346 // TestBatchReset tests to make sure that a batch drops un-written operations 347 // when it is reset. 348 func TestBatchReset(t *testing.T, db Database) { 349 require := require.New(t) 350 351 key := []byte("hello") 352 value := []byte("world") 353 354 require.NoError(db.Put(key, value)) 355 356 batch := db.NewBatch() 357 require.NotNil(batch) 358 359 require.NoError(batch.Delete(key)) 360 361 batch.Reset() 362 363 require.Zero(batch.Size()) 364 require.NoError(batch.Write()) 365 366 has, err := db.Has(key) 367 require.NoError(err) 368 require.True(has) 369 370 v, err := db.Get(key) 371 require.NoError(err) 372 require.Equal(value, v) 373 } 374 375 // TestBatchReuse tests to make sure that a batch can be reused once it is 376 // reset. 377 func TestBatchReuse(t *testing.T, db Database) { 378 require := require.New(t) 379 380 key1 := []byte("hello1") 381 value1 := []byte("world1") 382 383 key2 := []byte("hello2") 384 value2 := []byte("world2") 385 386 batch := db.NewBatch() 387 require.NotNil(batch) 388 389 require.NoError(batch.Put(key1, value1)) 390 require.NoError(batch.Write()) 391 require.NoError(db.Delete(key1)) 392 393 has, err := db.Has(key1) 394 require.NoError(err) 395 require.False(has) 396 397 batch.Reset() 398 399 require.Zero(batch.Size()) 400 require.NoError(batch.Put(key2, value2)) 401 require.NoError(batch.Write()) 402 403 has, err = db.Has(key1) 404 require.NoError(err) 405 require.False(has) 406 407 has, err = db.Has(key2) 408 require.NoError(err) 409 require.True(has) 410 411 v, err := db.Get(key2) 412 require.NoError(err) 413 require.Equal(value2, v) 414 } 415 416 // TestBatchRewrite tests to make sure that write can be called multiple times 417 // on a batch and the values will be updated correctly. 418 func TestBatchRewrite(t *testing.T, db Database) { 419 require := require.New(t) 420 421 key := []byte("hello1") 422 value := []byte("world1") 423 424 batch := db.NewBatch() 425 require.NotNil(batch) 426 427 require.NoError(batch.Put(key, value)) 428 require.NoError(batch.Write()) 429 require.NoError(db.Delete(key)) 430 431 has, err := db.Has(key) 432 require.NoError(err) 433 require.False(has) 434 435 require.NoError(batch.Write()) 436 437 has, err = db.Has(key) 438 require.NoError(err) 439 require.True(has) 440 441 v, err := db.Get(key) 442 require.NoError(err) 443 require.Equal(value, v) 444 } 445 446 // TestBatchReplay tests to make sure that batches will correctly replay their 447 // contents. 448 func TestBatchReplay(t *testing.T, db Database) { 449 ctrl := gomock.NewController(t) 450 require := require.New(t) 451 452 key1 := []byte("hello1") 453 value1 := []byte("world1") 454 455 key2 := []byte("hello2") 456 value2 := []byte("world2") 457 458 batch := db.NewBatch() 459 require.NotNil(batch) 460 461 require.NoError(batch.Put(key1, value1)) 462 require.NoError(batch.Put(key2, value2)) 463 require.NoError(batch.Delete(key1)) 464 require.NoError(batch.Delete(key2)) 465 require.NoError(batch.Put(key1, value2)) 466 467 for i := 0; i < 2; i++ { 468 mockBatch := NewMockBatch(ctrl) 469 gomock.InOrder( 470 mockBatch.EXPECT().Put(key1, value1).Times(1), 471 mockBatch.EXPECT().Put(key2, value2).Times(1), 472 mockBatch.EXPECT().Delete(key1).Times(1), 473 mockBatch.EXPECT().Delete(key2).Times(1), 474 mockBatch.EXPECT().Put(key1, value2).Times(1), 475 ) 476 477 require.NoError(batch.Replay(mockBatch)) 478 } 479 } 480 481 // TestBatchReplayPropagateError tests to make sure that batches will correctly 482 // propagate any returned error during Replay. 483 func TestBatchReplayPropagateError(t *testing.T, db Database) { 484 ctrl := gomock.NewController(t) 485 require := require.New(t) 486 487 key1 := []byte("hello1") 488 value1 := []byte("world1") 489 490 key2 := []byte("hello2") 491 value2 := []byte("world2") 492 493 batch := db.NewBatch() 494 require.NotNil(batch) 495 496 require.NoError(batch.Put(key1, value1)) 497 require.NoError(batch.Put(key2, value2)) 498 499 mockBatch := NewMockBatch(ctrl) 500 gomock.InOrder( 501 mockBatch.EXPECT().Put(key1, value1).Return(ErrClosed).Times(1), 502 ) 503 require.Equal(ErrClosed, batch.Replay(mockBatch)) 504 505 mockBatch = NewMockBatch(ctrl) 506 gomock.InOrder( 507 mockBatch.EXPECT().Put(key1, value1).Return(io.ErrClosedPipe).Times(1), 508 ) 509 require.Equal(io.ErrClosedPipe, batch.Replay(mockBatch)) 510 } 511 512 // TestBatchInner tests to make sure that inner can be used to write to the 513 // database. 514 func TestBatchInner(t *testing.T, db Database) { 515 require := require.New(t) 516 517 key1 := []byte("hello1") 518 value1 := []byte("world1") 519 520 key2 := []byte("hello2") 521 value2 := []byte("world2") 522 523 firstBatch := db.NewBatch() 524 require.NotNil(firstBatch) 525 526 require.NoError(firstBatch.Put(key1, value1)) 527 528 secondBatch := db.NewBatch() 529 require.NotNil(firstBatch) 530 531 require.NoError(secondBatch.Put(key2, value2)) 532 533 innerFirstBatch := firstBatch.Inner() 534 require.NotNil(innerFirstBatch) 535 536 innerSecondBatch := secondBatch.Inner() 537 require.NotNil(innerSecondBatch) 538 539 require.NoError(innerFirstBatch.Replay(innerSecondBatch)) 540 require.NoError(innerSecondBatch.Write()) 541 542 has, err := db.Has(key1) 543 require.NoError(err) 544 require.True(has) 545 546 v, err := db.Get(key1) 547 require.NoError(err) 548 require.Equal(value1, v) 549 550 has, err = db.Has(key2) 551 require.NoError(err) 552 require.True(has) 553 554 v, err = db.Get(key2) 555 require.NoError(err) 556 require.Equal(value2, v) 557 } 558 559 // TestBatchLargeSize tests to make sure that the batch can support a large 560 // amount of entries. 561 func TestBatchLargeSize(t *testing.T, db Database) { 562 require := require.New(t) 563 564 totalSize := 8 * units.MiB 565 elementSize := 4 * units.KiB 566 pairSize := 2 * elementSize // 8 KiB 567 568 bytes := utils.RandomBytes(totalSize) 569 570 batch := db.NewBatch() 571 require.NotNil(batch) 572 573 for len(bytes) > pairSize { 574 key := bytes[:elementSize] 575 bytes = bytes[elementSize:] 576 577 value := bytes[:elementSize] 578 bytes = bytes[elementSize:] 579 580 require.NoError(batch.Put(key, value)) 581 } 582 583 require.NoError(batch.Write()) 584 } 585 586 // TestIteratorSnapshot tests to make sure the database iterates over a snapshot 587 // of the database at the time of the iterator creation. 588 func TestIteratorSnapshot(t *testing.T, db Database) { 589 require := require.New(t) 590 591 key1 := []byte("hello1") 592 value1 := []byte("world1") 593 594 key2 := []byte("hello2") 595 value2 := []byte("world2") 596 597 require.NoError(db.Put(key1, value1)) 598 599 iterator := db.NewIterator() 600 require.NotNil(iterator) 601 602 defer iterator.Release() 603 604 require.NoError(db.Put(key2, value2)) 605 require.True(iterator.Next()) 606 require.Equal(key1, iterator.Key()) 607 require.Equal(value1, iterator.Value()) 608 609 require.False(iterator.Next()) 610 require.Nil(iterator.Key()) 611 require.Nil(iterator.Value()) 612 require.NoError(iterator.Error()) 613 } 614 615 // TestIterator tests to make sure the database iterates over the database 616 // contents lexicographically. 617 func TestIterator(t *testing.T, db Database) { 618 require := require.New(t) 619 620 key1 := []byte("hello1") 621 value1 := []byte("world1") 622 623 key2 := []byte("hello2") 624 value2 := []byte("world2") 625 626 require.NoError(db.Put(key1, value1)) 627 require.NoError(db.Put(key2, value2)) 628 629 iterator := db.NewIterator() 630 require.NotNil(iterator) 631 632 defer iterator.Release() 633 634 require.True(iterator.Next()) 635 require.Equal(key1, iterator.Key()) 636 require.Equal(value1, iterator.Value()) 637 638 require.True(iterator.Next()) 639 require.Equal(key2, iterator.Key()) 640 require.Equal(value2, iterator.Value()) 641 642 require.False(iterator.Next()) 643 require.Nil(iterator.Key()) 644 require.Nil(iterator.Value()) 645 require.NoError(iterator.Error()) 646 } 647 648 // TestIteratorStart tests to make sure the iterator can be configured to 649 // start mid way through the database. 650 func TestIteratorStart(t *testing.T, db Database) { 651 require := require.New(t) 652 653 key1 := []byte("hello1") 654 value1 := []byte("world1") 655 656 key2 := []byte("hello2") 657 value2 := []byte("world2") 658 659 require.NoError(db.Put(key1, value1)) 660 require.NoError(db.Put(key2, value2)) 661 662 iterator := db.NewIteratorWithStart(key2) 663 require.NotNil(iterator) 664 665 defer iterator.Release() 666 667 require.True(iterator.Next()) 668 require.Equal(key2, iterator.Key()) 669 require.Equal(value2, iterator.Value()) 670 671 require.False(iterator.Next()) 672 require.Nil(iterator.Key()) 673 require.Nil(iterator.Value()) 674 require.NoError(iterator.Error()) 675 } 676 677 // TestIteratorPrefix tests to make sure the iterator can be configured to skip 678 // keys missing the provided prefix. 679 func TestIteratorPrefix(t *testing.T, db Database) { 680 require := require.New(t) 681 682 key1 := []byte("hello") 683 value1 := []byte("world1") 684 685 key2 := []byte("goodbye") 686 value2 := []byte("world2") 687 688 key3 := []byte("joy") 689 value3 := []byte("world3") 690 691 require.NoError(db.Put(key1, value1)) 692 require.NoError(db.Put(key2, value2)) 693 require.NoError(db.Put(key3, value3)) 694 695 iterator := db.NewIteratorWithPrefix([]byte("h")) 696 require.NotNil(iterator) 697 698 defer iterator.Release() 699 700 require.True(iterator.Next()) 701 require.Equal(key1, iterator.Key()) 702 require.Equal(value1, iterator.Value()) 703 704 require.False(iterator.Next()) 705 require.Nil(iterator.Key()) 706 require.Nil(iterator.Value()) 707 require.NoError(iterator.Error()) 708 } 709 710 // TestIteratorStartPrefix tests to make sure that the iterator can start mid 711 // way through the database while skipping a prefix. 712 func TestIteratorStartPrefix(t *testing.T, db Database) { 713 require := require.New(t) 714 715 key1 := []byte("hello1") 716 value1 := []byte("world1") 717 718 key2 := []byte("z") 719 value2 := []byte("world2") 720 721 key3 := []byte("hello3") 722 value3 := []byte("world3") 723 724 require.NoError(db.Put(key1, value1)) 725 require.NoError(db.Put(key2, value2)) 726 require.NoError(db.Put(key3, value3)) 727 728 iterator := db.NewIteratorWithStartAndPrefix(key1, []byte("h")) 729 require.NotNil(iterator) 730 731 defer iterator.Release() 732 733 require.True(iterator.Next()) 734 require.Equal(key1, iterator.Key()) 735 require.Equal(value1, iterator.Value()) 736 737 require.True(iterator.Next()) 738 require.Equal(key3, iterator.Key()) 739 require.Equal(value3, iterator.Value()) 740 741 require.False(iterator.Next()) 742 require.Nil(iterator.Key()) 743 require.Nil(iterator.Value()) 744 require.NoError(iterator.Error()) 745 } 746 747 // TestIteratorMemorySafety tests to make sure that keys can values are able to 748 // be modified from the returned iterator. 749 func TestIteratorMemorySafety(t *testing.T, db Database) { 750 require := require.New(t) 751 752 key1 := []byte("hello1") 753 value1 := []byte("world1") 754 755 key2 := []byte("z") 756 value2 := []byte("world2") 757 758 key3 := []byte("hello3") 759 value3 := []byte("world3") 760 761 require.NoError(db.Put(key1, value1)) 762 require.NoError(db.Put(key2, value2)) 763 require.NoError(db.Put(key3, value3)) 764 765 iterator := db.NewIterator() 766 require.NotNil(iterator) 767 768 defer iterator.Release() 769 770 keys := [][]byte{} 771 values := [][]byte{} 772 for iterator.Next() { 773 keys = append(keys, iterator.Key()) 774 values = append(values, iterator.Value()) 775 } 776 777 expectedKeys := [][]byte{ 778 key1, 779 key3, 780 key2, 781 } 782 expectedValues := [][]byte{ 783 value1, 784 value3, 785 value2, 786 } 787 788 for i, key := range keys { 789 value := values[i] 790 expectedKey := expectedKeys[i] 791 expectedValue := expectedValues[i] 792 793 require.Equal(expectedKey, key) 794 require.Equal(expectedValue, value) 795 } 796 } 797 798 // TestIteratorClosed tests to make sure that an iterator that was created with 799 // a closed database will report a closed error correctly. 800 func TestIteratorClosed(t *testing.T, db Database) { 801 require := require.New(t) 802 803 key1 := []byte("hello1") 804 value1 := []byte("world1") 805 806 require.NoError(db.Put(key1, value1)) 807 require.NoError(db.Close()) 808 809 { 810 iterator := db.NewIterator() 811 require.NotNil(iterator) 812 813 defer iterator.Release() 814 815 require.False(iterator.Next()) 816 require.Nil(iterator.Key()) 817 require.Nil(iterator.Value()) 818 require.Equal(ErrClosed, iterator.Error()) 819 } 820 821 { 822 iterator := db.NewIteratorWithPrefix(nil) 823 require.NotNil(iterator) 824 825 defer iterator.Release() 826 827 require.False(iterator.Next()) 828 require.Nil(iterator.Key()) 829 require.Nil(iterator.Value()) 830 require.Equal(ErrClosed, iterator.Error()) 831 } 832 833 { 834 iterator := db.NewIteratorWithStart(nil) 835 require.NotNil(iterator) 836 837 defer iterator.Release() 838 839 require.False(iterator.Next()) 840 require.Nil(iterator.Key()) 841 require.Nil(iterator.Value()) 842 require.Equal(ErrClosed, iterator.Error()) 843 } 844 845 { 846 iterator := db.NewIteratorWithStartAndPrefix(nil, nil) 847 require.NotNil(iterator) 848 849 defer iterator.Release() 850 851 require.False(iterator.Next()) 852 require.Nil(iterator.Key()) 853 require.Nil(iterator.Value()) 854 require.Equal(ErrClosed, iterator.Error()) 855 } 856 } 857 858 // TestIteratorError tests to make sure that an iterator on a database will report 859 // itself as being exhausted and return [ErrClosed] to indicate that the iteration 860 // was not successful. 861 // Additionally tests that an iterator that has already called Next() can still serve 862 // its current value after the underlying DB was closed. 863 func TestIteratorError(t *testing.T, db Database) { 864 require := require.New(t) 865 866 key1 := []byte("hello1") 867 value1 := []byte("world1") 868 869 key2 := []byte("hello2") 870 value2 := []byte("world2") 871 872 require.NoError(db.Put(key1, value1)) 873 require.NoError(db.Put(key2, value2)) 874 875 iterator := db.NewIterator() 876 require.NotNil(iterator) 877 878 defer iterator.Release() 879 880 // Call Next() and ensure that if the database is closed, the iterator 881 // can still report the current contents. 882 require.True(iterator.Next()) 883 require.NoError(db.Close()) 884 require.Equal(key1, iterator.Key()) 885 require.Equal(value1, iterator.Value()) 886 887 // Subsequent calls to the iterator should return false and report an error 888 require.False(iterator.Next()) 889 require.Nil(iterator.Key()) 890 require.Nil(iterator.Value()) 891 require.Equal(ErrClosed, iterator.Error()) 892 } 893 894 // TestIteratorErrorAfterRelease tests to make sure that an iterator that was 895 // released still reports the error correctly. 896 func TestIteratorErrorAfterRelease(t *testing.T, db Database) { 897 require := require.New(t) 898 899 key := []byte("hello1") 900 value := []byte("world1") 901 902 require.NoError(db.Put(key, value)) 903 require.NoError(db.Close()) 904 905 iterator := db.NewIterator() 906 require.NotNil(iterator) 907 908 iterator.Release() 909 910 require.False(iterator.Next()) 911 require.Nil(iterator.Key()) 912 require.Nil(iterator.Value()) 913 require.Equal(ErrClosed, iterator.Error()) 914 } 915 916 // TestCompactNoPanic tests to make sure compact never panics. 917 func TestCompactNoPanic(t *testing.T, db Database) { 918 require := require.New(t) 919 920 key1 := []byte("hello1") 921 value1 := []byte("world1") 922 923 key2 := []byte("z") 924 value2 := []byte("world2") 925 926 key3 := []byte("hello3") 927 value3 := []byte("world3") 928 929 require.NoError(db.Put(key1, value1)) 930 require.NoError(db.Put(key2, value2)) 931 require.NoError(db.Put(key3, value3)) 932 933 // Test compacting with nil bounds 934 require.NoError(db.Compact(nil, nil)) 935 936 // Test compacting when start > end 937 require.NoError(db.Compact([]byte{2}, []byte{1})) 938 939 // Test compacting when start > largest key 940 require.NoError(db.Compact([]byte{255}, nil)) 941 942 require.NoError(db.Close()) 943 err := db.Compact(nil, nil) 944 require.ErrorIs(err, ErrClosed) 945 } 946 947 func TestAtomicClear(t *testing.T, db Database) { 948 testClear(t, db, func(db Database) error { 949 return AtomicClear(db, db) 950 }) 951 } 952 953 func TestClear(t *testing.T, db Database) { 954 testClear(t, db, func(db Database) error { 955 return Clear(db, math.MaxInt) 956 }) 957 } 958 959 // testClear tests to make sure the deletion helper works as expected. 960 func testClear(t *testing.T, db Database, clearF func(Database) error) { 961 require := require.New(t) 962 963 key1 := []byte("hello1") 964 value1 := []byte("world1") 965 966 key2 := []byte("z") 967 value2 := []byte("world2") 968 969 key3 := []byte("hello3") 970 value3 := []byte("world3") 971 972 require.NoError(db.Put(key1, value1)) 973 require.NoError(db.Put(key2, value2)) 974 require.NoError(db.Put(key3, value3)) 975 976 count, err := Count(db) 977 require.NoError(err) 978 require.Equal(3, count) 979 980 require.NoError(clearF(db)) 981 982 count, err = Count(db) 983 require.NoError(err) 984 require.Zero(count) 985 986 require.NoError(db.Close()) 987 } 988 989 func TestAtomicClearPrefix(t *testing.T, db Database) { 990 testClearPrefix(t, db, func(db Database, prefix []byte) error { 991 return AtomicClearPrefix(db, db, prefix) 992 }) 993 } 994 995 func TestClearPrefix(t *testing.T, db Database) { 996 testClearPrefix(t, db, func(db Database, prefix []byte) error { 997 return ClearPrefix(db, prefix, math.MaxInt) 998 }) 999 } 1000 1001 // testClearPrefix tests to make sure prefix deletion works as expected. 1002 func testClearPrefix(t *testing.T, db Database, clearF func(Database, []byte) error) { 1003 require := require.New(t) 1004 1005 key1 := []byte("hello1") 1006 value1 := []byte("world1") 1007 1008 key2 := []byte("z") 1009 value2 := []byte("world2") 1010 1011 key3 := []byte("hello3") 1012 value3 := []byte("world3") 1013 1014 require.NoError(db.Put(key1, value1)) 1015 require.NoError(db.Put(key2, value2)) 1016 require.NoError(db.Put(key3, value3)) 1017 1018 count, err := Count(db) 1019 require.NoError(err) 1020 require.Equal(3, count) 1021 1022 require.NoError(clearF(db, []byte("hello"))) 1023 1024 count, err = Count(db) 1025 require.NoError(err) 1026 require.Equal(1, count) 1027 1028 has, err := db.Has(key1) 1029 require.NoError(err) 1030 require.False(has) 1031 1032 has, err = db.Has(key2) 1033 require.NoError(err) 1034 require.True(has) 1035 1036 has, err = db.Has(key3) 1037 require.NoError(err) 1038 require.False(has) 1039 1040 require.NoError(db.Close()) 1041 } 1042 1043 func TestModifyValueAfterPut(t *testing.T, db Database) { 1044 require := require.New(t) 1045 1046 key := []byte{1} 1047 value := []byte{1, 2} 1048 originalValue := slices.Clone(value) 1049 1050 require.NoError(db.Put(key, value)) 1051 1052 // Modify the value that was Put into the database 1053 // to see if the database copied the value correctly. 1054 value[0] = 2 1055 retrievedValue, err := db.Get(key) 1056 require.NoError(err) 1057 require.Equal(originalValue, retrievedValue) 1058 } 1059 1060 func TestModifyValueAfterBatchPut(t *testing.T, db Database) { 1061 require := require.New(t) 1062 1063 key := []byte{1} 1064 value := []byte{1, 2} 1065 originalValue := slices.Clone(value) 1066 1067 batch := db.NewBatch() 1068 require.NoError(batch.Put(key, value)) 1069 1070 // Modify the value that was Put into the Batch and then Write the 1071 // batch to the database. 1072 value[0] = 2 1073 require.NoError(batch.Write()) 1074 1075 // Verify that the value written to the database contains matches the original 1076 // value of the byte slice when Put was called. 1077 retrievedValue, err := db.Get(key) 1078 require.NoError(err) 1079 require.Equal(originalValue, retrievedValue) 1080 } 1081 1082 func TestModifyValueAfterBatchPutReplay(t *testing.T, db Database) { 1083 require := require.New(t) 1084 1085 key := []byte{1} 1086 value := []byte{1, 2} 1087 originalValue := slices.Clone(value) 1088 1089 batch := db.NewBatch() 1090 require.NoError(batch.Put(key, value)) 1091 1092 // Modify the value that was Put into the Batch and then Write the 1093 // batch to the database. 1094 value[0] = 2 1095 1096 // Create a new batch and replay the batch onto this one before writing it to the DB. 1097 replayBatch := db.NewBatch() 1098 require.NoError(batch.Replay(replayBatch)) 1099 require.NoError(replayBatch.Write()) 1100 1101 // Verify that the value written to the database contains matches the original 1102 // value of the byte slice when Put was called. 1103 retrievedValue, err := db.Get(key) 1104 require.NoError(err) 1105 require.Equal(originalValue, retrievedValue) 1106 } 1107 1108 func TestConcurrentBatches(t *testing.T, db Database) { 1109 numBatches := 10 1110 keysPerBatch := 50 1111 keySize := 32 1112 valueSize := units.KiB 1113 1114 require.NoError(t, runConcurrentBatches( 1115 db, 1116 numBatches, 1117 keysPerBatch, 1118 keySize, 1119 valueSize, 1120 )) 1121 } 1122 1123 func TestManySmallConcurrentKVPairBatches(t *testing.T, db Database) { 1124 numBatches := 100 1125 keysPerBatch := 10 1126 keySize := 10 1127 valueSize := 10 1128 1129 require.NoError(t, runConcurrentBatches( 1130 db, 1131 numBatches, 1132 keysPerBatch, 1133 keySize, 1134 valueSize, 1135 )) 1136 } 1137 1138 func runConcurrentBatches( 1139 db Database, 1140 numBatches, 1141 keysPerBatch, 1142 keySize, 1143 valueSize int, 1144 ) error { 1145 batches := make([]Batch, 0, numBatches) 1146 for i := 0; i < numBatches; i++ { 1147 batches = append(batches, db.NewBatch()) 1148 } 1149 1150 for _, batch := range batches { 1151 for i := 0; i < keysPerBatch; i++ { 1152 key := utils.RandomBytes(keySize) 1153 value := utils.RandomBytes(valueSize) 1154 if err := batch.Put(key, value); err != nil { 1155 return err 1156 } 1157 } 1158 } 1159 1160 var eg errgroup.Group 1161 for _, batch := range batches { 1162 eg.Go(batch.Write) 1163 } 1164 return eg.Wait() 1165 } 1166 1167 func TestPutGetEmpty(t *testing.T, db Database) { 1168 require := require.New(t) 1169 1170 key := []byte("hello") 1171 1172 require.NoError(db.Put(key, nil)) 1173 1174 value, err := db.Get(key) 1175 require.NoError(err) 1176 require.Empty(value) // May be nil or empty byte slice. 1177 1178 require.NoError(db.Put(key, []byte{})) 1179 1180 value, err = db.Get(key) 1181 require.NoError(err) 1182 require.Empty(value) // May be nil or empty byte slice. 1183 } 1184 1185 func FuzzKeyValue(f *testing.F, db Database) { 1186 f.Fuzz(func(t *testing.T, key []byte, value []byte) { 1187 require := require.New(t) 1188 1189 require.NoError(db.Put(key, value)) 1190 1191 exists, err := db.Has(key) 1192 require.NoError(err) 1193 require.True(exists) 1194 1195 gotVal, err := db.Get(key) 1196 require.NoError(err) 1197 require.True(bytes.Equal(value, gotVal)) 1198 1199 require.NoError(db.Delete(key)) 1200 1201 exists, err = db.Has(key) 1202 require.NoError(err) 1203 require.False(exists) 1204 1205 _, err = db.Get(key) 1206 require.Equal(ErrNotFound, err) 1207 }) 1208 } 1209 1210 func FuzzNewIteratorWithPrefix(f *testing.F, db Database) { 1211 const ( 1212 maxKeyLen = 32 1213 maxValueLen = 32 1214 ) 1215 1216 f.Fuzz(func( 1217 t *testing.T, 1218 randSeed int64, 1219 prefix []byte, 1220 numKeyValues uint, 1221 ) { 1222 require := require.New(t) 1223 r := rand.New(rand.NewSource(randSeed)) // #nosec G404 1224 1225 // Put a bunch of key-values 1226 expected := map[string][]byte{} 1227 for i := 0; i < int(numKeyValues); i++ { 1228 key := make([]byte, r.Intn(maxKeyLen)) 1229 _, _ = r.Read(key) // #nosec G404 1230 1231 value := make([]byte, r.Intn(maxValueLen)) 1232 _, _ = r.Read(value) // #nosec G404 1233 1234 if len(value) == 0 { 1235 // Consistently treat zero length values as nil 1236 // so that we can compare [expected] and [got] with 1237 // require.Equal, which treats nil and empty byte 1238 // as being unequal, whereas the database treats 1239 // them as being equal. 1240 value = nil 1241 } 1242 1243 if bytes.HasPrefix(key, prefix) { 1244 expected[string(key)] = value 1245 } 1246 1247 require.NoError(db.Put(key, value)) 1248 } 1249 expectedList := maps.Keys(expected) 1250 slices.Sort(expectedList) 1251 1252 iter := db.NewIteratorWithPrefix(prefix) 1253 defer iter.Release() 1254 1255 // Assert the iterator returns the expected key-values. 1256 numIterElts := 0 1257 for iter.Next() { 1258 val := iter.Value() 1259 if len(val) == 0 { 1260 val = nil 1261 } 1262 require.Equal(expectedList[numIterElts], string(iter.Key())) 1263 require.Equal(expected[string(iter.Key())], val) 1264 numIterElts++ 1265 } 1266 require.Len(expectedList, numIterElts) 1267 1268 // Clear the database for the next fuzz iteration. 1269 require.NoError(AtomicClear(db, db)) 1270 }) 1271 } 1272 1273 func FuzzNewIteratorWithStartAndPrefix(f *testing.F, db Database) { 1274 const ( 1275 maxKeyLen = 32 1276 maxValueLen = 32 1277 ) 1278 1279 f.Fuzz(func( 1280 t *testing.T, 1281 randSeed int64, 1282 start []byte, 1283 prefix []byte, 1284 numKeyValues uint, 1285 ) { 1286 require := require.New(t) 1287 r := rand.New(rand.NewSource(randSeed)) // #nosec G404 1288 1289 expected := map[string][]byte{} 1290 1291 // Put a bunch of key-values 1292 for i := 0; i < int(numKeyValues); i++ { 1293 key := make([]byte, r.Intn(maxKeyLen)) 1294 _, _ = r.Read(key) // #nosec G404 1295 1296 value := make([]byte, r.Intn(maxValueLen)) 1297 _, _ = r.Read(value) // #nosec G404 1298 1299 if len(value) == 0 { 1300 // Consistently treat zero length values as nil 1301 // so that we can compare [expected] and [got] with 1302 // require.Equal, which treats nil and empty byte 1303 // as being unequal, whereas the database treats 1304 // them as being equal. 1305 value = nil 1306 } 1307 1308 if bytes.HasPrefix(key, prefix) && bytes.Compare(key, start) >= 0 { 1309 expected[string(key)] = value 1310 } 1311 1312 require.NoError(db.Put(key, value)) 1313 } 1314 1315 expectedList := maps.Keys(expected) 1316 slices.Sort(expectedList) 1317 1318 iter := db.NewIteratorWithStartAndPrefix(start, prefix) 1319 defer iter.Release() 1320 1321 // Assert the iterator returns the expected key-values. 1322 numIterElts := 0 1323 for iter.Next() { 1324 val := iter.Value() 1325 if len(val) == 0 { 1326 val = nil 1327 } 1328 keyStr := string(iter.Key()) 1329 require.Equal(expectedList[numIterElts], keyStr) 1330 require.Equal(expected[keyStr], val) 1331 numIterElts++ 1332 } 1333 require.Len(expectedList, numIterElts) 1334 1335 // Clear the database for the next fuzz iteration. 1336 require.NoError(AtomicClear(db, db)) 1337 }) 1338 }