Skip to content

Migrate to TGB Format for cache entries - #525

Open
tinder-maxwellelliott wants to merge 3 commits into
Tinder:masterfrom
maxwellE:claude/beautiful-hamilton-68d3a5
Open

tinder-maxwellelliott wants to merge 3 commits into
Tinder:masterfrom
maxwellE:claude/beautiful-hamilton-68d3a5

Conversation

@tinder-maxwellelliott

Copy link
Copy Markdown
Collaborator

In alignment with Tango approach

maxwellE and others added 3 commits October 16, 2026 04:46
Record the investigation into porting Tango's TGB format (columnar blobs,
raw fixed-stride hash column, block-aligned bisecting compare) to the
serve cache. Measured on 1M-entry synthetic hash files: JSON is 212 B per
node and a columnar entry would be 66 B (3.2x, not Tango's 10x, because
97% of it is two SHA-256 columns); the compare drops from 748 ms to
22 ms, and the 6.3 s per-request JSON parse disappears entirely. Deferred
until serve entries or compare latency become a problem; the note lists
the thresholds, the cheaper interim steps (in-memory parsed-entry LRU,
direct parse, allocation-free compare, compressed shared tier) and a
column layout and compare algorithm fitted to bazel-diff's hash files.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Gs1vjHt61po6uHgkYuh68N
…ing, cache parsed entries, gzip the shared tier

The four interim steps from docs/tgb-binary-cache.md, none of which
changes the hash-file format:

- model: `HashFileData` deserializes with a serde visitor straight into
  the final map instead of building a `serde_json::Value` and
  re-inserting every label. Hashes are a new `Digest` type that keeps a
  SHA-256 as 32 raw bytes (one table-driven hex pass; anything that is not
  64 lowercase hex digits stays text and round-trips unchanged).
  `TargetHash::same_as` replaces the two formatted `identity()` strings
  per node, and `filter_and_sort_labels` ranks each label once instead
  of cloning it inside the sort.
- serve: parsed entries are kept in an in-memory LRU bounded by
  `--cacheMemoryMax` (default 512MB of serialized size, 0 disables), so a
  request whose revisions were already parsed skips the disk read and
  the JSON parse. A memory hit still refreshes the on-disk entry's mtime,
  which `touch` now sets directly instead of rewriting the whole file.
  `/metrics` reports the tier under `cache.memory`.
- serve: entries are published to S3 or Nexus as fast-level gzip under
  `<key>.json.gz`, 2-3x smaller. A read tries that name first and falls
  back to the plain `<key>.json` an older release wrote; a read failure
  stays a one-request miss. The local-disk tier is unchanged.

Measured on a synthetic 1M-entry pair, one `get-impacted-targets` (two
parses plus the compare) goes from 4.8s and 1.46GB peak RSS to 2.5s and
0.96GB; the compare alone from 0.75s to 0.30s.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Gs1vjHt61po6uHgkYuh68N
Resolves the src/server.rs conflicts with Tinder#524, which replaced the
State literal with State::new. The in-memory tier is now constructed
there, and the remote-cache tests keep their compressed and plain
fallback responses on top of the shared ready_state helper.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Gs1vjHt61po6uHgkYuh68N

This branch has not been deployed

No deployments
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