Replace []Result cache with bitmap cache for reduced memory usage

Replace the per-chunk query cache from []Result slices to fixed-size
bitmaps (ChunkBitmap: [16]uint64 = 128 bytes per entry). Each bit
indicates whether the corresponding item in the chunk matched.

This reduces cache memory by 86 times in testing:
- Old []Result cache: ~22KB per chunk per query (for 500 matches)
- New bitmap cache:   ~262 bytes per chunk per query (fixed)

With the reduced per-entry cost, queryCacheMax is raised from
chunkSize/5 to chunkSize/2, allowing broader queries (up to 50% match
rate) to be cached while still using far less memory.
This commit is contained in:
Junegunn Choi
2026-03-08 11:40:37 +09:00
parent 9249ea1739
commit 2f27a3ede2
5 changed files with 191 additions and 87 deletions
+11 -11
View File
@@ -6,34 +6,34 @@ func TestChunkCache(t *testing.T) {
cache := NewChunkCache()
chunk1p := &Chunk{}
chunk2p := &Chunk{count: chunkSize}
items1 := []Result{{}}
items2 := []Result{{}, {}}
cache.Add(chunk1p, "foo", items1)
cache.Add(chunk2p, "foo", items1)
cache.Add(chunk2p, "bar", items2)
bm1 := ChunkBitmap{1}
bm2 := ChunkBitmap{1, 2}
cache.Add(chunk1p, "foo", bm1, 1)
cache.Add(chunk2p, "foo", bm1, 1)
cache.Add(chunk2p, "bar", bm2, 2)
{ // chunk1 is not full
cached := cache.Lookup(chunk1p, "foo")
if cached != nil {
t.Error("Cached disabled for non-empty chunks", cached)
t.Error("Cached disabled for non-full chunks", cached)
}
}
{
cached := cache.Lookup(chunk2p, "foo")
if cached == nil || len(cached) != 1 {
t.Error("Expected 1 item cached", cached)
if cached == nil || cached[0] != 1 {
t.Error("Expected bitmap cached", cached)
}
}
{
cached := cache.Lookup(chunk2p, "bar")
if cached == nil || len(cached) != 2 {
t.Error("Expected 2 items cached", cached)
if cached == nil || cached[1] != 2 {
t.Error("Expected bitmap cached", cached)
}
}
{
cached := cache.Lookup(chunk1p, "foobar")
if cached != nil {
t.Error("Expected 0 item cached", cached)
t.Error("Expected nil cached", cached)
}
}
}