mirror of
https://github.com/lightningnetwork/lnd.git
synced 2025-12-01 08:29:00 +01:00
sqldb: exclude sqlite from the JS and unsupported platform builds
This commit is contained in:
55
sqldb/config.go
Normal file
55
sqldb/config.go
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
package sqldb
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/url"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// defaultMaxConns is the number of permitted active and idle
|
||||||
|
// connections. We want to limit this so it isn't unlimited. We use the
|
||||||
|
// same value for the number of idle connections as, this can speed up
|
||||||
|
// queries given a new connection doesn't need to be established each
|
||||||
|
// time.
|
||||||
|
defaultMaxConns = 25
|
||||||
|
|
||||||
|
// connIdleLifetime is the amount of time a connection can be idle.
|
||||||
|
connIdleLifetime = 5 * time.Minute
|
||||||
|
)
|
||||||
|
|
||||||
|
// SqliteConfig holds all the config arguments needed to interact with our
|
||||||
|
// sqlite DB.
|
||||||
|
//
|
||||||
|
//nolint:lll
|
||||||
|
type SqliteConfig struct {
|
||||||
|
Timeout time.Duration `long:"timeout" description:"The time after which a database query should be timed out."`
|
||||||
|
BusyTimeout time.Duration `long:"busytimeout" description:"The maximum amount of time to wait for a database connection to become available for a query."`
|
||||||
|
MaxConnections int `long:"maxconnections" description:"The maximum number of open connections to the database. Set to zero for unlimited."`
|
||||||
|
PragmaOptions []string `long:"pragmaoptions" description:"A list of pragma options to set on a database connection. For example, 'auto_vacuum=incremental'. Note that the flag must be specified multiple times if multiple options are to be set."`
|
||||||
|
SkipMigrations bool `long:"skipmigrations" description:"Skip applying migrations on startup."`
|
||||||
|
}
|
||||||
|
|
||||||
|
// PostgresConfig holds the postgres database configuration.
|
||||||
|
//
|
||||||
|
//nolint:lll
|
||||||
|
type PostgresConfig struct {
|
||||||
|
Dsn string `long:"dsn" description:"Database connection string."`
|
||||||
|
Timeout time.Duration `long:"timeout" description:"Database connection timeout. Set to zero to disable."`
|
||||||
|
MaxConnections int `long:"maxconnections" description:"The maximum number of open connections to the database. Set to zero for unlimited."`
|
||||||
|
SkipMigrations bool `long:"skipmigrations" description:"Skip applying migrations on startup."`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *PostgresConfig) Validate() error {
|
||||||
|
if p.Dsn == "" {
|
||||||
|
return fmt.Errorf("DSN is required")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse the DSN as a URL.
|
||||||
|
_, err := url.Parse(p.Dsn)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("invalid DSN: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
18
sqldb/no_sqlite.go
Normal file
18
sqldb/no_sqlite.go
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
//go:build js || (windows && (arm || 386)) || (linux && (ppc64 || mips || mipsle || mips64))
|
||||||
|
|
||||||
|
package sqldb
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
// SqliteStore is a database store implementation that uses a sqlite backend.
|
||||||
|
type SqliteStore struct {
|
||||||
|
cfg *SqliteConfig
|
||||||
|
|
||||||
|
*BaseDB
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewSqliteStore attempts to open a new sqlite database based on the passed
|
||||||
|
// config.
|
||||||
|
func NewSqliteStore(cfg *SqliteConfig, dbPath string) (*SqliteStore, error) {
|
||||||
|
return nil, fmt.Errorf("SQLite backend not supported in WebAssembly")
|
||||||
|
}
|
||||||
@@ -1,21 +1,15 @@
|
|||||||
package sqldb
|
package sqldb
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"crypto/rand"
|
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"encoding/hex"
|
|
||||||
"fmt"
|
|
||||||
"net/url"
|
"net/url"
|
||||||
"path"
|
"path"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
postgres_migrate "github.com/golang-migrate/migrate/v4/database/postgres"
|
postgres_migrate "github.com/golang-migrate/migrate/v4/database/postgres"
|
||||||
_ "github.com/golang-migrate/migrate/v4/source/file" // Read migrations from files. // nolint:lll
|
_ "github.com/golang-migrate/migrate/v4/source/file" // Read migrations from files. // nolint:lll
|
||||||
"github.com/lightningnetwork/lnd/sqldb/sqlc"
|
"github.com/lightningnetwork/lnd/sqldb/sqlc"
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -27,30 +21,6 @@ var (
|
|||||||
DefaultPostgresFixtureLifetime = 10 * time.Minute
|
DefaultPostgresFixtureLifetime = 10 * time.Minute
|
||||||
)
|
)
|
||||||
|
|
||||||
// PostgresConfig holds the postgres database configuration.
|
|
||||||
//
|
|
||||||
//nolint:lll
|
|
||||||
type PostgresConfig struct {
|
|
||||||
Dsn string `long:"dsn" description:"Database connection string."`
|
|
||||||
Timeout time.Duration `long:"timeout" description:"Database connection timeout. Set to zero to disable."`
|
|
||||||
MaxConnections int `long:"maxconnections" description:"The maximum number of open connections to the database. Set to zero for unlimited."`
|
|
||||||
SkipMigrations bool `long:"skipmigrations" description:"Skip applying migrations on startup."`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *PostgresConfig) Validate() error {
|
|
||||||
if p.Dsn == "" {
|
|
||||||
return fmt.Errorf("DSN is required")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse the DSN as a URL.
|
|
||||||
_, err := url.Parse(p.Dsn)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("invalid DSN: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// replacePasswordInDSN takes a DSN string and returns it with the password
|
// replacePasswordInDSN takes a DSN string and returns it with the password
|
||||||
// replaced by "***".
|
// replaced by "***".
|
||||||
func replacePasswordInDSN(dsn string) (string, error) {
|
func replacePasswordInDSN(dsn string) (string, error) {
|
||||||
@@ -167,33 +137,3 @@ func NewPostgresStore(cfg *PostgresConfig) (*PostgresStore, error) {
|
|||||||
},
|
},
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewTestPostgresDB is a helper function that creates a Postgres database for
|
|
||||||
// testing using the given fixture.
|
|
||||||
func NewTestPostgresDB(t *testing.T, fixture *TestPgFixture) *PostgresStore {
|
|
||||||
t.Helper()
|
|
||||||
|
|
||||||
// Create random database name.
|
|
||||||
randBytes := make([]byte, 8)
|
|
||||||
_, err := rand.Read(randBytes)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
dbName := "test_" + hex.EncodeToString(randBytes)
|
|
||||||
|
|
||||||
t.Logf("Creating new Postgres DB '%s' for testing", dbName)
|
|
||||||
|
|
||||||
_, err = fixture.db.ExecContext(
|
|
||||||
context.Background(), "CREATE DATABASE "+dbName,
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
cfg := fixture.GetConfig(dbName)
|
|
||||||
store, err := NewPostgresStore(cfg)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
return store
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,7 +1,12 @@
|
|||||||
|
//go:build !js && !(windows && (arm || 386)) && !(linux && (ppc64 || mips || mipsle || mips64)) && !(netbsd || openbsd)
|
||||||
|
|
||||||
package sqldb
|
package sqldb
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
|
"crypto/rand"
|
||||||
"database/sql"
|
"database/sql"
|
||||||
|
"encoding/hex"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -118,3 +123,33 @@ func (f *TestPgFixture) TearDown(t *testing.T) {
|
|||||||
err := f.pool.Purge(f.resource)
|
err := f.pool.Purge(f.resource)
|
||||||
require.NoError(t, err, "Could not purge resource")
|
require.NoError(t, err, "Could not purge resource")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewTestPostgresDB is a helper function that creates a Postgres database for
|
||||||
|
// testing using the given fixture.
|
||||||
|
func NewTestPostgresDB(t *testing.T, fixture *TestPgFixture) *PostgresStore {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
// Create random database name.
|
||||||
|
randBytes := make([]byte, 8)
|
||||||
|
_, err := rand.Read(randBytes)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
dbName := "test_" + hex.EncodeToString(randBytes)
|
||||||
|
|
||||||
|
t.Logf("Creating new Postgres DB '%s' for testing", dbName)
|
||||||
|
|
||||||
|
_, err = fixture.db.ExecContext(
|
||||||
|
context.Background(), "CREATE DATABASE "+dbName,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
cfg := fixture.GetConfig(dbName)
|
||||||
|
store, err := NewPostgresStore(cfg)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
return store
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
//go:build !js && !(windows && (arm || 386)) && !(linux && (ppc64 || mips || mipsle || mips64))
|
||||||
|
|
||||||
package sqldb
|
package sqldb
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|||||||
86
sqldb/sqlerrors_no_sqlite.go
Normal file
86
sqldb/sqlerrors_no_sqlite.go
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
//go:build js || (windows && (arm || 386)) || (linux && (ppc64 || mips || mipsle || mips64))
|
||||||
|
|
||||||
|
package sqldb
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/jackc/pgconn"
|
||||||
|
"github.com/jackc/pgerrcode"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// ErrRetriesExceeded is returned when a transaction is retried more
|
||||||
|
// than the max allowed valued without a success.
|
||||||
|
ErrRetriesExceeded = errors.New("db tx retries exceeded")
|
||||||
|
)
|
||||||
|
|
||||||
|
// MapSQLError attempts to interpret a given error as a database agnostic SQL
|
||||||
|
// error.
|
||||||
|
func MapSQLError(err error) error {
|
||||||
|
// Attempt to interpret the error as a postgres error.
|
||||||
|
var pqErr *pgconn.PgError
|
||||||
|
if errors.As(err, &pqErr) {
|
||||||
|
return parsePostgresError(pqErr)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return original error if it could not be classified as a database
|
||||||
|
// specific error.
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// parsePostgresError attempts to parse a postgres error as a database agnostic
|
||||||
|
// SQL error.
|
||||||
|
func parsePostgresError(pqErr *pgconn.PgError) error {
|
||||||
|
switch pqErr.Code {
|
||||||
|
// Handle unique constraint violation error.
|
||||||
|
case pgerrcode.UniqueViolation:
|
||||||
|
return &ErrSQLUniqueConstraintViolation{
|
||||||
|
DBError: pqErr,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unable to serialize the transaction, so we'll need to try again.
|
||||||
|
case pgerrcode.SerializationFailure:
|
||||||
|
return &ErrSerializationError{
|
||||||
|
DBError: pqErr,
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("unknown postgres error: %w", pqErr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrSQLUniqueConstraintViolation is an error type which represents a database
|
||||||
|
// agnostic SQL unique constraint violation.
|
||||||
|
type ErrSQLUniqueConstraintViolation struct {
|
||||||
|
DBError error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e ErrSQLUniqueConstraintViolation) Error() string {
|
||||||
|
return fmt.Sprintf("sql unique constraint violation: %v", e.DBError)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrSerializationError is an error type which represents a database agnostic
|
||||||
|
// error that a transaction couldn't be serialized with other concurrent db
|
||||||
|
// transactions.
|
||||||
|
type ErrSerializationError struct {
|
||||||
|
DBError error
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unwrap returns the wrapped error.
|
||||||
|
func (e ErrSerializationError) Unwrap() error {
|
||||||
|
return e.DBError
|
||||||
|
}
|
||||||
|
|
||||||
|
// Error returns the error message.
|
||||||
|
func (e ErrSerializationError) Error() string {
|
||||||
|
return e.DBError.Error()
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsSerializationError returns true if the given error is a serialization
|
||||||
|
// error.
|
||||||
|
func IsSerializationError(err error) bool {
|
||||||
|
var serializationError *ErrSerializationError
|
||||||
|
return errors.As(err, &serializationError)
|
||||||
|
}
|
||||||
@@ -1,3 +1,5 @@
|
|||||||
|
//go:build !js && !(windows && (arm || 386)) && !(linux && (ppc64 || mips || mipsle || mips64))
|
||||||
|
|
||||||
package sqldb
|
package sqldb
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@@ -6,7 +8,6 @@ import (
|
|||||||
"net/url"
|
"net/url"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
|
||||||
|
|
||||||
sqlite_migrate "github.com/golang-migrate/migrate/v4/database/sqlite"
|
sqlite_migrate "github.com/golang-migrate/migrate/v4/database/sqlite"
|
||||||
"github.com/lightningnetwork/lnd/sqldb/sqlc"
|
"github.com/lightningnetwork/lnd/sqldb/sqlc"
|
||||||
@@ -23,30 +24,8 @@ const (
|
|||||||
// sqliteTxLockImmediate is a dsn option used to ensure that write
|
// sqliteTxLockImmediate is a dsn option used to ensure that write
|
||||||
// transactions are started immediately.
|
// transactions are started immediately.
|
||||||
sqliteTxLockImmediate = "_txlock=immediate"
|
sqliteTxLockImmediate = "_txlock=immediate"
|
||||||
|
|
||||||
// defaultMaxConns is the number of permitted active and idle
|
|
||||||
// connections. We want to limit this so it isn't unlimited. We use the
|
|
||||||
// same value for the number of idle connections as, this can speed up
|
|
||||||
// queries given a new connection doesn't need to be established each
|
|
||||||
// time.
|
|
||||||
defaultMaxConns = 25
|
|
||||||
|
|
||||||
// connIdleLifetime is the amount of time a connection can be idle.
|
|
||||||
connIdleLifetime = 5 * time.Minute
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// SqliteConfig holds all the config arguments needed to interact with our
|
|
||||||
// sqlite DB.
|
|
||||||
//
|
|
||||||
//nolint:lll
|
|
||||||
type SqliteConfig struct {
|
|
||||||
Timeout time.Duration `long:"timeout" description:"The time after which a database query should be timed out."`
|
|
||||||
BusyTimeout time.Duration `long:"busytimeout" description:"The maximum amount of time to wait for a database connection to become available for a query."`
|
|
||||||
MaxConnections int `long:"maxconnections" description:"The maximum number of open connections to the database. Set to zero for unlimited."`
|
|
||||||
PragmaOptions []string `long:"pragmaoptions" description:"A list of pragma options to set on a database connection. For example, 'auto_vacuum=incremental'. Note that the flag must be specified multiple times if multiple options are to be set."`
|
|
||||||
SkipMigrations bool `long:"skipmigrations" description:"Skip applying migrations on startup."`
|
|
||||||
}
|
|
||||||
|
|
||||||
// SqliteStore is a database store implementation that uses a sqlite backend.
|
// SqliteStore is a database store implementation that uses a sqlite backend.
|
||||||
type SqliteStore struct {
|
type SqliteStore struct {
|
||||||
cfg *SqliteConfig
|
cfg *SqliteConfig
|
||||||
|
|||||||
Reference in New Issue
Block a user