Skip to content

Commit 825ee3d

Browse files
authored
Merge pull request lightningnetwork#9723 from ziggie1984/add-global-lock-walletdb
Add the global lock for the wallet db back for postgres
2 parents 51add8a + fee6859 commit 825ee3d

File tree

8 files changed

+72
-4
lines changed

8 files changed

+72
-4
lines changed

docs/release-notes/release-notes-0.19.0.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -475,6 +475,8 @@ the on going rate we'll permit.
475475
* [When running with neutrino as a backend with the kv-db backend `postgres`
476476
selected use postgres for the neutrino.db store](https://github.com/lightningnetwork/lnd/pull/9674).
477477

478+
* [Add the global lock back to the wallet db for the postgres backend](https://github.com/lightningnetwork/lnd/pull/9723).
479+
478480
## Code Health
479481

480482
* A code refactor that [moves all the graph related DB code out of the

go.mod

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,3 +216,5 @@ replace google.golang.org/protobuf => github.com/lightninglabs/protobuf-go-hex-d
216216
go 1.23.6
217217

218218
retract v0.0.2
219+
220+
replace github.com/lightningnetwork/lnd/kvdb => ./kvdb

go.sum

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -371,8 +371,6 @@ github.com/lightningnetwork/lnd/fn/v2 v2.0.8 h1:r2SLz7gZYQPVc3IZhU82M66guz3Zk2oY
371371
github.com/lightningnetwork/lnd/fn/v2 v2.0.8/go.mod h1:TOzwrhjB/Azw1V7aa8t21ufcQmdsQOQMDtxVOQWNl8s=
372372
github.com/lightningnetwork/lnd/healthcheck v1.2.6 h1:1sWhqr93GdkWy4+6U7JxBfcyZIE78MhIHTJZfPx7qqI=
373373
github.com/lightningnetwork/lnd/healthcheck v1.2.6/go.mod h1:Mu02um4CWY/zdTOvFje7WJgJcHyX2zq/FG3MhOAiGaQ=
374-
github.com/lightningnetwork/lnd/kvdb v1.4.15 h1:3eN6uGcubvGB5itPp1D0D4uEEkIMYht3w0LDnqLzAWI=
375-
github.com/lightningnetwork/lnd/kvdb v1.4.15/go.mod h1:HW+bvwkxNaopkz3oIgBV6NEnV4jCEZCACFUcNg4xSjM=
376374
github.com/lightningnetwork/lnd/queue v1.1.1 h1:99ovBlpM9B0FRCGYJo6RSFDlt8/vOkQQZznVb18iNMI=
377375
github.com/lightningnetwork/lnd/queue v1.1.1/go.mod h1:7A6nC1Qrm32FHuhx/mi1cieAiBZo5O6l8IBIoQxvkz4=
378376
github.com/lightningnetwork/lnd/sqldb v1.0.9 h1:7OHi+Hui823mB/U9NzCdlZTAGSVdDCbjp33+6d/Q+G0=

kvdb/postgres/config.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,5 @@ type Config struct {
99
Dsn string `long:"dsn" description:"Database connection string."`
1010
Timeout time.Duration `long:"timeout" description:"Database connection timeout. Set to zero to disable."`
1111
MaxConnections int `long:"maxconnections" description:"The maximum number of open connections to the database. Set to zero for unlimited."`
12+
WithGlobalLock bool `long:"withgloballock" description:"Use a global lock to ensure a single writer."`
1213
}

kvdb/postgres/db.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ func newPostgresBackend(ctx context.Context, config *Config, prefix string) (
2828
Schema: "public",
2929
TableNamePrefix: prefix,
3030
SQLiteCmdReplacements: sqliteCmdReplacements,
31+
WithTxLevelLock: config.WithGlobalLock,
3132
}
3233

3334
return sqlbase.NewSqlBackend(ctx, cfg)

kvdb/sqlbase/db.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,13 @@ type Config struct {
5555
// commands. Note that the sqlite keywords to be replaced are
5656
// case-sensitive.
5757
SQLiteCmdReplacements SQLiteCmdReplacements
58+
59+
// WithTxLevelLock when set will ensure that there is a transaction
60+
// level lock.
61+
//
62+
// NOTE: Temporary, should be removed when all parts of the LND code
63+
// are more resilient against concurrent db access..
64+
WithTxLevelLock bool
5865
}
5966

6067
// db holds a reference to the sql db connection.
@@ -79,6 +86,10 @@ type db struct {
7986
// top-level buckets that have keys that cannot be mapped to a distinct
8087
// sql table.
8188
table string
89+
90+
// lock is the global write lock that ensures single writer. This is
91+
// only used if cfg.WithTxLevelLock is set.
92+
lock sync.RWMutex
8293
}
8394

8495
// Enforce db implements the walletdb.DB interface.

kvdb/sqlbase/readwrite_tx.go

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ package sqlbase
55
import (
66
"context"
77
"database/sql"
8+
"sync"
89

910
"github.com/btcsuite/btcwallet/walletdb"
1011
)
@@ -19,11 +20,28 @@ type readWriteTx struct {
1920

2021
// active is true if the transaction hasn't been committed yet.
2122
active bool
23+
24+
// locker is a pointer to the global db lock.
25+
locker sync.Locker
2226
}
2327

2428
// newReadWriteTx creates an rw transaction using a connection from the
2529
// specified pool.
2630
func newReadWriteTx(db *db, readOnly bool) (*readWriteTx, error) {
31+
locker := newNoopLocker()
32+
if db.cfg.WithTxLevelLock {
33+
// Obtain the global lock instance. An alternative here is to
34+
// obtain a database lock from Postgres. Unfortunately there is
35+
// no database-level lock in Postgres, meaning that each table
36+
// would need to be locked individually. Perhaps an advisory
37+
// lock could perform this function too.
38+
locker = &db.lock
39+
if readOnly {
40+
locker = db.lock.RLocker()
41+
}
42+
}
43+
locker.Lock()
44+
2745
// Start the transaction. Don't use the timeout context because it would
2846
// be applied to the transaction as a whole. If possible, mark the
2947
// transaction as read-only to make sure that potential programming
@@ -36,13 +54,15 @@ func newReadWriteTx(db *db, readOnly bool) (*readWriteTx, error) {
3654
},
3755
)
3856
if err != nil {
57+
locker.Unlock()
3958
return nil, err
4059
}
4160

4261
return &readWriteTx{
4362
db: db,
4463
tx: tx,
4564
active: true,
65+
locker: locker,
4666
}, nil
4767
}
4868

@@ -74,6 +94,7 @@ func (tx *readWriteTx) Rollback() error {
7494

7595
// Unlock the transaction regardless of the error result.
7696
tx.active = false
97+
tx.locker.Unlock()
7798
return err
7899
}
79100

@@ -141,6 +162,7 @@ func (tx *readWriteTx) Commit() error {
141162

142163
// Unlock the transaction regardless of the error result.
143164
tx.active = false
165+
tx.locker.Unlock()
144166

145167
return err
146168
}
@@ -182,3 +204,25 @@ func (tx *readWriteTx) Exec(query string, args ...interface{}) (sql.Result,
182204

183205
return tx.tx.ExecContext(ctx, query, args...)
184206
}
207+
208+
// noopLocker is an implementation of a no-op sync.Locker.
209+
type noopLocker struct{}
210+
211+
// newNoopLocker creates a new noopLocker.
212+
func newNoopLocker() sync.Locker {
213+
return &noopLocker{}
214+
}
215+
216+
// Lock is a noop.
217+
//
218+
// NOTE: this is part of the sync.Locker interface.
219+
func (n *noopLocker) Lock() {
220+
}
221+
222+
// Unlock is a noop.
223+
//
224+
// NOTE: this is part of the sync.Locker interface.
225+
func (n *noopLocker) Unlock() {
226+
}
227+
228+
var _ sync.Locker = (*noopLocker)(nil)

lncfg/db.go

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -443,12 +443,21 @@ func (db *DB) GetBackends(ctx context.Context, chanDBPath,
443443
}
444444
closeFuncs[NSTowerServerDB] = postgresTowerServerBackend.Close
445445

446+
// The wallet subsystem is still not robust enough to run it
447+
// without a single writer in postgres therefore we create a
448+
// new config with the global lock enabled.
449+
//
450+
// NOTE: This is a temporary measure and should be removed as
451+
// soon as the wallet code is more robust.
452+
postgresConfigWalletDB := GetPostgresConfigKVDB(db.Postgres)
453+
postgresConfigWalletDB.WithGlobalLock = true
454+
446455
postgresWalletBackend, err := kvdb.Open(
447456
kvdb.PostgresBackendName, ctx,
448-
postgresConfig, NSWalletDB,
457+
postgresConfigWalletDB, NSWalletDB,
449458
)
450459
if err != nil {
451-
return nil, fmt.Errorf("error opening postgres macaroon "+
460+
return nil, fmt.Errorf("error opening postgres wallet "+
452461
"DB: %v", err)
453462
}
454463
closeFuncs[NSWalletDB] = postgresWalletBackend.Close

0 commit comments

Comments
 (0)