test(scheduler-allocator-runner): characterize the parjob allocator (task 2.2)
15 tests drive the real parjob plugin through job_alloc_fn: success, short shared, pending on hosts, mid-plan rollback, task counts 0/1, missing inputs, six OOM steps with their debits, COMPOUND. Values the runner changes on purpose sit in *_today tests. Spec: the task showed that parjob records host reasons only for a bucket search's first rejected candidate (the rejected host's request stays in alloc_req.host and the host iterator pre-filters later hosts against it). Decision: the runner clears alloc_req.host before every candidate, for both allocators, so every short host gets its reasons (Req 3.6/3.7); publishing reasons only when they change is a follow-up. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
91a8580948
commit
b4470b2b94
6 changed files with 874 additions and 56 deletions
|
|
@ -117,40 +117,37 @@ goal that plugins no longer export `my_alloc()`).
|
|||
the seqjob OOM rollback of item 2 (Req 5 AC 5).
|
||||
- Divergences found in discovery that the design MUST resolve explicitly
|
||||
(they are not in the 2026-09-23 proposal):
|
||||
1. **Decided 2026-09-29: the shared loop resets `ctx->alloc_req.host` to
|
||||
empty before every bucket's host scan, for both allocators.** Background:
|
||||
the per-host request used by the authoritative check is already rebuilt
|
||||
for every candidate (`sched_try_alloc_on_host_()` -> `plugin_prepare_
|
||||
allocation()` with `ctx->worker` set resets and refills it,
|
||||
`plugin.c:639`). The per-bucket reset only affects the host iterator's
|
||||
pre-filter (`host_iter.c:143`), which reads `alloc_req.host` before that
|
||||
rebuild and silently skips hosts that fail. parjob already resets
|
||||
(`parjob_allocator.c:479`), so its pre-filter does no resource filtering.
|
||||
seqjob does not, so its pre-filter reads stale content: the job-level
|
||||
`slots:1` for the first candidate, then the last rejected candidate's
|
||||
full request. Resetting for seqjob too drops the stale-state dependency
|
||||
and makes seqjob's pre-filter a resource no-op, like parjob's.
|
||||
**Accepted consequence (intentional change):** host choice is unchanged
|
||||
(a host the stale pre-filter rejects also fails the authoritative check
|
||||
while the per-host request is host-independent; where a limit makes it
|
||||
host-specific, the stale filter could wrongly skip a host, which the
|
||||
reset fixes). But a pending seqjob job now gets a `PREASON_NO_RESOURCE`
|
||||
host/resource reason from the authoritative check
|
||||
(`resource.c:575`) for every host that passes the select filter and
|
||||
lacks resources, not only for hosts the stale pre-filter let through.
|
||||
`main_reason` is unaffected (host/resource reasons go to
|
||||
`res_based_reasons`, `lib/preason.c:147`), so sim parity
|
||||
(`sim_verify_pend_main_reason_eq`) is unaffected; no testsuite file
|
||||
asserts `PREASON_*` host reasons (checked 2026-09-29).
|
||||
Also accepted (found in design review): seqjob now runs the per-host
|
||||
prepare fan-out on those hosts too, so the limit plugin may instantiate
|
||||
a host limit's virtual resource and set its value on the worker earlier
|
||||
than before (decision-neutral, lazy creation moves earlier), at the cost
|
||||
of one prepare + check per short host per pending seqjob attempt.
|
||||
Rejected: keeping the reset parjob-only (preserves the stale-state
|
||||
quirk in shared code); staging each bucket's real request before the
|
||||
scan so the pre-filter filters correctly (changes parjob's pend
|
||||
reasons too; a separate follow-up if wanted).
|
||||
1. **Decided 2026-09-29, revised 2026-09-30 (task 2.2 finding, user
|
||||
decision): the runner clears `ctx->alloc_req.host` before every
|
||||
candidate host (at the start of each bucket and after every rejected
|
||||
candidate), for both allocators.** The per-host request used by the
|
||||
authoritative check is rebuilt for every candidate anyway
|
||||
(`plugin_prepare_allocation()` with `ctx->worker` set, `plugin.c:639`).
|
||||
What the clear changes is the host iterator's pre-filter
|
||||
(`host_iter.c:143`), which reads `alloc_req.host` before that rebuild and
|
||||
silently skips hosts that fail. The 2026-09-29 plan (clear once per
|
||||
bucket, as parjob does) turned out not to be enough: task 2.2's
|
||||
characterization showed that a rejected candidate leaves its own request
|
||||
behind, so parjob today records reasons only for the first rejected
|
||||
candidate of a bucket search, and a once-per-bucket clear would give
|
||||
seqjob the same partial reasons. With a clear before every candidate,
|
||||
the pre-filter only applies the select expression, and every
|
||||
selection-matching unclaimed short host gets its host/resource reasons,
|
||||
in both allocators.
|
||||
**Accepted consequences (intentional changes):** host choice, main
|
||||
reason and decisions are unchanged (a host the stale pre-filter rejects
|
||||
also fails the authoritative check while the per-host request is
|
||||
host-independent; where a limit makes it host-specific, the stale filter
|
||||
could wrongly skip a host, which the clear fixes). Pending jobs of both
|
||||
allocators carry more host/resource reasons (`res_based_reasons`; not
|
||||
`main_reason`, so the unsatisfiable cache and sim parity are unaffected).
|
||||
The per-host prepare fan-out, including the limit plugin's lazy
|
||||
host-limit instantiation, now runs on every short host (decision-neutral;
|
||||
one prepare + check per short host per bucket search). Larger reason sets
|
||||
are published and persisted; publishing reasons only when they change is
|
||||
a follow-up (user, 2026-09-30), out of scope here.
|
||||
Rejected: clearing once per bucket (partial reasons, still stale-state
|
||||
dependent); keeping today's per-plugin behaviour.
|
||||
2. **Decided (requirements Req 5 AC 5):** seqjob builds its halloc directly
|
||||
from `ctx->alloc_req.host`; under the shared per-claim snapshot it gains
|
||||
a new `-ENOMEM` path, which goes through the same rollback
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue