140 lines
2.9 KiB
Go
140 lines
2.9 KiB
Go
package branch
|
|
|
|
import (
|
|
"errors"
|
|
|
|
"cosmossdk.io/core/store"
|
|
)
|
|
|
|
var _ store.Writer = (*Store[store.Reader])(nil)
|
|
|
|
// Store wraps an in-memory child around an underlying types.KVStore.
|
|
type Store[T store.Reader] struct {
|
|
changeSet changeSet // ordered changeset.
|
|
parent T
|
|
}
|
|
|
|
// NewStore creates a new Store object
|
|
func NewStore[T store.Reader](parent T) Store[T] {
|
|
return Store[T]{
|
|
changeSet: newChangeSet(),
|
|
parent: parent,
|
|
}
|
|
}
|
|
|
|
// Get implements types.KVStore.
|
|
func (s Store[T]) Get(key []byte) (value []byte, err error) {
|
|
// if found in memory cache, immediately return.
|
|
value, found := s.changeSet.get(key)
|
|
if found {
|
|
return
|
|
}
|
|
// if not found in the changeset, then check the parent.
|
|
value, err = s.parent.Get(key)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return value, nil
|
|
}
|
|
|
|
// Set implements types.KVStore.
|
|
func (s Store[T]) Set(key, value []byte) error {
|
|
if value == nil {
|
|
return errors.New("cannot set a nil value")
|
|
}
|
|
s.changeSet.set(key, value)
|
|
return nil
|
|
}
|
|
|
|
// Has implements types.KVStore.
|
|
func (s Store[T]) Has(key []byte) (bool, error) {
|
|
tmpValue, found := s.changeSet.get(key)
|
|
if found {
|
|
return tmpValue != nil, nil
|
|
}
|
|
return s.parent.Has(key)
|
|
}
|
|
|
|
// Delete implements types.KVStore.
|
|
func (s Store[T]) Delete(key []byte) error {
|
|
s.changeSet.delete(key)
|
|
return nil
|
|
}
|
|
|
|
// ----------------------------------------
|
|
// Iteration
|
|
|
|
// Iterator implements types.KVStore.
|
|
func (s Store[T]) Iterator(start, end []byte) (store.Iterator, error) {
|
|
return s.iterator(start, end, true)
|
|
}
|
|
|
|
// ReverseIterator implements types.KVStore.
|
|
func (s Store[T]) ReverseIterator(start, end []byte) (store.Iterator, error) {
|
|
return s.iterator(start, end, false)
|
|
}
|
|
|
|
func (s Store[T]) iterator(start, end []byte, ascending bool) (store.Iterator, error) {
|
|
var (
|
|
err error
|
|
parent, cache store.Iterator
|
|
)
|
|
|
|
if ascending {
|
|
parent, err = s.parent.Iterator(start, end)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
cache, err = s.changeSet.iterator(start, end)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return mergeIterators(parent, cache, ascending), nil
|
|
} else {
|
|
parent, err = s.parent.ReverseIterator(start, end)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
cache, err = s.changeSet.reverseIterator(start, end)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return mergeIterators(parent, cache, ascending), nil
|
|
}
|
|
}
|
|
|
|
func (s Store[T]) ApplyChangeSets(changes []store.KVPair) error {
|
|
for _, c := range changes {
|
|
if c.Remove {
|
|
err := s.Delete(c.Key)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
} else {
|
|
err := s.Set(c.Key, c.Value)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (s Store[T]) ChangeSets() (cs []store.KVPair, err error) {
|
|
iter, err := s.changeSet.iterator(nil, nil)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer iter.Close()
|
|
|
|
for ; iter.Valid(); iter.Next() {
|
|
k, v := iter.Key(), iter.Value()
|
|
cs = append(cs, store.KVPair{
|
|
Key: k,
|
|
Value: v,
|
|
Remove: v == nil, // maybe we can optimistically compute size.
|
|
})
|
|
}
|
|
return cs, nil
|
|
}
|