feat(job-array-single-wal-record): implement restore_job_array primitive
Adds the shared N-way array expansion primitive: decodes a committed WAL_JOB_ARRAY_SUBMIT payload, scratch-builds every element via a throwaway kv-table (never touching c->jobmgr during construction), then makes the whole set visible in one bulk pass under a single write-lock acquisition -- no window where a concurrent reader can observe a partially-constructed array. Idempotent per index (skips already-existing jobids; whole-record no-op if all exist). Includes an XCE_TESTING-guarded fault-injection seam. Not yet wired into any live dispatch path (tasks 3.2/3.3). Two review rounds: round 1 found the bulk-insert pass silently claimed success even when key_add() itself could fail on allocation exhaustion (c->jobmgr grows via realloc, no reservation primitive exists anywhere in kv.c/kvmgr.c/zarray.c to pre-check this). Fixed by checking key_add()'s return and reporting failure honestly instead of a false success. The underlying table has no key_del, so an already-inserted prefix on this specific failure mode can remain genuinely visible while the call reports failure -- documented as a residual gap in design.md and tasks.md for tasks 3.2/4.x to account for (that prefix is never pushed to scheduler/API server, even on a later successful retry, since it's never included in out_new_jobs). Task 3.1 of job-array-single-wal-record.
This commit is contained in:
parent
78eb983a74
commit
7c755dc4d7
7 changed files with 1346 additions and 1 deletions
|
|
@ -45,6 +45,33 @@ extern int update_resvals(cluster_t*, worker_t*, int, xce_resval_t*);
|
|||
|
||||
extern int load_jobs(void*);
|
||||
extern int restore_job(cluster_t*, uint64_t, const void*, size_t, uint64_t);
|
||||
/* job-array-single-wal-record task 3.1 (design.md Array Apply Expansion):
|
||||
* shared N-way expansion primitive for a committed WAL_JOB_ARRAY_SUBMIT
|
||||
* payload -- see the doc comment on the definition (job.c) for the full
|
||||
* atomicity/idempotency contract. out_new_jobs is optional; when non-NULL
|
||||
* and the call genuinely creates new elements, it is populated (ownership
|
||||
* transferred) with every newly created job_t* in index order. */
|
||||
extern int restore_job_array(cluster_t*, const void*, size_t, uint64_t,
|
||||
xlist_t*);
|
||||
#ifdef XCE_TESTING
|
||||
/* job-array-single-wal-record task 3.1: forces restore_job_array()'s
|
||||
* scratch-build loop to fail construction at the given 0-based element
|
||||
* index (simulating resource exhaustion), so a test can prove the
|
||||
* all-or-nothing atomicity contract. Pass a negative index, or call the
|
||||
* clear helper, to disable. Compiled out of production. */
|
||||
extern void job_array_apply_test_set_force_fail_at(int index);
|
||||
extern void job_array_apply_test_clear_force_fail(void);
|
||||
/* job-array-single-wal-record task 3.1 remediation: forces
|
||||
* restore_job_array()'s BULK-INSERT pass (the key_add(c->jobmgr, ...) loop,
|
||||
* distinct from the scratch-build loop above) to fail at the given 0-based
|
||||
* index WITHIN THAT PASS, simulating c->jobmgr's backing store hitting a
|
||||
* genuine realloc() OOM while growing under the write lock. Lets a test
|
||||
* prove this failure mode is reported as a negative errno, never a false
|
||||
* built.count success. Pass a negative index, or call the clear helper, to
|
||||
* disable. Compiled out of production. */
|
||||
extern void job_array_apply_test_set_bulk_insert_force_fail_at(int index);
|
||||
extern void job_array_apply_test_clear_bulk_insert_force_fail(void);
|
||||
#endif
|
||||
extern int update_job(void*, uint64_t, xce_kv_list_t*);
|
||||
extern int do_job_started(void*, uint64_t, int, int*, int, int*);
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue