From a395cb9b3fef3b20b2c2f00aef94e155a44599b2 Mon Sep 17 00:00:00 2001 From: Elle Mouton Date: Tue, 11 Mar 2025 15:37:42 -0500 Subject: [PATCH] firewaldb: single implementation of BBolt DBExecutor The `kvStores` and `privacyMapDB` types have very similar looking `Update` and `View` methods. Instead of the duplication, here we let things be more generic by defining a generic `kvdbExecutor` which has Update and View methods defined. --- firewalldb/kvdb_store.go | 44 +++++++++++++++++++++++++++ firewalldb/kvstores.go | 58 ++++++++---------------------------- firewalldb/privacy_mapper.go | 54 +++++++-------------------------- 3 files changed, 66 insertions(+), 90 deletions(-) create mode 100644 firewalldb/kvdb_store.go diff --git a/firewalldb/kvdb_store.go b/firewalldb/kvdb_store.go new file mode 100644 index 00000000..d4ce79f2 --- /dev/null +++ b/firewalldb/kvdb_store.go @@ -0,0 +1,44 @@ +package firewalldb + +import ( + "context" + + "go.etcd.io/bbolt" +) + +// kvdbExecutor is a concrete implementation of the DBExecutor interface that +// uses a bbolt database as its backing store. +type kvdbExecutor[T any] struct { + db *bbolt.DB + wrapTx func(tx *bbolt.Tx) T +} + +// Update opens a database read/write transaction and executes the function f +// with the transaction passed as a parameter. After f exits, if f did not +// error, the transaction is committed. Otherwise, if f did error, the +// transaction is rolled back. If the rollback fails, the original error +// returned by f is still returned. If the commit fails, the commit error is +// returned. +// +// NOTE: this is part of the DBExecutor interface. +func (e *kvdbExecutor[T]) Update(ctx context.Context, + fn func(ctx context.Context, tx T) error) error { + + return e.db.Update(func(tx *bbolt.Tx) error { + return fn(ctx, e.wrapTx(tx)) + }) +} + +// View opens a database read transaction and executes the function f with the +// transaction passed as a parameter. After f exits, the transaction is rolled +// back. If f errors, its error is returned, not a rollback error (if any +// occur). +// +// NOTE: this is part of the DBExecutor interface. +func (e *kvdbExecutor[T]) View(ctx context.Context, + fn func(ctx context.Context, tx T) error) error { + + return e.db.View(func(tx *bbolt.Tx) error { + return fn(ctx, e.wrapTx(tx)) + }) +} diff --git a/firewalldb/kvstores.go b/firewalldb/kvstores.go index 1dffd54c..9dad0a0c 100644 --- a/firewalldb/kvstores.go +++ b/firewalldb/kvstores.go @@ -107,62 +107,28 @@ type RulesDB interface { func (db *DB) GetKVStores(rule string, groupID session.ID, feature string) KVStores { - return &kvStores{ - db: db.DB, - ruleName: rule, - groupID: groupID, - featureName: feature, + return &kvdbExecutor[KVStoreTx]{ + db: db.DB, + wrapTx: func(tx *bbolt.Tx) KVStoreTx { + return &kvStoreTx{ + boltTx: tx, + kvStores: &kvStores{ + ruleName: rule, + groupID: groupID, + featureName: feature, + }, + } + }, } } // kvStores implements the rules.KVStores interface. type kvStores struct { - db *bbolt.DB ruleName string groupID session.ID featureName string } -// Update opens a database read/write transaction and executes the function f -// with the transaction passed as a parameter. After f exits, if f did not -// error, the transaction is committed. Otherwise, if f did error, the -// transaction is rolled back. If the rollback fails, the original error -// returned by f is still returned. If the commit fails, the commit error is -// returned. -// -// NOTE: this is part of the KVStores interface. -func (s *kvStores) Update(ctx context.Context, fn func(ctx context.Context, - tx KVStoreTx) error) error { - - return s.db.Update(func(tx *bbolt.Tx) error { - boltTx := &kvStoreTx{ - boltTx: tx, - kvStores: s, - } - - return fn(ctx, boltTx) - }) -} - -// View opens a database read transaction and executes the function f with the -// transaction passed as a parameter. After f exits, the transaction is rolled -// back. If f errors, its error is returned, not a rollback error (if any -// occur). -// -// NOTE: this is part of the KVStores interface. -func (s *kvStores) View(ctx context.Context, fn func(ctx context.Context, - tx KVStoreTx) error) error { - - return s.db.View(func(tx *bbolt.Tx) error { - boltTx := &kvStoreTx{ - boltTx: tx, - kvStores: s, - } - - return fn(ctx, boltTx) - }) -} - // getBucketFunc defines the signature of the bucket creation/fetching function // required by kvStoreTx. If create is true, then all the bucket (and all // buckets leading up to the bucket) should be created if they do not already diff --git a/firewalldb/privacy_mapper.go b/firewalldb/privacy_mapper.go index 2db18594..ab8e60e4 100644 --- a/firewalldb/privacy_mapper.go +++ b/firewalldb/privacy_mapper.go @@ -42,9 +42,16 @@ type NewPrivacyMapDB func(groupID session.ID) PrivacyMapDB // PrivacyDB constructs a PrivacyMapDB that will be indexed under the given // group ID key. func (db *DB) PrivacyDB(groupID session.ID) PrivacyMapDB { - return &privacyMapDB{ - db: db, - groupID: groupID, + return &kvdbExecutor[PrivacyMapTx]{ + db: db.DB, + wrapTx: func(tx *bbolt.Tx) PrivacyMapTx { + return &privacyMapTx{ + boltTx: tx, + privacyMapDB: &privacyMapDB{ + groupID: groupID, + }, + } + }, } } @@ -74,50 +81,9 @@ type PrivacyMapTx interface { // privacyMapDB is an implementation of PrivacyMapDB. type privacyMapDB struct { - db *DB groupID session.ID } -// Update opens a database read/write transaction and executes the function f -// with the transaction passed as a parameter. After f exits, if f did not -// error, the transaction is committed. Otherwise, if f did error, the -// transaction is rolled back. If the rollback fails, the original error -// returned by f is still returned. If the commit fails, the commit error is -// returned. -// -// NOTE: this is part of the PrivacyMapDB interface. -func (p *privacyMapDB) Update(ctx context.Context, fn func(ctx context.Context, - tx PrivacyMapTx) error) error { - - return p.db.Update(func(tx *bbolt.Tx) error { - boltTx := &privacyMapTx{ - privacyMapDB: p, - boltTx: tx, - } - - return fn(ctx, boltTx) - }) -} - -// View opens a database read transaction and executes the function f with the -// transaction passed as a parameter. After f exits, the transaction is rolled -// back. If f errors, its error is returned, not a rollback error (if any -// occur). -// -// NOTE: this is part of the PrivacyMapDB interface. -func (p *privacyMapDB) View(ctx context.Context, fn func(ctx context.Context, - tx PrivacyMapTx) error) error { - - return p.db.View(func(tx *bbolt.Tx) error { - boltTx := &privacyMapTx{ - privacyMapDB: p, - boltTx: tx, - } - - return fn(ctx, boltTx) - }) -} - // privacyMapTx is an implementation of PrivacyMapTx. type privacyMapTx struct { *privacyMapDB