diff --git a/walletdb/hdb/db.go b/walletdb/hdb/db.go new file mode 100644 index 0000000000..84b502f401 --- /dev/null +++ b/walletdb/hdb/db.go @@ -0,0 +1,157 @@ +package hdb + +import ( + "errors" + "io" + + "github.com/btcsuite/btcwallet/walletdb" + hamtcontainer "github.com/simplecoincom/go-ipld-adl-hamt-container" +) + +const ( + // metadataDbName is the name used for the metadata database. + metadataDbName = "metadata" +) + +// db represents a collection of namespaces which are persisted and implements +// the database.DB interface. All database access is performed through +// transactions which are obtained through the specific Namespace. +type db struct { + closed bool // Is the database closed? + hdb *hamtcontainer.HAMTContainer +} + +// Enforce db implements the database.DB interface. +var _ walletdb.DB = (*db)(nil) + +// bucket is an internal type used to represent a collection of key/value pairs +// and implements the database.Bucket interface. +type bucket struct { + id [4]byte +} + +// ReadBucket opens the root bucket for read only access. If the bucket +// described by the key does not exist, nil is returned. +func (b *bucket) ReadBucket(_ []byte) walletdb.ReadBucket { + return nil +} + +// ForEachBucket will iterate through all top level buckets. +func (b *bucket) ForEachBucket(func(key []byte) error) error { + return nil +} + +// Rollback closes the transaction, discarding changes (if any) if the +// database was modified by a write transaction. +func (b *bucket) Rollback() error { + return nil +} + +// ReadWriteBucket opens the root bucket for read/write access. If the +// bucket described by the key does not exist, nil is returned. +func (b *bucket) ReadWriteBucket(_ []byte) walletdb.ReadWriteBucket { + return nil +} + +// CreateTopLevelBucket creates the top level bucket for a key if it +// does not exist. The newly-created bucket it returned. +func (b *bucket) CreateTopLevelBucket(_ []byte) (walletdb.ReadWriteBucket, error) { + return nil, nil +} + +// DeleteTopLevelBucket deletes the top level bucket for a key. This +// errors if the bucket can not be found or the key keys a single value +// instead of a bucket. +func (b *bucket) DeleteTopLevelBucket(_ []byte) error { + return nil +} + +// Commit commits all changes that have been on the transaction's root +// buckets and all of their sub-buckets to persistent storage. +func (b *bucket) Commit() error { + return nil +} + +// OnCommit takes a function closure that will be executed when the +// transaction successfully gets committed. +func (b *bucket) OnCommit(func()) { + +} + +// CreateBucket creates and returns a new nested bucket with the given key. +// +// Returns the following errors as required by the interface contract: +// - ErrBucketExists if the bucket already exists +// - ErrBucketNameRequired if the key is empty +// - ErrIncompatibleValue if the key is otherwise invalid for the particular +// implementation +// - ErrTxNotWritable if attempted against a read-only transaction +// - ErrTxClosed if the transaction has already been closed +// +// This function is part of the database.Bucket interface implementation. +func (b *bucket) CreateBucket(_ []byte) (walletdb.ReadWriteBucket, error) { + return nil, nil +} + +// BeginReadTx starts a read-only transaction. Multiple read-only transactions +// can be started simultaneously while only a single read-write transaction can +// be started at a time. +// +// NOTE: The transaction must be closed by calling Rollbackon it when it is no +// longer needed. Failure to do so will result in unclaimed memory. +// +// This function is part of the walletdb.DB interface implementation. +func (db *db) BeginReadTx() (walletdb.ReadTx, error) { + return &bucket{id: [4]byte{}}, nil +} + +// BeginReadTx starts a read-write transaction. Multiple read-only transactions +// can be started simultaneously while only a single read-write transaction can +// be started at a time. The call will block when a read-write transaction is +// already open. +// +// NOTE: The transaction must be closed by calling Rollback or Commit on it when +// it is no longer needed. Failure to do so will result in unclaimed memory. +// +// This function is part of the walletdb.DB interface implementation. +func (db *db) BeginReadWriteTx() (walletdb.ReadWriteTx, error) { + return &bucket{id: [4]byte{}}, nil +} + +// TODO(eduardonunesp): implement this +func (db *db) Copy(_ io.Writer) error { + return errors.New("Not implemented yet") +} + +// Batch is required by the BatchDB interface +func (db *db) Batch(fn func(tx walletdb.ReadWriteTx) error) error { + return walletdb.Update(db, fn) +} + +// Close cleanly shuts down the database and syncs all data. It will block +// until all database transactions have been finalized (rolled back or +// committed). +// +// This function is part of the database.DB interface implementation. +func (db *db) Close() error { + if db.closed { + return walletdb.ErrDbNotOpen + } + db.closed = true + return nil +} + +// 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(ipfsURL string) (walletdb.DB, error) { + _ = ipfsURL + + hdb, err := hamtcontainer.NewHAMTBuilder().Build() + if err != nil { + return nil, err + } + + pdb := &db{hdb: hdb} + + return pdb, nil +} diff --git a/walletdb/hdb/driver.go b/walletdb/hdb/driver.go new file mode 100644 index 0000000000..d9c3efa9fa --- /dev/null +++ b/walletdb/hdb/driver.go @@ -0,0 +1,68 @@ +// Copyright (c) 2014 The btcsuite developers +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package hdb + +import ( + "fmt" + + "github.com/btcsuite/btcwallet/walletdb" +) + +const ( + dbType = "hdb" +) + +// parseArgs parses the arguments from the walletdb Open/Create methods. +func parseArgs(funcName string, args ...interface{}) (string, error) { + if len(args) < 1 { + return "", fmt.Errorf("invalid arguments to %s.%s -- "+ + "expected ipfs url", + dbType, funcName) + } + + ipfsURL, ok := args[0].(string) + if !ok { + return "", fmt.Errorf("first argument to %s.%s is "+ + "invalid -- expected ipfs url", dbType, + funcName) + } + + return ipfsURL, nil +} + +// openDBDriver is the callback provided during driver registration that opens +// an existing database for use. +func openDBDriver(args ...interface{}) (walletdb.DB, error) { + dbPath, err := parseArgs("Open", args...) + if err != nil { + return nil, err + } + + return openDB(dbPath) +} + +// 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, err := parseArgs("Create", args...) + if err != nil { + return nil, err + } + + return openDB(dbPath) +} + +func init() { + // Register the driver. + driver := walletdb.Driver{ + DbType: dbType, + Create: createDBDriver, + Open: openDBDriver, + } + if err := walletdb.RegisterDriver(driver); err != nil { + panic(fmt.Sprintf("Failed to regiser database driver '%s': %v", + dbType, err)) + } +} diff --git a/walletdb/hdb/driver_test.go b/walletdb/hdb/driver_test.go new file mode 100644 index 0000000000..538f2711dd --- /dev/null +++ b/walletdb/hdb/driver_test.go @@ -0,0 +1,4 @@ +package hdb_test + +// dbType is the database type name for this driver. +const dbType = "hdb" diff --git a/walletdb/hdb/interface_test.go b/walletdb/hdb/interface_test.go new file mode 100644 index 0000000000..653a05a704 --- /dev/null +++ b/walletdb/hdb/interface_test.go @@ -0,0 +1,36 @@ +// Copyright (c) 2014 The btcsuite developers +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +// This file intended to be copied into each backend driver directory. Each +// driver should have their own driver_test.go file which creates a database and +// invokes the testInterface function in this file to ensure the driver properly +// implements the interface. See the bdb backend driver for a working example. +// +// NOTE: When copying this file into the backend driver folder, the package name +// will need to be changed accordingly. + +package hdb_test + +import ( + "io/ioutil" + "os" + "path/filepath" + "testing" + + "github.com/btcsuite/btcwallet/walletdb/walletdbtest" +) + +// TestInterface performs all interfaces tests for this database driver. +func TestInterface(t *testing.T) { + tempDir, err := ioutil.TempDir("", "interfacetest") + if err != nil { + t.Errorf("unable to create temp dir: %v", err) + return + } + defer os.Remove(tempDir) + + dbPath := filepath.Join(tempDir, "db") + defer os.RemoveAll(dbPath) + walletdbtest.TestInterface(t, dbType, dbPath) +}