core: sort items in MemoryStore.Seek

MemoryStore is used in a MemCachedStore as a persistent layer in tests.
Further commits suppose that persistent storage returns sorted values
from Seek, so sort the result of MemoryStore.Seek.

Benchmark results for 10000 matching items in MemoryStore compared to
master:
name          old time/op    new time/op    delta
MemorySeek-8     712µs ± 0%    3850µs ± 0%   +440.52%  (p=0.000 n=8+8)

name          old alloc/op   new alloc/op   delta
MemorySeek-8     160kB ± 0%    2724kB ± 0%  +1602.61%  (p=0.000 n=10+8)

name          old allocs/op  new allocs/op  delta
MemorySeek-8     10.0k ± 0%     10.0k ± 0%     +0.24%  (p=0.000 n=10+10)

For details on implementation efficiency see the
https://github.com/nspcc-dev/neo-go/pull/2193#discussion_r722993358.
This commit is contained in:
Anna Shaleva 2021-09-24 16:00:13 +03:00
parent d8210c0137
commit 191cc45032

View file

@ -1,6 +1,8 @@
package storage
import (
"bytes"
"sort"
"strings"
"sync"
@ -128,11 +130,21 @@ func (s *MemoryStore) SeekAll(key []byte, f func(k, v []byte)) {
// seek is an internal unlocked implementation of Seek.
func (s *MemoryStore) seek(key []byte, f func(k, v []byte)) {
sk := string(key)
var memList []KeyValue
for k, v := range s.mem {
if strings.HasPrefix(k, sk) {
f([]byte(k), v)
memList = append(memList, KeyValue{
Key: []byte(k),
Value: v,
})
}
}
sort.Slice(memList, func(i, j int) bool {
return bytes.Compare(memList[i].Key, memList[j].Key) < 0
})
for _, kv := range memList {
f(kv.Key, kv.Value)
}
}
// Batch implements the Batch interface and returns a compatible Batch.