Summary
Make the pool's multi-slot permit race borrow stable slot storage for the duration of one acquisition instead of cloning every slot into 'static boxed futures.
This is the second implementation slice for ADR 013 proposal #638 and follows the PoolCore work in #645.
Problem
The current acquisition path:
- clones every
Arc<PoolSlot> into a newly allocated ordered vector;
- moves each clone into a boxed future;
- erases the future lifetime, which defaults the trait object to
'static;
- races the futures with
select_all;
- returns the winning slot Arc and permit.
The permit race cannot outlive the acquisition call. The 'static ownership is therefore self-imposed by the type alias rather than required by Tokio.
Proposed design
After #645 gives the pool stable slot storage, represent selection order as indices and race futures borrowing those slots.
A lifetime-aware shape may look like:
type AcquirePermitFuture<'a> = Pin<
Box<dyn Future<Output = Result<(usize, OwnedSemaphorePermit), ClientError>> + Send + 'a>
>;
Alternatively, use FuturesUnordered, an iterator of concrete futures, or another scoped collection that avoids boxing if the resulting code remains comprehensible.
The winner returns:
- the stable slot index;
- the owned permit.
Losing futures are dropped when the winner is selected. They must not leak or retain permits.
Selection order
Preserve the current round-robin starting-point behaviour without allocating and cloning a vector of slots.
Preferred approaches include:
- iterate
0..len and map logical offset to (start + offset) % len;
- use a small index iterator that wraps once;
- collect indices only if a collection materially simplifies cancellation and benchmark evidence justifies it.
Do not rotate or clone the slot objects themselves.
Cancellation safety
Verify the semaphore acquisition operation remains cancellation-safe for losing futures. The race must not:
- consume a permit without returning it;
- leave a queued waiter permanently ahead of later acquisitions;
- grant multiple permits to one acquisition;
- keep the pool core alive after the caller and scheduler release it.
If Tokio's owned permit acquisition queue semantics make racing every slot undesirable, document and implement a different scoped strategy, such as probing immediate permits before awaiting one selected slot. Preserve fairness at the logical-handle scheduler layer.
Acceptance criteria
Tests
- Pool sizes 2 and 4 with all but one slot saturated; assert the free slot wins.
- Repeated acquisitions verify the rotating start index changes the first attempted slot.
- Cancel an acquisition while all slots are saturated, release capacity, and assert a later acquisition succeeds without a lost permit.
- Make two slots become ready together and assert exactly one permit enters the lease.
- Close the pool while the race is pending and assert prompt typed failure.
- Include a deterministic or loom-style model for registration/drop races where practical.
Non-goals
- Replacing the central scheduler; tracked separately.
- Changing public fairness policy.
- Removing
OwnedSemaphorePermit or the semaphore's legitimate internal shared ownership.
- Adding dynamic pool resizing.
Dependencies
References
Summary
Make the pool's multi-slot permit race borrow stable slot storage for the duration of one acquisition instead of cloning every slot into
'staticboxed futures.This is the second implementation slice for ADR 013 proposal #638 and follows the
PoolCorework in #645.Problem
The current acquisition path:
Arc<PoolSlot>into a newly allocated ordered vector;'static;select_all;The permit race cannot outlive the acquisition call. The
'staticownership is therefore self-imposed by the type alias rather than required by Tokio.Proposed design
After #645 gives the pool stable slot storage, represent selection order as indices and race futures borrowing those slots.
A lifetime-aware shape may look like:
Alternatively, use
FuturesUnordered, an iterator of concrete futures, or another scoped collection that avoids boxing if the resulting code remains comprehensible.The winner returns:
Losing futures are dropped when the winner is selected. They must not leak or retain permits.
Selection order
Preserve the current round-robin starting-point behaviour without allocating and cloning a vector of slots.
Preferred approaches include:
0..lenand map logical offset to(start + offset) % len;Do not rotate or clone the slot objects themselves.
Cancellation safety
Verify the semaphore acquisition operation remains cancellation-safe for losing futures. The race must not:
If Tokio's owned permit acquisition queue semantics make racing every slot undesirable, document and implement a different scoped strategy, such as probing immediate permits before awaiting one selected slot. Preserve fairness at the logical-handle scheduler layer.
Acceptance criteria
'staticmerely for type erasure.(slot_index, OwnedSemaphorePermit)or an equivalent non-owning slot identity.Tests
Non-goals
OwnedSemaphorePermitor the semaphore's legitimate internal shared ownership.Dependencies
References
src/client/pool/client_pool.rssrc/client/pool/slot.rs