merge: sync Rongsong's scheduler-framework (88 commits, f01ae353..c5b172c7)
Two-sided divergence from f01ae353 (2026-08-30): theirs +88 (worker
rejoin-resync reconciliation, terminal-state bug-1737/1738/1739/1764,
scheduler-sim verbosity, hermetic offline build, go mod vendor of Go deps
in apiserver -- 3375 pure-adds), ours +89 (job-finish robustness bug-1509
B1/B3, PEND-reason, worker reconnect resend, apiserver job control).
Conflict resolutions (kept both sides' fixes):
- controller_connector.c checking_connection(): combine theirs
xcecd_resync_is_pending() rejoin deferral gate with ours
resend_job_status() actual-state re-report on rejoin success.
- job.c: keep both unknown-finish registry (ours, bug-1509) and
record_job_finish_fact_at (theirs, bug-1747); keep both
mark_jobs_unknown_core family (ours) and record_job_reconcile_*
(theirs). No double-notify: on_job_finish unchanged, theirs is
resync-path-only.
- scheduler handler.c/test_handlers.c/meson: theirs schedExitJob
exit_code branch (bug-1737) + ours jobDispatchFail success-ack no-op
(bug-1512) + configpush enq_pend_update (bug-1513) both present; both
test suites and REPL/sim targets wired.
- apiserver jobs.go: keep ours normalizeJobInt64/jobArrayIdx superset +
JobIDHuman; drop theirs strict IntOrInt64 early-reject (superseded --
ours tolerates float64/json.Number, no panic path).
- jobs_test.go: keep both regression suites (ours bug-1490, theirs
bug-1742).
- .kiro/specs scheduler-sim-*/worker-rejoin-resync + .wolf/*: keep our
deletions (established convention -- drop Rongsong bookkeeping on merge).
Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
commit
5e2985542f
3469 changed files with 1466599 additions and 382 deletions
|
|
@ -25,6 +25,12 @@ typedef struct {
|
|||
int nlimits;
|
||||
xce_limit_config_t** limits;
|
||||
uint64_t config_generation; /* monotonic audit counter from capnp schema */
|
||||
/* worker-rejoin-resync (Req 3.7, 5.3): shared, cluster-wide via
|
||||
* operational-uniformity override (design.md Configuration Model) --
|
||||
* alongside heartbeat_interval/inactive_heartbeat_count above, same
|
||||
* domain. */
|
||||
int worker_resync_window_ms;
|
||||
int worker_resync_timeout_ms;
|
||||
} cluster_config_t;
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -60,6 +60,31 @@ extern int xce_ctrlstatus_req(endpoint_t*);
|
|||
extern int xce_get_req(endpoint_t*, xce_get_t*);
|
||||
extern int xce_reply_get(endpoint_t*, xce_peerinfo_t*, xce_reply_t*,
|
||||
xce_check_fn_t, void*, int);
|
||||
|
||||
/*
|
||||
* xce_job_state_query_req / xce_job_state_report_req: send the worker-rejoin-
|
||||
* resync job-state reconciliation exchange's paginated request/reply pair
|
||||
* (worker-rejoin-resync task 1.4, Req 8.1/8.2/8.3) --
|
||||
* OPCode_jobStateQuery (controller -> worker, query->jobids) and
|
||||
* OPCode_jobStateReport (worker -> controller, report->entries) -- using the
|
||||
* same {pos,count,ntotal} pagination idiom as xce_push_data_req()/
|
||||
* xce_reply_get() above: `pktlimit <= 0` sends the whole list in one page;
|
||||
* a zero-length list still sends exactly one page with count == 0 (an empty
|
||||
* page is a valid, complete exchange, not something to skip). The receiving
|
||||
* side decodes each page with the generic xce_decode() -- these opcodes are
|
||||
* their own dedicated Request body union arms (jobstatequerymsg/
|
||||
* jobstatereportmsg, added by task 1.1's schema), not multiplexed through
|
||||
* xce_data_t, so encode/decode of each page's payload is already handled by
|
||||
* the generated encode_JobStateQuery()/encode_JobStateReport() (controller.capnp.c)
|
||||
* that xce_encode()/xce_decode() call into.
|
||||
*/
|
||||
extern int xce_job_state_query_req(endpoint_t*, xce_peerinfo_t*,
|
||||
xce_job_state_query_t*,
|
||||
xce_check_fn_t, void*, int);
|
||||
extern int xce_job_state_report_req(endpoint_t*, xce_peerinfo_t*,
|
||||
xce_job_state_report_t*,
|
||||
xce_check_fn_t, void*, int);
|
||||
|
||||
extern int xce_notify_req(endpoint_t*, xce_notify_data_t*);
|
||||
extern int extract_data(dataset_t*, xce_data_t*);
|
||||
extern int xce_update_req(endpoint_t*, xce_update_data_t*);
|
||||
|
|
|
|||
|
|
@ -72,6 +72,11 @@ typedef struct {
|
|||
char* clustername;
|
||||
int n_confvars;
|
||||
xce_config_t** confvars;
|
||||
/* worker-rejoin-resync task 6.1 (Req 3.7): mirrors clustername above --
|
||||
* pulled directly from c->myconf->cluster_config->worker_resync_window_ms
|
||||
* (worker.c's worker_push_config()), not part of the generic confvars
|
||||
* key/value list. */
|
||||
int worker_resync_window_ms;
|
||||
} xce_conf4worker_t;
|
||||
|
||||
typedef struct {
|
||||
|
|
@ -153,7 +158,9 @@ typedef struct {
|
|||
job_failinfo_t* dispatchfail;
|
||||
xce_jobfinish_t* finishinfo;
|
||||
uint64_t sched_start_job;
|
||||
uint64_t sched_exit_job;
|
||||
/* bug-1737: carries exit_code alongside jobid now -- see
|
||||
* controller.capnp's schedExitJob field comment. */
|
||||
xce_jobfinish_t* sched_exit_job;
|
||||
uint64_t sched_fail_job;
|
||||
xce_job_t* sched_update_job;
|
||||
xce_resval_list_t* sched_update_resvals;
|
||||
|
|
@ -279,6 +286,42 @@ typedef struct {
|
|||
uint64_t responder_time_ms; /* @13: responder wall-clock at sample time (epoch ms) */
|
||||
} xce_ctrlstatus_t;
|
||||
|
||||
/* ── Worker rejoin/resync job-state reconciliation (worker-rejoin-resync
|
||||
* task 1.1, Req 2.1/2.2/3.5/3.7/5.3/8.1-8.3) ────────────────────────────
|
||||
* Frame-only wire types for the controller<->worker job-state
|
||||
* reconciliation exchange (OPCode_jobStateQuery/OPCode_jobStateReport) --
|
||||
* same "no live C struct" convention as capnp_host_admin_state_t/
|
||||
* replay_cluster_t above (see controller.capnp's comment at `struct
|
||||
* JobStateEntry`). An enum-typed capnp field (status) maps to a plain
|
||||
* `int` here, not a separate named C enum type -- mirrors the existing
|
||||
* HostRole/JoinData.role and SchedAdminAction/sched_admin_req_t.action
|
||||
* convention (the generated `enum JobStateStatus` in controller.capnp.h
|
||||
* already supplies the JobStateStatus_running/finishedOk/finishedFail/
|
||||
* unrecognized constants for callers that want them). This is schema-only:
|
||||
* the C-side send/receive/encode/decode logic is later tasks (1.4 wire
|
||||
* codec helpers; 6.1/6.2 controller wiring; 4.x worker wiring). */
|
||||
typedef struct {
|
||||
uint64_t jobid;
|
||||
int status; /* JobStateStatus_running/finishedOk/finishedFail/unrecognized */
|
||||
int32_t exit_code;
|
||||
uint64_t finish_time_ms;
|
||||
int queried;
|
||||
} xce_job_state_entry_t;
|
||||
|
||||
typedef struct {
|
||||
int n_total;
|
||||
int pos;
|
||||
int count;
|
||||
uint64_t* jobids;
|
||||
} xce_job_state_query_t;
|
||||
|
||||
typedef struct {
|
||||
int n_total;
|
||||
int pos;
|
||||
int count;
|
||||
xce_job_state_entry_t** entries;
|
||||
} xce_job_state_report_t;
|
||||
|
||||
typedef struct {
|
||||
uint64_t seq;
|
||||
uint32_t opcode;
|
||||
|
|
@ -341,6 +384,8 @@ typedef struct {
|
|||
xce_fetchfile_t* fetchfilemsg;
|
||||
sched_admin_req_t* schedadminmsg;
|
||||
probe_config_tag_req_t* probeconfigtagrequestmsg;
|
||||
xce_job_state_query_t* jobstatequerymsg;
|
||||
xce_job_state_report_t* jobstatereportmsg;
|
||||
} body;
|
||||
} xce_request_t;
|
||||
|
||||
|
|
|
|||
|
|
@ -174,6 +174,7 @@ typedef struct {
|
|||
#define XCE_WORKER_CLOSED (0x00100000)
|
||||
#define XCE_WORKER_HIDDEN (0x00200000) /* Admin explicitly removed — invisible but not yet cleaned up */
|
||||
#define XCE_WORKER_CLOSED_BY_ADMIN (0x00400000) /* Admin closed — host closed explicitly by admin */
|
||||
#define XCE_WORKER_RECONCILING (0x00800000) /* worker-rejoin-resync: job-state reconciliation outstanding for this host (Req 5.1) */
|
||||
|
||||
#define IS_WORKER_UNAVAIL(status) (((status) & XCE_WORKER_UNAVAIL) != 0)
|
||||
#define IS_WORKER_LOCKEDU(status) (((status) & XCE_WORKER_LOCKEDU) != 0)
|
||||
|
|
@ -182,6 +183,7 @@ typedef struct {
|
|||
#define IS_WORKER_LOCKED(status) \
|
||||
(IS_WORKER_LOCKEDU(status) || IS_WORKER_LOCKEDW(status))
|
||||
#define IS_WORKER_BUSY(status) (((status) & XCE_WORKER_BUSY) != 0)
|
||||
#define IS_WORKER_RECONCILING(status) (((status) & XCE_WORKER_RECONCILING) != 0)
|
||||
|
||||
typedef struct {
|
||||
char* hosttype;
|
||||
|
|
@ -281,12 +283,43 @@ typedef struct {
|
|||
double allocated;
|
||||
} xce_res_account_t;
|
||||
|
||||
/* worker-rejoin-resync: per-worker job-state reconciliation round. One
|
||||
* resync_state_t per worker_t (worker_t.resync below), absent (NULL) when
|
||||
* no reconciliation is currently outstanding for that worker. Purely
|
||||
* in-memory bookkeeping, not itself persisted -- see design.md's Data
|
||||
* Models / State Management for the full rationale. */
|
||||
typedef struct {
|
||||
xce_worker_t host;
|
||||
char hostkey[XCE_MAXKEY_LEN];
|
||||
endpoint_t* ep;
|
||||
int idx;
|
||||
zarray_t usages;
|
||||
uint64_t round_token; /* discards stale/superseded reports (Req 6.3) */
|
||||
int n_queried_jobids;
|
||||
uint64_t* queried_jobids; /* set semantics (membership-checked, not
|
||||
* positionally iterated): job IDs queried this
|
||||
* round; array+count, mirroring
|
||||
* xce_job_state_query_t.jobids (typemap.h) */
|
||||
uint64_t deadline; /* CLOCK_MONOTONIC ms deadline (Req 5.3); same
|
||||
* representation as delaymgr_t.nextrun_ms
|
||||
* (delay.h) */
|
||||
} resync_state_t;
|
||||
|
||||
typedef struct {
|
||||
xce_worker_t host;
|
||||
char hostkey[XCE_MAXKEY_LEN];
|
||||
endpoint_t* ep;
|
||||
int idx;
|
||||
zarray_t usages;
|
||||
resync_state_t* resync; /* worker-rejoin-resync: NULL unless a job-state
|
||||
* reconciliation round is currently outstanding
|
||||
* for this worker */
|
||||
/* worker-rejoin-resync task 6.2 (Req 8.1, 8.3): opaque (void*) rather
|
||||
* than a typed pointer here because its real type, resync_report_
|
||||
* accum_t (resync.h), embeds xce_job_state_entry_t -- defined in
|
||||
* typemap.h, which itself includes THIS header (xce/types.h), so
|
||||
* typemap.h cannot be included from here without a cycle. NULL unless
|
||||
* an OPCode_jobStateReport is currently being reassembled across
|
||||
* multiple pages for this worker; owned and cast back to resync_
|
||||
* report_accum_t* exclusively by resync.c, under this worker's own
|
||||
* RTTI lock, mirroring how `resync` above is the only other opaque-
|
||||
* from-here, resync.c-owned worker_t field. */
|
||||
void* report_accum;
|
||||
} worker_t;
|
||||
|
||||
typedef struct {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue