diff --git a/bucket.go b/bucket.go index 1ef0d5e..2b0e340 100644 --- a/bucket.go +++ b/bucket.go @@ -634,7 +634,7 @@ func (b *Bucket) free() { var tx = b.tx b.forEachPageNode(func(p *page, n *node, _ int) { if p != nil { - tx.db.freelist.free(tx.id(), p) + tx.db.freelist.free(tx.meta.txid, p) } else { n.free() } diff --git a/bucket_test.go b/bucket_test.go index 6e5aed7..6923b6c 100644 --- a/bucket_test.go +++ b/bucket_test.go @@ -1,4 +1,4 @@ -package bolt +package bolt_test import ( "bytes" @@ -12,6 +12,7 @@ import ( "testing" "testing/quick" + "github.com/boltdb/bolt" "github.com/stretchr/testify/assert" ) @@ -19,7 +20,7 @@ import ( func TestBucket_Get_NonExistent(t *testing.T) { db := NewTestDB() defer db.Close() - db.Update(func(tx *Tx) error { + db.Update(func(tx *bolt.Tx) error { tx.CreateBucket([]byte("widgets")) value := tx.Bucket([]byte("widgets")).Get([]byte("foo")) assert.Nil(t, value) @@ -31,7 +32,7 @@ func TestBucket_Get_NonExistent(t *testing.T) { func TestBucket_Get_FromNode(t *testing.T) { db := NewTestDB() defer db.Close() - db.Update(func(tx *Tx) error { + db.Update(func(tx *bolt.Tx) error { tx.CreateBucket([]byte("widgets")) b := tx.Bucket([]byte("widgets")) b.Put([]byte("foo"), []byte("bar")) @@ -45,7 +46,7 @@ func TestBucket_Get_FromNode(t *testing.T) { func TestBucket_Get_IncompatibleValue(t *testing.T) { db := NewTestDB() defer db.Close() - db.Update(func(tx *Tx) error { + db.Update(func(tx *bolt.Tx) error { tx.CreateBucket([]byte("widgets")) _, err := tx.Bucket([]byte("widgets")).CreateBucket([]byte("foo")) assert.NoError(t, err) @@ -58,7 +59,7 @@ func TestBucket_Get_IncompatibleValue(t *testing.T) { func TestBucket_Put(t *testing.T) { db := NewTestDB() defer db.Close() - db.Update(func(tx *Tx) error { + db.Update(func(tx *bolt.Tx) error { tx.CreateBucket([]byte("widgets")) err := tx.Bucket([]byte("widgets")).Put([]byte("foo"), []byte("bar")) assert.NoError(t, err) @@ -72,7 +73,7 @@ func TestBucket_Put(t *testing.T) { func TestBucket_Put_Repeat(t *testing.T) { db := NewTestDB() defer db.Close() - db.Update(func(tx *Tx) error { + db.Update(func(tx *bolt.Tx) error { tx.CreateBucket([]byte("widgets")) b := tx.Bucket([]byte("widgets")) assert.NoError(t, b.Put([]byte("foo"), []byte("bar"))) @@ -89,7 +90,7 @@ func TestBucket_Put_Large(t *testing.T) { defer db.Close() count, factor := 100, 200 - db.Update(func(tx *Tx) error { + db.Update(func(tx *bolt.Tx) error { tx.CreateBucket([]byte("widgets")) b := tx.Bucket([]byte("widgets")) for i := 1; i < count; i++ { @@ -97,7 +98,7 @@ func TestBucket_Put_Large(t *testing.T) { } return nil }) - db.View(func(tx *Tx) error { + db.View(func(tx *bolt.Tx) error { b := tx.Bucket([]byte("widgets")) for i := 1; i < count; i++ { value := b.Get([]byte(strings.Repeat("0", i*factor))) @@ -120,7 +121,7 @@ func TestDB_Put_VeryLarge(t *testing.T) { defer db.Close() for i := 0; i < n; i += batchN { - err := db.Update(func(tx *Tx) error { + err := db.Update(func(tx *bolt.Tx) error { b, _ := tx.CreateBucketIfNotExists([]byte("widgets")) for j := 0; j < batchN; j++ { k, v := make([]byte, ksize), make([]byte, vsize) @@ -137,11 +138,11 @@ func TestDB_Put_VeryLarge(t *testing.T) { func TestBucket_Put_IncompatibleValue(t *testing.T) { db := NewTestDB() defer db.Close() - db.Update(func(tx *Tx) error { + db.Update(func(tx *bolt.Tx) error { tx.CreateBucket([]byte("widgets")) _, err := tx.Bucket([]byte("widgets")).CreateBucket([]byte("foo")) assert.NoError(t, err) - assert.Equal(t, ErrIncompatibleValue, tx.Bucket([]byte("widgets")).Put([]byte("foo"), []byte("bar"))) + assert.Equal(t, bolt.ErrIncompatibleValue, tx.Bucket([]byte("widgets")).Put([]byte("foo"), []byte("bar"))) return nil }) } @@ -154,22 +155,22 @@ func TestBucket_Put_Closed(t *testing.T) { tx.CreateBucket([]byte("widgets")) b := tx.Bucket([]byte("widgets")) tx.Rollback() - assert.Equal(t, ErrTxClosed, b.Put([]byte("foo"), []byte("bar"))) + assert.Equal(t, bolt.ErrTxClosed, b.Put([]byte("foo"), []byte("bar"))) } // Ensure that setting a value on a read-only bucket returns an error. func TestBucket_Put_ReadOnly(t *testing.T) { db := NewTestDB() defer db.Close() - db.Update(func(tx *Tx) error { + db.Update(func(tx *bolt.Tx) error { _, err := tx.CreateBucket([]byte("widgets")) assert.NoError(t, err) return nil }) - db.View(func(tx *Tx) error { + db.View(func(tx *bolt.Tx) error { b := tx.Bucket([]byte("widgets")) err := b.Put([]byte("foo"), []byte("bar")) - assert.Equal(t, err, ErrTxNotWritable) + assert.Equal(t, err, bolt.ErrTxNotWritable) return nil }) } @@ -178,7 +179,7 @@ func TestBucket_Put_ReadOnly(t *testing.T) { func TestBucket_Delete(t *testing.T) { db := NewTestDB() defer db.Close() - db.Update(func(tx *Tx) error { + db.Update(func(tx *bolt.Tx) error { tx.CreateBucket([]byte("widgets")) tx.Bucket([]byte("widgets")).Put([]byte("foo"), []byte("bar")) err := tx.Bucket([]byte("widgets")).Delete([]byte("foo")) @@ -193,21 +194,21 @@ func TestBucket_Delete(t *testing.T) { func TestBucket_Delete_Large(t *testing.T) { db := NewTestDB() defer db.Close() - db.Update(func(tx *Tx) error { + db.Update(func(tx *bolt.Tx) error { var b, _ = tx.CreateBucket([]byte("widgets")) for i := 0; i < 100; i++ { assert.NoError(t, b.Put([]byte(strconv.Itoa(i)), []byte(strings.Repeat("*", 1024)))) } return nil }) - db.Update(func(tx *Tx) error { + db.Update(func(tx *bolt.Tx) error { var b = tx.Bucket([]byte("widgets")) for i := 0; i < 100; i++ { assert.NoError(t, b.Delete([]byte(strconv.Itoa(i)))) } return nil }) - db.View(func(tx *Tx) error { + db.View(func(tx *bolt.Tx) error { var b = tx.Bucket([]byte("widgets")) for i := 0; i < 100; i++ { assert.Nil(t, b.Get([]byte(strconv.Itoa(i)))) @@ -226,7 +227,7 @@ func TestBucket_Delete_FreelistOverflow(t *testing.T) { defer db.Close() k := make([]byte, 16) for i := uint64(0); i < 10000; i++ { - err := db.Update(func(tx *Tx) error { + err := db.Update(func(tx *bolt.Tx) error { b, err := tx.CreateBucketIfNotExists([]byte("0")) if err != nil { t.Fatalf("bucket error: %s", err) @@ -249,7 +250,7 @@ func TestBucket_Delete_FreelistOverflow(t *testing.T) { } // Delete all of them in one large transaction - err := db.Update(func(tx *Tx) error { + err := db.Update(func(tx *bolt.Tx) error { b := tx.Bucket([]byte("0")) c := b.Cursor() for k, _ := c.First(); k != nil; k, _ = c.Next() { @@ -266,7 +267,7 @@ func TestBucket_Delete_FreelistOverflow(t *testing.T) { func TestBucket_Nested(t *testing.T) { db := NewTestDB() defer db.Close() - db.Update(func(tx *Tx) error { + db.Update(func(tx *bolt.Tx) error { // Create a widgets bucket. b, err := tx.CreateBucket([]byte("widgets")) assert.NoError(t, err) @@ -283,7 +284,7 @@ func TestBucket_Nested(t *testing.T) { db.MustCheck() // Update widgets/bar. - db.Update(func(tx *Tx) error { + db.Update(func(tx *bolt.Tx) error { var b = tx.Bucket([]byte("widgets")) assert.NoError(t, b.Put([]byte("bar"), []byte("xxxx"))) return nil @@ -291,7 +292,7 @@ func TestBucket_Nested(t *testing.T) { db.MustCheck() // Cause a split. - db.Update(func(tx *Tx) error { + db.Update(func(tx *bolt.Tx) error { var b = tx.Bucket([]byte("widgets")) for i := 0; i < 10000; i++ { assert.NoError(t, b.Put([]byte(strconv.Itoa(i)), []byte(strconv.Itoa(i)))) @@ -301,7 +302,7 @@ func TestBucket_Nested(t *testing.T) { db.MustCheck() // Insert into widgets/foo/baz. - db.Update(func(tx *Tx) error { + db.Update(func(tx *bolt.Tx) error { var b = tx.Bucket([]byte("widgets")) assert.NoError(t, b.Bucket([]byte("foo")).Put([]byte("baz"), []byte("yyyy"))) return nil @@ -309,7 +310,7 @@ func TestBucket_Nested(t *testing.T) { db.MustCheck() // Verify. - db.View(func(tx *Tx) error { + db.View(func(tx *bolt.Tx) error { var b = tx.Bucket([]byte("widgets")) assert.Equal(t, []byte("yyyy"), b.Bucket([]byte("foo")).Get([]byte("baz"))) assert.Equal(t, []byte("xxxx"), b.Get([]byte("bar"))) @@ -324,12 +325,12 @@ func TestBucket_Nested(t *testing.T) { func TestBucket_Delete_Bucket(t *testing.T) { db := NewTestDB() defer db.Close() - db.Update(func(tx *Tx) error { + db.Update(func(tx *bolt.Tx) error { tx.CreateBucket([]byte("widgets")) b := tx.Bucket([]byte("widgets")) _, err := b.CreateBucket([]byte("foo")) assert.NoError(t, err) - assert.Equal(t, ErrIncompatibleValue, b.Delete([]byte("foo"))) + assert.Equal(t, bolt.ErrIncompatibleValue, b.Delete([]byte("foo"))) return nil }) } @@ -338,14 +339,14 @@ func TestBucket_Delete_Bucket(t *testing.T) { func TestBucket_Delete_ReadOnly(t *testing.T) { db := NewTestDB() defer db.Close() - db.Update(func(tx *Tx) error { + db.Update(func(tx *bolt.Tx) error { tx.CreateBucket([]byte("widgets")) return nil }) - db.View(func(tx *Tx) error { + db.View(func(tx *bolt.Tx) error { b := tx.Bucket([]byte("widgets")) err := b.Delete([]byte("foo")) - assert.Equal(t, err, ErrTxNotWritable) + assert.Equal(t, err, bolt.ErrTxNotWritable) return nil }) } @@ -358,14 +359,14 @@ func TestBucket_Delete_Closed(t *testing.T) { tx.CreateBucket([]byte("widgets")) b := tx.Bucket([]byte("widgets")) tx.Rollback() - assert.Equal(t, ErrTxClosed, b.Delete([]byte("foo"))) + assert.Equal(t, bolt.ErrTxClosed, b.Delete([]byte("foo"))) } // Ensure that deleting a bucket causes nested buckets to be deleted. func TestBucket_DeleteBucket_Nested(t *testing.T) { db := NewTestDB() defer db.Close() - db.Update(func(tx *Tx) error { + db.Update(func(tx *bolt.Tx) error { tx.CreateBucket([]byte("widgets")) _, err := tx.Bucket([]byte("widgets")).CreateBucket([]byte("foo")) assert.NoError(t, err) @@ -381,7 +382,7 @@ func TestBucket_DeleteBucket_Nested(t *testing.T) { func TestBucket_DeleteBucket_Nested2(t *testing.T) { db := NewTestDB() defer db.Close() - db.Update(func(tx *Tx) error { + db.Update(func(tx *bolt.Tx) error { tx.CreateBucket([]byte("widgets")) _, err := tx.Bucket([]byte("widgets")).CreateBucket([]byte("foo")) assert.NoError(t, err) @@ -390,7 +391,7 @@ func TestBucket_DeleteBucket_Nested2(t *testing.T) { assert.NoError(t, tx.Bucket([]byte("widgets")).Bucket([]byte("foo")).Bucket([]byte("bar")).Put([]byte("baz"), []byte("bat"))) return nil }) - db.Update(func(tx *Tx) error { + db.Update(func(tx *bolt.Tx) error { assert.NotNil(t, tx.Bucket([]byte("widgets"))) assert.NotNil(t, tx.Bucket([]byte("widgets")).Bucket([]byte("foo"))) assert.NotNil(t, tx.Bucket([]byte("widgets")).Bucket([]byte("foo")).Bucket([]byte("bar"))) @@ -398,7 +399,7 @@ func TestBucket_DeleteBucket_Nested2(t *testing.T) { assert.NoError(t, tx.DeleteBucket([]byte("widgets"))) return nil }) - db.View(func(tx *Tx) error { + db.View(func(tx *bolt.Tx) error { assert.Nil(t, tx.Bucket([]byte("widgets"))) return nil }) @@ -408,7 +409,7 @@ func TestBucket_DeleteBucket_Nested2(t *testing.T) { func TestBucket_DeleteBucket_Large(t *testing.T) { db := NewTestDB() defer db.Close() - db.Update(func(tx *Tx) error { + db.Update(func(tx *bolt.Tx) error { _, err := tx.CreateBucket([]byte("widgets")) assert.NoError(t, err) _, err = tx.Bucket([]byte("widgets")).CreateBucket([]byte("foo")) @@ -419,7 +420,7 @@ func TestBucket_DeleteBucket_Large(t *testing.T) { } return nil }) - db.Update(func(tx *Tx) error { + db.Update(func(tx *bolt.Tx) error { assert.NoError(t, tx.DeleteBucket([]byte("widgets"))) return nil }) @@ -431,7 +432,7 @@ func TestBucket_DeleteBucket_Large(t *testing.T) { func TestBucket_Bucket_IncompatibleValue(t *testing.T) { db := NewTestDB() defer db.Close() - db.Update(func(tx *Tx) error { + db.Update(func(tx *bolt.Tx) error { tx.CreateBucket([]byte("widgets")) assert.NoError(t, tx.Bucket([]byte("widgets")).Put([]byte("foo"), []byte("bar"))) assert.Nil(t, tx.Bucket([]byte("widgets")).Bucket([]byte("foo"))) @@ -443,12 +444,12 @@ func TestBucket_Bucket_IncompatibleValue(t *testing.T) { func TestBucket_CreateBucket_IncompatibleValue(t *testing.T) { db := NewTestDB() defer db.Close() - db.Update(func(tx *Tx) error { + db.Update(func(tx *bolt.Tx) error { _, err := tx.CreateBucket([]byte("widgets")) assert.NoError(t, err) assert.NoError(t, tx.Bucket([]byte("widgets")).Put([]byte("foo"), []byte("bar"))) _, err = tx.Bucket([]byte("widgets")).CreateBucket([]byte("foo")) - assert.Equal(t, ErrIncompatibleValue, err) + assert.Equal(t, bolt.ErrIncompatibleValue, err) return nil }) } @@ -457,11 +458,11 @@ func TestBucket_CreateBucket_IncompatibleValue(t *testing.T) { func TestBucket_DeleteBucket_IncompatibleValue(t *testing.T) { db := NewTestDB() defer db.Close() - db.Update(func(tx *Tx) error { + db.Update(func(tx *bolt.Tx) error { _, err := tx.CreateBucket([]byte("widgets")) assert.NoError(t, err) assert.NoError(t, tx.Bucket([]byte("widgets")).Put([]byte("foo"), []byte("bar"))) - assert.Equal(t, ErrIncompatibleValue, tx.Bucket([]byte("widgets")).DeleteBucket([]byte("foo"))) + assert.Equal(t, bolt.ErrIncompatibleValue, tx.Bucket([]byte("widgets")).DeleteBucket([]byte("foo"))) return nil }) } @@ -470,7 +471,7 @@ func TestBucket_DeleteBucket_IncompatibleValue(t *testing.T) { func TestBucket_NextSequence(t *testing.T) { db := NewTestDB() defer db.Close() - db.Update(func(tx *Tx) error { + db.Update(func(tx *bolt.Tx) error { tx.CreateBucket([]byte("widgets")) tx.CreateBucket([]byte("woojits")) @@ -494,15 +495,15 @@ func TestBucket_NextSequence(t *testing.T) { func TestBucket_NextSequence_ReadOnly(t *testing.T) { db := NewTestDB() defer db.Close() - db.Update(func(tx *Tx) error { + db.Update(func(tx *bolt.Tx) error { tx.CreateBucket([]byte("widgets")) return nil }) - db.View(func(tx *Tx) error { + db.View(func(tx *bolt.Tx) error { b := tx.Bucket([]byte("widgets")) i, err := b.NextSequence() assert.Equal(t, i, uint64(0)) - assert.Equal(t, err, ErrTxNotWritable) + assert.Equal(t, err, bolt.ErrTxNotWritable) return nil }) } @@ -516,14 +517,14 @@ func TestBucket_NextSequence_Closed(t *testing.T) { b := tx.Bucket([]byte("widgets")) tx.Rollback() _, err := b.NextSequence() - assert.Equal(t, ErrTxClosed, err) + assert.Equal(t, bolt.ErrTxClosed, err) } // Ensure a user can loop over all key/value pairs in a bucket. func TestBucket_ForEach(t *testing.T) { db := NewTestDB() defer db.Close() - db.Update(func(tx *Tx) error { + db.Update(func(tx *bolt.Tx) error { tx.CreateBucket([]byte("widgets")) tx.Bucket([]byte("widgets")).Put([]byte("foo"), []byte("0000")) tx.Bucket([]byte("widgets")).Put([]byte("baz"), []byte("0001")) @@ -555,7 +556,7 @@ func TestBucket_ForEach(t *testing.T) { func TestBucket_ForEach_ShortCircuit(t *testing.T) { db := NewTestDB() defer db.Close() - db.Update(func(tx *Tx) error { + db.Update(func(tx *bolt.Tx) error { tx.CreateBucket([]byte("widgets")) tx.Bucket([]byte("widgets")).Put([]byte("bar"), []byte("0000")) tx.Bucket([]byte("widgets")).Put([]byte("baz"), []byte("0000")) @@ -584,19 +585,19 @@ func TestBucket_ForEach_Closed(t *testing.T) { b := tx.Bucket([]byte("widgets")) tx.Rollback() err := b.ForEach(func(k, v []byte) error { return nil }) - assert.Equal(t, ErrTxClosed, err) + assert.Equal(t, bolt.ErrTxClosed, err) } // Ensure that an error is returned when inserting with an empty key. func TestBucket_Put_EmptyKey(t *testing.T) { db := NewTestDB() defer db.Close() - db.Update(func(tx *Tx) error { + db.Update(func(tx *bolt.Tx) error { tx.CreateBucket([]byte("widgets")) err := tx.Bucket([]byte("widgets")).Put([]byte(""), []byte("bar")) - assert.Equal(t, err, ErrKeyRequired) + assert.Equal(t, err, bolt.ErrKeyRequired) err = tx.Bucket([]byte("widgets")).Put(nil, []byte("bar")) - assert.Equal(t, err, ErrKeyRequired) + assert.Equal(t, err, bolt.ErrKeyRequired) return nil }) } @@ -605,10 +606,10 @@ func TestBucket_Put_EmptyKey(t *testing.T) { func TestBucket_Put_KeyTooLarge(t *testing.T) { db := NewTestDB() defer db.Close() - db.Update(func(tx *Tx) error { + db.Update(func(tx *bolt.Tx) error { tx.CreateBucket([]byte("widgets")) err := tx.Bucket([]byte("widgets")).Put(make([]byte, 32769), []byte("bar")) - assert.Equal(t, err, ErrKeyTooLarge) + assert.Equal(t, err, bolt.ErrKeyTooLarge) return nil }) } @@ -621,18 +622,18 @@ func TestBucket_Stats(t *testing.T) { // Add bucket with fewer keys but one big value. big_key := []byte("really-big-value") for i := 0; i < 500; i++ { - db.Update(func(tx *Tx) error { + db.Update(func(tx *bolt.Tx) error { b, _ := tx.CreateBucketIfNotExists([]byte("woojits")) return b.Put([]byte(fmt.Sprintf("%03d", i)), []byte(strconv.Itoa(i))) }) } - db.Update(func(tx *Tx) error { + db.Update(func(tx *bolt.Tx) error { b, _ := tx.CreateBucketIfNotExists([]byte("woojits")) return b.Put(big_key, []byte(strings.Repeat("*", 10000))) }) db.MustCheck() - db.View(func(tx *Tx) error { + db.View(func(tx *bolt.Tx) error { b := tx.Bucket([]byte("woojits")) stats := b.Stats() assert.Equal(t, 1, stats.BranchPageN, "BranchPageN") @@ -642,13 +643,13 @@ func TestBucket_Stats(t *testing.T) { assert.Equal(t, 501, stats.KeyN, "KeyN") assert.Equal(t, 2, stats.Depth, "Depth") - branchInuse := pageHeaderSize // branch page header - branchInuse += 7 * branchPageElementSize // branch elements - branchInuse += 7 * 3 // branch keys (6 3-byte keys) + branchInuse := 16 // branch page header + branchInuse += 7 * 16 // branch elements + branchInuse += 7 * 3 // branch keys (6 3-byte keys) assert.Equal(t, branchInuse, stats.BranchInuse, "BranchInuse") - leafInuse := 7 * pageHeaderSize // leaf page header - leafInuse += 501 * leafPageElementSize // leaf elements + leafInuse := 7 * 16 // leaf page header + leafInuse += 501 * 16 // leaf elements leafInuse += 500*3 + len(big_key) // leaf keys leafInuse += 1*10 + 2*90 + 3*400 + 10000 // leaf values assert.Equal(t, leafInuse, stats.LeafInuse, "LeafInuse") @@ -682,7 +683,7 @@ func TestBucket_Stats_RandomFill(t *testing.T) { var count int r := rand.New(rand.NewSource(42)) for _, i := range r.Perm(1000) { - db.Update(func(tx *Tx) error { + db.Update(func(tx *bolt.Tx) error { b, _ := tx.CreateBucketIfNotExists([]byte("woojits")) b.FillPercent = 0.9 for _, j := range r.Perm(100) { @@ -695,7 +696,7 @@ func TestBucket_Stats_RandomFill(t *testing.T) { } db.MustCheck() - db.View(func(tx *Tx) error { + db.View(func(tx *bolt.Tx) error { s := tx.Bucket([]byte("woojits")).Stats() assert.Equal(t, 100000, s.KeyN, "KeyN") @@ -716,7 +717,7 @@ func TestBucket_Stats_RandomFill(t *testing.T) { func TestBucket_Stats_Small(t *testing.T) { db := NewTestDB() defer db.Close() - db.Update(func(tx *Tx) error { + db.Update(func(tx *bolt.Tx) error { // Add a bucket that fits on a single root leaf. b, err := tx.CreateBucket([]byte("whozawhats")) assert.NoError(t, err) @@ -725,7 +726,7 @@ func TestBucket_Stats_Small(t *testing.T) { return nil }) db.MustCheck() - db.View(func(tx *Tx) error { + db.View(func(tx *bolt.Tx) error { b := tx.Bucket([]byte("whozawhats")) stats := b.Stats() assert.Equal(t, 0, stats.BranchPageN, "BranchPageN") @@ -743,7 +744,7 @@ func TestBucket_Stats_Small(t *testing.T) { } assert.Equal(t, 1, stats.BucketN, "BucketN") assert.Equal(t, 1, stats.InlineBucketN, "InlineBucketN") - assert.Equal(t, pageHeaderSize+leafPageElementSize+6, stats.InlineBucketInuse, "InlineBucketInuse") + assert.Equal(t, 16+16+6, stats.InlineBucketInuse, "InlineBucketInuse") return nil }) } @@ -752,14 +753,14 @@ func TestBucket_Stats_EmptyBucket(t *testing.T) { db := NewTestDB() defer db.Close() - db.Update(func(tx *Tx) error { + db.Update(func(tx *bolt.Tx) error { // Add a bucket that fits on a single root leaf. _, err := tx.CreateBucket([]byte("whozawhats")) assert.NoError(t, err) return nil }) db.MustCheck() - db.View(func(tx *Tx) error { + db.View(func(tx *bolt.Tx) error { b := tx.Bucket([]byte("whozawhats")) stats := b.Stats() assert.Equal(t, 0, stats.BranchPageN, "BranchPageN") @@ -777,7 +778,7 @@ func TestBucket_Stats_EmptyBucket(t *testing.T) { } assert.Equal(t, 1, stats.BucketN, "BucketN") assert.Equal(t, 1, stats.InlineBucketN, "InlineBucketN") - assert.Equal(t, pageHeaderSize, stats.InlineBucketInuse, "InlineBucketInuse") + assert.Equal(t, 16, stats.InlineBucketInuse, "InlineBucketInuse") return nil }) } @@ -787,7 +788,7 @@ func TestBucket_Stats_Nested(t *testing.T) { db := NewTestDB() defer db.Close() - db.Update(func(tx *Tx) error { + db.Update(func(tx *bolt.Tx) error { b, err := tx.CreateBucket([]byte("foo")) assert.NoError(t, err) for i := 0; i < 100; i++ { @@ -808,7 +809,7 @@ func TestBucket_Stats_Nested(t *testing.T) { db.MustCheck() - db.View(func(tx *Tx) error { + db.View(func(tx *bolt.Tx) error { b := tx.Bucket([]byte("foo")) stats := b.Stats() assert.Equal(t, 0, stats.BranchPageN, "BranchPageN") @@ -819,19 +820,19 @@ func TestBucket_Stats_Nested(t *testing.T) { assert.Equal(t, 3, stats.Depth, "Depth") assert.Equal(t, 0, stats.BranchInuse, "BranchInuse") - foo := pageHeaderSize // foo - foo += 101 * leafPageElementSize // foo leaf elements - foo += 100*2 + 100*2 // foo leaf key/values - foo += 3 + bucketHeaderSize // foo -> bar key/value + foo := 16 // foo (pghdr) + foo += 101 * 16 // foo leaf elements + foo += 100*2 + 100*2 // foo leaf key/values + foo += 3 + 16 // foo -> bar key/value - bar := pageHeaderSize // bar - bar += 11 * leafPageElementSize // bar leaf elements - bar += 10 + 10 // bar leaf key/values - bar += 3 + bucketHeaderSize // bar -> baz key/value + bar := 16 // bar (pghdr) + bar += 11 * 16 // bar leaf elements + bar += 10 + 10 // bar leaf key/values + bar += 3 + 16 // bar -> baz key/value - baz := pageHeaderSize // baz (inline) - baz += 10 * leafPageElementSize // baz leaf elements - baz += 10 + 10 // baz leaf key/values + baz := 16 // baz (inline) (pghdr) + baz += 10 * 16 // baz leaf elements + baz += 10 + 10 // baz leaf key/values assert.Equal(t, foo+bar+baz, stats.LeafInuse, "LeafInuse") if os.Getpagesize() == 4096 { @@ -857,7 +858,7 @@ func TestBucket_Stats_Large(t *testing.T) { var index int for i := 0; i < 100; i++ { - db.Update(func(tx *Tx) error { + db.Update(func(tx *bolt.Tx) error { // Add bucket with lots of keys. b, _ := tx.CreateBucketIfNotExists([]byte("widgets")) for i := 0; i < 1000; i++ { @@ -869,7 +870,7 @@ func TestBucket_Stats_Large(t *testing.T) { } db.MustCheck() - db.View(func(tx *Tx) error { + db.View(func(tx *bolt.Tx) error { b := tx.Bucket([]byte("widgets")) stats := b.Stats() assert.Equal(t, 13, stats.BranchPageN, "BranchPageN") @@ -905,12 +906,12 @@ func TestBucket_Put_Single(t *testing.T) { m := make(map[string][]byte) - db.Update(func(tx *Tx) error { + db.Update(func(tx *bolt.Tx) error { _, err := tx.CreateBucket([]byte("widgets")) return err }) for _, item := range items { - db.Update(func(tx *Tx) error { + db.Update(func(tx *bolt.Tx) error { if err := tx.Bucket([]byte("widgets")).Put(item.Key, item.Value); err != nil { panic("put error: " + err.Error()) } @@ -919,7 +920,7 @@ func TestBucket_Put_Single(t *testing.T) { }) // Verify all key/values so far. - db.View(func(tx *Tx) error { + db.View(func(tx *bolt.Tx) error { i := 0 for k, v := range m { value := tx.Bucket([]byte("widgets")).Get([]byte(k)) @@ -952,11 +953,11 @@ func TestBucket_Put_Multiple(t *testing.T) { db := NewTestDB() defer db.Close() // Bulk insert all values. - db.Update(func(tx *Tx) error { + db.Update(func(tx *bolt.Tx) error { _, err := tx.CreateBucket([]byte("widgets")) return err }) - err := db.Update(func(tx *Tx) error { + err := db.Update(func(tx *bolt.Tx) error { b := tx.Bucket([]byte("widgets")) for _, item := range items { assert.NoError(t, b.Put(item.Key, item.Value)) @@ -966,7 +967,7 @@ func TestBucket_Put_Multiple(t *testing.T) { assert.NoError(t, err) // Verify all items exist. - db.View(func(tx *Tx) error { + db.View(func(tx *bolt.Tx) error { b := tx.Bucket([]byte("widgets")) for _, item := range items { value := b.Get(item.Key) @@ -994,11 +995,11 @@ func TestBucket_Delete_Quick(t *testing.T) { db := NewTestDB() defer db.Close() // Bulk insert all values. - db.Update(func(tx *Tx) error { + db.Update(func(tx *bolt.Tx) error { _, err := tx.CreateBucket([]byte("widgets")) return err }) - err := db.Update(func(tx *Tx) error { + err := db.Update(func(tx *bolt.Tx) error { b := tx.Bucket([]byte("widgets")) for _, item := range items { assert.NoError(t, b.Put(item.Key, item.Value)) @@ -1009,14 +1010,14 @@ func TestBucket_Delete_Quick(t *testing.T) { // Remove items one at a time and check consistency. for _, item := range items { - err := db.Update(func(tx *Tx) error { + err := db.Update(func(tx *bolt.Tx) error { return tx.Bucket([]byte("widgets")).Delete(item.Key) }) assert.NoError(t, err) } // Anything before our deletion index should be nil. - db.View(func(tx *Tx) error { + db.View(func(tx *bolt.Tx) error { tx.Bucket([]byte("widgets")).ForEach(func(k, v []byte) error { t.Fatalf("bucket should be empty; found: %06x", trunc(k, 3)) return nil @@ -1032,12 +1033,12 @@ func TestBucket_Delete_Quick(t *testing.T) { func ExampleBucket_Put() { // Open the database. - db, _ := Open(tempfile(), 0666, nil) + db, _ := bolt.Open(tempfile(), 0666, nil) defer os.Remove(db.Path()) defer db.Close() // Start a write transaction. - db.Update(func(tx *Tx) error { + db.Update(func(tx *bolt.Tx) error { // Create a bucket. tx.CreateBucket([]byte("widgets")) @@ -1047,7 +1048,7 @@ func ExampleBucket_Put() { }) // Read value back in a different read-only transaction. - db.View(func(tx *Tx) error { + db.View(func(tx *bolt.Tx) error { value := tx.Bucket([]byte("widgets")).Get([]byte("foo")) fmt.Printf("The value of 'foo' is: %s\n", value) return nil @@ -1059,12 +1060,12 @@ func ExampleBucket_Put() { func ExampleBucket_Delete() { // Open the database. - db, _ := Open(tempfile(), 0666, nil) + db, _ := bolt.Open(tempfile(), 0666, nil) defer os.Remove(db.Path()) defer db.Close() // Start a write transaction. - db.Update(func(tx *Tx) error { + db.Update(func(tx *bolt.Tx) error { // Create a bucket. tx.CreateBucket([]byte("widgets")) b := tx.Bucket([]byte("widgets")) @@ -1079,12 +1080,12 @@ func ExampleBucket_Delete() { }) // Delete the key in a different write transaction. - db.Update(func(tx *Tx) error { + db.Update(func(tx *bolt.Tx) error { return tx.Bucket([]byte("widgets")).Delete([]byte("foo")) }) // Retrieve the key again. - db.View(func(tx *Tx) error { + db.View(func(tx *bolt.Tx) error { value := tx.Bucket([]byte("widgets")).Get([]byte("foo")) if value == nil { fmt.Printf("The value of 'foo' is now: nil\n") @@ -1099,12 +1100,12 @@ func ExampleBucket_Delete() { func ExampleBucket_ForEach() { // Open the database. - db, _ := Open(tempfile(), 0666, nil) + db, _ := bolt.Open(tempfile(), 0666, nil) defer os.Remove(db.Path()) defer db.Close() // Insert data into a bucket. - db.Update(func(tx *Tx) error { + db.Update(func(tx *bolt.Tx) error { tx.CreateBucket([]byte("animals")) b := tx.Bucket([]byte("animals")) b.Put([]byte("dog"), []byte("fun")) diff --git a/cursor_test.go b/cursor_test.go index 424d254..edca0f0 100644 --- a/cursor_test.go +++ b/cursor_test.go @@ -1,4 +1,4 @@ -package bolt +package bolt_test import ( "bytes" @@ -7,6 +7,7 @@ import ( "testing" "testing/quick" + "github.com/boltdb/bolt" "github.com/stretchr/testify/assert" ) @@ -14,7 +15,7 @@ import ( func TestCursor_Bucket(t *testing.T) { db := NewTestDB() defer db.Close() - db.Update(func(tx *Tx) error { + db.Update(func(tx *bolt.Tx) error { b, _ := tx.CreateBucket([]byte("widgets")) c := b.Cursor() assert.Equal(t, b, c.Bucket()) @@ -26,7 +27,7 @@ func TestCursor_Bucket(t *testing.T) { func TestCursor_Seek(t *testing.T) { db := NewTestDB() defer db.Close() - db.Update(func(tx *Tx) error { + db.Update(func(tx *bolt.Tx) error { b, err := tx.CreateBucket([]byte("widgets")) assert.NoError(t, err) assert.NoError(t, b.Put([]byte("foo"), []byte("0001"))) @@ -36,7 +37,7 @@ func TestCursor_Seek(t *testing.T) { assert.NoError(t, err) return nil }) - db.View(func(tx *Tx) error { + db.View(func(tx *bolt.Tx) error { c := tx.Bucket([]byte("widgets")).Cursor() // Exact match should go to the key. @@ -75,7 +76,7 @@ func TestCursor_Delete(t *testing.T) { var count = 1000 // Insert every other key between 0 and $count. - db.Update(func(tx *Tx) error { + db.Update(func(tx *bolt.Tx) error { b, _ := tx.CreateBucket([]byte("widgets")) for i := 0; i < count; i += 1 { k := make([]byte, 8) @@ -86,7 +87,7 @@ func TestCursor_Delete(t *testing.T) { return nil }) - db.Update(func(tx *Tx) error { + db.Update(func(tx *bolt.Tx) error { c := tx.Bucket([]byte("widgets")).Cursor() bound := make([]byte, 8) binary.BigEndian.PutUint64(bound, uint64(count/2)) @@ -97,11 +98,11 @@ func TestCursor_Delete(t *testing.T) { } c.Seek([]byte("sub")) err := c.Delete() - assert.Equal(t, err, ErrIncompatibleValue) + assert.Equal(t, err, bolt.ErrIncompatibleValue) return nil }) - db.View(func(tx *Tx) error { + db.View(func(tx *bolt.Tx) error { b := tx.Bucket([]byte("widgets")) assert.Equal(t, b.Stats().KeyN, count/2+1) return nil @@ -120,7 +121,7 @@ func TestCursor_Seek_Large(t *testing.T) { var count = 10000 // Insert every other key between 0 and $count. - db.Update(func(tx *Tx) error { + db.Update(func(tx *bolt.Tx) error { b, _ := tx.CreateBucket([]byte("widgets")) for i := 0; i < count; i += 100 { for j := i; j < i+100; j += 2 { @@ -132,7 +133,7 @@ func TestCursor_Seek_Large(t *testing.T) { return nil }) - db.View(func(tx *Tx) error { + db.View(func(tx *bolt.Tx) error { c := tx.Bucket([]byte("widgets")).Cursor() for i := 0; i < count; i++ { seek := make([]byte, 8) @@ -164,11 +165,11 @@ func TestCursor_Seek_Large(t *testing.T) { func TestCursor_EmptyBucket(t *testing.T) { db := NewTestDB() defer db.Close() - db.Update(func(tx *Tx) error { + db.Update(func(tx *bolt.Tx) error { _, err := tx.CreateBucket([]byte("widgets")) return err }) - db.View(func(tx *Tx) error { + db.View(func(tx *bolt.Tx) error { c := tx.Bucket([]byte("widgets")).Cursor() k, v := c.First() assert.Nil(t, k) @@ -182,11 +183,11 @@ func TestCursor_EmptyBucketReverse(t *testing.T) { db := NewTestDB() defer db.Close() - db.Update(func(tx *Tx) error { + db.Update(func(tx *bolt.Tx) error { _, err := tx.CreateBucket([]byte("widgets")) return err }) - db.View(func(tx *Tx) error { + db.View(func(tx *bolt.Tx) error { c := tx.Bucket([]byte("widgets")).Cursor() k, v := c.Last() assert.Nil(t, k) @@ -200,7 +201,7 @@ func TestCursor_Iterate_Leaf(t *testing.T) { db := NewTestDB() defer db.Close() - db.Update(func(tx *Tx) error { + db.Update(func(tx *bolt.Tx) error { tx.CreateBucket([]byte("widgets")) tx.Bucket([]byte("widgets")).Put([]byte("baz"), []byte{}) tx.Bucket([]byte("widgets")).Put([]byte("foo"), []byte{0}) @@ -238,7 +239,7 @@ func TestCursor_LeafRootReverse(t *testing.T) { db := NewTestDB() defer db.Close() - db.Update(func(tx *Tx) error { + db.Update(func(tx *bolt.Tx) error { tx.CreateBucket([]byte("widgets")) tx.Bucket([]byte("widgets")).Put([]byte("baz"), []byte{}) tx.Bucket([]byte("widgets")).Put([]byte("foo"), []byte{0}) @@ -276,7 +277,7 @@ func TestCursor_Restart(t *testing.T) { db := NewTestDB() defer db.Close() - db.Update(func(tx *Tx) error { + db.Update(func(tx *bolt.Tx) error { tx.CreateBucket([]byte("widgets")) tx.Bucket([]byte("widgets")).Put([]byte("bar"), []byte{}) tx.Bucket([]byte("widgets")).Put([]byte("foo"), []byte{}) @@ -380,7 +381,7 @@ func TestCursor_QuickCheck_BucketsOnly(t *testing.T) { db := NewTestDB() defer db.Close() - db.Update(func(tx *Tx) error { + db.Update(func(tx *bolt.Tx) error { b, err := tx.CreateBucket([]byte("widgets")) assert.NoError(t, err) _, err = b.CreateBucket([]byte("foo")) @@ -391,7 +392,7 @@ func TestCursor_QuickCheck_BucketsOnly(t *testing.T) { assert.NoError(t, err) return nil }) - db.View(func(tx *Tx) error { + db.View(func(tx *bolt.Tx) error { var names []string c := tx.Bucket([]byte("widgets")).Cursor() for k, v := c.First(); k != nil; k, v = c.Next() { @@ -408,7 +409,7 @@ func TestCursor_QuickCheck_BucketsOnly_Reverse(t *testing.T) { db := NewTestDB() defer db.Close() - db.Update(func(tx *Tx) error { + db.Update(func(tx *bolt.Tx) error { b, err := tx.CreateBucket([]byte("widgets")) assert.NoError(t, err) _, err = b.CreateBucket([]byte("foo")) @@ -419,7 +420,7 @@ func TestCursor_QuickCheck_BucketsOnly_Reverse(t *testing.T) { assert.NoError(t, err) return nil }) - db.View(func(tx *Tx) error { + db.View(func(tx *bolt.Tx) error { var names []string c := tx.Bucket([]byte("widgets")).Cursor() for k, v := c.Last(); k != nil; k, v = c.Prev() { diff --git a/db.go b/db.go index bb6beef..7364454 100644 --- a/db.go +++ b/db.go @@ -384,8 +384,8 @@ func (db *DB) beginRWTx() (*Tx, error) { // Free any pages associated with closed read-only transactions. var minid txid = 0xFFFFFFFFFFFFFFFF for _, t := range db.txs { - if t.id() < minid { - minid = t.id() + if t.meta.txid < minid { + minid = t.meta.txid } } if minid > 0 { diff --git a/db_test.go b/db_test.go index 7044359..22eaea7 100644 --- a/db_test.go +++ b/db_test.go @@ -1,4 +1,4 @@ -package bolt +package bolt_test import ( "errors" @@ -12,8 +12,8 @@ import ( "strings" "testing" "time" - "unsafe" + "github.com/boltdb/bolt" "github.com/stretchr/testify/assert" ) @@ -21,7 +21,7 @@ var statsFlag = flag.Bool("stats", false, "show performance stats") // Ensure that opening a database with a bad path returns an error. func TestOpen_BadPath(t *testing.T) { - db, err := Open("", 0666, nil) + db, err := bolt.Open("", 0666, nil) assert.Error(t, err) assert.Nil(t, db) } @@ -30,7 +30,7 @@ func TestOpen_BadPath(t *testing.T) { func TestOpen(t *testing.T) { path := tempfile() defer os.Remove(path) - db, err := Open(path, 0666, nil) + db, err := bolt.Open(path, 0666, nil) assert.NotNil(t, db) assert.NoError(t, err) assert.Equal(t, db.Path(), path) @@ -47,15 +47,15 @@ func TestOpen_Timeout(t *testing.T) { defer os.Remove(path) // Open a data file. - db0, err := Open(path, 0666, nil) + db0, err := bolt.Open(path, 0666, nil) assert.NotNil(t, db0) assert.NoError(t, err) // Attempt to open the database again. start := time.Now() - db1, err := Open(path, 0666, &Options{Timeout: 100 * time.Millisecond}) + db1, err := bolt.Open(path, 0666, &bolt.Options{Timeout: 100 * time.Millisecond}) assert.Nil(t, db1) - assert.Equal(t, ErrTimeout, err) + assert.Equal(t, bolt.ErrTimeout, err) assert.True(t, time.Since(start) > 100*time.Millisecond) db0.Close() @@ -71,7 +71,7 @@ func TestOpen_Wait(t *testing.T) { defer os.Remove(path) // Open a data file. - db0, err := Open(path, 0666, nil) + db0, err := bolt.Open(path, 0666, nil) assert.NotNil(t, db0) assert.NoError(t, err) @@ -80,7 +80,7 @@ func TestOpen_Wait(t *testing.T) { // Attempt to open the database again. start := time.Now() - db1, err := Open(path, 0666, &Options{Timeout: 200 * time.Millisecond}) + db1, err := bolt.Open(path, 0666, &bolt.Options{Timeout: 200 * time.Millisecond}) assert.NotNil(t, db1) assert.NoError(t, err) assert.True(t, time.Since(start) > 100*time.Millisecond) @@ -91,14 +91,14 @@ func TestOpen_Check(t *testing.T) { path := tempfile() defer os.Remove(path) - db, err := Open(path, 0666, nil) + db, err := bolt.Open(path, 0666, nil) assert.NoError(t, err) - assert.NoError(t, db.View(func(tx *Tx) error { return <-tx.Check() })) + assert.NoError(t, db.View(func(tx *bolt.Tx) error { return <-tx.Check() })) db.Close() - db, err = Open(path, 0666, nil) + db, err = bolt.Open(path, 0666, nil) assert.NoError(t, err) - assert.NoError(t, db.View(func(tx *Tx) error { return <-tx.Check() })) + assert.NoError(t, db.View(func(tx *bolt.Tx) error { return <-tx.Check() })) db.Close() } @@ -107,7 +107,7 @@ func TestDB_Open_FileError(t *testing.T) { path := tempfile() defer os.Remove(path) - _, err := Open(path+"/youre-not-my-real-parent", 0666, nil) + _, err := bolt.Open(path+"/youre-not-my-real-parent", 0666, nil) if err, _ := err.(*os.PathError); assert.Error(t, err) { assert.Equal(t, path+"/youre-not-my-real-parent", err.Path) assert.Equal(t, "open", err.Op) @@ -124,17 +124,20 @@ func TestDB_Open_FileTooSmall(t *testing.T) { path := tempfile() defer os.Remove(path) - db, err := Open(path, 0666, nil) + db, err := bolt.Open(path, 0666, nil) assert.NoError(t, err) db.Close() // corrupt the database assert.NoError(t, os.Truncate(path, int64(os.Getpagesize()))) - db, err = Open(path, 0666, nil) + db, err = bolt.Open(path, 0666, nil) assert.Equal(t, errors.New("file size too small"), err) } +// TODO(benbjohnson): Test corruption at every byte of the first two pages. + +/* // Ensure that corrupt meta0 page errors get returned. func TestDB_Open_CorruptMeta0(t *testing.T) { var m meta @@ -156,7 +159,7 @@ func TestDB_Open_CorruptMeta0(t *testing.T) { assert.NoError(t, err) // Open the database. - _, err = Open(path, 0666, nil) + _, err = bolt.Open(path, 0666, nil) assert.Equal(t, err, errors.New("meta0 error: invalid database")) } @@ -166,13 +169,13 @@ func TestDB_Open_MetaChecksumError(t *testing.T) { path := tempfile() defer os.Remove(path) - db, err := Open(path, 0600, nil) + db, err := bolt.Open(path, 0600, nil) pageSize := db.pageSize - db.Update(func(tx *Tx) error { + db.Update(func(tx *bolt.Tx) error { _, err := tx.CreateBucket([]byte("widgets")) return err }) - db.Update(func(tx *Tx) error { + db.Update(func(tx *bolt.Tx) error { _, err := tx.CreateBucket([]byte("woojits")) return err }) @@ -185,7 +188,7 @@ func TestDB_Open_MetaChecksumError(t *testing.T) { f.Close() // Reopen the database. - _, err = Open(path, 0600, nil) + _, err = bolt.Open(path, 0600, nil) if assert.Error(t, err) { if i == 0 { assert.Equal(t, "meta0 error: checksum error", err.Error()) @@ -195,13 +198,14 @@ func TestDB_Open_MetaChecksumError(t *testing.T) { } } } +*/ // Ensure that a database cannot open a transaction when it's not open. func TestDB_Begin_DatabaseNotOpen(t *testing.T) { - var db DB + var db bolt.DB tx, err := db.Begin(false) assert.Nil(t, tx) - assert.Equal(t, err, ErrDatabaseNotOpen) + assert.Equal(t, err, bolt.ErrDatabaseNotOpen) } // Ensure that a read-write transaction can be retrieved. @@ -218,9 +222,9 @@ func TestDB_BeginRW(t *testing.T) { // Ensure that opening a transaction while the DB is closed returns an error. func TestDB_BeginRW_Closed(t *testing.T) { - var db DB + var db bolt.DB tx, err := db.Begin(true) - assert.Equal(t, err, ErrDatabaseNotOpen) + assert.Equal(t, err, bolt.ErrDatabaseNotOpen) assert.Nil(t, tx) } @@ -228,7 +232,7 @@ func TestDB_BeginRW_Closed(t *testing.T) { func TestDB_Update(t *testing.T) { db := NewTestDB() defer db.Close() - err := db.Update(func(tx *Tx) error { + err := db.Update(func(tx *bolt.Tx) error { tx.CreateBucket([]byte("widgets")) b := tx.Bucket([]byte("widgets")) b.Put([]byte("foo"), []byte("bar")) @@ -237,7 +241,7 @@ func TestDB_Update(t *testing.T) { return nil }) assert.NoError(t, err) - err = db.View(func(tx *Tx) error { + err = db.View(func(tx *bolt.Tx) error { assert.Nil(t, tx.Bucket([]byte("widgets")).Get([]byte("foo"))) assert.Equal(t, []byte("bat"), tx.Bucket([]byte("widgets")).Get([]byte("baz"))) return nil @@ -247,24 +251,24 @@ func TestDB_Update(t *testing.T) { // Ensure a closed database returns an error while running a transaction block func TestDB_Update_Closed(t *testing.T) { - var db DB - err := db.Update(func(tx *Tx) error { + var db bolt.DB + err := db.Update(func(tx *bolt.Tx) error { tx.CreateBucket([]byte("widgets")) return nil }) - assert.Equal(t, err, ErrDatabaseNotOpen) + assert.Equal(t, err, bolt.ErrDatabaseNotOpen) } // Ensure a panic occurs while trying to commit a managed transaction. func TestDB_Update_ManualCommitAndRollback(t *testing.T) { - var db DB - db.Update(func(tx *Tx) error { + var db bolt.DB + db.Update(func(tx *bolt.Tx) error { tx.CreateBucket([]byte("widgets")) assert.Panics(t, func() { tx.Commit() }) assert.Panics(t, func() { tx.Rollback() }) return nil }) - db.View(func(tx *Tx) error { + db.View(func(tx *bolt.Tx) error { assert.Panics(t, func() { tx.Commit() }) assert.Panics(t, func() { tx.Rollback() }) return nil @@ -279,24 +283,24 @@ func TestDB_Update_Panic(t *testing.T) { func() { defer func() { if r := recover(); r != nil { - warn("recover: update", r) + t.Log("recover: update", r) } }() - db.Update(func(tx *Tx) error { + db.Update(func(tx *bolt.Tx) error { tx.CreateBucket([]byte("widgets")) panic("omg") }) }() // Verify we can update again. - err := db.Update(func(tx *Tx) error { + err := db.Update(func(tx *bolt.Tx) error { _, err := tx.CreateBucket([]byte("widgets")) return err }) assert.NoError(t, err) // Verify that our change persisted. - err = db.Update(func(tx *Tx) error { + err = db.Update(func(tx *bolt.Tx) error { assert.NotNil(t, tx.Bucket([]byte("widgets"))) return nil }) @@ -306,7 +310,7 @@ func TestDB_Update_Panic(t *testing.T) { func TestDB_View_Error(t *testing.T) { db := NewTestDB() defer db.Close() - err := db.View(func(tx *Tx) error { + err := db.View(func(tx *bolt.Tx) error { return errors.New("xxx") }) assert.Equal(t, errors.New("xxx"), err) @@ -316,7 +320,7 @@ func TestDB_View_Error(t *testing.T) { func TestDB_View_Panic(t *testing.T) { db := NewTestDB() defer db.Close() - db.Update(func(tx *Tx) error { + db.Update(func(tx *bolt.Tx) error { tx.CreateBucket([]byte("widgets")) return nil }) @@ -324,17 +328,17 @@ func TestDB_View_Panic(t *testing.T) { func() { defer func() { if r := recover(); r != nil { - warn("recover: view", r) + t.Log("recover: view", r) } }() - db.View(func(tx *Tx) error { + db.View(func(tx *bolt.Tx) error { assert.NotNil(t, tx.Bucket([]byte("widgets"))) panic("omg") }) }() // Verify that we can still use read transactions. - db.View(func(tx *Tx) error { + db.View(func(tx *bolt.Tx) error { assert.NotNil(t, tx.Bucket([]byte("widgets"))) return nil }) @@ -349,7 +353,7 @@ func TestDB_Commit_WriteFail(t *testing.T) { func TestDB_Stats(t *testing.T) { db := NewTestDB() defer db.Close() - db.Update(func(tx *Tx) error { + db.Update(func(tx *bolt.Tx) error { _, err := tx.CreateBucket([]byte("widgets")) return err }) @@ -359,35 +363,22 @@ func TestDB_Stats(t *testing.T) { assert.Equal(t, 2, stats.PendingPageN, "PendingPageN") } -// Ensure that the mmap grows appropriately. -func TestDB_mmapSize(t *testing.T) { - db := &DB{pageSize: 4096} - assert.Equal(t, db.mmapSize(0), minMmapSize) - assert.Equal(t, db.mmapSize(16384), minMmapSize) - assert.Equal(t, db.mmapSize(minMmapSize-1), minMmapSize) - assert.Equal(t, db.mmapSize(minMmapSize), minMmapSize) - assert.Equal(t, db.mmapSize(minMmapSize+1), (minMmapSize*2)+4096) - assert.Equal(t, db.mmapSize(10000000), 20000768) - assert.Equal(t, db.mmapSize((1<<30)-1), 2147483648) - assert.Equal(t, db.mmapSize(1<<30), 1<<31) -} - // Ensure that database pages are in expected order and type. func TestDB_Consistency(t *testing.T) { db := NewTestDB() defer db.Close() - db.Update(func(tx *Tx) error { + db.Update(func(tx *bolt.Tx) error { _, err := tx.CreateBucket([]byte("widgets")) return err }) for i := 0; i < 10; i++ { - db.Update(func(tx *Tx) error { + db.Update(func(tx *bolt.Tx) error { assert.NoError(t, tx.Bucket([]byte("widgets")).Put([]byte("foo"), []byte("bar"))) return nil }) } - db.Update(func(tx *Tx) error { + db.Update(func(tx *bolt.Tx) error { if p, _ := tx.Page(0); assert.NotNil(t, p) { assert.Equal(t, "meta", p.Type) } @@ -412,16 +403,9 @@ func TestDB_Consistency(t *testing.T) { }) } -// Ensure that a database can return a string representation of itself. -func TestDB_String(t *testing.T) { - db := &DB{path: "/foo/bar"} - assert.Equal(t, db.String(), `DB<"/foo/bar">`) - assert.Equal(t, db.GoString(), `bolt.DB{path:"/foo/bar"}`) -} - // Ensure that DB stats can be substracted from one another. func TestDBStats_Sub(t *testing.T) { - var a, b Stats + var a, b bolt.Stats a.TxStats.PageCount = 3 a.FreePageN = 4 b.TxStats.PageCount = 10 @@ -432,76 +416,14 @@ func TestDBStats_Sub(t *testing.T) { assert.Equal(t, 14, diff.FreePageN) } -// Ensure that meta with bad magic is invalid. -func TestMeta_validate_magic(t *testing.T) { - m := &meta{magic: 0x01234567} - assert.Equal(t, m.validate(), ErrInvalid) -} - -// Ensure that meta with a bad version is invalid. -func TestMeta_validate_version(t *testing.T) { - m := &meta{magic: magic, version: 200} - assert.Equal(t, m.validate(), ErrVersionMismatch) -} - -// Ensure that a DB in strict mode will fail when corrupted. -func TestDB_StrictMode(t *testing.T) { - var msg string - func() { - defer func() { - msg = fmt.Sprintf("%s", recover()) - }() - - db := NewTestDB() - defer db.Close() - - db.StrictMode = true - db.Update(func(tx *Tx) error { - tx.CreateBucket([]byte("foo")) - - // Corrupt the DB by extending the high water mark. - tx.meta.pgid++ - - return nil - }) - }() - - assert.Equal(t, "check fail: page 4: unreachable unfreed", msg) -} - -// Ensure that a double freeing a page will result in a panic. -func TestDB_DoubleFree(t *testing.T) { - var msg string - func() { - defer func() { - msg = fmt.Sprintf("%s", recover()) - }() - - db := NewTestDB() - defer os.Remove(db.DB.Path()) - defer db.DB.Close() - - db.Update(func(tx *Tx) error { - tx.CreateBucket([]byte("foo")) - - // Corrupt the DB by adding a page to the freelist. - db.freelist.free(0, tx.page(3)) - - return nil - }) - }() - - assert.Equal(t, "assertion failed: page 3 already freed", msg) -} - func ExampleDB_Update() { // Open the database. - db, _ := Open(tempfile(), 0666, nil) + db, _ := bolt.Open(tempfile(), 0666, nil) defer os.Remove(db.Path()) defer db.Close() // Execute several commands within a write transaction. - err := db.Update(func(tx *Tx) error { + err := db.Update(func(tx *bolt.Tx) error { b, err := tx.CreateBucket([]byte("widgets")) if err != nil { return err @@ -514,7 +436,7 @@ func ExampleDB_Update() { // If our transactional block didn't return an error then our data is saved. if err == nil { - db.View(func(tx *Tx) error { + db.View(func(tx *bolt.Tx) error { value := tx.Bucket([]byte("widgets")).Get([]byte("foo")) fmt.Printf("The value of 'foo' is: %s\n", value) return nil @@ -527,12 +449,12 @@ func ExampleDB_Update() { func ExampleDB_View() { // Open the database. - db, _ := Open(tempfile(), 0666, nil) + db, _ := bolt.Open(tempfile(), 0666, nil) defer os.Remove(db.Path()) defer db.Close() // Insert data into a bucket. - db.Update(func(tx *Tx) error { + db.Update(func(tx *bolt.Tx) error { tx.CreateBucket([]byte("people")) b := tx.Bucket([]byte("people")) b.Put([]byte("john"), []byte("doe")) @@ -541,7 +463,7 @@ func ExampleDB_View() { }) // Access data from within a read-only transactional block. - db.View(func(tx *Tx) error { + db.View(func(tx *bolt.Tx) error { v := tx.Bucket([]byte("people")).Get([]byte("john")) fmt.Printf("John's last name is %s.\n", v) return nil @@ -553,12 +475,12 @@ func ExampleDB_View() { func ExampleDB_Begin_ReadOnly() { // Open the database. - db, _ := Open(tempfile(), 0666, nil) + db, _ := bolt.Open(tempfile(), 0666, nil) defer os.Remove(db.Path()) defer db.Close() // Create a bucket. - db.Update(func(tx *Tx) error { + db.Update(func(tx *bolt.Tx) error { _, err := tx.CreateBucket([]byte("widgets")) return err }) @@ -588,12 +510,12 @@ func ExampleDB_Begin_ReadOnly() { // TestDB represents a wrapper around a Bolt DB to handle temporary file // creation and automatic cleanup on close. type TestDB struct { - *DB + *bolt.DB } // NewTestDB returns a new instance of TestDB. func NewTestDB() *TestDB { - db, err := Open(tempfile(), 0666, nil) + db, err := bolt.Open(tempfile(), 0666, nil) if err != nil { panic("cannot open db: " + err.Error()) } @@ -632,7 +554,7 @@ func (db *TestDB) PrintStats() { // MustCheck runs a consistency check on the database and panics if any errors are found. func (db *TestDB) MustCheck() { - db.View(func(tx *Tx) error { + db.View(func(tx *bolt.Tx) error { // Collect all the errors. var errors []error for err := range tx.Check() { @@ -667,7 +589,7 @@ func (db *TestDB) MustCheck() { // CopyTempFile copies a database to a temporary file. func (db *TestDB) CopyTempFile() { path := tempfile() - db.View(func(tx *Tx) error { return tx.CopyFile(path, 0600) }) + db.View(func(tx *bolt.Tx) error { return tx.CopyFile(path, 0600) }) fmt.Println("db copied to: ", path) } @@ -680,7 +602,7 @@ func tempfile() string { } // mustContainKeys checks that a bucket contains a given set of keys. -func mustContainKeys(b *Bucket, m map[string]string) { +func mustContainKeys(b *bolt.Bucket, m map[string]string) { found := make(map[string]string) b.ForEach(func(k, _ []byte) error { found[string(k)] = "" diff --git a/node.go b/node.go index 9dbc3f9..c204c39 100644 --- a/node.go +++ b/node.go @@ -337,7 +337,7 @@ func (n *node) spill() error { for _, node := range nodes { // Add node's page to the freelist if it's not new. if node.pgid > 0 { - tx.db.freelist.free(tx.id(), tx.page(node.pgid)) + tx.db.freelist.free(tx.meta.txid, tx.page(node.pgid)) node.pgid = 0 } @@ -565,7 +565,7 @@ func (n *node) dereference() { // free adds the node's underlying page to the freelist. func (n *node) free() { if n.pgid != 0 { - n.bucket.tx.db.freelist.free(n.bucket.tx.id(), n.bucket.tx.page(n.pgid)) + n.bucket.tx.db.freelist.free(n.bucket.tx.meta.txid, n.bucket.tx.page(n.pgid)) n.pgid = 0 } } diff --git a/quick_test.go b/quick_test.go index b083250..4da5817 100644 --- a/quick_test.go +++ b/quick_test.go @@ -1,9 +1,11 @@ -package bolt +package bolt_test import ( "bytes" "flag" + "fmt" "math/rand" + "os" "reflect" "testing/quick" "time" @@ -28,8 +30,8 @@ func init() { flag.IntVar(&qmaxksize, "quick.maxksize", 1024, "") flag.IntVar(&qmaxvsize, "quick.maxvsize", 1024, "") flag.Parse() - warn("seed:", qseed) - warnf("quick settings: count=%v, items=%v, ksize=%v, vsize=%v", qcount, qmaxitems, qmaxksize, qmaxvsize) + fmt.Fprintln(os.Stderr, "seed:", qseed) + fmt.Fprintf(os.Stderr, "quick settings: count=%v, items=%v, ksize=%v, vsize=%v\n", qcount, qmaxitems, qmaxksize, qmaxvsize) } func qconfig() *quick.Config { diff --git a/simulation_test.go b/simulation_test.go index 021d6db..1c2aaf8 100644 --- a/simulation_test.go +++ b/simulation_test.go @@ -1,4 +1,4 @@ -package bolt +package bolt_test import ( "bytes" @@ -7,6 +7,7 @@ import ( "sync" "testing" + "github.com/boltdb/bolt" "github.com/stretchr/testify/assert" ) @@ -39,7 +40,7 @@ func testSimulate(t *testing.T, threadCount, parallelism int) { var readerHandlers = []simulateHandler{simulateGetHandler} var writerHandlers = []simulateHandler{simulateGetHandler, simulatePutHandler} - var versions = make(map[txid]*QuickDB) + var versions = make(map[int]*QuickDB) versions[1] = NewQuickDB() db := NewTestDB() @@ -76,9 +77,9 @@ func testSimulate(t *testing.T, threadCount, parallelism int) { // Obtain current state of the dataset. mutex.Lock() - var qdb = versions[tx.id()] + var qdb = versions[tx.ID()] if writable { - qdb = versions[tx.id()-1].Copy() + qdb = versions[tx.ID()-1].Copy() } mutex.Unlock() @@ -86,7 +87,7 @@ func testSimulate(t *testing.T, threadCount, parallelism int) { if writable { defer func() { mutex.Lock() - versions[tx.id()] = qdb + versions[tx.ID()] = qdb mutex.Unlock() assert.NoError(t, tx.Commit()) @@ -117,10 +118,10 @@ func testSimulate(t *testing.T, threadCount, parallelism int) { wg.Wait() } -type simulateHandler func(tx *Tx, qdb *QuickDB) +type simulateHandler func(tx *bolt.Tx, qdb *QuickDB) // Retrieves a key from the database and verifies that it is what is expected. -func simulateGetHandler(tx *Tx, qdb *QuickDB) { +func simulateGetHandler(tx *bolt.Tx, qdb *QuickDB) { // Randomly retrieve an existing exist. keys := qdb.Rand() if len(keys) == 0 { @@ -155,7 +156,7 @@ func simulateGetHandler(tx *Tx, qdb *QuickDB) { } // Inserts a key into the database. -func simulatePutHandler(tx *Tx, qdb *QuickDB) { +func simulatePutHandler(tx *bolt.Tx, qdb *QuickDB) { var err error keys, value := randKeys(), randValue() diff --git a/tx.go b/tx.go index bc2842f..62b9be6 100644 --- a/tx.go +++ b/tx.go @@ -52,9 +52,9 @@ func (tx *Tx) init(db *DB) { } } -// id returns the transaction id. -func (tx *Tx) id() txid { - return tx.meta.txid +// ID returns the transaction id. +func (tx *Tx) ID() int { + return int(tx.meta.txid) } // DB returns a reference to the database that created the transaction. @@ -158,7 +158,7 @@ func (tx *Tx) Commit() error { // Free the freelist and allocate new pages for it. This will overestimate // the size of the freelist but not underestimate the size (which would be bad). - tx.db.freelist.free(tx.id(), tx.db.page(tx.meta.freelist)) + tx.db.freelist.free(tx.meta.txid, tx.db.page(tx.meta.freelist)) p, err := tx.allocate((tx.db.freelist.size() / tx.db.pageSize) + 1) if err != nil { tx.rollback() @@ -218,7 +218,7 @@ func (tx *Tx) rollback() { return } if tx.writable { - tx.db.freelist.rollback(tx.id()) + tx.db.freelist.rollback(tx.meta.txid) tx.db.freelist.reload(tx.db.page(tx.db.meta().freelist)) } tx.close() diff --git a/tx_test.go b/tx_test.go index 55a31ea..1046842 100644 --- a/tx_test.go +++ b/tx_test.go @@ -1,4 +1,4 @@ -package bolt +package bolt_test import ( "errors" @@ -6,6 +6,7 @@ import ( "os" "testing" + "github.com/boltdb/bolt" "github.com/stretchr/testify/assert" ) @@ -16,7 +17,7 @@ func TestTx_Commit_Closed(t *testing.T) { tx, _ := db.Begin(true) tx.CreateBucket([]byte("foo")) assert.NoError(t, tx.Commit()) - assert.Equal(t, tx.Commit(), ErrTxClosed) + assert.Equal(t, tx.Commit(), bolt.ErrTxClosed) } // Ensure that rolling back a closed transaction returns an error. @@ -25,7 +26,7 @@ func TestTx_Rollback_Closed(t *testing.T) { defer db.Close() tx, _ := db.Begin(true) assert.NoError(t, tx.Rollback()) - assert.Equal(t, tx.Rollback(), ErrTxClosed) + assert.Equal(t, tx.Rollback(), bolt.ErrTxClosed) } // Ensure that committing a read-only transaction returns an error. @@ -33,14 +34,14 @@ func TestTx_Commit_ReadOnly(t *testing.T) { db := NewTestDB() defer db.Close() tx, _ := db.Begin(false) - assert.Equal(t, tx.Commit(), ErrTxNotWritable) + assert.Equal(t, tx.Commit(), bolt.ErrTxNotWritable) } // Ensure that a transaction can retrieve a cursor on the root bucket. func TestTx_Cursor(t *testing.T) { db := NewTestDB() defer db.Close() - db.Update(func(tx *Tx) error { + db.Update(func(tx *bolt.Tx) error { tx.CreateBucket([]byte("widgets")) tx.CreateBucket([]byte("woojits")) c := tx.Cursor() @@ -65,10 +66,10 @@ func TestTx_Cursor(t *testing.T) { func TestTx_CreateBucket_ReadOnly(t *testing.T) { db := NewTestDB() defer db.Close() - db.View(func(tx *Tx) error { + db.View(func(tx *bolt.Tx) error { b, err := tx.CreateBucket([]byte("foo")) assert.Nil(t, b) - assert.Equal(t, ErrTxNotWritable, err) + assert.Equal(t, bolt.ErrTxNotWritable, err) return nil }) } @@ -81,14 +82,14 @@ func TestTx_CreateBucket_Closed(t *testing.T) { tx.Commit() b, err := tx.CreateBucket([]byte("foo")) assert.Nil(t, b) - assert.Equal(t, ErrTxClosed, err) + assert.Equal(t, bolt.ErrTxClosed, err) } // Ensure that a Tx can retrieve a bucket. func TestTx_Bucket(t *testing.T) { db := NewTestDB() defer db.Close() - db.Update(func(tx *Tx) error { + db.Update(func(tx *bolt.Tx) error { tx.CreateBucket([]byte("widgets")) b := tx.Bucket([]byte("widgets")) assert.NotNil(t, b) @@ -100,7 +101,7 @@ func TestTx_Bucket(t *testing.T) { func TestTx_Get_Missing(t *testing.T) { db := NewTestDB() defer db.Close() - db.Update(func(tx *Tx) error { + db.Update(func(tx *bolt.Tx) error { tx.CreateBucket([]byte("widgets")) tx.Bucket([]byte("widgets")).Put([]byte("foo"), []byte("bar")) value := tx.Bucket([]byte("widgets")).Get([]byte("no_such_key")) @@ -115,7 +116,7 @@ func TestTx_CreateBucket(t *testing.T) { defer db.Close() // Create a bucket. - db.Update(func(tx *Tx) error { + db.Update(func(tx *bolt.Tx) error { b, err := tx.CreateBucket([]byte("widgets")) assert.NotNil(t, b) assert.NoError(t, err) @@ -123,7 +124,7 @@ func TestTx_CreateBucket(t *testing.T) { }) // Read the bucket through a separate transaction. - db.View(func(tx *Tx) error { + db.View(func(tx *bolt.Tx) error { b := tx.Bucket([]byte("widgets")) assert.NotNil(t, b) return nil @@ -134,7 +135,7 @@ func TestTx_CreateBucket(t *testing.T) { func TestTx_CreateBucketIfNotExists(t *testing.T) { db := NewTestDB() defer db.Close() - db.Update(func(tx *Tx) error { + db.Update(func(tx *bolt.Tx) error { b, err := tx.CreateBucketIfNotExists([]byte("widgets")) assert.NotNil(t, b) assert.NoError(t, err) @@ -145,16 +146,16 @@ func TestTx_CreateBucketIfNotExists(t *testing.T) { b, err = tx.CreateBucketIfNotExists([]byte{}) assert.Nil(t, b) - assert.Equal(t, ErrBucketNameRequired, err) + assert.Equal(t, bolt.ErrBucketNameRequired, err) b, err = tx.CreateBucketIfNotExists(nil) assert.Nil(t, b) - assert.Equal(t, ErrBucketNameRequired, err) + assert.Equal(t, bolt.ErrBucketNameRequired, err) return nil }) // Read the bucket through a separate transaction. - db.View(func(tx *Tx) error { + db.View(func(tx *bolt.Tx) error { b := tx.Bucket([]byte("widgets")) assert.NotNil(t, b) return nil @@ -166,7 +167,7 @@ func TestTx_CreateBucket_Exists(t *testing.T) { db := NewTestDB() defer db.Close() // Create a bucket. - db.Update(func(tx *Tx) error { + db.Update(func(tx *bolt.Tx) error { b, err := tx.CreateBucket([]byte("widgets")) assert.NotNil(t, b) assert.NoError(t, err) @@ -174,10 +175,10 @@ func TestTx_CreateBucket_Exists(t *testing.T) { }) // Create the same bucket again. - db.Update(func(tx *Tx) error { + db.Update(func(tx *bolt.Tx) error { b, err := tx.CreateBucket([]byte("widgets")) assert.Nil(t, b) - assert.Equal(t, ErrBucketExists, err) + assert.Equal(t, bolt.ErrBucketExists, err) return nil }) } @@ -186,10 +187,10 @@ func TestTx_CreateBucket_Exists(t *testing.T) { func TestTx_CreateBucket_NameRequired(t *testing.T) { db := NewTestDB() defer db.Close() - db.Update(func(tx *Tx) error { + db.Update(func(tx *bolt.Tx) error { b, err := tx.CreateBucket(nil) assert.Nil(t, b) - assert.Equal(t, ErrBucketNameRequired, err) + assert.Equal(t, bolt.ErrBucketNameRequired, err) return nil }) } @@ -200,30 +201,20 @@ func TestTx_DeleteBucket(t *testing.T) { defer db.Close() // Create a bucket and add a value. - db.Update(func(tx *Tx) error { + db.Update(func(tx *bolt.Tx) error { tx.CreateBucket([]byte("widgets")) tx.Bucket([]byte("widgets")).Put([]byte("foo"), []byte("bar")) return nil }) - // Save root page id. - var root pgid - db.View(func(tx *Tx) error { - root = tx.Bucket([]byte("widgets")).root - return nil - }) - // Delete the bucket and make sure we can't get the value. - db.Update(func(tx *Tx) error { + db.Update(func(tx *bolt.Tx) error { assert.NoError(t, tx.DeleteBucket([]byte("widgets"))) assert.Nil(t, tx.Bucket([]byte("widgets"))) return nil }) - db.Update(func(tx *Tx) error { - // Verify that the bucket's page is free. - assert.Equal(t, []pgid{4, 5}, db.freelist.all()) - + db.Update(func(tx *bolt.Tx) error { // Create the bucket again and make sure there's not a phantom value. b, err := tx.CreateBucket([]byte("widgets")) assert.NotNil(t, b) @@ -239,15 +230,15 @@ func TestTx_DeleteBucket_Closed(t *testing.T) { defer db.Close() tx, _ := db.Begin(true) tx.Commit() - assert.Equal(t, tx.DeleteBucket([]byte("foo")), ErrTxClosed) + assert.Equal(t, tx.DeleteBucket([]byte("foo")), bolt.ErrTxClosed) } // Ensure that deleting a bucket with a read-only transaction returns an error. func TestTx_DeleteBucket_ReadOnly(t *testing.T) { db := NewTestDB() defer db.Close() - db.View(func(tx *Tx) error { - assert.Equal(t, tx.DeleteBucket([]byte("foo")), ErrTxNotWritable) + db.View(func(tx *bolt.Tx) error { + assert.Equal(t, tx.DeleteBucket([]byte("foo")), bolt.ErrTxNotWritable) return nil }) } @@ -256,8 +247,8 @@ func TestTx_DeleteBucket_ReadOnly(t *testing.T) { func TestTx_DeleteBucket_NotFound(t *testing.T) { db := NewTestDB() defer db.Close() - db.Update(func(tx *Tx) error { - assert.Equal(t, ErrBucketNotFound, tx.DeleteBucket([]byte("widgets"))) + db.Update(func(tx *bolt.Tx) error { + assert.Equal(t, bolt.ErrBucketNotFound, tx.DeleteBucket([]byte("widgets"))) return nil }) } @@ -267,7 +258,7 @@ func TestTx_OnCommit(t *testing.T) { var x int db := NewTestDB() defer db.Close() - db.Update(func(tx *Tx) error { + db.Update(func(tx *bolt.Tx) error { tx.OnCommit(func() { x += 1 }) tx.OnCommit(func() { x += 2 }) _, err := tx.CreateBucket([]byte("widgets")) @@ -281,7 +272,7 @@ func TestTx_OnCommit_Rollback(t *testing.T) { var x int db := NewTestDB() defer db.Close() - db.Update(func(tx *Tx) error { + db.Update(func(tx *bolt.Tx) error { tx.OnCommit(func() { x += 1 }) tx.OnCommit(func() { x += 2 }) tx.CreateBucket([]byte("widgets")) @@ -295,20 +286,20 @@ func TestTx_CopyFile(t *testing.T) { db := NewTestDB() defer db.Close() var dest = tempfile() - db.Update(func(tx *Tx) error { + db.Update(func(tx *bolt.Tx) error { tx.CreateBucket([]byte("widgets")) tx.Bucket([]byte("widgets")).Put([]byte("foo"), []byte("bar")) tx.Bucket([]byte("widgets")).Put([]byte("baz"), []byte("bat")) return nil }) - assert.NoError(t, db.View(func(tx *Tx) error { return tx.CopyFile(dest, 0600) })) + assert.NoError(t, db.View(func(tx *bolt.Tx) error { return tx.CopyFile(dest, 0600) })) - db2, err := Open(dest, 0600, nil) + db2, err := bolt.Open(dest, 0600, nil) assert.NoError(t, err) defer db2.Close() - db2.View(func(tx *Tx) error { + db2.View(func(tx *bolt.Tx) error { assert.Equal(t, []byte("bar"), tx.Bucket([]byte("widgets")).Get([]byte("foo"))) assert.Equal(t, []byte("bat"), tx.Bucket([]byte("widgets")).Get([]byte("baz"))) return nil @@ -340,14 +331,14 @@ func (f *failWriter) Write(p []byte) (n int, err error) { func TestTx_CopyFile_Error_Meta(t *testing.T) { db := NewTestDB() defer db.Close() - db.Update(func(tx *Tx) error { + db.Update(func(tx *bolt.Tx) error { tx.CreateBucket([]byte("widgets")) tx.Bucket([]byte("widgets")).Put([]byte("foo"), []byte("bar")) tx.Bucket([]byte("widgets")).Put([]byte("baz"), []byte("bat")) return nil }) - err := db.View(func(tx *Tx) error { return tx.Copy(&failWriter{}) }) + err := db.View(func(tx *bolt.Tx) error { return tx.Copy(&failWriter{}) }) assert.EqualError(t, err, "meta copy: error injected for tests") } @@ -355,31 +346,31 @@ func TestTx_CopyFile_Error_Meta(t *testing.T) { func TestTx_CopyFile_Error_Normal(t *testing.T) { db := NewTestDB() defer db.Close() - db.Update(func(tx *Tx) error { + db.Update(func(tx *bolt.Tx) error { tx.CreateBucket([]byte("widgets")) tx.Bucket([]byte("widgets")).Put([]byte("foo"), []byte("bar")) tx.Bucket([]byte("widgets")).Put([]byte("baz"), []byte("bat")) return nil }) - err := db.View(func(tx *Tx) error { return tx.Copy(&failWriter{3 * db.pageSize}) }) + err := db.View(func(tx *bolt.Tx) error { return tx.Copy(&failWriter{3 * db.Info().PageSize}) }) assert.EqualError(t, err, "error injected for tests") } func ExampleTx_Rollback() { // Open the database. - db, _ := Open(tempfile(), 0666, nil) + db, _ := bolt.Open(tempfile(), 0666, nil) defer os.Remove(db.Path()) defer db.Close() // Create a bucket. - db.Update(func(tx *Tx) error { + db.Update(func(tx *bolt.Tx) error { _, err := tx.CreateBucket([]byte("widgets")) return err }) // Set a value for a key. - db.Update(func(tx *Tx) error { + db.Update(func(tx *bolt.Tx) error { return tx.Bucket([]byte("widgets")).Put([]byte("foo"), []byte("bar")) }) @@ -390,7 +381,7 @@ func ExampleTx_Rollback() { tx.Rollback() // Ensure that our original value is still set. - db.View(func(tx *Tx) error { + db.View(func(tx *bolt.Tx) error { value := tx.Bucket([]byte("widgets")).Get([]byte("foo")) fmt.Printf("The value for 'foo' is still: %s\n", value) return nil @@ -402,12 +393,12 @@ func ExampleTx_Rollback() { func ExampleTx_CopyFile() { // Open the database. - db, _ := Open(tempfile(), 0666, nil) + db, _ := bolt.Open(tempfile(), 0666, nil) defer os.Remove(db.Path()) defer db.Close() // Create a bucket and a key. - db.Update(func(tx *Tx) error { + db.Update(func(tx *bolt.Tx) error { tx.CreateBucket([]byte("widgets")) tx.Bucket([]byte("widgets")).Put([]byte("foo"), []byte("bar")) return nil @@ -415,15 +406,15 @@ func ExampleTx_CopyFile() { // Copy the database to another file. toFile := tempfile() - db.View(func(tx *Tx) error { return tx.CopyFile(toFile, 0666) }) + db.View(func(tx *bolt.Tx) error { return tx.CopyFile(toFile, 0666) }) defer os.Remove(toFile) // Open the cloned database. - db2, _ := Open(toFile, 0666, nil) + db2, _ := bolt.Open(toFile, 0666, nil) defer db2.Close() // Ensure that the key exists in the copy. - db2.View(func(tx *Tx) error { + db2.View(func(tx *bolt.Tx) error { value := tx.Bucket([]byte("widgets")).Get([]byte("foo")) fmt.Printf("The value for 'foo' in the clone is: %s\n", value) return nil