260308.1 · 2f27a3ede2f5063459809454ccf691dc876e5337
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.
reading declarations
Changes to src/cache_test.go. All files
@@ -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) } } }