pub struct Governor { /* private fields */ }Expand description
The single source of parallelism in the process.
Work units acquire LeaseSets rather than being handed a thread count,
which is what makes nested parallelism safe: an outer “8 entries at once”
and an inner “multi-threaded zstd” both draw from this one pool, so their
product can never exceed the budget.
Implementations§
Source§impl Governor
impl Governor
pub fn new(workers: usize, memory_limit: u64) -> Arc<Self> ⓘ
pub fn from_inputs(inputs: &BudgetInputs, memory_limit: u64) -> Arc<Self> ⓘ
pub fn workers(&self) -> usize
pub fn memory_limit(&self) -> u64
pub fn outstanding(&self) -> usize
pub fn reserved_bytes(&self) -> u64
Sourcepub fn acquire_many(
self: &Arc<Self>,
want: usize,
per_worker_bytes: u64,
) -> LeaseSet
pub fn acquire_many( self: &Arc<Self>, want: usize, per_worker_bytes: u64, ) -> LeaseSet
Acquires up to want workers, and the memory they need, in one call.
Grants min(want, workers_free, memory_free / per_worker_bytes),
blocking only while no worker slot is free at all, and never granting
fewer than one — a single over-budget worker beats no progress.
Granting the floor worker can push the reserved total past
memory_limit — by less than one worker’s demand per grant, but that
bound does not sum across grants. Eight concurrent callers each asking
for one worker will each see cpu_free > 0, each floor to 1, and each
charge per_worker_bytes, so the reserved total can reach
workers × per_worker_bytes regardless of memory_limit. The memory
budget therefore bounds voluntary parallelism, not a hard ceiling on
reserved bytes; the hard ceiling is the worker count. That
over-commitment is the price of the progress guarantee — a caller that
would otherwise wait forever runs over budget instead of never running.
Acquire once. A unit takes its whole allocation in one call and does not acquire again while holding. Hold-and-wait is what deadlocks: four units each holding one lease and each blocking for a second would never progress. Getting fewer workers than asked is fine, the work runs slower; blocking for the full request would trade a deadlock for a stall.
Sourcepub fn try_acquire(self: &Arc<Self>) -> Option<LeaseSet>
pub fn try_acquire(self: &Arc<Self>) -> Option<LeaseSet>
Returns None immediately if the pool is full.
Sourcepub fn workers_for(&self, per_worker_bytes: u64) -> usize
pub fn workers_for(&self, per_worker_bytes: u64) -> usize
How many workers a codec needing per_worker_bytes could use.
A hint for sizing work before committing. It reserves nothing — two
concurrent callers both get the same answer. Call Self::acquire_many
to actually reserve.