Skip to content

Dependency-aware semaphore with permit inheritance for concurrently() admission control #23503

Description

@tobni

Is your feature request related to a problem? Please describe.

#23486 throttles how many items of a concurrently(..) group are driven at once.

The implementation scopes a tokio::sync::Semaphore to each gen_all call, with a window of max(64, local_parallelism * 4, remote_parallelism * 2).

Two things about it are ad hoc, per review discussion on the PR:

  1. The 4x / 2x multipliers are guesses and untuned for remote execution.
  2. Per-call scoping means the global bound is not a bound at all so worst-case admitted concurrency is window^depth.

The per-call scoping exists because a single shared pool deadlocks.

Describe the solution you'd like

A dependency-aware semaphore with permit inheritance. A single session-global pool of permits caps memory globally. An acquisition may borrow the permit held by an ancestor on its requester chain with at most one borrower per permit at a time.

Implementation suggestion:

  • A custom primitive (Semaphore has no borrow). Two waker queues. Acquire would first try pool, then try borrowing the nearest ancestor's permit, then wait on both.
  • Intra-node nesting (AllItem::Concurrent): the ancestor's borrow-permit is task-local, threaded through gen_allgen_all_itemgen_all.
  • Cross-node nesting (AllItem::Call): the borrow check is "does any current dependent chain of this node hold a permit?" The graph crate already tracks dependents so we can expose that at acquire time and re-check when a new dependent attaches while blocked.
  • Borrowability derives dynamically from current dependents.

Describe alternatives you've considered

Keep per-call windows and only tune the multipliers. Never fixes the W^depth blow-up on deeply nested concurrently usage. The multipliers as is have no principled setting because the quantity they bound is not global.

Additional context

#23486

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions