fix(controller): WAL_JOB_PREASON loses job.pend_reasons on replay (bug-1692)
Last of the five field-parity gaps from the original audit (bug-1678,
bug-1687, bug-1689, bug-1690, bug-1691). set_preason()/clear_preason()
set job.pend_reasons (host/resource-based pending-job explanations), but
persist_job_hook_fun's default: arm only ever captured {jobid, state}.
Neither apply seam restored pend_reasons after a restart.
Reuses the ALREADY-EXISTING JobPendReason/HostBasedReason/ResourceBasedReason
capnp structs -- no schema change needed, unlike bug-1690's WAL_JOB_RUSAGE.
Safety-checked against bug-1690's lesson (RTTI/makeString()-backed fields
need merge-not-replace, not free-and-replace): pend_reasons is plain
malloc/strdup-backed throughout (erase_job_preason is FREEUP()-only,
add_host_preason/add_res_preason use strdup()/calloc()), so a
straightforward free-and-replace is safe here, matching bug-1678/1687's
pattern instead.
New wrinkle beyond the four prior fixes: pend_reasons has a genuine CLEAR
operation, and "trailing bytes present or absent" can't distinguish a
legitimate clear from an old-format payload -- added an explicit presence
byte (0=cleared/adopt NULL, 1=capnp bytes follow), verified by two
dedicated "clear survives restart" tests.
11 new tests in test_wal_job_preason_fact.c; RED/GREEN independently
verified (7 genuine pre-fix failures, one test's own wrong premise about
capnp's garbage-byte behavior caught and corrected during RED/GREEN
iteration). Full controller suite: 1178 tests, 2 failures -- both the
pre-existing, unrelated bug-1561 overlayfs sandbox flake. No ASAN findings.
This closes the field-complete apply parity invariant class the
xce-audit-invariants controller dimension 7 was added for.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AgYRU3zDTqNGV5Jk8aiKLg
This commit is contained in:
parent
1b86e04078
commit
d0e5f85aa8
7 changed files with 1465 additions and 3 deletions
|
|
@ -187,7 +187,43 @@ typedef enum {
|
|||
* forward state transition -- a checkpoint report
|
||||
* never changes job.state, so gating it the same
|
||||
* way would make it dead code. */
|
||||
WAL_JOB_PREASON = 10,
|
||||
WAL_JOB_PREASON = 10, /* scheduler-reported host/resource-based pending
|
||||
* reasons (job.pend_reasons, set by set_preason()/
|
||||
* cleared by do_clr_preason(), job.c). Payload is
|
||||
* wal_jobstate_t{jobid, state, _pad=0} for any
|
||||
* entry written before bug-1692. As of bug-1692,
|
||||
* persist_job_hook_fun's HOOK_DETAIL_SETPREASON/
|
||||
* HOOK_DETAIL_CLRPREASON arm appends an explicit
|
||||
* presence byte after the header: 0 = pend_reasons
|
||||
* was genuinely cleared (adopt NULL on replay), 1
|
||||
* = trailing Cap'n Proto JobPendReason bytes
|
||||
* follow (adopt the decoded value). Unlike
|
||||
* WAL_JOB_CKPT/WAL_JOB_RUSAGE, "trailing bytes
|
||||
* present or absent" alone cannot distinguish
|
||||
* "old-format payload" from "field is legitimately
|
||||
* NULL", because pend_reasons -- uniquely among
|
||||
* this fact-type family -- has a real CLEAR
|
||||
* operation (do_clr_preason) that must survive
|
||||
* replay durably, not just its SET side; the
|
||||
* presence byte resolves that ambiguity. A payload
|
||||
* of exactly sizeof(wal_jobstate_t) (no presence
|
||||
* byte at all) leaves pend_reasons untouched on
|
||||
* both apply seams, matching the pre-fix
|
||||
* state-only behavior exactly. Like
|
||||
* WAL_JOB_RUSAGE/WAL_JOB_CKPT, adoption on the
|
||||
* apply_committed_entry() seam is NOT gated on a
|
||||
* forward state transition -- set_preason()/
|
||||
* do_clr_preason() never change job.state, so
|
||||
* gating it the same way would make it dead code.
|
||||
* Adoption is a plain free-and-replace (via the
|
||||
* capnp-generated free_JobPendReason_ptr()), NOT a
|
||||
* merge like WAL_JOB_RUSAGE -- job.pend_reasons
|
||||
* and its nested host/resource reason arrays are
|
||||
* plain calloc()/strdup() throughout (verified via
|
||||
* erase_job_preason()'s FREEUP-only release, NOT
|
||||
* xstring/RTTI-backed like ckptinfo/rusage's
|
||||
* host_name), so no merge-not-replace hazard
|
||||
* exists here. */
|
||||
WAL_JOB_ARRAY_SUBMIT = 11, /* job-array-single-wal-record: one record for
|
||||
* the whole array (base spec + index range),
|
||||
* distinct from WAL_JOB_SUBMIT's single-job
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue