diff --git a/channeldb/kvdb/etcd/bucket.go b/channeldb/kvdb/etcd/bucket.go index fd4a37015..3bc087dbf 100644 --- a/channeldb/kvdb/etcd/bucket.go +++ b/channeldb/kvdb/etcd/bucket.go @@ -16,12 +16,6 @@ var ( sequencePrefix = []byte("$") ) -// rootBucketId returns a zero filled 32 byte array -func rootBucketID() []byte { - var rootID [bucketIDLength]byte - return rootID[:] -} - // makeBucketID returns a deterministic key for the passed byte slice. // Currently it returns the sha256 hash of the slice. func makeBucketID(key []byte) [bucketIDLength]byte { diff --git a/channeldb/kvdb/etcd/bucket_test.go b/channeldb/kvdb/etcd/bucket_test.go index c9df28471..e68821f1e 100644 --- a/channeldb/kvdb/etcd/bucket_test.go +++ b/channeldb/kvdb/etcd/bucket_test.go @@ -7,7 +7,8 @@ package etcd func bkey(buckets ...string) string { var bucketKey []byte - parent := rootBucketID() + rootID := makeBucketID([]byte("")) + parent := rootID[:] for _, bucketName := range buckets { bucketKey = makeBucketKey(parent, []byte(bucketName)) @@ -28,7 +29,8 @@ func bval(buckets ...string) string { // vkey is a helper function used in tests to create a value key from the // passed key and bucket list. func vkey(key string, buckets ...string) string { - bucket := rootBucketID() + rootID := makeBucketID([]byte("")) + bucket := rootID[:] for _, bucketName := range buckets { bucketKey := makeBucketKey(bucket, []byte(bucketName)) diff --git a/channeldb/kvdb/etcd/db.go b/channeldb/kvdb/etcd/db.go index 0079d2c9c..a082e6109 100644 --- a/channeldb/kvdb/etcd/db.go +++ b/channeldb/kvdb/etcd/db.go @@ -143,6 +143,11 @@ type BackendConfig struct { // skip TLS verification. InsecureSkipVerify bool + // Prefix the hash of the prefix will be used as the root + // bucket id. This enables key space separation similar to + // name spaces. + Prefix string + // CollectCommitStats indicates wheter to commit commit stats. CollectCommitStats bool } @@ -203,7 +208,7 @@ func (db *db) getSTMOptions() []STMOptionFunc { // occur). func (db *db) View(f func(tx walletdb.ReadTx) error) error { apply := func(stm STM) error { - return f(newReadWriteTx(stm)) + return f(newReadWriteTx(stm, db.config.Prefix)) } return RunSTM(db.cli, apply, db.getSTMOptions()...) @@ -217,7 +222,7 @@ func (db *db) View(f func(tx walletdb.ReadTx) error) error { // returned. func (db *db) Update(f func(tx walletdb.ReadWriteTx) error) error { apply := func(stm STM) error { - return f(newReadWriteTx(stm)) + return f(newReadWriteTx(stm, db.config.Prefix)) } return RunSTM(db.cli, apply, db.getSTMOptions()...) @@ -234,12 +239,18 @@ func (db *db) PrintStats() string { // BeginReadTx opens a database read transaction. func (db *db) BeginReadWriteTx() (walletdb.ReadWriteTx, error) { - return newReadWriteTx(NewSTM(db.cli, db.getSTMOptions()...)), nil + return newReadWriteTx( + NewSTM(db.cli, db.getSTMOptions()...), + db.config.Prefix, + ), nil } // BeginReadWriteTx opens a database read+write transaction. func (db *db) BeginReadTx() (walletdb.ReadTx, error) { - return newReadWriteTx(NewSTM(db.cli, db.getSTMOptions()...)), nil + return newReadWriteTx( + NewSTM(db.cli, db.getSTMOptions()...), + db.config.Prefix, + ), nil } // Copy writes a copy of the database to the provided writer. This call will diff --git a/channeldb/kvdb/etcd/readwrite_bucket.go b/channeldb/kvdb/etcd/readwrite_bucket.go index 60a19cc18..e60d2cec3 100644 --- a/channeldb/kvdb/etcd/readwrite_bucket.go +++ b/channeldb/kvdb/etcd/readwrite_bucket.go @@ -24,7 +24,7 @@ type readWriteBucket struct { // newReadWriteBucket creates a new rw bucket with the passed transaction // and bucket id. func newReadWriteBucket(tx *readWriteTx, key, id []byte) *readWriteBucket { - if !bytes.Equal(id, rootBucketID()) { + if !bytes.Equal(id, tx.rootBucketID[:]) { // Add the bucket key/value to the lock set. tx.lock(string(key), string(id)) } diff --git a/channeldb/kvdb/etcd/readwrite_tx.go b/channeldb/kvdb/etcd/readwrite_tx.go index 37914e8c9..22d0ce421 100644 --- a/channeldb/kvdb/etcd/readwrite_tx.go +++ b/channeldb/kvdb/etcd/readwrite_tx.go @@ -11,6 +11,10 @@ type readWriteTx struct { // stm is the reference to the parent STM. stm STM + // rootBucketID holds the sha256 hash of the root bucket id, which is used + // for key space spearation. + rootBucketID [bucketIDLength]byte + // active is true if the transaction hasn't been committed yet. active bool @@ -24,18 +28,19 @@ type readWriteTx struct { } // newReadWriteTx creates an rw transaction with the passed STM. -func newReadWriteTx(stm STM) *readWriteTx { +func newReadWriteTx(stm STM, prefix string) *readWriteTx { return &readWriteTx{ - stm: stm, - active: true, - lset: make(map[string]string), + stm: stm, + active: true, + rootBucketID: makeBucketID([]byte(prefix)), + lset: make(map[string]string), } } // rooBucket is a helper function to return the always present -// root bucket. +// pseudo root bucket. func rootBucket(tx *readWriteTx) *readWriteBucket { - return newReadWriteBucket(tx, rootBucketID(), rootBucketID()) + return newReadWriteBucket(tx, tx.rootBucketID[:], tx.rootBucketID[:]) } // lock adds a key value to the lock set. diff --git a/channeldb/kvdb/kvdb_etcd.go b/channeldb/kvdb/kvdb_etcd.go index b2662e098..265e7daeb 100644 --- a/channeldb/kvdb/kvdb_etcd.go +++ b/channeldb/kvdb/kvdb_etcd.go @@ -12,7 +12,7 @@ const TestBackend = EtcdBackendName // GetEtcdBackend returns an etcd backend configured according to the // passed etcdConfig. -func GetEtcdBackend(etcdConfig *EtcdConfig) (Backend, error) { +func GetEtcdBackend(prefix string, etcdConfig *EtcdConfig) (Backend, error) { // Config translation is needed here in order to keep the // etcd package fully independent from the rest of the source tree. backendConfig := etcd.BackendConfig{ @@ -22,6 +22,7 @@ func GetEtcdBackend(etcdConfig *EtcdConfig) (Backend, error) { CertFile: etcdConfig.CertFile, KeyFile: etcdConfig.KeyFile, InsecureSkipVerify: etcdConfig.InsecureSkipVerify, + Prefix: prefix, CollectCommitStats: etcdConfig.CollectStats, } diff --git a/channeldb/kvdb/kvdb_no_etcd.go b/channeldb/kvdb/kvdb_no_etcd.go index 1758551f8..ea5de4275 100644 --- a/channeldb/kvdb/kvdb_no_etcd.go +++ b/channeldb/kvdb/kvdb_no_etcd.go @@ -13,7 +13,7 @@ const TestBackend = BoltBackendName var errEtcdNotAvailable = fmt.Errorf("etcd backend not available") // GetEtcdBackend is a stub returning nil and errEtcdNotAvailable error. -func GetEtcdBackend(etcdConfig *EtcdConfig) (Backend, error) { +func GetEtcdBackend(prefix string, etcdConfig *EtcdConfig) (Backend, error) { return nil, errEtcdNotAvailable } diff --git a/lncfg/db.go b/lncfg/db.go index c0f47fc7f..62de1f130 100644 --- a/lncfg/db.go +++ b/lncfg/db.go @@ -2,6 +2,7 @@ package lncfg import ( "fmt" + "path" "github.com/lightningnetwork/lnd/channeldb/kvdb" ) @@ -50,12 +51,14 @@ func (db *DB) Validate() error { } // GetBackend returns a kvdb.Backend as set in the DB config. -func (db *DB) GetBackend(path string) (kvdb.Backend, error) { +func (db *DB) GetBackend(dbPath string) (kvdb.Backend, error) { if db.Backend == etcdBackend { - return kvdb.GetEtcdBackend(db.Etcd) + // Prefix will separate key/values in the db. + prefix := path.Join(dbPath, dbName) + return kvdb.GetEtcdBackend(prefix, db.Etcd) } - return kvdb.GetBoltBackend(path, dbName, db.Bolt.NoFreeListSync) + return kvdb.GetBoltBackend(dbPath, dbName, db.Bolt.NoFreeListSync) } // Compile-time constraint to ensure Workers implements the Validator interface.