cosmos-sdk/server/v2/stf/branch/store.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
}