fix(store): handle nil end in cachekv/iterator (#12945)
## Description
Closes: #12661
Adds support for nil end semantics to iterators in cachekv store, addressing [this workaround](4176b287d4/osmoutils/store_helper.go (L37-L41)).
Note that this has the effect of sorting the dirty cache into the BTree cache store in the bounds `[startIndex, end-of-cache-space]`
---
### Author Checklist
*All items are required. Please add a note to the item if the item is not applicable and
please add links to any relevant follow up issues.*
I have...
- [x] included the correct [type prefix](https://github.com/commitizen/conventional-commit-types/blob/v3.0.0/index.json) in the PR title
- [ ] added `!` to the type prefix if API or client breaking change
- [x] targeted the correct branch (see [PR Targeting](https://github.com/cosmos/cosmos-sdk/blob/main/CONTRIBUTING.md#pr-targeting))
- [x] provided a link to the relevant issue or specification
- [x] followed the guidelines for [building modules](https://github.com/cosmos/cosmos-sdk/blob/main/docs/building-modules)
- [x] included the necessary unit and integration [tests](https://github.com/cosmos/cosmos-sdk/blob/main/CONTRIBUTING.md#testing)
- [ ] added a changelog entry to `CHANGELOG.md`
- [x] included comments for [documenting Go code](https://blog.golang.org/godoc)
- [ ] updated the relevant documentation or specification
- [x] reviewed "Files changed" and left comments if necessary
- [ ] confirmed all CI checks have passed
### Reviewers Checklist
*All items are required. Please add a note if the item is not applicable and please add
your handle next to the items reviewed if you only reviewed selected items.*
I have...
- [ ] confirmed the correct [type prefix](https://github.com/commitizen/conventional-commit-types/blob/v3.0.0/index.json) in the PR title
- [ ] confirmed `!` in the type prefix if API or client breaking change
- [ ] confirmed all author checklist items have been addressed
- [ ] reviewed state machine logic
- [ ] reviewed API design and naming
- [ ] reviewed documentation is accurate
- [ ] reviewed tests and test coverage
- [ ] manually tested (if applicable)
This commit is contained in:
parent
b51537260f
commit
0ed7360921
@ -122,6 +122,7 @@ Ref: https://keepachangelog.com/en/1.0.0/
|
||||
* (x/group) [#12888](https://github.com/cosmos/cosmos-sdk/pull/12888) Fix event propagation to the current context of `x/group` message execution `[]sdk.Result`.
|
||||
* (sdk/dec_coins) [#12903](https://github.com/cosmos/cosmos-sdk/pull/12903) Fix nil `DecCoin` creation when converting `Coins` to `DecCoins`
|
||||
* (x/upgrade) [#12906](https://github.com/cosmos/cosmos-sdk/pull/12906) Fix upgrade failure by moving downgrade verification logic after store migration.
|
||||
* (store) [#12945](https://github.com/cosmos/cosmos-sdk/pull/12945) Fix nil end semantics in store/cachekv/iterator when iterating a dirty cache.
|
||||
|
||||
### Deprecated
|
||||
|
||||
|
||||
@ -281,7 +281,7 @@ const (
|
||||
// Constructs a slice of dirty items, to use w/ memIterator.
|
||||
func (store *Store) dirtyItems(start, end []byte) {
|
||||
startStr, endStr := conv.UnsafeBytesToStr(start), conv.UnsafeBytesToStr(end)
|
||||
if startStr > endStr {
|
||||
if end != nil && startStr > endStr {
|
||||
// Nothing to do here.
|
||||
return
|
||||
}
|
||||
@ -296,6 +296,7 @@ func (store *Store) dirtyItems(start, end []byte) {
|
||||
// than just not having the cache.
|
||||
if n < 1024 {
|
||||
for key := range store.unsortedCache {
|
||||
// dbm.IsKeyInDomain is nil safe and returns true iff key is greater than start
|
||||
if dbm.IsKeyInDomain(conv.UnsafeStrToBytes(key), start, end) {
|
||||
cacheValue := store.cache[key]
|
||||
unsorted = append(unsorted, &kv.Pair{Key: []byte(key), Value: cacheValue.value})
|
||||
@ -316,15 +317,20 @@ func (store *Store) dirtyItems(start, end []byte) {
|
||||
// Now find the values within the domain
|
||||
// [start, end)
|
||||
startIndex := findStartIndex(strL, startStr)
|
||||
endIndex := findEndIndex(strL, endStr)
|
||||
|
||||
if endIndex < 0 {
|
||||
endIndex = len(strL) - 1
|
||||
}
|
||||
if startIndex < 0 {
|
||||
startIndex = 0
|
||||
}
|
||||
|
||||
var endIndex int
|
||||
if end == nil {
|
||||
endIndex = len(strL) - 1
|
||||
} else {
|
||||
endIndex = findEndIndex(strL, endStr)
|
||||
}
|
||||
if endIndex < 0 {
|
||||
endIndex = len(strL) - 1
|
||||
}
|
||||
|
||||
kvL := make([]*kv.Pair, 0)
|
||||
for i := startIndex; i <= endIndex; i++ {
|
||||
key := strL[i]
|
||||
|
||||
@ -306,6 +306,50 @@ func TestCacheKVMergeIteratorRandom(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestNilEndIterator(t *testing.T) {
|
||||
const SIZE = 3000
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
write bool
|
||||
startIndex int
|
||||
end []byte
|
||||
}{
|
||||
{name: "write=false, end=nil", write: false, end: nil, startIndex: 1000},
|
||||
{name: "write=false, end=nil; full key scan", write: false, end: nil, startIndex: 2000},
|
||||
{name: "write=true, end=nil", write: true, end: nil, startIndex: 1000},
|
||||
{name: "write=false, end=non-nil", write: false, end: keyFmt(3000), startIndex: 1000},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
st := newCacheKVStore()
|
||||
|
||||
for i := 0; i < SIZE; i++ {
|
||||
kstr := keyFmt(i)
|
||||
st.Set(kstr, valFmt(i))
|
||||
}
|
||||
|
||||
if tt.write {
|
||||
st.Write()
|
||||
}
|
||||
|
||||
itr := st.Iterator(keyFmt(tt.startIndex), tt.end)
|
||||
i := tt.startIndex
|
||||
j := 0
|
||||
for itr.Valid() {
|
||||
require.Equal(t, keyFmt(i), itr.Key())
|
||||
require.Equal(t, valFmt(i), itr.Value())
|
||||
itr.Next()
|
||||
i++
|
||||
j++
|
||||
}
|
||||
|
||||
require.Equal(t, SIZE-tt.startIndex, j)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------
|
||||
// do some random ops
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user