bdb: add timeout option in bbolt

This commit is contained in:
yyforyongyu 2020-08-11 20:15:46 +08:00
parent 9bd6d26f83
commit 28c804ccc8
No known key found for this signature in database
GPG key ID: 9BCD95C4FF296868
6 changed files with 126 additions and 36 deletions

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"
) )
const (
// dbType is the database type name for this driver. // dbType is the database type name for this driver.
const dbType = "bdb" 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)
} }