Skip to content

Commit 8ad2ace

Browse files
yihuangmmsqe
authored andcommitted
Support object store (#206)
generic interface generic btree generic cachekv generic transient store support ObjStore changelog Update CHANGELOG.md Signed-off-by: yihuang <[email protected]> object store key Apply review suggestions fix merge conflict fix snapshot revert dependers Problem: store key type assertion is incorrect (#244) fix and add test
1 parent c263939 commit 8ad2ace

File tree

24 files changed

+595
-276
lines changed

24 files changed

+595
-276
lines changed

baseapp/baseapp.go

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,16 @@ import (
44
"context"
55
"errors"
66
"fmt"
7-
"maps"
87
"math"
9-
"slices"
8+
"sort"
109
"strconv"
1110
"sync"
1211

1312
abci "github.com/cometbft/cometbft/api/cometbft/abci/v1"
1413
cmtproto "github.com/cometbft/cometbft/api/cometbft/types/v1"
1514
"github.com/cometbft/cometbft/crypto/tmhash"
1615
"github.com/cosmos/gogoproto/proto"
16+
"golang.org/x/exp/maps"
1717
"google.golang.org/protobuf/reflect/protoreflect"
1818

1919
"cosmossdk.io/core/header"
@@ -336,13 +336,25 @@ func (app *BaseApp) MountTransientStores(keys map[string]*storetypes.TransientSt
336336
// MountMemoryStores mounts all in-memory KVStores with the BaseApp's internal
337337
// commit multi-store.
338338
func (app *BaseApp) MountMemoryStores(keys map[string]*storetypes.MemoryStoreKey) {
339-
skeys := slices.Sorted(maps.Keys(keys))
339+
skeys := maps.Keys(keys)
340+
sort.Strings(skeys)
340341
for _, key := range skeys {
341342
memKey := keys[key]
342343
app.MountStore(memKey, storetypes.StoreTypeMemory)
343344
}
344345
}
345346

347+
// MountObjectStores mounts all transient object stores with the BaseApp's internal
348+
// commit multi-store.
349+
func (app *BaseApp) MountObjectStores(keys map[string]*storetypes.ObjectStoreKey) {
350+
skeys := maps.Keys(keys)
351+
sort.Strings(skeys)
352+
for _, key := range skeys {
353+
memKey := keys[key]
354+
app.MountStore(memKey, storetypes.StoreTypeObject)
355+
}
356+
}
357+
346358
// MountStore mounts a store to the provided key in the BaseApp multistore,
347359
// using the default DB.
348360
func (app *BaseApp) MountStore(key storetypes.StoreKey, typ storetypes.StoreType) {

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ require (
5454
gitlab.com/yawning/secp256k1-voi v0.0.0-20230925100816-f2616030848b
5555
go.uber.org/mock v0.5.0
5656
golang.org/x/crypto v0.31.0
57+
golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f
5758
golang.org/x/sync v0.10.0
5859
google.golang.org/genproto/googleapis/api v0.0.0-20240903143218-8af14fe29dc1
5960
google.golang.org/grpc v1.68.1
@@ -163,7 +164,6 @@ require (
163164
go.opencensus.io v0.24.0 // indirect
164165
go.uber.org/multierr v1.11.0 // indirect
165166
golang.org/x/arch v0.12.0 // indirect
166-
golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f // indirect
167167
golang.org/x/mod v0.22.0 // indirect
168168
golang.org/x/net v0.32.0 // indirect
169169
golang.org/x/sys v0.28.0 // indirect

runtime/store.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -163,15 +163,15 @@ func (s kvStoreAdapter) Set(key, value []byte) {
163163
}
164164
}
165165

166-
func (s kvStoreAdapter) Iterator(start, end []byte) store.Iterator {
166+
func (s kvStoreAdapter) Iterator(start, end []byte) storetypes.Iterator {
167167
it, err := s.store.Iterator(start, end)
168168
if err != nil {
169169
panic(err)
170170
}
171171
return it
172172
}
173173

174-
func (s kvStoreAdapter) ReverseIterator(start, end []byte) store.Iterator {
174+
func (s kvStoreAdapter) ReverseIterator(start, end []byte) storetypes.Iterator {
175175
it, err := s.store.ReverseIterator(start, end)
176176
if err != nil {
177177
panic(err)

server/mock/store.go

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,6 @@ func (ms multiStore) CacheWrapWithTrace(_ io.Writer, _ storetypes.TraceContext)
3434
panic("not implemented")
3535
}
3636

37-
func (ms multiStore) CacheWrapWithListeners(_ storetypes.StoreKey, _ []storetypes.MemoryListener) storetypes.CacheWrap {
38-
panic("not implemented")
39-
}
40-
4137
func (ms multiStore) TracingEnabled() bool {
4238
panic("not implemented")
4339
}
@@ -114,6 +110,10 @@ func (ms multiStore) GetKVStore(key storetypes.StoreKey) storetypes.KVStore {
114110
return ms.kv[key]
115111
}
116112

113+
func (ms multiStore) GetObjKVStore(storetypes.StoreKey) storetypes.ObjKVStore {
114+
panic("not implemented")
115+
}
116+
117117
func (ms multiStore) GetStore(key storetypes.StoreKey) storetypes.Store {
118118
panic("not implemented")
119119
}
@@ -186,10 +186,6 @@ func (kv kvStore) CacheWrapWithTrace(w io.Writer, tc storetypes.TraceContext) st
186186
panic("not implemented")
187187
}
188188

189-
func (kv kvStore) CacheWrapWithListeners(_ storetypes.StoreKey, _ []storetypes.MemoryListener) storetypes.CacheWrap {
190-
panic("not implemented")
191-
}
192-
193189
func (kv kvStore) GetStoreType() storetypes.StoreType {
194190
panic("not implemented")
195191
}

store/cachekv/internal/mergeiterator.go

Lines changed: 23 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -14,21 +14,24 @@ import (
1414
// cache shadows (overrides) the parent.
1515
//
1616
// TODO: Optimize by memoizing.
17-
type cacheMergeIterator struct {
18-
parent types.Iterator
19-
cache types.Iterator
17+
type cacheMergeIterator[V any] struct {
18+
parent types.GIterator[V]
19+
cache types.GIterator[V]
2020
ascending bool
2121

2222
valid bool
23+
24+
isZero func(V) bool
2325
}
2426

25-
var _ types.Iterator = (*cacheMergeIterator)(nil)
27+
var _ types.Iterator = (*cacheMergeIterator[[]byte])(nil)
2628

27-
func NewCacheMergeIterator(parent, cache types.Iterator, ascending bool) types.Iterator {
28-
iter := &cacheMergeIterator{
29+
func NewCacheMergeIterator[V any](parent, cache types.GIterator[V], ascending bool, isZero func(V) bool) types.GIterator[V] {
30+
iter := &cacheMergeIterator[V]{
2931
parent: parent,
3032
cache: cache,
3133
ascending: ascending,
34+
isZero: isZero,
3235
}
3336

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

3841
// Domain implements Iterator.
3942
// Returns parent domain because cache and parent domains are the same.
40-
func (iter *cacheMergeIterator) Domain() (start, end []byte) {
43+
func (iter *cacheMergeIterator[V]) Domain() (start, end []byte) {
4144
return iter.parent.Domain()
4245
}
4346

4447
// Valid implements Iterator.
45-
func (iter *cacheMergeIterator) Valid() bool {
48+
func (iter *cacheMergeIterator[V]) Valid() bool {
4649
return iter.valid
4750
}
4851

4952
// Next implements Iterator
50-
func (iter *cacheMergeIterator) Next() {
53+
func (iter *cacheMergeIterator[V]) Next() {
5154
iter.assertValid()
5255

5356
switch {
@@ -74,7 +77,7 @@ func (iter *cacheMergeIterator) Next() {
7477
}
7578

7679
// Key implements Iterator
77-
func (iter *cacheMergeIterator) Key() []byte {
80+
func (iter *cacheMergeIterator[V]) Key() []byte {
7881
iter.assertValid()
7982

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

106109
// Value implements Iterator
107-
func (iter *cacheMergeIterator) Value() []byte {
110+
func (iter *cacheMergeIterator[V]) Value() V {
108111
iter.assertValid()
109112

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

136139
// Close implements Iterator
137-
func (iter *cacheMergeIterator) Close() error {
140+
func (iter *cacheMergeIterator[V]) Close() error {
138141
err1 := iter.cache.Close()
139142
if err := iter.parent.Close(); err != nil {
140143
return err
@@ -145,7 +148,7 @@ func (iter *cacheMergeIterator) Close() error {
145148

146149
// Error returns an error if the cacheMergeIterator is invalid defined by the
147150
// Valid method.
148-
func (iter *cacheMergeIterator) Error() error {
151+
func (iter *cacheMergeIterator[V]) Error() error {
149152
if !iter.Valid() {
150153
return errors.New("invalid cacheMergeIterator")
151154
}
@@ -155,14 +158,14 @@ func (iter *cacheMergeIterator) Error() error {
155158

156159
// If not valid, panics.
157160
// NOTE: May have side-effect of iterating over cache.
158-
func (iter *cacheMergeIterator) assertValid() {
161+
func (iter *cacheMergeIterator[V]) assertValid() {
159162
if err := iter.Error(); err != nil {
160163
panic(err)
161164
}
162165
}
163166

164167
// Like bytes.Compare but opposite if not ascending.
165-
func (iter *cacheMergeIterator) compare(a, b []byte) int {
168+
func (iter *cacheMergeIterator[V]) compare(a, b []byte) int {
166169
if iter.ascending {
167170
return bytes.Compare(a, b)
168171
}
@@ -175,9 +178,9 @@ func (iter *cacheMergeIterator) compare(a, b []byte) int {
175178
// If the current cache item is not a delete item, does nothing.
176179
// If `until` is nil, there is no limit, and cache may end up invalid.
177180
// CONTRACT: cache is valid.
178-
func (iter *cacheMergeIterator) skipCacheDeletes(until []byte) {
181+
func (iter *cacheMergeIterator[V]) skipCacheDeletes(until []byte) {
179182
for iter.cache.Valid() &&
180-
iter.cache.Value() == nil &&
183+
iter.isZero(iter.cache.Value()) &&
181184
(until == nil || iter.compare(iter.cache.Key(), until) < 0) {
182185
iter.cache.Next()
183186
}
@@ -186,7 +189,7 @@ func (iter *cacheMergeIterator) skipCacheDeletes(until []byte) {
186189
// Fast forwards cache (or parent+cache in case of deleted items) until current
187190
// item exists, or until iterator becomes invalid.
188191
// Returns whether the iterator is valid.
189-
func (iter *cacheMergeIterator) skipUntilExistsOrInvalid() bool {
192+
func (iter *cacheMergeIterator[V]) skipUntilExistsOrInvalid() bool {
190193
for {
191194
// If parent is invalid, fast-forward cache.
192195
if !iter.parent.Valid() {
@@ -211,7 +214,7 @@ func (iter *cacheMergeIterator) skipUntilExistsOrInvalid() bool {
211214
case 0: // parent == cache.
212215
// Skip over if cache item is a delete.
213216
valueC := iter.cache.Value()
214-
if valueC == nil {
217+
if iter.isZero(valueC) {
215218
iter.parent.Next()
216219
iter.cache.Next()
217220

@@ -223,7 +226,7 @@ func (iter *cacheMergeIterator) skipUntilExistsOrInvalid() bool {
223226
case 1: // cache < parent
224227
// Skip over if cache item is a delete.
225228
valueC := iter.cache.Value()
226-
if valueC == nil {
229+
if iter.isZero(valueC) {
227230
iter.skipCacheDeletes(keyP)
228231
continue
229232
}

store/cachekv/search_benchmark_test.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import (
44
"strconv"
55
"testing"
66

7-
"cosmossdk.io/store/cachekv/internal"
7+
"cosmossdk.io/store/internal/btree"
88
)
99

1010
func BenchmarkLargeUnsortedMisses(b *testing.B) {
@@ -22,23 +22,23 @@ func BenchmarkLargeUnsortedMisses(b *testing.B) {
2222
}
2323

2424
func generateStore() *Store {
25-
cache := map[string]*cValue{}
25+
cache := map[string]*cValue[[]byte]{}
2626
unsorted := map[string]struct{}{}
2727
for i := 0; i < 5000; i++ {
2828
key := "A" + strconv.Itoa(i)
2929
unsorted[key] = struct{}{}
30-
cache[key] = &cValue{}
30+
cache[key] = &cValue[[]byte]{}
3131
}
3232

3333
for i := 0; i < 5000; i++ {
3434
key := "Z" + strconv.Itoa(i)
3535
unsorted[key] = struct{}{}
36-
cache[key] = &cValue{}
36+
cache[key] = &cValue[[]byte]{}
3737
}
3838

39-
return &Store{
39+
return &GStore[[]byte]{
4040
cache: cache,
4141
unsortedCache: unsorted,
42-
sortedCache: internal.NewBTree(),
42+
sortedCache: btree.NewBTree[[]byte](),
4343
}
4444
}

0 commit comments

Comments
 (0)