[NOD-885] Use database.Key and database.Bucket instead of byte slices (#692)

* [NOD-885] Create database.Key type

* [NOD-885] Rename FullKey()->FullKeyBytes() and Key()->KeyBytes()

* [NOD-885] Make Key.String return a hex string

* [NOD-885] Rename key parts

* [NOD-885] Rename separator->bucketSeparator

* [NOD-885] Rename SuffixBytes->Suffix and PrefixBytes->Prefix

* [NOD-885] Change comments

* [NOD-885] Change key prefix to bucket

* [NOD-885] Don't use database.NewKey inside dbaccess

* [NOD-885] Fix nil bug in Bucket.Path()

* [NOD-885] Rename helpers.go -> keys.go

* [NOD-885] Unexport database.NewKey

* [NOD-885] Remove redundant code in Bucket.Path()
This commit is contained in:
Ori Newman 2020-04-08 12:12:21 +03:00 committed by GitHub
parent df934990d7
commit 7609c50641
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
26 changed files with 174 additions and 127 deletions

View File

@ -324,7 +324,7 @@ func (dag *BlockDAG) initUTXOSet() (fullUTXOCollection utxoCollection, err error
if err != nil { if err != nil {
return nil, err return nil, err
} }
outpoint, err := deserializeOutpoint(bytes.NewReader(key)) outpoint, err := deserializeOutpoint(bytes.NewReader(key.Suffix()))
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -639,7 +639,7 @@ func (dag *BlockDAG) BlockHashesFrom(lowHash *daghash.Hash, limit int) ([]*dagha
if err != nil { if err != nil {
return nil, err return nil, err
} }
blockHash, err := blockHashFromBlockIndexKey(key) blockHash, err := blockHashFromBlockIndexKey(key.Suffix())
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -96,7 +96,7 @@ func (store *multisetStore) init(dbContext dbaccess.Context) error {
return err return err
} }
hash, err := daghash.NewHash(key) hash, err := daghash.NewHash(key.Suffix())
if err != nil { if err != nil {
return err return err
} }

View File

@ -137,7 +137,7 @@ func (store *reachabilityStore) initReachabilityData(cursor database.Cursor) err
return err return err
} }
hash, err := daghash.NewHash(key) hash, err := daghash.NewHash(key.Suffix())
if err != nil { if err != nil {
return err return err
} }
@ -155,7 +155,7 @@ func (store *reachabilityStore) loadReachabilityDataFromCursor(cursor database.C
return err return err
} }
hash, err := daghash.NewHash(key) hash, err := daghash.NewHash(key.Suffix())
if err != nil { if err != nil {
return err return err
} }

View File

@ -1,51 +0,0 @@
package database
import "bytes"
var separator = []byte("/")
// Bucket is a helper type meant to combine buckets,
// sub-buckets, and keys into a single full key-value
// database key.
type Bucket struct {
path [][]byte
}
// MakeBucket creates a new Bucket using the given path
// of buckets.
func MakeBucket(path ...[]byte) *Bucket {
return &Bucket{path: path}
}
// Bucket returns the sub-bucket of the current bucket
// defined by bucketBytes.
func (b *Bucket) Bucket(bucketBytes []byte) *Bucket {
newPath := make([][]byte, len(b.path)+1)
copy(newPath, b.path)
copy(newPath[len(b.path):], [][]byte{bucketBytes})
return MakeBucket(newPath...)
}
// Key returns the key inside of the current bucket.
func (b *Bucket) Key(key []byte) []byte {
bucketPath := b.Path()
fullKeyLength := len(bucketPath) + len(key)
fullKey := make([]byte, fullKeyLength)
copy(fullKey, bucketPath)
copy(fullKey[len(bucketPath):], key)
return fullKey
}
// Path returns the full path of the current bucket.
func (b *Bucket) Path() []byte {
bucketPath := bytes.Join(b.path, separator)
bucketPathWithFinalSeparator := make([]byte, len(bucketPath)+len(separator))
copy(bucketPathWithFinalSeparator, bucketPath)
copy(bucketPathWithFinalSeparator[len(bucketPath):], separator)
return bucketPathWithFinalSeparator
}

View File

@ -13,13 +13,13 @@ type Cursor interface {
// Seek moves the iterator to the first key/value pair whose key is greater // Seek moves the iterator to the first key/value pair whose key is greater
// than or equal to the given key. It returns ErrNotFound if such pair does not // than or equal to the given key. It returns ErrNotFound if such pair does not
// exist. // exist.
Seek(key []byte) error Seek(key *Key) error
// Key returns the key of the current key/value pair, or ErrNotFound if done. // Key returns the key of the current key/value pair, or ErrNotFound if done.
// Note that the key is trimmed to not include the prefix the cursor was opened // Note that the key is trimmed to not include the prefix the cursor was opened
// with. The caller should not modify the contents of the returned slice, and // with. The caller should not modify the contents of the returned slice, and
// its contents may change on the next call to Next. // its contents may change on the next call to Next.
Key() ([]byte, error) Key() (*Key, error)
// Value returns the value of the current key/value pair, or ErrNotFound if done. // Value returns the value of the current key/value pair, or ErrNotFound if done.
// The caller should not modify the contents of the returned slice, and its // The caller should not modify the contents of the returned slice, and its

View File

@ -5,19 +5,19 @@ package database
type DataAccessor interface { type DataAccessor interface {
// Put sets the value for the given key. It overwrites // Put sets the value for the given key. It overwrites
// any previous value for that key. // any previous value for that key.
Put(key []byte, value []byte) error Put(key *Key, value []byte) error
// Get gets the value for the given key. It returns // Get gets the value for the given key. It returns
// ErrNotFound if the given key does not exist. // ErrNotFound if the given key does not exist.
Get(key []byte) ([]byte, error) Get(key *Key) ([]byte, error)
// Has returns true if the database does contains the // Has returns true if the database does contains the
// given key. // given key.
Has(key []byte) (bool, error) Has(key *Key) (bool, error)
// Delete deletes the value for the given key. Will not // Delete deletes the value for the given key. Will not
// return an error if the key doesn't exist. // return an error if the key doesn't exist.
Delete(key []byte) error Delete(key *Key) error
// AppendToStore appends the given data to the store // AppendToStore appends the given data to the store
// defined by storeName. This function returns a serialized // defined by storeName. This function returns a serialized
@ -32,5 +32,5 @@ type DataAccessor interface {
RetrieveFromStore(storeName string, location []byte) ([]byte, error) RetrieveFromStore(storeName string, location []byte) ([]byte, error)
// Cursor begins a new cursor over the given bucket. // Cursor begins a new cursor over the given bucket.
Cursor(bucket []byte) (Cursor, error) Cursor(bucket *Bucket) (Cursor, error)
} }

View File

@ -59,28 +59,28 @@ func (db *ffldb) Close() error {
// Put sets the value for the given key. It overwrites // Put sets the value for the given key. It overwrites
// any previous value for that key. // any previous value for that key.
// This method is part of the DataAccessor interface. // This method is part of the DataAccessor interface.
func (db *ffldb) Put(key []byte, value []byte) error { func (db *ffldb) Put(key *database.Key, value []byte) error {
return db.levelDB.Put(key, value) return db.levelDB.Put(key, value)
} }
// Get gets the value for the given key. It returns // Get gets the value for the given key. It returns
// ErrNotFound if the given key does not exist. // ErrNotFound if the given key does not exist.
// This method is part of the DataAccessor interface. // This method is part of the DataAccessor interface.
func (db *ffldb) Get(key []byte) ([]byte, error) { func (db *ffldb) Get(key *database.Key) ([]byte, error) {
return db.levelDB.Get(key) return db.levelDB.Get(key)
} }
// Has returns true if the database does contains the // Has returns true if the database does contains the
// given key. // given key.
// This method is part of the DataAccessor interface. // This method is part of the DataAccessor interface.
func (db *ffldb) Has(key []byte) (bool, error) { func (db *ffldb) Has(key *database.Key) (bool, error) {
return db.levelDB.Has(key) return db.levelDB.Has(key)
} }
// Delete deletes the value for the given key. Will not // Delete deletes the value for the given key. Will not
// return an error if the key doesn't exist. // return an error if the key doesn't exist.
// This method is part of the DataAccessor interface. // This method is part of the DataAccessor interface.
func (db *ffldb) Delete(key []byte) error { func (db *ffldb) Delete(key *database.Key) error {
return db.levelDB.Delete(key) return db.levelDB.Delete(key)
} }
@ -155,8 +155,8 @@ func (db *ffldb) RetrieveFromStore(storeName string, location []byte) ([]byte, e
// Cursor begins a new cursor over the given bucket. // Cursor begins a new cursor over the given bucket.
// This method is part of the DataAccessor interface. // This method is part of the DataAccessor interface.
func (db *ffldb) Cursor(bucket []byte) (database.Cursor, error) { func (db *ffldb) Cursor(bucket *database.Bucket) (database.Cursor, error) {
ldbCursor := db.levelDB.Cursor(bucket) ldbCursor := db.levelDB.Cursor(bucket.Path())
return ldbCursor, nil return ldbCursor, nil
} }

View File

@ -33,7 +33,7 @@ func (db *ffldb) flatFiles() (map[string][]byte, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
storeName := string(storeNameKey) storeName := string(storeNameKey.Suffix())
currentLocation, err := flatFilesCursor.Value() currentLocation, err := flatFilesCursor.Value()
if err != nil { if err != nil {

View File

@ -2,7 +2,6 @@ package ldb
import ( import (
"bytes" "bytes"
"encoding/hex"
"github.com/kaspanet/kaspad/database" "github.com/kaspanet/kaspad/database"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/syndtr/goleveldb/leveldb/iterator" "github.com/syndtr/goleveldb/leveldb/iterator"
@ -48,14 +47,14 @@ func (c *LevelDBCursor) First() bool {
// Seek moves the iterator to the first key/value pair whose key is greater // Seek moves the iterator to the first key/value pair whose key is greater
// than or equal to the given key. It returns ErrNotFound if such pair does not // than or equal to the given key. It returns ErrNotFound if such pair does not
// exist. // exist.
func (c *LevelDBCursor) Seek(key []byte) error { func (c *LevelDBCursor) Seek(key *database.Key) error {
if c.isClosed { if c.isClosed {
return errors.New("cannot seek a closed cursor") return errors.New("cannot seek a closed cursor")
} }
notFoundErr := errors.Wrapf(database.ErrNotFound, "key %s not "+ notFoundErr := errors.Wrapf(database.ErrNotFound, "key %s not "+
"found", hex.EncodeToString(key)) "found", key)
found := c.ldbIterator.Seek(key) found := c.ldbIterator.Seek(key.Bytes())
if !found { if !found {
return notFoundErr return notFoundErr
} }
@ -65,7 +64,7 @@ func (c *LevelDBCursor) Seek(key []byte) error {
if currentKey == nil { if currentKey == nil {
return notFoundErr return notFoundErr
} }
if !bytes.Equal(currentKey, key) { if !bytes.Equal(currentKey, key.Bytes()) {
return notFoundErr return notFoundErr
} }
@ -76,7 +75,7 @@ func (c *LevelDBCursor) Seek(key []byte) error {
// Note that the key is trimmed to not include the prefix the cursor was opened // Note that the key is trimmed to not include the prefix the cursor was opened
// with. The caller should not modify the contents of the returned slice, and // with. The caller should not modify the contents of the returned slice, and
// its contents may change on the next call to Next. // its contents may change on the next call to Next.
func (c *LevelDBCursor) Key() ([]byte, error) { func (c *LevelDBCursor) Key() (*database.Key, error) {
if c.isClosed { if c.isClosed {
return nil, errors.New("cannot get the key of a closed cursor") return nil, errors.New("cannot get the key of a closed cursor")
} }
@ -85,8 +84,8 @@ func (c *LevelDBCursor) Key() ([]byte, error) {
return nil, errors.Wrapf(database.ErrNotFound, "cannot get the "+ return nil, errors.Wrapf(database.ErrNotFound, "cannot get the "+
"key of a done cursor") "key of a done cursor")
} }
key := bytes.TrimPrefix(fullKeyPath, c.prefix) suffix := bytes.TrimPrefix(fullKeyPath, c.prefix)
return key, nil return database.MakeBucket(c.prefix).Key(suffix), nil
} }
// Value returns the value of the current key/value pair, or ErrNotFound if done. // Value returns the value of the current key/value pair, or ErrNotFound if done.

View File

@ -1,7 +1,6 @@
package ldb package ldb
import ( import (
"encoding/hex"
"github.com/kaspanet/kaspad/database" "github.com/kaspanet/kaspad/database"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/syndtr/goleveldb/leveldb" "github.com/syndtr/goleveldb/leveldb"
@ -52,19 +51,19 @@ func (db *LevelDB) Close() error {
// Put sets the value for the given key. It overwrites // Put sets the value for the given key. It overwrites
// any previous value for that key. // any previous value for that key.
func (db *LevelDB) Put(key []byte, value []byte) error { func (db *LevelDB) Put(key *database.Key, value []byte) error {
err := db.ldb.Put(key, value, nil) err := db.ldb.Put(key.Bytes(), value, nil)
return errors.WithStack(err) return errors.WithStack(err)
} }
// Get gets the value for the given key. It returns // Get gets the value for the given key. It returns
// ErrNotFound if the given key does not exist. // ErrNotFound if the given key does not exist.
func (db *LevelDB) Get(key []byte) ([]byte, error) { func (db *LevelDB) Get(key *database.Key) ([]byte, error) {
data, err := db.ldb.Get(key, nil) data, err := db.ldb.Get(key.Bytes(), nil)
if err != nil { if err != nil {
if errors.Is(err, leveldb.ErrNotFound) { if errors.Is(err, leveldb.ErrNotFound) {
return nil, errors.Wrapf(database.ErrNotFound, return nil, errors.Wrapf(database.ErrNotFound,
"key %s not found", hex.EncodeToString(key)) "key %s not found", key)
} }
return nil, errors.WithStack(err) return nil, errors.WithStack(err)
} }
@ -73,8 +72,8 @@ func (db *LevelDB) Get(key []byte) ([]byte, error) {
// Has returns true if the database does contains the // Has returns true if the database does contains the
// given key. // given key.
func (db *LevelDB) Has(key []byte) (bool, error) { func (db *LevelDB) Has(key *database.Key) (bool, error) {
exists, err := db.ldb.Has(key, nil) exists, err := db.ldb.Has(key.Bytes(), nil)
if err != nil { if err != nil {
return false, errors.WithStack(err) return false, errors.WithStack(err)
} }
@ -83,7 +82,7 @@ func (db *LevelDB) Has(key []byte) (bool, error) {
// Delete deletes the value for the given key. Will not // Delete deletes the value for the given key. Will not
// return an error if the key doesn't exist. // return an error if the key doesn't exist.
func (db *LevelDB) Delete(key []byte) error { func (db *LevelDB) Delete(key *database.Key) error {
err := db.ldb.Delete(key, nil) err := db.ldb.Delete(key.Bytes(), nil)
return errors.WithStack(err) return errors.WithStack(err)
} }

View File

@ -28,7 +28,7 @@ func TestLevelDBSanity(t *testing.T) {
}() }()
// Put something into the db // Put something into the db
key := []byte("key") key := database.MakeBucket().Key([]byte("key"))
putData := []byte("Hello world!") putData := []byte("Hello world!")
err = ldb.Put(key, putData) err = ldb.Put(key, putData)
if err != nil { if err != nil {
@ -80,7 +80,7 @@ func TestLevelDBTransactionSanity(t *testing.T) {
} }
// Put something into the transaction // Put something into the transaction
key := []byte("key") key := database.MakeBucket().Key([]byte("key"))
putData := []byte("Hello world!") putData := []byte("Hello world!")
err = tx.Put(key, putData) err = tx.Put(key, putData)
if err != nil { if err != nil {
@ -124,7 +124,7 @@ func TestLevelDBTransactionSanity(t *testing.T) {
// Case 2. Write directly to the DB and then read from a tx // Case 2. Write directly to the DB and then read from a tx
// Put something into the db // Put something into the db
key = []byte("key2") key = database.MakeBucket().Key([]byte("key2"))
putData = []byte("Goodbye world!") putData = []byte("Goodbye world!")
err = ldb.Put(key, putData) err = ldb.Put(key, putData)
if err != nil { if err != nil {

View File

@ -1,7 +1,6 @@
package ldb package ldb
import ( import (
"encoding/hex"
"github.com/kaspanet/kaspad/database" "github.com/kaspanet/kaspad/database"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/syndtr/goleveldb/leveldb" "github.com/syndtr/goleveldb/leveldb"
@ -82,27 +81,27 @@ func (tx *LevelDBTransaction) RollbackUnlessClosed() error {
// Put sets the value for the given key. It overwrites // Put sets the value for the given key. It overwrites
// any previous value for that key. // any previous value for that key.
func (tx *LevelDBTransaction) Put(key []byte, value []byte) error { func (tx *LevelDBTransaction) Put(key *database.Key, value []byte) error {
if tx.isClosed { if tx.isClosed {
return errors.New("cannot put into a closed transaction") return errors.New("cannot put into a closed transaction")
} }
tx.batch.Put(key, value) tx.batch.Put(key.Bytes(), value)
return nil return nil
} }
// Get gets the value for the given key. It returns // Get gets the value for the given key. It returns
// ErrNotFound if the given key does not exist. // ErrNotFound if the given key does not exist.
func (tx *LevelDBTransaction) Get(key []byte) ([]byte, error) { func (tx *LevelDBTransaction) Get(key *database.Key) ([]byte, error) {
if tx.isClosed { if tx.isClosed {
return nil, errors.New("cannot get from a closed transaction") return nil, errors.New("cannot get from a closed transaction")
} }
data, err := tx.snapshot.Get(key, nil) data, err := tx.snapshot.Get(key.Bytes(), nil)
if err != nil { if err != nil {
if errors.Is(err, leveldb.ErrNotFound) { if errors.Is(err, leveldb.ErrNotFound) {
return nil, errors.Wrapf(database.ErrNotFound, return nil, errors.Wrapf(database.ErrNotFound,
"key %s not found", hex.EncodeToString(key)) "key %s not found", key)
} }
return nil, errors.WithStack(err) return nil, errors.WithStack(err)
} }
@ -111,30 +110,30 @@ func (tx *LevelDBTransaction) Get(key []byte) ([]byte, error) {
// Has returns true if the database does contains the // Has returns true if the database does contains the
// given key. // given key.
func (tx *LevelDBTransaction) Has(key []byte) (bool, error) { func (tx *LevelDBTransaction) Has(key *database.Key) (bool, error) {
if tx.isClosed { if tx.isClosed {
return false, errors.New("cannot has from a closed transaction") return false, errors.New("cannot has from a closed transaction")
} }
return tx.snapshot.Has(key, nil) return tx.snapshot.Has(key.Bytes(), nil)
} }
// Delete deletes the value for the given key. Will not // Delete deletes the value for the given key. Will not
// return an error if the key doesn't exist. // return an error if the key doesn't exist.
func (tx *LevelDBTransaction) Delete(key []byte) error { func (tx *LevelDBTransaction) Delete(key *database.Key) error {
if tx.isClosed { if tx.isClosed {
return errors.New("cannot delete from a closed transaction") return errors.New("cannot delete from a closed transaction")
} }
tx.batch.Delete(key) tx.batch.Delete(key.Bytes())
return nil return nil
} }
// Cursor begins a new cursor over the given bucket. // Cursor begins a new cursor over the given bucket.
func (tx *LevelDBTransaction) Cursor(bucket []byte) (*LevelDBCursor, error) { func (tx *LevelDBTransaction) Cursor(bucket *database.Bucket) (*LevelDBCursor, error) {
if tx.isClosed { if tx.isClosed {
return nil, errors.New("cannot open a cursor from a closed transaction") return nil, errors.New("cannot open a cursor from a closed transaction")
} }
return tx.db.Cursor(bucket), nil return tx.db.Cursor(bucket.Path()), nil
} }

View File

@ -20,28 +20,28 @@ type transaction struct {
// Put sets the value for the given key. It overwrites // Put sets the value for the given key. It overwrites
// any previous value for that key. // any previous value for that key.
// This method is part of the DataAccessor interface. // This method is part of the DataAccessor interface.
func (tx *transaction) Put(key []byte, value []byte) error { func (tx *transaction) Put(key *database.Key, value []byte) error {
return tx.ldbTx.Put(key, value) return tx.ldbTx.Put(key, value)
} }
// Get gets the value for the given key. It returns // Get gets the value for the given key. It returns
// ErrNotFound if the given key does not exist. // ErrNotFound if the given key does not exist.
// This method is part of the DataAccessor interface. // This method is part of the DataAccessor interface.
func (tx *transaction) Get(key []byte) ([]byte, error) { func (tx *transaction) Get(key *database.Key) ([]byte, error) {
return tx.ldbTx.Get(key) return tx.ldbTx.Get(key)
} }
// Has returns true if the database does contains the // Has returns true if the database does contains the
// given key. // given key.
// This method is part of the DataAccessor interface. // This method is part of the DataAccessor interface.
func (tx *transaction) Has(key []byte) (bool, error) { func (tx *transaction) Has(key *database.Key) (bool, error) {
return tx.ldbTx.Has(key) return tx.ldbTx.Has(key)
} }
// Delete deletes the value for the given key. Will not // Delete deletes the value for the given key. Will not
// return an error if the key doesn't exist. // return an error if the key doesn't exist.
// This method is part of the DataAccessor interface. // This method is part of the DataAccessor interface.
func (tx *transaction) Delete(key []byte) error { func (tx *transaction) Delete(key *database.Key) error {
return tx.ldbTx.Delete(key) return tx.ldbTx.Delete(key)
} }
@ -66,7 +66,7 @@ func (tx *transaction) RetrieveFromStore(storeName string, location []byte) ([]b
// Cursor begins a new cursor over the given bucket. // Cursor begins a new cursor over the given bucket.
// This method is part of the DataAccessor interface. // This method is part of the DataAccessor interface.
func (tx *transaction) Cursor(bucket []byte) (database.Cursor, error) { func (tx *transaction) Cursor(bucket *database.Bucket) (database.Cursor, error) {
return tx.ldbTx.Cursor(bucket) return tx.ldbTx.Cursor(bucket)
} }

85
database/keys.go Normal file
View File

@ -0,0 +1,85 @@
package database
import (
"bytes"
"encoding/hex"
)
var bucketSeparator = []byte("/")
// Key is a helper type meant to combine prefix
// and suffix into a single database key.
type Key struct {
bucket *Bucket
suffix []byte
}
// Bytes returns the full key bytes that are consisted
// from the bucket path concatenated to the suffix.
func (k *Key) Bytes() []byte {
bucketPath := k.bucket.Path()
keyBytes := make([]byte, len(bucketPath)+len(k.suffix))
copy(keyBytes, bucketPath)
copy(keyBytes[len(bucketPath):], k.suffix)
return keyBytes
}
func (k *Key) String() string {
return hex.EncodeToString(k.Bytes())
}
// Bucket returns the key bucket.
func (k *Key) Bucket() *Bucket {
return k.bucket
}
// Suffix returns the key suffix.
func (k *Key) Suffix() []byte {
return k.suffix
}
// newKey returns a new key composed
// of the given bucket and suffix
func newKey(bucket *Bucket, suffix []byte) *Key {
return &Key{bucket: bucket, suffix: suffix}
}
// Bucket is a helper type meant to combine buckets
// and sub-buckets that can be used to create database
// keys and prefix-based cursors.
type Bucket struct {
path [][]byte
}
// MakeBucket creates a new Bucket using the given path
// of buckets.
func MakeBucket(path ...[]byte) *Bucket {
return &Bucket{path: path}
}
// Bucket returns the sub-bucket of the current bucket
// defined by bucketBytes.
func (b *Bucket) Bucket(bucketBytes []byte) *Bucket {
newPath := make([][]byte, len(b.path)+1)
copy(newPath, b.path)
copy(newPath[len(b.path):], [][]byte{bucketBytes})
return MakeBucket(newPath...)
}
// Key returns a key in the current bucket with the
// given suffix.
func (b *Bucket) Key(suffix []byte) *Key {
return newKey(b, suffix)
}
// Path returns the full path of the current bucket.
func (b *Bucket) Path() []byte {
bucketPath := bytes.Join(b.path, bucketSeparator)
bucketPathWithFinalSeparator := make([]byte, len(bucketPath)+len(bucketSeparator))
copy(bucketPathWithFinalSeparator, bucketPath)
copy(bucketPathWithFinalSeparator[len(bucketPath):], bucketSeparator)
return bucketPathWithFinalSeparator
}

View File

@ -1,6 +1,7 @@
package database package database
import ( import (
"bytes"
"reflect" "reflect"
"testing" "testing"
) )
@ -45,17 +46,26 @@ func TestBucketKey(t *testing.T) {
tests := []struct { tests := []struct {
bucketByteSlices [][]byte bucketByteSlices [][]byte
key []byte key []byte
expectedKey []byte expectedKeyBytes []byte
expectedKey *Key
}{ }{
{ {
bucketByteSlices: [][]byte{[]byte("hello")}, bucketByteSlices: [][]byte{[]byte("hello")},
key: []byte("test"), key: []byte("test"),
expectedKey: []byte("hello/test"), expectedKeyBytes: []byte("hello/test"),
expectedKey: &Key{
bucket: MakeBucket([]byte("hello")),
suffix: []byte("test"),
},
}, },
{ {
bucketByteSlices: [][]byte{[]byte("hello"), []byte("world")}, bucketByteSlices: [][]byte{[]byte("hello"), []byte("world")},
key: []byte("test"), key: []byte("test"),
expectedKey: []byte("hello/world/test"), expectedKeyBytes: []byte("hello/world/test"),
expectedKey: &Key{
bucket: MakeBucket([]byte("hello"), []byte("world")),
suffix: []byte("test"),
},
}, },
} }
@ -63,7 +73,11 @@ func TestBucketKey(t *testing.T) {
resultKey := MakeBucket(test.bucketByteSlices...).Key(test.key) resultKey := MakeBucket(test.bucketByteSlices...).Key(test.key)
if !reflect.DeepEqual(resultKey, test.expectedKey) { if !reflect.DeepEqual(resultKey, test.expectedKey) {
t.Errorf("TestBucketKey: got wrong key. Want: %s, got: %s", t.Errorf("TestBucketKey: got wrong key. Want: %s, got: %s",
string(test.expectedKey), string(resultKey)) test.expectedKeyBytes, resultKey)
}
if !bytes.Equal(resultKey.Bytes(), test.expectedKeyBytes) {
t.Errorf("TestBucketKey: got wrong key bytes. Want: %s, got: %s",
test.expectedKeyBytes, resultKey.Bytes())
} }
} }
} }

View File

@ -10,7 +10,7 @@ var (
acceptanceIndexBucket = database.MakeBucket([]byte("acceptance-index")) acceptanceIndexBucket = database.MakeBucket([]byte("acceptance-index"))
) )
func acceptanceIndexKey(hash *daghash.Hash) []byte { func acceptanceIndexKey(hash *daghash.Hash) *database.Key {
return acceptanceIndexBucket.Key(hash[:]) return acceptanceIndexBucket.Key(hash[:])
} }

View File

@ -14,7 +14,7 @@ var (
blockLocationsBucket = database.MakeBucket([]byte("block-locations")) blockLocationsBucket = database.MakeBucket([]byte("block-locations"))
) )
func blockLocationKey(hash *daghash.Hash) []byte { func blockLocationKey(hash *daghash.Hash) *database.Key {
return blockLocationsBucket.Key(hash[:]) return blockLocationsBucket.Key(hash[:])
} }

View File

@ -30,7 +30,7 @@ func BlockIndexCursor(context Context) (database.Cursor, error) {
return nil, err return nil, err
} }
return accessor.Cursor(blockIndexBucket.Path()) return accessor.Cursor(blockIndexBucket)
} }
// BlockIndexCursorFrom opens a cursor over blocks-index blocks // BlockIndexCursorFrom opens a cursor over blocks-index blocks

View File

@ -11,8 +11,8 @@ func clearBucket(dbTx *TxContext, bucket *database.Bucket) error {
// Collect all of the keys before deleting them. We do this // Collect all of the keys before deleting them. We do this
// as to not modify the cursor while we're still iterating // as to not modify the cursor while we're still iterating
// over it. // over it.
keys := make([][]byte, 0) keys := make([]*database.Key, 0)
cursor, err := accessor.Cursor(bucket.Path()) cursor, err := accessor.Cursor(bucket)
if err != nil { if err != nil {
return err return err
} }

View File

@ -1,7 +1,9 @@
package dbaccess package dbaccess
import "github.com/kaspanet/kaspad/database"
var ( var (
dagStateKey = []byte("dag-state") dagStateKey = database.MakeBucket().Key([]byte("dag-state"))
) )
// StoreDAGState stores the DAG state in the database. // StoreDAGState stores the DAG state in the database.

View File

@ -8,7 +8,7 @@ import (
var feeBucket = database.MakeBucket([]byte("fees")) var feeBucket = database.MakeBucket([]byte("fees"))
func feeDataKey(hash *daghash.Hash) []byte { func feeDataKey(hash *daghash.Hash) *database.Key {
return feeBucket.Key(hash[:]) return feeBucket.Key(hash[:])
} }

View File

@ -7,7 +7,7 @@ import (
var multisetBucket = database.MakeBucket([]byte("multiset")) var multisetBucket = database.MakeBucket([]byte("multiset"))
func multisetKey(hash *daghash.Hash) []byte { func multisetKey(hash *daghash.Hash) *database.Key {
return multisetBucket.Key(hash[:]) return multisetBucket.Key(hash[:])
} }
@ -19,7 +19,7 @@ func MultisetCursor(context Context) (database.Cursor, error) {
return nil, err return nil, err
} }
return accessor.Cursor(multisetBucket.Path()) return accessor.Cursor(multisetBucket)
} }
// StoreMultiset stores the multiset of a block by its hash. // StoreMultiset stores the multiset of a block by its hash.

View File

@ -7,7 +7,7 @@ import (
var reachabilityDataBucket = database.MakeBucket([]byte("reachability")) var reachabilityDataBucket = database.MakeBucket([]byte("reachability"))
func reachabilityKey(hash *daghash.Hash) []byte { func reachabilityKey(hash *daghash.Hash) *database.Key {
return reachabilityDataBucket.Key(hash[:]) return reachabilityDataBucket.Key(hash[:])
} }
@ -19,7 +19,7 @@ func ReachabilityDataCursor(context Context) (database.Cursor, error) {
return nil, err return nil, err
} }
return accessor.Cursor(reachabilityDataBucket.Path()) return accessor.Cursor(reachabilityDataBucket)
} }
// StoreReachabilityData stores the reachability data of a block by its hash. // StoreReachabilityData stores the reachability data of a block by its hash.

View File

@ -7,7 +7,7 @@ import (
var subnetworkBucket = database.MakeBucket([]byte("subnetworks")) var subnetworkBucket = database.MakeBucket([]byte("subnetworks"))
func subnetworkKey(subnetworkID *subnetworkid.SubnetworkID) []byte { func subnetworkKey(subnetworkID *subnetworkid.SubnetworkID) *database.Key {
return subnetworkBucket.Key(subnetworkID[:]) return subnetworkBucket.Key(subnetworkID[:])
} }

View File

@ -8,7 +8,7 @@ var (
utxoBucket = database.MakeBucket([]byte("utxo")) utxoBucket = database.MakeBucket([]byte("utxo"))
) )
func utxoKey(outpointKey []byte) []byte { func utxoKey(outpointKey []byte) *database.Key {
return utxoBucket.Key(outpointKey) return utxoBucket.Key(outpointKey)
} }
@ -44,5 +44,5 @@ func UTXOSetCursor(context Context) (database.Cursor, error) {
return nil, err return nil, err
} }
return accessor.Cursor(utxoBucket.Path()) return accessor.Cursor(utxoBucket)
} }

View File

@ -8,7 +8,7 @@ import (
var utxoDiffsBucket = database.MakeBucket([]byte("utxo-diffs")) var utxoDiffsBucket = database.MakeBucket([]byte("utxo-diffs"))
func utxoDiffKey(hash *daghash.Hash) []byte { func utxoDiffKey(hash *daghash.Hash) *database.Key {
return utxoDiffsBucket.Key(hash[:]) return utxoDiffsBucket.Key(hash[:])
} }