storage: reduce lock time in (*MemoryStore).Seek

It makes a copy of the resulting set, so the lock can be released
earlier. This helps a lot with iterators that keep Seek() unfinished for a
long time,
This commit is contained in:
Roman Khimov 2022-07-11 16:13:19 +03:00
parent 07f58abe3d
commit 125c2805d3

View file

@ -68,13 +68,14 @@ func (s *MemoryStore) putChangeSet(puts map[string][]byte, stores map[string][]b
// Seek implements the Store interface. // Seek implements the Store interface.
func (s *MemoryStore) Seek(rng SeekRange, f func(k, v []byte) bool) { func (s *MemoryStore) Seek(rng SeekRange, f func(k, v []byte) bool) {
s.mut.RLock() s.seek(rng, f, s.mut.RLock, s.mut.RUnlock)
s.seek(rng, f)
s.mut.RUnlock()
} }
// SeekGC implements the Store interface. // SeekGC implements the Store interface.
func (s *MemoryStore) SeekGC(rng SeekRange, keep func(k, v []byte) bool) error { func (s *MemoryStore) SeekGC(rng SeekRange, keep func(k, v []byte) bool) error {
noop := func() {}
// Keep RW lock for the whole Seek time, state must be consistent across whole
// operation and we call delete in the handler.
s.mut.Lock() s.mut.Lock()
// We still need to perform normal seek, some GC operations can be // We still need to perform normal seek, some GC operations can be
// sensitive to the order of KV pairs. // sensitive to the order of KV pairs.
@ -83,7 +84,7 @@ func (s *MemoryStore) SeekGC(rng SeekRange, keep func(k, v []byte) bool) error {
delete(s.chooseMap(k), string(k)) delete(s.chooseMap(k), string(k))
} }
return true return true
}) }, noop, noop)
s.mut.Unlock() s.mut.Unlock()
return nil return nil
} }
@ -91,7 +92,7 @@ func (s *MemoryStore) SeekGC(rng SeekRange, keep func(k, v []byte) bool) error {
// seek is an internal unlocked implementation of Seek. `start` denotes whether // seek is an internal unlocked implementation of Seek. `start` denotes whether
// seeking starting from the provided prefix should be performed. Backwards // seeking starting from the provided prefix should be performed. Backwards
// seeking from some point is supported with corresponding SeekRange field set. // seeking from some point is supported with corresponding SeekRange field set.
func (s *MemoryStore) seek(rng SeekRange, f func(k, v []byte) bool) { func (s *MemoryStore) seek(rng SeekRange, f func(k, v []byte) bool, lock func(), unlock func()) {
sPrefix := string(rng.Prefix) sPrefix := string(rng.Prefix)
lPrefix := len(sPrefix) lPrefix := len(sPrefix)
sStart := string(rng.Start) sStart := string(rng.Start)
@ -111,6 +112,7 @@ func (s *MemoryStore) seek(rng SeekRange, f func(k, v []byte) bool) {
return res != 0 && rng.Backwards == (res > 0) return res != 0 && rng.Backwards == (res > 0)
} }
lock()
m := s.chooseMap(rng.Prefix) m := s.chooseMap(rng.Prefix)
for k, v := range m { for k, v := range m {
if v != nil && isKeyOK(k) { if v != nil && isKeyOK(k) {
@ -120,6 +122,7 @@ func (s *MemoryStore) seek(rng SeekRange, f func(k, v []byte) bool) {
}) })
} }
} }
unlock()
sort.Slice(memList, func(i, j int) bool { sort.Slice(memList, func(i, j int) bool {
return less(memList[i].Key, memList[j].Key) return less(memList[i].Key, memList[j].Key)
}) })