#if !defined(_TYPEMAP_H_) #define _TYPEMAP_H_ 1 #include #include "clusterconfig.h" #include "xce/types.h" /* Forward declarations for config-replication types used in * xce_reply_t and xce_request_t unions below. */ typedef struct repl_config_reply_s repl_config_reply_t; typedef struct repl_config_push_reply_s repl_config_push_reply_t; typedef struct upgrade_config_reply_s upgrade_config_reply_t; typedef struct repl_config_req_s repl_config_req_t; typedef struct repl_config_push_req_s repl_config_push_req_t; typedef struct upgrade_config_req_s upgrade_config_req_t; typedef struct heartbeat_msg_s heartbeat_msg_t; typedef struct ctrl_hello_req_s ctrl_hello_req_t; typedef struct ctrl_hello_reply_s ctrl_hello_reply_t; typedef struct wal_catchup_entry wal_catchup_entry_t; typedef struct snapshot_transfer_s snapshot_transfer_t; typedef struct { char* resname; char* hostname; } xce_reskey_t; typedef struct { int type; union { uint64_t jobid; char* wname; xce_reskey_t* reskey; } condition; } xce_match_t; typedef struct { int table; int nrows; void* rows; } dataset_t; typedef struct { int role; int data_which; union { hostattrs_t* attrs; } data; } xce_joindata_t; typedef struct { char* clustername; int n_confvars; xce_config_t** confvars; int n_resources; xce_resource_t** resources; int n_queues; xce_queue_t** queues; int n_ugroups; xce_group_config_t** ugroups; int n_hgroups; xce_group_config_t** hgroups; int nresvals; xce_name_val_t** resvals; int nlimits; xce_limit_config_t** limits; int nhproviders; scaler_config_t** hproviders; } xce_conf4sched_t; 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 { int data_which; union { xce_conf4sched_t* conf4sched; xce_conf4worker_t* conf4worker; cluster_config_t* clusterconfig; } data; } xce_configdata_t; typedef struct { int n_total; int pos; int count; xce_job_t** jobs; } xce_jobs_data_t; typedef struct { int n_total; int pos; int count; xce_worker_t** workers; } xce_workers_data_t; typedef struct { int n_total; int pos; int count; xce_resource_t** resources; } xce_resource_data_t; typedef struct { int n_total; int pos; int count; xce_resval_t** vals; } xce_resval_data_t; typedef struct { int count; xce_resval_t** vals; } xce_resval_list_t; typedef struct { uint64_t jobid; int npids; int* pids; int npgids; int* pgids; int count; xce_rusage_t** usages; } xce_job_rusages_t; typedef struct { int table; union { xce_jobs_data_t* jobs; xce_workers_data_t* workers; xce_resource_data_t* resources; xce_resval_data_t* resvals; xce_job_submit_t* job_array; /* job-array-single-wal-record 1.2: compact * (base jobid, array size, one spec) push * descriptor -- same JobSubmit shape as the * client submit request and WAL payload. */ } data; } xce_data_t; typedef struct { int table; xce_match_t* condition; } xce_get_t; typedef struct { int event; union { job_pidinfo_t* pidinfo; job_failinfo_t* failinfo; job_failinfo_t* dispatchfail; xce_jobfinish_t* finishinfo; uint64_t sched_start_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; uint64_t stopped_job; uint64_t resumed_job; xce_ckptinfo_t* ckptinfo; xce_queue_t* sched_update_queue; xce_task_pidinfo_t* taskinfo; xce_task_failinfo_t* taskfailinfo; xce_task_finish_t* taskfinish; uint64_t pdone_job; xce_job_rusages_t* sched_job_rusages; xce_job_t* update_job; } data; } xce_notify_data_t; typedef struct { int table; union { xce_resval_list_t* resvals; xce_job_rusages_t* jobrusages; } data; } xce_update_data_t; typedef struct { uint64_t term; char *candidate_id; uint64_t config_tag; uint64_t last_log_lsn; /* Raft (lastLogTerm, lastLogIndex) freshness tuple (ha-term-safety task 1.2): * feeds the library logOk gate, distinct from config_tag/last_log_lsn which * drive the application freshness gate. last_log_index == candidate log_len. */ uint64_t last_log_term; uint64_t last_log_index; } request_vote_req_t; typedef struct { uint64_t term; int vote_granted; uint64_t peer_config_tag; uint64_t peer_last_log_lsn; } request_vote_reply_t; typedef struct { char *name; } probe_config_tag_req_t; typedef struct { uint64_t config_tag; } probe_config_tag_reply_t; /* Heartbeat reply state report — carries standby's applied_lsn and config_tag, * plus its raft term so the primary can discover a higher term it lost track * of (bug-1421 term-discovery: an AE reject response never reaches the raft * library, so a heartbeat-reply term stamp is the fallback path). */ typedef struct { uint64_t applied_lsn; uint64_t config_tag; uint64_t term; } state_report_t; /* WAL apply ACK — sent by standby to primary after applying a WAL catch-up * entry (Task 3.1, ha-wal-replication). Must be declared before xce_reply_t * so the walackreplymsg union arm compiles correctly. */ typedef struct { uint64_t term; uint64_t lsn; int success; } wal_ack_reply_t; /* Scheduler admin opcode request/reply (scheduler-core task 7.4, Req 5 AC 10). * OPCode_schedAdmin: start/stop/query a scheduler-side `.replay` recording * session. No field-level $C.mapname on either capnp struct (per the exact * verbatim schema spec), so -- same convention as xce_ctrlstatus_t below -- * the generated accessors and this mapped struct's field names match the * capnp schema's camelCase names exactly (no snake_case conversion). action * mirrors the existing HostRole/JoinData.role convention: an enum-typed * capnp field maps to a plain `int` here, not a separate named C enum type * (the generated `enum SchedAdminAction` in controller.capnp.h already * supplies the SchedAdminAction_recordStart/recordStop/recordStatus * constants for callers that want them). */ typedef struct { int action; char *recordFile; } sched_admin_req_t; typedef struct { int ok; char *error; int recording; char *file; uint64_t eventCount; uint64_t startedAt; } sched_admin_reply_t; /* ctrlstatus reply payload (controller-status spec): one configured * controller (CtrlPeer) and the lean identity/health snapshot (CtrlStatus). * The peers list maps via $C.mapname("peers.list")/$C.maplistcount("peers.count") * to the nested { count, list } member below. */ typedef struct { char* name; char* host; uint32_t port; uint8_t status; /* @3: 0=unknown 1=ok 2=catching-up 3=dead (Req 13.1) */ } xce_ctrlpeer_t; typedef struct { char* clusterName; char* primaryName; char* responderName; uint8_t responderRole; uint64_t term; uint64_t configVersion; char* configChecksum; uint64_t committedConfigVersion; uint64_t committedLsn; uint64_t appliedLsn; unsigned fenced; struct { int count; xce_ctrlpeer_t** list; } peers; uint32_t peerCount; uint64_t responder_time_ms; /* @13: responder wall-clock at sample time (epoch ms) */ uint64_t elected_at_ms; /* @14: current primary's election time (epoch ms), * learned off-primary via heartbeat; 0 = unknown */ } 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; int32_t status; int data_which; union { char* debugmsg; uint64_t jobid; xce_data_t* getdata; xce_clusterconf_t* clusterconf; repl_config_reply_t* replconfigreplymsg; repl_config_push_reply_t* replconfigpushreplymsg; upgrade_config_reply_t* upgradeconfigreplymsg; ctrl_hello_reply_t* ctrlhelloreplymsg; request_vote_reply_t* requestvotereplymsg; state_report_t* state_report; wal_ack_reply_t* walackreplymsg; xce_ctrlstatus_t* ctrlstatus; xce_fetchfile_reply_t* fetchfilereply; sched_admin_reply_t* schedadminreplymsg; probe_config_tag_reply_t* probeconfigtagreplymsg; } data; /* Req 7: standby redirect fields — populated when status == XCE_ERR_STANDBY */ char *redirect_host; uint16_t redirect_port; } xce_reply_t; typedef struct { uint32_t opcode; uint64_t seq; xce_peerinfo_t* from; int body_which; union { xce_reply_t* replymsg; char* hellomsg; xce_joindata_t* joinmsg; xce_configdata_t* configpushmsg; xce_data_t* pushmsg; xce_get_t* getmsg; dataset_t* datamsg; xce_job_dispatch_t* dispatchmsg; xce_job_exec_t* jobstartmsg; xce_notify_data_t* notifymsg; xce_job_submit_t* jobsubmsg; xce_update_data_t* updatemsg; xce_jobctrl_t* jobctrlmsg; xce_queuectrl_t* queuectrlmsg; xce_taskrun_t* runtaskmsg; xce_preason_set_t* preasonmsg; xce_clear_reason_t* clrpreasonmsg; xce_hostctrl_t* hostctrlmsg; repl_config_req_t* replconfigrequestmsg; repl_config_push_req_t* replconfigpushrequestmsg; upgrade_config_req_t* upgradeconfigrequestmsg; heartbeat_msg_t* heartbeatmsg; ctrl_hello_req_t* ctrlhellomsg; request_vote_req_t* requestvotemsg; wal_catchup_entry_t* walcatchupentrymsg; snapshot_transfer_t* snapshottransfermsg; 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; /* ── HA election and replication Cap'n Proto mapped types ──────────────── * C-side counterparts for the HA protocol capnp structs added in the * ha-config-bootstrap spec (controller.capnp structs with $C.mapname). * Must be declared here so controller.capnp.h can reference them. * request_vote_req_t and request_vote_reply_t are defined above * xce_reply_t so they can be used in the xce_request_t body union. */ typedef struct { uint64_t term; uint64_t lsn; } wal_ack_req_t; typedef struct { uint64_t term; uint64_t acked_tag; int success; } upgrade_config_ack_t; struct snapshot_transfer_s { uint64_t snapshot_lsn; /* checkpoint LSN this snapshot corresponds to */ xce_data_t *payload; /* legacy decoded field — broken for raw bytes * (decode_Data_ptr misinterprets List(UInt8)); * kept NULL on send, do not use */ uint32_t chunk_index; /* 0-based chunk number */ uint64_t chunk_offset; /* byte offset in the full snapshot */ uint64_t total_size; /* total snapshot size in bytes */ int is_last; /* true (non-zero) for the final chunk */ /* Raw chunk bytes — same pattern as repl_config_push_req_t. * Send side: filled by the sender, encoded by xce_snapshot_chunk_req_raw. * Receive side: extracted by xce_decode() before capn_free(); malloc'd, * owned by the struct, freed by xce_free_request(). */ uint8_t *raw_payload; size_t raw_payload_len; /* raft-ha-core-safety task 3.2 (Req 3.1/5.1): the leader's term for the * checkpoint LSN above. 0 = unset (legacy sender) -> receiver treats as * WAL_LEGACY_TERM, same convention as persist's existing legacy-0 term * mapping (see entry_term_locked in persist.c). */ uint64_t checkpoint_term; }; struct wal_catchup_entry { uint64_t lsn; uint8_t entry_type; /* bug-1505 fix: List(UInt8) now, not Data (see controller.capnp's * WalCatchupEntry.payload comment for the full root cause) — a real * uint8_t* + wire_payload_len pair via the generic codec, same shape * bytes_read/content already establish elsewhere. Still legacy/unused * by production (wal_entry_to_wire() in request.c deliberately never * sets it — see that comment); this genuinely round-trips now instead * of being a documented-broken placeholder, but nothing reads it. */ uint8_t *payload; int n_entries; /* batch: number of sub-entries */ struct wal_catchup_entry **entries; /* batch: array of sub-entry pointers */ /* Raw WAL entry payload bytes — same pattern as repl_config_push_req_t. * Send side: filled from the WAL segment file, encoded per sub-entry by * xce_wal_batch_req_raw. Receive side: extracted by xce_decode() before * capn_free(); malloc'd, owned, freed by xce_free_request(). */ uint8_t *raw_payload; size_t raw_payload_len; /* Raft AppendEntries term fields (ha-term-safety task 1.1, Req 1.3/1.4). * term == this entry's term stamp; prev_log_index == lsn-1; prev_log_term == * term of the entry at prev_log_index (0 if absent). Consumed by the log * callbacks (tasks 2.x) for the AppendEntries logOk / truncation decision. */ uint64_t term; uint64_t prev_log_index; uint64_t prev_log_term; /* ha-term-safety task 3.2 (Req 2.5/4.1): the leader's commit index carried on * the AppendEntries so the standby intake passes it into * raft_on_append_entries_request. Wire field leaderCommit @7. */ uint64_t leader_commit; /* bug-1067: the streaming leader's CURRENT term — the Raft AppendEntries * HEADER term, DISTINCT from `term` above (the entry's STORED term). Equal for * a live append; for a HISTORICAL catch-up entry the stored term is lower than * the leader's current term. The standby intake uses this as the AE header * term (UpdateTerm/stale-check) so cross-term catch-up is not stale-rejected; * 0 = unset (legacy sender) → fall back to the stored term. Wire field * leaderCurrentTerm @8. */ uint64_t leader_current_term; /* bug-847: this sub-entry's payload length, carried as a plain scalar (wire * field wirePayloadLen @9) so it decodes via the generic generated decode * exactly like lsn/entry_type/term — never subject to the per-element Data * cross-segment loss. Set by the encoder for every xce_wal_batch_encode_raw * send; used on decode to slice this entry's bytes out of the TOP-LEVEL * container's batch_payloads blob (below). */ uint32_t wire_payload_len; /* bug-1505 fix: List(UInt8) now, not Data (controller.capnp's * WalCatchupEntry.batchPayloads comment has the full root cause — * same class as `payload` above and SnapshotData.internalState, * bug-1504). Generic decoded field for wire field batchPayloads @10; * genuinely round-trips now via the generic codec, but still unused by * production — the real bytes are hand-extracted by xce_decode() into * raw_batch_payloads/raw_batch_payloads_len below (a separate, * already-correct code path this fix does not touch), then sliced per * sub-entry using each entry's wire_payload_len into that entry's OWN * raw_payload/raw_payload_len (so every consumer keeps reading * raw_payload exactly as before). Only meaningful on the TOP-LEVEL * container (never on a nested sub-entry). batch_payloads_wire_len is * its own maplistcount companion (wire field batchPayloadsLen @11) — * distinct from raw_batch_payloads_len below, which belongs to the * separate hand-rolled extraction path. */ uint8_t *batch_payloads; uint32_t batch_payloads_wire_len; uint8_t *raw_batch_payloads; size_t raw_batch_payloads_len; }; /* ── Persistence Cap'n Proto mapped types (P0-9) ───────────────────── * These are the C-side counterparts for the capnp encode/decode shims. * Named with capnp_ prefix to avoid collision with the plain-C structs * in persist.h (persist_config_t) and the on-disk binary formats. */ typedef struct { uint32_t walSyncMs; uint32_t snapIntervalS; uint32_t snapWalSizeMb; uint32_t finishedRetainS; uint32_t workerRetainS; uint32_t syncTimeoutMs; uint32_t snapKeepN; uint32_t transientJobTimeoutS; } capnp_persist_cfg_t; typedef struct { uint64_t lsn; uint64_t term; uint64_t timestamp; uint32_t version; uint32_t nJobs; uint32_t nQueues; uint32_t nWorkers; uint32_t checksum; uint32_t headerChecksum; } capnp_snap_hdr_t; typedef struct { uint64_t term; uint64_t lsn; uint32_t entryType; xce_data_t* payload; /* owned; decoded via decode_Data_ptr */ uint32_t crc; uint32_t prevCrc; } capnp_repl_envelope_t; /* ── Upgrade snapshot admin-state frames (config-upgrade-snapshot task 1, * Req 1.9/5.7) ─────────────────────────────────────────────────────────── * Frame-only wire types for the checkpoint's host/queue admin-state * sections -- carry only the administratively-set (name, status) pair, * never the full xce_worker_t/xce_queue_t (design.md Design Invariant 5: a * snapshot frame must never inherit a live struct's dynamic fields just * because reusing it is convenient). Neither has a corresponding "live" C * struct, so each gets its own frame-only counterpart here, same as * capnp_snap_hdr_t/capnp_persist_cfg_t/capnp_repl_envelope_t above. */ typedef struct { char* name; uint32_t status; } capnp_host_admin_state_t; typedef struct { char* name; uint32_t status; } capnp_queue_admin_state_t; /* ── Config replication Cap'n Proto mapped types (Phase 1) ────────────── * C-side counterparts for the capnp encode/decode shims for config sync. * Struct tags match the forward declarations near the top of this file. */ struct repl_config_req_s { uint64_t version_tag; /* local config version tag */ }; struct repl_config_reply_s { int up_to_date; /* 1 if standby is current */ uint64_t version_tag; /* primary's current version tag */ xce_data_t *sha256; /* 32-byte SHA-256 of config blob (may be NULL) */ xce_data_t *bytes; /* serialised ClusterConfig blob (may be NULL) */ }; struct repl_config_push_req_s { uint64_t version_tag; /* version tag of the pushed config */ xce_data_t *sha256; /* 32-byte SHA-256 (decoded, not usable as raw bytes) */ xce_data_t *bytes; /* serialised ClusterConfig blob (decoded, not usable) */ /* Pre-extracted raw fields populated by xce_decode() before capn_free(), * mirroring the same pattern as upgrade_config_req_t. Owned by the struct. */ uint8_t *raw_sha256; /* 32-byte SHA-256, malloc'd, or NULL */ uint8_t *raw_bytes; /* serialised ClusterConfig blob, malloc'd, or NULL */ size_t raw_bytes_len; /* length of raw_bytes */ }; struct repl_config_push_reply_s { int accepted; /* 1 if standby accepted the push */ uint64_t version_tag; /* standby's current version tag after decision */ uint64_t term; /* replying member's current term (raft-adapter- * conformance Req 7.4 term-discovery channel) */ }; struct upgrade_config_req_s { /* Legacy decoded fields — populated by generated decode_UpgradeConfigRequest() * via decode_Data_ptr. These are structurally broken for List(UInt8) wire * fields (decode_Data_ptr reads a discriminant and misinterprets the bytes), * but must remain for the generated code to compile. Do NOT use these for * actual byte extraction. */ xce_data_t *sha256; /* broken: always a bogus xce_jobs_data_t */ xce_data_t *bytes; /* broken: always a bogus xce_jobs_data_t */ /* Correct raw bytes extracted by xce_decode() before capn_free() runs, * using UpgradeConfigRequest_get_sha256/bytes + capn_getv8. * Both are malloc'd and owned here; freed by free_upgrade_config_req_raw() * called from free_Request() after free_UpgradeConfigRequest(). * raw_sha256 is exactly 32 bytes when non-NULL. */ uint8_t *raw_sha256; /* 32-byte SHA-256, malloc'd, or NULL */ uint8_t *raw_bytes; /* serialised ClusterConfig blob, malloc'd, or NULL */ size_t raw_bytes_len; /* length of raw_bytes */ }; struct upgrade_config_reply_s { uint64_t version_tag; /* new version tag after upgrade */ char *error; /* NULL on success; error message on failure */ uint32_t acked_count; /* number of standbys that acknowledged */ }; struct heartbeat_msg_s { uint32_t sender_priority; /* sender's HA priority */ uint64_t term; /* sender's current term */ uint64_t committed_lsn; /* Req 5: primary's committed WAL LSN */ uint64_t committed_config_tag; /* Req 8: primary's committed config tag */ uint64_t elected_at_ms; /* Req 12.2: primary's own last_known_elected_at_ms, * echoed on every heartbeat */ }; /* CtrlHello state sync (Req 6.5, 6.6, 6.7) */ struct ctrl_hello_req_s { char *name; /* standby's logical name */ uint8_t *key; /* SHA-256(cluster_name + shared_secret) auth key, * malloc'd, or NULL; wire type is List(UInt8), * not Data (see controller.capnp's own comment) */ uint64_t applied_lsn; /* standby's last applied WAL LSN */ uint64_t config_tag; /* standby's current config tag */ uint32_t key_len; /* length of key */ }; struct ctrl_hello_reply_s { uint64_t committed_lsn; /* primary's committed WAL LSN */ int needs_snapshot; /* 1 if standby LSN < oldest WAL segment */ uint64_t config_tag; /* primary's current config tag */ }; /* ── Replay stream envelope frames (scheduler-core Group 7 task 7.1, * Req 5 AC 20) ────────────────────────────────────────────────────────── * Frame-only wire types for the `.replay` stream envelope -- same "no live * C struct" convention as capnp_snap_hdr_t/capnp_persist_cfg_t/ * capnp_host_admin_state_t above (see controller.capnp's comment at * `struct ReplayCluster` for the full Group 7 task split). The C-side * reader/writer that actually populates/consumes these (recording, * `.replay` file I/O) is task 9+, out of this schema-only task's scope. */ typedef struct { char *name; char **controllers; int n_controllers; char *recording_host; } replay_cluster_t; typedef struct { char *recorder_version; /* configHash is a Data field -- the generated encode_/decode_ codec is * a documented no-op for Data fields in this codebase's capnpc-c setup * (same limitation as e.g. upgrade_config_req_s.sha256/bytes above); * real byte extraction is task 9+ hand-written code, same raw_sha256- * style pattern used throughout this file. This pointer/len pair exists * only so the mapname target type is well-formed; nothing here reads it * yet. */ uint8_t *config_hash; size_t config_hash_len; replay_cluster_t *cluster; uint64_t recording_start_ts; char *recording_start_wall; char *sched_policy; } replay_header_t; /* task 7.3 (Req 5 AC 21): SchedUser/SchedProject mirror controller.capnp's * SchedUser/SchedProject structs. Field lists match xce_sched_user_t/ * xce_sched_project_t (src/scheduler/include/sched/types.h) exactly -- name * only, name+priority respectively -- but these are FRESH, wire-only C * types under different names, NOT aliases of the scheduler-internal ones. * See controller.capnp's comment at `struct SchedUser` for the full * rationale: sched/types.h is scheduler-private and already `#include`s * this file, so a duplicate `xce_sched_user_t`/`xce_sched_project_t` * typedef here would break every scheduler .c file that includes both * headers (confirmed: core_events.c, schedobj.c already do). */ typedef struct { char *name; } sched_snapshot_user_t; typedef struct { char *name; int32_t priority; } sched_snapshot_project_t; /* task 7.3 (Req 5 AC 21): the full snapshot struct, replacing the task 7.1 * placeholder wholesale. Every domain-object pointer reuses a pre-existing * native type (already used natively throughout the scheduler/controller) * except users/projects (sched_snapshot_user_t/sched_snapshot_project_t * above) and the two scheduler-internal-only opaque fields. internal_version * is a format tag for internal_state so an incompatible future internal * layout is rejected rather than misinterpreted (this task's Observable). * * internal_state/internal_state_len map controller.capnp's internalState, * a List(UInt8) (task 12.1 review finding, fixed -- was Data, whose * generated codec is a silent no-op in this codebase's capnpc-c setup and * left a genuinely uninitialized capn_ptr on the wire, a real reproducible * crash; see controller.capnp's SnapshotData comment for the full story). * List(UInt8)'s generated encode_/decode_ actually runs (proven precedent: * xce_fetchfile_reply_t.content/bytes_read below), so internal_state_len * must be uint32_t to match internalStateLen's UInt32 wire type -- same * maplistcount convention as content/bytes_read. */ typedef struct { xce_conf4sched_t *config; xce_jobs_data_t *jobs; xce_queue_t **queues; int n_queues; xce_workers_data_t *workers; xce_resource_data_t *resources; xce_resval_list_t *resvals; sched_snapshot_user_t **users; int n_users; sched_snapshot_project_t **projects; int n_projects; uint64_t prng_seed; uint8_t *internal_state; uint32_t internal_state_len; uint32_t internal_version; } sched_snapshot_data_t; typedef struct { uint64_t ts; sched_snapshot_data_t *data; } replay_snapshot_entry_t; /* task 7.2 (Req 5 AC 20): the two genuinely new event payload types -- every * other replay_event_t.body variant above reuses a pre-existing wire type * (see controller.capnp's comment at `struct JobStateChangeEvent`). */ typedef struct { uint64_t jobid; uint32_t old_state; uint32_t new_state; int32_t exit_code; } job_state_change_event_t; typedef struct { uint64_t jobid; /* changedFields is a UInt32 bitmask (JOB_F_PRIORITY, JOB_F_QUEUE, * JOB_F_RESREQ per design.md) -- no JOB_F_* constants exist anywhere in * the codebase yet (task 5.1's grep); concrete bit assignments are * task 9+ event-translation/recording code's job, not this schema-only * task's. */ uint32_t changed_fields; xce_job_t *job; /* full updated record -- reuses xce_job_t (Job in * controller.capnp) */ } job_update_event_t; typedef struct { uint64_t ts; int body_which; union { xce_conf4sched_t *config_push; xce_jobs_data_t *jobs_push; xce_workers_data_t *workers_push; xce_resource_data_t *resources_push; xce_resval_list_t *resvals_full; xce_resval_list_t *resvals_delta; xce_queue_t *queue_update; xce_job_rusages_t *job_rusage; /* endSession: Void, no storage */ job_state_change_event_t *job_state_change; job_update_event_t *job_update; } body; } replay_event_t; typedef struct { uint64_t duration_ns; uint32_t n_decisions; uint32_t n_dispatched; uint32_t n_pended; } session_summary_t; /* task 7.3 (Req 5 AC 5, AC 20): the three decision payload types -- * dispatch/pend reuse existing native types (xce_job_alloc_t, * xce_job_preason_t); preempt_victim_t/sched_preempt_decision_t are fresh, * wire-only types, deliberately distinct from decision.h's core-internal * xce_preempt_victim_t/xce_preempt_t (task 4.4's in-process live-decision * representation) -- see controller.capnp's matching comment. */ typedef struct { xce_job_alloc_t *alloc; } sched_dispatch_decision_t; typedef struct { uint64_t jobid; xce_job_preason_t *reason; } sched_pend_decision_t; typedef struct { uint64_t jobid; char *workerid; } preempt_victim_t; typedef struct { uint64_t jobid; preempt_victim_t **victims; int n_victims; xce_job_preason_t *reason; } sched_preempt_decision_t; typedef struct { uint64_t ts; int body_which; union { sched_dispatch_decision_t *dispatch; sched_pend_decision_t *pend; sched_preempt_decision_t *preempt; } body; } replay_decision_t; typedef struct { uint64_t begin_round; replay_decision_t **decisions; int n_decisions; session_summary_t *summary; } replay_session_t; #endif