Skip to content

feat(engine): AIMD concurrency limiter type#3951

Merged
oferchen merged 3 commits into
masterfrom
feat/aimd-limiter-2091
May 7, 2026
Merged

feat(engine): AIMD concurrency limiter type#3951
oferchen merged 3 commits into
masterfrom
feat/aimd-limiter-2091

Conversation

@oferchen
Copy link
Copy Markdown
Owner

@oferchen oferchen commented May 7, 2026

Summary

  • Lands the standalone AIMD limiter type defined by the design RFC at docs/design/aimd-concurrency-limiter.md (Use branded constants in daemon wrapper tests #2090). The implementation lives at crates/engine/src/concurrent_delta/work_queue/limiter.rs and is exported from work_queue/mod.rs as AimdLimiter, LimiterConfig, OverloadReason, and Ticket.
  • Pure-std implementation: AtomicUsize / AtomicU32 / AtomicU64 for state, Instant + OnceLock for the monotonic epoch, integer-only RTT EMA per RFC 6298 (alpha_ema = 1/8), Newton-method isqrt for the RTT-spike sigma threshold. No new dependencies, no unsafe.
  • RAII slot guard: Ticket is #[must_use], consumed by record_success / record_overload / record_error. The Drop fallback releases in_flight without disturbing target or the EMA so a panicking worker cannot leak the slot.
  • Atomic ordering matches the spec: AcqRel for the try_acquire CAS and counter mutations, Release for state publishes, Acquire for state reads. No Relaxed on target.
  • Not integrated yet. This PR adds only the type and unit tests so it can land independently. Wiring into WorkQueueSender::send and the disk-commit WriterPressure reporter arrives with Remove legacy daemon wrappers #2092 (convergence tests under injected error). The --adaptive-concurrency / --no-adaptive-concurrency CLI flag is Brand version banners around oc-rsync #2093.

Test plan

Twelve unit tests inside limiter.rs::tests cover the algorithm:

  • isqrt_matches_floor_sqrt - Newton iteration matches floor(sqrt(n)) for boundary, mid-range, and near-u64::MAX inputs.
  • acquire_respects_target - try_acquire returns None once in_flight == target, and a record_success re-opens the slot.
  • acquire_saturation_under_threads - two threads racing on a one-slot limiter never exceed target and in_flight returns to 0 after the join.
  • additive_increase_after_target_successes - alpha = 1 adds one slot per completed window in steady state.
  • multiplicative_decrease_halves_target_on_overload - beta = 1/2 halves target on record_overload.
  • decrease_clamped_to_min_limit - decrease saturates at min_limit.
  • increase_clamped_to_max_limit - increase saturates at max_limit.
  • debounce_suppresses_back_to_back_decreases - second overload inside the 2 * rtt_ema window leaves target unchanged.
  • rtt_ema_smoothing_converges - 10 baseline + 20 stress samples settle the EMA in [9.0ms, 9.5ms], matching the analytic geometric tail of (7/8)^20.
  • ticket_drop_on_panic_decrements_in_flight - panic::catch_unwind confirms the Drop fallback releases the slot without changing target.
  • error_kind_classification - WouldBlock / Interrupted halve target; NotFound / PermissionDenied keep target untouched per design section 3.4 item 3.
  • slow_start_doubles_until_first_decrease - target doubles 2 -> 4 -> 8 in slow-start, halves to 4 on first overload, then grows additively (4 -> 5) instead of doubling.
  • rtt_spike_predicate - returns false with no samples, false at the EMA, true at a 100x outlier.
  • config_builder_clamps_initial_target - builder clamps an out-of-range initial_target into [min_limit, max_limit].

CI (fmt + clippy + nextest on Linux/macOS/Windows) is the test runner per the contributing guide; nothing was run locally.

@github-actions github-actions Bot added the enhancement New feature or request label May 7, 2026
oferchen added 3 commits May 7, 2026 23:07
Adds the standalone limiter type defined by the design RFC at
docs/design/aimd-concurrency-limiter.md. The implementation lives in
crates/engine/src/concurrent_delta/work_queue/limiter.rs and exposes:

- LimiterConfig builder with min_limit / max_limit / alpha / beta_num /
  beta_den / build().
- AimdLimiter with try_acquire, target, in_flight, rtt_ema_nanos, and a
  pub is_rtt_spike predicate.
- RAII Ticket guard (#[must_use]) with record_success / record_overload /
  record_error and Drop fallback for panic paths.
- OverloadReason variants for RttSpike / QueueSaturated /
  DiskCommitPressure / ErrorRate.

Internals follow the RFC: integer-only RTT EMA (alpha_ema = 1/8 per
RFC 6298), variance smoothed with beta = 1/4, RTT-spike threshold of
ema + 2*sqrt(var) via Newton-method isqrt, slow-start doubling until
the first decrease, debounce window of 2*rtt_ema after each
multiplicative decrease, and AcqRel/Acquire atomic ordering on every
target/in_flight transition.

Twelve unit tests cover the algorithm: target saturation (single
threaded and under thread contention), additive increase, multiplicative
decrease, min/max clamps, debounce suppression, RTT EMA convergence,
ticket Drop on panic, transient-vs-deterministic error classification,
slow-start doubling, RTT-spike predicate, builder clamps, and the
isqrt helper.

Not yet integrated. Callers (WorkQueueSender, disk-commit, CLI) are
wired in the follow-on tickets:
- #2092: convergence tests under injected error.
- #2093: --adaptive-concurrency / --no-adaptive-concurrency CLI flag.
@oferchen oferchen force-pushed the feat/aimd-limiter-2091 branch from bfc0c39 to acdb8cf Compare May 7, 2026 20:07
@oferchen oferchen merged commit 509c928 into master May 7, 2026
39 checks passed
@oferchen oferchen deleted the feat/aimd-limiter-2091 branch May 8, 2026 03:46
oferchen added a commit that referenced this pull request May 18, 2026
* feat(engine): AIMD concurrency limiter type (#2091)

Adds the standalone limiter type defined by the design RFC at
docs/design/aimd-concurrency-limiter.md. The implementation lives in
crates/engine/src/concurrent_delta/work_queue/limiter.rs and exposes:

- LimiterConfig builder with min_limit / max_limit / alpha / beta_num /
  beta_den / build().
- AimdLimiter with try_acquire, target, in_flight, rtt_ema_nanos, and a
  pub is_rtt_spike predicate.
- RAII Ticket guard (#[must_use]) with record_success / record_overload /
  record_error and Drop fallback for panic paths.
- OverloadReason variants for RttSpike / QueueSaturated /
  DiskCommitPressure / ErrorRate.

Internals follow the RFC: integer-only RTT EMA (alpha_ema = 1/8 per
RFC 6298), variance smoothed with beta = 1/4, RTT-spike threshold of
ema + 2*sqrt(var) via Newton-method isqrt, slow-start doubling until
the first decrease, debounce window of 2*rtt_ema after each
multiplicative decrease, and AcqRel/Acquire atomic ordering on every
target/in_flight transition.

Twelve unit tests cover the algorithm: target saturation (single
threaded and under thread contention), additive increase, multiplicative
decrease, min/max clamps, debounce suppression, RTT EMA convergence,
ticket Drop on panic, transient-vs-deterministic error classification,
slow-start doubling, RTT-spike predicate, builder clamps, and the
isqrt helper.

Not yet integrated. Callers (WorkQueueSender, disk-commit, CLI) are
wired in the follow-on tickets:
- #2092: convergence tests under injected error.
- #2093: --adaptive-concurrency / --no-adaptive-concurrency CLI flag.

* style: cargo fmt --all

* fix(engine): clippy lints on AIMD limiter (abs_diff, div_ceil, format args)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant