|
|
|
package prefix
|
|
|
|
|
|
|
|
import (
|
|
|
|
"github.com/ethereum/go-ethereum/ethdb"
|
|
|
|
"github.com/harmony-one/harmony/internal/tikv/byte_alloc"
|
|
|
|
"github.com/harmony-one/harmony/internal/tikv/common"
|
|
|
|
)
|
|
|
|
|
|
|
|
// PrefixDatabase is a wrapper to split the storage with prefix
|
|
|
|
type PrefixDatabase struct {
|
|
|
|
prefix []byte
|
|
|
|
db common.TiKVStore
|
|
|
|
keysPool *byte_alloc.Allocator
|
|
|
|
}
|
|
|
|
|
|
|
|
func NewPrefixDatabase(prefix []byte, db common.TiKVStore) *PrefixDatabase {
|
|
|
|
return &PrefixDatabase{
|
|
|
|
prefix: prefix,
|
|
|
|
db: db,
|
|
|
|
keysPool: byte_alloc.NewAllocator(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (p *PrefixDatabase) AncientDatadir() (string, error) {
|
|
|
|
return "", nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// NewBatchWithSize creates a write-only database batch with pre-allocated buffer.
|
|
|
|
func (p *PrefixDatabase) NewBatchWithSize(size int) ethdb.Batch {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// makeKey use to create a key with prefix, keysPool can reduce gc pressure
|
|
|
|
func (p *PrefixDatabase) makeKey(keys []byte) []byte {
|
|
|
|
prefixLen := len(p.prefix)
|
|
|
|
byt := p.keysPool.Get(len(keys) + prefixLen)
|
|
|
|
copy(byt, p.prefix)
|
|
|
|
copy(byt[prefixLen:], keys)
|
|
|
|
|
|
|
|
return byt
|
|
|
|
}
|
|
|
|
|
|
|
|
// Has retrieves if a key is present in the key-value data store.
|
|
|
|
func (p *PrefixDatabase) Has(key []byte) (bool, error) {
|
|
|
|
return p.db.Has(p.makeKey(key))
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get retrieves the given key if it's present in the key-value data store.
|
|
|
|
func (p *PrefixDatabase) Get(key []byte) ([]byte, error) {
|
|
|
|
return p.db.Get(p.makeKey(key))
|
|
|
|
}
|
|
|
|
|
|
|
|
// Put inserts the given value into the key-value data store.
|
|
|
|
func (p *PrefixDatabase) Put(key []byte, value []byte) error {
|
|
|
|
return p.db.Put(p.makeKey(key), value)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Delete removes the key from the key-value data store.
|
|
|
|
func (p *PrefixDatabase) Delete(key []byte) error {
|
|
|
|
return p.db.Delete(p.makeKey(key))
|
|
|
|
}
|
|
|
|
|
|
|
|
// NewBatch creates a write-only database that buffers changes to its host db
|
|
|
|
// until a final write is called.
|
|
|
|
func (p *PrefixDatabase) NewBatch() ethdb.Batch {
|
|
|
|
return newPrefixBatch(p.prefix, p.db.NewBatch())
|
|
|
|
}
|
|
|
|
|
|
|
|
// buildLimitUsePrefix build the limit byte from start byte, useful generating from prefix works
|
|
|
|
func (p *PrefixDatabase) buildLimitUsePrefix() []byte {
|
|
|
|
var limit []byte
|
|
|
|
for i := len(p.prefix) - 1; i >= 0; i-- {
|
|
|
|
c := p.prefix[i]
|
|
|
|
if c < 0xff {
|
|
|
|
limit = make([]byte, i+1)
|
|
|
|
copy(limit, p.prefix)
|
|
|
|
limit[i] = c + 1
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return limit
|
|
|
|
}
|
|
|
|
|
|
|
|
// NewIterator creates a binary-alphabetical iterator over the start to end keyspace
|
|
|
|
// contained within the key-value database.
|
|
|
|
func (p *PrefixDatabase) NewIterator(start, end []byte) ethdb.Iterator {
|
|
|
|
start = append(p.prefix, start...)
|
|
|
|
|
|
|
|
if len(end) == 0 {
|
|
|
|
end = p.buildLimitUsePrefix()
|
|
|
|
} else {
|
|
|
|
end = append(p.prefix, end...)
|
|
|
|
}
|
|
|
|
|
|
|
|
return newPrefixIterator(p.prefix, p.db.NewIterator(start, end))
|
|
|
|
}
|
|
|
|
|
|
|
|
// Stat returns a particular internal stat of the database.
|
|
|
|
func (p *PrefixDatabase) Stat(property string) (string, error) {
|
|
|
|
return p.db.Stat(property)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Compact flattens the underlying data store for the given key range. In essence,
|
|
|
|
// deleted and overwritten versions are discarded, and the data is rearranged to
|
|
|
|
// reduce the cost of operations needed to access them.
|
|
|
|
//
|
|
|
|
// A nil start is treated as a key before all keys in the data store; a nil limit
|
|
|
|
// is treated as a key after all keys in the data store. If both is nil then it
|
|
|
|
// will compact entire data store.
|
|
|
|
func (p *PrefixDatabase) Compact(start []byte, limit []byte) error {
|
|
|
|
return p.db.Compact(start, limit)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Close the storage
|
|
|
|
func (p *PrefixDatabase) Close() error {
|
|
|
|
return p.db.Close()
|
|
|
|
}
|