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.
This commit is contained in:
Olaoluwa Osuntokun 2020-01-15 04:51:15 -08:00 committed by Conner Fromknecht
parent eb2582bbde
commit 0bcbb4cc4a
No known key found for this signature in database
GPG key ID: E7D737B67FA592C7
4 changed files with 84 additions and 9 deletions

View file

@ -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.
//

View file

@ -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

View file

@ -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

View file

@ -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