fix(job-array-single-wal-record): wire dispatcher was silently dropping compact array pushes

extract_data() (src/lib/request.c), the shared reassembly step every
inbound push passes through inside vtask_entry() before any receiver's
handler runs, had no case for Data_data_jobArray -- it hit
default: rc=-EINVAL. Because vtask_entry()'s callnext check treats any
nonzero return (including a negative errno) as "reassembly complete,
proceed," this never surfaced as an error: the real payload was freed
and the receiver silently handed an empty, zeroed dataset_t, with no
log anywhere in the chain. Tasks 5.1-5.3 were each individually
correct and tested in isolation, but the feature was dead on the real
wire end-to-end.

Adds case Data_data_jobArray: passing the single, unchunked
descriptor straight through (no pagination needed, unlike the
existing LIST-shaped cases) and nulls the source pointer after
transfer -- verified this is not cosmetic, since free_Request()'s
pushmsg case would otherwise double-free it via free_Data()'s live
Data_data_jobArray branch.

Proven with a real xce_encode()/xce_decode() round-trip through the
fixed extract_data() -> sched_handle_dataset() -> sched_on_job_array()
(task 5.3, unmodified) chain, not just a unit-level check on
extract_data() alone. Also confirms task 5.4's future API-server
receive path shares this exact fix, since both go through the same
xcecli_ctx_init() -> vtask_entry() -> extract_data() pipeline.

One self-flagged, non-blocking residual gap (pre-existing since task
5.3, out of this task's request.c-only boundary): dataset->rows for
the jobArray case is never deep-freed downstream, leaking one bounded
xce_job_submit_t per successfully-delivered array push commit.

Task 5.3b of job-array-single-wal-record (Requirements 6.1, 6.2, 6.4, 8.4).
Inserted mid-run after independent review confirmed the gap; user
confirmed sequencing (fix now, before task 5.4).
This commit is contained in:
Rongsong Shen 2026-07-15 10:59:39 +00:00
parent d16847185e
commit 1cbd7df1a8
4 changed files with 216 additions and 1 deletions

View file

@ -1778,6 +1778,27 @@ int extract_data(dataset_t* dataset, xce_data_t* getdata)
memset(getdata->data.resvals->vals, 0x0, count * sizeof(xce_resval_t*));
break;
case Data_data_jobArray:
/* job-array-single-wal-record task 5.3b: single, unchunked JobSubmit
* descriptor (base jobid, array_size, one shared spec) -- unlike the
* LIST-shaped cases above, no pagination/accumulation loop is needed:
* xcesched_push_jobarray() (sched.c) and apiserver_push_jobarray()
* (apiserver.c) always send exactly one complete descriptor per
* commit. Transfer ownership of the decoded pointer straight into
* dataset->rows (mirrors the LIST cases' ownership-transfer intent,
* without an array-of-pointers layer since there is only one row)
* and signal reassembly complete immediately -- returning here skips
* the shared ntotal/pos-based tail below, which does not apply to a
* single-shot payload. */
if (getdata->data.job_array == NULL) {
return -EINVAL;
}
dataset->rows = (void*)getdata->data.job_array;
dataset->nrows = 1;
getdata->data.job_array = NULL;
return 1;
default:
rc = -EINVAL;
break;