Skip to content

Use seekable Sieve for frame caching#1

Closed
SaveTheRbtz wants to merge 6 commits into
mainfrom
use-seekable-sieve-frame-cache
Closed

Use seekable Sieve for frame caching#1
SaveTheRbtz wants to merge 6 commits into
mainfrom
use-seekable-sieve-frame-cache

Conversation

@SaveTheRbtz

@SaveTheRbtz SaveTheRbtz commented Jun 4, 2026

Copy link
Copy Markdown
Owner

Summary

This switches sqlitezstd to the Reader-owned decoded-frame cache added in zstd-seekable-format-go v0.10.0. The configured policy is framecache.NewSieve, and the existing WithFrameCacheSize option continues to control the number of decoded frames cached per opened file.

The important design choice is that sqlitezstd now has one persistent frame cache, not several partially overlapping caches. The cache lives at the seekable-reader layer, is keyed by seek-table frame IDs, and stores decoded frame data directly. That avoids hashing compressed payloads, duplicated frame-cache lifetimes, and confusing memory accounting where one frame-cache knob could imply multiple resident caches.

Cache Model

Before this PR, an opened compressed database could keep separate frame-level state in sqlitezstd:

  • a decoded-frame LRU wrapper around the zstd decoder;
  • a compressed-frame LRU in frameReader, keyed by compressed offset;
  • an optional HTTP byte/page cache for remote reads.

After this PR, ZstdVFS.open passes framecache.NewSieve(framecache.Limits{MaxFrames: frameCacheSize}) to seekable.NewReader via seekable.WithReaderFrameCache. The local frameReader is reduced to the positional io.ReaderAt/io.ReadSeeker adapter needed by the seekable reader, and the process-wide shared decoder remains unchanged.

This makes WithFrameCacheSize(64) mean one thing: cache up to 64 decoded zstd frames for that opened file.

API And HTTP Path

WithFrameCacheSize remains the public cache knob.

This intentionally removes the HTTP byte-cache API added on the upgrade branch: WithHTTPCacheSize, WithHTTPPageSize, and DefaultHTTPPageSize. The HTTP path now uses the range reader directly and relies on the decoded-frame Sieve cache as the only persistent cache layer.

Benchmarks

Fresh run after rebasing onto main; medians of 5 runs, with main as the baseline. Lower is better.

Benchmark CPU before CPU after CPU change Mem before Mem after Mem change Allocs
Point read 9,965 ns/op 9,222 ns/op -7.5% 18,061 B/op 19,286 B/op +6.8% 15 -> 15
HTTP point read 11,006 ns/op 10,682 ns/op -2.9% 11,719 B/op 12,930 B/op +10.3% 17 -> 17
RTree 13,265 ns/op 13,074 ns/op -1.4% 17,188 B/op 18,400 B/op +7.1% 13 -> 13
FTS5 3,300,782 ns/op 3,169,517 ns/op -4.0% 159,157 B/op 140,199 B/op -11.9% 24 -> 20
FTS5, min cache 3,768,040 ns/op 3,154,699 ns/op -16.3% 185,281 B/op 147,282 B/op -20.5% 26 -> 21

The strongest signal is the compressed FTS5/min-cache path, where moving to the seekable Sieve cache reduces both CPU and allocation pressure. The small point-read deltas should be read cautiously because the uncompressed controls also moved between runs.

The removed HTTP-cache benchmark existed only for the old second cache layer. Its baseline median was 10,420 ns/op, 18,963 B/op, and 17 allocs/op; the regular HTTP compressed path after this PR is 10,682 ns/op, 12,930 B/op, and 17 allocs/op, without a separate resident HTTP cache.

Testing

  • env GOCACHE=/tmp/codex-go-build-cache go test ./...
  • env GOCACHE=/tmp/codex-go-build-cache go test -tags fts5
  • env GOWORK=off TMPDIR=/home/rbtz/tmp/bench/... GOCACHE=/home/rbtz/tmp/bench/go-build-cache GOMODCACHE=/tmp/codex-gomodcache GODEBUG=randautoseed=0 GOMAXPROCS=8 go test -tags fts5 -run '^$' -bench '^BenchmarkRead' -benchmem -count=5 -timeout=90m

@SaveTheRbtz SaveTheRbtz marked this pull request as draft June 4, 2026 02:22
@SaveTheRbtz SaveTheRbtz marked this pull request as ready for review June 4, 2026 02:24
@SaveTheRbtz SaveTheRbtz changed the title Use seekable Sieve for decoded frame cache Use seekable Sieve for frame caching Jun 4, 2026
@jtarchie

jtarchie commented Jun 4, 2026

Copy link
Copy Markdown

I don't need source compatibility.
Those options are only used by one thing at the moment.

@SaveTheRbtz SaveTheRbtz force-pushed the use-seekable-sieve-frame-cache branch from f59c241 to ffad5b0 Compare June 4, 2026 20:41
@SaveTheRbtz SaveTheRbtz changed the base branch from upgrade/zstd-seekable-format-go-v0.10.0-rc.1 to main June 4, 2026 20:41

Copy link
Copy Markdown
Owner Author

Moved upstream to jtarchie#39.

@SaveTheRbtz SaveTheRbtz closed this Jun 4, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants