diff options
-rw-r--r-- | src/dedo.go | 70 | ||||
-rw-r--r-- | tests/dedo.go | 248 |
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) }) |