• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

lightningnetwork / lnd / 19610155923

23 Nov 2025 11:02AM UTC coverage: 65.159% (-0.07%) from 65.229%
19610155923

Pull #10390

github

web-flow
Merge 4927490d9 into 8c8662c86
Pull Request #10390: Defer Channel Cleanup after a channel is closed to avoid kv-sql stress

53 of 206 new or added lines in 4 files covered. (25.73%)

117 existing lines in 22 files now uncovered.

137580 of 211145 relevant lines covered (65.16%)

20686.05 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

75.76
/kvdb/interface.go
1
package kvdb
2

3
import (
4
        "github.com/btcsuite/btcwallet/walletdb"
5
)
6

7
// Update opens a database read/write transaction and executes the function f
8
// with the transaction passed as a parameter. After f exits, if f did not
9
// error, the transaction is committed. Otherwise, if f did error, the
10
// transaction is rolled back. If the rollback fails, the original error
11
// returned by f is still returned. If the commit fails, the commit error is
12
// returned. As callers may expect retries of the f closure (depending on the
13
// database backend used), the reset function will be called before each retry
14
// respectively.
15
func Update(db Backend, f func(tx RwTx) error, reset func()) error {
38,839✔
16
        return db.Update(f, reset)
38,839✔
17
}
38,839✔
18

19
// View opens a database read transaction and executes the function f with the
20
// transaction passed as a parameter. After f exits, the transaction is rolled
21
// back. If f errors, its error is returned, not a rollback error (if any
22
// occur). The passed reset function is called before the start of the
23
// transaction and can be used to reset intermediate state. As callers may
24
// expect retries of the f closure (depending on the database backend used), the
25
// reset function will be called before each retry respectively.
26
func View(db Backend, f func(tx RTx) error, reset func()) error {
17,915✔
27
        return db.View(f, reset)
17,915✔
28
}
17,915✔
29

30
// Batch is identical to the Update call, but it attempts to combine several
31
// individual Update transactions into a single write database transaction on
32
// an optimistic basis. This only has benefits if multiple goroutines call
33
// Batch. For etcd Batch simply does an Update since combination is more complex
34
// in that case due to STM retries.
35
func Batch(db Backend, f func(tx RwTx) error) error {
3,791✔
36
        // Fall back to the normal Update method if the backend doesn't support
3,791✔
37
        // batching.
3,791✔
38
        if _, ok := db.(walletdb.BatchDB); !ok {
6,506✔
39
                // Since Batch calls handle external state reset, we can safely
2,715✔
40
                // pass in an empty reset closure.
2,715✔
41
                return db.Update(f, func() {})
5,430✔
42
        }
43

44
        return walletdb.Batch(db, f)
1,076✔
45
}
46

47
// Create initializes and opens a database for the specified type. The
48
// arguments are specific to the database type driver. See the documentation
49
// for the database driver for further details.
50
//
51
// ErrDbUnknownType will be returned if the database type is not registered.
52
var Create = walletdb.Create
53

54
// Backend represents an ACID database. All database access is performed
55
// through read or read+write transactions.
56
type Backend = walletdb.DB
57

58
// Open opens an existing database for the specified type. The arguments are
59
// specific to the database type driver. See the documentation for the database
60
// driver for further details.
61
//
62
// ErrDbUnknownType will be returned if the database type is not registered.
63
var Open = walletdb.Open
64

65
// Driver defines a structure for backend drivers to use when they registered
66
// themselves as a backend which implements the Backend interface.
67
type Driver = walletdb.Driver
68

69
// RBucket represents a bucket (a hierarchical structure within the
70
// database) that is only allowed to perform read operations.
71
type RBucket = walletdb.ReadBucket
72

73
// RCursor represents a bucket cursor that can be positioned at the start or
74
// end of the bucket's key/value pairs and iterate over pairs in the bucket.
75
// This type is only allowed to perform database read operations.
76
type RCursor = walletdb.ReadCursor
77

78
// RTx represents a database transaction that can only be used for reads. If
79
// a database update must occur, use a RwTx.
80
type RTx = walletdb.ReadTx
81

82
// RwBucket represents a bucket (a hierarchical structure within the database)
83
// that is allowed to perform both read and write operations.
84
type RwBucket = walletdb.ReadWriteBucket
85

86
// RwCursor represents a bucket cursor that can be positioned at the start or
87
// end of the bucket's key/value pairs and iterate over pairs in the bucket.
88
// This abstraction is allowed to perform both database read and write
89
// operations.
90
type RwCursor = walletdb.ReadWriteCursor
91

92
// RwTx represents a database transaction that can be used for both reads and
93
// writes. When only reads are necessary, consider using a RTx instead.
94
type RwTx = walletdb.ReadWriteTx
95

96
// ExtendedRTx is an extension to walletdb.ReadTx to allow prefetching of keys.
97
type ExtendedRTx interface {
98
        RTx
99

100
        // RootBucket returns the "root bucket" which is pseudo bucket used
101
        // when prefetching (keys from) top level buckets.
102
        RootBucket() RBucket
103
}
104

105
// ExtendedRBucket is an extension to walletdb.ReadBucket to allow prefetching
106
// of all values inside buckets.
107
type ExtendedRBucket interface {
108
        RBucket
109

110
        // Prefetch will attempt to prefetch all values under a path.
111
        Prefetch(paths ...[]string)
112

113
        // ForAll is an optimized version of ForEach.
114
        //
115
        // NOTE: ForAll differs from ForEach in that no additional queries can
116
        // be executed within the callback.
117
        ForAll(func(k, v []byte) error) error
118
}
119

120
// Prefetch will attempt to prefetch all values under a path from the passed
121
// bucket.
122
func Prefetch(b RBucket, paths ...[]string) {
530✔
123
        if bucket, ok := b.(ExtendedRBucket); ok {
530✔
124
                bucket.Prefetch(paths...)
×
125
        }
×
126
}
127

128
// ForAll is an optimized version of ForEach with the limitation that no
129
// additional queries can be executed within the callback.
130
func ForAll(b RBucket, cb func(k, v []byte) error) error {
312✔
131
        if bucket, ok := b.(ExtendedRBucket); ok {
312✔
132
                return bucket.ForAll(cb)
×
133
        }
×
134

135
        return b.ForEach(cb)
312✔
136
}
137

138
// RootBucket is a wrapper to ExtendedRTx.RootBucket which does nothing if
139
// the implementation doesn't have ExtendedRTx.
140
func RootBucket(t RTx) RBucket {
530✔
141
        if tx, ok := t.(ExtendedRTx); ok {
530✔
142
                return tx.RootBucket()
×
143
        }
×
144

145
        return nil
530✔
146
}
147

148
// DeferrableBackend is an optional interface that backends can implement to
149
// indicate they prefer deferring heavy operations (like bulk deletes) to
150
// startup rather than executing them inline. SQL-based backends typically
151
// implement this interface since concurrent large transactions can cause
152
// lock contention and timeouts.
153
type DeferrableBackend interface {
154
        // ShouldDeferHeavyOperations returns true if the backend prefers to
155
        // defer expensive operations (like deleting thousands of revocation
156
        // log entries) to startup rather than executing them inline during
157
        // normal operations.
158
        ShouldDeferHeavyOperations() bool
159
}
160

161
// ShouldDeferHeavyOperations checks if the backend implements
162
// DeferrableBackend and if so, returns the result of
163
// ShouldDeferHeavyOperations(). Returns false for backends that don't
164
// implement the interface (like bbolt).
165
func ShouldDeferHeavyOperations(backend Backend) bool {
116✔
166
        if db, ok := backend.(DeferrableBackend); ok {
116✔
NEW
167
                return db.ShouldDeferHeavyOperations()
×
NEW
168
        }
×
169

170
        return false
116✔
171
}
172

173
var (
174
        // ErrBucketNotFound is returned when trying to access a bucket that
175
        // has not been created yet.
176
        ErrBucketNotFound = walletdb.ErrBucketNotFound
177

178
        // ErrBucketExists is returned when creating a bucket that already
179
        // exists.
180
        ErrBucketExists = walletdb.ErrBucketExists
181

182
        // ErrDatabaseNotOpen is returned when a database instance is accessed
183
        // before it is opened or after it is closed.
184
        ErrDatabaseNotOpen = walletdb.ErrDbNotOpen
185

186
        // ErrDbDoesNotExist is returned when a database instance is opened
187
        // but it does not exist.
188
        ErrDbDoesNotExist = walletdb.ErrDbDoesNotExist
189
)
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc