mirror of
https://github.com/lightninglabs/lightning-terminal.git
synced 2026-08-13 12:33:36 +02:00
accounts: add database backend benchmark test
This commit is contained in:
parent
f90f468a32
commit
fe28ff7e60
1 changed files with 405 additions and 0 deletions
405
accounts/benchmark_test.go
Normal file
405
accounts/benchmark_test.go
Normal file
|
|
@ -0,0 +1,405 @@
|
|||
package accounts
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/binary"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/lightninglabs/lightning-terminal/db"
|
||||
"github.com/lightninglabs/lightning-terminal/db/sqlc"
|
||||
"github.com/lightningnetwork/lnd/clock"
|
||||
"github.com/lightningnetwork/lnd/fn"
|
||||
"github.com/lightningnetwork/lnd/lnrpc"
|
||||
"github.com/lightningnetwork/lnd/lntypes"
|
||||
"github.com/lightningnetwork/lnd/lnwire"
|
||||
"github.com/lightningnetwork/lnd/sqldb/v2"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
// NOTE: Set this to true if you also want to benchmark with a postgres backend.
|
||||
var benchPostgres = false
|
||||
|
||||
// BenchmarkAccountStore benchmarks common account store operations across
|
||||
// supported DB backends.
|
||||
func BenchmarkAccountStore(b *testing.B) {
|
||||
for _, backend := range accountBenchBackends(b) {
|
||||
backend := backend
|
||||
b.Run(backend.name, func(b *testing.B) {
|
||||
runAccountBench(
|
||||
b, backend, "NewAccount", benchmarkAccountNew,
|
||||
)
|
||||
runAccountBench(
|
||||
b, backend, "UpdateBalance",
|
||||
benchmarkAccountUpdateBalance,
|
||||
)
|
||||
runAccountBench(
|
||||
b, backend, "AddInvoice",
|
||||
benchmarkAccountAddInvoice,
|
||||
)
|
||||
runAccountBench(
|
||||
b, backend, "CreditAccount",
|
||||
benchmarkAccountCredit,
|
||||
)
|
||||
runAccountBench(
|
||||
b, backend, "DebitAccount",
|
||||
benchmarkAccountDebit,
|
||||
)
|
||||
runAccountBench(
|
||||
b, backend, "UpsertPayment",
|
||||
benchmarkAccountUpsertPayment,
|
||||
)
|
||||
runAccountBench(
|
||||
b, backend, "DeletePayment",
|
||||
benchmarkAccountDeletePayment,
|
||||
)
|
||||
runAccountBench(
|
||||
b, backend, "RemoveAccount",
|
||||
benchmarkAccountRemove,
|
||||
)
|
||||
runAccountBench(
|
||||
b, backend, "GetAccount",
|
||||
benchmarkAccountGet,
|
||||
)
|
||||
runAccountBench(
|
||||
b, backend, "ListAccounts",
|
||||
benchmarkAccountList,
|
||||
)
|
||||
runAccountBench(
|
||||
b, backend, "StoreLastIndexes",
|
||||
benchmarkAccountStoreLastIndexes,
|
||||
)
|
||||
runAccountBench(
|
||||
b, backend, "LastIndexes",
|
||||
benchmarkAccountLastIndexes,
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
type accountBenchBackend struct {
|
||||
name string
|
||||
newStore func(b *testing.B) Store
|
||||
}
|
||||
|
||||
func runAccountBench(b *testing.B, backend accountBenchBackend, name string,
|
||||
fn func(b *testing.B, store Store)) {
|
||||
|
||||
b.Run(name, func(b *testing.B) {
|
||||
store := backend.newStore(b)
|
||||
b.Cleanup(func() {
|
||||
require.NoError(b, store.Close())
|
||||
})
|
||||
|
||||
fn(b, store)
|
||||
})
|
||||
}
|
||||
|
||||
func accountBenchBackends(b *testing.B) []accountBenchBackend {
|
||||
backends := []accountBenchBackend{
|
||||
{
|
||||
name: "kvdb-bbolt",
|
||||
newStore: func(b *testing.B) Store {
|
||||
clk := clock.NewTestClock(time.Now())
|
||||
dir := b.TempDir()
|
||||
store, err := NewBoltStore(dir, DBFilename, clk)
|
||||
require.NoError(b, err)
|
||||
return store
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "native-sqlite",
|
||||
newStore: func(b *testing.B) Store {
|
||||
clk := clock.NewTestClock(time.Now())
|
||||
dbFile := filepath.Join(
|
||||
b.TempDir(), "accounts.sqlite",
|
||||
)
|
||||
|
||||
sqlStore, err := sqldb.NewSqliteStore(
|
||||
&sqldb.SqliteConfig{
|
||||
SkipMigrations: false,
|
||||
},
|
||||
dbFile,
|
||||
)
|
||||
require.NoError(b, err)
|
||||
|
||||
require.NoError(
|
||||
b,
|
||||
sqldb.ApplyAllMigrations(
|
||||
sqlStore,
|
||||
db.MakeTestMigrationStreams(),
|
||||
),
|
||||
)
|
||||
|
||||
queries := sqlc.NewForType(
|
||||
sqlStore.BaseDB,
|
||||
sqlStore.BaseDB.BackendType,
|
||||
)
|
||||
return NewSQLStore(
|
||||
sqlStore.BaseDB, queries, clk,
|
||||
)
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
if benchPostgres {
|
||||
backends = append(backends, accountBenchBackend{
|
||||
name: "native-postgres",
|
||||
newStore: func(b *testing.B) Store {
|
||||
clk := clock.NewTestClock(time.Now())
|
||||
fixture := sqldb.NewTestPgFixture(
|
||||
b, db.DefaultPostgresFixtureLifetime,
|
||||
)
|
||||
b.Cleanup(func() {
|
||||
fixture.TearDown(b)
|
||||
})
|
||||
|
||||
sqlStore := sqldb.NewTestPostgresDB(
|
||||
b, fixture,
|
||||
db.MakeTestMigrationStreams(),
|
||||
)
|
||||
|
||||
queries := sqlc.NewForType(
|
||||
sqlStore.BaseDB,
|
||||
sqlStore.BaseDB.BackendType,
|
||||
)
|
||||
return NewSQLStore(
|
||||
sqlStore.BaseDB, queries, clk,
|
||||
)
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
return backends
|
||||
}
|
||||
|
||||
// benchmarkAccountNew measures account creation performance.
|
||||
func benchmarkAccountNew(b *testing.B, store Store) {
|
||||
ctx := context.Background()
|
||||
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, err := store.NewAccount(
|
||||
ctx, 1000, time.Time{}, "",
|
||||
)
|
||||
require.NoError(b, err)
|
||||
}
|
||||
}
|
||||
|
||||
// benchmarkAccountUpdateBalance measures balance update performance.
|
||||
func benchmarkAccountUpdateBalance(b *testing.B, store Store) {
|
||||
ctx := context.Background()
|
||||
|
||||
acct, err := store.NewAccount(ctx, 1000, time.Time{}, "")
|
||||
require.NoError(b, err)
|
||||
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
newBalance := fn.Some(int64(i))
|
||||
err := store.UpdateAccount(
|
||||
ctx, acct.ID, newBalance, fn.None[time.Time](),
|
||||
fn.None[string](),
|
||||
)
|
||||
require.NoError(b, err)
|
||||
}
|
||||
}
|
||||
|
||||
// benchmarkAccountAddInvoice measures invoice association performance.
|
||||
func benchmarkAccountAddInvoice(b *testing.B, store Store) {
|
||||
ctx := context.Background()
|
||||
|
||||
acct, err := store.NewAccount(ctx, 1000, time.Time{}, "")
|
||||
require.NoError(b, err)
|
||||
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
var hash lntypes.Hash
|
||||
binary.BigEndian.PutUint64(hash[:], uint64(i))
|
||||
err := store.AddAccountInvoice(ctx, acct.ID, hash)
|
||||
require.NoError(b, err)
|
||||
}
|
||||
}
|
||||
|
||||
// benchmarkAccountUpsertPayment measures payment upsert performance.
|
||||
func benchmarkAccountUpsertPayment(b *testing.B, store Store) {
|
||||
ctx := context.Background()
|
||||
|
||||
acct, err := store.NewAccount(ctx, 1000, time.Time{}, "")
|
||||
require.NoError(b, err)
|
||||
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
var hash lntypes.Hash
|
||||
binary.BigEndian.PutUint64(hash[:], uint64(i))
|
||||
_, err := store.UpsertAccountPayment(
|
||||
ctx, acct.ID, hash, lnwire.MilliSatoshi(1000),
|
||||
lnrpc.Payment_SUCCEEDED,
|
||||
)
|
||||
require.NoError(b, err)
|
||||
}
|
||||
}
|
||||
|
||||
// benchmarkAccountDeletePayment measures payment delete performance.
|
||||
func benchmarkAccountDeletePayment(b *testing.B, store Store) {
|
||||
ctx := context.Background()
|
||||
|
||||
acct, err := store.NewAccount(ctx, 1000, time.Time{}, "")
|
||||
require.NoError(b, err)
|
||||
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
var hash lntypes.Hash
|
||||
binary.BigEndian.PutUint64(hash[:], uint64(i))
|
||||
|
||||
// As this function should benchmark the DeleteAccountPayment
|
||||
// function, ensure that the timer isn't running when
|
||||
// UpsertAccountPayment is executed.
|
||||
b.StopTimer()
|
||||
_, err := store.UpsertAccountPayment(
|
||||
ctx, acct.ID, hash, lnwire.MilliSatoshi(1000),
|
||||
lnrpc.Payment_SUCCEEDED,
|
||||
)
|
||||
require.NoError(b, err)
|
||||
b.StartTimer()
|
||||
|
||||
err = store.DeleteAccountPayment(ctx, acct.ID, hash)
|
||||
require.NoError(b, err)
|
||||
}
|
||||
}
|
||||
|
||||
// benchmarkAccountCredit measures credit performance.
|
||||
func benchmarkAccountCredit(b *testing.B, store Store) {
|
||||
ctx := context.Background()
|
||||
|
||||
acct, err := store.NewAccount(ctx, 1000, time.Time{}, "")
|
||||
require.NoError(b, err)
|
||||
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
err := store.CreditAccount(
|
||||
ctx, acct.ID, lnwire.MilliSatoshi(1),
|
||||
)
|
||||
require.NoError(b, err)
|
||||
}
|
||||
}
|
||||
|
||||
// benchmarkAccountDebit measures debit performance.
|
||||
func benchmarkAccountDebit(b *testing.B, store Store) {
|
||||
ctx := context.Background()
|
||||
|
||||
acct, err := store.NewAccount(ctx, 1000000, time.Time{}, "")
|
||||
require.NoError(b, err)
|
||||
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
err := store.DebitAccount(
|
||||
ctx, acct.ID, lnwire.MilliSatoshi(1),
|
||||
)
|
||||
require.NoError(b, err)
|
||||
}
|
||||
}
|
||||
|
||||
// benchmarkAccountGet measures account lookup performance.
|
||||
func benchmarkAccountGet(b *testing.B, store Store) {
|
||||
ctx := context.Background()
|
||||
|
||||
acct, err := store.NewAccount(ctx, 1000, time.Time{}, "")
|
||||
require.NoError(b, err)
|
||||
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, err := store.Account(ctx, acct.ID)
|
||||
require.NoError(b, err)
|
||||
}
|
||||
}
|
||||
|
||||
// benchmarkAccountRemove measures account deletion performance.
|
||||
func benchmarkAccountRemove(b *testing.B, store Store) {
|
||||
ctx := context.Background()
|
||||
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
// As this function should benchmark the RemoveAccount function,
|
||||
// ensure that the timer isn't running when NewAccount is
|
||||
// executed.
|
||||
b.StopTimer()
|
||||
acct, err := store.NewAccount(
|
||||
ctx, 1000, time.Time{}, "",
|
||||
)
|
||||
require.NoError(b, err)
|
||||
b.StartTimer()
|
||||
|
||||
err = store.RemoveAccount(ctx, acct.ID)
|
||||
require.NoError(b, err)
|
||||
}
|
||||
}
|
||||
|
||||
// benchmarkAccountList measures listing performance with seeded data.
|
||||
func benchmarkAccountList(b *testing.B, store Store) {
|
||||
ctx := context.Background()
|
||||
|
||||
const seedCount = 100
|
||||
for i := 0; i < seedCount; i++ {
|
||||
_, err := store.NewAccount(
|
||||
ctx, 1000, time.Time{}, "",
|
||||
)
|
||||
require.NoError(b, err)
|
||||
}
|
||||
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, err := store.Accounts(ctx)
|
||||
require.NoError(b, err)
|
||||
}
|
||||
}
|
||||
|
||||
// benchmarkAccountStoreLastIndexes measures write performance.
|
||||
func benchmarkAccountStoreLastIndexes(b *testing.B, store Store) {
|
||||
ctx := context.Background()
|
||||
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
err := store.StoreLastIndexes(
|
||||
ctx, uint64(i), uint64(i+1),
|
||||
)
|
||||
require.NoError(b, err)
|
||||
}
|
||||
}
|
||||
|
||||
// benchmarkAccountLastIndexes measures read performance.
|
||||
func benchmarkAccountLastIndexes(b *testing.B, store Store) {
|
||||
ctx := context.Background()
|
||||
|
||||
require.NoError(b, store.StoreLastIndexes(ctx, 1, 2))
|
||||
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, _, err := store.LastIndexes(ctx)
|
||||
require.NoError(b, err)
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue