aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/dedo.go70
-rw-r--r--tests/dedo.go248
2 files changed, 177 insertions, 141 deletions
diff --git a/src/dedo.go b/src/dedo.go
index af29fdd..8ec8b41 100644
--- a/src/dedo.go
+++ b/src/dedo.go
@@ -77,13 +77,13 @@ type BucketI interface{
ForEach(func([]byte, []byte) error) error
CreateBucket([]byte) (BucketI, error)
DeleteBucket([]byte) error
- Bucket([]byte) BucketI
+ Bucket([]byte) (BucketI, error)
NextSequence() (uint64, error)
Cursor() CursorI
}
type SnapshotI interface{
- Bucket([]byte) BucketI
+ Bucket([]byte) (BucketI, error)
Cursor() CursorI
ForEach(func([]byte, BucketI) error) error
@@ -92,7 +92,7 @@ type SnapshotI interface{
}
type TransactionI interface{
- Bucket([]byte) BucketI
+ Bucket([]byte) (BucketI, error)
Cursor() CursorI
ForEach(func([]byte, BucketI) error) error
@@ -458,6 +458,8 @@ var (
/// These errors can occur when putting or deleting a value or a bucket.
///
+ ErrBucketBadFlag = errors.New("bucket does not have bucketLeafFlag")
+
/// ErrBucketNotFound is returned when trying to access a bucket that
/// has not been created yet.
ErrBucketNotFound = errors.New("bucket not found")
@@ -620,11 +622,11 @@ func (b *bucketT) Cursor() CursorI {
/// bucketT.Bucket() retrieves a nested bucket by name. Returns nil if the
/// bucket does not exist. The bucket instance is only valid for the lifetime
/// of the transaction.
-func bucketGetNested(b *bucketT, name []byte) *bucketT {
+func bucketGetNested(b *bucketT, name []byte) (*bucketT, error) {
if b.buckets != nil {
child := b.buckets[string(name)]
if child != nil {
- return child
+ return child, nil
}
}
@@ -633,8 +635,12 @@ func bucketGetNested(b *bucketT, name []byte) *bucketT {
k, v, flags := c.seek(name)
// Return nil if the key doesn't exist or it is not a bucket.
- if !bytes.Equal(name, k) || (flags&bucketLeafFlag) == 0 {
- return nil
+ if !bytes.Equal(name, k) {
+ return nil, ErrBucketNotFound
+ }
+
+ if (flags & bucketLeafFlag) == 0 {
+ return nil, ErrBucketBadFlag
}
// Otherwise create a bucket and cache it.
@@ -643,10 +649,10 @@ func bucketGetNested(b *bucketT, name []byte) *bucketT {
b.buckets[string(name)] = child
}
- return child
+ return child, nil
}
-func (b *bucketT) Bucket(name []byte) BucketI {
+func (b *bucketT) Bucket(name []byte) (BucketI, error) {
return bucketGetNested(b, name)
}
@@ -714,7 +720,7 @@ func bucketCreateBucket(b *bucketT, key []byte) (*bucketT, error) {
// the tx.
b.page = nil
- return bucketGetNested(b, key), nil
+ return bucketGetNested(b, key)
}
func (b *bucketT) CreateBucket(key []byte) (BucketI, error) {
@@ -728,7 +734,7 @@ func (b *bucketT) CreateBucket(key []byte) (BucketI, error) {
func bucketCreateBucketIfNotExists(b *bucketT, key []byte) (*bucketT, error) {
child, err := bucketCreateBucket(b, key)
if err == ErrBucketExists {
- return bucketGetNested(b, key), nil
+ return bucketGetNested(b, key)
} else if err != nil {
return nil, err
}
@@ -760,8 +766,12 @@ func bucketDeleteBucket(b *bucketT, key []byte) error {
}
// Recursively delete all child buckets.
- child := bucketGetNested(b, key)
- err := child.ForEach(func(k, v []byte) error {
+ child, err := bucketGetNested(b, key)
+ if err != nil {
+ return err
+ }
+
+ err = child.ForEach(func(k, v []byte) error {
if v == nil {
err := child.DeleteBucket(k)
if err != nil {
@@ -3580,11 +3590,11 @@ func (tx *transactionT) Cursor() CursorI {
/// transactionT.Bucket() retrieves a bucket by name. Returns nil if the bucket does not
/// exist. The bucket instance is only valid for the lifetime of the
/// transaction.
-func txBucket(tx *transactionT, name []byte) *bucketT {
+func txBucket(tx *transactionT, name []byte) (*bucketT, error) {
return bucketGetNested(&tx.root, name)
}
-func (tx *transactionT) Bucket(name []byte) BucketI {
+func (tx *transactionT) Bucket(name []byte) (BucketI, error) {
return txBucket(tx, name)
}
@@ -3627,11 +3637,11 @@ func (tx *transactionT) DeleteBucket(name []byte) error {
/// error is returned to the caller.
func txForEach(tx *transactionT, fn func([]byte, BucketI) error) error {
return tx.root.ForEach(func(k []byte, v []byte) error {
- err := fn(k, tx.root.Bucket(k))
+ bucket, err := tx.root.Bucket(k)
if err != nil {
return err
}
- return nil
+ return fn(k, bucket)
})
}
@@ -3923,10 +3933,12 @@ func (tx *transactionT) checkBucket(
// Check each bucket within this bucket.
_ = b.ForEach(func(k, v []byte) error {
- child := bucketGetNested(b, k)
- if child != nil {
- tx.checkBucket(child, reachable, freed, ch)
+ child, err := bucketGetNested(b, k)
+ if err != nil{
+ return nil
}
+
+ tx.checkBucket(child, reachable, freed, ch)
return nil
})
}
@@ -4107,9 +4119,9 @@ func checkExec(args argsT, db DatabaseI, _r io.Reader, _w io.Writer) error {
func getExec(args argsT, db DatabaseI, r io.Reader, w io.Writer) error {
return db.View(func(snapshot SnapshotI) error {
- bucket := snapshot.Bucket(args.bucket)
- if bucket == nil {
- return ErrBucketNotFound
+ bucket, err := snapshot.Bucket(args.bucket)
+ if err != nil {
+ return err
}
value := bucket.Get(args.key)
@@ -4135,9 +4147,9 @@ func setExec(args argsT, db DatabaseI, r io.Reader, w io.Writer) error {
func rmExec(args argsT, db DatabaseI, r io.Reader, w io.Writer) error {
return db.Update(func(tx TransactionI) error {
- bucket := tx.Bucket(args.bucket)
- if bucket == nil {
- return ErrBucketNotFound
+ bucket, err := tx.Bucket(args.bucket)
+ if err != nil {
+ return err
}
return bucket.Delete(args.key)
@@ -4156,9 +4168,9 @@ func listExec(args argsT, db DatabaseI, r io.Reader, w io.Writer) error {
})
}
- bucket := snapshot.Bucket(args.bucket)
- if bucket == nil {
- return ErrBucketNotFound
+ bucket, err := snapshot.Bucket(args.bucket)
+ if err != nil {
+ return err
}
return bucket.ForEach(func(key []byte, value []byte) error {
diff --git a/tests/dedo.go b/tests/dedo.go
index efb386f..72bc795 100644
--- a/tests/dedo.go
+++ b/tests/dedo.go
@@ -57,6 +57,21 @@ func (tx *transactionT) copyFile(path string, mode os.FileMode) error {
return f.Close()
}
+func copyFile(transaction TransactionI, path string, mode os.FileMode) error {
+ f, err := os.OpenFile(path, os.O_RDWR | os.O_CREATE | os.O_TRUNC, mode)
+ if err != nil {
+ return err
+ }
+
+ _, err = transaction.WriteTo(f)
+ if err != nil {
+ _ = f.Close()
+ return err
+ }
+
+ return f.Close()
+}
+
/// transactionT.Page() returns page information for a given page number. This is only
/// safe for concurrent use when used by a writable transaction.
func (tx *transactionT) pageInfo(id int) (*pageInfoT, error) {
@@ -538,7 +553,6 @@ func TestOpen_ErrInvalid(t *testing.T) {
func TestBucket_Get_NonExistent(t *testing.T) {
db := MustOpenDB()
defer db.MustClose()
- defer os.Remove(db.Path())
err := db.Update(func(tx TransactionI) error {
b, err := tx.CreateBucket([]byte("widgets"))
@@ -599,14 +613,14 @@ func TestBucket_Get_IncompatibleValue(t *testing.T) {
t.Fatal(err)
}
- _, err = tx.Bucket([]byte("widgets")).CreateBucket([
+ _, err = g.Must(tx.Bucket([]byte("widgets"))).CreateBucket([
]byte("foo"),
)
if err != nil {
t.Fatal(err)
}
- if tx.Bucket([]byte("widgets")).Get([]byte("foo")) != nil {
+ if g.Must(tx.Bucket([]byte("widgets"))).Get([]byte("foo")) != nil {
t.Fatal("expected nil value")
}
@@ -642,7 +656,7 @@ func TestBucket_Get_Capacity(t *testing.T) {
// Retrieve value and attempt to append to it.
err = db.Update(func(tx TransactionI) error {
- k, v := tx.Bucket([]byte("bucket")).Cursor().First()
+ k, v := g.Must(tx.Bucket([]byte("bucket"))).Cursor().First()
// Verify capacity.
if len(k) != cap(k) {
@@ -679,7 +693,7 @@ func TestBucket_Put(t *testing.T) {
t.Fatal(err)
}
- v := tx.Bucket([]byte("widgets")).Get([]byte("foo"))
+ v := g.Must(tx.Bucket([]byte("widgets"))).Get([]byte("foo"))
if !bytes.Equal([]byte("bar"), v) {
t.Fatalf("unexpected value: %v", v)
}
@@ -713,7 +727,7 @@ func TestBucket_Put_Repeat(t *testing.T) {
t.Fatal(err)
}
- value := tx.Bucket([]byte("widgets")).Get([]byte("foo"))
+ value := g.Must(tx.Bucket([]byte("widgets"))).Get([]byte("foo"))
if !bytes.Equal([]byte("baz"), value) {
t.Fatalf("unexpected value: %v", value)
}
@@ -729,7 +743,6 @@ func TestBucket_Put_Repeat(t *testing.T) {
func TestBucket_Put_Large(t *testing.T) {
db := MustOpenDB()
defer db.MustClose()
- defer os.Remove(db.Path())
count, factor := 100, 200
err := db.Update(func(tx TransactionI) error {
@@ -754,7 +767,7 @@ func TestBucket_Put_Large(t *testing.T) {
}
err = db.View(func(snapshot SnapshotI) error {
- b := snapshot.Bucket([]byte("widgets"))
+ b := g.Must(snapshot.Bucket([]byte("widgets")))
for i := 1; i < count; i++ {
value := b.Get([]byte(strings.Repeat("0", i*factor)))
expected := []byte(strings.Repeat(
@@ -819,7 +832,7 @@ func TestBucket_Put_IncompatibleValue(t *testing.T) {
t.Fatal(err)
}
- _, err = tx.Bucket([]byte("widgets")).CreateBucket(
+ _, err = g.Must(tx.Bucket([]byte("widgets"))).CreateBucket(
[]byte("foo"),
)
if err != nil {
@@ -885,7 +898,7 @@ func TestBucket_Put_ReadOnly(t *testing.T) {
}
err = db.View(func(snapshot SnapshotI) error {
- b := snapshot.Bucket([]byte("widgets"))
+ b := g.Must(snapshot.Bucket([]byte("widgets")))
err := b.Put([]byte("foo"), []byte("bar"))
if err != ErrTxNotWritable {
t.Fatalf("unexpected error: %s", err)
@@ -961,7 +974,7 @@ func TestBucket_Delete_Large(t *testing.T) {
}
err = db.Update(func(tx TransactionI) error {
- b := tx.Bucket([]byte("widgets"))
+ b := g.Must(tx.Bucket([]byte("widgets")))
for i := 0; i < 100; i++ {
err := b.Delete([]byte(strconv.Itoa(i)))
if err != nil {
@@ -975,7 +988,7 @@ func TestBucket_Delete_Large(t *testing.T) {
}
err = db.View(func(snapshot SnapshotI) error {
- b := snapshot.Bucket([]byte("widgets"))
+ b := g.Must(snapshot.Bucket([]byte("widgets")))
for i := 0; i < 100; i++ {
v := b.Get([]byte(strconv.Itoa(i)))
if v != nil {
@@ -1027,7 +1040,7 @@ func TestBucket_Delete_FreelistOverflow(t *testing.T) {
// Delete all of them in one large transaction
err := db.Update(func(tx TransactionI) error {
- b := tx.Bucket([]byte("0"))
+ b := g.Must(tx.Bucket([]byte("0")))
c := b.Cursor()
for k, _ := c.First(); k != nil; k, _ = c.Next() {
err := c.Delete()
@@ -1076,7 +1089,7 @@ func TestBucket_Nested(t *testing.T) {
// Update widgets/bar.
err = db.Update(func(tx TransactionI) error {
- b := tx.Bucket([]byte("widgets"))
+ b := g.Must(tx.Bucket([]byte("widgets")))
err := b.Put([]byte("bar"), []byte("xxxx"))
if err != nil {
t.Fatal(err)
@@ -1091,7 +1104,7 @@ func TestBucket_Nested(t *testing.T) {
// Cause a split.
err = db.Update(func(tx TransactionI) error {
- b := tx.Bucket([]byte("widgets"))
+ b := g.Must(tx.Bucket([]byte("widgets")))
for i := 0; i < 10000; i++ {
err := b.Put(
[]byte(strconv.Itoa(i)),
@@ -1111,8 +1124,8 @@ func TestBucket_Nested(t *testing.T) {
// Insert into widgets/foo/baz.
err = db.Update(func(tx TransactionI) error {
- b := tx.Bucket([]byte("widgets"))
- err := b.Bucket([]byte("foo")).Put(
+ b := g.Must(tx.Bucket([]byte("widgets")))
+ err := g.Must(b.Bucket([]byte("foo"))).Put(
[]byte("baz"),
[]byte("yyyy"),
)
@@ -1129,8 +1142,8 @@ func TestBucket_Nested(t *testing.T) {
// Verify.
err = db.View(func(snapshot SnapshotI) error {
- b := snapshot.Bucket([]byte("widgets"))
- v := b.Bucket([]byte("foo")).Get([]byte("baz"))
+ b := g.Must(snapshot.Bucket([]byte("widgets")))
+ v := g.Must(b.Bucket([]byte("foo"))).Get([]byte("baz"))
if !bytes.Equal(v, []byte("yyyy")) {
t.Fatalf("unexpected value: %v", v)
}
@@ -1202,7 +1215,7 @@ func TestBucket_Delete_ReadOnly(t *testing.T) {
}
err = db.View(func(snapshot SnapshotI) error {
- err := snapshot.Bucket([]byte("widgets")).Delete([]byte("foo"))
+ err := g.Must(snapshot.Bucket([]byte("widgets"))).Delete([]byte("foo"))
if err != ErrTxNotWritable {
t.Fatalf("unexpected error: %s", err)
}
@@ -1269,7 +1282,7 @@ func TestBucket_DeleteBucket_Nested(t *testing.T) {
t.Fatal(err)
}
- err = tx.Bucket([]byte("widgets")).DeleteBucket([]byte("foo"))
+ err = g.Must(tx.Bucket([]byte("widgets"))).DeleteBucket([]byte("foo"))
if err != nil {
t.Fatal(err)
}
@@ -1315,18 +1328,18 @@ func TestBucket_DeleteBucket_Nested2(t *testing.T) {
}
err = db.Update(func(tx TransactionI) error {
- widgets := tx.Bucket([]byte("widgets"))
- if widgets == nil {
+ widgets, err := tx.Bucket([]byte("widgets"))
+ if err != nil {
t.Fatal("expected widgets bucket")
}
- foo := widgets.Bucket([]byte("foo"))
- if foo == nil {
+ foo, err := widgets.Bucket([]byte("foo"))
+ if err != nil {
t.Fatal("expected foo bucket")
}
- bar := foo.Bucket([]byte("bar"))
- if bar == nil {
+ bar, err := foo.Bucket([]byte("bar"))
+ if err != nil {
t.Fatal("expected bar bucket")
}
@@ -1335,7 +1348,7 @@ func TestBucket_DeleteBucket_Nested2(t *testing.T) {
t.Fatalf("unexpected value: %v", v)
}
- err := tx.DeleteBucket([]byte("widgets"))
+ err = tx.DeleteBucket([]byte("widgets"))
if err != nil {
t.Fatal(err)
}
@@ -1347,9 +1360,11 @@ func TestBucket_DeleteBucket_Nested2(t *testing.T) {
}
err = db.View(func(snapshot SnapshotI) error {
- if snapshot.Bucket([]byte("widgets")) != /* nil FIXME */ (*bucketT)(nil) {
+ _, err := snapshot.Bucket([]byte("widgets"))
+ if err != ErrBucketNotFound {
t.Fatal("expected bucket to be deleted")
}
+
return nil
})
if err != nil {
@@ -1421,9 +1436,9 @@ func TestBucket_Bucket_IncompatibleValue(t *testing.T) {
t.Fatal(err)
}
- b := tx.Bucket([]byte("widgets")).Bucket([]byte("foo"))
- if b != /* nil FIXME */ (*bucketT)(nil) {
- t.Fatal("expected nil bucket")
+ _, err = g.Must(tx.Bucket([]byte("widgets"))).Bucket([]byte("foo"))
+ if err != ErrBucketBadFlag {
+ t.Fatal("expected value, not bucket")
}
return nil
@@ -1479,7 +1494,7 @@ func TestBucket_DeleteBucket_IncompatibleValue(t *testing.T) {
t.Fatal(err)
}
- err = tx.Bucket([]byte("widgets")).DeleteBucket([]byte("foo"))
+ err = g.Must(tx.Bucket([]byte("widgets"))).DeleteBucket([]byte("foo"))
if err != ErrIncompatibleValue {
t.Fatalf("unexpected error: %s", err)
}
@@ -1559,7 +1574,7 @@ func TestBucket_NextSequence_Persist(t *testing.T) {
}
err = db.Update(func(tx TransactionI) error {
- _, err := tx.Bucket([]byte("widgets")).NextSequence()
+ _, err := g.Must(tx.Bucket([]byte("widgets"))).NextSequence()
if err != nil {
t.Fatal(err)
}
@@ -1571,7 +1586,7 @@ func TestBucket_NextSequence_Persist(t *testing.T) {
}
err = db.Update(func(tx TransactionI) error {
- seq, err := tx.Bucket([]byte("widgets")).NextSequence()
+ seq, err := g.Must(tx.Bucket([]byte("widgets"))).NextSequence()
if err != nil {
t.Fatalf("unexpected error: %s", err)
} else if seq != 2 {
@@ -1605,7 +1620,7 @@ func TestBucket_NextSequence_ReadOnly(t *testing.T) {
}
err = db.View(func(snapshot SnapshotI) error {
- _, err := snapshot.Bucket([]byte("widgets")).NextSequence()
+ _, err := g.Must(snapshot.Bucket([]byte("widgets"))).NextSequence()
if err != ErrTxNotWritable {
t.Fatalf("unexpected error: %s", err)
}
@@ -1741,9 +1756,9 @@ func TestBucket_ForEach_ShortCircuit(t *testing.T) {
}
var index int
- err = tx.Bucket(
+ err = g.Must(tx.Bucket(
[]byte("widgets"),
- ).ForEach(func(k, v []byte) error {
+ )).ForEach(func(k, v []byte) error {
index++
if bytes.Equal(k, []byte("baz")) {
return errors.New("marker")
@@ -1896,7 +1911,7 @@ func TestBucket_Put_Single(t *testing.T) {
for _, item := range items {
err := db.Update(func(tx TransactionI) error {
- err := tx.Bucket([]byte("widgets")).Put(
+ err := g.Must(tx.Bucket([]byte("widgets"))).Put(
item.Key,
item.Value,
)
@@ -1918,9 +1933,9 @@ func TestBucket_Put_Single(t *testing.T) {
err = db.View(func(snapshot SnapshotI) error {
i := 0
for k, v := range m {
- value := snapshot.Bucket(
+ value := g.Must(snapshot.Bucket(
[]byte("widgets"),
- ).Get([]byte(k))
+ )).Get([]byte(k))
if !bytes.Equal(value, v) {
t.Logf(
errmsg,
@@ -1976,7 +1991,7 @@ func TestBucket_Put_Multiple(t *testing.T) {
}
err = db.Update(func(tx TransactionI) error {
- b := tx.Bucket([]byte("widgets"))
+ b := g.Must(tx.Bucket([]byte("widgets")))
for _, item := range items {
err := b.Put(item.Key, item.Value)
if err != nil {
@@ -1992,7 +2007,7 @@ func TestBucket_Put_Multiple(t *testing.T) {
// Verify all items exist.
err = db.View(func(snapshot SnapshotI) error {
- b := snapshot.Bucket([]byte("widgets"))
+ b := g.Must(snapshot.Bucket([]byte("widgets")))
for _, item := range items {
value := b.Get(item.Key)
if !bytes.Equal(item.Value, value) {
@@ -2043,7 +2058,7 @@ func TestBucket_Delete_Quick(t *testing.T) {
}
err = db.Update(func(tx TransactionI) error {
- b := tx.Bucket([]byte("widgets"))
+ b := g.Must(tx.Bucket([]byte("widgets")))
for _, item := range items {
err := b.Put(item.Key, item.Value)
if err != nil {
@@ -2060,7 +2075,7 @@ 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 TransactionI) error {
- return tx.Bucket([]byte("widgets")).Delete(
+ return g.Must(tx.Bucket([]byte("widgets"))).Delete(
item.Key,
)
})
@@ -2071,9 +2086,9 @@ func TestBucket_Delete_Quick(t *testing.T) {
// Anything before our deletion index should be nil.
err = db.View(func(snapshot SnapshotI) error {
- err := snapshot.Bucket(
+ err := g.Must(snapshot.Bucket(
[]byte("widgets"),
- ).ForEach(func(k, v []byte) error {
+ )).ForEach(func(k, v []byte) error {
t.Fatalf(
"bucket should be empty; found: %06x",
trunc(k, 3),
@@ -2127,7 +2142,7 @@ func ExampleBucket_Put() {
// Read value back in a different read-only transaction.
err = db.View(func(snapshot SnapshotI) error {
- value := snapshot.Bucket([]byte("widgets")).Get([]byte("foo"))
+ value := g.Must(snapshot.Bucket([]byte("widgets"))).Get([]byte("foo"))
fmt.Printf("The value of 'foo' is: %s\n", value)
return nil
})
@@ -2179,7 +2194,7 @@ func ExampleBucket_Delete() {
// Delete the key in a different write transaction.
err = db.Update(func(tx TransactionI) error {
- return tx.Bucket([]byte("widgets")).Delete([]byte("foo"))
+ return g.Must(tx.Bucket([]byte("widgets"))).Delete([]byte("foo"))
})
if err != nil {
log.Fatal(err)
@@ -2187,7 +2202,7 @@ func ExampleBucket_Delete() {
// Retrieve the key again.
err = db.View(func(snapshot SnapshotI) error {
- value := snapshot.Bucket([]byte("widgets")).Get([]byte("foo"))
+ value := g.Must(snapshot.Bucket([]byte("widgets"))).Get([]byte("foo"))
if value == nil {
fmt.Printf("The value of 'foo' is now: nil\n")
}
@@ -2304,7 +2319,7 @@ func TestCursor_Seek(t *testing.T) {
}
err = db.View(func(snapshot SnapshotI) error {
- c := snapshot.Bucket([]byte("widgets")).Cursor()
+ c := g.Must(snapshot.Bucket([]byte("widgets"))).Cursor()
// Exact match should go to the key.
k, v := c.Seek([]byte("bar"))
@@ -2388,7 +2403,7 @@ func TestCursor_Delete(t *testing.T) {
}
err = db.Update(func(tx TransactionI) error {
- c := tx.Bucket([]byte("widgets")).Cursor()
+ c := g.Must(tx.Bucket([]byte("widgets"))).Cursor()
bound := make([]byte, 8)
binary.BigEndian.PutUint64(bound, uint64(count/2))
for
@@ -2450,7 +2465,7 @@ func TestCursor_Seek_Large(t *testing.T) {
}
err = db.View(func(snapshot SnapshotI) error {
- c := snapshot.Bucket([]byte("widgets")).Cursor()
+ c := g.Must(snapshot.Bucket([]byte("widgets"))).Cursor()
for i := 0; i < count; i++ {
seek := make([]byte, 8)
binary.BigEndian.PutUint64(seek, uint64(i))
@@ -2502,7 +2517,7 @@ func TestCursor_EmptyBucket(t *testing.T) {
}
err = db.View(func(snapshot SnapshotI) error {
- c := snapshot.Bucket([]byte("widgets")).Cursor()
+ c := g.Must(snapshot.Bucket([]byte("widgets"))).Cursor()
k, v := c.First()
if k != nil {
t.Fatalf("unexpected key: %v", k)
@@ -2532,7 +2547,7 @@ func TestCursor_EmptyBucketReverse(t *testing.T) {
}
err = db.View(func(snapshot SnapshotI) error {
- c := snapshot.Bucket([]byte("widgets")).Cursor()
+ c := g.Must(snapshot.Bucket([]byte("widgets"))).Cursor()
k, v := c.Last()
if k != nil {
t.Fatalf("unexpected key: %v", k)
@@ -2586,7 +2601,7 @@ func TestCursor_Iterate_Leaf(t *testing.T) {
}
defer func() { _ = tx.rollback() }()
- c := tx.Bucket([]byte("widgets")).Cursor()
+ c := g.Must(tx.Bucket([]byte("widgets"))).Cursor()
k, v := c.First()
if !bytes.Equal(k, []byte("bar")) {
@@ -2668,7 +2683,7 @@ func TestCursor_LeafRootReverse(t *testing.T) {
t.Fatal(err)
}
- c := tx.Bucket([]byte("widgets")).Cursor()
+ c := g.Must(tx.Bucket([]byte("widgets"))).Cursor()
k, v := c.Last()
if !bytes.Equal(k, []byte("foo")) {
t.Fatalf("unexpected key: %v", k)
@@ -2743,7 +2758,7 @@ func TestCursor_Restart(t *testing.T) {
t.Fatal(err)
}
- c := tx.Bucket([]byte("widgets")).Cursor()
+ c := g.Must(tx.Bucket([]byte("widgets"))).Cursor()
k, _ := c.First()
if !bytes.Equal(k, []byte("bar")) {
@@ -2798,7 +2813,7 @@ func TestCursor_First_EmptyPages(t *testing.T) {
// Delete half the keys and then try to iterate.
err = db.Update(func(tx TransactionI) error {
- b := tx.Bucket([]byte("widgets"))
+ b := g.Must(tx.Bucket([]byte("widgets")))
for i := 0; i < 600; i++ {
err := b.Delete(u64tob(uint64(i)))
if err != nil {
@@ -2860,7 +2875,7 @@ func TestCursor_QuickCheck(t *testing.T) {
t.Fatal(err)
}
- c := tx.Bucket([]byte("widgets")).Cursor()
+ c := g.Must(tx.Bucket([]byte("widgets"))).Cursor()
for
k, v := c.First();
k != nil && index < len(items);
@@ -2935,7 +2950,7 @@ func TestCursor_QuickCheck_Reverse(t *testing.T) {
t.Fatal(err)
}
- c := tx.Bucket([]byte("widgets")).Cursor()
+ c := g.Must(tx.Bucket([]byte("widgets"))).Cursor()
for
k, v := c.Last();
k != nil && index < len(items);
@@ -3005,7 +3020,7 @@ func TestCursor_QuickCheck_BucketsOnly(t *testing.T) {
err = db.View(func(snapshot SnapshotI) error {
names := []string{}
- c := snapshot.Bucket([]byte("widgets")).Cursor()
+ c := g.Must(snapshot.Bucket([]byte("widgets"))).Cursor()
for k, v := c.First(); k != nil; k, v = c.Next() {
names = append(names, string(k))
if v != nil {
@@ -3059,7 +3074,7 @@ func TestCursor_QuickCheck_BucketsOnly_Reverse(t *testing.T) {
err = db.View(func(snapshot SnapshotI) error {
names := []string{}
- c := snapshot.Bucket([]byte("widgets")).Cursor()
+ c := g.Must(snapshot.Bucket([]byte("widgets"))).Cursor()
for k, v := c.Last(); k != nil; k, v = c.Prev() {
names = append(names, string(k))
if v != nil {
@@ -3374,7 +3389,7 @@ func TestOpen_Size(t *testing.T) {
}
err = db0.Update(func(tx TransactionI) error {
- err := tx.Bucket([]byte("data")).Put([]byte{0}, []byte{0})
+ err := g.Must(tx.Bucket([]byte("data"))).Put([]byte{0}, []byte{0})
if err != nil {
t.Fatal(err)
}
@@ -3461,7 +3476,7 @@ func TestOpen_Size_Large(t *testing.T) {
}
err = db0.Update(func(tx TransactionI) error {
- return tx.Bucket([]byte("data")).Put([]byte{0}, []byte{0})
+ return g.Must(tx.Bucket([]byte("data"))).Put([]byte{0}, []byte{0})
})
if err != nil {
t.Fatal(err)
@@ -3758,7 +3773,7 @@ func TestDB_Update(t *testing.T) {
}
err = db.View(func(snapshot SnapshotI) error {
- b := snapshot.Bucket([]byte("widgets"))
+ b := g.Must(snapshot.Bucket([]byte("widgets")))
v := b.Get([]byte("foo"))
if v != nil {
t.Fatalf("expected nil value, got: %v", v)
@@ -3835,7 +3850,8 @@ func TestDB_Update_Panic(t *testing.T) {
// Verify that our change persisted.
err = db.Update(func(tx TransactionI) error {
- if tx.Bucket([]byte("widgets")) == nil {
+ _, err := tx.Bucket([]byte("widgets"))
+ if err != nil {
t.Fatal("expected bucket")
}
return nil
@@ -3888,7 +3904,8 @@ func TestDB_View_Panic(t *testing.T) {
}()
err := db.View(func(snapshot SnapshotI) error {
- if snapshot.Bucket([]byte("widgets")) == nil {
+ _, err := snapshot.Bucket([]byte("widgets"))
+ if err != nil {
t.Fatal("expected bucket")
}
panic("omg")
@@ -3900,7 +3917,8 @@ func TestDB_View_Panic(t *testing.T) {
// Verify that we can still use read transactions.
err = db.View(func(snapshot SnapshotI) error {
- if snapshot.Bucket([]byte("widgets")) == nil {
+ _, err := snapshot.Bucket([]byte("widgets"))
+ if err != nil {
t.Fatal("expected bucket")
}
return nil
@@ -3926,7 +3944,7 @@ func TestDB_Consistency(t *testing.T) {
for i := 0; i < 10; i++ {
err := db.Update(func(tx TransactionI) error {
- err := tx.Bucket([]byte("widgets")).Put(
+ err := g.Must(tx.Bucket([]byte("widgets"))).Put(
[]byte("foo"),
[]byte("bar"),
)
@@ -4021,7 +4039,7 @@ func TestDB_Batch(t *testing.T) {
for i := 0; i < n; i++ {
go func(i int) {
ch <- db.Batch(func(tx TransactionI) error {
- return tx.Bucket([]byte("widgets")).Put(
+ return g.Must(tx.Bucket([]byte("widgets"))).Put(
u64tob(uint64(i)),
[]byte{},
)
@@ -4039,7 +4057,7 @@ func TestDB_Batch(t *testing.T) {
// Ensure data is correct.
err = db.View(func(snapshot SnapshotI) error {
- b := snapshot.Bucket([]byte("widgets"))
+ b := g.Must(snapshot.Bucket([]byte("widgets")))
for i := 0; i < n; i++ {
v := b.Get(u64tob(uint64(i)))
if v == nil {
@@ -4108,7 +4126,7 @@ func TestDB_BatchFull(t *testing.T) {
ch := make(chan error, size)
put := func(i int) {
ch <- db.Batch(func(tx TransactionI) error {
- return tx.Bucket([]byte("widgets")).Put(
+ return g.Must(tx.Bucket([]byte("widgets"))).Put(
u64tob(uint64(i)),
[]byte{},
)
@@ -4144,7 +4162,7 @@ func TestDB_BatchFull(t *testing.T) {
// Ensure data is correct.
err = db.View(func(snapshot SnapshotI) error {
- b := snapshot.Bucket([]byte("widgets"))
+ b := g.Must(snapshot.Bucket([]byte("widgets")))
for i := 1; i <= size; i++ {
v := b.Get(u64tob(uint64(i)))
if v == nil {
@@ -4177,7 +4195,7 @@ func TestDB_BatchTime(t *testing.T) {
ch := make(chan error, size)
put := func(i int) {
ch <- db.Batch(func(tx TransactionI) error {
- return tx.Bucket([]byte("widgets")).Put(
+ return g.Must(tx.Bucket([]byte("widgets"))).Put(
u64tob(uint64(i)),
[]byte{},
)
@@ -4200,7 +4218,7 @@ func TestDB_BatchTime(t *testing.T) {
// Ensure data is correct.
err = db.View(func(snapshot SnapshotI) error {
- b := snapshot.Bucket([]byte("widgets"))
+ b := g.Must(snapshot.Bucket([]byte("widgets")))
for i := 1; i <= size; i++ {
if v := b.Get(u64tob(uint64(i))); v == nil {
t.Errorf("key not found: %d", i)
@@ -4241,7 +4259,7 @@ func ExampleDB_Update() {
// Read the value back from a separate read-only transaction.
err = db.View(func(snapshot SnapshotI) error {
- value := snapshot.Bucket([]byte("widgets")).Get([]byte("foo"))
+ value := g.Must(snapshot.Bucket([]byte("widgets"))).Get([]byte("foo"))
fmt.Printf("The value of 'foo' is: %s\n", value)
return nil
})
@@ -4292,7 +4310,7 @@ func ExampleDB_View() {
// Access data from within a read-only transactional block.
err = db.View(func(snapshot SnapshotI) error {
- v := snapshot.Bucket([]byte("people")).Get([]byte("john"))
+ v := g.Must(snapshot.Bucket([]byte("people"))).Get([]byte("john"))
fmt.Printf("John's last name is %s.\n", v)
return nil
})
@@ -4334,7 +4352,7 @@ func ExampleDB_Begin_ReadOnly() {
log.Fatal(err)
}
- b := tx.Bucket([]byte("widgets"))
+ b := g.Must(tx.Bucket([]byte("widgets")))
err = b.Put([]byte("john"), []byte("blue"))
if err != nil {
log.Fatal(err)
@@ -4360,7 +4378,7 @@ func ExampleDB_Begin_ReadOnly() {
if err != nil {
log.Fatal(err)
}
- c := tx.Bucket([]byte("widgets")).Cursor()
+ c := g.Must(tx.Bucket([]byte("widgets"))).Cursor()
for k, v := c.First(); k != nil; k, v = c.Next() {
fmt.Printf("%s likes %s\n", k, v)
}
@@ -4412,7 +4430,7 @@ func BenchmarkDBBatchAutomatic(b *testing.B) {
_, _ = h.Write(buf[:])
k := h.Sum(nil)
insert := func(tx TransactionI) error {
- b := tx.Bucket([]byte("bench"))
+ b := g.Must(tx.Bucket([]byte("bench")))
return b.Put(k, []byte("filler"))
}
@@ -4461,7 +4479,7 @@ func BenchmarkDBBatchSingle(b *testing.B) {
_, _ = h.Write(buf[:])
k := h.Sum(nil)
insert := func(tx TransactionI) error {
- b := tx.Bucket([]byte("bench"))
+ b := g.Must(tx.Bucket([]byte("bench")))
return b.Put(k, []byte("filler"))
}
@@ -4516,7 +4534,7 @@ func BenchmarkDBBatchManual10x100(b *testing.B) {
h.Reset()
_, _ = h.Write(buf[:])
k := h.Sum(nil)
- b := tx.Bucket([]byte("bench"))
+ b := g.Must(tx.Bucket([]byte("bench")))
err := b.Put(
k,
[]byte("filler"),
@@ -4545,7 +4563,7 @@ func BenchmarkDBBatchManual10x100(b *testing.B) {
func validateBatchBench(b *testing.B, db *WDB) {
rollback := errors.New("sentinel error to cause rollback")
validate := func(tx TransactionI) error {
- bucket := tx.Bucket([]byte("bench"))
+ bucket := g.Must(tx.Bucket([]byte("bench")))
h := fnv.New32a()
buf := make([]byte, 4)
for id := uint32(0); id < 1000; id++ {
@@ -4618,22 +4636,16 @@ func (db *WDB) Close() error {
// MustClose closes the database and deletes the underlying file. Panic on
// error.
func (db *WDB) MustClose() {
- err := db.Close()
- if err != nil {
- panic(err)
- }
-
- os.Remove(db.Path())
+ g.PanicIf(db.Close())
}
// MustCheck runs a consistency check on the database and panics if any errors
// are found.
func (db *WDB) MustCheck() {
- err := db.Update(func(itx TransactionI) error {
- tx := itx.(*transactionT)
+ err := db.Update(func(t TransactionI) error {
// Collect all the errors.
errors := []error{}
- for err := range tx.Check() {
+ for err := range t.Check() {
errors = append(errors, err)
if len(errors) > 10 {
break
@@ -4644,7 +4656,7 @@ func (db *WDB) MustCheck() {
if len(errors) > 0 {
path := tempfile()
defer os.Remove(path)
- err := tx.copyFile(path, 0600)
+ err := copyFile(t, path, 0600)
if err != nil {
panic(err)
}
@@ -5584,8 +5596,8 @@ func simulateGetHandler(tx *transactionT, qdb *QuickDB) {
}
// Retrieve root bucket.
- b := tx.Bucket(keys[0])
- if b == nil {
+ b, err := tx.Bucket(keys[0])
+ if err != nil {
panic(fmt.Sprintf(
"bucket[0] expected: %08x\n",
trunc(keys[0], 4),
@@ -5594,8 +5606,8 @@ func simulateGetHandler(tx *transactionT, qdb *QuickDB) {
// Drill into nested buckets.
for _, key := range keys[1 : len(keys)-1] {
- b = b.Bucket(key)
- if b == nil {
+ b, err = b.Bucket(key)
+ if err != nil {
panic(fmt.Sprintf(
"bucket[n] expected: %v -> %v\n",
keys,
@@ -5623,25 +5635,33 @@ func simulatePutHandler(tx *transactionT, qdb *QuickDB) {
keys, value := randKeys(), randValue()
// Retrieve root bucket.
- b := tx.Bucket(keys[0])
- if b == /* nil FIXME */ (*bucketT)(nil) {
+ b, err := tx.Bucket(keys[0])
+ if err == ErrBucketNotFound {
b, err = tx.CreateBucket(keys[0])
if err != nil {
panic("create bucket: " + err.Error())
}
}
+ if err != nil {
+ panic(err)
+ }
// Create nested buckets, if necessary.
for _, key := range keys[1 : len(keys)-1] {
- child := b.Bucket(key)
- if child != /* nil FIXME */ (*bucketT)(nil) {
- b = child
- } else {
+ child, err := b.Bucket(key)
+ if err == ErrBucketNotFound {
b, err = b.CreateBucket(key)
if err != nil {
panic("create bucket: " + err.Error())
}
+ continue
+ }
+
+ if err != nil {
+ panic(err)
}
+
+ b = child
}
// Insert into database.
@@ -5966,7 +5986,8 @@ func TestTx_Bucket(t *testing.T) {
t.Fatal(err)
}
- if tx.Bucket([]byte("widgets")) == nil {
+ _, err = tx.Bucket([]byte("widgets"))
+ if err != nil {
t.Fatal("expected bucket")
}
@@ -6028,7 +6049,8 @@ func TestTx_CreateBucket(t *testing.T) {
// Read the bucket through a separate transaction.
err = db.View(func(snapshot SnapshotI) error {
- if snapshot.Bucket([]byte("widgets")) == nil {
+ _, err := snapshot.Bucket([]byte("widgets"))
+ if err != nil {
t.Fatal("expected bucket")
}
@@ -6070,7 +6092,8 @@ func TestTx_CreateBucketIfNotExists(t *testing.T) {
// Read the bucket through a separate transaction.
err = db.View(func(snapshot SnapshotI) error {
- if snapshot.Bucket([]byte("widgets")) == nil {
+ _, err := snapshot.Bucket([]byte("widgets"))
+ if err != nil {
t.Fatal("expected bucket")
}
@@ -6188,7 +6211,8 @@ func TestTx_DeleteBucket(t *testing.T) {
t.Fatal(err)
}
- if tx.Bucket([]byte("widgets")) != /* nil FIXME */ (*bucketT)(nil) {
+ _, err = tx.Bucket([]byte("widgets"))
+ if err != ErrBucketNotFound {
t.Fatal("unexpected bucket")
}
@@ -6507,7 +6531,7 @@ func ExampleTx_Rollback() {
// Set a value for a key.
err = db.Update(func(tx TransactionI) error {
- return tx.Bucket([]byte("widgets")).Put(
+ return g.Must(tx.Bucket([]byte("widgets"))).Put(
[]byte("foo"),
[]byte("bar"),
)
@@ -6522,7 +6546,7 @@ func ExampleTx_Rollback() {
log.Fatal(err)
}
- b := tx.Bucket([]byte("widgets"))
+ b := g.Must(tx.Bucket([]byte("widgets")))
err = b.Put([]byte("foo"), []byte("baz"))
if err != nil {
log.Fatal(err)
@@ -6535,7 +6559,7 @@ func ExampleTx_Rollback() {
// Ensure that our original value is still set.
err = db.View(func(snapshot SnapshotI) error {
- value := tx.Bucket([]byte("widgets")).Get([]byte("foo"))
+ value := g.Must(tx.Bucket([]byte("widgets"))).Get([]byte("foo"))
fmt.Printf("The value for 'foo' is still: %s\n", value)
return nil
})
@@ -6628,7 +6652,7 @@ func walkBucket(parent *bucketT, k []byte, v []byte, w io.Writer) error {
}
return parent.ForEach(func(k, v []byte) error {
if v == nil {
- return walkBucket(bucketGetNested(parent, k), k, nil, w)
+ return walkBucket(g.Must(bucketGetNested(parent, k)), k, nil, w)
}
return walkBucket(parent, k, v, w)
})