diff options
-rw-r--r-- | src/dedo.go | 130 | ||||
-rw-r--r-- | tests/dedo.go | 266 |
2 files changed, 177 insertions, 219 deletions
diff --git a/src/dedo.go b/src/dedo.go index ae15ff2..f308b71 100644 --- a/src/dedo.go +++ b/src/dedo.go @@ -71,39 +71,46 @@ type CursorI interface{ Delete() error } -type BucketI interface{ +type ROBucketI interface{ Get([]byte) []byte + Cursor() CursorI + ForEach(func([]byte, []byte) error) error + ROBucket([]byte) (ROBucketI, error) +} + +type RWBucketI interface{ + Get([]byte) []byte + Cursor() CursorI + ForEach(func([]byte, []byte) error) error + RWBucket([]byte) (RWBucketI, error) Put([]byte, []byte) error Delete([]byte) error - ForEach(func([]byte, []byte) error) error - CreateBucket([]byte) (BucketI, error) - CreateBucketIfNotExists([]byte) (BucketI, error) + CreateBucket([]byte) (RWBucketI, error) + CreateBucketIfNotExists([]byte) (RWBucketI, error) DeleteBucket([]byte) error - Bucket([]byte) (BucketI, error) NextID() []byte NextSequence() (uint64, error) - Cursor() CursorI } type SnapshotI interface{ - Bucket([]byte) (BucketI, error) + ROBucket([]byte) (ROBucketI, error) Cursor() CursorI - ForEach(func([]byte, BucketI) error) error + ROForEach(func([]byte, ROBucketI) error) error WriteTo(io.Writer) (int64, error) Check() <-chan error } type TransactionI interface{ - Bucket([]byte) (BucketI, error) + RWBucket([]byte) (RWBucketI, error) Cursor() CursorI - ForEach(func([]byte, BucketI) error) error + RWForEach(func([]byte, RWBucketI) error) error WriteTo(io.Writer) (int64, error) Check() <-chan error - CreateBucket ([]byte) (BucketI, error) - CreateBucketIfNotExists([]byte) (BucketI, error) + CreateBucket ([]byte) (RWBucketI, error) + CreateBucketIfNotExists([]byte) (RWBucketI, error) DeleteBucket([]byte) error OnCommit(func()) } @@ -678,7 +685,11 @@ func bucketGetNested(b *bucketT, name []byte) (*bucketT, error) { return child, nil } -func (b *bucketT) Bucket(name []byte) (BucketI, error) { +func (b *bucketT) ROBucket(name []byte) (ROBucketI, error) { + return bucketGetNested(b, name) +} + +func (b *bucketT) RWBucket(name []byte) (RWBucketI, error) { return bucketGetNested(b, name) } @@ -749,7 +760,7 @@ func bucketCreateBucket(b *bucketT, key []byte) (*bucketT, error) { return bucketGetNested(b, key) } -func (b *bucketT) CreateBucket(key []byte) (BucketI, error) { +func (b *bucketT) CreateBucket(key []byte) (RWBucketI, error) { return bucketCreateBucket(b, key) } @@ -767,7 +778,7 @@ func bucketCreateBucketIfNotExists(b *bucketT, key []byte) (*bucketT, error) { return child, nil } -func (b *bucketT) CreateBucketIfNotExists(key []byte) (BucketI, error) { +func (b *bucketT) CreateBucketIfNotExists(key []byte) (RWBucketI, error) { return bucketCreateBucketIfNotExists(b, key) } @@ -1811,7 +1822,10 @@ func (cursor *inMemoryCursorT) Delete() error { return nil // FIXME } -func (bucket *inMemoryValueT) Bucket(name []byte) (BucketI, error) { +func memBucketGetNested( + bucket *inMemoryValueT, + name []byte, +) (*inMemoryValueT, error) { if bucket.tx.root == nil { return nil, ErrTxClosed } @@ -1828,7 +1842,15 @@ func (bucket *inMemoryValueT) Bucket(name []byte) (BucketI, error) { return value, nil } -func (bucket *inMemoryValueT) CreateBucket(name []byte) (BucketI, error) { +func (bucket *inMemoryValueT) ROBucket(name []byte) (ROBucketI, error) { + return memBucketGetNested(bucket, name) +} + +func (bucket *inMemoryValueT) RWBucket(name []byte) (RWBucketI, error) { + return memBucketGetNested(bucket, name) +} + +func (bucket *inMemoryValueT) CreateBucket(name []byte) (RWBucketI, error) { if bucket.tx.root == nil { return nil, ErrTxClosed } else if !bucket.tx.writable { @@ -1837,7 +1859,7 @@ func (bucket *inMemoryValueT) CreateBucket(name []byte) (BucketI, error) { return nil, ErrBucketNameRequired } - _, err := bucket.Bucket(name) + _, err := bucket.RWBucket(name) if err == nil { return nil, ErrBucketExists } @@ -1853,7 +1875,7 @@ func (bucket *inMemoryValueT) CreateBucket(name []byte) (BucketI, error) { return newBucket, nil } -func (bucket *inMemoryValueT) CreateBucketIfNotExists(name []byte) (BucketI, error) { +func (bucket *inMemoryValueT) CreateBucketIfNotExists(name []byte) (RWBucketI, error) { if bucket.tx.root == nil { return nil, ErrTxClosed } else if !bucket.tx.writable { @@ -1862,7 +1884,7 @@ func (bucket *inMemoryValueT) CreateBucketIfNotExists(name []byte) (BucketI, err newBucket, err := bucket.CreateBucket(name) if err == ErrBucketExists { - return bucket.Bucket(name) + return bucket.RWBucket(name) } else if err != nil { return nil, err } @@ -1956,20 +1978,28 @@ func (bucket *inMemoryValueT) NextSequence() (uint64, error) { return 0, nil // FIXME } -func (tx *inMemoryTxT) Bucket(name []byte) (BucketI, error) { +func memTxBucket(tx *inMemoryTxT, name []byte) (*inMemoryValueT, error) { if tx.root == nil { return nil, ErrTxClosed } - return tx.root.Bucket(name) + return memBucketGetNested(tx.root, name) +} + +func (tx *inMemoryTxT) ROBucket(name []byte) (ROBucketI, error) { + return memTxBucket(tx, name) +} + +func (tx *inMemoryTxT) RWBucket(name []byte) (RWBucketI, error) { + return memTxBucket(tx, name) } -func (tx *inMemoryTxT) CreateBucket(name []byte) (BucketI, error) { +func (tx *inMemoryTxT) CreateBucket(name []byte) (RWBucketI, error) { // return tx.root.CreateBucket(name) return nil, nil // FIXME } -func (tx *inMemoryTxT) CreateBucketIfNotExists(name []byte) (BucketI, error) { +func (tx *inMemoryTxT) CreateBucketIfNotExists(name []byte) (RWBucketI, error) { return nil, nil // FIXME } @@ -1985,7 +2015,11 @@ func (tx *inMemoryTxT) DeleteBucket(name []byte) error { return tx.root.DeleteBucket(name) } -func (tx *inMemoryTxT) ForEach(fn func([]byte, BucketI) error) error { +func (tx *inMemoryTxT) ROForEach(fn func([]byte, ROBucketI) error) error { + return nil // FIXME +} + +func (tx *inMemoryTxT) RWForEach(fn func([]byte, RWBucketI) error) error { return nil // FIXME } @@ -3800,7 +3834,11 @@ func txBucket(tx *transactionT, name []byte) (*bucketT, error) { return bucketGetNested(&tx.root, name) } -func (tx *transactionT) Bucket(name []byte) (BucketI, error) { +func (tx *transactionT) ROBucket(name []byte) (ROBucketI, error) { + return txBucket(tx, name) +} + +func (tx *transactionT) RWBucket(name []byte) (RWBucketI, error) { return txBucket(tx, name) } @@ -3812,7 +3850,7 @@ func txCreateBucket(tx *transactionT, name []byte) (*bucketT, error) { return bucketCreateBucket(&tx.root, name) } -func (tx *transactionT) CreateBucket(name []byte) (BucketI, error) { +func (tx *transactionT) CreateBucket(name []byte) (RWBucketI, error) { return txCreateBucket(tx, name) } @@ -3824,7 +3862,7 @@ func txCreateBucketIfNotExists(tx *transactionT, name []byte) (*bucketT, error) return bucketCreateBucketIfNotExists(&tx.root, name) } -func (tx *transactionT) CreateBucketIfNotExists(name []byte) (BucketI, error) { +func (tx *transactionT) CreateBucketIfNotExists(name []byte) (RWBucketI, error) { return txCreateBucketIfNotExists(tx, name) } @@ -3841,9 +3879,13 @@ func (tx *transactionT) DeleteBucket(name []byte) error { /// transactionT.ForEach() executes a function for each bucket in the root. If the /// provided function returns an error then the iteration is stopped and the /// error is returned to the caller. -func txForEach(tx *transactionT, fn func([]byte, BucketI) error) error { +func txForEach[T any]( + tx *transactionT, + fn func([]byte, T) error, + bucketFn func(*bucketT, []byte) (T, error), +) error { return tx.root.ForEach(func(k []byte, v []byte) error { - bucket, err := tx.root.Bucket(k) + bucket, err := bucketFn(&tx.root, k) if err != nil { return err } @@ -3851,8 +3893,22 @@ func txForEach(tx *transactionT, fn func([]byte, BucketI) error) error { }) } -func (tx *transactionT) ForEach(fn func([]byte, BucketI) error) error { - return txForEach(tx, fn) +func (tx *transactionT) ROForEach(fn func([]byte, ROBucketI) error) error { + return txForEach(tx, fn, func( + bucket *bucketT, + name []byte, + ) (ROBucketI, error) { + return bucket.ROBucket(name) + }) +} + +func (tx *transactionT) RWForEach(fn func([]byte, RWBucketI) error) error { + return txForEach(tx, fn, func( + bucket *bucketT, + name []byte, + ) (RWBucketI, error) { + return bucket.RWBucket(name) + }) } /// transactionT.OnCommit() adds a handler function to be executed after the transaction @@ -4327,7 +4383,7 @@ 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, err := snapshot.Bucket(args.bucket) + bucket, err := snapshot.ROBucket(args.bucket) if err != nil { return err } @@ -4355,7 +4411,7 @@ 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, err := tx.Bucket(args.bucket) + bucket, err := tx.RWBucket(args.bucket) if err != nil { return err } @@ -4367,16 +4423,16 @@ func rmExec(args argsT, db DatabaseI, r io.Reader, w io.Writer) error { func listExec(args argsT, db DatabaseI, r io.Reader, w io.Writer) error { return db.View(func(snapshot SnapshotI) error { if len(args.bucket) == 0 { - return snapshot.ForEach(func( + return snapshot.ROForEach(func( name []byte, - bucket BucketI, + bucket ROBucketI, ) error { fmt.Fprintf(w, "%s\n", string(name)) return nil }) } - bucket, err := snapshot.Bucket(args.bucket) + bucket, err := snapshot.ROBucket(args.bucket) if err != nil { return err } diff --git a/tests/dedo.go b/tests/dedo.go index 72bc795..bce24b5 100644 --- a/tests/dedo.go +++ b/tests/dedo.go @@ -613,14 +613,14 @@ func TestBucket_Get_IncompatibleValue(t *testing.T) { t.Fatal(err) } - _, err = g.Must(tx.Bucket([]byte("widgets"))).CreateBucket([ - ]byte("foo"), + _, err = g.Must(tx.RWBucket([]byte("widgets"))).CreateBucket( + []byte("foo"), ) if err != nil { t.Fatal(err) } - if g.Must(tx.Bucket([]byte("widgets"))).Get([]byte("foo")) != nil { + if g.Must(tx.RWBucket([]byte("widgets"))).Get([]byte("foo")) != nil { t.Fatal("expected nil value") } @@ -656,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 := g.Must(tx.Bucket([]byte("bucket"))).Cursor().First() + k, v := g.Must(tx.RWBucket([]byte("bucket"))).Cursor().First() // Verify capacity. if len(k) != cap(k) { @@ -693,7 +693,7 @@ func TestBucket_Put(t *testing.T) { t.Fatal(err) } - v := g.Must(tx.Bucket([]byte("widgets"))).Get([]byte("foo")) + v := g.Must(tx.RWBucket([]byte("widgets"))).Get([]byte("foo")) if !bytes.Equal([]byte("bar"), v) { t.Fatalf("unexpected value: %v", v) } @@ -727,7 +727,7 @@ func TestBucket_Put_Repeat(t *testing.T) { t.Fatal(err) } - value := g.Must(tx.Bucket([]byte("widgets"))).Get([]byte("foo")) + value := g.Must(tx.RWBucket([]byte("widgets"))).Get([]byte("foo")) if !bytes.Equal([]byte("baz"), value) { t.Fatalf("unexpected value: %v", value) } @@ -767,7 +767,7 @@ func TestBucket_Put_Large(t *testing.T) { } err = db.View(func(snapshot SnapshotI) error { - b := g.Must(snapshot.Bucket([]byte("widgets"))) + b := g.Must(snapshot.ROBucket([]byte("widgets"))) for i := 1; i < count; i++ { value := b.Get([]byte(strings.Repeat("0", i*factor))) expected := []byte(strings.Repeat( @@ -832,7 +832,7 @@ func TestBucket_Put_IncompatibleValue(t *testing.T) { t.Fatal(err) } - _, err = g.Must(tx.Bucket([]byte("widgets"))).CreateBucket( + _, err = g.Must(tx.RWBucket([]byte("widgets"))).CreateBucket( []byte("foo"), ) if err != nil { @@ -879,38 +879,6 @@ func TestBucket_Put_Closed(t *testing.T) { } } -// Ensure that setting a value on a read-only bucket returns an error. -func TestBucket_Put_ReadOnly(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - defer os.Remove(db.Path()) - - err := db.Update(func(tx TransactionI) error { - _, err := tx.CreateBucket([]byte("widgets")) - if err != nil { - t.Fatal(err) - } - - return nil - }) - if err != nil { - t.Fatal(err) - } - - err = db.View(func(snapshot SnapshotI) error { - b := g.Must(snapshot.Bucket([]byte("widgets"))) - err := b.Put([]byte("foo"), []byte("bar")) - if err != ErrTxNotWritable { - t.Fatalf("unexpected error: %s", err) - } - - return nil - }) - if err != nil { - t.Fatal(err) - } -} - // Ensure that a bucket can delete an existing key. func TestBucket_Delete(t *testing.T) { db := MustOpenDB() @@ -974,7 +942,7 @@ func TestBucket_Delete_Large(t *testing.T) { } err = db.Update(func(tx TransactionI) error { - b := g.Must(tx.Bucket([]byte("widgets"))) + b := g.Must(tx.RWBucket([]byte("widgets"))) for i := 0; i < 100; i++ { err := b.Delete([]byte(strconv.Itoa(i))) if err != nil { @@ -988,7 +956,7 @@ func TestBucket_Delete_Large(t *testing.T) { } err = db.View(func(snapshot SnapshotI) error { - b := g.Must(snapshot.Bucket([]byte("widgets"))) + b := g.Must(snapshot.ROBucket([]byte("widgets"))) for i := 0; i < 100; i++ { v := b.Get([]byte(strconv.Itoa(i))) if v != nil { @@ -1040,7 +1008,7 @@ func TestBucket_Delete_FreelistOverflow(t *testing.T) { // Delete all of them in one large transaction err := db.Update(func(tx TransactionI) error { - b := g.Must(tx.Bucket([]byte("0"))) + b := g.Must(tx.RWBucket([]byte("0"))) c := b.Cursor() for k, _ := c.First(); k != nil; k, _ = c.Next() { err := c.Delete() @@ -1089,7 +1057,7 @@ func TestBucket_Nested(t *testing.T) { // Update widgets/bar. err = db.Update(func(tx TransactionI) error { - b := g.Must(tx.Bucket([]byte("widgets"))) + b := g.Must(tx.RWBucket([]byte("widgets"))) err := b.Put([]byte("bar"), []byte("xxxx")) if err != nil { t.Fatal(err) @@ -1104,7 +1072,7 @@ func TestBucket_Nested(t *testing.T) { // Cause a split. err = db.Update(func(tx TransactionI) error { - b := g.Must(tx.Bucket([]byte("widgets"))) + b := g.Must(tx.RWBucket([]byte("widgets"))) for i := 0; i < 10000; i++ { err := b.Put( []byte(strconv.Itoa(i)), @@ -1124,8 +1092,8 @@ func TestBucket_Nested(t *testing.T) { // Insert into widgets/foo/baz. err = db.Update(func(tx TransactionI) error { - b := g.Must(tx.Bucket([]byte("widgets"))) - err := g.Must(b.Bucket([]byte("foo"))).Put( + b := g.Must(tx.RWBucket([]byte("widgets"))) + err := g.Must(b.RWBucket([]byte("foo"))).Put( []byte("baz"), []byte("yyyy"), ) @@ -1142,8 +1110,8 @@ func TestBucket_Nested(t *testing.T) { // Verify. err = db.View(func(snapshot SnapshotI) error { - b := g.Must(snapshot.Bucket([]byte("widgets"))) - v := g.Must(b.Bucket([]byte("foo"))).Get([]byte("baz")) + b := g.Must(snapshot.ROBucket([]byte("widgets"))) + v := g.Must(b.ROBucket([]byte("foo"))).Get([]byte("baz")) if !bytes.Equal(v, []byte("yyyy")) { t.Fatalf("unexpected value: %v", v) } @@ -1196,37 +1164,6 @@ func TestBucket_Delete_Bucket(t *testing.T) { } } -// Ensure that deleting a key on a read-only bucket returns an error. -func TestBucket_Delete_ReadOnly(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - defer os.Remove(db.Path()) - - err := db.Update(func(tx TransactionI) error { - _, err := tx.CreateBucket([]byte("widgets")) - if err != nil { - t.Fatal(err) - } - - return nil - }) - if err != nil { - t.Fatal(err) - } - - err = db.View(func(snapshot SnapshotI) error { - err := g.Must(snapshot.Bucket([]byte("widgets"))).Delete([]byte("foo")) - if err != ErrTxNotWritable { - t.Fatalf("unexpected error: %s", err) - } - - return nil - }) - if err != nil { - t.Fatal(err) - } -} - // Ensure that a deleting value while the transaction is closed returns an // error. func TestBucket_Delete_Closed(t *testing.T) { @@ -1282,7 +1219,7 @@ func TestBucket_DeleteBucket_Nested(t *testing.T) { t.Fatal(err) } - err = g.Must(tx.Bucket([]byte("widgets"))).DeleteBucket([]byte("foo")) + err = g.Must(tx.RWBucket([]byte("widgets"))).DeleteBucket([]byte("foo")) if err != nil { t.Fatal(err) } @@ -1328,17 +1265,17 @@ func TestBucket_DeleteBucket_Nested2(t *testing.T) { } err = db.Update(func(tx TransactionI) error { - widgets, err := tx.Bucket([]byte("widgets")) + widgets, err := tx.RWBucket([]byte("widgets")) if err != nil { t.Fatal("expected widgets bucket") } - foo, err := widgets.Bucket([]byte("foo")) + foo, err := widgets.RWBucket([]byte("foo")) if err != nil { t.Fatal("expected foo bucket") } - bar, err := foo.Bucket([]byte("bar")) + bar, err := foo.RWBucket([]byte("bar")) if err != nil { t.Fatal("expected bar bucket") } @@ -1360,7 +1297,7 @@ func TestBucket_DeleteBucket_Nested2(t *testing.T) { } err = db.View(func(snapshot SnapshotI) error { - _, err := snapshot.Bucket([]byte("widgets")) + _, err := snapshot.ROBucket([]byte("widgets")) if err != ErrBucketNotFound { t.Fatal("expected bucket to be deleted") } @@ -1436,7 +1373,7 @@ func TestBucket_Bucket_IncompatibleValue(t *testing.T) { t.Fatal(err) } - _, err = g.Must(tx.Bucket([]byte("widgets"))).Bucket([]byte("foo")) + _, err = g.Must(tx.RWBucket([]byte("widgets"))).RWBucket([]byte("foo")) if err != ErrBucketBadFlag { t.Fatal("expected value, not bucket") } @@ -1494,7 +1431,7 @@ func TestBucket_DeleteBucket_IncompatibleValue(t *testing.T) { t.Fatal(err) } - err = g.Must(tx.Bucket([]byte("widgets"))).DeleteBucket([]byte("foo")) + err = g.Must(tx.RWBucket([]byte("widgets"))).DeleteBucket([]byte("foo")) if err != ErrIncompatibleValue { t.Fatalf("unexpected error: %s", err) } @@ -1574,7 +1511,7 @@ func TestBucket_NextSequence_Persist(t *testing.T) { } err = db.Update(func(tx TransactionI) error { - _, err := g.Must(tx.Bucket([]byte("widgets"))).NextSequence() + _, err := g.Must(tx.RWBucket([]byte("widgets"))).NextSequence() if err != nil { t.Fatal(err) } @@ -1586,7 +1523,7 @@ func TestBucket_NextSequence_Persist(t *testing.T) { } err = db.Update(func(tx TransactionI) error { - seq, err := g.Must(tx.Bucket([]byte("widgets"))).NextSequence() + seq, err := g.Must(tx.RWBucket([]byte("widgets"))).NextSequence() if err != nil { t.Fatalf("unexpected error: %s", err) } else if seq != 2 { @@ -1600,38 +1537,6 @@ func TestBucket_NextSequence_Persist(t *testing.T) { } } -// Ensure that retrieving the next sequence on a read-only bucket returns an -// error. -func TestBucket_NextSequence_ReadOnly(t *testing.T) { - db := MustOpenDB() - defer db.MustClose() - defer os.Remove(db.Path()) - - err := db.Update(func(tx TransactionI) error { - _, err := tx.CreateBucket([]byte("widgets")) - if err != nil { - t.Fatal(err) - } - - return nil - }) - if err != nil { - t.Fatal(err) - } - - err = db.View(func(snapshot SnapshotI) error { - _, err := g.Must(snapshot.Bucket([]byte("widgets"))).NextSequence() - if err != ErrTxNotWritable { - t.Fatalf("unexpected error: %s", err) - } - - return nil - }) - if err != nil { - t.Fatal(err) - } -} - // Ensure that retrieving the next sequence for a bucket on a closed database // return an error. func TestBucket_NextSequence_Closed(t *testing.T) { @@ -1756,7 +1661,7 @@ func TestBucket_ForEach_ShortCircuit(t *testing.T) { } var index int - err = g.Must(tx.Bucket( + err = g.Must(tx.RWBucket( []byte("widgets"), )).ForEach(func(k, v []byte) error { index++ @@ -1911,7 +1816,7 @@ func TestBucket_Put_Single(t *testing.T) { for _, item := range items { err := db.Update(func(tx TransactionI) error { - err := g.Must(tx.Bucket([]byte("widgets"))).Put( + err := g.Must(tx.RWBucket([]byte("widgets"))).Put( item.Key, item.Value, ) @@ -1933,7 +1838,7 @@ func TestBucket_Put_Single(t *testing.T) { err = db.View(func(snapshot SnapshotI) error { i := 0 for k, v := range m { - value := g.Must(snapshot.Bucket( + value := g.Must(snapshot.ROBucket( []byte("widgets"), )).Get([]byte(k)) if !bytes.Equal(value, v) { @@ -1991,7 +1896,7 @@ func TestBucket_Put_Multiple(t *testing.T) { } err = db.Update(func(tx TransactionI) error { - b := g.Must(tx.Bucket([]byte("widgets"))) + b := g.Must(tx.RWBucket([]byte("widgets"))) for _, item := range items { err := b.Put(item.Key, item.Value) if err != nil { @@ -2007,7 +1912,7 @@ func TestBucket_Put_Multiple(t *testing.T) { // Verify all items exist. err = db.View(func(snapshot SnapshotI) error { - b := g.Must(snapshot.Bucket([]byte("widgets"))) + b := g.Must(snapshot.ROBucket([]byte("widgets"))) for _, item := range items { value := b.Get(item.Key) if !bytes.Equal(item.Value, value) { @@ -2058,7 +1963,7 @@ func TestBucket_Delete_Quick(t *testing.T) { } err = db.Update(func(tx TransactionI) error { - b := g.Must(tx.Bucket([]byte("widgets"))) + b := g.Must(tx.RWBucket([]byte("widgets"))) for _, item := range items { err := b.Put(item.Key, item.Value) if err != nil { @@ -2075,7 +1980,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 g.Must(tx.Bucket([]byte("widgets"))).Delete( + return g.Must(tx.RWBucket([]byte("widgets"))).Delete( item.Key, ) }) @@ -2086,7 +1991,7 @@ func TestBucket_Delete_Quick(t *testing.T) { // Anything before our deletion index should be nil. err = db.View(func(snapshot SnapshotI) error { - err := g.Must(snapshot.Bucket( + err := g.Must(snapshot.ROBucket( []byte("widgets"), )).ForEach(func(k, v []byte) error { t.Fatalf( @@ -2142,7 +2047,7 @@ func ExampleBucket_Put() { // Read value back in a different read-only transaction. err = db.View(func(snapshot SnapshotI) error { - value := g.Must(snapshot.Bucket([]byte("widgets"))).Get([]byte("foo")) + value := g.Must(snapshot.ROBucket([]byte("widgets"))).Get([]byte("foo")) fmt.Printf("The value of 'foo' is: %s\n", value) return nil }) @@ -2194,7 +2099,7 @@ func ExampleBucket_Delete() { // Delete the key in a different write transaction. err = db.Update(func(tx TransactionI) error { - return g.Must(tx.Bucket([]byte("widgets"))).Delete([]byte("foo")) + return g.Must(tx.RWBucket([]byte("widgets"))).Delete([]byte("foo")) }) if err != nil { log.Fatal(err) @@ -2202,7 +2107,7 @@ func ExampleBucket_Delete() { // Retrieve the key again. err = db.View(func(snapshot SnapshotI) error { - value := g.Must(snapshot.Bucket([]byte("widgets"))).Get([]byte("foo")) + value := g.Must(snapshot.ROBucket([]byte("widgets"))).Get([]byte("foo")) if value == nil { fmt.Printf("The value of 'foo' is now: nil\n") } @@ -2319,7 +2224,7 @@ func TestCursor_Seek(t *testing.T) { } err = db.View(func(snapshot SnapshotI) error { - c := g.Must(snapshot.Bucket([]byte("widgets"))).Cursor() + c := g.Must(snapshot.ROBucket([]byte("widgets"))).Cursor() // Exact match should go to the key. k, v := c.Seek([]byte("bar")) @@ -2403,7 +2308,7 @@ func TestCursor_Delete(t *testing.T) { } err = db.Update(func(tx TransactionI) error { - c := g.Must(tx.Bucket([]byte("widgets"))).Cursor() + c := g.Must(tx.RWBucket([]byte("widgets"))).Cursor() bound := make([]byte, 8) binary.BigEndian.PutUint64(bound, uint64(count/2)) for @@ -2465,7 +2370,7 @@ func TestCursor_Seek_Large(t *testing.T) { } err = db.View(func(snapshot SnapshotI) error { - c := g.Must(snapshot.Bucket([]byte("widgets"))).Cursor() + c := g.Must(snapshot.ROBucket([]byte("widgets"))).Cursor() for i := 0; i < count; i++ { seek := make([]byte, 8) binary.BigEndian.PutUint64(seek, uint64(i)) @@ -2517,7 +2422,7 @@ func TestCursor_EmptyBucket(t *testing.T) { } err = db.View(func(snapshot SnapshotI) error { - c := g.Must(snapshot.Bucket([]byte("widgets"))).Cursor() + c := g.Must(snapshot.ROBucket([]byte("widgets"))).Cursor() k, v := c.First() if k != nil { t.Fatalf("unexpected key: %v", k) @@ -2547,7 +2452,7 @@ func TestCursor_EmptyBucketReverse(t *testing.T) { } err = db.View(func(snapshot SnapshotI) error { - c := g.Must(snapshot.Bucket([]byte("widgets"))).Cursor() + c := g.Must(snapshot.ROBucket([]byte("widgets"))).Cursor() k, v := c.Last() if k != nil { t.Fatalf("unexpected key: %v", k) @@ -2601,7 +2506,7 @@ func TestCursor_Iterate_Leaf(t *testing.T) { } defer func() { _ = tx.rollback() }() - c := g.Must(tx.Bucket([]byte("widgets"))).Cursor() + c := g.Must(tx.RWBucket([]byte("widgets"))).Cursor() k, v := c.First() if !bytes.Equal(k, []byte("bar")) { @@ -2683,7 +2588,7 @@ func TestCursor_LeafRootReverse(t *testing.T) { t.Fatal(err) } - c := g.Must(tx.Bucket([]byte("widgets"))).Cursor() + c := g.Must(tx.ROBucket([]byte("widgets"))).Cursor() k, v := c.Last() if !bytes.Equal(k, []byte("foo")) { t.Fatalf("unexpected key: %v", k) @@ -2758,7 +2663,7 @@ func TestCursor_Restart(t *testing.T) { t.Fatal(err) } - c := g.Must(tx.Bucket([]byte("widgets"))).Cursor() + c := g.Must(tx.ROBucket([]byte("widgets"))).Cursor() k, _ := c.First() if !bytes.Equal(k, []byte("bar")) { @@ -2813,7 +2718,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 := g.Must(tx.Bucket([]byte("widgets"))) + b := g.Must(tx.RWBucket([]byte("widgets"))) for i := 0; i < 600; i++ { err := b.Delete(u64tob(uint64(i))) if err != nil { @@ -2875,7 +2780,7 @@ func TestCursor_QuickCheck(t *testing.T) { t.Fatal(err) } - c := g.Must(tx.Bucket([]byte("widgets"))).Cursor() + c := g.Must(tx.ROBucket([]byte("widgets"))).Cursor() for k, v := c.First(); k != nil && index < len(items); @@ -2950,7 +2855,7 @@ func TestCursor_QuickCheck_Reverse(t *testing.T) { t.Fatal(err) } - c := g.Must(tx.Bucket([]byte("widgets"))).Cursor() + c := g.Must(tx.ROBucket([]byte("widgets"))).Cursor() for k, v := c.Last(); k != nil && index < len(items); @@ -3020,7 +2925,7 @@ func TestCursor_QuickCheck_BucketsOnly(t *testing.T) { err = db.View(func(snapshot SnapshotI) error { names := []string{} - c := g.Must(snapshot.Bucket([]byte("widgets"))).Cursor() + c := g.Must(snapshot.ROBucket([]byte("widgets"))).Cursor() for k, v := c.First(); k != nil; k, v = c.Next() { names = append(names, string(k)) if v != nil { @@ -3074,7 +2979,7 @@ func TestCursor_QuickCheck_BucketsOnly_Reverse(t *testing.T) { err = db.View(func(snapshot SnapshotI) error { names := []string{} - c := g.Must(snapshot.Bucket([]byte("widgets"))).Cursor() + c := g.Must(snapshot.ROBucket([]byte("widgets"))).Cursor() for k, v := c.Last(); k != nil; k, v = c.Prev() { names = append(names, string(k)) if v != nil { @@ -3389,7 +3294,7 @@ func TestOpen_Size(t *testing.T) { } err = db0.Update(func(tx TransactionI) error { - err := g.Must(tx.Bucket([]byte("data"))).Put([]byte{0}, []byte{0}) + err := g.Must(tx.RWBucket([]byte("data"))).Put([]byte{0}, []byte{0}) if err != nil { t.Fatal(err) } @@ -3476,7 +3381,7 @@ func TestOpen_Size_Large(t *testing.T) { } err = db0.Update(func(tx TransactionI) error { - return g.Must(tx.Bucket([]byte("data"))).Put([]byte{0}, []byte{0}) + return g.Must(tx.RWBucket([]byte("data"))).Put([]byte{0}, []byte{0}) }) if err != nil { t.Fatal(err) @@ -3773,7 +3678,7 @@ func TestDB_Update(t *testing.T) { } err = db.View(func(snapshot SnapshotI) error { - b := g.Must(snapshot.Bucket([]byte("widgets"))) + b := g.Must(snapshot.ROBucket([]byte("widgets"))) v := b.Get([]byte("foo")) if v != nil { t.Fatalf("expected nil value, got: %v", v) @@ -3850,7 +3755,7 @@ func TestDB_Update_Panic(t *testing.T) { // Verify that our change persisted. err = db.Update(func(tx TransactionI) error { - _, err := tx.Bucket([]byte("widgets")) + _, err := tx.RWBucket([]byte("widgets")) if err != nil { t.Fatal("expected bucket") } @@ -3904,7 +3809,7 @@ func TestDB_View_Panic(t *testing.T) { }() err := db.View(func(snapshot SnapshotI) error { - _, err := snapshot.Bucket([]byte("widgets")) + _, err := snapshot.ROBucket([]byte("widgets")) if err != nil { t.Fatal("expected bucket") } @@ -3917,7 +3822,7 @@ func TestDB_View_Panic(t *testing.T) { // Verify that we can still use read transactions. err = db.View(func(snapshot SnapshotI) error { - _, err := snapshot.Bucket([]byte("widgets")) + _, err := snapshot.ROBucket([]byte("widgets")) if err != nil { t.Fatal("expected bucket") } @@ -3944,7 +3849,7 @@ func TestDB_Consistency(t *testing.T) { for i := 0; i < 10; i++ { err := db.Update(func(tx TransactionI) error { - err := g.Must(tx.Bucket([]byte("widgets"))).Put( + err := g.Must(tx.RWBucket([]byte("widgets"))).Put( []byte("foo"), []byte("bar"), ) @@ -4039,7 +3944,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 g.Must(tx.Bucket([]byte("widgets"))).Put( + return g.Must(tx.RWBucket([]byte("widgets"))).Put( u64tob(uint64(i)), []byte{}, ) @@ -4057,7 +3962,7 @@ func TestDB_Batch(t *testing.T) { // Ensure data is correct. err = db.View(func(snapshot SnapshotI) error { - b := g.Must(snapshot.Bucket([]byte("widgets"))) + b := g.Must(snapshot.ROBucket([]byte("widgets"))) for i := 0; i < n; i++ { v := b.Get(u64tob(uint64(i))) if v == nil { @@ -4126,7 +4031,7 @@ func TestDB_BatchFull(t *testing.T) { ch := make(chan error, size) put := func(i int) { ch <- db.Batch(func(tx TransactionI) error { - return g.Must(tx.Bucket([]byte("widgets"))).Put( + return g.Must(tx.RWBucket([]byte("widgets"))).Put( u64tob(uint64(i)), []byte{}, ) @@ -4162,7 +4067,7 @@ func TestDB_BatchFull(t *testing.T) { // Ensure data is correct. err = db.View(func(snapshot SnapshotI) error { - b := g.Must(snapshot.Bucket([]byte("widgets"))) + b := g.Must(snapshot.ROBucket([]byte("widgets"))) for i := 1; i <= size; i++ { v := b.Get(u64tob(uint64(i))) if v == nil { @@ -4195,7 +4100,7 @@ func TestDB_BatchTime(t *testing.T) { ch := make(chan error, size) put := func(i int) { ch <- db.Batch(func(tx TransactionI) error { - return g.Must(tx.Bucket([]byte("widgets"))).Put( + return g.Must(tx.RWBucket([]byte("widgets"))).Put( u64tob(uint64(i)), []byte{}, ) @@ -4218,7 +4123,7 @@ func TestDB_BatchTime(t *testing.T) { // Ensure data is correct. err = db.View(func(snapshot SnapshotI) error { - b := g.Must(snapshot.Bucket([]byte("widgets"))) + b := g.Must(snapshot.ROBucket([]byte("widgets"))) for i := 1; i <= size; i++ { if v := b.Get(u64tob(uint64(i))); v == nil { t.Errorf("key not found: %d", i) @@ -4259,7 +4164,7 @@ func ExampleDB_Update() { // Read the value back from a separate read-only transaction. err = db.View(func(snapshot SnapshotI) error { - value := g.Must(snapshot.Bucket([]byte("widgets"))).Get([]byte("foo")) + value := g.Must(snapshot.ROBucket([]byte("widgets"))).Get([]byte("foo")) fmt.Printf("The value of 'foo' is: %s\n", value) return nil }) @@ -4310,7 +4215,7 @@ func ExampleDB_View() { // Access data from within a read-only transactional block. err = db.View(func(snapshot SnapshotI) error { - v := g.Must(snapshot.Bucket([]byte("people"))).Get([]byte("john")) + v := g.Must(snapshot.ROBucket([]byte("people"))).Get([]byte("john")) fmt.Printf("John's last name is %s.\n", v) return nil }) @@ -4352,7 +4257,7 @@ func ExampleDB_Begin_ReadOnly() { log.Fatal(err) } - b := g.Must(tx.Bucket([]byte("widgets"))) + b := g.Must(tx.RWBucket([]byte("widgets"))) err = b.Put([]byte("john"), []byte("blue")) if err != nil { log.Fatal(err) @@ -4378,7 +4283,7 @@ func ExampleDB_Begin_ReadOnly() { if err != nil { log.Fatal(err) } - c := g.Must(tx.Bucket([]byte("widgets"))).Cursor() + c := g.Must(tx.ROBucket([]byte("widgets"))).Cursor() for k, v := c.First(); k != nil; k, v = c.Next() { fmt.Printf("%s likes %s\n", k, v) } @@ -4430,7 +4335,7 @@ func BenchmarkDBBatchAutomatic(b *testing.B) { _, _ = h.Write(buf[:]) k := h.Sum(nil) insert := func(tx TransactionI) error { - b := g.Must(tx.Bucket([]byte("bench"))) + b := g.Must(tx.RWBucket([]byte("bench"))) return b.Put(k, []byte("filler")) } @@ -4479,7 +4384,7 @@ func BenchmarkDBBatchSingle(b *testing.B) { _, _ = h.Write(buf[:]) k := h.Sum(nil) insert := func(tx TransactionI) error { - b := g.Must(tx.Bucket([]byte("bench"))) + b := g.Must(tx.RWBucket([]byte("bench"))) return b.Put(k, []byte("filler")) } @@ -4534,7 +4439,7 @@ func BenchmarkDBBatchManual10x100(b *testing.B) { h.Reset() _, _ = h.Write(buf[:]) k := h.Sum(nil) - b := g.Must(tx.Bucket([]byte("bench"))) + b := g.Must(tx.RWBucket([]byte("bench"))) err := b.Put( k, []byte("filler"), @@ -4563,7 +4468,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 := g.Must(tx.Bucket([]byte("bench"))) + bucket := g.Must(tx.RWBucket([]byte("bench"))) h := fnv.New32a() buf := make([]byte, 4) for id := uint32(0); id < 1000; id++ { @@ -5596,7 +5501,7 @@ func simulateGetHandler(tx *transactionT, qdb *QuickDB) { } // Retrieve root bucket. - b, err := tx.Bucket(keys[0]) + b, err := tx.ROBucket(keys[0]) if err != nil { panic(fmt.Sprintf( "bucket[0] expected: %08x\n", @@ -5606,7 +5511,7 @@ func simulateGetHandler(tx *transactionT, qdb *QuickDB) { // Drill into nested buckets. for _, key := range keys[1 : len(keys)-1] { - b, err = b.Bucket(key) + b, err = b.ROBucket(key) if err != nil { panic(fmt.Sprintf( "bucket[n] expected: %v -> %v\n", @@ -5635,7 +5540,7 @@ func simulatePutHandler(tx *transactionT, qdb *QuickDB) { keys, value := randKeys(), randValue() // Retrieve root bucket. - b, err := tx.Bucket(keys[0]) + b, err := tx.RWBucket(keys[0]) if err == ErrBucketNotFound { b, err = tx.CreateBucket(keys[0]) if err != nil { @@ -5648,7 +5553,7 @@ func simulatePutHandler(tx *transactionT, qdb *QuickDB) { // Create nested buckets, if necessary. for _, key := range keys[1 : len(keys)-1] { - child, err := b.Bucket(key) + child, err := b.RWBucket(key) if err == ErrBucketNotFound { b, err = b.CreateBucket(key) if err != nil { @@ -5986,7 +5891,7 @@ func TestTx_Bucket(t *testing.T) { t.Fatal(err) } - _, err = tx.Bucket([]byte("widgets")) + _, err = tx.RWBucket([]byte("widgets")) if err != nil { t.Fatal("expected bucket") } @@ -6049,7 +5954,7 @@ func TestTx_CreateBucket(t *testing.T) { // Read the bucket through a separate transaction. err = db.View(func(snapshot SnapshotI) error { - _, err := snapshot.Bucket([]byte("widgets")) + _, err := snapshot.ROBucket([]byte("widgets")) if err != nil { t.Fatal("expected bucket") } @@ -6092,7 +5997,7 @@ func TestTx_CreateBucketIfNotExists(t *testing.T) { // Read the bucket through a separate transaction. err = db.View(func(snapshot SnapshotI) error { - _, err := snapshot.Bucket([]byte("widgets")) + _, err := snapshot.ROBucket([]byte("widgets")) if err != nil { t.Fatal("expected bucket") } @@ -6211,7 +6116,7 @@ func TestTx_DeleteBucket(t *testing.T) { t.Fatal(err) } - _, err = tx.Bucket([]byte("widgets")) + _, err = tx.RWBucket([]byte("widgets")) if err != ErrBucketNotFound { t.Fatal("unexpected bucket") } @@ -6321,7 +6226,7 @@ func TestTx_ForEach_NoError(t *testing.T) { t.Fatal(err) } - err = tx.ForEach(func(name []byte, b BucketI) error { + err = tx.RWForEach(func(name []byte, b RWBucketI) error { return nil }) if err != nil { @@ -6353,7 +6258,7 @@ func TestTx_ForEach_WithError(t *testing.T) { } marker := errors.New("marker") - err = tx.ForEach(func(name []byte, b BucketI) error { + err = tx.RWForEach(func(name []byte, b RWBucketI) error { return marker }) if err != marker { @@ -6531,7 +6436,7 @@ func ExampleTx_Rollback() { // Set a value for a key. err = db.Update(func(tx TransactionI) error { - return g.Must(tx.Bucket([]byte("widgets"))).Put( + return g.Must(tx.RWBucket([]byte("widgets"))).Put( []byte("foo"), []byte("bar"), ) @@ -6546,7 +6451,7 @@ func ExampleTx_Rollback() { log.Fatal(err) } - b := g.Must(tx.Bucket([]byte("widgets"))) + b := g.Must(tx.RWBucket([]byte("widgets"))) err = b.Put([]byte("foo"), []byte("baz")) if err != nil { log.Fatal(err) @@ -6559,7 +6464,7 @@ func ExampleTx_Rollback() { // Ensure that our original value is still set. err = db.View(func(snapshot SnapshotI) error { - value := g.Must(tx.Bucket([]byte("widgets"))).Get([]byte("foo")) + value := g.Must(tx.RWBucket([]byte("widgets"))).Get([]byte("foo")) fmt.Printf("The value for 'foo' is still: %s\n", value) return nil }) @@ -6687,13 +6592,11 @@ func MainTest() { { "TestDB_Put_VeryLarge", TestDB_Put_VeryLarge }, { "TestBucket_Put_IncompatibleValue", TestBucket_Put_IncompatibleValue }, { "TestBucket_Put_Closed", TestBucket_Put_Closed }, - { "TestBucket_Put_ReadOnly", TestBucket_Put_ReadOnly }, { "TestBucket_Delete", TestBucket_Delete }, { "TestBucket_Delete_Large", TestBucket_Delete_Large }, { "TestBucket_Delete_FreelistOverflow", TestBucket_Delete_FreelistOverflow }, { "TestBucket_Nested", TestBucket_Nested }, { "TestBucket_Delete_Bucket", TestBucket_Delete_Bucket }, - { "TestBucket_Delete_ReadOnly", TestBucket_Delete_ReadOnly }, { "TestBucket_Delete_Closed", TestBucket_Delete_Closed }, { "TestBucket_DeleteBucket_Nested", TestBucket_DeleteBucket_Nested }, { "TestBucket_DeleteBucket_Nested2", TestBucket_DeleteBucket_Nested2 }, @@ -6703,7 +6606,6 @@ func MainTest() { { "TestBucket_DeleteBucket_IncompatibleValue", TestBucket_DeleteBucket_IncompatibleValue }, { "TestBucket_NextSequence", TestBucket_NextSequence }, { "TestBucket_NextSequence_Persist", TestBucket_NextSequence_Persist }, - { "TestBucket_NextSequence_ReadOnly", TestBucket_NextSequence_ReadOnly }, { "TestBucket_NextSequence_Closed", TestBucket_NextSequence_Closed }, { "TestBucket_ForEach", TestBucket_ForEach }, { "TestBucket_ForEach_ShortCircuit", TestBucket_ForEach_ShortCircuit }, |