db.go
1 //go:build kvdb_sqlite && !(windows && (arm || 386)) && !(linux && (ppc64 || mips || mipsle || mips64)) 2 3 package sqlite 4 5 import ( 6 "context" 7 "fmt" 8 "net/url" 9 "path/filepath" 10 11 "github.com/btcsuite/btcwallet/walletdb" 12 "github.com/lightningnetwork/lnd/kvdb/sqlbase" 13 _ "modernc.org/sqlite" // Register relevant drivers. 14 ) 15 16 const ( 17 // sqliteOptionPrefix is the string prefix sqlite uses to set various 18 // options. This is used in the following format: 19 // * sqliteOptionPrefix || option_name = option_value. 20 sqliteOptionPrefix = "_pragma" 21 22 // sqliteTxLockImmediate is a dsn option used to ensure that write 23 // transactions are started immediately. 24 sqliteTxLockImmediate = "_txlock=immediate" 25 ) 26 27 // pragmaOption holds a key-value pair for a SQLite pragma setting. 28 type pragmaOption struct { 29 name string 30 value string 31 } 32 33 // NewSqliteBackend returns a db object initialized with the passed backend 34 // config. If a sqlite connection cannot be established, then an error is 35 // returned. 36 func NewSqliteBackend(ctx context.Context, cfg *Config, dbPath, fileName, 37 prefix string) (walletdb.DB, error) { 38 39 // First, we add a set of mandatory pragma options to the query. 40 pragmaOptions := []pragmaOption{ 41 { 42 name: "busy_timeout", 43 value: fmt.Sprintf( 44 "%d", cfg.BusyTimeout.Milliseconds(), 45 ), 46 }, 47 { 48 name: "foreign_keys", 49 value: "on", 50 }, 51 { 52 name: "journal_mode", 53 value: "WAL", 54 }, 55 { 56 name: "auto_vacuum", 57 value: "incremental", 58 }, 59 } 60 61 sqliteOptions := make(url.Values) 62 for _, option := range pragmaOptions { 63 sqliteOptions.Add( 64 sqliteOptionPrefix, 65 fmt.Sprintf("%v=%v", option.name, option.value), 66 ) 67 } 68 69 // Then we add any user specified pragma options. Note that these can 70 // be of the form: "key=value", "key(N)" or "key". 71 for _, option := range cfg.PragmaOptions { 72 sqliteOptions.Add(sqliteOptionPrefix, option) 73 } 74 75 // Construct the DSN which is just the database file name, appended 76 // with the series of pragma options as a query URL string. For more 77 // details on the formatting here, see the modernc.org/sqlite docs: 78 // https://pkg.go.dev/modernc.org/sqlite#Driver.Open. 79 dsn := fmt.Sprintf( 80 "%v?%v&%v", filepath.Join(dbPath, fileName), 81 sqliteOptions.Encode(), sqliteTxLockImmediate, 82 ) 83 sqlCfg := &sqlbase.Config{ 84 DriverName: "sqlite", 85 Dsn: dsn, 86 Timeout: cfg.Timeout, 87 TableNamePrefix: prefix, 88 } 89 90 return sqlbase.NewSqlBackend(ctx, sqlCfg) 91 }