feat(ha-convergence-recovery): commit-gated scheduler egress — submit_lsn tagging + watermark gate (task 1.2)

This commit is contained in:
Rongsong Shen 2026-06-14 02:33:36 +00:00
parent 7ff81156c2
commit b9ddfa60cb
9 changed files with 241 additions and 67 deletions

View file

@ -14,19 +14,49 @@ extern void collect_shared_resvals(cluster_t*, collect_check_fn_t, xlist_t*);
static int xcesched_push_joblist(cluster_t* c, xlist_t* l)
{
xce_data_t data;
xce_jobs_data_t jobs = { .n_total = l->count,
int rc = 0;
/* ha-convergence-recovery (3.1, 3.2): the incremental JOB_NEW push is a
* scheduler-bound export, so it gates on the commit watermark — exclude any
* job whose submit entry is uncommitted (job_submit_committed). A
* just-submitted job whose entry is not yet committed is correctly withheld
* here and reaches the scheduler at the next full push once committed.
* Build a filtered pointer array over the caller's list (the list stores
* xce_job_t*; recover the job_t wrapper via CONTAINER_OF for the predicate). */
xce_job_t** filtered = NULL;
int nfiltered = 0;
if (l->count > 0) {
filtered = calloc((size_t)l->count, sizeof(*filtered));
if (filtered == NULL)
return -ENOMEM;
for (int i = 0; i < l->count; i++) {
xce_job_t* xj = (xce_job_t*)xlist_get(l, i);
if (xj == NULL)
continue;
job_t* j = CONTAINER_OF(xj, job_t, job);
if (job_submit_committed(c, j))
filtered[nfiltered++] = xj;
}
}
xce_jobs_data_t jobs = { .n_total = nfiltered,
.pos = 0,
.count = l->count,
.jobs = (xce_job_t**)l->data };
int rc = 0;
.count = nfiltered,
.jobs = filtered };
memset(&data, 0x0, sizeof(data));
data.table = Data_data_schedjobs;
data.data.jobs = &jobs;
rc = xce_push_data_req(c->sched.ep, c->myhost, &data, check_controller, c,
100);
/* No committed jobs to push → nothing to send (avoids an empty payload). */
if (nfiltered > 0) {
rc = xce_push_data_req(c->sched.ep, c->myhost, &data, check_controller,
c, 100);
}
free(filtered);
return rc;
}
@ -180,7 +210,12 @@ static int xcesched_push_jobs(cluster_t* c)
data.table = Data_data_schedjobs;
data.data.jobs = &jobs;
collect_jobs(c, (collect_check_fn_t)check_job_, &jlist);
/* ha-convergence-recovery (3.1, 3.2): scheduler-bound full push gates on the
* commit watermark — a job whose submit entry is uncommitted is excluded so
* the scheduler never acts on state the post-failover cluster may not have.
* Same lock contract as collect_jobs (caller releases via
* unlock_collect_jobs). */
collect_jobs_committed(c, (collect_check_fn_t)check_job_, &jlist);
jobs.n_total = jlist.count;
jobs.jobs = (xce_job_t**)jlist.data;
jobs.count = jobs.n_total;