walletdb: add ForEachBucket to the ReadTx with bbolt implementation

This commit extends the ReadTx (and ReadWriteTx) interface with
ForEachBucket which can be used to iterate through all top level
buckets. This is a missing piece from the walletdb abstraction which
will allow us to iterate all keys in a walletdb opening the possibility
to build generic tools to browse and edit walletdb files regardless of
the underlying driver.
This commit is contained in:
Andras Banki-Horvath 2021-04-27 11:14:43 +02:00
parent 50978fcf79
commit c6f007b74a
No known key found for this signature in database
GPG key ID: 80E5375C094198D8
3 changed files with 37 additions and 0 deletions

View file

@ -60,6 +60,15 @@ func (tx *transaction) ReadBucket(key []byte) walletdb.ReadBucket {
return tx.ReadWriteBucket(key)
}
// ForEachBucket will iterate through all top level buckets.
func (tx *transaction) ForEachBucket(fn func(key []byte) error) error {
return convertErr(tx.boltTx.ForEach(
func(name []byte, _ *bbolt.Bucket) error {
return fn(name)
},
))
}
func (tx *transaction) ReadWriteBucket(key []byte) walletdb.ReadWriteBucket {
boltBucket := tx.boltTx.Bucket(key)
if boltBucket == nil {

View file

@ -19,6 +19,9 @@ type ReadTx interface {
// described by the key does not exist, nil is returned.
ReadBucket(key []byte) ReadBucket
// ForEachBucket will iterate through all top level buckets.
ForEachBucket(func(key []byte) error) error
// Rollback closes the transaction, discarding changes (if any) if the
// database was modified by a write transaction.
Rollback() error

View file

@ -540,6 +540,31 @@ func testNamespaceAndTxInterfaces(tc *testContext, namespaceKey string) bool {
return false
}
// Test that we can read the top level buckets.
var topLevelBuckets []string
walletdb.View(tc.db, func(tx walletdb.ReadTx) error {
return tx.ForEachBucket(func(key []byte) error {
topLevelBuckets = append(topLevelBuckets, string(key))
return nil
})
})
if err != nil {
if err != errSubTestFail {
tc.t.Errorf("%v", err)
}
return false
}
if len(topLevelBuckets) != 1 {
tc.t.Errorf("ForEachBucket: expected only one top level bucket")
return false
}
if topLevelBuckets[0] != namespaceKey {
tc.t.Errorf("ForEachBucket: expected %v, got %v", namespaceKey,
topLevelBuckets[0])
return false
}
// Test the bucket interface via a managed read-write transaction.
// Also, put a series of values and force a rollback so the following
// code can ensure the values were not stored.