From 0bcbb4cc4a2320782fb122f50dc98e38535ad081 Mon Sep 17 00:00:00 2001 From: Olaoluwa Osuntokun Date: Wed, 15 Jan 2020 04:51:15 -0800 Subject: [PATCH] walletdb: add sequence methods to main interface, update bdb to implement In this commit, we add the trio of sequence based methods that bbolt ships with to the main bucket interface. We do this in order to easily allow walletdb as is to be slotted into place where bbolt is currently used, without sacrificing any functionality. --- walletdb/bdb/db.go | 17 +++++++++- walletdb/bdb/driver_test.go | 14 ++++---- walletdb/interface.go | 10 ++++++ walletdb/walletdbtest/interface.go | 52 +++++++++++++++++++++++++++++- 4 files changed, 84 insertions(+), 9 deletions(-) diff --git a/walletdb/bdb/db.go b/walletdb/bdb/db.go index 046c6ac..9d700bf 100644 --- a/walletdb/bdb/db.go +++ b/walletdb/bdb/db.go @@ -68,7 +68,7 @@ func (tx *transaction) ReadWriteBucket(key []byte) walletdb.ReadWriteBucket { } func (tx *transaction) CreateTopLevelBucket(key []byte) (walletdb.ReadWriteBucket, error) { - boltBucket, err := tx.boltTx.CreateBucket(key) + boltBucket, err := tx.boltTx.CreateBucketIfNotExists(key) if err != nil { return nil, convertErr(err) } @@ -231,6 +231,21 @@ func (b *bucket) Tx() walletdb.ReadWriteTx { } } +// NextSequence returns an autoincrementing integer for the bucket. +func (b *bucket) NextSequence() (uint64, error) { + return (*bbolt.Bucket)(b).NextSequence() +} + +// SetSequence updates the sequence number for the bucket. +func (b *bucket) SetSequence(v uint64) error { + return (*bbolt.Bucket)(b).SetSequence(v) +} + +// Sequence returns the current integer for the bucket without incrementing it. +func (b *bucket) Sequence() uint64 { + return (*bbolt.Bucket)(b).Sequence() +} + // cursor represents a cursor over key/value pairs and nested buckets of a // bucket. // diff --git a/walletdb/bdb/driver_test.go b/walletdb/bdb/driver_test.go index c233abe..8fdcab1 100644 --- a/walletdb/bdb/driver_test.go +++ b/walletdb/bdb/driver_test.go @@ -23,7 +23,7 @@ func TestCreateOpenFail(t *testing.T) { // Ensure that attempting to open a database that doesn't exist returns // the expected error. wantErr := walletdb.ErrDbDoesNotExist - if _, err := walletdb.Open(dbType, "noexist.db"); err != wantErr { + if _, err := walletdb.Open(dbType, "noexist.db", true); err != wantErr { t.Errorf("Open: did not receive expected error - got %v, "+ "want %v", err, wantErr) return @@ -32,7 +32,7 @@ func TestCreateOpenFail(t *testing.T) { // Ensure that attempting to open a database with the wrong number of // parameters returns the expected error. wantErr = fmt.Errorf("invalid arguments to %s.Open -- expected "+ - "database path", dbType) + "database path and no-freelist-sync option", dbType) if _, err := walletdb.Open(dbType, 1, 2, 3); err.Error() != wantErr.Error() { t.Errorf("Open: did not receive expected error - got %v, "+ "want %v", err, wantErr) @@ -43,7 +43,7 @@ func TestCreateOpenFail(t *testing.T) { // the first parameter returns the expected error. wantErr = fmt.Errorf("first argument to %s.Open is invalid -- "+ "expected database path string", dbType) - if _, err := walletdb.Open(dbType, 1); err.Error() != wantErr.Error() { + if _, err := walletdb.Open(dbType, 1, true); err.Error() != wantErr.Error() { t.Errorf("Open: did not receive expected error - got %v, "+ "want %v", err, wantErr) return @@ -52,7 +52,7 @@ func TestCreateOpenFail(t *testing.T) { // Ensure that attempting to create a database with the wrong number of // parameters returns the expected error. wantErr = fmt.Errorf("invalid arguments to %s.Create -- expected "+ - "database path", dbType) + "database path and no-freelist-sync option", dbType) if _, err := walletdb.Create(dbType, 1, 2, 3); err.Error() != wantErr.Error() { t.Errorf("Create: did not receive expected error - got %v, "+ "want %v", err, wantErr) @@ -63,7 +63,7 @@ func TestCreateOpenFail(t *testing.T) { // the first parameter returns the expected error. wantErr = fmt.Errorf("first argument to %s.Create is invalid -- "+ "expected database path string", dbType) - if _, err := walletdb.Create(dbType, 1); err.Error() != wantErr.Error() { + if _, err := walletdb.Create(dbType, 1, true); err.Error() != wantErr.Error() { t.Errorf("Create: did not receive expected error - got %v, "+ "want %v", err, wantErr) return @@ -72,7 +72,7 @@ func TestCreateOpenFail(t *testing.T) { // Ensure operations against a closed database return the expected // error. dbPath := "createfail.db" - db, err := walletdb.Create(dbType, dbPath) + db, err := walletdb.Create(dbType, dbPath, true) if err != nil { t.Errorf("Create: unexpected error: %v", err) return @@ -93,7 +93,7 @@ func TestCreateOpenFail(t *testing.T) { func TestPersistence(t *testing.T) { // Create a new database to run tests against. dbPath := "persistencetest.db" - db, err := walletdb.Create(dbType, dbPath) + db, err := walletdb.Create(dbType, dbPath, true) if err != nil { t.Errorf("Failed to create test database (%s) %v", dbType, err) return diff --git a/walletdb/interface.go b/walletdb/interface.go index f89fa91..f120e71 100644 --- a/walletdb/interface.go +++ b/walletdb/interface.go @@ -126,6 +126,16 @@ type ReadWriteBucket interface { // Tx returns the bucket's transaction. Tx() ReadWriteTx + + // NextSequence returns an autoincrementing integer for the bucket. + NextSequence() (uint64, error) + + // SetSequence updates the sequence number for the bucket. + SetSequence(v uint64) error + + // Sequence returns the current integer for the bucket without + // incrementing it. + Sequence() uint64 } // ReadCursor represents a bucket cursor that can be positioned at the start or diff --git a/walletdb/walletdbtest/interface.go b/walletdb/walletdbtest/interface.go index 8a2beb1..663a0fa 100644 --- a/walletdb/walletdbtest/interface.go +++ b/walletdb/walletdbtest/interface.go @@ -104,6 +104,51 @@ func testNestedReadWriteBucket(tc *testContext, testBucket walletdb.ReadWriteBuc return true } +// testSequence tests that the sequence related methods work as expected. +func testSequence(tc *testContext, testBucket walletdb.ReadWriteBucket) bool { + // Obtaining the current sequence twice should give us the same value. + seqNo1 := testBucket.Sequence() + seqNo2 := testBucket.Sequence() + if seqNo1 != seqNo2 { + tc.t.Errorf("Sequence: seq has incremented") + return false + } + + // Incrementing to the next sequence should give us a value one larger + // than the prior number. + seqNo3, err := testBucket.NextSequence() + if err != nil { + tc.t.Errorf("Sequence: unexpected error: %v", err) + return false + } + if seqNo3 != seqNo2+1 { + tc.t.Errorf("Sequence: expected seq no of %v, instead got %v", + seqNo2+1, seqNo3) + return false + } + + // We should be able to modify the sequence base number. + newBase := uint64(100) + if err := testBucket.SetSequence(newBase); err != nil { + tc.t.Errorf("Sequence: unexpected error: %v", err) + return false + } + + // Any offset from this new sequence should now be properly reflected. + seqNo4, err := testBucket.NextSequence() + if err != nil { + tc.t.Errorf("Sequence: unexpected error: %v", err) + return false + } + if seqNo4 != newBase+1 { + tc.t.Errorf("Sequence: expected seq no of %v, instead got %v", + newBase+1, seqNo4) + return false + } + + return false +} + // testReadWriteBucketInterface ensures the bucket interface is working properly by // exercising all of its functions. func testReadWriteBucketInterface(tc *testContext, bucket walletdb.ReadWriteBucket) bool { @@ -164,6 +209,11 @@ func testReadWriteBucketInterface(tc *testContext, bucket walletdb.ReadWriteBuck return false } + // Test that the sequence methods work as expected. + if !testSequence(tc, bucket) { + return false + } + // Ensure creating a new bucket works as expected. testBucketName := []byte("testbucket") testBucket, err := bucket.CreateBucket(testBucketName) @@ -678,7 +728,7 @@ func testAdditionalErrors(tc *testContext) bool { // TestInterface performs all interfaces tests for this database driver. func TestInterface(t Tester, dbType, dbPath string) { - db, err := walletdb.Create(dbType, dbPath) + db, err := walletdb.Create(dbType, dbPath, true) if err != nil { t.Errorf("Failed to create test database (%s) %v", dbType, err) return