aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEuAndreh <eu@euandre.org>2025-02-07 07:26:16 -0300
committerEuAndreh <eu@euandre.org>2025-02-07 07:26:22 -0300
commit7b3b038f70e165711b77ce4513480892fca3b4f7 (patch)
treee5220d5f22963a56b95008732163e9b6673979f3
parentsrc/dedo.go: Introduce inMemoryTx (diff)
downloaddedo-7b3b038f70e165711b77ce4513480892fca3b4f7.tar.gz
dedo-7b3b038f70e165711b77ce4513480892fca3b4f7.tar.xz
src/dedo.go: Introduce SnapshotI type
-rw-r--r--src/dedo.go27
-rw-r--r--tests/dedo.go150
2 files changed, 96 insertions, 81 deletions
diff --git a/src/dedo.go b/src/dedo.go
index 9f64693..c0aecaf 100644
--- a/src/dedo.go
+++ b/src/dedo.go
@@ -127,13 +127,20 @@ type ITx interface{
OnCommit(func())
WriteTo(io.Writer) (int64, error)
+}
+
+type SnapshotI interface{
+ Bucket([]byte) *Bucket
+
+ WriteTo(io.Writer) (int64, error)
+ ForEach(func([]byte, *Bucket) error) error
Check() <-chan error
}
type IDedo interface{
Close() error
- View (func(tx ITx) error) error
+ View (func(tx SnapshotI) error) error
Update(func(tx ITx) error) error
Path() string
}
@@ -1743,7 +1750,7 @@ func (m *InMemory) Update(fn func(ITx) error) error {
return err
}
-func (m *InMemory) View(func(ITx) error) error {
+func (m *InMemory) View(func(SnapshotI) error) error {
return nil
}
@@ -2109,7 +2116,7 @@ func (db *DB) Update(fn func(ITx) error) error {
/// the DB.View() method.
///
/// Attempting to manually rollback within the function will cause a panic.
-func (db *DB) View(fn func(ITx) error) error {
+func (db *DB) View(fn func(SnapshotI) error) error {
t, err := db.begin(false)
if err != nil {
return err
@@ -3967,9 +3974,9 @@ func setGetopt(args argsT, w io.Writer) (argsT, bool) {
}
func checkExec(args argsT, db IDedo, _r io.Reader, _w io.Writer) error {
- return db.View(func(tx ITx) error {
+ return db.View(func(snapshot SnapshotI) error {
var errs error
- for err := range tx.Check() {
+ for err := range snapshot.Check() {
errs = g.WrapErrors(errs, err)
}
return errs
@@ -3977,8 +3984,8 @@ func checkExec(args argsT, db IDedo, _r io.Reader, _w io.Writer) error {
}
func getExec(args argsT, db IDedo, r io.Reader, w io.Writer) error {
- return db.View(func(tx ITx) error {
- bucket := tx.Bucket(args.bucket)
+ return db.View(func(snapshot SnapshotI) error {
+ bucket := snapshot.Bucket(args.bucket)
if bucket == nil {
return ErrBucketNotFound
}
@@ -4016,9 +4023,9 @@ func rmExec(args argsT, db IDedo, r io.Reader, w io.Writer) error {
}
func listExec(args argsT, db IDedo, r io.Reader, w io.Writer) error {
- return db.View(func(tx ITx) error {
+ return db.View(func(snapshot SnapshotI) error {
if len(args.bucket) == 0 {
- return tx.ForEach(func(
+ return snapshot.ForEach(func(
name []byte,
bucket *Bucket,
) error {
@@ -4027,7 +4034,7 @@ func listExec(args argsT, db IDedo, r io.Reader, w io.Writer) error {
})
}
- bucket := tx.Bucket(args.bucket)
+ bucket := snapshot.Bucket(args.bucket)
if bucket == nil {
return ErrBucketNotFound
}
diff --git a/tests/dedo.go b/tests/dedo.go
index 7dba449..b5ed229 100644
--- a/tests/dedo.go
+++ b/tests/dedo.go
@@ -753,8 +753,8 @@ func TestBucket_Put_Large(t *testing.T) {
t.Fatal(err)
}
- err = db.View(func(tx ITx) error {
- b := tx.Bucket([]byte("widgets"))
+ err = db.View(func(snapshot SnapshotI) error {
+ b := snapshot.Bucket([]byte("widgets"))
for i := 1; i < count; i++ {
value := b.Get([]byte(strings.Repeat("0", i*factor)))
expected := []byte(strings.Repeat(
@@ -884,8 +884,8 @@ func TestBucket_Put_ReadOnly(t *testing.T) {
t.Fatal(err)
}
- err = db.View(func(tx ITx) error {
- b := tx.Bucket([]byte("widgets"))
+ err = db.View(func(snapshot SnapshotI) error {
+ b := snapshot.Bucket([]byte("widgets"))
err := b.Put([]byte("foo"), []byte("bar"))
if err != ErrTxNotWritable {
t.Fatalf("unexpected error: %s", err)
@@ -974,8 +974,8 @@ func TestBucket_Delete_Large(t *testing.T) {
t.Fatal(err)
}
- err = db.View(func(tx ITx) error {
- b := tx.Bucket([]byte("widgets"))
+ err = db.View(func(snapshot SnapshotI) error {
+ b := snapshot.Bucket([]byte("widgets"))
for i := 0; i < 100; i++ {
v := b.Get([]byte(strconv.Itoa(i)))
if v != nil {
@@ -1128,8 +1128,8 @@ func TestBucket_Nested(t *testing.T) {
db.MustCheck()
// Verify.
- err = db.View(func(tx ITx) error {
- b := tx.Bucket([]byte("widgets"))
+ err = db.View(func(snapshot SnapshotI) error {
+ b := snapshot.Bucket([]byte("widgets"))
v := b.Bucket([]byte("foo")).Get([]byte("baz"))
if !bytes.Equal(v, []byte("yyyy")) {
t.Fatalf("unexpected value: %v", v)
@@ -1201,8 +1201,8 @@ func TestBucket_Delete_ReadOnly(t *testing.T) {
t.Fatal(err)
}
- err = db.View(func(tx ITx) error {
- err := tx.Bucket([]byte("widgets")).Delete([]byte("foo"))
+ err = db.View(func(snapshot SnapshotI) error {
+ err := snapshot.Bucket([]byte("widgets")).Delete([]byte("foo"))
if err != ErrTxNotWritable {
t.Fatalf("unexpected error: %s", err)
}
@@ -1346,8 +1346,8 @@ func TestBucket_DeleteBucket_Nested2(t *testing.T) {
t.Fatal(err)
}
- err = db.View(func(tx ITx) error {
- if tx.Bucket([]byte("widgets")) != nil {
+ err = db.View(func(snapshot SnapshotI) error {
+ if snapshot.Bucket([]byte("widgets")) != nil {
t.Fatal("expected bucket to be deleted")
}
return nil
@@ -1604,8 +1604,8 @@ func TestBucket_NextSequence_ReadOnly(t *testing.T) {
t.Fatal(err)
}
- err = db.View(func(tx ITx) error {
- _, err := tx.Bucket([]byte("widgets")).NextSequence()
+ err = db.View(func(snapshot SnapshotI) error {
+ _, err := snapshot.Bucket([]byte("widgets")).NextSequence()
if err != ErrTxNotWritable {
t.Fatalf("unexpected error: %s", err)
}
@@ -1915,10 +1915,10 @@ func TestBucket_Put_Single(t *testing.T) {
const errmsg = "value mismatch [run %d] (%d of %d):\n" +
"key: %x\ngot: %x\nexp: %x"
// Verify all key/values so far.
- err = db.View(func(tx ITx) error {
+ err = db.View(func(snapshot SnapshotI) error {
i := 0
for k, v := range m {
- value := tx.Bucket(
+ value := snapshot.Bucket(
[]byte("widgets"),
).Get([]byte(k))
if !bytes.Equal(value, v) {
@@ -1991,8 +1991,8 @@ func TestBucket_Put_Multiple(t *testing.T) {
}
// Verify all items exist.
- err = db.View(func(tx ITx) error {
- b := tx.Bucket([]byte("widgets"))
+ err = db.View(func(snapshot SnapshotI) error {
+ b := snapshot.Bucket([]byte("widgets"))
for _, item := range items {
value := b.Get(item.Key)
if !bytes.Equal(item.Value, value) {
@@ -2070,8 +2070,8 @@ func TestBucket_Delete_Quick(t *testing.T) {
}
// Anything before our deletion index should be nil.
- err = db.View(func(tx ITx) error {
- err := tx.Bucket(
+ err = db.View(func(snapshot SnapshotI) error {
+ err := snapshot.Bucket(
[]byte("widgets"),
).ForEach(func(k, v []byte) error {
t.Fatalf(
@@ -2126,8 +2126,8 @@ func ExampleBucket_Put() {
}
// Read value back in a different read-only transaction.
- err = db.View(func(tx ITx) error {
- value := tx.Bucket([]byte("widgets")).Get([]byte("foo"))
+ err = db.View(func(snapshot SnapshotI) error {
+ value := snapshot.Bucket([]byte("widgets")).Get([]byte("foo"))
fmt.Printf("The value of 'foo' is: %s\n", value)
return nil
})
@@ -2186,8 +2186,8 @@ func ExampleBucket_Delete() {
}
// Retrieve the key again.
- err = db.View(func(tx ITx) error {
- value := tx.Bucket([]byte("widgets")).Get([]byte("foo"))
+ err = db.View(func(snapshot SnapshotI) error {
+ value := snapshot.Bucket([]byte("widgets")).Get([]byte("foo"))
if value == nil {
fmt.Printf("The value of 'foo' is now: nil\n")
}
@@ -2303,8 +2303,8 @@ func TestCursor_Seek(t *testing.T) {
t.Fatal(err)
}
- err = db.View(func(tx ITx) error {
- c := tx.Bucket([]byte("widgets")).Cursor()
+ err = db.View(func(snapshot SnapshotI) error {
+ c := snapshot.Bucket([]byte("widgets")).Cursor()
// Exact match should go to the key.
k, v := c.Seek([]byte("bar"))
@@ -2449,8 +2449,8 @@ func TestCursor_Seek_Large(t *testing.T) {
t.Fatal(err)
}
- err = db.View(func(tx ITx) error {
- c := tx.Bucket([]byte("widgets")).Cursor()
+ err = db.View(func(snapshot SnapshotI) error {
+ c := snapshot.Bucket([]byte("widgets")).Cursor()
for i := 0; i < count; i++ {
seek := make([]byte, 8)
binary.BigEndian.PutUint64(seek, uint64(i))
@@ -2501,8 +2501,8 @@ func TestCursor_EmptyBucket(t *testing.T) {
t.Fatal(err)
}
- err = db.View(func(tx ITx) error {
- c := tx.Bucket([]byte("widgets")).Cursor()
+ err = db.View(func(snapshot SnapshotI) error {
+ c := snapshot.Bucket([]byte("widgets")).Cursor()
k, v := c.First()
if k != nil {
t.Fatalf("unexpected key: %v", k)
@@ -2531,8 +2531,8 @@ func TestCursor_EmptyBucketReverse(t *testing.T) {
t.Fatal(err)
}
- err = db.View(func(tx ITx) error {
- c := tx.Bucket([]byte("widgets")).Cursor()
+ err = db.View(func(snapshot SnapshotI) error {
+ c := snapshot.Bucket([]byte("widgets")).Cursor()
k, v := c.Last()
if k != nil {
t.Fatalf("unexpected key: %v", k)
@@ -3003,9 +3003,9 @@ func TestCursor_QuickCheck_BucketsOnly(t *testing.T) {
t.Fatal(err)
}
- err = db.View(func(tx ITx) error {
+ err = db.View(func(snapshot SnapshotI) error {
names := []string{}
- c := tx.Bucket([]byte("widgets")).Cursor()
+ c := snapshot.Bucket([]byte("widgets")).Cursor()
for k, v := c.First(); k != nil; k, v = c.Next() {
names = append(names, string(k))
if v != nil {
@@ -3057,9 +3057,9 @@ func TestCursor_QuickCheck_BucketsOnly_Reverse(t *testing.T) {
t.Fatal(err)
}
- err = db.View(func(tx ITx) error {
+ err = db.View(func(snapshot SnapshotI) error {
names := []string{}
- c := tx.Bucket([]byte("widgets")).Cursor()
+ c := snapshot.Bucket([]byte("widgets")).Cursor()
for k, v := c.Last(); k != nil; k, v = c.Prev() {
names = append(names, string(k))
if v != nil {
@@ -3494,7 +3494,9 @@ func TestOpen_Check(t *testing.T) {
t.Fatal(err)
}
- err = db.View(func(tx ITx) error { return <-tx.Check() })
+ err = db.View(func(snapshot SnapshotI) error {
+ return <-snapshot.Check()
+ })
if err != nil {
t.Fatal(err)
}
@@ -3509,7 +3511,9 @@ func TestOpen_Check(t *testing.T) {
t.Fatal(err)
}
- err = db.View(func(tx ITx) error { return <-tx.Check() })
+ err = db.View(func(snapshot SnapshotI) error {
+ return <-snapshot.Check()
+ })
if err != nil {
t.Fatal(err)
}
@@ -3753,8 +3757,8 @@ func TestDB_Update(t *testing.T) {
t.Fatal(err)
}
- err = db.View(func(tx ITx) error {
- b := tx.Bucket([]byte("widgets"))
+ err = db.View(func(snapshot SnapshotI) error {
+ b := snapshot.Bucket([]byte("widgets"))
v := b.Get([]byte("foo"))
if v != nil {
t.Fatalf("expected nil value, got: %v", v)
@@ -3848,7 +3852,7 @@ func TestDB_View_Error(t *testing.T) {
defer db.MustClose()
defer os.Remove(db.Path())
- err := db.View(func(tx ITx) error {
+ err := db.View(func(snapshot SnapshotI) error {
return errors.New("xxx")
})
if err == nil || err.Error() != "xxx" {
@@ -3883,8 +3887,8 @@ func TestDB_View_Panic(t *testing.T) {
}
}()
- err := db.View(func(tx ITx) error {
- if tx.Bucket([]byte("widgets")) == nil {
+ err := db.View(func(snapshot SnapshotI) error {
+ if snapshot.Bucket([]byte("widgets")) == nil {
t.Fatal("expected bucket")
}
panic("omg")
@@ -3895,8 +3899,8 @@ func TestDB_View_Panic(t *testing.T) {
}()
// Verify that we can still use read transactions.
- err = db.View(func(tx ITx) error {
- if tx.Bucket([]byte("widgets")) == nil {
+ err = db.View(func(snapshot SnapshotI) error {
+ if snapshot.Bucket([]byte("widgets")) == nil {
t.Fatal("expected bucket")
}
return nil
@@ -4034,8 +4038,8 @@ func TestDB_Batch(t *testing.T) {
}
// Ensure data is correct.
- err = db.View(func(tx ITx) error {
- b := tx.Bucket([]byte("widgets"))
+ err = db.View(func(snapshot SnapshotI) error {
+ b := snapshot.Bucket([]byte("widgets"))
for i := 0; i < n; i++ {
v := b.Get(u64tob(uint64(i)))
if v == nil {
@@ -4139,8 +4143,8 @@ func TestDB_BatchFull(t *testing.T) {
}
// Ensure data is correct.
- err = db.View(func(tx ITx) error {
- b := tx.Bucket([]byte("widgets"))
+ err = db.View(func(snapshot SnapshotI) error {
+ b := snapshot.Bucket([]byte("widgets"))
for i := 1; i <= size; i++ {
v := b.Get(u64tob(uint64(i)))
if v == nil {
@@ -4195,8 +4199,8 @@ func TestDB_BatchTime(t *testing.T) {
}
// Ensure data is correct.
- err = db.View(func(tx ITx) error {
- b := tx.Bucket([]byte("widgets"))
+ err = db.View(func(snapshot SnapshotI) error {
+ b := 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)
@@ -4236,8 +4240,8 @@ func ExampleDB_Update() {
}
// Read the value back from a separate read-only transaction.
- err = db.View(func(tx ITx) error {
- value := tx.Bucket([]byte("widgets")).Get([]byte("foo"))
+ err = db.View(func(snapshot SnapshotI) error {
+ value := snapshot.Bucket([]byte("widgets")).Get([]byte("foo"))
fmt.Printf("The value of 'foo' is: %s\n", value)
return nil
})
@@ -4287,8 +4291,8 @@ func ExampleDB_View() {
}
// Access data from within a read-only transactional block.
- err = db.View(func(tx ITx) error {
- v := tx.Bucket([]byte("people")).Get([]byte("john"))
+ err = db.View(func(snapshot SnapshotI) error {
+ v := snapshot.Bucket([]byte("people")).Get([]byte("john"))
fmt.Printf("John's last name is %s.\n", v)
return nil
})
@@ -4671,8 +4675,8 @@ func (db *WDB) MustCheck() {
// CopyTempFile copies a database to a temporary file.
func (db *WDB) CopyTempFile() {
path := tempfile()
- err := db.View(func(itx ITx) error {
- tx := itx.(*Tx)
+ err := db.View(func(snapshot SnapshotI) error {
+ tx := snapshot.(*Tx)
return tx.copyFile(path, 0600)
})
if err != nil {
@@ -5902,14 +5906,15 @@ func TestTx_Cursor(t *testing.T) {
}
}
+/*
// Ensure that creating a bucket with a read-only transaction returns an error.
func TestTx_CreateBucket_ErrTxNotWritable(t *testing.T) {
db := MustOpenDB()
defer db.MustClose()
defer os.Remove(db.Path())
- err := db.View(func(tx ITx) error {
- _, err := tx.CreateBucket([]byte("foo"))
+ err := db.View(func(snapshot SnapshotI) error {
+ _, err := snapshot.CreateBucket([]byte("foo"))
if err != ErrTxNotWritable {
t.Fatalf("unexpected error: %s", err)
}
@@ -5920,6 +5925,7 @@ func TestTx_CreateBucket_ErrTxNotWritable(t *testing.T) {
t.Fatal(err)
}
}
+*/
// Ensure that creating a bucket on a closed transaction returns an error.
func TestTx_CreateBucket_ErrTxClosed(t *testing.T) {
@@ -6016,8 +6022,8 @@ func TestTx_CreateBucket(t *testing.T) {
}
// Read the bucket through a separate transaction.
- err = db.View(func(tx ITx) error {
- if tx.Bucket([]byte("widgets")) == nil {
+ err = db.View(func(snapshot SnapshotI) error {
+ if snapshot.Bucket([]byte("widgets")) == nil {
t.Fatal("expected bucket")
}
@@ -6058,8 +6064,8 @@ func TestTx_CreateBucketIfNotExists(t *testing.T) {
}
// Read the bucket through a separate transaction.
- err = db.View(func(tx ITx) error {
- if tx.Bucket([]byte("widgets")) == nil {
+ err = db.View(func(snapshot SnapshotI) error {
+ if snapshot.Bucket([]byte("widgets")) == nil {
t.Fatal("expected bucket")
}
@@ -6229,13 +6235,14 @@ func TestTx_DeleteBucket_ErrTxClosed(t *testing.T) {
}
}
+/*
// Ensure that deleting a bucket with a read-only transaction returns an error.
func TestTx_DeleteBucket_ReadOnly(t *testing.T) {
db := MustOpenDB()
defer db.MustClose()
defer os.Remove(db.Path())
- err := db.View(func(tx ITx) error {
+ err := db.View(func(snapshot SnapshotI) error {
err := tx.DeleteBucket([]byte("foo"))
if err != ErrTxNotWritable {
t.Fatalf("unexpected error: %s", err)
@@ -6247,6 +6254,7 @@ func TestTx_DeleteBucket_ReadOnly(t *testing.T) {
t.Fatal(err)
}
}
+*/
// Ensure that nothing happens when deleting a bucket that doesn't exist.
func TestTx_DeleteBucket_NotFound(t *testing.T) {
@@ -6429,8 +6437,8 @@ func TestTx_WriteTo_Error_Meta(t *testing.T) {
}
const expectedMsg = "meta 0 copy: error injected for tests"
- err = db.View(func(tx ITx) error {
- _, err := tx.WriteTo(&failWriter{})
+ err = db.View(func(snapshot SnapshotI) error {
+ _, err := snapshot.WriteTo(&failWriter{})
return err
})
if err == nil || err.Error() != expectedMsg {
@@ -6466,8 +6474,8 @@ func TestTx_WriteTo_Error_Normal(t *testing.T) {
t.Fatal(err)
}
- err = db.View(func(tx ITx) error {
- _, err := tx.WriteTo(&failWriter{3 * db.pageSize})
+ err = db.View(func(snapshot SnapshotI) error {
+ _, err := snapshot.WriteTo(&failWriter{3 * db.pageSize})
return err
})
if err == nil || err.Error() != "error injected for tests" {
@@ -6522,7 +6530,7 @@ func ExampleTx_Rollback() {
}
// Ensure that our original value is still set.
- err = db.View(func(tx ITx) error {
+ err = db.View(func(snapshot SnapshotI) error {
value := tx.Bucket([]byte("widgets")).Get([]byte("foo"))
fmt.Printf("The value for 'foo' is still: %s\n", value)
return nil
@@ -6750,7 +6758,7 @@ func MainTest() {
{ "TestTx_Rollback_ErrTxClosed", TestTx_Rollback_ErrTxClosed },
{ "TestTx_Commit_ErrTxNotWritable", TestTx_Commit_ErrTxNotWritable },
{ "TestTx_Cursor", TestTx_Cursor },
- { "TestTx_CreateBucket_ErrTxNotWritable", TestTx_CreateBucket_ErrTxNotWritable },
+ // { "TestTx_CreateBucket_ErrTxNotWritable", TestTx_CreateBucket_ErrTxNotWritable },
{ "TestTx_CreateBucket_ErrTxClosed", TestTx_CreateBucket_ErrTxClosed },
{ "TestTx_Bucket", TestTx_Bucket },
{ "TestTx_Get_NotFound", TestTx_Get_NotFound },
@@ -6761,7 +6769,7 @@ func MainTest() {
{ "TestTx_CreateBucket_ErrBucketNameRequired", TestTx_CreateBucket_ErrBucketNameRequired },
{ "TestTx_DeleteBucket", TestTx_DeleteBucket },
{ "TestTx_DeleteBucket_ErrTxClosed", TestTx_DeleteBucket_ErrTxClosed },
- { "TestTx_DeleteBucket_ReadOnly", TestTx_DeleteBucket_ReadOnly },
+ // { "TestTx_DeleteBucket_ReadOnly", TestTx_DeleteBucket_ReadOnly },
{ "TestTx_DeleteBucket_NotFound", TestTx_DeleteBucket_NotFound },
{ "TestTx_ForEach_NoError", TestTx_ForEach_NoError },
{ "TestTx_ForEach_WithError", TestTx_ForEach_WithError },