Skip to content

Commit 60675e9

Browse files
authored
Merge pull request #7 from C-Pro/fix/dfs-depth-jump
fix error when DFS failed to backtrack on trie depth jump > 1
2 parents 9a80dac + 2857458 commit 60675e9

File tree

2 files changed

+121
-2
lines changed

2 files changed

+121
-2
lines changed

kv.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,7 @@ func (kv *KV[V]) dfs(node *trieNode, prefix []byte) ([]V, error) {
193193
key = append(key, top.c)
194194
} else if top.d < prevDepth {
195195
// We have ascended to the previous level.
196-
key = key[:len(key)-1]
196+
key = key[:len(key)-(prevDepth-top.d)]
197197
key[len(key)-1] = top.c
198198
} else {
199199
key[len(key)-1] = top.c

kv_test.go

+120-1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@ package geche
33
import (
44
"errors"
55
"fmt"
6+
"math/rand"
7+
"sort"
8+
"strings"
69
"testing"
710
)
811

@@ -23,7 +26,7 @@ func ExampleNewKV() {
2326
func compareSlice(t *testing.T, exp, got []string) {
2427
t.Helper()
2528

26-
t.Log(got)
29+
// t.Log(got)
2730
if len(exp) != len(got) {
2831
t.Fatalf("expected length %d, got %d", len(exp), len(got))
2932
}
@@ -137,6 +140,122 @@ func TestKVEmptyPrefix(t *testing.T) {
137140
compareSlice(t, expected, got)
138141
}
139142

143+
func TestKVEmptyPrefixDiffLen(t *testing.T) {
144+
cache := NewMapCache[string, string]()
145+
kv := NewKV[string](cache)
146+
147+
kv.Set("12345", "12345")
148+
kv.Set("123", "123")
149+
kv.Set("3", "3")
150+
kv.Set("2", "2")
151+
kv.Set("33333", "33333")
152+
kv.Set("1", "1")
153+
154+
expected := []string{"1", "123", "12345", "2", "3", "33333"}
155+
156+
got, err := kv.ListByPrefix("")
157+
if err != nil {
158+
t.Fatalf("unexpected error in ListByPrefix: %v", err)
159+
}
160+
161+
compareSlice(t, expected, got)
162+
}
163+
164+
func genRandomString(n int) string {
165+
b := make([]byte, n)
166+
for i := range b {
167+
b[i] = byte(rand.Intn(256))
168+
}
169+
return string(b)
170+
}
171+
172+
func TestKVEmptyPrefixFuzz(t *testing.T) {
173+
cache := NewMapCache[string, string]()
174+
kv := NewKV[string](cache)
175+
176+
set := map[string]struct{}{}
177+
for i := 0; i < 10000; i++ {
178+
key := genRandomString(rand.Intn(300) + 1)
179+
set[key] = struct{}{}
180+
kv.Set(key, key)
181+
}
182+
183+
expected := []string{}
184+
for key := range set {
185+
expected = append(expected, key)
186+
}
187+
sort.Strings(expected)
188+
189+
got, err := kv.ListByPrefix("")
190+
if err != nil {
191+
t.Fatalf("unexpected error in ListByPrefix: %v", err)
192+
}
193+
194+
compareSlice(t, expected, got)
195+
}
196+
197+
// This test creates 10k random KV pairs. Each key is prefixed with one of 10
198+
// random prefixes. Then it deletes 10% of keys and checks that ListByPrefix
199+
// returns correct results.
200+
func TestKVPrefixFuzz(t *testing.T) {
201+
prefixes := []string{}
202+
for i := 0; i < 10; i++ {
203+
prefixes = append(prefixes, genRandomString(rand.Intn(20)+1))
204+
}
205+
cache := NewMapCache[string, string]()
206+
kv := NewKV[string](cache)
207+
208+
set := map[string]struct{}{}
209+
for i := 0; i < 10000; i++ {
210+
prefix := prefixes[rand.Intn(len(prefixes))]
211+
pl := rand.Intn(len(prefix))
212+
key := prefix[:pl] + genRandomString(rand.Intn(300)+1)
213+
set[key] = struct{}{}
214+
kv.Set(key, key)
215+
}
216+
217+
// Delete 10% of keys.
218+
for key := range set {
219+
if rand.Float64() < 0.1 {
220+
delete(set, key)
221+
_ = kv.Del(key)
222+
}
223+
}
224+
225+
expected := []string{}
226+
for key := range set {
227+
expected = append(expected, key)
228+
}
229+
sort.Strings(expected)
230+
231+
got, err := kv.ListByPrefix("")
232+
if err != nil {
233+
t.Fatalf("unexpected error in ListByPrefix: %v", err)
234+
}
235+
236+
compareSlice(t, expected, got)
237+
238+
for i := 1; i < len(prefixes); i++ {
239+
prefix := prefixes[i]
240+
for j := 1; j < len(prefix); j++ {
241+
q := prefix[:j]
242+
expected2 := make([]string, 0, len(expected))
243+
for _, key := range expected {
244+
if strings.HasPrefix(key, q) {
245+
expected2 = append(expected2, key)
246+
}
247+
}
248+
249+
got, err := kv.ListByPrefix(q)
250+
if err != nil {
251+
t.Fatalf("unexpected error in ListByPrefix: %v", err)
252+
}
253+
254+
compareSlice(t, expected2, got)
255+
}
256+
}
257+
}
258+
140259
func TestKVNonexist(t *testing.T) {
141260
cache := NewMapCache[string, string]()
142261
kv := NewKV[string](cache)

0 commit comments

Comments
 (0)