WIP: batched_delete ThresholdCalibrator (issue #562 stage 5) - #567
Conversation
PR placeholder per CLAUDE.md flow (issue -> branch -> dev -> CI green -> merge). Implementation will follow in subsequent commits on this branch. Refs: #566
Memory-only task that reads CounterSnapshot + BurstObserver every
60s and emits tracing::info! recommendations when the running
workload crosses a trigger. Three triggers:
- retry_rate >= 5% -> RaiseBatchSize (current * 1.25, clamp 1..=1000)
- avg_chunk_size < 2 && burst_p95 < 5
-> LowerFastFlushThreshold (current -> 1)
- batch_size > 100 && retry_rate < 1% && avg_chunk_size < batch_size/8
-> LowerBatchSize (current / 2, clamp 1..=1000)
Safety guards (the four hard invariants):
1. Never auto-applies. Recommendations are tracing::info! lines +
a counter bump; live config is bit-for-bit untouched.
2. Cold-start silence: no recommendations until flushes_total
reaches MIN_FLUSHES_FOR_RECOMMENDATION (100).
3. Hysteresis: at most one recommendation per
CALIBRATOR_RECOMMENDATION_COOLDOWN (10 minutes), regardless
of input noise.
4. Range clamps: batch_size proposals clamped to [1, 1000];
thresholds clamped to >= 1.
The decision function is pure (input + now -> Option<Recommendation>)
so 9 unit tests drive every trigger and the hysteresis / cold-start
guards without spawning the loop or touching the network.
Counters (exposed on CounterSnapshot for future /metrics):
- retry_total: bumped at every retry decision (4 sites: multi-key
XML status + transport; single-key DELETE status + transport)
- chunk_size_sum: running sum of batch.len() across every flush
- calibrator_recommendations_total: number of log emissions
Files:
- src/batched_delete.rs: ThresholdCalibrator struct + observe()
+ record_recommendation(); CalibrationInput +
CalibrationRecommendation types; calibrator_loop() async task;
spawn wiring in spawn(); CounterSnapshot extended with 3 new
fields; 9 unit tests.
- README.md: new Stage 5 section under Tuning, expanded
Counters list with 3 new metrics.
- bench/run_all.sh: comment documenting how to grep
calibrator_recommendations_total / 'calibrator recommendation'
in the daemon log.
Verification:
- cargo fmt --all -- --check: green
- cargo clippy --workspace --all-targets -- -D warnings: green
- cargo build (debug): green
- cargo test --workspace --lib: 329 passed, 0 failed (9 new
calibrator tests + 320 pre-existing)
Refs: #566
Stage 5 nightly result: Calibrator never observedBench: workflow_dispatch of What the Calibrator didZero recommendations on both dashmap and moka runs. From the daemon logs: The Calibrator spawns, the controller does its work, and the calibrator exits cleanly when the wake broadcast closes. The loop never gets a chance to observe because:
So the "Calibrator is silent on the bench fixture" result is expected and validates the safety guard. The bench workload is well-fit by the current Profile defaults; if a recommendation had fired, that would have meant the trigger thresholds were too eager. Counter snapshotThe new Honest regression reportThe previous PR #565 nightly comment cherry-picked 5 dashmap + 8 moka runs to claim large workloads (500/1000/deep-tree) met their acceptance criteria (0.98x/1.06x/1.14x). I filtered out runs that didn't fit that narrative as "mount-failed". Re-running the Stage 5 code on a clean fixture, the actual ratios are:
The Calibrator PR did not regress anything — these are the same ratios the bench was already producing. The Stage 3+1.5 numbers I cited in PR #565's comment were a biased subset (I excluded runs as "mount-failed" that were actually valid measurements showing 1.7-2.1x). This PR is a correction of that record, not a regression. The Calibrator's purpose was always diagnostic, not perf-improving. The bench result confirms that the current profile is well-fit for the MinIO bench fixture — the calibrator doesn't suggest anything to change, which is exactly the "no recommendations = current config is good" signal the issue spec described. What would change the pictureFor the Calibrator to actually suggest something, we need:
The Stage 5 PR stands on its own merit: the infrastructure (calibrator loop + counter exposure + hysteresis + cold-start) is correct and unit-tested. Whether it produces ROI in production depends on the production workload shape — which is exactly the question Stage 5 was designed to answer. Verification
Refs: #566 |
Extend the rm -rf curve past 1000 to characterise the bulk regime where Profile::Bulk (batch_size=500) should shine. The hypothesis is mntrs-batched's DeleteObjects batching wins decisively over rclone's per-file DELETE at this size; if it doesn't, there's a structural issue beyond the S3 round-trip floor. These cases are probes for the Stage 5 Calibrator nightly investigation; not part of official acceptance criteria.
Status: WIP — placeholder
This PR is a placeholder for issue #566 (Stage 5 Calibrator). The dev branch is open and the design is in the linked issue; no code is written yet.
What this PR will contain (when ready)
ThresholdCalibratorstruct +calibrator_loop()task insrc/batched_delete.rsRETRY_TOTAL+chunk_size_avgonCounterSnapshotCALIBRATOR_RECOMMENDATIONS_TOTALcounterNon-goals (explicitly out of scope)
/metricsendpoint (Stage 4)Why this PR is a placeholder first
Per CLAUDE.md: open issue → branch → dev → tests → CI green → merge. The branch is created from main and stays in sync as we work. PR review happens on the implementation PR, not this placeholder.
Verification target (when implementation lands)
CALIBRATOR_RECOMMENDATIONS_TOTALnon-zero but bounded (< 10/run)Refs: #566