Merge pull request #714 from yyforyongyu/add-bdb-timeout

bdb: Add timeout options for bbolt
This commit is contained in:
Olaoluwa Osuntokun 2020-11-18 18:28:10 -08:00 committed by GitHub
commit 664f77ded1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
18 changed files with 204 additions and 70 deletions

View file

@ -69,7 +69,9 @@ func walletMain() error {
} }
dbDir := networkDir(cfg.AppDataDir.Value, activeNet.Params) dbDir := networkDir(cfg.AppDataDir.Value, activeNet.Params)
loader := wallet.NewLoader(activeNet.Params, dbDir, true, 250) loader := wallet.NewLoader(
activeNet.Params, dbDir, true, cfg.DBTimeout, 250,
)
// Create and start HTTP server to serve wallet client connections. // Create and start HTTP server to serve wallet client connections.
// This will be updated with the wallet and chain server RPC client // This will be updated with the wallet and chain server RPC client
@ -160,8 +162,10 @@ func rpcClientConnectLoop(legacyRPCServer *legacyrpc.Server, loader *wallet.Load
spvdb walletdb.DB spvdb walletdb.DB
) )
netDir := networkDir(cfg.AppDataDir.Value, activeNet.Params) netDir := networkDir(cfg.AppDataDir.Value, activeNet.Params)
spvdb, err = walletdb.Create("bdb", spvdb, err = walletdb.Create(
filepath.Join(netDir, "neutrino.db"), true) "bdb", filepath.Join(netDir, "neutrino.db"),
true, cfg.DBTimeout,
)
defer spvdb.Close() defer spvdb.Close()
if err != nil { if err != nil {
log.Errorf("Unable to create Neutrino DB: %s", err) log.Errorf("Unable to create Neutrino DB: %s", err)

View file

@ -9,6 +9,7 @@ import (
"fmt" "fmt"
"os" "os"
"path/filepath" "path/filepath"
"time"
"github.com/btcsuite/btcutil" "github.com/btcsuite/btcutil"
"github.com/btcsuite/btcwallet/wallet" "github.com/btcsuite/btcwallet/wallet"
@ -19,16 +20,20 @@ import (
const defaultNet = "mainnet" const defaultNet = "mainnet"
var datadir = btcutil.AppDataDir("btcwallet", false) var (
datadir = btcutil.AppDataDir("btcwallet", false)
)
// Flags. // Flags.
var opts = struct { var opts = struct {
Force bool `short:"f" description:"Force removal without prompt"` Force bool `short:"f" description:"Force removal without prompt"`
DbPath string `long:"db" description:"Path to wallet database"` DbPath string `long:"db" description:"Path to wallet database"`
DropLabels bool `long:"droplabels" description:"Drop transaction labels"` DropLabels bool `long:"droplabels" description:"Drop transaction labels"`
Timeout time.Duration `long:"timeout" description:"Timeout value when opening the wallet database"`
}{ }{
Force: false, Force: false,
DbPath: filepath.Join(datadir, defaultNet, "wallet.db"), DbPath: filepath.Join(datadir, defaultNet, wallet.WalletDBName),
Timeout: wallet.DefaultDBTimeout,
} }
func init() { func init() {
@ -93,7 +98,7 @@ func mainInt() int {
fmt.Println("Enter yes or no.") fmt.Println("Enter yes or no.")
} }
db, err := walletdb.Open("bdb", opts.DbPath, true) db, err := walletdb.Open("bdb", opts.DbPath, true, opts.Timeout)
if err != nil { if err != nil {
fmt.Println("Failed to open database:", err) fmt.Println("Failed to open database:", err)
return 1 return 1

View file

@ -32,8 +32,6 @@ const (
defaultLogFilename = "btcwallet.log" defaultLogFilename = "btcwallet.log"
defaultRPCMaxClients = 10 defaultRPCMaxClients = 10
defaultRPCMaxWebsockets = 25 defaultRPCMaxWebsockets = 25
walletDbName = "wallet.db"
) )
var ( var (
@ -58,6 +56,7 @@ type config struct {
DebugLevel string `short:"d" long:"debuglevel" description:"Logging level {trace, debug, info, warn, error, critical}"` DebugLevel string `short:"d" long:"debuglevel" description:"Logging level {trace, debug, info, warn, error, critical}"`
LogDir string `long:"logdir" description:"Directory to log output."` LogDir string `long:"logdir" description:"Directory to log output."`
Profile string `long:"profile" description:"Enable HTTP profiling on given port -- NOTE port must be between 1024 and 65536"` Profile string `long:"profile" description:"Enable HTTP profiling on given port -- NOTE port must be between 1024 and 65536"`
DBTimeout time.Duration `long:"dbtimeout" description:"The timeout value to use when opening the wallet database."`
// Wallet options // Wallet options
WalletPass string `long:"walletpass" default-mask:"-" description:"The public wallet password -- Only required if the wallet was created with one"` WalletPass string `long:"walletpass" default-mask:"-" description:"The public wallet password -- Only required if the wallet was created with one"`
@ -273,6 +272,7 @@ func loadConfig() (*config, []string, error) {
MaxPeers: neutrino.MaxPeers, MaxPeers: neutrino.MaxPeers,
BanDuration: neutrino.BanDuration, BanDuration: neutrino.BanDuration,
BanThreshold: neutrino.BanThreshold, BanThreshold: neutrino.BanThreshold,
DBTimeout: wallet.DefaultDBTimeout,
} }
// Pre-parse the command line options to see if an alternative config // Pre-parse the command line options to see if an alternative config
@ -415,7 +415,7 @@ func loadConfig() (*config, []string, error) {
// Ensure the wallet exists or create it when the create flag is set. // Ensure the wallet exists or create it when the create flag is set.
netDir := networkDir(cfg.AppDataDir.Value, activeNet.Params) netDir := networkDir(cfg.AppDataDir.Value, activeNet.Params)
dbPath := filepath.Join(netDir, walletDbName) dbPath := filepath.Join(netDir, wallet.WalletDBName)
if cfg.CreateTemp && cfg.Create { if cfg.CreateTemp && cfg.Create {
err := fmt.Errorf("The flags --create and --createtemp can not " + err := fmt.Errorf("The flags --create and --createtemp can not " +

View file

@ -200,6 +200,10 @@ var (
// expectedInternalAddrs is the list of expected internal addresses // expectedInternalAddrs is the list of expected internal addresses
// generated from the seed // generated from the seed
expectedInternalAddrs = expectedAddrs[5:] expectedInternalAddrs = expectedAddrs[5:]
// defaultDBTimeout specifies the timeout value when opening the wallet
// database.
defaultDBTimeout = 10 * time.Second
) )
// checkManagerError ensures the passed error is a ManagerError with an error // checkManagerError ensures the passed error is a ManagerError with an error
@ -238,7 +242,7 @@ func emptyDB(t *testing.T) (tearDownFunc func(), db walletdb.DB) {
t.Fatalf("Failed to create db temp dir: %v", err) t.Fatalf("Failed to create db temp dir: %v", err)
} }
dbPath := filepath.Join(dirName, "mgrtest.db") dbPath := filepath.Join(dirName, "mgrtest.db")
db, err = walletdb.Create("bdb", dbPath, true) db, err = walletdb.Create("bdb", dbPath, true, defaultDBTimeout)
if err != nil { if err != nil {
_ = os.RemoveAll(dirName) _ = os.RemoveAll(dirName)
t.Fatalf("createDbNamespace: unexpected error: %v", err) t.Fatalf("createDbNamespace: unexpected error: %v", err)
@ -259,7 +263,7 @@ func setupManager(t *testing.T) (tearDownFunc func(), db walletdb.DB, mgr *Manag
t.Fatalf("Failed to create db temp dir: %v", err) t.Fatalf("Failed to create db temp dir: %v", err)
} }
dbPath := filepath.Join(dirName, "mgrtest.db") dbPath := filepath.Join(dirName, "mgrtest.db")
db, err = walletdb.Create("bdb", dbPath, true) db, err = walletdb.Create("bdb", dbPath, true, defaultDBTimeout)
if err != nil { if err != nil {
_ = os.RemoveAll(dirName) _ = os.RemoveAll(dirName)
t.Fatalf("createDbNamespace: unexpected error: %v", err) t.Fatalf("createDbNamespace: unexpected error: %v", err)

View file

@ -1683,7 +1683,7 @@ func testConvertWatchingOnly(tc *testContext) bool {
defer os.Remove(woMgrName) defer os.Remove(woMgrName)
// Open the new database copy and get the address manager namespace. // Open the new database copy and get the address manager namespace.
db, err := walletdb.Open("bdb", woMgrName, true) db, err := walletdb.Open("bdb", woMgrName, true, defaultDBTimeout)
if err != nil { if err != nil {
tc.t.Errorf("openDbNamespace: unexpected error: %v", err) tc.t.Errorf("openDbNamespace: unexpected error: %v", err)
return false return false

View file

@ -10,6 +10,10 @@ import (
"github.com/btcsuite/btcutil/hdkeychain" "github.com/btcsuite/btcutil/hdkeychain"
) )
// defaultDBTimeout specifies the timeout value when opening the wallet
// database.
var defaultDBTimeout = 10 * time.Second
// testWallet creates a test wallet and unlocks it. // testWallet creates a test wallet and unlocks it.
func testWallet(t *testing.T) (*Wallet, func()) { func testWallet(t *testing.T) (*Wallet, func()) {
// Set up a wallet. // Set up a wallet.
@ -32,7 +36,9 @@ func testWallet(t *testing.T) (*Wallet, func()) {
pubPass := []byte("hello") pubPass := []byte("hello")
privPass := []byte("world") privPass := []byte("world")
loader := NewLoader(&chaincfg.TestNet3Params, dir, true, 250) loader := NewLoader(
&chaincfg.TestNet3Params, dir, true, defaultDBTimeout, 250,
)
w, err := loader.CreateNewWallet(pubPass, privPass, seed, time.Now()) w, err := loader.CreateNewWallet(pubPass, privPass, seed, time.Now())
if err != nil { if err != nil {
t.Fatalf("unable to create wallet: %v", err) t.Fatalf("unable to create wallet: %v", err)

View file

@ -18,7 +18,12 @@ import (
) )
const ( const (
walletDbName = "wallet.db" // WalletDBName specified the database filename for the wallet.
WalletDBName = "wallet.db"
// DefaultDBTimeout is the default timeout value when opening the wallet
// database.
DefaultDBTimeout = 60 * time.Second
) )
var ( var (
@ -47,6 +52,7 @@ type Loader struct {
chainParams *chaincfg.Params chainParams *chaincfg.Params
dbDirPath string dbDirPath string
noFreelistSync bool noFreelistSync bool
timeout time.Duration
recoveryWindow uint32 recoveryWindow uint32
wallet *Wallet wallet *Wallet
db walletdb.DB db walletdb.DB
@ -57,12 +63,14 @@ type Loader struct {
// recovery window is non-zero, the wallet will attempt to recovery addresses // recovery window is non-zero, the wallet will attempt to recovery addresses
// starting from the last SyncedTo height. // starting from the last SyncedTo height.
func NewLoader(chainParams *chaincfg.Params, dbDirPath string, func NewLoader(chainParams *chaincfg.Params, dbDirPath string,
noFreelistSync bool, recoveryWindow uint32) *Loader { noFreelistSync bool, timeout time.Duration,
recoveryWindow uint32) *Loader {
return &Loader{ return &Loader{
chainParams: chainParams, chainParams: chainParams,
dbDirPath: dbDirPath, dbDirPath: dbDirPath,
noFreelistSync: noFreelistSync, noFreelistSync: noFreelistSync,
timeout: timeout,
recoveryWindow: recoveryWindow, recoveryWindow: recoveryWindow,
} }
} }
@ -126,7 +134,7 @@ func (l *Loader) createNewWallet(pubPassphrase, privPassphrase,
return nil, ErrLoaded return nil, ErrLoaded
} }
dbPath := filepath.Join(l.dbDirPath, walletDbName) dbPath := filepath.Join(l.dbDirPath, WalletDBName)
exists, err := fileExists(dbPath) exists, err := fileExists(dbPath)
if err != nil { if err != nil {
return nil, err return nil, err
@ -140,7 +148,7 @@ func (l *Loader) createNewWallet(pubPassphrase, privPassphrase,
if err != nil { if err != nil {
return nil, err return nil, err
} }
db, err := walletdb.Create("bdb", dbPath, l.noFreelistSync) db, err := walletdb.Create("bdb", dbPath, l.noFreelistSync, l.timeout)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -195,8 +203,8 @@ func (l *Loader) OpenExistingWallet(pubPassphrase []byte, canConsolePrompt bool)
} }
// Open the database using the boltdb backend. // Open the database using the boltdb backend.
dbPath := filepath.Join(l.dbDirPath, walletDbName) dbPath := filepath.Join(l.dbDirPath, WalletDBName)
db, err := walletdb.Open("bdb", dbPath, l.noFreelistSync) db, err := walletdb.Open("bdb", dbPath, l.noFreelistSync, l.timeout)
if err != nil { if err != nil {
log.Errorf("Failed to open database: %v", err) log.Errorf("Failed to open database: %v", err)
return nil, err return nil, err
@ -234,7 +242,7 @@ func (l *Loader) OpenExistingWallet(pubPassphrase []byte, canConsolePrompt bool)
// WalletExists returns whether a file exists at the loader's database path. // WalletExists returns whether a file exists at the loader's database path.
// This may return an error for unexpected I/O failures. // This may return an error for unexpected I/O failures.
func (l *Loader) WalletExists() (bool, error) { func (l *Loader) WalletExists() (bool, error) {
dbPath := filepath.Join(l.dbDirPath, walletDbName) dbPath := filepath.Join(l.dbDirPath, WalletDBName)
return fileExists(dbPath) return fileExists(dbPath)
} }

View file

@ -26,7 +26,9 @@ func TestCreateWatchingOnly(t *testing.T) {
pubPass := []byte("hello") pubPass := []byte("hello")
loader := NewLoader(&chaincfg.TestNet3Params, dir, true, 250) loader := NewLoader(
&chaincfg.TestNet3Params, dir, true, defaultDBTimeout, 250,
)
_, err = loader.CreateNewWatchingOnlyWallet(pubPass, time.Now()) _, err = loader.CreateNewWatchingOnlyWallet(pubPass, time.Now())
if err != nil { if err != nil {
t.Fatalf("unable to create wallet: %v", err) t.Fatalf("unable to create wallet: %v", err)

View file

@ -10,19 +10,20 @@ datastore. Package bdb is licensed under the copyfree ISC license.
## Usage ## Usage
This package is only a driver to the walletdb package and provides the database This package is only a driver to the walletdb package and provides the database
type of "bdb". The only parameters the Open and Create functions take is the type of "bdb". The only parameters the Open and Create functions take are the
database path as a string, and an option for the database to not sync its database path as a string, an option for the database to not sync its freelist
freelist to disk as a bool: to disk as a bool, and a timeout value for opening the database as a
time.Duration:
```Go ```Go
db, err := walletdb.Open("bdb", "path/to/database.db", true) db, err := walletdb.Open("bdb", "path/to/database.db", true, 60*time.Second)
if err != nil { if err != nil {
// Handle error // Handle error
} }
``` ```
```Go ```Go
db, err := walletdb.Create("bdb", "path/to/database.db", true) db, err := walletdb.Create("bdb", "path/to/database.db", true, 60*time.Second)
if err != nil { if err != nil {
// Handle error // Handle error
} }

View file

@ -7,6 +7,7 @@ package bdb
import ( import (
"io" "io"
"os" "os"
"time"
"github.com/btcsuite/btcwallet/walletdb" "github.com/btcsuite/btcwallet/walletdb"
"go.etcd.io/bbolt" "go.etcd.io/bbolt"
@ -367,7 +368,9 @@ func fileExists(name string) bool {
// openDB opens the database at the provided path. walletdb.ErrDbDoesNotExist // openDB opens the database at the provided path. walletdb.ErrDbDoesNotExist
// is returned if the database doesn't exist and the create flag is not set. // is returned if the database doesn't exist and the create flag is not set.
func openDB(dbPath string, noFreelistSync bool, create bool) (walletdb.DB, error) { func openDB(dbPath string, noFreelistSync bool,
create bool, timeout time.Duration) (walletdb.DB, error) {
if !create && !fileExists(dbPath) { if !create && !fileExists(dbPath) {
return nil, walletdb.ErrDbDoesNotExist return nil, walletdb.ErrDbDoesNotExist
} }
@ -377,6 +380,7 @@ func openDB(dbPath string, noFreelistSync bool, create bool) (walletdb.DB, error
options := &bbolt.Options{ options := &bbolt.Options{
NoFreelistSync: noFreelistSync, NoFreelistSync: noFreelistSync,
FreelistType: bbolt.FreelistMapType, FreelistType: bbolt.FreelistMapType,
Timeout: timeout,
} }
boltDB, err := bbolt.Open(dbPath, 0600, options) boltDB, err := bbolt.Open(dbPath, 0600, options)

View file

@ -9,16 +9,17 @@ datastore.
Usage Usage
This package is only a driver to the walletdb package and provides the database This package is only a driver to the walletdb package and provides the database
type of "bdb". The only parameters the Open and Create functions take is the type of "bdb". The only parameters the Open and Create functions take are the
database path as a string, and an option for the database to not sync its database path as a string, an option for the database to not sync its freelist
freelist to disk as a bool: to disk as a bool, and a timeout value for opening the database as a
time.Duration:
db, err := walletdb.Open("bdb", "path/to/database.db", true) db, err := walletdb.Open("bdb", "path/to/database.db", true, 60*time.Second)
if err != nil { if err != nil {
// Handle error // Handle error
} }
db, err := walletdb.Create("bdb", "path/to/database.db", true) db, err := walletdb.Create("bdb", "path/to/database.db", true, 60*time.Second)
if err != nil { if err != nil {
// Handle error // Handle error
} }

View file

@ -6,6 +6,7 @@ package bdb
import ( import (
"fmt" "fmt"
"time"
"github.com/btcsuite/btcwallet/walletdb" "github.com/btcsuite/btcwallet/walletdb"
) )
@ -15,50 +16,60 @@ const (
) )
// parseArgs parses the arguments from the walletdb Open/Create methods. // parseArgs parses the arguments from the walletdb Open/Create methods.
func parseArgs(funcName string, args ...interface{}) (string, bool, error) { func parseArgs(funcName string,
if len(args) != 2 { args ...interface{}) (string, bool, time.Duration, error) {
return "", false, fmt.Errorf("invalid arguments to %s.%s -- "+
"expected database path and no-freelist-sync option", if len(args) != 3 {
return "", false, 0, fmt.Errorf("invalid arguments to %s.%s "+
"-- expected database path, no-freelist-sync and "+
"timeout option",
dbType, funcName) dbType, funcName)
} }
dbPath, ok := args[0].(string) dbPath, ok := args[0].(string)
if !ok { if !ok {
return "", false, fmt.Errorf("first argument to %s.%s is "+ return "", false, 0, fmt.Errorf("first argument to %s.%s is "+
"invalid -- expected database path string", dbType, "invalid -- expected database path string", dbType,
funcName) funcName)
} }
noFreelistSync, ok := args[1].(bool) noFreelistSync, ok := args[1].(bool)
if !ok { if !ok {
return "", false, fmt.Errorf("second argument to %s.%s is "+ return "", false, 0, fmt.Errorf("second argument to %s.%s is "+
"invalid -- expected no-freelist-sync bool", dbType, "invalid -- expected no-freelist-sync bool", dbType,
funcName) funcName)
} }
return dbPath, noFreelistSync, nil timeout, ok := args[2].(time.Duration)
if !ok {
return "", false, 0, fmt.Errorf("third argument to %s.%s is "+
"invalid -- expected timeout time.Duration", dbType,
funcName)
}
return dbPath, noFreelistSync, timeout, nil
} }
// openDBDriver is the callback provided during driver registration that opens // openDBDriver is the callback provided during driver registration that opens
// an existing database for use. // an existing database for use.
func openDBDriver(args ...interface{}) (walletdb.DB, error) { func openDBDriver(args ...interface{}) (walletdb.DB, error) {
dbPath, noFreelistSync, err := parseArgs("Open", args...) dbPath, noFreelistSync, timeout, err := parseArgs("Open", args...)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return openDB(dbPath, noFreelistSync, false) return openDB(dbPath, noFreelistSync, false, timeout)
} }
// createDBDriver is the callback provided during driver registration that // createDBDriver is the callback provided during driver registration that
// creates, initializes, and opens a database for use. // creates, initializes, and opens a database for use.
func createDBDriver(args ...interface{}) (walletdb.DB, error) { func createDBDriver(args ...interface{}) (walletdb.DB, error) {
dbPath, noFreelistSync, err := parseArgs("Create", args...) dbPath, noFreelistSync, timeout, err := parseArgs("Create", args...)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return openDB(dbPath, noFreelistSync, true) return openDB(dbPath, noFreelistSync, true, timeout)
} }
func init() { func init() {

View file

@ -11,13 +11,19 @@ import (
"path/filepath" "path/filepath"
"reflect" "reflect"
"testing" "testing"
"time"
"github.com/btcsuite/btcwallet/walletdb" "github.com/btcsuite/btcwallet/walletdb"
_ "github.com/btcsuite/btcwallet/walletdb/bdb" _ "github.com/btcsuite/btcwallet/walletdb/bdb"
) )
// dbType is the database type name for this driver. const (
const dbType = "bdb" // dbType is the database type name for this driver.
dbType = "bdb"
// defaultDBTimeout is the value of db timeout for testing.
defaultDBTimeout = 10 * time.Second
)
// TestCreateOpenFail ensures that errors related to creating and opening a // TestCreateOpenFail ensures that errors related to creating and opening a
// database are handled properly. // database are handled properly.
@ -25,7 +31,10 @@ func TestCreateOpenFail(t *testing.T) {
// Ensure that attempting to open a database that doesn't exist returns // Ensure that attempting to open a database that doesn't exist returns
// the expected error. // the expected error.
wantErr := walletdb.ErrDbDoesNotExist wantErr := walletdb.ErrDbDoesNotExist
if _, err := walletdb.Open(dbType, "noexist.db", true); err != wantErr { if _, err := walletdb.Open(
dbType, "noexist.db", true, defaultDBTimeout,
); err != wantErr {
t.Errorf("Open: did not receive expected error - got %v, "+ t.Errorf("Open: did not receive expected error - got %v, "+
"want %v", err, wantErr) "want %v", err, wantErr)
return return
@ -34,8 +43,11 @@ func TestCreateOpenFail(t *testing.T) {
// Ensure that attempting to open a database with the wrong number of // Ensure that attempting to open a database with the wrong number of
// parameters returns the expected error. // parameters returns the expected error.
wantErr = fmt.Errorf("invalid arguments to %s.Open -- expected "+ wantErr = fmt.Errorf("invalid arguments to %s.Open -- expected "+
"database path and no-freelist-sync option", dbType) "database path, no-freelist-sync and timeout option", dbType)
if _, err := walletdb.Open(dbType, 1, 2, 3); err.Error() != wantErr.Error() { if _, err := walletdb.Open(
dbType, 1, 2, 3, 4,
); err.Error() != wantErr.Error() {
t.Errorf("Open: did not receive expected error - got %v, "+ t.Errorf("Open: did not receive expected error - got %v, "+
"want %v", err, wantErr) "want %v", err, wantErr)
return return
@ -45,7 +57,36 @@ func TestCreateOpenFail(t *testing.T) {
// the first parameter returns the expected error. // the first parameter returns the expected error.
wantErr = fmt.Errorf("first argument to %s.Open is invalid -- "+ wantErr = fmt.Errorf("first argument to %s.Open is invalid -- "+
"expected database path string", dbType) "expected database path string", dbType)
if _, err := walletdb.Open(dbType, 1, true); err.Error() != wantErr.Error() { if _, err := walletdb.Open(
dbType, 1, true, defaultDBTimeout,
); err.Error() != wantErr.Error() {
t.Errorf("Open: did not receive expected error - got %v, "+
"want %v", err, wantErr)
return
}
// Ensure that attempting to open a database with an invalid type for
// the second parameter returns the expected error.
wantErr = fmt.Errorf("second argument to %s.Open is invalid -- "+
"expected no-freelist-sync bool", dbType)
if _, err := walletdb.Open(
dbType, "noexist.db", 1, defaultDBTimeout,
); err.Error() != wantErr.Error() {
t.Errorf("Open: did not receive expected error - got %v, "+
"want %v", err, wantErr)
return
}
// Ensure that attempting to open a database with an invalid type for
// the third parameter returns the expected error.
wantErr = fmt.Errorf("third argument to %s.Open is invalid -- "+
"expected timeout time.Duration", dbType)
if _, err := walletdb.Open(
dbType, "noexist.db", true, 1,
); err.Error() != wantErr.Error() {
t.Errorf("Open: did not receive expected error - got %v, "+ t.Errorf("Open: did not receive expected error - got %v, "+
"want %v", err, wantErr) "want %v", err, wantErr)
return return
@ -54,18 +95,50 @@ func TestCreateOpenFail(t *testing.T) {
// Ensure that attempting to create a database with the wrong number of // Ensure that attempting to create a database with the wrong number of
// parameters returns the expected error. // parameters returns the expected error.
wantErr = fmt.Errorf("invalid arguments to %s.Create -- expected "+ wantErr = fmt.Errorf("invalid arguments to %s.Create -- expected "+
"database path and no-freelist-sync option", dbType) "database path, no-freelist-sync and timeout option", dbType)
if _, err := walletdb.Create(dbType, 1, 2, 3); err.Error() != wantErr.Error() { if _, err := walletdb.Create(
dbType, 1, 2, 3, 4,
); err.Error() != wantErr.Error() {
t.Errorf("Create: did not receive expected error - got %v, "+ t.Errorf("Create: did not receive expected error - got %v, "+
"want %v", err, wantErr) "want %v", err, wantErr)
return return
} }
// Ensure that attempting to open a database with an invalid type for // Ensure that attempting to create a database with an invalid type for
// the first parameter returns the expected error. // the first parameter returns the expected error.
wantErr = fmt.Errorf("first argument to %s.Create is invalid -- "+ wantErr = fmt.Errorf("first argument to %s.Create is invalid -- "+
"expected database path string", dbType) "expected database path string", dbType)
if _, err := walletdb.Create(dbType, 1, true); err.Error() != wantErr.Error() { if _, err := walletdb.Create(
dbType, 1, true, defaultDBTimeout,
); err.Error() != wantErr.Error() {
t.Errorf("Create: did not receive expected error - got %v, "+
"want %v", err, wantErr)
return
}
// Ensure that attempting to create a database with an invalid type for
// the second parameter returns the expected error.
wantErr = fmt.Errorf("second argument to %s.Create is invalid -- "+
"expected no-freelist-sync bool", dbType)
if _, err := walletdb.Create(
dbType, "noexist.db", 1, defaultDBTimeout,
); err.Error() != wantErr.Error() {
t.Errorf("Create: did not receive expected error - got %v, "+
"want %v", err, wantErr)
return
}
// Ensure that attempting to create a database with an invalid type for
// the third parameter returns the expected error.
wantErr = fmt.Errorf("third argument to %s.Create is invalid -- "+
"expected timeout time.Duration", dbType)
if _, err := walletdb.Create(
dbType, "noexist.db", true, 1,
); err.Error() != wantErr.Error() {
t.Errorf("Create: did not receive expected error - got %v, "+ t.Errorf("Create: did not receive expected error - got %v, "+
"want %v", err, wantErr) "want %v", err, wantErr)
return return
@ -81,7 +154,7 @@ func TestCreateOpenFail(t *testing.T) {
defer os.Remove(tempDir) defer os.Remove(tempDir)
dbPath := filepath.Join(tempDir, "db") dbPath := filepath.Join(tempDir, "db")
db, err := walletdb.Create(dbType, dbPath, true) db, err := walletdb.Create(dbType, dbPath, true, defaultDBTimeout)
if err != nil { if err != nil {
t.Errorf("Create: unexpected error: %v", err) t.Errorf("Create: unexpected error: %v", err)
return return
@ -108,7 +181,7 @@ func TestPersistence(t *testing.T) {
defer os.Remove(tempDir) defer os.Remove(tempDir)
dbPath := filepath.Join(tempDir, "db") dbPath := filepath.Join(tempDir, "db")
db, err := walletdb.Create(dbType, dbPath, true) db, err := walletdb.Create(dbType, dbPath, true, defaultDBTimeout)
if err != nil { if err != nil {
t.Errorf("Failed to create test database (%s) %v", dbType, err) t.Errorf("Failed to create test database (%s) %v", dbType, err)
return return
@ -144,7 +217,7 @@ func TestPersistence(t *testing.T) {
// Close and reopen the database to ensure the values persist. // Close and reopen the database to ensure the values persist.
db.Close() db.Close()
db, err = walletdb.Open(dbType, dbPath, true) db, err = walletdb.Open(dbType, dbPath, true, defaultDBTimeout)
if err != nil { if err != nil {
t.Errorf("Failed to open test database (%s) %v", dbType, err) t.Errorf("Failed to open test database (%s) %v", dbType, err)
return return

View file

@ -32,5 +32,5 @@ func TestInterface(t *testing.T) {
dbPath := filepath.Join(tempDir, "db") dbPath := filepath.Join(tempDir, "db")
defer os.RemoveAll(dbPath) defer os.RemoveAll(dbPath)
walletdbtest.TestInterface(t, dbType, dbPath, true) walletdbtest.TestInterface(t, dbType, dbPath, true, defaultDBTimeout)
} }

View file

@ -10,6 +10,7 @@ import (
"os" "os"
"path/filepath" "path/filepath"
"testing" "testing"
"time"
"github.com/btcsuite/btcwallet/walletdb" "github.com/btcsuite/btcwallet/walletdb"
_ "github.com/btcsuite/btcwallet/walletdb/bdb" _ "github.com/btcsuite/btcwallet/walletdb/bdb"
@ -21,6 +22,10 @@ var (
// bogus drivers for testing purposes while still allowing other tests // bogus drivers for testing purposes while still allowing other tests
// to easily iterate all supported drivers. // to easily iterate all supported drivers.
ignoreDbTypes = map[string]bool{"createopenfail": true} ignoreDbTypes = map[string]bool{"createopenfail": true}
// defaultDBTimeout specifies the timeout value when opening the wallet
// database.
defaultDBTimeout = 10 * time.Second
) )
// TestAddDuplicateDriver ensures that adding a duplicate driver does not // TestAddDuplicateDriver ensures that adding a duplicate driver does not
@ -64,7 +69,7 @@ func TestAddDuplicateDriver(t *testing.T) {
defer os.Remove(tempDir) defer os.Remove(tempDir)
dbPath := filepath.Join(tempDir, "db") dbPath := filepath.Join(tempDir, "db")
db, err := walletdb.Create(dbType, dbPath, true) db, err := walletdb.Create(dbType, dbPath, true, defaultDBTimeout)
if err != nil { if err != nil {
t.Errorf("failed to create database: %v", err) t.Errorf("failed to create database: %v", err)
return return

View file

@ -28,7 +28,7 @@ func ExampleCreate() {
// this, but it's done here in the example to ensure the example cleans // this, but it's done here in the example to ensure the example cleans
// up after itself. // up after itself.
dbPath := filepath.Join(os.TempDir(), "examplecreate.db") dbPath := filepath.Join(os.TempDir(), "examplecreate.db")
db, err := walletdb.Create("bdb", dbPath, true) db, err := walletdb.Create("bdb", dbPath, true, defaultDBTimeout)
if err != nil { if err != nil {
fmt.Println(err) fmt.Println(err)
return return
@ -47,7 +47,7 @@ var exampleNum = 0
func exampleLoadDB() (walletdb.DB, func(), error) { func exampleLoadDB() (walletdb.DB, func(), error) {
dbName := fmt.Sprintf("exampleload%d.db", exampleNum) dbName := fmt.Sprintf("exampleload%d.db", exampleNum)
dbPath := filepath.Join(os.TempDir(), dbName) dbPath := filepath.Join(os.TempDir(), dbName)
db, err := walletdb.Create("bdb", dbPath, true) db, err := walletdb.Create("bdb", dbPath, true, defaultDBTimeout)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
@ -111,7 +111,7 @@ func Example_basicUsage() {
// this, but it's done here in the example to ensure the example cleans // this, but it's done here in the example to ensure the example cleans
// up after itself. // up after itself.
dbPath := filepath.Join(os.TempDir(), "exampleusage.db") dbPath := filepath.Join(os.TempDir(), "exampleusage.db")
db, err := walletdb.Create("bdb", dbPath, true) db, err := walletdb.Create("bdb", dbPath, true, defaultDBTimeout)
if err != nil { if err != nil {
fmt.Println(err) fmt.Println(err)
return return

View file

@ -102,7 +102,9 @@ func convertLegacyKeystore(legacyKeyStore *keystore.Store, w *wallet.Wallet) err
// provided path. // provided path.
func createWallet(cfg *config) error { func createWallet(cfg *config) error {
dbDir := networkDir(cfg.AppDataDir.Value, activeNet.Params) dbDir := networkDir(cfg.AppDataDir.Value, activeNet.Params)
loader := wallet.NewLoader(activeNet.Params, dbDir, true, 250) loader := wallet.NewLoader(
activeNet.Params, dbDir, true, cfg.DBTimeout, 250,
)
// When there is a legacy keystore, open it now to ensure any errors // When there is a legacy keystore, open it now to ensure any errors
// don't end up exiting the process after the user has spent time // don't end up exiting the process after the user has spent time
@ -215,11 +217,11 @@ func createSimulationWallet(cfg *config) error {
netDir := networkDir(cfg.AppDataDir.Value, activeNet.Params) netDir := networkDir(cfg.AppDataDir.Value, activeNet.Params)
// Create the wallet. // Create the wallet.
dbPath := filepath.Join(netDir, walletDbName) dbPath := filepath.Join(netDir, wallet.WalletDBName)
fmt.Println("Creating the wallet...") fmt.Println("Creating the wallet...")
// Create the wallet database backed by bolt db. // Create the wallet database backed by bolt db.
db, err := walletdb.Create("bdb", dbPath, true) db, err := walletdb.Create("bdb", dbPath, true, cfg.DBTimeout)
if err != nil { if err != nil {
return err return err
} }

View file

@ -45,6 +45,10 @@ var (
Block: Block{Hash: *TstSignedTxBlockHash, Height: TstSpendingTxBlockHeight}, Block: Block{Hash: *TstSignedTxBlockHash, Height: TstSpendingTxBlockHeight},
Time: time.Unix(1389114091, 0), Time: time.Unix(1389114091, 0),
} }
// defaultDBTimeout specifies the timeout value when opening the wallet
// database.
defaultDBTimeout = 10 * time.Second
) )
func testDB() (walletdb.DB, func(), error) { func testDB() (walletdb.DB, func(), error) {
@ -52,7 +56,9 @@ func testDB() (walletdb.DB, func(), error) {
if err != nil { if err != nil {
return nil, func() {}, err return nil, func() {}, err
} }
db, err := walletdb.Create("bdb", filepath.Join(tmpDir, "db"), true) db, err := walletdb.Create(
"bdb", filepath.Join(tmpDir, "db"), true, defaultDBTimeout,
)
return db, func() { os.RemoveAll(tmpDir) }, err return db, func() { os.RemoveAll(tmpDir) }, err
} }
@ -64,7 +70,9 @@ func testStore() (*Store, walletdb.DB, func(), error) {
return nil, nil, func() {}, err return nil, nil, func() {}, err
} }
db, err := walletdb.Create("bdb", filepath.Join(tmpDir, "db"), true) db, err := walletdb.Create(
"bdb", filepath.Join(tmpDir, "db"), true, defaultDBTimeout,
)
if err != nil { if err != nil {
os.RemoveAll(tmpDir) os.RemoveAll(tmpDir)
return nil, nil, nil, err return nil, nil, nil, err