Requirements reviewed and revised (seqjob per-bucket reset, nslots/nhosts, bug-1893 fix in the runner), design and 11-task plan generated and reviewed. bug-1892: unsatisfy_() reads index-keyed uncommitted amounts by position. bug-1893: allocators' shared pend-reason loop reads past the unmet list. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
3.9 KiB
| id | status | status_updated | status_note | component | severity | timestamp | last_seen | occurrences | files | tags | related | |||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| bug-1892 | open | 2026-09-30 | newly logged | scheduler | wrong-result | 2026-09-30T03:58:52Z | 2026-09-30T03:58:52Z | 1 |
|
|
|
bug-1892: xce_scheduler admission check reads per-resource uncommitted amounts by list position, not index
Description
Observed: found by code reading, so there is no failing run yet. unsatisfy_() (src/scheduler/src/resource.c:130-169) compares
if (total[i] < inuse[i] + uncomitted[i] + wanted[i])
where total, inuse and wanted are positional arrays (entry i is the
i-th resource of the request, gathered by get_resvals(..., wanted->idxs, ...)),
but uncomitted is the context's dense, resource-index-keyed vector
(ctx->uncomitted.shared / ctx->uncomitted.hosts[w], 1024 floats,
schedobj.c:514/595), filled by xvec_idval(uncomit, &req, XVEC_ADD_FLOAT),
which writes d[idx] += val (lib/xvec.c, DEFINE_XVEC_IDVAL_OP). Both
sched_check_shared_satisfy_() (resource.c:309) and
sched_check_host_satisfy_() (resource.c:376) pass uncomitted->data
straight through, so entry i reads the uncommitted amount of resource index
i, not of resource wanted->idxs[i].
Expected: entry i uses uncomitted[wanted->idxs[i]] (gather it
positionally like total/inuse, e.g. with the existing get_resvals()).
Impact: wrong admission result. Uncommitted amounts are nonzero only
within one allocation context that already committed something, i.e. from the
second primary of a COMPOUND (or ALTER) job on, since those primaries share one
ctx (scheduler.c:348-354); the first primary and ordinary PRIMARY jobs
always see all-zero uncommitted vectors, and parjob rolls back failed plans.
For a later primary, the check subtracts an unrelated resource's uncommitted
amount (or 0) instead of the earlier primaries' real claim on the same
resource, so it can over-admit (earlier primary's claim ignored: the job is
dispatched beyond host/shared capacity) or wrongly pend (another resource's
amount charged). Pend reasons printed for the same check carry the wrong
shortfall.
Found by: review of the scheduler-allocator-runner requirements
(2026-09-29), while checking the shared-resource precheck the runner inherits.
Environment
- OS: no /etc/os-release; Docker container; NixOS kernel; kernel Linux 6.18.33 x86_64
- libc: glibc 2.42-47 (interpreter /nix/store/wb6rhpznjfczwlwx23zmdrrw74bayxw4-glibc-2.42-47/lib/ld-linux-x86-64.so.2)
- Toolchain: gcc (GCC) 15.2.0, meson 1.9.1
- Build: asan (xce.build)
- Code: scheduler-framework @ a370d724-dirty
- Deployment: n/a: found by code reading; affects any deployment scheduling COMPOUND/ALTER jobs
Reproduction
git checkout a370d724; readsrc/scheduler/src/resource.c:130-169(unsatisfy_) and its two callers at:309and:376, andsrc/scheduler/src/schedobj.c:509-514,586-600(dense 1024-entry uncommitted vectors) andsrc/lib/xvec.cDEFINE_XVEC_IDVAL_OP(d[idx] += val).- Unit-test sketch (white-box
#include "resource.c", liketest_resource_accounting.c): one host withmemtotal 10 at resource idx 5 (idx 0 =slots, plenty); set the host's uncommitted vector[5] = 8(an earlier primary's claim); callsched_check_host_satisfy()withwanted = {idx 5: 4}. Expected 0 (8 + 4 > 10); today it returns 1, because it readsuncomitted[0](= 0).
- Frequency: deterministic (by code reading; no test exercises it yet)
- Evidence: not kept (code reading only)
Root cause
TODO: required for fixed/partial
Fix
TODO: required for fixed/partial
Verification
- Test: TODO: name + file; RED before the fix, GREEN after
- Suites: TODO: suite results and build profile
- Live: TODO: soak/deploy run, or n/a and why
References
- Related: none