Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: implement object stores #22893

Open
wants to merge 10 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ Every module contains its own CHANGELOG.md. Please refer to the module you are i
* (crypto/keyring) [#21653](https://github.com/cosmos/cosmos-sdk/pull/21653) New Linux-only backend that adds Linux kernel's `keyctl` support.
* (client/keys) [#21829](https://github.com/cosmos/cosmos-sdk/pull/21829) Add support for importing hex key using standard input.
* (client) [#22807](https://github.com/cosmos/cosmos-sdk/pull/22807) Return v2 server information in the `version` command.
* (baseapp) [#22893](https://github.com/cosmos/cosmos-sdk/pull/22893) Support mount object store in baseapp, add `ObjectStore` api in context.

### Improvements

Expand Down
13 changes: 13 additions & 0 deletions baseapp/baseapp.go
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,9 @@
case *storetypes.MemoryStoreKey:
app.MountStore(key, storetypes.StoreTypeMemory)

case *storetypes.ObjectStoreKey:

Check failure on line 308 in baseapp/baseapp.go

View workflow job for this annotation

GitHub Actions / dependency-review

undefined: storetypes.ObjectStoreKey
app.MountStore(key, storetypes.StoreTypeObject)

Check failure on line 309 in baseapp/baseapp.go

View workflow job for this annotation

GitHub Actions / dependency-review

undefined: storetypes.StoreTypeObject

default:
panic(fmt.Sprintf("Unrecognized store key type :%T", key))
}
Expand Down Expand Up @@ -343,6 +346,16 @@
}
}

// MountObjectStores mounts all transient object stores with the BaseApp's internal
// commit multi-store.
func (app *BaseApp) MountObjectStores(keys map[string]*storetypes.ObjectStoreKey) {

Check failure on line 351 in baseapp/baseapp.go

View workflow job for this annotation

GitHub Actions / dependency-review

undefined: storetypes.ObjectStoreKey
skeys := slices.Sorted(maps.Keys(keys))
for _, key := range skeys {
memKey := keys[key]
app.MountStore(memKey, storetypes.StoreTypeObject)

Check failure on line 355 in baseapp/baseapp.go

View workflow job for this annotation

GitHub Actions / dependency-review

undefined: storetypes.StoreTypeObject
}
}

// MountStore mounts a store to the provided key in the BaseApp multistore,
// using the default DB.
func (app *BaseApp) MountStore(key storetypes.StoreKey, typ storetypes.StoreType) {
Expand Down
7 changes: 7 additions & 0 deletions runtime/module.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@
ProvideKVStoreFactory,
ProvideTransientStoreKey,
ProvideMemoryStoreKey,
ProvideObjectStoreKey,
ProvideGenesisTxHandler,
ProvideEnvironment,
ProvideTransientStoreService,
Expand Down Expand Up @@ -242,6 +243,12 @@
return storeKey
}

func ProvideObjectStoreKey(key depinject.ModuleKey, app *AppBuilder) *storetypes.ObjectStoreKey {

Check failure on line 246 in runtime/module.go

View workflow job for this annotation

GitHub Actions / dependency-review

undefined: storetypes.ObjectStoreKey
storeKey := storetypes.NewObjectStoreKey(fmt.Sprintf("object:%s", key.Name()))

Check failure on line 247 in runtime/module.go

View workflow job for this annotation

GitHub Actions / dependency-review

undefined: storetypes.NewObjectStoreKey
registerStoreKey(app, storeKey)
return storeKey
}

func ProvideModuleManager(modules map[string]appmodule.AppModule) *module.Manager {
return module.NewManagerFromMap(modules)
}
Expand Down
4 changes: 2 additions & 2 deletions runtime/store.go
Original file line number Diff line number Diff line change
Expand Up @@ -163,15 +163,15 @@ func (s kvStoreAdapter) Set(key, value []byte) {
}
}

func (s kvStoreAdapter) Iterator(start, end []byte) store.Iterator {
func (s kvStoreAdapter) Iterator(start, end []byte) storetypes.Iterator {
it, err := s.store.Iterator(start, end)
if err != nil {
panic(err)
}
return it
}

func (s kvStoreAdapter) ReverseIterator(start, end []byte) store.Iterator {
func (s kvStoreAdapter) ReverseIterator(start, end []byte) storetypes.Iterator {
it, err := s.store.ReverseIterator(start, end)
if err != nil {
panic(err)
Expand Down
12 changes: 4 additions & 8 deletions server/mock/store.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,6 @@
panic("not implemented")
}

func (ms multiStore) CacheWrapWithListeners(_ storetypes.StoreKey, _ []storetypes.MemoryListener) storetypes.CacheWrap {
panic("not implemented")
}

func (ms multiStore) TracingEnabled() bool {
panic("not implemented")
}
Expand Down Expand Up @@ -114,6 +110,10 @@
return ms.kv[key]
}

func (ms multiStore) GetObjKVStore(storetypes.StoreKey) storetypes.ObjKVStore {

Check failure on line 113 in server/mock/store.go

View workflow job for this annotation

GitHub Actions / dependency-review

undefined: storetypes.ObjKVStore
panic("not implemented")
}

func (ms multiStore) GetStore(key storetypes.StoreKey) storetypes.Store {
panic("not implemented")
}
Expand Down Expand Up @@ -186,10 +186,6 @@
panic("not implemented")
}

func (kv kvStore) CacheWrapWithListeners(_ storetypes.StoreKey, _ []storetypes.MemoryListener) storetypes.CacheWrap {
panic("not implemented")
}

func (kv kvStore) GetStoreType() storetypes.StoreType {
panic("not implemented")
}
Expand Down
4 changes: 4 additions & 0 deletions store/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@ Ref: https://keepachangelog.com/en/1.0.0/

## v1.10.0 (December 13, 2024)

### Features

* [#22893](https://github.com/cosmos/cosmos-sdk/pull/22893) Support mount object store in baseapp, add `ObjectStore` api in context.

### Improvements

* [#22305](https://github.com/cosmos/cosmos-sdk/pull/22305) Add `LatestVersion` to the `Committer` interface to get the latest version of the store.
Expand Down
43 changes: 23 additions & 20 deletions store/cachekv/internal/mergeiterator.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,21 +14,24 @@ import (
// cache shadows (overrides) the parent.
//
// TODO: Optimize by memoizing.
type cacheMergeIterator struct {
parent types.Iterator
cache types.Iterator
type cacheMergeIterator[V any] struct {
parent types.GIterator[V]
cache types.GIterator[V]
ascending bool

valid bool

isZero func(V) bool
}

var _ types.Iterator = (*cacheMergeIterator)(nil)
var _ types.Iterator = (*cacheMergeIterator[[]byte])(nil)

func NewCacheMergeIterator(parent, cache types.Iterator, ascending bool) types.Iterator {
iter := &cacheMergeIterator{
func NewCacheMergeIterator[V any](parent, cache types.GIterator[V], ascending bool, isZero func(V) bool) types.GIterator[V] {
iter := &cacheMergeIterator[V]{
parent: parent,
cache: cache,
ascending: ascending,
isZero: isZero,
}

iter.valid = iter.skipUntilExistsOrInvalid()
Expand All @@ -37,17 +40,17 @@ func NewCacheMergeIterator(parent, cache types.Iterator, ascending bool) types.I

// Domain implements Iterator.
// Returns parent domain because cache and parent domains are the same.
func (iter *cacheMergeIterator) Domain() (start, end []byte) {
func (iter *cacheMergeIterator[V]) Domain() (start, end []byte) {
return iter.parent.Domain()
}

// Valid implements Iterator.
func (iter *cacheMergeIterator) Valid() bool {
func (iter *cacheMergeIterator[V]) Valid() bool {
return iter.valid
}

// Next implements Iterator
func (iter *cacheMergeIterator) Next() {
func (iter *cacheMergeIterator[V]) Next() {
iter.assertValid()

switch {
Expand All @@ -74,7 +77,7 @@ func (iter *cacheMergeIterator) Next() {
}

// Key implements Iterator
func (iter *cacheMergeIterator) Key() []byte {
func (iter *cacheMergeIterator[V]) Key() []byte {
iter.assertValid()

// If parent is invalid, get the cache key.
Expand Down Expand Up @@ -104,7 +107,7 @@ func (iter *cacheMergeIterator) Key() []byte {
}

// Value implements Iterator
func (iter *cacheMergeIterator) Value() []byte {
func (iter *cacheMergeIterator[V]) Value() V {
iter.assertValid()

// If parent is invalid, get the cache value.
Expand Down Expand Up @@ -134,7 +137,7 @@ func (iter *cacheMergeIterator) Value() []byte {
}

// Close implements Iterator
func (iter *cacheMergeIterator) Close() error {
func (iter *cacheMergeIterator[V]) Close() error {
err1 := iter.cache.Close()
if err := iter.parent.Close(); err != nil {
return err
Expand All @@ -145,7 +148,7 @@ func (iter *cacheMergeIterator) Close() error {

// Error returns an error if the cacheMergeIterator is invalid defined by the
// Valid method.
func (iter *cacheMergeIterator) Error() error {
func (iter *cacheMergeIterator[V]) Error() error {
if !iter.Valid() {
return errors.New("invalid cacheMergeIterator")
}
Expand All @@ -155,14 +158,14 @@ func (iter *cacheMergeIterator) Error() error {

// If not valid, panics.
// NOTE: May have side-effect of iterating over cache.
func (iter *cacheMergeIterator) assertValid() {
func (iter *cacheMergeIterator[V]) assertValid() {
if err := iter.Error(); err != nil {
panic(err)
}
}

// Like bytes.Compare but opposite if not ascending.
func (iter *cacheMergeIterator) compare(a, b []byte) int {
func (iter *cacheMergeIterator[V]) compare(a, b []byte) int {
if iter.ascending {
return bytes.Compare(a, b)
}
Expand All @@ -175,9 +178,9 @@ func (iter *cacheMergeIterator) compare(a, b []byte) int {
// If the current cache item is not a delete item, does nothing.
// If `until` is nil, there is no limit, and cache may end up invalid.
// CONTRACT: cache is valid.
func (iter *cacheMergeIterator) skipCacheDeletes(until []byte) {
func (iter *cacheMergeIterator[V]) skipCacheDeletes(until []byte) {
for iter.cache.Valid() &&
iter.cache.Value() == nil &&
iter.isZero(iter.cache.Value()) &&
(until == nil || iter.compare(iter.cache.Key(), until) < 0) {
iter.cache.Next()
}
Expand All @@ -186,7 +189,7 @@ func (iter *cacheMergeIterator) skipCacheDeletes(until []byte) {
// Fast forwards cache (or parent+cache in case of deleted items) until current
// item exists, or until iterator becomes invalid.
// Returns whether the iterator is valid.
func (iter *cacheMergeIterator) skipUntilExistsOrInvalid() bool {
func (iter *cacheMergeIterator[V]) skipUntilExistsOrInvalid() bool {
for {
// If parent is invalid, fast-forward cache.
if !iter.parent.Valid() {
Expand All @@ -211,7 +214,7 @@ func (iter *cacheMergeIterator) skipUntilExistsOrInvalid() bool {
case 0: // parent == cache.
// Skip over if cache item is a delete.
valueC := iter.cache.Value()
if valueC == nil {
if iter.isZero(valueC) {
iter.parent.Next()
iter.cache.Next()

Expand All @@ -223,7 +226,7 @@ func (iter *cacheMergeIterator) skipUntilExistsOrInvalid() bool {
case 1: // cache < parent
// Skip over if cache item is a delete.
valueC := iter.cache.Value()
if valueC == nil {
if iter.isZero(valueC) {
iter.skipCacheDeletes(keyP)
continue
}
Expand Down
12 changes: 6 additions & 6 deletions store/cachekv/search_benchmark_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import (
"strconv"
"testing"

"cosmossdk.io/store/cachekv/internal"
"cosmossdk.io/store/internal/btree"
)

func BenchmarkLargeUnsortedMisses(b *testing.B) {
Expand All @@ -22,23 +22,23 @@ func BenchmarkLargeUnsortedMisses(b *testing.B) {
}

func generateStore() *Store {
cache := map[string]*cValue{}
cache := map[string]*cValue[[]byte]{}
unsorted := map[string]struct{}{}
for i := 0; i < 5000; i++ {
key := "A" + strconv.Itoa(i)
unsorted[key] = struct{}{}
cache[key] = &cValue{}
cache[key] = &cValue[[]byte]{}
}

for i := 0; i < 5000; i++ {
key := "Z" + strconv.Itoa(i)
unsorted[key] = struct{}{}
cache[key] = &cValue{}
cache[key] = &cValue[[]byte]{}
}

return &Store{
return &GStore[[]byte]{
cache: cache,
unsortedCache: unsorted,
sortedCache: internal.NewBTree(),
sortedCache: btree.NewBTree[[]byte](),
}
}
Loading
Loading