diff --git a/walletdb/bdb/README.md b/walletdb/bdb/README.md index 67ae35f..0d7db3f 100644 --- a/walletdb/bdb/README.md +++ b/walletdb/bdb/README.md @@ -10,19 +10,20 @@ datastore. Package bdb is licensed under the copyfree ISC license. ## Usage 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 -database path as a string, and an option for the database to not sync its -freelist to disk as a bool: +type of "bdb". The only parameters the Open and Create functions take are the +database path as a string, an option for the database to not sync its freelist +to disk as a bool, and a timeout value for opening the database as a +time.Duration: ```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 { // Handle error } ``` ```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 { // Handle error } diff --git a/walletdb/bdb/db.go b/walletdb/bdb/db.go index 2408fad..e6a782f 100644 --- a/walletdb/bdb/db.go +++ b/walletdb/bdb/db.go @@ -7,6 +7,7 @@ package bdb import ( "io" "os" + "time" "github.com/btcsuite/btcwallet/walletdb" "go.etcd.io/bbolt" @@ -367,7 +368,9 @@ func fileExists(name string) bool { // 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. -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) { return nil, walletdb.ErrDbDoesNotExist } @@ -377,6 +380,7 @@ func openDB(dbPath string, noFreelistSync bool, create bool) (walletdb.DB, error options := &bbolt.Options{ NoFreelistSync: noFreelistSync, FreelistType: bbolt.FreelistMapType, + Timeout: timeout, } boltDB, err := bbolt.Open(dbPath, 0600, options) diff --git a/walletdb/bdb/doc.go b/walletdb/bdb/doc.go index 6e5087a..af8ffd4 100644 --- a/walletdb/bdb/doc.go +++ b/walletdb/bdb/doc.go @@ -9,16 +9,17 @@ datastore. Usage 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 -database path as a string, and an option for the database to not sync its -freelist to disk as a bool: +type of "bdb". The only parameters the Open and Create functions take are the +database path as a string, an option for the database to not sync its freelist +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 { // 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 { // Handle error } diff --git a/walletdb/bdb/driver.go b/walletdb/bdb/driver.go index 78442fd..da4ad26 100644 --- a/walletdb/bdb/driver.go +++ b/walletdb/bdb/driver.go @@ -6,6 +6,7 @@ package bdb import ( "fmt" + "time" "github.com/btcsuite/btcwallet/walletdb" ) @@ -15,50 +16,60 @@ const ( ) // parseArgs parses the arguments from the walletdb Open/Create methods. -func parseArgs(funcName string, args ...interface{}) (string, bool, error) { - if len(args) != 2 { - return "", false, fmt.Errorf("invalid arguments to %s.%s -- "+ - "expected database path and no-freelist-sync option", +func parseArgs(funcName string, + args ...interface{}) (string, bool, time.Duration, error) { + + 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) } dbPath, ok := args[0].(string) 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, funcName) } noFreelistSync, ok := args[1].(bool) 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, 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 // an existing database for use. func openDBDriver(args ...interface{}) (walletdb.DB, error) { - dbPath, noFreelistSync, err := parseArgs("Open", args...) + dbPath, noFreelistSync, timeout, err := parseArgs("Open", args...) if err != nil { return nil, err } - return openDB(dbPath, noFreelistSync, false) + return openDB(dbPath, noFreelistSync, false, timeout) } // createDBDriver is the callback provided during driver registration that // creates, initializes, and opens a database for use. func createDBDriver(args ...interface{}) (walletdb.DB, error) { - dbPath, noFreelistSync, err := parseArgs("Create", args...) + dbPath, noFreelistSync, timeout, err := parseArgs("Create", args...) if err != nil { return nil, err } - return openDB(dbPath, noFreelistSync, true) + return openDB(dbPath, noFreelistSync, true, timeout) } func init() { diff --git a/walletdb/bdb/driver_test.go b/walletdb/bdb/driver_test.go index aa4d872..df88d49 100644 --- a/walletdb/bdb/driver_test.go +++ b/walletdb/bdb/driver_test.go @@ -11,13 +11,19 @@ import ( "path/filepath" "reflect" "testing" + "time" "github.com/btcsuite/btcwallet/walletdb" _ "github.com/btcsuite/btcwallet/walletdb/bdb" ) -// dbType is the database type name for this driver. -const dbType = "bdb" +const ( + // 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 // 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 // the expected error. 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, "+ "want %v", err, wantErr) return @@ -34,8 +43,11 @@ func TestCreateOpenFail(t *testing.T) { // Ensure that attempting to open a database with the wrong number of // parameters returns the expected error. wantErr = fmt.Errorf("invalid arguments to %s.Open -- expected "+ - "database path and no-freelist-sync option", dbType) - if _, err := walletdb.Open(dbType, 1, 2, 3); err.Error() != wantErr.Error() { + "database path, no-freelist-sync and timeout option", dbType) + if _, err := walletdb.Open( + dbType, 1, 2, 3, 4, + ); err.Error() != wantErr.Error() { + t.Errorf("Open: did not receive expected error - got %v, "+ "want %v", err, wantErr) return @@ -45,7 +57,36 @@ func TestCreateOpenFail(t *testing.T) { // the first parameter returns the expected error. wantErr = fmt.Errorf("first argument to %s.Open is invalid -- "+ "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, "+ "want %v", err, wantErr) return @@ -54,18 +95,50 @@ func TestCreateOpenFail(t *testing.T) { // Ensure that attempting to create a database with the wrong number of // parameters returns the expected error. wantErr = fmt.Errorf("invalid arguments to %s.Create -- expected "+ - "database path and no-freelist-sync option", dbType) - if _, err := walletdb.Create(dbType, 1, 2, 3); err.Error() != wantErr.Error() { + "database path, no-freelist-sync and timeout option", dbType) + if _, err := walletdb.Create( + dbType, 1, 2, 3, 4, + ); err.Error() != wantErr.Error() { + t.Errorf("Create: did not receive expected error - got %v, "+ "want %v", err, wantErr) 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. wantErr = fmt.Errorf("first argument to %s.Create is invalid -- "+ "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, "+ "want %v", err, wantErr) return @@ -81,7 +154,7 @@ func TestCreateOpenFail(t *testing.T) { defer os.Remove(tempDir) dbPath := filepath.Join(tempDir, "db") - db, err := walletdb.Create(dbType, dbPath, true) + db, err := walletdb.Create(dbType, dbPath, true, defaultDBTimeout) if err != nil { t.Errorf("Create: unexpected error: %v", err) return @@ -108,7 +181,7 @@ func TestPersistence(t *testing.T) { defer os.Remove(tempDir) dbPath := filepath.Join(tempDir, "db") - db, err := walletdb.Create(dbType, dbPath, true) + db, err := walletdb.Create(dbType, dbPath, true, defaultDBTimeout) if err != nil { t.Errorf("Failed to create test database (%s) %v", dbType, err) return @@ -144,7 +217,7 @@ func TestPersistence(t *testing.T) { // Close and reopen the database to ensure the values persist. db.Close() - db, err = walletdb.Open(dbType, dbPath, true) + db, err = walletdb.Open(dbType, dbPath, true, defaultDBTimeout) if err != nil { t.Errorf("Failed to open test database (%s) %v", dbType, err) return diff --git a/walletdb/bdb/interface_test.go b/walletdb/bdb/interface_test.go index 3755b1d..4bfddb0 100644 --- a/walletdb/bdb/interface_test.go +++ b/walletdb/bdb/interface_test.go @@ -32,5 +32,5 @@ func TestInterface(t *testing.T) { dbPath := filepath.Join(tempDir, "db") defer os.RemoveAll(dbPath) - walletdbtest.TestInterface(t, dbType, dbPath, true) + walletdbtest.TestInterface(t, dbType, dbPath, true, defaultDBTimeout) }