Skip to content

Commit 8986d41

Browse files
accounts: iterate over bbolt buckets in migration
Update the SQL migration to instead of using the public functions of the BoltStore struct, we instead iterate over the buckets directly. This ensures that the BoltStore struct Acccounts & LastIndexes functions of the BoltStore implementation can be changed, without effecting the SQL migration.
1 parent d0eaa3d commit 8986d41

File tree

2 files changed

+87
-6
lines changed

2 files changed

+87
-6
lines changed

accounts/sql_migration.go

Lines changed: 86 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package accounts
22

33
import (
4+
"bytes"
45
"context"
56
"database/sql"
67
"errors"
@@ -11,6 +12,7 @@ import (
1112

1213
"github.com/davecgh/go-spew/spew"
1314
"github.com/lightninglabs/lightning-terminal/db/sqlc"
15+
"github.com/lightningnetwork/lnd/kvdb"
1416
"github.com/pmezard/go-difflib/difflib"
1517
)
1618

@@ -24,7 +26,7 @@ var (
2426
// MigrateAccountStoreToSQL runs the migration of all accounts and indices from
2527
// the KV database to the SQL database. The migration is done in a single
2628
// transaction to ensure that all accounts are migrated or none at all.
27-
func MigrateAccountStoreToSQL(ctx context.Context, kvStore *BoltStore,
29+
func MigrateAccountStoreToSQL(ctx context.Context, kvStore kvdb.Backend,
2830
tx SQLQueries) error {
2931

3032
log.Infof("Starting migration of the KV accounts store to SQL")
@@ -47,12 +49,12 @@ func MigrateAccountStoreToSQL(ctx context.Context, kvStore *BoltStore,
4749
// migrateAccountsToSQL runs the migration of all accounts from the KV database
4850
// to the SQL database. The migration is done in a single transaction to ensure
4951
// that all accounts are migrated or none at all.
50-
func migrateAccountsToSQL(ctx context.Context, kvStore *BoltStore,
52+
func migrateAccountsToSQL(ctx context.Context, kvStore kvdb.Backend,
5153
tx SQLQueries) error {
5254

5355
log.Infof("Starting migration of accounts from KV to SQL")
5456

55-
kvAccounts, err := kvStore.Accounts(ctx)
57+
kvAccounts, err := getBBoltAccounts(kvStore)
5658
if err != nil {
5759
return err
5860
}
@@ -104,6 +106,51 @@ func migrateAccountsToSQL(ctx context.Context, kvStore *BoltStore,
104106
return nil
105107
}
106108

109+
// getBBoltAccounts is a helper function that fetches all accounts from the
110+
// Bbolt store, by iterating directly over the buckets, without needing to
111+
// use any public functions of the BoltStore struct.
112+
func getBBoltAccounts(db kvdb.Backend) ([]*OffChainBalanceAccount, error) {
113+
var accounts []*OffChainBalanceAccount
114+
err := db.View(func(tx kvdb.RTx) error {
115+
// This function will be called in the ForEach and receive
116+
// the key and value of each account in the DB. The key, which
117+
// is also the ID is not used because it is also marshaled into
118+
// the value.
119+
readFn := func(k, v []byte) error {
120+
// Skip the two special purpose keys.
121+
if bytes.Equal(k, lastAddIndexKey) ||
122+
bytes.Equal(k, lastSettleIndexKey) {
123+
124+
return nil
125+
}
126+
127+
// There should be no sub-buckets.
128+
if v == nil {
129+
return fmt.Errorf("invalid bucket structure")
130+
}
131+
132+
account, err := deserializeAccount(v)
133+
if err != nil {
134+
return err
135+
}
136+
137+
accounts = append(accounts, account)
138+
return nil
139+
}
140+
141+
// We know the bucket should exist since it's created when
142+
// the account storage is initialized.
143+
return tx.ReadBucket(accountBucketName).ForEach(readFn)
144+
}, func() {
145+
accounts = nil
146+
})
147+
if err != nil {
148+
return nil, err
149+
}
150+
151+
return accounts, nil
152+
}
153+
107154
// migrateSingleAccountToSQL runs the migration for a single account from the
108155
// KV database to the SQL database.
109156
func migrateSingleAccountToSQL(ctx context.Context,
@@ -163,12 +210,12 @@ func migrateSingleAccountToSQL(ctx context.Context,
163210

164211
// migrateAccountsIndicesToSQL runs the migration for the account indices from
165212
// the KV database to the SQL database.
166-
func migrateAccountsIndicesToSQL(ctx context.Context, kvStore *BoltStore,
213+
func migrateAccountsIndicesToSQL(ctx context.Context, kvStore kvdb.Backend,
167214
tx SQLQueries) error {
168215

169216
log.Infof("Starting migration of accounts indices from KV to SQL")
170217

171-
addIndex, settleIndex, err := kvStore.LastIndexes(ctx)
218+
addIndex, settleIndex, err := getBBoltIndices(kvStore)
172219
if errors.Is(err, ErrNoInvoiceIndexKnown) {
173220
log.Infof("No indices found in KV store, skipping migration")
174221
return nil
@@ -211,6 +258,40 @@ func migrateAccountsIndicesToSQL(ctx context.Context, kvStore *BoltStore,
211258
return nil
212259
}
213260

261+
// getBBoltIndices is a helper function that fetches the índices from the
262+
// Bbolt store, by iterating directly over the buckets, without needing to
263+
// use any public functions of the BoltStore struct.
264+
func getBBoltIndices(db kvdb.Backend) (uint64, uint64, error) {
265+
var (
266+
addValue, settleValue []byte
267+
)
268+
err := db.View(func(tx kvdb.RTx) error {
269+
bucket := tx.ReadBucket(accountBucketName)
270+
if bucket == nil {
271+
return ErrAccountBucketNotFound
272+
}
273+
274+
addValue = bucket.Get(lastAddIndexKey)
275+
if len(addValue) == 0 {
276+
return ErrNoInvoiceIndexKnown
277+
}
278+
279+
settleValue = bucket.Get(lastSettleIndexKey)
280+
if len(settleValue) == 0 {
281+
return ErrNoInvoiceIndexKnown
282+
}
283+
284+
return nil
285+
}, func() {
286+
addValue, settleValue = nil, nil
287+
})
288+
if err != nil {
289+
return 0, 0, err
290+
}
291+
292+
return byteOrder.Uint64(addValue), byteOrder.Uint64(settleValue), nil
293+
}
294+
214295
// overrideAccountTimeZone overrides the time zone of the account to the local
215296
// time zone and chops off the nanosecond part for comparison. This is needed
216297
// because KV database stores times as-is which as an unwanted side effect would

accounts/sql_migration_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -344,7 +344,7 @@ func TestAccountStoreMigration(t *testing.T) {
344344
err = txEx.ExecTx(ctx, &opts,
345345
func(tx SQLQueries) error {
346346
return MigrateAccountStoreToSQL(
347-
ctx, kvStore, tx,
347+
ctx, kvStore.db, tx,
348348
)
349349
},
350350
)

0 commit comments

Comments
 (0)