github.com/zuoyebang/bitalosdb@v1.1.1-0.20240516111551-79a8c4d8ce20/bitree/bdb/cursor_test.go (about) 1 // Copyright 2021 The Bitalosdb author(hustxrb@163.com) and other contributors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package bdb_test 16 17 import ( 18 "bytes" 19 "encoding/binary" 20 "fmt" 21 "log" 22 "os" 23 "reflect" 24 "sort" 25 "testing" 26 "testing/quick" 27 28 "github.com/zuoyebang/bitalosdb/bitree/bdb" 29 ) 30 31 func TestCursor_Bucket(t *testing.T) { 32 db := MustOpenDB() 33 defer db.MustClose() 34 if err := db.Update(func(tx *bdb.Tx) error { 35 b, err := tx.CreateBucket([]byte("widgets")) 36 if err != nil { 37 t.Fatal(err) 38 } 39 if cb := b.Cursor().Bucket(); !reflect.DeepEqual(cb, b) { 40 t.Fatal("cursor bucket mismatch") 41 } 42 return nil 43 }); err != nil { 44 t.Fatal(err) 45 } 46 } 47 48 func TestCursor_Seek(t *testing.T) { 49 db := MustOpenDB() 50 defer db.MustClose() 51 if err := db.Update(func(tx *bdb.Tx) error { 52 b, err := tx.CreateBucket([]byte("widgets")) 53 if err != nil { 54 t.Fatal(err) 55 } 56 if err := b.Put([]byte("foo"), []byte("0001")); err != nil { 57 t.Fatal(err) 58 } 59 if err := b.Put([]byte("bar"), []byte("0002")); err != nil { 60 t.Fatal(err) 61 } 62 if err := b.Put([]byte("baz"), []byte("0003")); err != nil { 63 t.Fatal(err) 64 } 65 66 if _, err := b.CreateBucket([]byte("bkt")); err != nil { 67 t.Fatal(err) 68 } 69 return nil 70 }); err != nil { 71 t.Fatal(err) 72 } 73 74 if err := db.View(func(tx *bdb.Tx) error { 75 c := tx.Bucket([]byte("widgets")).Cursor() 76 77 if k, v := c.Seek([]byte("bar")); !bytes.Equal(k, []byte("bar")) { 78 t.Fatalf("unexpected key: %v", k) 79 } else if !bytes.Equal(v, []byte("0002")) { 80 t.Fatalf("unexpected value: %v", v) 81 } 82 83 if k, v := c.Seek([]byte("bas")); !bytes.Equal(k, []byte("baz")) { 84 t.Fatalf("unexpected key: %v", k) 85 } else if !bytes.Equal(v, []byte("0003")) { 86 t.Fatalf("unexpected value: %v", v) 87 } 88 89 if k, v := c.Seek([]byte("")); !bytes.Equal(k, []byte("bar")) { 90 t.Fatalf("unexpected key: %v", k) 91 } else if !bytes.Equal(v, []byte("0002")) { 92 t.Fatalf("unexpected value: %v", v) 93 } 94 95 if k, v := c.Seek([]byte("zzz")); k != nil { 96 t.Fatalf("expected nil key: %v", k) 97 } else if v != nil { 98 t.Fatalf("expected nil value: %v", v) 99 } 100 101 if k, v := c.Seek([]byte("bkt")); !bytes.Equal(k, []byte("bkt")) { 102 t.Fatalf("unexpected key: %v", k) 103 } else if v != nil { 104 t.Fatalf("expected nil value: %v", v) 105 } 106 107 return nil 108 }); err != nil { 109 t.Fatal(err) 110 } 111 } 112 113 func TestCursor_Delete(t *testing.T) { 114 db := MustOpenDB() 115 defer db.MustClose() 116 117 const count = 1000 118 119 if err := db.Update(func(tx *bdb.Tx) error { 120 b, err := tx.CreateBucket([]byte("widgets")) 121 if err != nil { 122 t.Fatal(err) 123 } 124 for i := 0; i < count; i += 1 { 125 k := make([]byte, 8) 126 binary.BigEndian.PutUint64(k, uint64(i)) 127 if err := b.Put(k, make([]byte, 100)); err != nil { 128 t.Fatal(err) 129 } 130 } 131 if _, err := b.CreateBucket([]byte("sub")); err != nil { 132 t.Fatal(err) 133 } 134 return nil 135 }); err != nil { 136 t.Fatal(err) 137 } 138 139 if err := db.Update(func(tx *bdb.Tx) error { 140 c := tx.Bucket([]byte("widgets")).Cursor() 141 bound := make([]byte, 8) 142 binary.BigEndian.PutUint64(bound, uint64(count/2)) 143 for key, _ := c.First(); bytes.Compare(key, bound) < 0; key, _ = c.Next() { 144 if err := c.Delete(); err != nil { 145 t.Fatal(err) 146 } 147 } 148 149 c.Seek([]byte("sub")) 150 if err := c.Delete(); err != bdb.ErrIncompatibleValue { 151 t.Fatalf("unexpected error: %s", err) 152 } 153 154 return nil 155 }); err != nil { 156 t.Fatal(err) 157 } 158 159 if err := db.View(func(tx *bdb.Tx) error { 160 stats := tx.Bucket([]byte("widgets")).Stats() 161 if stats.KeyN != count/2+1 { 162 t.Fatalf("unexpected KeyN: %d", stats.KeyN) 163 } 164 return nil 165 }); err != nil { 166 t.Fatal(err) 167 } 168 } 169 170 func TestCursor_Seek_Large(t *testing.T) { 171 db := MustOpenDB() 172 defer db.MustClose() 173 174 var count = 10000 175 176 if err := db.Update(func(tx *bdb.Tx) error { 177 b, err := tx.CreateBucket([]byte("widgets")) 178 if err != nil { 179 t.Fatal(err) 180 } 181 182 for i := 0; i < count; i += 100 { 183 for j := i; j < i+100; j += 2 { 184 k := make([]byte, 8) 185 binary.BigEndian.PutUint64(k, uint64(j)) 186 if err := b.Put(k, make([]byte, 100)); err != nil { 187 t.Fatal(err) 188 } 189 } 190 } 191 return nil 192 }); err != nil { 193 t.Fatal(err) 194 } 195 196 if err := db.View(func(tx *bdb.Tx) error { 197 c := tx.Bucket([]byte("widgets")).Cursor() 198 for i := 0; i < count; i++ { 199 seek := make([]byte, 8) 200 binary.BigEndian.PutUint64(seek, uint64(i)) 201 202 k, _ := c.Seek(seek) 203 204 if i == count-1 { 205 if k != nil { 206 t.Fatal("expected nil key") 207 } 208 continue 209 } 210 211 num := binary.BigEndian.Uint64(k) 212 if i%2 == 0 { 213 if num != uint64(i) { 214 t.Fatalf("unexpected num: %d", num) 215 } 216 } else { 217 if num != uint64(i+1) { 218 t.Fatalf("unexpected num: %d", num) 219 } 220 } 221 } 222 223 return nil 224 }); err != nil { 225 t.Fatal(err) 226 } 227 } 228 229 func TestCursor_EmptyBucket(t *testing.T) { 230 db := MustOpenDB() 231 defer db.MustClose() 232 if err := db.Update(func(tx *bdb.Tx) error { 233 _, err := tx.CreateBucket([]byte("widgets")) 234 return err 235 }); err != nil { 236 t.Fatal(err) 237 } 238 239 if err := db.View(func(tx *bdb.Tx) error { 240 c := tx.Bucket([]byte("widgets")).Cursor() 241 k, v := c.First() 242 if k != nil { 243 t.Fatalf("unexpected key: %v", k) 244 } else if v != nil { 245 t.Fatalf("unexpected value: %v", v) 246 } 247 return nil 248 }); err != nil { 249 t.Fatal(err) 250 } 251 } 252 253 func TestCursor_EmptyBucketReverse(t *testing.T) { 254 db := MustOpenDB() 255 defer db.MustClose() 256 257 if err := db.Update(func(tx *bdb.Tx) error { 258 _, err := tx.CreateBucket([]byte("widgets")) 259 return err 260 }); err != nil { 261 t.Fatal(err) 262 } 263 if err := db.View(func(tx *bdb.Tx) error { 264 c := tx.Bucket([]byte("widgets")).Cursor() 265 k, v := c.Last() 266 if k != nil { 267 t.Fatalf("unexpected key: %v", k) 268 } else if v != nil { 269 t.Fatalf("unexpected value: %v", v) 270 } 271 return nil 272 }); err != nil { 273 t.Fatal(err) 274 } 275 } 276 277 func TestCursor_Iterate_Leaf(t *testing.T) { 278 db := MustOpenDB() 279 defer db.MustClose() 280 281 if err := db.Update(func(tx *bdb.Tx) error { 282 b, err := tx.CreateBucket([]byte("widgets")) 283 if err != nil { 284 t.Fatal(err) 285 } 286 if err := b.Put([]byte("baz"), []byte{}); err != nil { 287 t.Fatal(err) 288 } 289 if err := b.Put([]byte("foo"), []byte{0}); err != nil { 290 t.Fatal(err) 291 } 292 if err := b.Put([]byte("bar"), []byte{1}); err != nil { 293 t.Fatal(err) 294 } 295 return nil 296 }); err != nil { 297 t.Fatal(err) 298 } 299 tx, err := db.Begin(false) 300 if err != nil { 301 t.Fatal(err) 302 } 303 defer func() { _ = tx.Rollback() }() 304 305 c := tx.Bucket([]byte("widgets")).Cursor() 306 307 k, v := c.First() 308 if !bytes.Equal(k, []byte("bar")) { 309 t.Fatalf("unexpected key: %v", k) 310 } else if !bytes.Equal(v, []byte{1}) { 311 t.Fatalf("unexpected value: %v", v) 312 } 313 314 k, v = c.Next() 315 if !bytes.Equal(k, []byte("baz")) { 316 t.Fatalf("unexpected key: %v", k) 317 } else if !bytes.Equal(v, []byte{}) { 318 t.Fatalf("unexpected value: %v", v) 319 } 320 321 k, v = c.Next() 322 if !bytes.Equal(k, []byte("foo")) { 323 t.Fatalf("unexpected key: %v", k) 324 } else if !bytes.Equal(v, []byte{0}) { 325 t.Fatalf("unexpected value: %v", v) 326 } 327 328 k, v = c.Next() 329 if k != nil { 330 t.Fatalf("expected nil key: %v", k) 331 } else if v != nil { 332 t.Fatalf("expected nil value: %v", v) 333 } 334 335 k, v = c.Next() 336 if k != nil { 337 t.Fatalf("expected nil key: %v", k) 338 } else if v != nil { 339 t.Fatalf("expected nil value: %v", v) 340 } 341 342 if err := tx.Rollback(); err != nil { 343 t.Fatal(err) 344 } 345 } 346 347 func TestCursor_LeafRootReverse(t *testing.T) { 348 db := MustOpenDB() 349 defer db.MustClose() 350 351 if err := db.Update(func(tx *bdb.Tx) error { 352 b, err := tx.CreateBucket([]byte("widgets")) 353 if err != nil { 354 t.Fatal(err) 355 } 356 if err := b.Put([]byte("baz"), []byte{}); err != nil { 357 t.Fatal(err) 358 } 359 if err := b.Put([]byte("foo"), []byte{0}); err != nil { 360 t.Fatal(err) 361 } 362 if err := b.Put([]byte("bar"), []byte{1}); err != nil { 363 t.Fatal(err) 364 } 365 return nil 366 }); err != nil { 367 t.Fatal(err) 368 } 369 tx, err := db.Begin(false) 370 if err != nil { 371 t.Fatal(err) 372 } 373 c := tx.Bucket([]byte("widgets")).Cursor() 374 375 if k, v := c.Last(); !bytes.Equal(k, []byte("foo")) { 376 t.Fatalf("unexpected key: %v", k) 377 } else if !bytes.Equal(v, []byte{0}) { 378 t.Fatalf("unexpected value: %v", v) 379 } 380 381 if k, v := c.Prev(); !bytes.Equal(k, []byte("baz")) { 382 t.Fatalf("unexpected key: %v", k) 383 } else if !bytes.Equal(v, []byte{}) { 384 t.Fatalf("unexpected value: %v", v) 385 } 386 387 if k, v := c.Prev(); !bytes.Equal(k, []byte("bar")) { 388 t.Fatalf("unexpected key: %v", k) 389 } else if !bytes.Equal(v, []byte{1}) { 390 t.Fatalf("unexpected value: %v", v) 391 } 392 393 if k, v := c.Prev(); k != nil { 394 t.Fatalf("expected nil key: %v", k) 395 } else if v != nil { 396 t.Fatalf("expected nil value: %v", v) 397 } 398 399 if k, v := c.Prev(); k != nil { 400 t.Fatalf("expected nil key: %v", k) 401 } else if v != nil { 402 t.Fatalf("expected nil value: %v", v) 403 } 404 405 if err := tx.Rollback(); err != nil { 406 t.Fatal(err) 407 } 408 } 409 410 func TestCursor_Restart(t *testing.T) { 411 db := MustOpenDB() 412 defer db.MustClose() 413 414 if err := db.Update(func(tx *bdb.Tx) error { 415 b, err := tx.CreateBucket([]byte("widgets")) 416 if err != nil { 417 t.Fatal(err) 418 } 419 if err := b.Put([]byte("bar"), []byte{}); err != nil { 420 t.Fatal(err) 421 } 422 if err := b.Put([]byte("foo"), []byte{}); err != nil { 423 t.Fatal(err) 424 } 425 return nil 426 }); err != nil { 427 t.Fatal(err) 428 } 429 430 tx, err := db.Begin(false) 431 if err != nil { 432 t.Fatal(err) 433 } 434 c := tx.Bucket([]byte("widgets")).Cursor() 435 436 if k, _ := c.First(); !bytes.Equal(k, []byte("bar")) { 437 t.Fatalf("unexpected key: %v", k) 438 } 439 if k, _ := c.Next(); !bytes.Equal(k, []byte("foo")) { 440 t.Fatalf("unexpected key: %v", k) 441 } 442 443 if k, _ := c.First(); !bytes.Equal(k, []byte("bar")) { 444 t.Fatalf("unexpected key: %v", k) 445 } 446 if k, _ := c.Next(); !bytes.Equal(k, []byte("foo")) { 447 t.Fatalf("unexpected key: %v", k) 448 } 449 450 if err := tx.Rollback(); err != nil { 451 t.Fatal(err) 452 } 453 } 454 455 func TestCursor_First_EmptyPages(t *testing.T) { 456 db := MustOpenDB() 457 defer db.MustClose() 458 459 if err := db.Update(func(tx *bdb.Tx) error { 460 b, err := tx.CreateBucket([]byte("widgets")) 461 if err != nil { 462 t.Fatal(err) 463 } 464 465 for i := 0; i < 1000; i++ { 466 if err := b.Put(u64tob(uint64(i)), []byte{}); err != nil { 467 t.Fatal(err) 468 } 469 } 470 471 return nil 472 }); err != nil { 473 t.Fatal(err) 474 } 475 476 if err := db.Update(func(tx *bdb.Tx) error { 477 b := tx.Bucket([]byte("widgets")) 478 for i := 0; i < 600; i++ { 479 if err := b.Delete(u64tob(uint64(i))); err != nil { 480 t.Fatal(err) 481 } 482 } 483 484 c := b.Cursor() 485 var n int 486 for k, _ := c.First(); k != nil; k, _ = c.Next() { 487 n++ 488 } 489 if n != 400 { 490 t.Fatalf("unexpected key count: %d", n) 491 } 492 493 return nil 494 }); err != nil { 495 t.Fatal(err) 496 } 497 } 498 499 func TestCursor_QuickCheck(t *testing.T) { 500 f := func(items testdata) bool { 501 db := MustOpenDB() 502 defer db.MustClose() 503 504 tx, err := db.Begin(true) 505 if err != nil { 506 t.Fatal(err) 507 } 508 b, err := tx.CreateBucket([]byte("widgets")) 509 if err != nil { 510 t.Fatal(err) 511 } 512 for _, item := range items { 513 if err := b.Put(item.Key, item.Value); err != nil { 514 t.Fatal(err) 515 } 516 } 517 if err := tx.Commit(); err != nil { 518 t.Fatal(err) 519 } 520 521 sort.Sort(items) 522 523 var index = 0 524 tx, err = db.Begin(false) 525 if err != nil { 526 t.Fatal(err) 527 } 528 529 c := tx.Bucket([]byte("widgets")).Cursor() 530 for k, v := c.First(); k != nil && index < len(items); k, v = c.Next() { 531 if !bytes.Equal(k, items[index].Key) { 532 t.Fatalf("unexpected key: %v", k) 533 } else if !bytes.Equal(v, items[index].Value) { 534 t.Fatalf("unexpected value: %v", v) 535 } 536 index++ 537 } 538 if len(items) != index { 539 t.Fatalf("unexpected item count: %v, expected %v", len(items), index) 540 } 541 542 if err := tx.Rollback(); err != nil { 543 t.Fatal(err) 544 } 545 546 return true 547 } 548 if err := quick.Check(f, qconfig()); err != nil { 549 t.Error(err) 550 } 551 } 552 553 func TestCursor_QuickCheck_Reverse(t *testing.T) { 554 f := func(items testdata) bool { 555 db := MustOpenDB() 556 defer db.MustClose() 557 558 tx, err := db.Begin(true) 559 if err != nil { 560 t.Fatal(err) 561 } 562 b, err := tx.CreateBucket([]byte("widgets")) 563 if err != nil { 564 t.Fatal(err) 565 } 566 for _, item := range items { 567 if err := b.Put(item.Key, item.Value); err != nil { 568 t.Fatal(err) 569 } 570 } 571 if err := tx.Commit(); err != nil { 572 t.Fatal(err) 573 } 574 575 sort.Sort(revtestdata(items)) 576 577 var index = 0 578 tx, err = db.Begin(false) 579 if err != nil { 580 t.Fatal(err) 581 } 582 c := tx.Bucket([]byte("widgets")).Cursor() 583 for k, v := c.Last(); k != nil && index < len(items); k, v = c.Prev() { 584 if !bytes.Equal(k, items[index].Key) { 585 t.Fatalf("unexpected key: %v", k) 586 } else if !bytes.Equal(v, items[index].Value) { 587 t.Fatalf("unexpected value: %v", v) 588 } 589 index++ 590 } 591 if len(items) != index { 592 t.Fatalf("unexpected item count: %v, expected %v", len(items), index) 593 } 594 595 if err := tx.Rollback(); err != nil { 596 t.Fatal(err) 597 } 598 599 return true 600 } 601 if err := quick.Check(f, qconfig()); err != nil { 602 t.Error(err) 603 } 604 } 605 606 func TestCursor_QuickCheck_BucketsOnly(t *testing.T) { 607 db := MustOpenDB() 608 defer db.MustClose() 609 610 if err := db.Update(func(tx *bdb.Tx) error { 611 b, err := tx.CreateBucket([]byte("widgets")) 612 if err != nil { 613 t.Fatal(err) 614 } 615 if _, err := b.CreateBucket([]byte("foo")); err != nil { 616 t.Fatal(err) 617 } 618 if _, err := b.CreateBucket([]byte("bar")); err != nil { 619 t.Fatal(err) 620 } 621 if _, err := b.CreateBucket([]byte("baz")); err != nil { 622 t.Fatal(err) 623 } 624 return nil 625 }); err != nil { 626 t.Fatal(err) 627 } 628 629 if err := db.View(func(tx *bdb.Tx) error { 630 var names []string 631 c := tx.Bucket([]byte("widgets")).Cursor() 632 for k, v := c.First(); k != nil; k, v = c.Next() { 633 names = append(names, string(k)) 634 if v != nil { 635 t.Fatalf("unexpected value: %v", v) 636 } 637 } 638 if !reflect.DeepEqual(names, []string{"bar", "baz", "foo"}) { 639 t.Fatalf("unexpected names: %+v", names) 640 } 641 return nil 642 }); err != nil { 643 t.Fatal(err) 644 } 645 } 646 647 func TestCursor_QuickCheck_BucketsOnly_Reverse(t *testing.T) { 648 db := MustOpenDB() 649 defer db.MustClose() 650 651 if err := db.Update(func(tx *bdb.Tx) error { 652 b, err := tx.CreateBucket([]byte("widgets")) 653 if err != nil { 654 t.Fatal(err) 655 } 656 if _, err := b.CreateBucket([]byte("foo")); err != nil { 657 t.Fatal(err) 658 } 659 if _, err := b.CreateBucket([]byte("bar")); err != nil { 660 t.Fatal(err) 661 } 662 if _, err := b.CreateBucket([]byte("baz")); err != nil { 663 t.Fatal(err) 664 } 665 return nil 666 }); err != nil { 667 t.Fatal(err) 668 } 669 670 if err := db.View(func(tx *bdb.Tx) error { 671 var names []string 672 c := tx.Bucket([]byte("widgets")).Cursor() 673 for k, v := c.Last(); k != nil; k, v = c.Prev() { 674 names = append(names, string(k)) 675 if v != nil { 676 t.Fatalf("unexpected value: %v", v) 677 } 678 } 679 if !reflect.DeepEqual(names, []string{"foo", "baz", "bar"}) { 680 t.Fatalf("unexpected names: %+v", names) 681 } 682 return nil 683 }); err != nil { 684 t.Fatal(err) 685 } 686 } 687 688 func ExampleCursor() { 689 db, err := bdb.Open(tempfile(), nil) 690 if err != nil { 691 log.Fatal(err) 692 } 693 defer os.Remove(db.Path()) 694 695 if err := db.Update(func(tx *bdb.Tx) error { 696 b, err := tx.CreateBucket([]byte("animals")) 697 if err != nil { 698 return err 699 } 700 701 if err := b.Put([]byte("dog"), []byte("fun")); err != nil { 702 log.Fatal(err) 703 } 704 if err := b.Put([]byte("cat"), []byte("lame")); err != nil { 705 log.Fatal(err) 706 } 707 if err := b.Put([]byte("liger"), []byte("awesome")); err != nil { 708 log.Fatal(err) 709 } 710 711 c := b.Cursor() 712 713 for k, v := c.First(); k != nil; k, v = c.Next() { 714 fmt.Printf("A %s is %s.\n", k, v) 715 } 716 717 return nil 718 }); err != nil { 719 log.Fatal(err) 720 } 721 722 if err := db.Close(); err != nil { 723 log.Fatal(err) 724 } 725 } 726 727 func ExampleCursor_reverse() { 728 db, err := bdb.Open(tempfile(), nil) 729 if err != nil { 730 log.Fatal(err) 731 } 732 defer os.Remove(db.Path()) 733 734 if err := db.Update(func(tx *bdb.Tx) error { 735 b, err := tx.CreateBucket([]byte("animals")) 736 if err != nil { 737 return err 738 } 739 740 if err := b.Put([]byte("dog"), []byte("fun")); err != nil { 741 log.Fatal(err) 742 } 743 if err := b.Put([]byte("cat"), []byte("lame")); err != nil { 744 log.Fatal(err) 745 } 746 if err := b.Put([]byte("liger"), []byte("awesome")); err != nil { 747 log.Fatal(err) 748 } 749 750 c := b.Cursor() 751 752 for k, v := c.Last(); k != nil; k, v = c.Prev() { 753 fmt.Printf("A %s is %s.\n", k, v) 754 } 755 756 return nil 757 }); err != nil { 758 log.Fatal(err) 759 } 760 761 if err := db.Close(); err != nil { 762 log.Fatal(err) 763 } 764 }