diff --git a/store/cachekv/mergeiterator.go b/store/cachekv/mergeiterator.go index a32dfb346..f13c4025c 100644 --- a/store/cachekv/mergeiterator.go +++ b/store/cachekv/mergeiterator.go @@ -16,10 +16,11 @@ import ( // // TODO: Optimize by memoizing. type cacheMergeIterator struct { - parent types.Iterator - cache types.Iterator - ascending bool - storeKey sdktypes.StoreKey + parent types.Iterator + cache types.Iterator + ascending bool + storeKey sdktypes.StoreKey + eventManager *sdktypes.EventManager } var _ types.Iterator = (*cacheMergeIterator)(nil) @@ -28,12 +29,14 @@ func NewCacheMergeIterator( parent, cache types.Iterator, ascending bool, storeKey sdktypes.StoreKey, + eventManager *sdktypes.EventManager, ) *cacheMergeIterator { iter := &cacheMergeIterator{ - parent: parent, - cache: cache, - ascending: ascending, - storeKey: storeKey, + parent: parent, + cache: cache, + ascending: ascending, + storeKey: storeKey, + eventManager: eventManager, } return iter @@ -135,12 +138,14 @@ func (iter *cacheMergeIterator) Value() []byte { // If parent is invalid, get the cache value. if !iter.parent.Valid() { value := iter.cache.Value() + iter.eventManager.EmitResourceAccessReadEvent("iterator", iter.storeKey, iter.cache.Key(), value) return value } // If cache is invalid, get the parent value. if !iter.cache.Valid() { value := iter.parent.Value() + iter.eventManager.EmitResourceAccessReadEvent("iterator", iter.storeKey, iter.parent.Key(), value) return value } @@ -151,9 +156,11 @@ func (iter *cacheMergeIterator) Value() []byte { switch cmp { case -1: // parent < cache value := iter.parent.Value() + iter.eventManager.EmitResourceAccessReadEvent("iterator", iter.storeKey, keyP, value) return value case 0, 1: // parent >= cache value := iter.cache.Value() + iter.eventManager.EmitResourceAccessReadEvent("iterator", iter.storeKey, keyC, value) return value default: panic("invalid comparison result") diff --git a/store/cachekv/mergeiterator_test.go b/store/cachekv/mergeiterator_test.go index b2648a865..00f065151 100644 --- a/store/cachekv/mergeiterator_test.go +++ b/store/cachekv/mergeiterator_test.go @@ -6,6 +6,7 @@ import ( "github.com/cosmos/cosmos-sdk/store/cachekv" "github.com/cosmos/cosmos-sdk/store/dbadapter" "github.com/cosmos/cosmos-sdk/store/types" + sdktypes "github.com/cosmos/cosmos-sdk/types" "github.com/stretchr/testify/require" dbm "github.com/tendermint/tm-db" ) @@ -13,6 +14,7 @@ import ( func TestMangerIterator(t *testing.T) { // initiate mock kvstore mem := dbadapter.Store{DB: dbm.NewMemDB()} + eventManager := sdktypes.NewEventManager() kvstore := cachekv.NewStore(mem, types.NewKVStoreKey("CacheKvTest"), types.DefaultCacheSizeLimit) value := randSlice(defaultValueSizeBz) startKey := randSlice(32) @@ -27,13 +29,27 @@ func TestMangerIterator(t *testing.T) { cache := kvstore.Iterator(nil, nil) for ; cache.Valid(); cache.Next() { } - iter := cachekv.NewCacheMergeIterator(parent, cache, true, types.NewKVStoreKey("CacheKvTest")) + iter := cachekv.NewCacheMergeIterator(parent, cache, true, types.NewKVStoreKey("CacheKvTest"), eventManager) - // get the next value and it should not be nil - nextValue := iter.Value() - require.NotNil(t, nextValue) + // get the next value + iter.Value() + + // assert the resource access is still emitted correctly when the cache store is unavailable + require.Equal(t, "access_type", string(eventManager.Events()[0].Attributes[0].Key)) + require.Equal(t, "read", string(eventManager.Events()[0].Attributes[0].Value)) + require.Equal(t, "store_key", string(eventManager.Events()[0].Attributes[1].Key)) + require.Equal(t, "CacheKvTest", string(eventManager.Events()[0].Attributes[1].Value)) + + // assert event emission when cache is available + cache = kvstore.Iterator(keys[1], keys[2]) + iter = cachekv.NewCacheMergeIterator(parent, cache, true, types.NewKVStoreKey("CacheKvTest"), eventManager) // get the next value - nextValue = iter.Value() - require.NotNil(t, nextValue) + iter.Value() + + // assert the resource access is still emitted correctly when the cache store is available + require.Equal(t, "access_type", string(eventManager.Events()[0].Attributes[0].Key)) + require.Equal(t, "read", string(eventManager.Events()[0].Attributes[0].Value)) + require.Equal(t, "store_key", string(eventManager.Events()[0].Attributes[1].Key)) + require.Equal(t, "CacheKvTest", string(eventManager.Events()[0].Attributes[1].Value)) } diff --git a/store/cachekv/store.go b/store/cachekv/store.go index a33adf17c..d3c71d373 100644 --- a/store/cachekv/store.go +++ b/store/cachekv/store.go @@ -56,6 +56,8 @@ func (store *Store) GetEvents() []abci.Event { // Implements Store func (store *Store) ResetEvents() { + store.mtx.Lock() + defer store.mtx.Unlock() store.eventManager = sdktypes.NewEventManager() } @@ -75,6 +77,7 @@ func (store *Store) getFromCache(key []byte) []byte { // Get implements types.KVStore. func (store *Store) Get(key []byte) (value []byte) { types.AssertValidKey(key) + store.eventManager.EmitResourceAccessReadEvent("get", store.storeKey, key, value) return store.getFromCache(key) } @@ -83,11 +86,13 @@ func (store *Store) Set(key []byte, value []byte) { types.AssertValidKey(key) types.AssertValidValue(value) store.setCacheValue(key, value, false, true) + store.eventManager.EmitResourceAccessWriteEvent("set", store.storeKey, key, value) } // Has implements types.KVStore. func (store *Store) Has(key []byte) bool { value := store.Get(key) + store.eventManager.EmitResourceAccessReadEvent("has", store.storeKey, key, value) return value != nil } @@ -189,7 +194,7 @@ func (store *Store) iterator(start, end []byte, ascending bool) types.Iterator { }() store.dirtyItems(start, end) cache = newMemIterator(start, end, store.sortedCache, store.deleted, ascending, store.eventManager, store.storeKey) - return NewCacheMergeIterator(parent, cache, ascending, store.storeKey) + return NewCacheMergeIterator(parent, cache, ascending, store.storeKey, store.eventManager) } func (store *Store) VersionExists(version int64) bool {