mirror of
https://github.com/kaspanet/kaspad.git
synced 2025-06-06 06:06:49 +00:00
[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:
parent
df934990d7
commit
7609c50641
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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
|
|
||||||
}
|
|
@ -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
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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 {
|
||||||
|
@ -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.
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
@ -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 {
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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
85
database/keys.go
Normal 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
|
||||||
|
}
|
@ -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())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -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[:])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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[:])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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.
|
||||||
|
@ -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[:])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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.
|
||||||
|
@ -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.
|
||||||
|
@ -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[:])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
@ -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[:])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user