Skip to content

feat(admission): count the on-disk liquid tier toward the gate budget - #9

Merged
anoop-narang merged 2 commits into
mainfrom
feat/admission-budget-mem-disk
Jul 23, 2026
Merged

feat(admission): count the on-disk liquid tier toward the gate budget#9
anoop-narang merged 2 commits into
mainfrom
feat/admission-budget-mem-disk

Conversation

@anoop-narang

Copy link
Copy Markdown
Collaborator

What

The footprint admission gate sized its budget against RAM only. With the disk (liquid) tier enabled, a scan whose estimated liquid footprint exceeded memory was bypassed to the fallback mount even though it would fit on the on-disk liquid tier without thrashing — the disk capacity sat idle.

This sizes the gate against both tiers, weighted differently:

threshold = memory × tolerance + disk
  • Memory keeps the compaction overcommit (tolerance, the measured RAM crossover where LiquidCache still beats the mount despite spilling).
  • Disk counts at face value (1×): a scan that overflows RAM spills to NVMe without thrashing, so its capacity needs no overcommit — and extending the RAM crossover factor to disk has no evidence behind it.

So it is memory × tolerance + disk, not (memory + disk) × tolerance (which would admit footprints far beyond physical capacity → thrash).

With the disk tier off (max_disk_bytes == 0) the threshold is exactly memory × tolerance, so gate behaviour is unchanged when disk is disabled.

Why

When the disk tier is on, evicted-from-RAM entries spill to the on-disk liquid tier (NVMe), so a scan up to memory + disk fits without thrashing. The gate should admit those instead of bouncing them to the mount (where every read re-decodes parquet).

How

  • Extract the threshold into a pure admission_threshold(memory, disk, tolerance) function.
  • should_bypass / should_bypass_guarded now take memory_budget and disk_budget separately; the per-decision admission log emits memory_bytes + disk_bytes + threshold_bytes.
  • Add threshold_tests: 5 pure unit tests pinning the exact formula (memory×tol+disk, disk-off = mem×tol, disk-at-1×, zero-threshold, large-memory no-overflow). These run everywhere; the cache-based gate tests remain Linux-only (direct_io).

Testing

  • cargo fmt clean; clippy clean.
  • Pure threshold_tests pass locally (macOS).
  • Cache-based gate tests are Linux-only (macOS lacks direct_io for the t4 mount) → validated in CI.

The footprint admission gate sized its budget against RAM only, so with the
disk tier enabled a scan whose liquid footprint exceeded memory was bypassed
to the fallback mount even though it would fit on the on-disk liquid tier
without thrashing.

Size the gate against both tiers, weighted differently: memory keeps the
compaction overcommit (tolerance, the measured RAM crossover) while the disk
tier counts at face value — threshold = memory * tolerance + disk. With the
disk tier off (max_disk_bytes == 0) the threshold is exactly memory *
tolerance, so gate behaviour is unchanged there.

Extract the threshold into a pure admission_threshold() and add unit tests
pinning the formula (these run everywhere; the cache-based gate tests remain
Linux-only via direct_io).
claude[bot]
claude Bot previously approved these changes Jul 23, 2026

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verified the threshold math: memory × tolerance + disk correctly reduces to the prior memory × tolerance behavior when the disk tier is off, and the f64 computation avoids the integer-overflow bug an integer budget × tolerance would have. Callers, docs, and tests are all consistent. The migration of existing gate tests to disk = 0 correctly preserves their prior semantics (the old gate ignored disk). LGTM.

@codecov

codecov Bot commented Jul 23, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

cargo doc --document-private-items with -D warnings denies public items
linking to a private fn (rustdoc::private_intra_doc_links). State the
formula inline in the public docs; keep the link only from private
should_bypass.

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verified the threshold math and behavioral equivalence:

  • memory × tolerance + disk computed in f64 — no overflow at large budgets.
  • Disk-off case reduces to the prior footprint > memory × tolerance (and memory == 0footprint > 0.0), so gate behaviour is exactly preserved when the disk tier is disabled.
  • The build_cache_with_budget helper now passes disk = 0, which correctly keeps the existing memory-only gate tests intact.
  • New unit tests pin the formula unambiguously (ruling out (mem+disk)×tol and disk-scaled-by-tolerance) and the disk-tier integration test is sound.

Clean, well-documented, and well-tested. LGTM.

@github-actions

github-actions Bot commented Jul 23, 2026

Copy link
Copy Markdown

📊 Benchmark Comparison

Current: 812660a4 (Liquid) vs Baseline: 812660a4 (DataFusionDefault)

Query Cold Time Δ Warm Time Δ CPU Time Δ
Q1 3.0ms (3.0ms) +0.0% 0.000ms (0.000ms) +0.0% 0.000ms (0.000ms) +0.0%
Q2 10.0ms (6.0ms) +66.7% 3.2ms (4.8ms) -31.6% 6.0ms (6.8ms) -11.1%
Q3 16.0ms (12.0ms) +33.3% 5.0ms (11.2ms) -55.6% 2.0ms (21.8ms) -90.8%
Q4 20.0ms (11.0ms) +81.8% 3.5ms (11.0ms) -68.2% 2.0ms (23.8ms) -91.6%
Q5 58.0ms (52.0ms) +11.5% 43.5ms (53.0ms) -17.9% 3.5ms (24.5ms) -85.7%
Q6 143.0ms (112.0ms) +27.7% 68.8ms (106.0ms) -35.1% 19.5ms (76.8ms) -74.6%
Q7 1.0ms (1.0ms) +0.0% 1.0ms (1.0ms) +0.0% 0.000ms (0.000ms) +0.0%
Q8 8.0ms (6.0ms) +33.3% 4.5ms (6.5ms) -30.8% 7.5ms (7.2ms) +3.4%
Q9 83.0ms (80.0ms) +3.8% 69.2ms (79.2ms) -12.6% 4.0ms (43.5ms) -90.8%
Q10 92.0ms (88.0ms) +4.5% 69.5ms (89.8ms) -22.6% 5.2ms (64.2ms) -91.8%
Q11 40.0ms (26.0ms) +53.8% 19.8ms (25.0ms) -21.0% 34.0ms (35.8ms) -4.9%
Q12 46.0ms (34.0ms) +35.3% 21.0ms (30.2ms) -30.6% 35.8ms (45.5ms) -21.4%
Q13 150.0ms (103.0ms) +45.6% 76.5ms (98.2ms) -22.1% 55.5ms (77.5ms) -28.4%
Q14 282.0ms (133.0ms) +112.0% 118.5ms (137.2ms) -13.7% 82.5ms (105.8ms) -22.0%
Q15 226.0ms (90.0ms) +151.1% 69.0ms (96.0ms) -28.1% 59.8ms (90.8ms) -34.2%
Q16 61.0ms (60.0ms) +1.7% 49.0ms (62.0ms) -21.0% 3.0ms (25.5ms) -88.2%
Q17 328.0ms (154.0ms) +113.0% 156.5ms (151.0ms) +3.6% 75.2ms (101.8ms) -26.0%
Q18 330.0ms (158.0ms) +108.9% 161.0ms (153.2ms) +5.1% 79.2ms (102.0ms) -22.3%
Q19 640.0ms (290.0ms) +120.7% 349.5ms (298.0ms) +17.3% 114.0ms (151.2ms) -24.6%
Q20 16.0ms (11.0ms) +45.5% 4.5ms (12.0ms) -62.5% 6.8ms (24.5ms) -72.4%
Q21 932.0ms (176.0ms) +429.5% 270.0ms (174.8ms) +54.5% 623.8ms (269.2ms) +131.7%
Q22 1.33s (202.0ms) +559.4% 326.2ms (208.5ms) +56.5% 192.5ms (351.0ms) -45.2%
Q23 2.24s (616.0ms) +263.1% 1.02s (602.5ms) +68.9% 570.8ms (747.5ms) -23.6%
Q24 18.22s (937.0ms) +1844.2% 851.0ms (967.2ms) -12.0% 676.2ms (2.58s) -73.8%
Q25 195.0ms (102.0ms) +91.2% 15.5ms (59.0ms) -73.7% 39.0ms (119.8ms) -67.4%
Q26 93.0ms (43.0ms) +116.3% 18.0ms (47.8ms) -62.3% 47.0ms (85.8ms) -45.2%
Q27 174.0ms (59.0ms) +194.9% 27.5ms (61.5ms) -55.3% 80.8ms (120.5ms) -33.0%
Q28 955.0ms (200.0ms) +377.5% 292.0ms (201.0ms) +45.3% 369.8ms (281.5ms) +31.3%
Q29 1.76s (1.02s) +73.3% 1.10s (1.05s) +5.1% 392.8ms (345.8ms) +13.6%
Q30 38.0ms (28.0ms) +35.7% 26.5ms (28.0ms) -5.4% 6.8ms (21.0ms) -67.9%
Q31 269.0ms (100.0ms) +169.0% 49.5ms (91.8ms) -46.0% 41.0ms (141.2ms) -71.0%
Q32 530.0ms (94.0ms) +463.8% 81.8ms (95.8ms) -14.6% 54.5ms (144.5ms) -62.3%
Q33 202.0ms (190.0ms) +6.3% 161.0ms (173.0ms) -6.9% 8.2ms (71.2ms) -88.4%
Q34 1.01s (333.0ms) +203.9% 428.2ms (338.8ms) +26.4% 372.2ms (264.5ms) +40.7%
Q35 878.0ms (354.0ms) +148.0% 416.5ms (332.8ms) +25.2% 353.2ms (265.2ms) +33.2%
Q36 75.0ms (60.0ms) +25.0% 51.8ms (59.2ms) -12.7% 3.8ms (25.2ms) -85.1%
Q37 299.0ms (97.0ms) +208.2% 77.5ms (97.5ms) -20.5% 45.5ms (76.0ms) -40.1%
Q38 68.0ms (42.0ms) +61.9% 34.0ms (44.5ms) -23.6% 20.8ms (25.5ms) -18.6%
Q39 266.0ms (48.0ms) +454.2% 12.2ms (46.2ms) -73.5% 10.8ms (70.5ms) -84.8%
Q40 751.0ms (166.0ms) +352.4% 214.8ms (167.5ms) +28.2% 93.8ms (124.8ms) -24.8%
Q41 31.0ms (19.0ms) +63.2% 9.8ms (20.0ms) -51.2% 7.2ms (19.0ms) -61.8%
Q42 20.0ms (17.0ms) +17.6% 12.5ms (20.0ms) -37.5% 11.5ms (17.5ms) -34.3%
Q43 18.0ms (15.0ms) +20.0% 12.8ms (15.8ms) -19.0% 8.0ms (11.0ms) -27.3%

⚠️ LiquidCache is slower on 11 queries (warm)

  • Q23: warm +68.9% (1.02s vs 602.5ms)
  • Q22: warm +56.5% (326.2ms vs 208.5ms)
  • Q21: warm +54.5% (270.0ms vs 174.8ms)
  • Q28: warm +45.3% (292.0ms vs 201.0ms)
  • Q40: warm +28.2% (214.8ms vs 167.5ms)
  • Q34: warm +26.4% (428.2ms vs 338.8ms)
  • Q35: warm +25.2% (416.5ms vs 332.8ms)
  • Q19: warm +17.3% (349.5ms vs 298.0ms)
  • Q29: warm +5.1% (1.10s vs 1.05s)
  • Q18: warm +5.1% (161.0ms vs 153.2ms)
  • Q17: warm +3.6% (156.5ms vs 151.0ms)

Compared Liquid vs DataFusionDefault on the same runner
Cold Time: first iteration; Warm Time: average of remaining iterations.

@anoop-narang
anoop-narang merged commit c21c291 into main Jul 23, 2026
13 checks passed
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.

1 participant