aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBen Johnson <benbjohnson@yahoo.com>2014-03-21 09:46:03 -0600
committerBen Johnson <benbjohnson@yahoo.com>2014-03-21 09:52:01 -0600
commit3cc959fb1a51296c3bb391c80280e37a02f0b6a5 (patch)
treef5b3993dd328b6896b57f954e4fc37125054ce97
parentMerge pull request #65 from benbjohnson/fix-tx-buckets-sort-order (diff)
downloaddedo-3cc959fb1a51296c3bb391c80280e37a02f0b6a5.tar.gz
dedo-3cc959fb1a51296c3bb391c80280e37a02f0b6a5.tar.xz
Remove ease-of-use functions from the DB type.
Functions such as DB.Put(), DB.Get(), and DB.Delete() were originally added to be easy to use, however, after implementing Bolt in multiple projects I have found these ease-of-use functions useless. Nearly every use case requires multiple calls in a single transaction. Using the DB ease of use functions turned out to be an antipattern.
-rw-r--r--bucket_test.go323
-rw-r--r--db.go129
-rw-r--r--db_test.go111
-rw-r--r--example_test.go194
-rw-r--r--functional_test.go4
-rw-r--r--tx_test.go225
6 files changed, 479 insertions, 507 deletions
diff --git a/bucket_test.go b/bucket_test.go
index 1970260..92d5288 100644
--- a/bucket_test.go
+++ b/bucket_test.go
@@ -15,19 +15,20 @@ import (
// Ensure that a bucket that gets a non-existent key returns nil.
func TestBucketGetNonExistent(t *testing.T) {
withOpenDB(func(db *DB, path string) {
- db.CreateBucket("widgets")
- value, err := db.Get("widgets", []byte("foo"))
- if assert.NoError(t, err) {
+ db.Do(func(tx *Tx) error {
+ tx.CreateBucket("widgets")
+ value := tx.Bucket("widgets").Get([]byte("foo"))
assert.Nil(t, value)
- }
+ return nil
+ })
})
}
// Ensure that a bucket can read a value that is not flushed yet.
func TestBucketGetFromNode(t *testing.T) {
withOpenDB(func(db *DB, path string) {
- db.CreateBucket("widgets")
db.Do(func(tx *Tx) error {
+ tx.CreateBucket("widgets")
b := tx.Bucket("widgets")
b.Put([]byte("foo"), []byte("bar"))
value := b.Get([]byte("foo"))
@@ -40,20 +41,24 @@ func TestBucketGetFromNode(t *testing.T) {
// Ensure that a bucket can write a key/value.
func TestBucketPut(t *testing.T) {
withOpenDB(func(db *DB, path string) {
- db.CreateBucket("widgets")
- err := db.Put("widgets", []byte("foo"), []byte("bar"))
- assert.NoError(t, err)
- value, err := db.Get("widgets", []byte("foo"))
- if assert.NoError(t, err) {
+ db.Do(func(tx *Tx) error {
+ tx.CreateBucket("widgets")
+ err := tx.Bucket("widgets").Put([]byte("foo"), []byte("bar"))
+ assert.NoError(t, err)
+ value := tx.Bucket("widgets").Get([]byte("foo"))
assert.Equal(t, value, []byte("bar"))
- }
+ return nil
+ })
})
}
// Ensure that setting a value on a read-only bucket returns an error.
func TestBucketPutReadOnly(t *testing.T) {
withOpenDB(func(db *DB, path string) {
- db.CreateBucket("widgets")
+ db.Do(func(tx *Tx) error {
+ tx.CreateBucket("widgets")
+ return nil
+ })
db.With(func(tx *Tx) error {
b := tx.Bucket("widgets")
err := b.Put([]byte("foo"), []byte("bar"))
@@ -66,21 +71,25 @@ func TestBucketPutReadOnly(t *testing.T) {
// Ensure that a bucket can delete an existing key.
func TestBucketDelete(t *testing.T) {
withOpenDB(func(db *DB, path string) {
- db.CreateBucket("widgets")
- db.Put("widgets", []byte("foo"), []byte("bar"))
- err := db.Delete("widgets", []byte("foo"))
- assert.NoError(t, err)
- value, err := db.Get("widgets", []byte("foo"))
- if assert.NoError(t, err) {
+ db.Do(func(tx *Tx) error {
+ tx.CreateBucket("widgets")
+ tx.Bucket("widgets").Put([]byte("foo"), []byte("bar"))
+ err := tx.Bucket("widgets").Delete([]byte("foo"))
+ assert.NoError(t, err)
+ value := tx.Bucket("widgets").Get([]byte("foo"))
assert.Nil(t, value)
- }
+ return nil
+ })
})
}
// Ensure that deleting a key on a read-only bucket returns an error.
func TestBucketDeleteReadOnly(t *testing.T) {
withOpenDB(func(db *DB, path string) {
- db.CreateBucket("widgets")
+ db.Do(func(tx *Tx) error {
+ tx.CreateBucket("widgets")
+ return nil
+ })
db.With(func(tx *Tx) error {
b := tx.Bucket("widgets")
err := b.Delete([]byte("foo"))
@@ -93,33 +102,34 @@ func TestBucketDeleteReadOnly(t *testing.T) {
// Ensure that a bucket can return an autoincrementing sequence.
func TestBucketNextSequence(t *testing.T) {
withOpenDB(func(db *DB, path string) {
- db.CreateBucket("widgets")
- db.CreateBucket("woojits")
-
- // Make sure sequence increments.
- seq, err := db.NextSequence("widgets")
- assert.NoError(t, err)
- assert.Equal(t, seq, 1)
- seq, err = db.NextSequence("widgets")
- assert.NoError(t, err)
- assert.Equal(t, seq, 2)
-
- // Buckets should be separate.
- seq, err = db.NextSequence("woojits")
- assert.NoError(t, err)
- assert.Equal(t, seq, 1)
-
- // Missing buckets return an error.
- seq, err = db.NextSequence("no_such_bucket")
- assert.Equal(t, err, ErrBucketNotFound)
- assert.Equal(t, seq, 0)
+ db.Do(func(tx *Tx) error {
+ tx.CreateBucket("widgets")
+ tx.CreateBucket("woojits")
+
+ // Make sure sequence increments.
+ seq, err := tx.Bucket("widgets").NextSequence()
+ assert.NoError(t, err)
+ assert.Equal(t, seq, 1)
+ seq, err = tx.Bucket("widgets").NextSequence()
+ assert.NoError(t, err)
+ assert.Equal(t, seq, 2)
+
+ // Buckets should be separate.
+ seq, err = tx.Bucket("woojits").NextSequence()
+ assert.NoError(t, err)
+ assert.Equal(t, seq, 1)
+ return nil
+ })
})
}
// Ensure that retrieving the next sequence on a read-only bucket returns an error.
func TestBucketNextSequenceReadOnly(t *testing.T) {
withOpenDB(func(db *DB, path string) {
- db.CreateBucket("widgets")
+ db.Do(func(tx *Tx) error {
+ tx.CreateBucket("widgets")
+ return nil
+ })
db.With(func(tx *Tx) error {
b := tx.Bucket("widgets")
i, err := b.NextSequence()
@@ -133,7 +143,10 @@ func TestBucketNextSequenceReadOnly(t *testing.T) {
// Ensure that incrementing past the maximum sequence number will return an error.
func TestBucketNextSequenceOverflow(t *testing.T) {
withOpenDB(func(db *DB, path string) {
- db.CreateBucket("widgets")
+ db.Do(func(tx *Tx) error {
+ tx.CreateBucket("widgets")
+ return nil
+ })
db.Do(func(tx *Tx) error {
b := tx.Bucket("widgets")
b.bucket.sequence = uint64(maxInt)
@@ -148,70 +161,82 @@ func TestBucketNextSequenceOverflow(t *testing.T) {
// Ensure a database can loop over all key/value pairs in a bucket.
func TestBucketForEach(t *testing.T) {
withOpenDB(func(db *DB, path string) {
- db.CreateBucket("widgets")
- db.Put("widgets", []byte("foo"), []byte("0000"))
- db.Put("widgets", []byte("baz"), []byte("0001"))
- db.Put("widgets", []byte("bar"), []byte("0002"))
-
- var index int
- err := db.ForEach("widgets", func(k, v []byte) error {
- switch index {
- case 0:
- assert.Equal(t, k, []byte("bar"))
- assert.Equal(t, v, []byte("0002"))
- case 1:
- assert.Equal(t, k, []byte("baz"))
- assert.Equal(t, v, []byte("0001"))
- case 2:
- assert.Equal(t, k, []byte("foo"))
- assert.Equal(t, v, []byte("0000"))
- }
- index++
+ db.Do(func(tx *Tx) error {
+ tx.CreateBucket("widgets")
+ tx.Bucket("widgets").Put([]byte("foo"), []byte("0000"))
+ tx.Bucket("widgets").Put([]byte("baz"), []byte("0001"))
+ tx.Bucket("widgets").Put([]byte("bar"), []byte("0002"))
+
+ var index int
+ err := tx.Bucket("widgets").ForEach(func(k, v []byte) error {
+ switch index {
+ case 0:
+ assert.Equal(t, k, []byte("bar"))
+ assert.Equal(t, v, []byte("0002"))
+ case 1:
+ assert.Equal(t, k, []byte("baz"))
+ assert.Equal(t, v, []byte("0001"))
+ case 2:
+ assert.Equal(t, k, []byte("foo"))
+ assert.Equal(t, v, []byte("0000"))
+ }
+ index++
+ return nil
+ })
+ assert.NoError(t, err)
+ assert.Equal(t, index, 3)
return nil
})
- assert.NoError(t, err)
- assert.Equal(t, index, 3)
})
}
// Ensure a database can stop iteration early.
func TestBucketForEachShortCircuit(t *testing.T) {
withOpenDB(func(db *DB, path string) {
- db.CreateBucket("widgets")
- db.Put("widgets", []byte("bar"), []byte("0000"))
- db.Put("widgets", []byte("baz"), []byte("0000"))
- db.Put("widgets", []byte("foo"), []byte("0000"))
-
- var index int
- err := db.ForEach("widgets", func(k, v []byte) error {
- index++
- if bytes.Equal(k, []byte("baz")) {
- return &Error{"marker", nil}
- }
+ db.Do(func(tx *Tx) error {
+ tx.CreateBucket("widgets")
+ tx.Bucket("widgets").Put([]byte("bar"), []byte("0000"))
+ tx.Bucket("widgets").Put([]byte("baz"), []byte("0000"))
+ tx.Bucket("widgets").Put([]byte("foo"), []byte("0000"))
+
+ var index int
+ err := tx.Bucket("widgets").ForEach(func(k, v []byte) error {
+ index++
+ if bytes.Equal(k, []byte("baz")) {
+ return &Error{"marker", nil}
+ }
+ return nil
+ })
+ assert.Equal(t, err, &Error{"marker", nil})
+ assert.Equal(t, index, 2)
return nil
})
- assert.Equal(t, err, &Error{"marker", nil})
- assert.Equal(t, index, 2)
})
}
// Ensure that an error is returned when inserting with an empty key.
func TestBucketPutEmptyKey(t *testing.T) {
withOpenDB(func(db *DB, path string) {
- db.CreateBucket("widgets")
- err := db.Put("widgets", []byte(""), []byte("bar"))
- assert.Equal(t, err, ErrKeyRequired)
- err = db.Put("widgets", nil, []byte("bar"))
- assert.Equal(t, err, ErrKeyRequired)
+ db.Do(func(tx *Tx) error {
+ tx.CreateBucket("widgets")
+ err := tx.Bucket("widgets").Put([]byte(""), []byte("bar"))
+ assert.Equal(t, err, ErrKeyRequired)
+ err = tx.Bucket("widgets").Put(nil, []byte("bar"))
+ assert.Equal(t, err, ErrKeyRequired)
+ return nil
+ })
})
}
// Ensure that an error is returned when inserting with a key that's too large.
func TestBucketPutKeyTooLarge(t *testing.T) {
withOpenDB(func(db *DB, path string) {
- db.CreateBucket("widgets")
- err := db.Put("widgets", make([]byte, 32769), []byte("bar"))
- assert.Equal(t, err, ErrKeyTooLarge)
+ db.Do(func(tx *Tx) error {
+ tx.CreateBucket("widgets")
+ err := tx.Bucket("widgets").Put(make([]byte, 32769), []byte("bar"))
+ assert.Equal(t, err, ErrKeyTooLarge)
+ return nil
+ })
})
}
@@ -286,30 +311,35 @@ func TestBucketPutSingle(t *testing.T) {
withOpenDB(func(db *DB, path string) {
m := make(map[string][]byte)
- db.CreateBucket("widgets")
+ db.Do(func(tx *Tx) error {
+ return tx.CreateBucket("widgets")
+ })
for _, item := range items {
- if err := db.Put("widgets", item.Key, item.Value); err != nil {
- panic("put error: " + err.Error())
- }
- m[string(item.Key)] = item.Value
+ db.Do(func(tx *Tx) error {
+ if err := tx.Bucket("widgets").Put(item.Key, item.Value); err != nil {
+ panic("put error: " + err.Error())
+ }
+ m[string(item.Key)] = item.Value
+ return nil
+ })
// Verify all key/values so far.
- i := 0
- for k, v := range m {
- value, err := db.Get("widgets", []byte(k))
- if err != nil {
- panic("get error: " + err.Error())
- }
- if !bytes.Equal(value, v) {
- db.CopyFile("/tmp/bolt.put.single.db", 0666)
- t.Fatalf("value mismatch [run %d] (%d of %d):\nkey: %x\ngot: %x\nexp: %x", index, i, len(m), []byte(k), value, v)
+ db.With(func(tx *Tx) error {
+ i := 0
+ for k, v := range m {
+ value := tx.Bucket("widgets").Get([]byte(k))
+ if !bytes.Equal(value, v) {
+ db.CopyFile("/tmp/bolt.put.single.db", 0666)
+ t.Fatalf("value mismatch [run %d] (%d of %d):\nkey: %x\ngot: %x\nexp: %x", index, i, len(m), []byte(k), value, v)
+ }
+ i++
}
- i++
- }
+ return nil
+ })
}
-
- fmt.Fprint(os.Stderr, ".")
})
+
+ fmt.Fprint(os.Stderr, ".")
index++
return true
}
@@ -328,25 +358,30 @@ func TestBucketPutMultiple(t *testing.T) {
f := func(items testdata) bool {
withOpenDB(func(db *DB, path string) {
// Bulk insert all values.
- db.CreateBucket("widgets")
- tx, _ := db.RWTx()
- b := tx.Bucket("widgets")
- for _, item := range items {
- assert.NoError(t, b.Put(item.Key, item.Value))
- }
- assert.NoError(t, tx.Commit())
+ db.Do(func(tx *Tx) error {
+ return tx.CreateBucket("widgets")
+ })
+ err := db.Do(func(tx *Tx) error {
+ b := tx.Bucket("widgets")
+ for _, item := range items {
+ assert.NoError(t, b.Put(item.Key, item.Value))
+ }
+ return nil
+ })
+ assert.NoError(t, err)
// Verify all items exist.
- tx, _ = db.Tx()
- b = tx.Bucket("widgets")
- for _, item := range items {
- value := b.Get(item.Key)
- if !assert.Equal(t, item.Value, value) {
- db.CopyFile("/tmp/bolt.put.multiple.db", 0666)
- t.FailNow()
+ db.With(func(tx *Tx) error {
+ b := tx.Bucket("widgets")
+ for _, item := range items {
+ value := b.Get(item.Key)
+ if !assert.Equal(t, item.Value, value) {
+ db.CopyFile("/tmp/bolt.put.multiple.db", 0666)
+ t.FailNow()
+ }
}
- }
- tx.Rollback()
+ return nil
+ })
})
fmt.Fprint(os.Stderr, ".")
return true
@@ -366,35 +401,43 @@ func TestBucketDeleteQuick(t *testing.T) {
f := func(items testdata) bool {
withOpenDB(func(db *DB, path string) {
// Bulk insert all values.
- db.CreateBucket("widgets")
- tx, _ := db.RWTx()
- b := tx.Bucket("widgets")
- for _, item := range items {
- assert.NoError(t, b.Put(item.Key, item.Value))
- }
- assert.NoError(t, tx.Commit())
+ db.Do(func(tx *Tx) error {
+ return tx.CreateBucket("widgets")
+ })
+ err := db.Do(func(tx *Tx) error {
+ b := tx.Bucket("widgets")
+ for _, item := range items {
+ assert.NoError(t, b.Put(item.Key, item.Value))
+ }
+ return nil
+ })
+ assert.NoError(t, err)
// Remove items one at a time and check consistency.
for i, item := range items {
- assert.NoError(t, db.Delete("widgets", item.Key))
+ err := db.Do(func(tx *Tx) error {
+ return tx.Bucket("widgets").Delete(item.Key)
+ })
+ assert.NoError(t, err)
// Anything before our deletion index should be nil.
- tx, _ := db.Tx()
- b := tx.Bucket("widgets")
- for j, exp := range items {
- if j > i {
- value := b.Get(exp.Key)
- if !assert.Equal(t, exp.Value, value) {
- t.FailNow()
- }
- } else {
- value := b.Get(exp.Key)
- if !assert.Nil(t, value) {
- t.FailNow()
+ db.With(func(tx *Tx) error {
+ b := tx.Bucket("widgets")
+ for j, exp := range items {
+ if j > i {
+ value := b.Get(exp.Key)
+ if !assert.Equal(t, exp.Value, value) {
+ t.FailNow()
+ }
+ } else {
+ value := b.Get(exp.Key)
+ if !assert.Nil(t, value) {
+ t.FailNow()
+ }
}
}
- }
- tx.Rollback()
+ return nil
+ })
}
})
fmt.Fprint(os.Stderr, ".")
diff --git a/db.go b/db.go
index 6493e1b..ed6f176 100644
--- a/db.go
+++ b/db.go
@@ -372,135 +372,6 @@ func (db *DB) With(fn func(*Tx) error) error {
return fn(t)
}
-// ForEach executes a function for each key/value pair in a bucket.
-// An error is returned if the bucket cannot be found.
-func (db *DB) ForEach(name string, fn func(k, v []byte) error) error {
- return db.With(func(t *Tx) error {
- b := t.Bucket(name)
- if b == nil {
- return ErrBucketNotFound
- }
- return b.ForEach(fn)
- })
-}
-
-// Bucket retrieves a reference to a bucket.
-// This is typically useful for checking the existence of a bucket.
-func (db *DB) Bucket(name string) (*Bucket, error) {
- t, err := db.Tx()
- if err != nil {
- return nil, err
- }
- defer t.Rollback()
- return t.Bucket(name), nil
-}
-
-// Buckets retrieves a list of all buckets in the database.
-func (db *DB) Buckets() ([]*Bucket, error) {
- t, err := db.Tx()
- if err != nil {
- return nil, err
- }
- defer t.Rollback()
- return t.Buckets(), nil
-}
-
-// CreateBucket creates a new bucket with the given name.
-// This function can return an error if the bucket already exists, if the name
-// is blank, or the bucket name is too long.
-func (db *DB) CreateBucket(name string) error {
- return db.Do(func(t *Tx) error {
- return t.CreateBucket(name)
- })
-}
-
-// CreateBucketIfNotExists creates a new bucket with the given name if it doesn't already exist.
-// This function can return an error if the name is blank, or the bucket name is too long.
-func (db *DB) CreateBucketIfNotExists(name string) error {
- return db.Do(func(t *Tx) error {
- return t.CreateBucketIfNotExists(name)
- })
-}
-
-// DeleteBucket removes a bucket from the database.
-// Returns an error if the bucket does not exist.
-func (db *DB) DeleteBucket(name string) error {
- return db.Do(func(t *Tx) error {
- return t.DeleteBucket(name)
- })
-}
-
-// NextSequence returns an autoincrementing integer for the bucket.
-// This function can return an error if the bucket does not exist.
-func (db *DB) NextSequence(name string) (int, error) {
- var seq int
- err := db.Do(func(t *Tx) error {
- b := t.Bucket(name)
- if b == nil {
- return ErrBucketNotFound
- }
-
- var err error
- seq, err = b.NextSequence()
- return err
- })
- if err != nil {
- return 0, err
- }
- return seq, nil
-}
-
-// Get retrieves the value for a key in a bucket.
-// Returns an error if the key does not exist.
-func (db *DB) Get(name string, key []byte) ([]byte, error) {
- t, err := db.Tx()
- if err != nil {
- return nil, err
- }
- defer t.Rollback()
-
- // Open bucket and retrieve value for key.
- b := t.Bucket(name)
- if b == nil {
- return nil, ErrBucketNotFound
- }
- value := b.Get(key)
- if value == nil {
- return nil, nil
- }
-
- // Copy the value out since the transaction will be closed after this
- // function ends. The data can get reclaimed between now and when the
- // value is used.
- tmp := make([]byte, len(value))
- copy(tmp, value)
- return tmp, nil
-}
-
-// Put sets the value for a key in a bucket.
-// Returns an error if the bucket is not found, if key is blank, if the key is too large, or if the value is too large.
-func (db *DB) Put(name string, key []byte, value []byte) error {
- return db.Do(func(t *Tx) error {
- b := t.Bucket(name)
- if b == nil {
- return ErrBucketNotFound
- }
- return b.Put(key, value)
- })
-}
-
-// Delete removes a key from a bucket.
-// Returns an error if the bucket cannot be found.
-func (db *DB) Delete(name string, key []byte) error {
- return db.Do(func(t *Tx) error {
- b := t.Bucket(name)
- if b == nil {
- return ErrBucketNotFound
- }
- return b.Delete(key)
- })
-}
-
// Copy writes the entire database to a writer.
// A reader transaction is maintained during the copy so it is safe to continue
// using the database while a copy is in progress.
diff --git a/db_test.go b/db_test.go
index e35502c..d7db679 100644
--- a/db_test.go
+++ b/db_test.go
@@ -164,14 +164,6 @@ func TestDBTxErrDatabaseNotOpen(t *testing.T) {
})
}
-// Ensure that a delete on a missing bucket returns an error.
-func TestDBDeleteFromMissingBucket(t *testing.T) {
- withOpenDB(func(db *DB, path string) {
- err := db.Delete("widgets", []byte("foo"))
- assert.Equal(t, err, ErrBucketNotFound)
- })
-}
-
// Ensure that a read-write transaction can be retrieved.
func TestDBRWTx(t *testing.T) {
withOpenDB(func(db *DB, path string) {
@@ -204,10 +196,12 @@ func TestDBTxBlock(t *testing.T) {
return nil
})
assert.NoError(t, err)
- value, _ := db.Get("widgets", []byte("foo"))
- assert.Nil(t, value)
- value, _ = db.Get("widgets", []byte("baz"))
- assert.Equal(t, value, []byte("bat"))
+ err = db.With(func(tx *Tx) error {
+ assert.Nil(t, tx.Bucket("widgets").Get([]byte("foo")))
+ assert.Equal(t, []byte("bat"), tx.Bucket("widgets").Get([]byte("baz")))
+ return nil
+ })
+ assert.NoError(t, err)
})
}
@@ -222,63 +216,15 @@ func TestDBTxBlockWhileClosed(t *testing.T) {
})
}
-// Ensure a database returns an error when trying to attempt a for each on a missing bucket.
-func TestDBForEachBucketNotFound(t *testing.T) {
- withOpenDB(func(db *DB, path string) {
- err := db.ForEach("widgets", func(k, v []byte) error { return nil })
- assert.Equal(t, err, ErrBucketNotFound)
- })
-}
-
-// Ensure a closed database returns an error when executing a for each.
-func TestDBForEachWhileClosed(t *testing.T) {
- withDB(func(db *DB, path string) {
- err := db.ForEach("widgets", func(k, v []byte) error { return nil })
- assert.Equal(t, err, ErrDatabaseNotOpen)
- })
-}
-
-// Ensure a closed database returns an error when finding a bucket.
-func TestDBBucketWhileClosed(t *testing.T) {
- withDB(func(db *DB, path string) {
- b, err := db.Bucket("widgets")
- assert.Equal(t, err, ErrDatabaseNotOpen)
- assert.Nil(t, b)
- })
-}
-
-// Ensure a closed database returns an error when finding all buckets.
-func TestDBBucketsWhileClosed(t *testing.T) {
- withDB(func(db *DB, path string) {
- b, err := db.Buckets()
- assert.Equal(t, err, ErrDatabaseNotOpen)
- assert.Nil(t, b)
- })
-}
-
-// Ensure a closed database returns an error when getting a key.
-func TestDBGetWhileClosed(t *testing.T) {
- withDB(func(db *DB, path string) {
- value, err := db.Get("widgets", []byte("foo"))
- assert.Equal(t, err, ErrDatabaseNotOpen)
- assert.Nil(t, value)
- })
-}
-
-// Ensure that an error is returned when inserting into a bucket that doesn't exist.
-func TestDBPutBucketNotFound(t *testing.T) {
- withOpenDB(func(db *DB, path string) {
- err := db.Put("widgets", []byte("foo"), []byte("bar"))
- assert.Equal(t, err, ErrBucketNotFound)
- })
-}
-
// Ensure that the database can be copied to a file path.
func TestDBCopyFile(t *testing.T) {
withOpenDB(func(db *DB, path string) {
- db.CreateBucket("widgets")
- db.Put("widgets", []byte("foo"), []byte("bar"))
- db.Put("widgets", []byte("baz"), []byte("bat"))
+ db.Do(func(tx *Tx) error {
+ tx.CreateBucket("widgets")
+ tx.Bucket("widgets").Put([]byte("foo"), []byte("bar"))
+ tx.Bucket("widgets").Put([]byte("baz"), []byte("bat"))
+ return nil
+ })
assert.NoError(t, os.RemoveAll("/tmp/bolt.copyfile.db"))
assert.NoError(t, db.CopyFile("/tmp/bolt.copyfile.db", 0666))
@@ -286,10 +232,11 @@ func TestDBCopyFile(t *testing.T) {
assert.NoError(t, db2.Open("/tmp/bolt.copyfile.db", 0666))
defer db2.Close()
- value, _ := db2.Get("widgets", []byte("foo"))
- assert.Equal(t, value, []byte("bar"))
- value, _ = db2.Get("widgets", []byte("baz"))
- assert.Equal(t, value, []byte("bat"))
+ db2.With(func(tx *Tx) error {
+ assert.Equal(t, []byte("bar"), tx.Bucket("widgets").Get([]byte("foo")))
+ assert.Equal(t, []byte("bat"), tx.Bucket("widgets").Get([]byte("baz")))
+ return nil
+ })
})
}
@@ -306,8 +253,12 @@ func TestDBStat(t *testing.T) {
})
// Delete some keys.
- db.Delete("widgets", []byte("10"))
- db.Delete("widgets", []byte("1000"))
+ db.Do(func(tx *Tx) error {
+ return tx.Bucket("widgets").Delete([]byte("10"))
+ })
+ db.Do(func(tx *Tx) error {
+ return tx.Bucket("widgets").Delete([]byte("1000"))
+ })
// Open some readers.
t0, _ := db.Tx()
@@ -367,9 +318,13 @@ func TestDBString(t *testing.T) {
func BenchmarkDBPutSequential(b *testing.B) {
value := []byte(strings.Repeat("0", 64))
withOpenDB(func(db *DB, path string) {
- db.CreateBucket("widgets")
+ db.Do(func(tx *Tx) error {
+ return tx.CreateBucket("widgets")
+ })
for i := 0; i < b.N; i++ {
- db.Put("widgets", []byte(strconv.Itoa(i)), value)
+ db.Do(func(tx *Tx) error {
+ return tx.Bucket("widgets").Put([]byte(strconv.Itoa(i)), value)
+ })
}
})
}
@@ -379,9 +334,13 @@ func BenchmarkDBPutRandom(b *testing.B) {
indexes := rand.Perm(b.N)
value := []byte(strings.Repeat("0", 64))
withOpenDB(func(db *DB, path string) {
- db.CreateBucket("widgets")
+ db.Do(func(tx *Tx) error {
+ return tx.CreateBucket("widgets")
+ })
for i := 0; i < b.N; i++ {
- db.Put("widgets", []byte(strconv.Itoa(indexes[i])), value)
+ db.Do(func(tx *Tx) error {
+ return tx.Bucket("widgets").Put([]byte(strconv.Itoa(indexes[i])), value)
+ })
}
})
}
diff --git a/example_test.go b/example_test.go
index 0185bb1..6c6e6f5 100644
--- a/example_test.go
+++ b/example_test.go
@@ -10,121 +10,148 @@ func init() {
os.MkdirAll("/tmp/bolt", 0777)
}
-func ExampleDB_Put() {
+func ExampleDB_Do() {
// Open the database.
var db DB
- db.Open("/tmp/bolt/db_put.db", 0666)
+ db.Open("/tmp/bolt/db_do.db", 0666)
defer db.Close()
- // Create a bucket.
- db.CreateBucket("widgets")
-
- // Set the value "bar" for the key "foo".
- db.Put("widgets", []byte("foo"), []byte("bar"))
+ // Execute several commands within a write transaction.
+ err := db.Do(func(tx *Tx) error {
+ if err := tx.CreateBucket("widgets"); err != nil {
+ return err
+ }
+ b := tx.Bucket("widgets")
+ if err := b.Put([]byte("foo"), []byte("bar")); err != nil {
+ return err
+ }
+ return nil
+ })
- // Retrieve the key back from the database and verify it.
- value, _ := db.Get("widgets", []byte("foo"))
- fmt.Printf("The value of 'foo' is: %s\n", string(value))
+ // If our transactional block didn't return an error then our data is saved.
+ if err == nil {
+ db.With(func(tx *Tx) error {
+ value := tx.Bucket("widgets").Get([]byte("foo"))
+ fmt.Printf("The value of 'foo' is: %s\n", string(value))
+ return nil
+ })
+ }
// Output:
// The value of 'foo' is: bar
}
-func ExampleDB_Delete() {
+func ExampleDB_With() {
// Open the database.
var db DB
- db.Open("/tmp/bolt/db_delete.db", 0666)
+ db.Open("/tmp/bolt/db_with.db", 0666)
defer db.Close()
- // Create a bucket.
- db.CreateBucket("widgets")
-
- // Set the value "bar" for the key "foo".
- db.Put("widgets", []byte("foo"), []byte("bar"))
-
- // Retrieve the key back from the database and verify it.
- value, _ := db.Get("widgets", []byte("foo"))
- fmt.Printf("The value of 'foo' was: %s\n", string(value))
-
- // Delete the "foo" key.
- db.Delete("widgets", []byte("foo"))
+ // Insert data into a bucket.
+ db.Do(func(tx *Tx) error {
+ tx.CreateBucket("people")
+ tx.Bucket("people").Put([]byte("john"), []byte("doe"))
+ tx.Bucket("people").Put([]byte("susy"), []byte("que"))
+ return nil
+ })
- // Retrieve the key again.
- value, _ = db.Get("widgets", []byte("foo"))
- if value == nil {
- fmt.Printf("The value of 'foo' is now: nil\n")
- }
+ // Access data from within a read-only transactional block.
+ db.With(func(t *Tx) error {
+ v := t.Bucket("people").Get([]byte("john"))
+ fmt.Printf("John's last name is %s.\n", string(v))
+ return nil
+ })
// Output:
- // The value of 'foo' was: bar
- // The value of 'foo' is now: nil
+ // John's last name is doe.
}
-func ExampleDB_Do() {
+func ExampleTx_Put() {
// Open the database.
var db DB
- db.Open("/tmp/bolt/db_do.db", 0666)
+ db.Open("/tmp/bolt/db_put.db", 0666)
defer db.Close()
- // Execute several commands within a write transaction.
- err := db.Do(func(t *Tx) error {
- if err := t.CreateBucket("widgets"); err != nil {
- return err
- }
- b := t.Bucket("widgets")
- if err := b.Put([]byte("foo"), []byte("bar")); err != nil {
- return err
- }
+ // Start a write transaction.
+ db.Do(func(tx *Tx) error {
+ // Create a bucket.
+ tx.CreateBucket("widgets")
+
+ // Set the value "bar" for the key "foo".
+ tx.Bucket("widgets").Put([]byte("foo"), []byte("bar"))
return nil
})
- // If our transactional block didn't return an error then our data is saved.
- if err == nil {
- value, _ := db.Get("widgets", []byte("foo"))
+ // Read value back in a different read-only transaction.
+ db.Do(func(tx *Tx) error {
+ value := tx.Bucket("widgets").Get([]byte("foo"))
fmt.Printf("The value of 'foo' is: %s\n", string(value))
- }
+ return nil
+ })
// Output:
// The value of 'foo' is: bar
}
-func ExampleDB_With() {
+func ExampleTx_Delete() {
// Open the database.
var db DB
- db.Open("/tmp/bolt/db_foreach.db", 0666)
+ db.Open("/tmp/bolt/db_delete.db", 0666)
defer db.Close()
- // Insert data into a bucket.
- db.CreateBucket("people")
- db.Put("people", []byte("john"), []byte("doe"))
- db.Put("people", []byte("susy"), []byte("que"))
+ // Start a write transaction.
+ db.Do(func(tx *Tx) error {
+ // Create a bucket.
+ tx.CreateBucket("widgets")
+ b := tx.Bucket("widgets")
- // Access data from within a read-only transactional block.
- db.With(func(t *Tx) error {
- v := t.Bucket("people").Get([]byte("john"))
- fmt.Printf("John's last name is %s.\n", string(v))
+ // Set the value "bar" for the key "foo".
+ b.Put([]byte("foo"), []byte("bar"))
+
+ // Retrieve the key back from the database and verify it.
+ value := b.Get([]byte("foo"))
+ fmt.Printf("The value of 'foo' was: %s\n", string(value))
+ return nil
+ })
+
+ // Delete the key in a different write transaction.
+ db.Do(func(tx *Tx) error {
+ return tx.Bucket("widgets").Delete([]byte("foo"))
+ })
+
+ // Retrieve the key again.
+ db.With(func(tx *Tx) error {
+ value := tx.Bucket("widgets").Get([]byte("foo"))
+ if value == nil {
+ fmt.Printf("The value of 'foo' is now: nil\n")
+ }
return nil
})
// Output:
- // John's last name is doe.
+ // The value of 'foo' was: bar
+ // The value of 'foo' is now: nil
}
-func ExampleDB_ForEach() {
+func ExampleTx_ForEach() {
// Open the database.
var db DB
- db.Open("/tmp/bolt/db_foreach.db", 0666)
+ db.Open("/tmp/bolt/tx_foreach.db", 0666)
defer db.Close()
// Insert data into a bucket.
- db.CreateBucket("animals")
- db.Put("animals", []byte("dog"), []byte("fun"))
- db.Put("animals", []byte("cat"), []byte("lame"))
- db.Put("animals", []byte("liger"), []byte("awesome"))
-
- // Iterate over items in sorted key order.
- db.ForEach("animals", func(k, v []byte) error {
- fmt.Printf("A %s is %s.\n", string(k), string(v))
+ db.Do(func(tx *Tx) error {
+ tx.CreateBucket("animals")
+ b := tx.Bucket("animals")
+ b.Put([]byte("dog"), []byte("fun"))
+ b.Put([]byte("cat"), []byte("lame"))
+ b.Put([]byte("liger"), []byte("awesome"))
+
+ // Iterate over items in sorted key order.
+ b.ForEach(func(k, v []byte) error {
+ fmt.Printf("A %s is %s.\n", string(k), string(v))
+ return nil
+ })
return nil
})
@@ -141,7 +168,9 @@ func ExampleTx() {
defer db.Close()
// Create a bucket.
- db.CreateBucket("widgets")
+ db.Do(func(tx *Tx) error {
+ return tx.CreateBucket("widgets")
+ })
// Create several keys in a transaction.
tx, _ := db.RWTx()
@@ -172,10 +201,14 @@ func ExampleTx_rollback() {
defer db.Close()
// Create a bucket.
- db.CreateBucket("widgets")
+ db.Do(func(tx *Tx) error {
+ return tx.CreateBucket("widgets")
+ })
// Set a value for a key.
- db.Put("widgets", []byte("foo"), []byte("bar"))
+ db.Do(func(tx *Tx) error {
+ return tx.Bucket("widgets").Put([]byte("foo"), []byte("bar"))
+ })
// Update the key but rollback the transaction so it never saves.
tx, _ := db.RWTx()
@@ -184,8 +217,11 @@ func ExampleTx_rollback() {
tx.Rollback()
// Ensure that our original value is still set.
- value, _ := db.Get("widgets", []byte("foo"))
- fmt.Printf("The value for 'foo' is still: %s\n", string(value))
+ db.With(func(tx *Tx) error {
+ value := tx.Bucket("widgets").Get([]byte("foo"))
+ fmt.Printf("The value for 'foo' is still: %s\n", string(value))
+ return nil
+ })
// Output:
// The value for 'foo' is still: bar
@@ -198,8 +234,11 @@ func ExampleDB_CopyFile() {
defer db.Close()
// Create a bucket and a key.
- db.CreateBucket("widgets")
- db.Put("widgets", []byte("foo"), []byte("bar"))
+ db.Do(func(tx *Tx) error {
+ tx.CreateBucket("widgets")
+ tx.Bucket("widgets").Put([]byte("foo"), []byte("bar"))
+ return nil
+ })
// Copy the database to another file.
db.CopyFile("/tmp/bolt/db_copy_2.db", 0666)
@@ -210,8 +249,11 @@ func ExampleDB_CopyFile() {
defer db2.Close()
// Ensure that the key exists in the copy.
- value, _ := db2.Get("widgets", []byte("foo"))
- fmt.Printf("The value for 'foo' in the clone is: %s\n", string(value))
+ db2.With(func(tx *Tx) error {
+ value := tx.Bucket("widgets").Get([]byte("foo"))
+ fmt.Printf("The value for 'foo' in the clone is: %s\n", string(value))
+ return nil
+ })
// Output:
// The value for 'foo' in the clone is: bar
diff --git a/functional_test.go b/functional_test.go
index 41bffd6..866ec95 100644
--- a/functional_test.go
+++ b/functional_test.go
@@ -28,7 +28,9 @@ func TestParallelTxs(t *testing.T) {
var current testdata
withOpenDB(func(db *DB, path string) {
- db.CreateBucket("widgets")
+ db.Do(func(tx *Tx) error {
+ return tx.CreateBucket("widgets")
+ })
// Maintain a set of concurrent readers.
var wg sync.WaitGroup
diff --git a/tx_test.go b/tx_test.go
index d3ad131..afdbb02 100644
--- a/tx_test.go
+++ b/tx_test.go
@@ -16,15 +16,18 @@ import (
// Ensure that the database can retrieve a list of buckets.
func TestTxBuckets(t *testing.T) {
withOpenDB(func(db *DB, path string) {
- db.CreateBucket("foo")
- db.CreateBucket("bar")
- db.CreateBucket("baz")
- buckets, err := db.Buckets()
- if assert.NoError(t, err) && assert.Equal(t, len(buckets), 3) {
- assert.Equal(t, buckets[0].Name(), "bar")
- assert.Equal(t, buckets[1].Name(), "baz")
- assert.Equal(t, buckets[2].Name(), "foo")
- }
+ db.Do(func(tx *Tx) error {
+ tx.CreateBucket("foo")
+ tx.CreateBucket("bar")
+ tx.CreateBucket("baz")
+ buckets := tx.Buckets()
+ if assert.Equal(t, len(buckets), 3) {
+ assert.Equal(t, buckets[0].Name(), "bar")
+ assert.Equal(t, buckets[1].Name(), "baz")
+ assert.Equal(t, buckets[2].Name(), "foo")
+ }
+ return nil
+ })
})
}
@@ -39,33 +42,40 @@ func TestTxCreateBucketReadOnly(t *testing.T) {
}
// Ensure that a Tx can retrieve a bucket.
-func TestTxBucketMissing(t *testing.T) {
+func TestTxBucket(t *testing.T) {
withOpenDB(func(db *DB, path string) {
- db.CreateBucket("widgets")
- b, err := db.Bucket("widgets")
- assert.NoError(t, err)
- if assert.NotNil(t, b) {
- assert.Equal(t, "widgets", b.Name())
- }
+ db.Do(func(tx *Tx) error {
+ tx.CreateBucket("widgets")
+ b := tx.Bucket("widgets")
+ if assert.NotNil(t, b) {
+ assert.Equal(t, "widgets", b.Name())
+ }
+ return nil
+ })
})
}
// Ensure that a Tx retrieving a non-existent key returns nil.
func TestTxGetMissing(t *testing.T) {
withOpenDB(func(db *DB, path string) {
- db.CreateBucket("widgets")
- db.Put("widgets", []byte("foo"), []byte("bar"))
- value, err := db.Get("widgets", []byte("no_such_key"))
- assert.NoError(t, err)
- assert.Nil(t, value)
+ db.Do(func(tx *Tx) error {
+ tx.CreateBucket("widgets")
+ tx.Bucket("widgets").Put([]byte("foo"), []byte("bar"))
+ value := tx.Bucket("widgets").Get([]byte("no_such_key"))
+ assert.Nil(t, value)
+ return nil
+ })
})
}
// Ensure that retrieving all buckets returns writable buckets.
func TestTxWritableBuckets(t *testing.T) {
withOpenDB(func(db *DB, path string) {
- db.CreateBucket("widgets")
- db.CreateBucket("woojits")
+ db.Do(func(tx *Tx) error {
+ tx.CreateBucket("widgets")
+ tx.CreateBucket("woojits")
+ return nil
+ })
db.Do(func(tx *Tx) error {
buckets := tx.Buckets()
assert.Equal(t, len(buckets), 2)
@@ -75,10 +85,11 @@ func TestTxWritableBuckets(t *testing.T) {
buckets[1].Put([]byte("bar"), []byte("0001"))
return nil
})
- v, _ := db.Get("widgets", []byte("foo"))
- assert.Equal(t, v, []byte("0000"))
- v, _ = db.Get("woojits", []byte("bar"))
- assert.Equal(t, v, []byte("0001"))
+ db.With(func(tx *Tx) error {
+ assert.Equal(t, []byte("0000"), tx.Bucket("widgets").Get([]byte("foo")))
+ assert.Equal(t, []byte("0001"), tx.Bucket("woojits").Get([]byte("bar")))
+ return nil
+ })
})
}
@@ -86,27 +97,36 @@ func TestTxWritableBuckets(t *testing.T) {
func TestTxCreateBucket(t *testing.T) {
withOpenDB(func(db *DB, path string) {
// Create a bucket.
- err := db.CreateBucket("widgets")
- assert.NoError(t, err)
+ db.Do(func(tx *Tx) error {
+ assert.NoError(t, tx.CreateBucket("widgets"))
+ return nil
+ })
// Read the bucket through a separate transaction.
- b, err := db.Bucket("widgets")
- assert.NotNil(t, b)
- assert.NoError(t, err)
+ db.With(func(tx *Tx) error {
+ b := tx.Bucket("widgets")
+ assert.NotNil(t, b)
+ return nil
+ })
})
}
// Ensure that a bucket can be created if it doesn't already exist.
func TestTxCreateBucketIfNotExists(t *testing.T) {
withOpenDB(func(db *DB, path string) {
- assert.NoError(t, db.CreateBucketIfNotExists("widgets"))
- assert.NoError(t, db.CreateBucketIfNotExists("widgets"))
- assert.Equal(t, db.CreateBucketIfNotExists(""), ErrBucketNameRequired)
+ db.Do(func(tx *Tx) error {
+ assert.NoError(t, tx.CreateBucketIfNotExists("widgets"))
+ assert.NoError(t, tx.CreateBucketIfNotExists("widgets"))
+ assert.Equal(t, tx.CreateBucketIfNotExists(""), ErrBucketNameRequired)
+ return nil
+ })
// Read the bucket through a separate transaction.
- b, err := db.Bucket("widgets")
- assert.NotNil(t, b)
- assert.NoError(t, err)
+ db.With(func(tx *Tx) error {
+ b := tx.Bucket("widgets")
+ assert.NotNil(t, b)
+ return nil
+ })
})
}
@@ -114,31 +134,37 @@ func TestTxCreateBucketIfNotExists(t *testing.T) {
func TestTxRecreateBucket(t *testing.T) {
withOpenDB(func(db *DB, path string) {
// Create a bucket.
- err := db.CreateBucket("widgets")
- assert.NoError(t, err)
+ db.Do(func(tx *Tx) error {
+ assert.NoError(t, tx.CreateBucket("widgets"))
+ return nil
+ })
// Create the same bucket again.
- err = db.CreateBucket("widgets")
- assert.Equal(t, err, ErrBucketExists)
+ db.Do(func(tx *Tx) error {
+ assert.Equal(t, ErrBucketExists, tx.CreateBucket("widgets"))
+ return nil
+ })
})
}
// Ensure that a bucket is created with a non-blank name.
func TestTxCreateBucketWithoutName(t *testing.T) {
withOpenDB(func(db *DB, path string) {
- err := db.CreateBucket("")
- assert.Equal(t, err, ErrBucketNameRequired)
+ db.Do(func(tx *Tx) error {
+ assert.Equal(t, ErrBucketNameRequired, tx.CreateBucket(""))
+ return nil
+ })
})
}
// Ensure that a bucket name is not too long.
func TestTxCreateBucketWithLongName(t *testing.T) {
withOpenDB(func(db *DB, path string) {
- err := db.CreateBucket(strings.Repeat("X", 255))
- assert.NoError(t, err)
-
- err = db.CreateBucket(strings.Repeat("X", 256))
- assert.Equal(t, err, ErrBucketNameTooLarge)
+ db.Do(func(tx *Tx) error {
+ assert.NoError(t, tx.CreateBucket(strings.Repeat("X", 255)))
+ assert.Equal(t, ErrBucketNameTooLarge, tx.CreateBucket(strings.Repeat("X", 256)))
+ return nil
+ })
})
}
@@ -146,25 +172,35 @@ func TestTxCreateBucketWithLongName(t *testing.T) {
func TestTxDeleteBucket(t *testing.T) {
withOpenDB(func(db *DB, path string) {
// Create a bucket and add a value.
- db.CreateBucket("widgets")
- db.Put("widgets", []byte("foo"), []byte("bar"))
+ db.Do(func(tx *Tx) error {
+ tx.CreateBucket("widgets")
+ tx.Bucket("widgets").Put([]byte("foo"), []byte("bar"))
+ return nil
+ })
- b, _ := db.Bucket("widgets")
+ // Save root page id.
+ var root pgid
+ db.With(func(tx *Tx) error {
+ root = tx.Bucket("widgets").root
+ return nil
+ })
// Delete the bucket and make sure we can't get the value.
- assert.NoError(t, db.DeleteBucket("widgets"))
- value, err := db.Get("widgets", []byte("foo"))
- assert.Equal(t, err, ErrBucketNotFound)
- assert.Nil(t, value)
-
- // Verify that the bucket's page is free.
- assert.Equal(t, db.freelist.all(), []pgid{b.root})
-
- // Create the bucket again and make sure there's not a phantom value.
- assert.NoError(t, db.CreateBucket("widgets"))
- value, err = db.Get("widgets", []byte("foo"))
- assert.NoError(t, err)
- assert.Nil(t, value)
+ db.Do(func(tx *Tx) error {
+ assert.NoError(t, tx.DeleteBucket("widgets"))
+ assert.Nil(t, tx.Bucket("widgets"))
+ return nil
+ })
+
+ db.Do(func(tx *Tx) error {
+ // Verify that the bucket's page is free.
+ assert.Equal(t, []pgid{root}, db.freelist.all())
+
+ // Create the bucket again and make sure there's not a phantom value.
+ assert.NoError(t, tx.CreateBucket("widgets"))
+ assert.Nil(t, tx.Bucket("widgets").Get([]byte("foo")))
+ return nil
+ })
})
}
@@ -181,15 +217,19 @@ func TestTxDeleteBucketReadOnly(t *testing.T) {
// Ensure that an error is returned when deleting from a bucket that doesn't exist.
func TestTxDeleteBucketNotFound(t *testing.T) {
withOpenDB(func(db *DB, path string) {
- err := db.DeleteBucket("widgets")
- assert.Equal(t, err, ErrBucketNotFound)
+ db.Do(func(tx *Tx) error {
+ assert.Equal(t, ErrBucketNotFound, tx.DeleteBucket("widgets"))
+ return nil
+ })
})
}
// Ensure that a Tx cursor can iterate over an empty bucket without error.
func TestTxCursorEmptyBucket(t *testing.T) {
withOpenDB(func(db *DB, path string) {
- db.CreateBucket("widgets")
+ db.Do(func(tx *Tx) error {
+ return tx.CreateBucket("widgets")
+ })
db.With(func(tx *Tx) error {
c := tx.Bucket("widgets").Cursor()
k, v := c.First()
@@ -203,7 +243,9 @@ func TestTxCursorEmptyBucket(t *testing.T) {
// Ensure that a Tx cursor can reverse iterate over an empty bucket without error.
func TestCursorEmptyBucketReverse(t *testing.T) {
withOpenDB(func(db *DB, path string) {
- db.CreateBucket("widgets")
+ db.Do(func(tx *Tx) error {
+ return tx.CreateBucket("widgets")
+ })
db.With(func(tx *Tx) error {
c := tx.Bucket("widgets").Cursor()
k, v := c.Last()
@@ -217,10 +259,13 @@ func TestCursorEmptyBucketReverse(t *testing.T) {
// Ensure that a Tx cursor can iterate over a single root with a couple elements.
func TestTxCursorLeafRoot(t *testing.T) {
withOpenDB(func(db *DB, path string) {
- db.CreateBucket("widgets")
- db.Put("widgets", []byte("baz"), []byte{})
- db.Put("widgets", []byte("foo"), []byte{0})
- db.Put("widgets", []byte("bar"), []byte{1})
+ db.Do(func(tx *Tx) error {
+ tx.CreateBucket("widgets")
+ tx.Bucket("widgets").Put([]byte("baz"), []byte{})
+ tx.Bucket("widgets").Put([]byte("foo"), []byte{0})
+ tx.Bucket("widgets").Put([]byte("bar"), []byte{1})
+ return nil
+ })
tx, _ := db.Tx()
c := tx.Bucket("widgets").Cursor()
@@ -251,10 +296,13 @@ func TestTxCursorLeafRoot(t *testing.T) {
// Ensure that a Tx cursor can iterate in reverse over a single root with a couple elements.
func TestTxCursorLeafRootReverse(t *testing.T) {
withOpenDB(func(db *DB, path string) {
- db.CreateBucket("widgets")
- db.Put("widgets", []byte("baz"), []byte{})
- db.Put("widgets", []byte("foo"), []byte{0})
- db.Put("widgets", []byte("bar"), []byte{1})
+ db.Do(func(tx *Tx) error {
+ tx.CreateBucket("widgets")
+ tx.Bucket("widgets").Put([]byte("baz"), []byte{})
+ tx.Bucket("widgets").Put([]byte("foo"), []byte{0})
+ tx.Bucket("widgets").Put([]byte("bar"), []byte{1})
+ return nil
+ })
tx, _ := db.Tx()
c := tx.Bucket("widgets").Cursor()
@@ -285,9 +333,12 @@ func TestTxCursorLeafRootReverse(t *testing.T) {
// Ensure that a Tx cursor can restart from the beginning.
func TestTxCursorRestart(t *testing.T) {
withOpenDB(func(db *DB, path string) {
- db.CreateBucket("widgets")
- db.Put("widgets", []byte("bar"), []byte{})
- db.Put("widgets", []byte("foo"), []byte{})
+ db.Do(func(tx *Tx) error {
+ tx.CreateBucket("widgets")
+ tx.Bucket("widgets").Put([]byte("bar"), []byte{})
+ tx.Bucket("widgets").Put([]byte("foo"), []byte{})
+ return nil
+ })
tx, _ := db.Tx()
c := tx.Bucket("widgets").Cursor()
@@ -317,8 +368,8 @@ func TestTxCursorIterate(t *testing.T) {
f := func(items testdata) bool {
withOpenDB(func(db *DB, path string) {
// Bulk insert all values.
- db.CreateBucket("widgets")
tx, _ := db.RWTx()
+ tx.CreateBucket("widgets")
b := tx.Bucket("widgets")
for _, item := range items {
assert.NoError(t, b.Put(item.Key, item.Value))
@@ -358,8 +409,8 @@ func TestTxCursorIterateReverse(t *testing.T) {
f := func(items testdata) bool {
withOpenDB(func(db *DB, path string) {
// Bulk insert all values.
- db.CreateBucket("widgets")
tx, _ := db.RWTx()
+ tx.CreateBucket("widgets")
b := tx.Bucket("widgets")
for _, item := range items {
assert.NoError(t, b.Put(item.Key, item.Value))
@@ -397,8 +448,8 @@ func BenchmarkTxCursor(b *testing.B) {
withOpenDB(func(db *DB, path string) {
// Write data to bucket.
- db.CreateBucket("widgets")
db.Do(func(tx *Tx) error {
+ tx.CreateBucket("widgets")
bucket := tx.Bucket("widgets")
for i := 0; i < b.N; i++ {
bucket.Put([]byte(strconv.Itoa(indexes[i])), value)
@@ -427,7 +478,9 @@ func BenchmarkTxPutRandom(b *testing.B) {
indexes := rand.Perm(b.N)
value := []byte(strings.Repeat("0", 64))
withOpenDB(func(db *DB, path string) {
- db.CreateBucket("widgets")
+ db.Do(func(tx *Tx) error {
+ return tx.CreateBucket("widgets")
+ })
var tx *Tx
var bucket *Bucket
for i := 0; i < b.N; i++ {
@@ -448,7 +501,9 @@ func BenchmarkTxPutRandom(b *testing.B) {
func BenchmarkTxPutSequential(b *testing.B) {
value := []byte(strings.Repeat("0", 64))
withOpenDB(func(db *DB, path string) {
- db.CreateBucket("widgets")
+ db.Do(func(tx *Tx) error {
+ return tx.CreateBucket("widgets")
+ })
db.Do(func(tx *Tx) error {
bucket := tx.Bucket("widgets")
for i := 0; i < b.N; i++ {