merge: sync Rongsong's scheduler-framework (122 commits, 070c7869..f01ae353)

Introduces WAL replay field-completeness fixes (bug-1687..1697, 1731), scheduler snapshot job-allocation restore, heap UAF fixes (vtask_enq, xcealloc, builtin_fcfs, limit), HA fixes (bug-1694/1695/1696), xceadmin retry, worker signal-exit severity, and their test suites.

Conflicts resolved keeping both sides (drop-audit passed):
- worker.c: mark_worker_jobs_exit (bug-1509 B1) + fetchfile_signal_worker_disconnect (bug-1693)
- handler.go: DefaultBroker.Publish (EventJobFinished) + bug-1731 logging
- config_repl.c / test_config_repl.c: our ns-resolution comment / unique-tmpdir
- test_dispatch_commit.c: both B3-UNKWN and bug-1697 start_time assertions

Excluded Rongsong's bookkeeping per policy: .wolf/, .kiro/, CHANGES.md, reports/;
.claude/ + CLAUDE.md kept ours (his settings.json has machine-absolute paths).
This commit is contained in:
lei.chen 2026-08-31 14:24:17 +00:00
commit 3b6f53bb65
168 changed files with 20744 additions and 568495 deletions

View file

@ -457,10 +457,28 @@ static int sched_job_update_fun(int type, int situation, void* data, va_list ap)
switch (situation) {
case HOOK_AFTER_EVENT:
rc = notify(c, c->sched.ep, &xdata);
/* TEMP diagnostic (bug-1731 job-finish-notify-loss
* investigation): fires for BOTH the deferred-apply source
* (apply_committed_entry(), persist.c) and the live-rusage
* source (update_job_rusages(), job.c) -- both route through
* this one function. jobid+state+rc together distinguish
* which source fired and whether notify() itself reported
* success. DEBUG3-gated -- see bug-1731's own "re-add before
* next occurrence" recommendation; the DEBUG3 log-retention
* bump (bug-1731 support, main.c) exists so this survives a
* live burst without rotating out. */
TRACE("DIAG sched_job_update_fun: jobid=%ld state=0x%x rc=%d",
(long)job->job.jobid, (unsigned)job->job.state, rc);
break;
default:
break;
}
} else {
/* TEMP diagnostic (bug-1731): scheduler disconnected at the exact
* moment this notification was due -- silently dropped today. */
TRACE("DIAG sched_job_update_fun: jobid=%ld state=0x%x -- "
"c->sched.ep is NULL, notify SKIPPED",
(long)job->job.jobid, (unsigned)job->job.state);
}
mylock_unlock(&(c->sched.lock));
@ -739,6 +757,27 @@ int handle_scheduler_leave(cluster_t* c)
{
/* we need to mark the cluster status */
TRACE("%s scheduler leave", __func__);
/* bug-1693 (Decision Log: "No client reply-wait timeout as a fix for a
* hung request -- fail loud at the real transport/source instead of
* masking with a deadline backstop"). Wake any pending OPCode_schedAdmin
* waiter (cluster.c) immediately instead of leaving it to the
* SCHEDADMIN_TIMEOUT_MS deadline (5s) -- a no-op if no schedAdmin
* request happens to be in flight (schedadmin_signal_disconnect()
* returns 0 in that case).
*
* MUST run BEFORE mylock_lock(&c->sched.lock) below, not after: the
* OPCode_schedAdmin dispatch case holds c->sched.lock for its ENTIRE
* forward+wait duration (by design -- see that case's own comment in
* cluster.c), so if we grabbed c->sched.lock first, this call would
* itself block until that handler's own wait resolves one way or the
* other -- i.e. nothing would ever be able to signal it early, which is
* exactly the bug this fixes. schedadmin_signal_disconnect() only takes
* g_schedadmin_mu (cluster.c, file-local) + the pending slot's own mu --
* never c->sched.lock -- so calling it here first introduces no new
* lock-ordering hazard. */
schedadmin_signal_disconnect();
mylock_lock(&(c->sched.lock));
c->sched.ep = NULL;
mylock_unlock(&(c->sched.lock));