You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
#100 and #101 cover adapting to what the SOURCES are doing. The upload side is currently the opposite of adaptive: batching.max_concurrent_batches is a fixed number (default 8, added in #94), applied identically whether the object store is answering in 5ms or 5 seconds.
That is fine while the engine is source-starved — which it is today, at 87-92% of the read cycle spent waiting (#99). It stops being fine the moment the read path is fixed (#96 A1/A2), because then the object store becomes the next thing that can saturate, and a fixed concurrency is wrong in both directions:
too low when the backend is fast and the engine is behind — artificial ceiling
too high when the backend is degraded — the engine piles on concurrent uploads against a struggling store, turning slow into failing
What to adapt on
Measured per-stage means (from the engine's own metrics, ~432 batches):
object_upload 7.75 ms
manifest_upload 5.20 ms
verify 2.55 ms
Those are already exported as vtop_stage_duration_seconds{stage=...}, so the control signal exists without new instrumentation. Candidates:
Latency-driven concurrency. Raise in-flight uploads while p95 upload latency is flat; back off when it climbs. Classic additive-increase / multiplicative-decrease.
Error/throttle-driven backoff. S3 answers overload with 503 SlowDown and 429. Treating those as a signal to reduce concurrency is strictly better than retrying at the same rate. Needs checking whether the current backend surfaces them distinguishably from other errors.
Do not start this until #96 A1/A2 lands and the 1M/s benchmark is re-run. Right now the target side is idle (0.33-1.6% CPU) and any adaptive controller would be tuning against a signal that is pure noise, because nothing is loading it.
This is exactly the mistake already made three times in this repo (#94, #97, and the reverted adaptive-poll attempt in #99): optimising a stage before establishing it was the constraint. The read path is the known constraint today. Fix it, re-measure, and only then find out whether the object store is the next one.
Explicit warning from the reverted attempt
The adaptive poll-window heuristic reverted in #99 failed because the adaptation made the thing it was adapting less able to succeed, with no recovery path — window shrank to 5ms, fetch could not complete, source read empty, window shrank further. 48x regression.
Any adaptive controller here must have:
a floor that still permits forward progress
a forced probe that lets it recover from an over-correction
Why the target side needs this too
#100 and #101 cover adapting to what the SOURCES are doing. The upload side is currently the opposite of adaptive:
batching.max_concurrent_batchesis a fixed number (default 8, added in #94), applied identically whether the object store is answering in 5ms or 5 seconds.That is fine while the engine is source-starved — which it is today, at 87-92% of the read cycle spent waiting (#99). It stops being fine the moment the read path is fixed (#96 A1/A2), because then the object store becomes the next thing that can saturate, and a fixed concurrency is wrong in both directions:
What to adapt on
Measured per-stage means (from the engine's own metrics, ~432 batches):
Those are already exported as
vtop_stage_duration_seconds{stage=...}, so the control signal exists without new instrumentation. Candidates:inflight_batchesand memory. The read and target sides should share one notion of "we are behind" rather than each optimising alone. Related: test: 1M records/sec for 5 minutes and 5M records / sec for 1 minute soak — sustained backpressure behaviour #98 hypothesis 1 (unbounded inflight growth under sustained load).Sequencing — deliberately after the read fix
Do not start this until #96 A1/A2 lands and the 1M/s benchmark is re-run. Right now the target side is idle (0.33-1.6% CPU) and any adaptive controller would be tuning against a signal that is pure noise, because nothing is loading it.
This is exactly the mistake already made three times in this repo (#94, #97, and the reverted adaptive-poll attempt in #99): optimising a stage before establishing it was the constraint. The read path is the known constraint today. Fix it, re-measure, and only then find out whether the object store is the next one.
Explicit warning from the reverted attempt
The adaptive poll-window heuristic reverted in #99 failed because the adaptation made the thing it was adapting less able to succeed, with no recovery path — window shrank to 5ms, fetch could not complete, source read empty, window shrank further. 48x regression.
Any adaptive controller here must have:
Related