Skip to content

Commit e4cf3f5

Browse files
committed
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.
1 parent 41f4a71 commit e4cf3f5

File tree

3 files changed

+79
-82
lines changed

3 files changed

+79
-82
lines changed

firewalldb/kvdb_store.go

+50
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
package firewalldb
2+
3+
import (
4+
"context"
5+
6+
"go.etcd.io/bbolt"
7+
)
8+
9+
// kvdbExecutor is a concrete implementation of the DBExecutor interface that
10+
// uses a bbolt database as its backing store.
11+
type kvdbExecutor[T any] struct {
12+
db *bbolt.DB
13+
wrapper txWrapper[T]
14+
}
15+
16+
// txWrapper is an interface that wraps a bbolt transaction.
17+
type txWrapper[T any] interface {
18+
// wrap wraps a bbolt transaction with extra functionality.
19+
wrap(tx *bbolt.Tx) T
20+
}
21+
22+
// Update opens a database read/write transaction and executes the function f
23+
// with the transaction passed as a parameter. After f exits, if f did not
24+
// error, the transaction is committed. Otherwise, if f did error, the
25+
// transaction is rolled back. If the rollback fails, the original error
26+
// returned by f is still returned. If the commit fails, the commit error is
27+
// returned.
28+
//
29+
// NOTE: this is part of the DBExecutor interface.
30+
func (e *kvdbExecutor[T]) Update(ctx context.Context,
31+
fn func(ctx context.Context, tx T) error) error {
32+
33+
return e.db.Update(func(tx *bbolt.Tx) error {
34+
return fn(ctx, e.wrapper.wrap(tx))
35+
})
36+
}
37+
38+
// View opens a database read transaction and executes the function f with the
39+
// transaction passed as a parameter. After f exits, the transaction is rolled
40+
// back. If f errors, its error is returned, not a rollback error (if any
41+
// occur).
42+
//
43+
// NOTE: this is part of the DBExecutor interface.
44+
func (e *kvdbExecutor[T]) View(ctx context.Context,
45+
fn func(ctx context.Context, tx T) error) error {
46+
47+
return e.db.View(func(tx *bbolt.Tx) error {
48+
return fn(ctx, e.wrapper.wrap(tx))
49+
})
50+
}

firewalldb/kvstores.go

+16-42
Original file line numberDiff line numberDiff line change
@@ -107,11 +107,14 @@ type RulesDB interface {
107107
func (db *DB) GetKVStores(rule string, groupID session.ID,
108108
feature string) KVStores {
109109

110-
return &kvStores{
111-
db: db.DB,
112-
ruleName: rule,
113-
groupID: groupID,
114-
featureName: feature,
110+
return &kvdbExecutor[KVStoreTx]{
111+
db: db.DB,
112+
wrapper: &kvStores{
113+
db: db.DB,
114+
ruleName: rule,
115+
groupID: groupID,
116+
featureName: feature,
117+
},
115118
}
116119
}
117120

@@ -123,44 +126,15 @@ type kvStores struct {
123126
featureName string
124127
}
125128

126-
// Update opens a database read/write transaction and executes the function f
127-
// with the transaction passed as a parameter. After f exits, if f did not
128-
// error, the transaction is committed. Otherwise, if f did error, the
129-
// transaction is rolled back. If the rollback fails, the original error
130-
// returned by f is still returned. If the commit fails, the commit error is
131-
// returned.
129+
// wrap wraps a bbolt transaction with the fields in kvStores and returns a
130+
// KVStoreTx.
132131
//
133-
// NOTE: this is part of the KVStores interface.
134-
func (s *kvStores) Update(ctx context.Context, fn func(ctx context.Context,
135-
tx KVStoreTx) error) error {
136-
137-
return s.db.Update(func(tx *bbolt.Tx) error {
138-
boltTx := &kvStoreTx{
139-
boltTx: tx,
140-
kvStores: s,
141-
}
142-
143-
return fn(ctx, boltTx)
144-
})
145-
}
146-
147-
// View opens a database read transaction and executes the function f with the
148-
// transaction passed as a parameter. After f exits, the transaction is rolled
149-
// back. If f errors, its error is returned, not a rollback error (if any
150-
// occur).
151-
//
152-
// NOTE: this is part of the KVStores interface.
153-
func (s *kvStores) View(ctx context.Context, fn func(ctx context.Context,
154-
tx KVStoreTx) error) error {
155-
156-
return s.db.View(func(tx *bbolt.Tx) error {
157-
boltTx := &kvStoreTx{
158-
boltTx: tx,
159-
kvStores: s,
160-
}
161-
162-
return fn(ctx, boltTx)
163-
})
132+
// NOTE: this is part of the txWrapper interface.
133+
func (s *kvStores) wrap(tx *bbolt.Tx) KVStoreTx {
134+
return &kvStoreTx{
135+
boltTx: tx,
136+
kvStores: s,
137+
}
164138
}
165139

166140
// getBucketFunc defines the signature of the bucket creation/fetching function

firewalldb/privacy_mapper.go

+13-40
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,12 @@ type NewPrivacyMapDB func(groupID session.ID) PrivacyMapDB
4242
// PrivacyDB constructs a PrivacyMapDB that will be indexed under the given
4343
// group ID key.
4444
func (db *DB) PrivacyDB(groupID session.ID) PrivacyMapDB {
45-
return &privacyMapDB{
46-
db: db,
47-
groupID: groupID,
45+
return &kvdbExecutor[PrivacyMapTx]{
46+
db: db.DB,
47+
wrapper: &privacyMapDB{
48+
db: db,
49+
groupID: groupID,
50+
},
4851
}
4952
}
5053

@@ -78,44 +81,14 @@ type privacyMapDB struct {
7881
groupID session.ID
7982
}
8083

81-
// Update opens a database read/write transaction and executes the function f
82-
// with the transaction passed as a parameter. After f exits, if f did not
83-
// error, the transaction is committed. Otherwise, if f did error, the
84-
// transaction is rolled back. If the rollback fails, the original error
85-
// returned by f is still returned. If the commit fails, the commit error is
86-
// returned.
84+
// wrap returns a new PrivacyMapTx that wraps the given bolt transaction.
8785
//
88-
// NOTE: this is part of the PrivacyMapDB interface.
89-
func (p *privacyMapDB) Update(ctx context.Context, fn func(ctx context.Context,
90-
tx PrivacyMapTx) error) error {
91-
92-
return p.db.Update(func(tx *bbolt.Tx) error {
93-
boltTx := &privacyMapTx{
94-
privacyMapDB: p,
95-
boltTx: tx,
96-
}
97-
98-
return fn(ctx, boltTx)
99-
})
100-
}
101-
102-
// View opens a database read transaction and executes the function f with the
103-
// transaction passed as a parameter. After f exits, the transaction is rolled
104-
// back. If f errors, its error is returned, not a rollback error (if any
105-
// occur).
106-
//
107-
// NOTE: this is part of the PrivacyMapDB interface.
108-
func (p *privacyMapDB) View(ctx context.Context, fn func(ctx context.Context,
109-
tx PrivacyMapTx) error) error {
110-
111-
return p.db.View(func(tx *bbolt.Tx) error {
112-
boltTx := &privacyMapTx{
113-
privacyMapDB: p,
114-
boltTx: tx,
115-
}
116-
117-
return fn(ctx, boltTx)
118-
})
86+
// NOTE: this is part of the txWrapper interface.
87+
func (p *privacyMapDB) wrap(tx *bbolt.Tx) PrivacyMapTx {
88+
return &privacyMapTx{
89+
boltTx: tx,
90+
privacyMapDB: p,
91+
}
11992
}
12093

12194
// privacyMapTx is an implementation of PrivacyMapTx.

0 commit comments

Comments
 (0)