// key顺序扫描,常用于数据导出、附近搜索 // 返回的key是面向用户的key,而非内部结构的raw_key func (l *LevelRedis) KeyEnumerate(seek []byte, direction IterDirection, fn func(i int, key, keytype, value []byte, quit *bool)) { var iter *gorocks.Iterator if l.snap != nil { iter = l.db.NewIterator(l.ro) } else { ro := gorocks.NewReadOptions() ro.SetFillCache(false) defer ro.Close() iter = l.db.NewIterator(ro) } defer iter.Close() minkey := joinStringBytes(KEY_PREFIX, SEP_LEFT, string(seek)) maxkey := []byte{MAXBYTE} prefix := joinStringBytes(KEY_PREFIX, SEP_LEFT) l.Enumerate(iter, minkey, maxkey, direction, func(i int, key, value []byte, quit *bool) { if !bytes.HasPrefix(key, prefix) { *quit = true return } left := bytes.Index(key, []byte(SEP_LEFT)) right := bytes.LastIndex(key, []byte(SEP_RIGHT)) if left == -1 || right == -1 { return // just skip } fn(i, key[left+1:right], key[right+1:], value, quit) }) }
func (l *LevelRedis) RangeEnumerate(min, max []byte, direction IterDirection, fn func(i int, key, value []byte, quit *bool)) { var iter *gorocks.Iterator if l.snap != nil { iter = l.db.NewIterator(l.ro) } else { ro := gorocks.NewReadOptions() ro.SetFillCache(false) defer ro.Close() iter = l.db.NewIterator(ro) } defer iter.Close() l.Enumerate(iter, min, max, direction, fn) }
// 范围扫描 func (l *LevelRedis) Enumerate(iter *gorocks.Iterator, min, max []byte, direction IterDirection, fn func(i int, key, value []byte, quit *bool)) { l.incrCounter("enum") found := false if direction == IterBackward { if len(max) == 0 { iter.SeekToLast() } else { iter.Seek(max) } } else { if len(min) == 0 { iter.SeekToFirst() } else { iter.Seek(min) } } found = iter.Valid() if !found { return } i := -1 // 范围判断 if found && between(iter.Key(), min, max) { i++ quit := false fn(i, copyBytes(iter.Key()), copyBytes(iter.Value()), &quit) if quit { return } } for { found = false if direction == IterBackward { iter.Prev() } else { iter.Next() } found = iter.Valid() if found && between(iter.Key(), min, max) { i++ quit := false fn(i, copyBytes(iter.Key()), copyBytes(iter.Value()), &quit) if quit { return } } else { break } } return }