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