1package bolt_test 2 3import ( 4 "bytes" 5 "encoding/binary" 6 "errors" 7 "fmt" 8 "log" 9 "math/rand" 10 "os" 11 "strconv" 12 "strings" 13 "testing" 14 "testing/quick" 15 16 "github.com/boltdb/bolt" 17) 18 19// Ensure that a bucket that gets a non-existent key returns nil. 20func TestBucket_Get_NonExistent(t *testing.T) { 21 db := MustOpenDB() 22 defer db.MustClose() 23 24 if err := db.Update(func(tx *bolt.Tx) error { 25 b, err := tx.CreateBucket([]byte("widgets")) 26 if err != nil { 27 t.Fatal(err) 28 } 29 if v := b.Get([]byte("foo")); v != nil { 30 t.Fatal("expected nil value") 31 } 32 return nil 33 }); err != nil { 34 t.Fatal(err) 35 } 36} 37 38// Ensure that a bucket can read a value that is not flushed yet. 39func TestBucket_Get_FromNode(t *testing.T) { 40 db := MustOpenDB() 41 defer db.MustClose() 42 43 if err := db.Update(func(tx *bolt.Tx) error { 44 b, err := tx.CreateBucket([]byte("widgets")) 45 if err != nil { 46 t.Fatal(err) 47 } 48 if err := b.Put([]byte("foo"), []byte("bar")); err != nil { 49 t.Fatal(err) 50 } 51 if v := b.Get([]byte("foo")); !bytes.Equal(v, []byte("bar")) { 52 t.Fatalf("unexpected value: %v", v) 53 } 54 return nil 55 }); err != nil { 56 t.Fatal(err) 57 } 58} 59 60// Ensure that a bucket retrieved via Get() returns a nil. 61func TestBucket_Get_IncompatibleValue(t *testing.T) { 62 db := MustOpenDB() 63 defer db.MustClose() 64 if err := db.Update(func(tx *bolt.Tx) error { 65 _, err := tx.CreateBucket([]byte("widgets")) 66 if err != nil { 67 t.Fatal(err) 68 } 69 70 if _, err := tx.Bucket([]byte("widgets")).CreateBucket([]byte("foo")); err != nil { 71 t.Fatal(err) 72 } 73 74 if tx.Bucket([]byte("widgets")).Get([]byte("foo")) != nil { 75 t.Fatal("expected nil value") 76 } 77 return nil 78 }); err != nil { 79 t.Fatal(err) 80 } 81} 82 83// Ensure that a slice returned from a bucket has a capacity equal to its length. 84// This also allows slices to be appended to since it will require a realloc by Go. 85// 86// https://github.com/boltdb/bolt/issues/544 87func TestBucket_Get_Capacity(t *testing.T) { 88 db := MustOpenDB() 89 defer db.MustClose() 90 91 // Write key to a bucket. 92 if err := db.Update(func(tx *bolt.Tx) error { 93 b, err := tx.CreateBucket([]byte("bucket")) 94 if err != nil { 95 return err 96 } 97 return b.Put([]byte("key"), []byte("val")) 98 }); err != nil { 99 t.Fatal(err) 100 } 101 102 // Retrieve value and attempt to append to it. 103 if err := db.Update(func(tx *bolt.Tx) error { 104 k, v := tx.Bucket([]byte("bucket")).Cursor().First() 105 106 // Verify capacity. 107 if len(k) != cap(k) { 108 t.Fatalf("unexpected key slice capacity: %d", cap(k)) 109 } else if len(v) != cap(v) { 110 t.Fatalf("unexpected value slice capacity: %d", cap(v)) 111 } 112 113 // Ensure slice can be appended to without a segfault. 114 k = append(k, []byte("123")...) 115 v = append(v, []byte("123")...) 116 117 return nil 118 }); err != nil { 119 t.Fatal(err) 120 } 121} 122 123// Ensure that a bucket can write a key/value. 124func TestBucket_Put(t *testing.T) { 125 db := MustOpenDB() 126 defer db.MustClose() 127 if err := db.Update(func(tx *bolt.Tx) error { 128 b, err := tx.CreateBucket([]byte("widgets")) 129 if err != nil { 130 t.Fatal(err) 131 } 132 if err := b.Put([]byte("foo"), []byte("bar")); err != nil { 133 t.Fatal(err) 134 } 135 136 v := tx.Bucket([]byte("widgets")).Get([]byte("foo")) 137 if !bytes.Equal([]byte("bar"), v) { 138 t.Fatalf("unexpected value: %v", v) 139 } 140 return nil 141 }); err != nil { 142 t.Fatal(err) 143 } 144} 145 146// Ensure that a bucket can rewrite a key in the same transaction. 147func TestBucket_Put_Repeat(t *testing.T) { 148 db := MustOpenDB() 149 defer db.MustClose() 150 if err := db.Update(func(tx *bolt.Tx) error { 151 b, err := tx.CreateBucket([]byte("widgets")) 152 if err != nil { 153 t.Fatal(err) 154 } 155 if err := b.Put([]byte("foo"), []byte("bar")); err != nil { 156 t.Fatal(err) 157 } 158 if err := b.Put([]byte("foo"), []byte("baz")); err != nil { 159 t.Fatal(err) 160 } 161 162 value := tx.Bucket([]byte("widgets")).Get([]byte("foo")) 163 if !bytes.Equal([]byte("baz"), value) { 164 t.Fatalf("unexpected value: %v", value) 165 } 166 return nil 167 }); err != nil { 168 t.Fatal(err) 169 } 170} 171 172// Ensure that a bucket can write a bunch of large values. 173func TestBucket_Put_Large(t *testing.T) { 174 db := MustOpenDB() 175 defer db.MustClose() 176 177 count, factor := 100, 200 178 if err := db.Update(func(tx *bolt.Tx) error { 179 b, err := tx.CreateBucket([]byte("widgets")) 180 if err != nil { 181 t.Fatal(err) 182 } 183 for i := 1; i < count; i++ { 184 if err := b.Put([]byte(strings.Repeat("0", i*factor)), []byte(strings.Repeat("X", (count-i)*factor))); err != nil { 185 t.Fatal(err) 186 } 187 } 188 return nil 189 }); err != nil { 190 t.Fatal(err) 191 } 192 193 if err := db.View(func(tx *bolt.Tx) error { 194 b := tx.Bucket([]byte("widgets")) 195 for i := 1; i < count; i++ { 196 value := b.Get([]byte(strings.Repeat("0", i*factor))) 197 if !bytes.Equal(value, []byte(strings.Repeat("X", (count-i)*factor))) { 198 t.Fatalf("unexpected value: %v", value) 199 } 200 } 201 return nil 202 }); err != nil { 203 t.Fatal(err) 204 } 205} 206 207// Ensure that a database can perform multiple large appends safely. 208func TestDB_Put_VeryLarge(t *testing.T) { 209 if testing.Short() { 210 t.Skip("skipping test in short mode.") 211 } 212 213 n, batchN := 400000, 200000 214 ksize, vsize := 8, 500 215 216 db := MustOpenDB() 217 defer db.MustClose() 218 219 for i := 0; i < n; i += batchN { 220 if err := db.Update(func(tx *bolt.Tx) error { 221 b, err := tx.CreateBucketIfNotExists([]byte("widgets")) 222 if err != nil { 223 t.Fatal(err) 224 } 225 for j := 0; j < batchN; j++ { 226 k, v := make([]byte, ksize), make([]byte, vsize) 227 binary.BigEndian.PutUint32(k, uint32(i+j)) 228 if err := b.Put(k, v); err != nil { 229 t.Fatal(err) 230 } 231 } 232 return nil 233 }); err != nil { 234 t.Fatal(err) 235 } 236 } 237} 238 239// Ensure that a setting a value on a key with a bucket value returns an error. 240func TestBucket_Put_IncompatibleValue(t *testing.T) { 241 db := MustOpenDB() 242 defer db.MustClose() 243 244 if err := db.Update(func(tx *bolt.Tx) error { 245 b0, err := tx.CreateBucket([]byte("widgets")) 246 if err != nil { 247 t.Fatal(err) 248 } 249 250 if _, err := tx.Bucket([]byte("widgets")).CreateBucket([]byte("foo")); err != nil { 251 t.Fatal(err) 252 } 253 if err := b0.Put([]byte("foo"), []byte("bar")); err != bolt.ErrIncompatibleValue { 254 t.Fatalf("unexpected error: %s", err) 255 } 256 return nil 257 }); err != nil { 258 t.Fatal(err) 259 } 260} 261 262// Ensure that a setting a value while the transaction is closed returns an error. 263func TestBucket_Put_Closed(t *testing.T) { 264 db := MustOpenDB() 265 defer db.MustClose() 266 tx, err := db.Begin(true) 267 if err != nil { 268 t.Fatal(err) 269 } 270 271 b, err := tx.CreateBucket([]byte("widgets")) 272 if err != nil { 273 t.Fatal(err) 274 } 275 276 if err := tx.Rollback(); err != nil { 277 t.Fatal(err) 278 } 279 280 if err := b.Put([]byte("foo"), []byte("bar")); err != bolt.ErrTxClosed { 281 t.Fatalf("unexpected error: %s", err) 282 } 283} 284 285// Ensure that setting a value on a read-only bucket returns an error. 286func TestBucket_Put_ReadOnly(t *testing.T) { 287 db := MustOpenDB() 288 defer db.MustClose() 289 290 if err := db.Update(func(tx *bolt.Tx) error { 291 if _, err := tx.CreateBucket([]byte("widgets")); err != nil { 292 t.Fatal(err) 293 } 294 return nil 295 }); err != nil { 296 t.Fatal(err) 297 } 298 299 if err := db.View(func(tx *bolt.Tx) error { 300 b := tx.Bucket([]byte("widgets")) 301 if err := b.Put([]byte("foo"), []byte("bar")); err != bolt.ErrTxNotWritable { 302 t.Fatalf("unexpected error: %s", err) 303 } 304 return nil 305 }); err != nil { 306 t.Fatal(err) 307 } 308} 309 310// Ensure that a bucket can delete an existing key. 311func TestBucket_Delete(t *testing.T) { 312 db := MustOpenDB() 313 defer db.MustClose() 314 315 if err := db.Update(func(tx *bolt.Tx) error { 316 b, err := tx.CreateBucket([]byte("widgets")) 317 if err != nil { 318 t.Fatal(err) 319 } 320 if err := b.Put([]byte("foo"), []byte("bar")); err != nil { 321 t.Fatal(err) 322 } 323 if err := b.Delete([]byte("foo")); err != nil { 324 t.Fatal(err) 325 } 326 if v := b.Get([]byte("foo")); v != nil { 327 t.Fatalf("unexpected value: %v", v) 328 } 329 return nil 330 }); err != nil { 331 t.Fatal(err) 332 } 333} 334 335// Ensure that deleting a large set of keys will work correctly. 336func TestBucket_Delete_Large(t *testing.T) { 337 db := MustOpenDB() 338 defer db.MustClose() 339 340 if err := db.Update(func(tx *bolt.Tx) error { 341 b, err := tx.CreateBucket([]byte("widgets")) 342 if err != nil { 343 t.Fatal(err) 344 } 345 346 for i := 0; i < 100; i++ { 347 if err := b.Put([]byte(strconv.Itoa(i)), []byte(strings.Repeat("*", 1024))); err != nil { 348 t.Fatal(err) 349 } 350 } 351 352 return nil 353 }); err != nil { 354 t.Fatal(err) 355 } 356 357 if err := db.Update(func(tx *bolt.Tx) error { 358 b := tx.Bucket([]byte("widgets")) 359 for i := 0; i < 100; i++ { 360 if err := b.Delete([]byte(strconv.Itoa(i))); err != nil { 361 t.Fatal(err) 362 } 363 } 364 return nil 365 }); err != nil { 366 t.Fatal(err) 367 } 368 369 if err := db.View(func(tx *bolt.Tx) error { 370 b := tx.Bucket([]byte("widgets")) 371 for i := 0; i < 100; i++ { 372 if v := b.Get([]byte(strconv.Itoa(i))); v != nil { 373 t.Fatalf("unexpected value: %v, i=%d", v, i) 374 } 375 } 376 return nil 377 }); err != nil { 378 t.Fatal(err) 379 } 380} 381 382// Deleting a very large list of keys will cause the freelist to use overflow. 383func TestBucket_Delete_FreelistOverflow(t *testing.T) { 384 if testing.Short() { 385 t.Skip("skipping test in short mode.") 386 } 387 388 db := MustOpenDB() 389 defer db.MustClose() 390 391 k := make([]byte, 16) 392 for i := uint64(0); i < 10000; i++ { 393 if err := db.Update(func(tx *bolt.Tx) error { 394 b, err := tx.CreateBucketIfNotExists([]byte("0")) 395 if err != nil { 396 t.Fatalf("bucket error: %s", err) 397 } 398 399 for j := uint64(0); j < 1000; j++ { 400 binary.BigEndian.PutUint64(k[:8], i) 401 binary.BigEndian.PutUint64(k[8:], j) 402 if err := b.Put(k, nil); err != nil { 403 t.Fatalf("put error: %s", err) 404 } 405 } 406 407 return nil 408 }); err != nil { 409 t.Fatal(err) 410 } 411 } 412 413 // Delete all of them in one large transaction 414 if err := db.Update(func(tx *bolt.Tx) error { 415 b := tx.Bucket([]byte("0")) 416 c := b.Cursor() 417 for k, _ := c.First(); k != nil; k, _ = c.Next() { 418 if err := c.Delete(); err != nil { 419 t.Fatal(err) 420 } 421 } 422 return nil 423 }); err != nil { 424 t.Fatal(err) 425 } 426} 427 428// Ensure that accessing and updating nested buckets is ok across transactions. 429func TestBucket_Nested(t *testing.T) { 430 db := MustOpenDB() 431 defer db.MustClose() 432 433 if err := db.Update(func(tx *bolt.Tx) error { 434 // Create a widgets bucket. 435 b, err := tx.CreateBucket([]byte("widgets")) 436 if err != nil { 437 t.Fatal(err) 438 } 439 440 // Create a widgets/foo bucket. 441 _, err = b.CreateBucket([]byte("foo")) 442 if err != nil { 443 t.Fatal(err) 444 } 445 446 // Create a widgets/bar key. 447 if err := b.Put([]byte("bar"), []byte("0000")); err != nil { 448 t.Fatal(err) 449 } 450 451 return nil 452 }); err != nil { 453 t.Fatal(err) 454 } 455 db.MustCheck() 456 457 // Update widgets/bar. 458 if err := db.Update(func(tx *bolt.Tx) error { 459 b := tx.Bucket([]byte("widgets")) 460 if err := b.Put([]byte("bar"), []byte("xxxx")); err != nil { 461 t.Fatal(err) 462 } 463 return nil 464 }); err != nil { 465 t.Fatal(err) 466 } 467 db.MustCheck() 468 469 // Cause a split. 470 if err := db.Update(func(tx *bolt.Tx) error { 471 var b = tx.Bucket([]byte("widgets")) 472 for i := 0; i < 10000; i++ { 473 if err := b.Put([]byte(strconv.Itoa(i)), []byte(strconv.Itoa(i))); err != nil { 474 t.Fatal(err) 475 } 476 } 477 return nil 478 }); err != nil { 479 t.Fatal(err) 480 } 481 db.MustCheck() 482 483 // Insert into widgets/foo/baz. 484 if err := db.Update(func(tx *bolt.Tx) error { 485 var b = tx.Bucket([]byte("widgets")) 486 if err := b.Bucket([]byte("foo")).Put([]byte("baz"), []byte("yyyy")); err != nil { 487 t.Fatal(err) 488 } 489 return nil 490 }); err != nil { 491 t.Fatal(err) 492 } 493 db.MustCheck() 494 495 // Verify. 496 if err := db.View(func(tx *bolt.Tx) error { 497 var b = tx.Bucket([]byte("widgets")) 498 if v := b.Bucket([]byte("foo")).Get([]byte("baz")); !bytes.Equal(v, []byte("yyyy")) { 499 t.Fatalf("unexpected value: %v", v) 500 } 501 if v := b.Get([]byte("bar")); !bytes.Equal(v, []byte("xxxx")) { 502 t.Fatalf("unexpected value: %v", v) 503 } 504 for i := 0; i < 10000; i++ { 505 if v := b.Get([]byte(strconv.Itoa(i))); !bytes.Equal(v, []byte(strconv.Itoa(i))) { 506 t.Fatalf("unexpected value: %v", v) 507 } 508 } 509 return nil 510 }); err != nil { 511 t.Fatal(err) 512 } 513} 514 515// Ensure that deleting a bucket using Delete() returns an error. 516func TestBucket_Delete_Bucket(t *testing.T) { 517 db := MustOpenDB() 518 defer db.MustClose() 519 if err := db.Update(func(tx *bolt.Tx) error { 520 b, err := tx.CreateBucket([]byte("widgets")) 521 if err != nil { 522 t.Fatal(err) 523 } 524 if _, err := b.CreateBucket([]byte("foo")); err != nil { 525 t.Fatal(err) 526 } 527 if err := b.Delete([]byte("foo")); err != bolt.ErrIncompatibleValue { 528 t.Fatalf("unexpected error: %s", err) 529 } 530 return nil 531 }); err != nil { 532 t.Fatal(err) 533 } 534} 535 536// Ensure that deleting a key on a read-only bucket returns an error. 537func TestBucket_Delete_ReadOnly(t *testing.T) { 538 db := MustOpenDB() 539 defer db.MustClose() 540 541 if err := db.Update(func(tx *bolt.Tx) error { 542 if _, err := tx.CreateBucket([]byte("widgets")); err != nil { 543 t.Fatal(err) 544 } 545 return nil 546 }); err != nil { 547 t.Fatal(err) 548 } 549 550 if err := db.View(func(tx *bolt.Tx) error { 551 if err := tx.Bucket([]byte("widgets")).Delete([]byte("foo")); err != bolt.ErrTxNotWritable { 552 t.Fatalf("unexpected error: %s", err) 553 } 554 return nil 555 }); err != nil { 556 t.Fatal(err) 557 } 558} 559 560// Ensure that a deleting value while the transaction is closed returns an error. 561func TestBucket_Delete_Closed(t *testing.T) { 562 db := MustOpenDB() 563 defer db.MustClose() 564 565 tx, err := db.Begin(true) 566 if err != nil { 567 t.Fatal(err) 568 } 569 570 b, err := tx.CreateBucket([]byte("widgets")) 571 if err != nil { 572 t.Fatal(err) 573 } 574 575 if err := tx.Rollback(); err != nil { 576 t.Fatal(err) 577 } 578 if err := b.Delete([]byte("foo")); err != bolt.ErrTxClosed { 579 t.Fatalf("unexpected error: %s", err) 580 } 581} 582 583// Ensure that deleting a bucket causes nested buckets to be deleted. 584func TestBucket_DeleteBucket_Nested(t *testing.T) { 585 db := MustOpenDB() 586 defer db.MustClose() 587 588 if err := db.Update(func(tx *bolt.Tx) error { 589 widgets, err := tx.CreateBucket([]byte("widgets")) 590 if err != nil { 591 t.Fatal(err) 592 } 593 594 foo, err := widgets.CreateBucket([]byte("foo")) 595 if err != nil { 596 t.Fatal(err) 597 } 598 599 bar, err := foo.CreateBucket([]byte("bar")) 600 if err != nil { 601 t.Fatal(err) 602 } 603 if err := bar.Put([]byte("baz"), []byte("bat")); err != nil { 604 t.Fatal(err) 605 } 606 if err := tx.Bucket([]byte("widgets")).DeleteBucket([]byte("foo")); err != nil { 607 t.Fatal(err) 608 } 609 return nil 610 }); err != nil { 611 t.Fatal(err) 612 } 613} 614 615// Ensure that deleting a bucket causes nested buckets to be deleted after they have been committed. 616func TestBucket_DeleteBucket_Nested2(t *testing.T) { 617 db := MustOpenDB() 618 defer db.MustClose() 619 620 if err := db.Update(func(tx *bolt.Tx) error { 621 widgets, err := tx.CreateBucket([]byte("widgets")) 622 if err != nil { 623 t.Fatal(err) 624 } 625 626 foo, err := widgets.CreateBucket([]byte("foo")) 627 if err != nil { 628 t.Fatal(err) 629 } 630 631 bar, err := foo.CreateBucket([]byte("bar")) 632 if err != nil { 633 t.Fatal(err) 634 } 635 636 if err := bar.Put([]byte("baz"), []byte("bat")); err != nil { 637 t.Fatal(err) 638 } 639 return nil 640 }); err != nil { 641 t.Fatal(err) 642 } 643 644 if err := db.Update(func(tx *bolt.Tx) error { 645 widgets := tx.Bucket([]byte("widgets")) 646 if widgets == nil { 647 t.Fatal("expected widgets bucket") 648 } 649 650 foo := widgets.Bucket([]byte("foo")) 651 if foo == nil { 652 t.Fatal("expected foo bucket") 653 } 654 655 bar := foo.Bucket([]byte("bar")) 656 if bar == nil { 657 t.Fatal("expected bar bucket") 658 } 659 660 if v := bar.Get([]byte("baz")); !bytes.Equal(v, []byte("bat")) { 661 t.Fatalf("unexpected value: %v", v) 662 } 663 if err := tx.DeleteBucket([]byte("widgets")); err != nil { 664 t.Fatal(err) 665 } 666 return nil 667 }); err != nil { 668 t.Fatal(err) 669 } 670 671 if err := db.View(func(tx *bolt.Tx) error { 672 if tx.Bucket([]byte("widgets")) != nil { 673 t.Fatal("expected bucket to be deleted") 674 } 675 return nil 676 }); err != nil { 677 t.Fatal(err) 678 } 679} 680 681// Ensure that deleting a child bucket with multiple pages causes all pages to get collected. 682// NOTE: Consistency check in bolt_test.DB.Close() will panic if pages not freed properly. 683func TestBucket_DeleteBucket_Large(t *testing.T) { 684 db := MustOpenDB() 685 defer db.MustClose() 686 687 if err := db.Update(func(tx *bolt.Tx) error { 688 widgets, err := tx.CreateBucket([]byte("widgets")) 689 if err != nil { 690 t.Fatal(err) 691 } 692 693 foo, err := widgets.CreateBucket([]byte("foo")) 694 if err != nil { 695 t.Fatal(err) 696 } 697 698 for i := 0; i < 1000; i++ { 699 if err := foo.Put([]byte(fmt.Sprintf("%d", i)), []byte(fmt.Sprintf("%0100d", i))); err != nil { 700 t.Fatal(err) 701 } 702 } 703 return nil 704 }); err != nil { 705 t.Fatal(err) 706 } 707 708 if err := db.Update(func(tx *bolt.Tx) error { 709 if err := tx.DeleteBucket([]byte("widgets")); err != nil { 710 t.Fatal(err) 711 } 712 return nil 713 }); err != nil { 714 t.Fatal(err) 715 } 716} 717 718// Ensure that a simple value retrieved via Bucket() returns a nil. 719func TestBucket_Bucket_IncompatibleValue(t *testing.T) { 720 db := MustOpenDB() 721 defer db.MustClose() 722 723 if err := db.Update(func(tx *bolt.Tx) error { 724 widgets, err := tx.CreateBucket([]byte("widgets")) 725 if err != nil { 726 t.Fatal(err) 727 } 728 729 if err := widgets.Put([]byte("foo"), []byte("bar")); err != nil { 730 t.Fatal(err) 731 } 732 if b := tx.Bucket([]byte("widgets")).Bucket([]byte("foo")); b != nil { 733 t.Fatal("expected nil bucket") 734 } 735 return nil 736 }); err != nil { 737 t.Fatal(err) 738 } 739} 740 741// Ensure that creating a bucket on an existing non-bucket key returns an error. 742func TestBucket_CreateBucket_IncompatibleValue(t *testing.T) { 743 db := MustOpenDB() 744 defer db.MustClose() 745 if err := db.Update(func(tx *bolt.Tx) error { 746 widgets, err := tx.CreateBucket([]byte("widgets")) 747 if err != nil { 748 t.Fatal(err) 749 } 750 751 if err := widgets.Put([]byte("foo"), []byte("bar")); err != nil { 752 t.Fatal(err) 753 } 754 if _, err := widgets.CreateBucket([]byte("foo")); err != bolt.ErrIncompatibleValue { 755 t.Fatalf("unexpected error: %s", err) 756 } 757 return nil 758 }); err != nil { 759 t.Fatal(err) 760 } 761} 762 763// Ensure that deleting a bucket on an existing non-bucket key returns an error. 764func TestBucket_DeleteBucket_IncompatibleValue(t *testing.T) { 765 db := MustOpenDB() 766 defer db.MustClose() 767 768 if err := db.Update(func(tx *bolt.Tx) error { 769 widgets, err := tx.CreateBucket([]byte("widgets")) 770 if err != nil { 771 t.Fatal(err) 772 } 773 if err := widgets.Put([]byte("foo"), []byte("bar")); err != nil { 774 t.Fatal(err) 775 } 776 if err := tx.Bucket([]byte("widgets")).DeleteBucket([]byte("foo")); err != bolt.ErrIncompatibleValue { 777 t.Fatalf("unexpected error: %s", err) 778 } 779 return nil 780 }); err != nil { 781 t.Fatal(err) 782 } 783} 784 785// Ensure bucket can set and update its sequence number. 786func TestBucket_Sequence(t *testing.T) { 787 db := MustOpenDB() 788 defer db.MustClose() 789 790 if err := db.Update(func(tx *bolt.Tx) error { 791 bkt, err := tx.CreateBucket([]byte("0")) 792 if err != nil { 793 t.Fatal(err) 794 } 795 796 // Retrieve sequence. 797 if v := bkt.Sequence(); v != 0 { 798 t.Fatalf("unexpected sequence: %d", v) 799 } 800 801 // Update sequence. 802 if err := bkt.SetSequence(1000); err != nil { 803 t.Fatal(err) 804 } 805 806 // Read sequence again. 807 if v := bkt.Sequence(); v != 1000 { 808 t.Fatalf("unexpected sequence: %d", v) 809 } 810 811 return nil 812 }); err != nil { 813 t.Fatal(err) 814 } 815 816 // Verify sequence in separate transaction. 817 if err := db.View(func(tx *bolt.Tx) error { 818 if v := tx.Bucket([]byte("0")).Sequence(); v != 1000 { 819 t.Fatalf("unexpected sequence: %d", v) 820 } 821 return nil 822 }); err != nil { 823 t.Fatal(err) 824 } 825} 826 827// Ensure that a bucket can return an autoincrementing sequence. 828func TestBucket_NextSequence(t *testing.T) { 829 db := MustOpenDB() 830 defer db.MustClose() 831 832 if err := db.Update(func(tx *bolt.Tx) error { 833 widgets, err := tx.CreateBucket([]byte("widgets")) 834 if err != nil { 835 t.Fatal(err) 836 } 837 woojits, err := tx.CreateBucket([]byte("woojits")) 838 if err != nil { 839 t.Fatal(err) 840 } 841 842 // Make sure sequence increments. 843 if seq, err := widgets.NextSequence(); err != nil { 844 t.Fatal(err) 845 } else if seq != 1 { 846 t.Fatalf("unexpecte sequence: %d", seq) 847 } 848 849 if seq, err := widgets.NextSequence(); err != nil { 850 t.Fatal(err) 851 } else if seq != 2 { 852 t.Fatalf("unexpected sequence: %d", seq) 853 } 854 855 // Buckets should be separate. 856 if seq, err := woojits.NextSequence(); err != nil { 857 t.Fatal(err) 858 } else if seq != 1 { 859 t.Fatalf("unexpected sequence: %d", 1) 860 } 861 862 return nil 863 }); err != nil { 864 t.Fatal(err) 865 } 866} 867 868// Ensure that a bucket will persist an autoincrementing sequence even if its 869// the only thing updated on the bucket. 870// https://github.com/boltdb/bolt/issues/296 871func TestBucket_NextSequence_Persist(t *testing.T) { 872 db := MustOpenDB() 873 defer db.MustClose() 874 875 if err := db.Update(func(tx *bolt.Tx) error { 876 if _, err := tx.CreateBucket([]byte("widgets")); err != nil { 877 t.Fatal(err) 878 } 879 return nil 880 }); err != nil { 881 t.Fatal(err) 882 } 883 884 if err := db.Update(func(tx *bolt.Tx) error { 885 if _, err := tx.Bucket([]byte("widgets")).NextSequence(); err != nil { 886 t.Fatal(err) 887 } 888 return nil 889 }); err != nil { 890 t.Fatal(err) 891 } 892 893 if err := db.Update(func(tx *bolt.Tx) error { 894 seq, err := tx.Bucket([]byte("widgets")).NextSequence() 895 if err != nil { 896 t.Fatalf("unexpected error: %s", err) 897 } else if seq != 2 { 898 t.Fatalf("unexpected sequence: %d", seq) 899 } 900 return nil 901 }); err != nil { 902 t.Fatal(err) 903 } 904} 905 906// Ensure that retrieving the next sequence on a read-only bucket returns an error. 907func TestBucket_NextSequence_ReadOnly(t *testing.T) { 908 db := MustOpenDB() 909 defer db.MustClose() 910 911 if err := db.Update(func(tx *bolt.Tx) error { 912 if _, err := tx.CreateBucket([]byte("widgets")); err != nil { 913 t.Fatal(err) 914 } 915 return nil 916 }); err != nil { 917 t.Fatal(err) 918 } 919 920 if err := db.View(func(tx *bolt.Tx) error { 921 _, err := tx.Bucket([]byte("widgets")).NextSequence() 922 if err != bolt.ErrTxNotWritable { 923 t.Fatalf("unexpected error: %s", err) 924 } 925 return nil 926 }); err != nil { 927 t.Fatal(err) 928 } 929} 930 931// Ensure that retrieving the next sequence for a bucket on a closed database return an error. 932func TestBucket_NextSequence_Closed(t *testing.T) { 933 db := MustOpenDB() 934 defer db.MustClose() 935 tx, err := db.Begin(true) 936 if err != nil { 937 t.Fatal(err) 938 } 939 b, err := tx.CreateBucket([]byte("widgets")) 940 if err != nil { 941 t.Fatal(err) 942 } 943 if err := tx.Rollback(); err != nil { 944 t.Fatal(err) 945 } 946 if _, err := b.NextSequence(); err != bolt.ErrTxClosed { 947 t.Fatal(err) 948 } 949} 950 951// Ensure a user can loop over all key/value pairs in a bucket. 952func TestBucket_ForEach(t *testing.T) { 953 db := MustOpenDB() 954 defer db.MustClose() 955 956 if err := db.Update(func(tx *bolt.Tx) error { 957 b, err := tx.CreateBucket([]byte("widgets")) 958 if err != nil { 959 t.Fatal(err) 960 } 961 if err := b.Put([]byte("foo"), []byte("0000")); err != nil { 962 t.Fatal(err) 963 } 964 if err := b.Put([]byte("baz"), []byte("0001")); err != nil { 965 t.Fatal(err) 966 } 967 if err := b.Put([]byte("bar"), []byte("0002")); err != nil { 968 t.Fatal(err) 969 } 970 971 var index int 972 if err := b.ForEach(func(k, v []byte) error { 973 switch index { 974 case 0: 975 if !bytes.Equal(k, []byte("bar")) { 976 t.Fatalf("unexpected key: %v", k) 977 } else if !bytes.Equal(v, []byte("0002")) { 978 t.Fatalf("unexpected value: %v", v) 979 } 980 case 1: 981 if !bytes.Equal(k, []byte("baz")) { 982 t.Fatalf("unexpected key: %v", k) 983 } else if !bytes.Equal(v, []byte("0001")) { 984 t.Fatalf("unexpected value: %v", v) 985 } 986 case 2: 987 if !bytes.Equal(k, []byte("foo")) { 988 t.Fatalf("unexpected key: %v", k) 989 } else if !bytes.Equal(v, []byte("0000")) { 990 t.Fatalf("unexpected value: %v", v) 991 } 992 } 993 index++ 994 return nil 995 }); err != nil { 996 t.Fatal(err) 997 } 998 999 if index != 3 { 1000 t.Fatalf("unexpected index: %d", index) 1001 } 1002 1003 return nil 1004 }); err != nil { 1005 t.Fatal(err) 1006 } 1007} 1008 1009// Ensure a database can stop iteration early. 1010func TestBucket_ForEach_ShortCircuit(t *testing.T) { 1011 db := MustOpenDB() 1012 defer db.MustClose() 1013 if err := db.Update(func(tx *bolt.Tx) error { 1014 b, err := tx.CreateBucket([]byte("widgets")) 1015 if err != nil { 1016 t.Fatal(err) 1017 } 1018 if err := b.Put([]byte("bar"), []byte("0000")); err != nil { 1019 t.Fatal(err) 1020 } 1021 if err := b.Put([]byte("baz"), []byte("0000")); err != nil { 1022 t.Fatal(err) 1023 } 1024 if err := b.Put([]byte("foo"), []byte("0000")); err != nil { 1025 t.Fatal(err) 1026 } 1027 1028 var index int 1029 if err := tx.Bucket([]byte("widgets")).ForEach(func(k, v []byte) error { 1030 index++ 1031 if bytes.Equal(k, []byte("baz")) { 1032 return errors.New("marker") 1033 } 1034 return nil 1035 }); err == nil || err.Error() != "marker" { 1036 t.Fatalf("unexpected error: %s", err) 1037 } 1038 if index != 2 { 1039 t.Fatalf("unexpected index: %d", index) 1040 } 1041 1042 return nil 1043 }); err != nil { 1044 t.Fatal(err) 1045 } 1046} 1047 1048// Ensure that looping over a bucket on a closed database returns an error. 1049func TestBucket_ForEach_Closed(t *testing.T) { 1050 db := MustOpenDB() 1051 defer db.MustClose() 1052 1053 tx, err := db.Begin(true) 1054 if err != nil { 1055 t.Fatal(err) 1056 } 1057 1058 b, err := tx.CreateBucket([]byte("widgets")) 1059 if err != nil { 1060 t.Fatal(err) 1061 } 1062 1063 if err := tx.Rollback(); err != nil { 1064 t.Fatal(err) 1065 } 1066 1067 if err := b.ForEach(func(k, v []byte) error { return nil }); err != bolt.ErrTxClosed { 1068 t.Fatalf("unexpected error: %s", err) 1069 } 1070} 1071 1072// Ensure that an error is returned when inserting with an empty key. 1073func TestBucket_Put_EmptyKey(t *testing.T) { 1074 db := MustOpenDB() 1075 defer db.MustClose() 1076 1077 if err := db.Update(func(tx *bolt.Tx) error { 1078 b, err := tx.CreateBucket([]byte("widgets")) 1079 if err != nil { 1080 t.Fatal(err) 1081 } 1082 if err := b.Put([]byte(""), []byte("bar")); err != bolt.ErrKeyRequired { 1083 t.Fatalf("unexpected error: %s", err) 1084 } 1085 if err := b.Put(nil, []byte("bar")); err != bolt.ErrKeyRequired { 1086 t.Fatalf("unexpected error: %s", err) 1087 } 1088 return nil 1089 }); err != nil { 1090 t.Fatal(err) 1091 } 1092} 1093 1094// Ensure that an error is returned when inserting with a key that's too large. 1095func TestBucket_Put_KeyTooLarge(t *testing.T) { 1096 db := MustOpenDB() 1097 defer db.MustClose() 1098 if err := db.Update(func(tx *bolt.Tx) error { 1099 b, err := tx.CreateBucket([]byte("widgets")) 1100 if err != nil { 1101 t.Fatal(err) 1102 } 1103 if err := b.Put(make([]byte, 32769), []byte("bar")); err != bolt.ErrKeyTooLarge { 1104 t.Fatalf("unexpected error: %s", err) 1105 } 1106 return nil 1107 }); err != nil { 1108 t.Fatal(err) 1109 } 1110} 1111 1112// Ensure that an error is returned when inserting a value that's too large. 1113func TestBucket_Put_ValueTooLarge(t *testing.T) { 1114 // Skip this test on DroneCI because the machine is resource constrained. 1115 if os.Getenv("DRONE") == "true" { 1116 t.Skip("not enough RAM for test") 1117 } 1118 1119 db := MustOpenDB() 1120 defer db.MustClose() 1121 1122 if err := db.Update(func(tx *bolt.Tx) error { 1123 b, err := tx.CreateBucket([]byte("widgets")) 1124 if err != nil { 1125 t.Fatal(err) 1126 } 1127 if err := b.Put([]byte("foo"), make([]byte, bolt.MaxValueSize+1)); err != bolt.ErrValueTooLarge { 1128 t.Fatalf("unexpected error: %s", err) 1129 } 1130 return nil 1131 }); err != nil { 1132 t.Fatal(err) 1133 } 1134} 1135 1136// Ensure a bucket can calculate stats. 1137func TestBucket_Stats(t *testing.T) { 1138 db := MustOpenDB() 1139 defer db.MustClose() 1140 1141 // Add bucket with fewer keys but one big value. 1142 bigKey := []byte("really-big-value") 1143 for i := 0; i < 500; i++ { 1144 if err := db.Update(func(tx *bolt.Tx) error { 1145 b, err := tx.CreateBucketIfNotExists([]byte("woojits")) 1146 if err != nil { 1147 t.Fatal(err) 1148 } 1149 1150 if err := b.Put([]byte(fmt.Sprintf("%03d", i)), []byte(strconv.Itoa(i))); err != nil { 1151 t.Fatal(err) 1152 } 1153 return nil 1154 }); err != nil { 1155 t.Fatal(err) 1156 } 1157 } 1158 if err := db.Update(func(tx *bolt.Tx) error { 1159 if err := tx.Bucket([]byte("woojits")).Put(bigKey, []byte(strings.Repeat("*", 10000))); err != nil { 1160 t.Fatal(err) 1161 } 1162 return nil 1163 }); err != nil { 1164 t.Fatal(err) 1165 } 1166 1167 db.MustCheck() 1168 1169 if err := db.View(func(tx *bolt.Tx) error { 1170 stats := tx.Bucket([]byte("woojits")).Stats() 1171 if stats.BranchPageN != 1 { 1172 t.Fatalf("unexpected BranchPageN: %d", stats.BranchPageN) 1173 } else if stats.BranchOverflowN != 0 { 1174 t.Fatalf("unexpected BranchOverflowN: %d", stats.BranchOverflowN) 1175 } else if stats.LeafPageN != 7 { 1176 t.Fatalf("unexpected LeafPageN: %d", stats.LeafPageN) 1177 } else if stats.LeafOverflowN != 2 { 1178 t.Fatalf("unexpected LeafOverflowN: %d", stats.LeafOverflowN) 1179 } else if stats.KeyN != 501 { 1180 t.Fatalf("unexpected KeyN: %d", stats.KeyN) 1181 } else if stats.Depth != 2 { 1182 t.Fatalf("unexpected Depth: %d", stats.Depth) 1183 } 1184 1185 branchInuse := 16 // branch page header 1186 branchInuse += 7 * 16 // branch elements 1187 branchInuse += 7 * 3 // branch keys (6 3-byte keys) 1188 if stats.BranchInuse != branchInuse { 1189 t.Fatalf("unexpected BranchInuse: %d", stats.BranchInuse) 1190 } 1191 1192 leafInuse := 7 * 16 // leaf page header 1193 leafInuse += 501 * 16 // leaf elements 1194 leafInuse += 500*3 + len(bigKey) // leaf keys 1195 leafInuse += 1*10 + 2*90 + 3*400 + 10000 // leaf values 1196 if stats.LeafInuse != leafInuse { 1197 t.Fatalf("unexpected LeafInuse: %d", stats.LeafInuse) 1198 } 1199 1200 // Only check allocations for 4KB pages. 1201 if os.Getpagesize() == 4096 { 1202 if stats.BranchAlloc != 4096 { 1203 t.Fatalf("unexpected BranchAlloc: %d", stats.BranchAlloc) 1204 } else if stats.LeafAlloc != 36864 { 1205 t.Fatalf("unexpected LeafAlloc: %d", stats.LeafAlloc) 1206 } 1207 } 1208 1209 if stats.BucketN != 1 { 1210 t.Fatalf("unexpected BucketN: %d", stats.BucketN) 1211 } else if stats.InlineBucketN != 0 { 1212 t.Fatalf("unexpected InlineBucketN: %d", stats.InlineBucketN) 1213 } else if stats.InlineBucketInuse != 0 { 1214 t.Fatalf("unexpected InlineBucketInuse: %d", stats.InlineBucketInuse) 1215 } 1216 1217 return nil 1218 }); err != nil { 1219 t.Fatal(err) 1220 } 1221} 1222 1223// Ensure a bucket with random insertion utilizes fill percentage correctly. 1224func TestBucket_Stats_RandomFill(t *testing.T) { 1225 if testing.Short() { 1226 t.Skip("skipping test in short mode.") 1227 } else if os.Getpagesize() != 4096 { 1228 t.Skip("invalid page size for test") 1229 } 1230 1231 db := MustOpenDB() 1232 defer db.MustClose() 1233 1234 // Add a set of values in random order. It will be the same random 1235 // order so we can maintain consistency between test runs. 1236 var count int 1237 rand := rand.New(rand.NewSource(42)) 1238 for _, i := range rand.Perm(1000) { 1239 if err := db.Update(func(tx *bolt.Tx) error { 1240 b, err := tx.CreateBucketIfNotExists([]byte("woojits")) 1241 if err != nil { 1242 t.Fatal(err) 1243 } 1244 b.FillPercent = 0.9 1245 for _, j := range rand.Perm(100) { 1246 index := (j * 10000) + i 1247 if err := b.Put([]byte(fmt.Sprintf("%d000000000000000", index)), []byte("0000000000")); err != nil { 1248 t.Fatal(err) 1249 } 1250 count++ 1251 } 1252 return nil 1253 }); err != nil { 1254 t.Fatal(err) 1255 } 1256 } 1257 1258 db.MustCheck() 1259 1260 if err := db.View(func(tx *bolt.Tx) error { 1261 stats := tx.Bucket([]byte("woojits")).Stats() 1262 if stats.KeyN != 100000 { 1263 t.Fatalf("unexpected KeyN: %d", stats.KeyN) 1264 } 1265 1266 if stats.BranchPageN != 98 { 1267 t.Fatalf("unexpected BranchPageN: %d", stats.BranchPageN) 1268 } else if stats.BranchOverflowN != 0 { 1269 t.Fatalf("unexpected BranchOverflowN: %d", stats.BranchOverflowN) 1270 } else if stats.BranchInuse != 130984 { 1271 t.Fatalf("unexpected BranchInuse: %d", stats.BranchInuse) 1272 } else if stats.BranchAlloc != 401408 { 1273 t.Fatalf("unexpected BranchAlloc: %d", stats.BranchAlloc) 1274 } 1275 1276 if stats.LeafPageN != 3412 { 1277 t.Fatalf("unexpected LeafPageN: %d", stats.LeafPageN) 1278 } else if stats.LeafOverflowN != 0 { 1279 t.Fatalf("unexpected LeafOverflowN: %d", stats.LeafOverflowN) 1280 } else if stats.LeafInuse != 4742482 { 1281 t.Fatalf("unexpected LeafInuse: %d", stats.LeafInuse) 1282 } else if stats.LeafAlloc != 13975552 { 1283 t.Fatalf("unexpected LeafAlloc: %d", stats.LeafAlloc) 1284 } 1285 return nil 1286 }); err != nil { 1287 t.Fatal(err) 1288 } 1289} 1290 1291// Ensure a bucket can calculate stats. 1292func TestBucket_Stats_Small(t *testing.T) { 1293 db := MustOpenDB() 1294 defer db.MustClose() 1295 1296 if err := db.Update(func(tx *bolt.Tx) error { 1297 // Add a bucket that fits on a single root leaf. 1298 b, err := tx.CreateBucket([]byte("whozawhats")) 1299 if err != nil { 1300 t.Fatal(err) 1301 } 1302 if err := b.Put([]byte("foo"), []byte("bar")); err != nil { 1303 t.Fatal(err) 1304 } 1305 1306 return nil 1307 }); err != nil { 1308 t.Fatal(err) 1309 } 1310 1311 db.MustCheck() 1312 1313 if err := db.View(func(tx *bolt.Tx) error { 1314 b := tx.Bucket([]byte("whozawhats")) 1315 stats := b.Stats() 1316 if stats.BranchPageN != 0 { 1317 t.Fatalf("unexpected BranchPageN: %d", stats.BranchPageN) 1318 } else if stats.BranchOverflowN != 0 { 1319 t.Fatalf("unexpected BranchOverflowN: %d", stats.BranchOverflowN) 1320 } else if stats.LeafPageN != 0 { 1321 t.Fatalf("unexpected LeafPageN: %d", stats.LeafPageN) 1322 } else if stats.LeafOverflowN != 0 { 1323 t.Fatalf("unexpected LeafOverflowN: %d", stats.LeafOverflowN) 1324 } else if stats.KeyN != 1 { 1325 t.Fatalf("unexpected KeyN: %d", stats.KeyN) 1326 } else if stats.Depth != 1 { 1327 t.Fatalf("unexpected Depth: %d", stats.Depth) 1328 } else if stats.BranchInuse != 0 { 1329 t.Fatalf("unexpected BranchInuse: %d", stats.BranchInuse) 1330 } else if stats.LeafInuse != 0 { 1331 t.Fatalf("unexpected LeafInuse: %d", stats.LeafInuse) 1332 } 1333 1334 if os.Getpagesize() == 4096 { 1335 if stats.BranchAlloc != 0 { 1336 t.Fatalf("unexpected BranchAlloc: %d", stats.BranchAlloc) 1337 } else if stats.LeafAlloc != 0 { 1338 t.Fatalf("unexpected LeafAlloc: %d", stats.LeafAlloc) 1339 } 1340 } 1341 1342 if stats.BucketN != 1 { 1343 t.Fatalf("unexpected BucketN: %d", stats.BucketN) 1344 } else if stats.InlineBucketN != 1 { 1345 t.Fatalf("unexpected InlineBucketN: %d", stats.InlineBucketN) 1346 } else if stats.InlineBucketInuse != 16+16+6 { 1347 t.Fatalf("unexpected InlineBucketInuse: %d", stats.InlineBucketInuse) 1348 } 1349 1350 return nil 1351 }); err != nil { 1352 t.Fatal(err) 1353 } 1354} 1355 1356func TestBucket_Stats_EmptyBucket(t *testing.T) { 1357 db := MustOpenDB() 1358 defer db.MustClose() 1359 1360 if err := db.Update(func(tx *bolt.Tx) error { 1361 // Add a bucket that fits on a single root leaf. 1362 if _, err := tx.CreateBucket([]byte("whozawhats")); err != nil { 1363 t.Fatal(err) 1364 } 1365 return nil 1366 }); err != nil { 1367 t.Fatal(err) 1368 } 1369 1370 db.MustCheck() 1371 1372 if err := db.View(func(tx *bolt.Tx) error { 1373 b := tx.Bucket([]byte("whozawhats")) 1374 stats := b.Stats() 1375 if stats.BranchPageN != 0 { 1376 t.Fatalf("unexpected BranchPageN: %d", stats.BranchPageN) 1377 } else if stats.BranchOverflowN != 0 { 1378 t.Fatalf("unexpected BranchOverflowN: %d", stats.BranchOverflowN) 1379 } else if stats.LeafPageN != 0 { 1380 t.Fatalf("unexpected LeafPageN: %d", stats.LeafPageN) 1381 } else if stats.LeafOverflowN != 0 { 1382 t.Fatalf("unexpected LeafOverflowN: %d", stats.LeafOverflowN) 1383 } else if stats.KeyN != 0 { 1384 t.Fatalf("unexpected KeyN: %d", stats.KeyN) 1385 } else if stats.Depth != 1 { 1386 t.Fatalf("unexpected Depth: %d", stats.Depth) 1387 } else if stats.BranchInuse != 0 { 1388 t.Fatalf("unexpected BranchInuse: %d", stats.BranchInuse) 1389 } else if stats.LeafInuse != 0 { 1390 t.Fatalf("unexpected LeafInuse: %d", stats.LeafInuse) 1391 } 1392 1393 if os.Getpagesize() == 4096 { 1394 if stats.BranchAlloc != 0 { 1395 t.Fatalf("unexpected BranchAlloc: %d", stats.BranchAlloc) 1396 } else if stats.LeafAlloc != 0 { 1397 t.Fatalf("unexpected LeafAlloc: %d", stats.LeafAlloc) 1398 } 1399 } 1400 1401 if stats.BucketN != 1 { 1402 t.Fatalf("unexpected BucketN: %d", stats.BucketN) 1403 } else if stats.InlineBucketN != 1 { 1404 t.Fatalf("unexpected InlineBucketN: %d", stats.InlineBucketN) 1405 } else if stats.InlineBucketInuse != 16 { 1406 t.Fatalf("unexpected InlineBucketInuse: %d", stats.InlineBucketInuse) 1407 } 1408 1409 return nil 1410 }); err != nil { 1411 t.Fatal(err) 1412 } 1413} 1414 1415// Ensure a bucket can calculate stats. 1416func TestBucket_Stats_Nested(t *testing.T) { 1417 db := MustOpenDB() 1418 defer db.MustClose() 1419 1420 if err := db.Update(func(tx *bolt.Tx) error { 1421 b, err := tx.CreateBucket([]byte("foo")) 1422 if err != nil { 1423 t.Fatal(err) 1424 } 1425 for i := 0; i < 100; i++ { 1426 if err := b.Put([]byte(fmt.Sprintf("%02d", i)), []byte(fmt.Sprintf("%02d", i))); err != nil { 1427 t.Fatal(err) 1428 } 1429 } 1430 1431 bar, err := b.CreateBucket([]byte("bar")) 1432 if err != nil { 1433 t.Fatal(err) 1434 } 1435 for i := 0; i < 10; i++ { 1436 if err := bar.Put([]byte(strconv.Itoa(i)), []byte(strconv.Itoa(i))); err != nil { 1437 t.Fatal(err) 1438 } 1439 } 1440 1441 baz, err := bar.CreateBucket([]byte("baz")) 1442 if err != nil { 1443 t.Fatal(err) 1444 } 1445 for i := 0; i < 10; i++ { 1446 if err := baz.Put([]byte(strconv.Itoa(i)), []byte(strconv.Itoa(i))); err != nil { 1447 t.Fatal(err) 1448 } 1449 } 1450 1451 return nil 1452 }); err != nil { 1453 t.Fatal(err) 1454 } 1455 1456 db.MustCheck() 1457 1458 if err := db.View(func(tx *bolt.Tx) error { 1459 b := tx.Bucket([]byte("foo")) 1460 stats := b.Stats() 1461 if stats.BranchPageN != 0 { 1462 t.Fatalf("unexpected BranchPageN: %d", stats.BranchPageN) 1463 } else if stats.BranchOverflowN != 0 { 1464 t.Fatalf("unexpected BranchOverflowN: %d", stats.BranchOverflowN) 1465 } else if stats.LeafPageN != 2 { 1466 t.Fatalf("unexpected LeafPageN: %d", stats.LeafPageN) 1467 } else if stats.LeafOverflowN != 0 { 1468 t.Fatalf("unexpected LeafOverflowN: %d", stats.LeafOverflowN) 1469 } else if stats.KeyN != 122 { 1470 t.Fatalf("unexpected KeyN: %d", stats.KeyN) 1471 } else if stats.Depth != 3 { 1472 t.Fatalf("unexpected Depth: %d", stats.Depth) 1473 } else if stats.BranchInuse != 0 { 1474 t.Fatalf("unexpected BranchInuse: %d", stats.BranchInuse) 1475 } 1476 1477 foo := 16 // foo (pghdr) 1478 foo += 101 * 16 // foo leaf elements 1479 foo += 100*2 + 100*2 // foo leaf key/values 1480 foo += 3 + 16 // foo -> bar key/value 1481 1482 bar := 16 // bar (pghdr) 1483 bar += 11 * 16 // bar leaf elements 1484 bar += 10 + 10 // bar leaf key/values 1485 bar += 3 + 16 // bar -> baz key/value 1486 1487 baz := 16 // baz (inline) (pghdr) 1488 baz += 10 * 16 // baz leaf elements 1489 baz += 10 + 10 // baz leaf key/values 1490 1491 if stats.LeafInuse != foo+bar+baz { 1492 t.Fatalf("unexpected LeafInuse: %d", stats.LeafInuse) 1493 } 1494 1495 if os.Getpagesize() == 4096 { 1496 if stats.BranchAlloc != 0 { 1497 t.Fatalf("unexpected BranchAlloc: %d", stats.BranchAlloc) 1498 } else if stats.LeafAlloc != 8192 { 1499 t.Fatalf("unexpected LeafAlloc: %d", stats.LeafAlloc) 1500 } 1501 } 1502 1503 if stats.BucketN != 3 { 1504 t.Fatalf("unexpected BucketN: %d", stats.BucketN) 1505 } else if stats.InlineBucketN != 1 { 1506 t.Fatalf("unexpected InlineBucketN: %d", stats.InlineBucketN) 1507 } else if stats.InlineBucketInuse != baz { 1508 t.Fatalf("unexpected InlineBucketInuse: %d", stats.InlineBucketInuse) 1509 } 1510 1511 return nil 1512 }); err != nil { 1513 t.Fatal(err) 1514 } 1515} 1516 1517// Ensure a large bucket can calculate stats. 1518func TestBucket_Stats_Large(t *testing.T) { 1519 if testing.Short() { 1520 t.Skip("skipping test in short mode.") 1521 } 1522 1523 db := MustOpenDB() 1524 defer db.MustClose() 1525 1526 var index int 1527 for i := 0; i < 100; i++ { 1528 // Add bucket with lots of keys. 1529 if err := db.Update(func(tx *bolt.Tx) error { 1530 b, err := tx.CreateBucketIfNotExists([]byte("widgets")) 1531 if err != nil { 1532 t.Fatal(err) 1533 } 1534 for i := 0; i < 1000; i++ { 1535 if err := b.Put([]byte(strconv.Itoa(index)), []byte(strconv.Itoa(index))); err != nil { 1536 t.Fatal(err) 1537 } 1538 index++ 1539 } 1540 return nil 1541 }); err != nil { 1542 t.Fatal(err) 1543 } 1544 } 1545 1546 db.MustCheck() 1547 1548 if err := db.View(func(tx *bolt.Tx) error { 1549 stats := tx.Bucket([]byte("widgets")).Stats() 1550 if stats.BranchPageN != 13 { 1551 t.Fatalf("unexpected BranchPageN: %d", stats.BranchPageN) 1552 } else if stats.BranchOverflowN != 0 { 1553 t.Fatalf("unexpected BranchOverflowN: %d", stats.BranchOverflowN) 1554 } else if stats.LeafPageN != 1196 { 1555 t.Fatalf("unexpected LeafPageN: %d", stats.LeafPageN) 1556 } else if stats.LeafOverflowN != 0 { 1557 t.Fatalf("unexpected LeafOverflowN: %d", stats.LeafOverflowN) 1558 } else if stats.KeyN != 100000 { 1559 t.Fatalf("unexpected KeyN: %d", stats.KeyN) 1560 } else if stats.Depth != 3 { 1561 t.Fatalf("unexpected Depth: %d", stats.Depth) 1562 } else if stats.BranchInuse != 25257 { 1563 t.Fatalf("unexpected BranchInuse: %d", stats.BranchInuse) 1564 } else if stats.LeafInuse != 2596916 { 1565 t.Fatalf("unexpected LeafInuse: %d", stats.LeafInuse) 1566 } 1567 1568 if os.Getpagesize() == 4096 { 1569 if stats.BranchAlloc != 53248 { 1570 t.Fatalf("unexpected BranchAlloc: %d", stats.BranchAlloc) 1571 } else if stats.LeafAlloc != 4898816 { 1572 t.Fatalf("unexpected LeafAlloc: %d", stats.LeafAlloc) 1573 } 1574 } 1575 1576 if stats.BucketN != 1 { 1577 t.Fatalf("unexpected BucketN: %d", stats.BucketN) 1578 } else if stats.InlineBucketN != 0 { 1579 t.Fatalf("unexpected InlineBucketN: %d", stats.InlineBucketN) 1580 } else if stats.InlineBucketInuse != 0 { 1581 t.Fatalf("unexpected InlineBucketInuse: %d", stats.InlineBucketInuse) 1582 } 1583 1584 return nil 1585 }); err != nil { 1586 t.Fatal(err) 1587 } 1588} 1589 1590// Ensure that a bucket can write random keys and values across multiple transactions. 1591func TestBucket_Put_Single(t *testing.T) { 1592 if testing.Short() { 1593 t.Skip("skipping test in short mode.") 1594 } 1595 1596 index := 0 1597 if err := quick.Check(func(items testdata) bool { 1598 db := MustOpenDB() 1599 defer db.MustClose() 1600 1601 m := make(map[string][]byte) 1602 1603 if err := db.Update(func(tx *bolt.Tx) error { 1604 if _, err := tx.CreateBucket([]byte("widgets")); err != nil { 1605 t.Fatal(err) 1606 } 1607 return nil 1608 }); err != nil { 1609 t.Fatal(err) 1610 } 1611 1612 for _, item := range items { 1613 if err := db.Update(func(tx *bolt.Tx) error { 1614 if err := tx.Bucket([]byte("widgets")).Put(item.Key, item.Value); err != nil { 1615 panic("put error: " + err.Error()) 1616 } 1617 m[string(item.Key)] = item.Value 1618 return nil 1619 }); err != nil { 1620 t.Fatal(err) 1621 } 1622 1623 // Verify all key/values so far. 1624 if err := db.View(func(tx *bolt.Tx) error { 1625 i := 0 1626 for k, v := range m { 1627 value := tx.Bucket([]byte("widgets")).Get([]byte(k)) 1628 if !bytes.Equal(value, v) { 1629 t.Logf("value mismatch [run %d] (%d of %d):\nkey: %x\ngot: %x\nexp: %x", index, i, len(m), []byte(k), value, v) 1630 db.CopyTempFile() 1631 t.FailNow() 1632 } 1633 i++ 1634 } 1635 return nil 1636 }); err != nil { 1637 t.Fatal(err) 1638 } 1639 } 1640 1641 index++ 1642 return true 1643 }, nil); err != nil { 1644 t.Error(err) 1645 } 1646} 1647 1648// Ensure that a transaction can insert multiple key/value pairs at once. 1649func TestBucket_Put_Multiple(t *testing.T) { 1650 if testing.Short() { 1651 t.Skip("skipping test in short mode.") 1652 } 1653 1654 if err := quick.Check(func(items testdata) bool { 1655 db := MustOpenDB() 1656 defer db.MustClose() 1657 1658 // Bulk insert all values. 1659 if err := db.Update(func(tx *bolt.Tx) error { 1660 if _, err := tx.CreateBucket([]byte("widgets")); err != nil { 1661 t.Fatal(err) 1662 } 1663 return nil 1664 }); err != nil { 1665 t.Fatal(err) 1666 } 1667 1668 if err := db.Update(func(tx *bolt.Tx) error { 1669 b := tx.Bucket([]byte("widgets")) 1670 for _, item := range items { 1671 if err := b.Put(item.Key, item.Value); err != nil { 1672 t.Fatal(err) 1673 } 1674 } 1675 return nil 1676 }); err != nil { 1677 t.Fatal(err) 1678 } 1679 1680 // Verify all items exist. 1681 if err := db.View(func(tx *bolt.Tx) error { 1682 b := tx.Bucket([]byte("widgets")) 1683 for _, item := range items { 1684 value := b.Get(item.Key) 1685 if !bytes.Equal(item.Value, value) { 1686 db.CopyTempFile() 1687 t.Fatalf("exp=%x; got=%x", item.Value, value) 1688 } 1689 } 1690 return nil 1691 }); err != nil { 1692 t.Fatal(err) 1693 } 1694 1695 return true 1696 }, qconfig()); err != nil { 1697 t.Error(err) 1698 } 1699} 1700 1701// Ensure that a transaction can delete all key/value pairs and return to a single leaf page. 1702func TestBucket_Delete_Quick(t *testing.T) { 1703 if testing.Short() { 1704 t.Skip("skipping test in short mode.") 1705 } 1706 1707 if err := quick.Check(func(items testdata) bool { 1708 db := MustOpenDB() 1709 defer db.MustClose() 1710 1711 // Bulk insert all values. 1712 if err := db.Update(func(tx *bolt.Tx) error { 1713 if _, err := tx.CreateBucket([]byte("widgets")); err != nil { 1714 t.Fatal(err) 1715 } 1716 return nil 1717 }); err != nil { 1718 t.Fatal(err) 1719 } 1720 1721 if err := db.Update(func(tx *bolt.Tx) error { 1722 b := tx.Bucket([]byte("widgets")) 1723 for _, item := range items { 1724 if err := b.Put(item.Key, item.Value); err != nil { 1725 t.Fatal(err) 1726 } 1727 } 1728 return nil 1729 }); err != nil { 1730 t.Fatal(err) 1731 } 1732 1733 // Remove items one at a time and check consistency. 1734 for _, item := range items { 1735 if err := db.Update(func(tx *bolt.Tx) error { 1736 return tx.Bucket([]byte("widgets")).Delete(item.Key) 1737 }); err != nil { 1738 t.Fatal(err) 1739 } 1740 } 1741 1742 // Anything before our deletion index should be nil. 1743 if err := db.View(func(tx *bolt.Tx) error { 1744 if err := tx.Bucket([]byte("widgets")).ForEach(func(k, v []byte) error { 1745 t.Fatalf("bucket should be empty; found: %06x", trunc(k, 3)) 1746 return nil 1747 }); err != nil { 1748 t.Fatal(err) 1749 } 1750 return nil 1751 }); err != nil { 1752 t.Fatal(err) 1753 } 1754 1755 return true 1756 }, qconfig()); err != nil { 1757 t.Error(err) 1758 } 1759} 1760 1761func ExampleBucket_Put() { 1762 // Open the database. 1763 db, err := bolt.Open(tempfile(), 0666, nil) 1764 if err != nil { 1765 log.Fatal(err) 1766 } 1767 defer os.Remove(db.Path()) 1768 1769 // Start a write transaction. 1770 if err := db.Update(func(tx *bolt.Tx) error { 1771 // Create a bucket. 1772 b, err := tx.CreateBucket([]byte("widgets")) 1773 if err != nil { 1774 return err 1775 } 1776 1777 // Set the value "bar" for the key "foo". 1778 if err := b.Put([]byte("foo"), []byte("bar")); err != nil { 1779 return err 1780 } 1781 return nil 1782 }); err != nil { 1783 log.Fatal(err) 1784 } 1785 1786 // Read value back in a different read-only transaction. 1787 if err := db.View(func(tx *bolt.Tx) error { 1788 value := tx.Bucket([]byte("widgets")).Get([]byte("foo")) 1789 fmt.Printf("The value of 'foo' is: %s\n", value) 1790 return nil 1791 }); err != nil { 1792 log.Fatal(err) 1793 } 1794 1795 // Close database to release file lock. 1796 if err := db.Close(); err != nil { 1797 log.Fatal(err) 1798 } 1799 1800 // Output: 1801 // The value of 'foo' is: bar 1802} 1803 1804func ExampleBucket_Delete() { 1805 // Open the database. 1806 db, err := bolt.Open(tempfile(), 0666, nil) 1807 if err != nil { 1808 log.Fatal(err) 1809 } 1810 defer os.Remove(db.Path()) 1811 1812 // Start a write transaction. 1813 if err := db.Update(func(tx *bolt.Tx) error { 1814 // Create a bucket. 1815 b, err := tx.CreateBucket([]byte("widgets")) 1816 if err != nil { 1817 return err 1818 } 1819 1820 // Set the value "bar" for the key "foo". 1821 if err := b.Put([]byte("foo"), []byte("bar")); err != nil { 1822 return err 1823 } 1824 1825 // Retrieve the key back from the database and verify it. 1826 value := b.Get([]byte("foo")) 1827 fmt.Printf("The value of 'foo' was: %s\n", value) 1828 1829 return nil 1830 }); err != nil { 1831 log.Fatal(err) 1832 } 1833 1834 // Delete the key in a different write transaction. 1835 if err := db.Update(func(tx *bolt.Tx) error { 1836 return tx.Bucket([]byte("widgets")).Delete([]byte("foo")) 1837 }); err != nil { 1838 log.Fatal(err) 1839 } 1840 1841 // Retrieve the key again. 1842 if err := db.View(func(tx *bolt.Tx) error { 1843 value := tx.Bucket([]byte("widgets")).Get([]byte("foo")) 1844 if value == nil { 1845 fmt.Printf("The value of 'foo' is now: nil\n") 1846 } 1847 return nil 1848 }); err != nil { 1849 log.Fatal(err) 1850 } 1851 1852 // Close database to release file lock. 1853 if err := db.Close(); err != nil { 1854 log.Fatal(err) 1855 } 1856 1857 // Output: 1858 // The value of 'foo' was: bar 1859 // The value of 'foo' is now: nil 1860} 1861 1862func ExampleBucket_ForEach() { 1863 // Open the database. 1864 db, err := bolt.Open(tempfile(), 0666, nil) 1865 if err != nil { 1866 log.Fatal(err) 1867 } 1868 defer os.Remove(db.Path()) 1869 1870 // Insert data into a bucket. 1871 if err := db.Update(func(tx *bolt.Tx) error { 1872 b, err := tx.CreateBucket([]byte("animals")) 1873 if err != nil { 1874 return err 1875 } 1876 1877 if err := b.Put([]byte("dog"), []byte("fun")); err != nil { 1878 return err 1879 } 1880 if err := b.Put([]byte("cat"), []byte("lame")); err != nil { 1881 return err 1882 } 1883 if err := b.Put([]byte("liger"), []byte("awesome")); err != nil { 1884 return err 1885 } 1886 1887 // Iterate over items in sorted key order. 1888 if err := b.ForEach(func(k, v []byte) error { 1889 fmt.Printf("A %s is %s.\n", k, v) 1890 return nil 1891 }); err != nil { 1892 return err 1893 } 1894 1895 return nil 1896 }); err != nil { 1897 log.Fatal(err) 1898 } 1899 1900 // Close database to release file lock. 1901 if err := db.Close(); err != nil { 1902 log.Fatal(err) 1903 } 1904 1905 // Output: 1906 // A cat is lame. 1907 // A dog is fun. 1908 // A liger is awesome. 1909} 1910