myxce/src/schema/controller.capnp
Rongsong Shen a88c5fbf21 feat(raft-adapter-conformance): add term field to ReplConfigPushReply schema
Additive term @2 field on ReplConfigPushReply so a configuration-push
reply can carry the replying member's current term for term-discovery
(Requirement 7.4). Companion repl_config_push_reply_t struct field
added in typemap.h per the existing $C.mapname convention.
2026-07-29 09:09:56 +00:00

979 lines
38 KiB
Cap'n Proto
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

@0xdefcdf6377db2e8e;
using C = import "/c.capnp";
$C.fieldgetset;
$C.codecgen;
$C.extraheader("#include \"clusterconfig.h\"");
$C.extraheader("#include \"typemap.h\"");
enum OPCode {
nop @0;
reply @1;
hello @2;
join @3;
shutdown @4;
get @5;
push @6;
update @7;
jobdispatch @8;
startjob @9;
notify @10;
jobsub @11;
jobstatus @12;
jobrusage @13;
hostcontrol @14;
jobcontrol @15;
newschedjobs @16;
clusterconf @17;
queuecontrol @18;
runtasks @19;
setpreason @20;
clrpreason @21;
replEntry @22;
replAck @23;
redirect @24;
heartbeat @25;
steppingDown @26;
replSnapshot @27;
replCatchUpDone @28;
replConfig @29;
replConfigPush @30;
upgradeConfig @31;
requestVote @32;
probeConfigTag @33;
walAck @34;
upgradeConfigAck @35;
snapshotTransfer @36;
walCatchupEntry @37;
preVoteRequest @38;
preVoteReply @39;
ctrlstatus @40;
fetchfile @41;
}
struct PeerInfo $C.mapname("xce_peerinfo_t") {
host @0: Text $C.mapname("name");
key @1: Text;
}
struct HostBasedReason $C.mapname("xce_host_reason_t") {
host @0: Text;
reason @1: UInt32;
}
struct ResourceBasedReason $C.mapname("xce_res_reason_t") {
resource @0: Text;
host @1: Text;
reason @2: UInt32;
}
struct JobPendReason $C.mapname("xce_job_preason_t") {
mainReason @0: UInt32 $C.mapname("main_reason");
hostReasons @1: List(HostBasedReason) $C.mapname("host_based_reasons") $C.maplistcount("nhost_reasons");
resReasons @2: List(ResourceBasedReason) $C.mapname("res_based_reasons") $C.maplistcount("nres_reasons");
}
struct StrList $C.mapname("xce_strlist_t") {
data @0: List(Text) $C.mapname("data") $C.maplistcount("count");
}
struct TimeWindowTime $C.mapname("xce_timewindow_time_t") {
day @0: UInt32 $C.mapname("day");
hour @1: UInt32 $C.mapname("hour");
min @2: UInt32 $C.mapname("min");
}
struct TimeWindowSeg $C.mapname("xce_timewindow_seg_config_t") {
timezone @0: Text $C.mapname("tz");
open @1: TimeWindowTime $C.mapname("open");
close @2: TimeWindowTime $C.mapname("close");
}
struct TimeWindow $C.mapname("xce_timewindow_config_t") {
segs @0: List(TimeWindowSeg) $C.mapname("segs") $C.maplistcount("nsegs");
}
struct GroupConfig $C.mapname("xce_group_config_t") {
name @0: Text $C.mapname("name");
members @1: List(Text) $C.mapname("members.data") $C.maplistcount("members.count");
exmembers @2: List(Text) $C.mapname("ex_members.data") $C.maplistcount("ex_members.count");
}
# This data structure will not be transfer in wire
# directly, it will be assembled by multiple Data packet
struct Dataset $C.mapname("dataset_t") {
table @0: UInt32;
nrows @1: UInt32;
rows @2: Void; # do NOT change this, it's place holder
}
struct ResKey $C.mapname("xce_reskey_t") {
resname @0: Text;
hostname @1: Text;
}
struct MatchCondition $C.mapname("xce_match_t") {
condition :union $C.mapuniontag("type") {
matchall @0: Void;
matchjid @1: UInt64 $C.mapname("jobid");
matchwname @2: Text $C.mapname("wname");
matchreskey @3: ResKey $C.mapname("reskey");
}
}
struct HostAttrs $C.mapname("hostattrs_t") {
type @0: Text $C.mapname("hosttype");
model @1: Text $C.mapname("hostmodel");
cpufactor @2: Float64;
maxcpus @3: Int32;
maxmem @4: Float64;
maxswap @5: Float64;
maxtmp @6: Float64;
ndisks @7: Int32;
}
struct Worker $C.mapname("xce_worker_t"){
name @0: Text;
attrs @1: HostAttrs;
status @2: UInt32;
dispatchWindow @3: TimeWindow $C.mapname("dispatch_window_config");
thresholds @4: List(Threshold) $C.mapname("thresholds") $C.maplistcount("nthresholds");
resvals @5: List(NameValue) $C.mapname("resvals_to_sched") $C.maplistcount("nresvals_to_sched");
deadSince @6: UInt64 = 0 $C.mapname("dead_since"); # epoch seconds; set when worker becomes UNAVAILABLE
}
enum HostRole {
client @0;
worker @1;
scheduler @2;
controller @3;
apiserver @4;
}
struct JoinData $C.mapname("xce_joindata_t") {
role @0: HostRole;
data :union {
nodata @1: Void;
attrs @2: HostAttrs;
}
}
struct Value $C.mapname("xce_val_t"){
u :union $C.mapuniontag("which") {
ivalue32 @0: Int32;
uvalue32 @1: UInt32;
ivalue64 @2: Int64;
uvalue64 @3: UInt64;
svalue @4: Text;
fvalue @5: Float64;
bvalue @6: Bool;
}
}
struct LimitValue $C.mapname("xce_limit_val_t") {
resname @0: Text $C.mapname("resname");
percentage @1: Bool $C.mapname("percent");
value @2: Float64 $C.mapname("val");
}
struct ValueWithIdx $C.mapname("xce_val_with_idx_t") {
idx @0: UInt32;
val @1: Value $C.mapname("val");
}
struct NameValue $C.mapname("xce_name_val_t") {
name @0: Text $C.mapname("name");
val @1: Value $C.mapname("val");
}
struct ConfigVar $C.mapname("xce_config_t") {
name @0: Text;
value @1: Text;
}
struct ResourceDistribution $C.mapname("res_distribution_t") {
value @0: Value;
hosts @1: List(Text) $C.maplistcount("nhosts");
}
struct Resource $C.mapname("xce_resource_t"){
name @0: Text;
desc @1: Text;
idx @2: Int32;
valtype @3: Int32;
ordtype @4: Int32;
flags @5: Int32;
interval @6: Int32;
lastReport @7: UInt64 $C.mapname("last_report");
# distributions @8: List(ResourceDistribution) $C.maplistcount("ndistributions");
# hostBased @9: Value $C.mapname("hbased_defined");
}
struct Threshold $C.mapname("xce_res_threshold_t"){
name @0: Text;
sched @1: Float64;
stop @2: Float64;
}
struct QueueConf $C.mapname("xce_queue_t") {
name @0: Text $C.mapname("queue");
attrs @1: UInt32;
status @2: UInt32;
priority @3: Int32;
acceptIntervals @4: Int32 $C.mapname("accept_interval");
schedDelay @5: Int32 $C.mapname("sched_delay");
resreq @6: Text;
users @7: GroupConfig $C.mapname("users");
hosts @8: GroupConfig $C.mapname("hosts");
thresholds @9: List(Threshold) $C.maplistcount("nthresholds");
preExec @10: Text $C.mapname("pre_exec");
postExec @11: Text $C.mapname("post_exec");
runWindow @12: TimeWindow $C.mapname("runwindow_config");
dispatchWindow @13: TimeWindow $C.mapname("dispatchwindow_config");
}
struct Conf4Sched $C.mapname("xce_conf4sched_t"){
clustername @0: Text;
configvars @1: List(ConfigVar) $C.mapname("confvars") $C.maplistcount("n_confvars");
resources @2: List(Resource) $C.maplistcount("n_resources");
queues @3: List(QueueConf) $C.maplistcount("n_queues");
ugroups @4: List(GroupConfig) $C.maplistcount("n_ugroups");
hgroups @5: List(GroupConfig) $C.maplistcount("n_hgroups");
resvals @6: List(NameValue) $C.mapname("resvals") $C.maplistcount("nresvals");
hproviders @7: List(ScalerConfig) $C.mapname("hproviders") $C.maplistcount("nhproviders");
limits @8: List(LimitConfig) $C.mapname("limits") $C.maplistcount("nlimits");
}
struct Conf4Worker $C.mapname("xce_conf4worker_t") {
clustername @0: Text;
configvars @1: List(ConfigVar) $C.mapname("confvars") $C.maplistcount("n_confvars");
}
struct ConfigData $C.mapname("xce_configdata_t") {
data :union $C.mapuniontag("data_which") {
schedconfig @0: Conf4Sched $C.mapname("conf4sched");
workerconfig @1: Conf4Worker $C.mapname("conf4worker");
clusterconfig @2: ClusterConfig $C.mapname("clusterconfig");
}
}
struct JobPIDInfo $C.mapname("job_pidinfo_t"){
jobId @0: UInt64 $C.mapname("jobid");
pids @1: List(UInt32) $C.mapname("pids") $C.maplistcount("npids");
pgids @2: List(UInt32) $C.mapname("pgids") $C.maplistcount("npgids");
exdata @3: Text $C.mapname("exdata");
}
struct JobFail $C.mapname("job_failinfo_t"){
jobId @0: UInt64 $C.mapname("jobid");
code @1: Int32 $C.mapname("code");
desc @2: Text $C.mapname("detail");
stage @3: UInt32 $C.mapname("stage");
}
struct JobStartInfo $C.mapname("job_startinfo_t"){
exechome @0: Text;
execcwd @1: Text;
execuser @2: Text;
cmdline @3: Text;
exdata @4: Text;
launchtype @5: Text $C.mapname("launch_type");
qPreExec @6: Text $C.mapname("q_pre_exec");
qPostExec @7: Text $C.mapname("q_post_exec");
preExec @8: Text $C.mapname("job_pre_exec");
postExec @9: Text $C.mapname("job_post_exec");
}
struct Job $C.mapname("xce_job_t"){
jobid @0: UInt64;
submitData @1: JobSubmitData $C.mapname("submit");
subtime @2: UInt64 $C.mapname("sub_time");
queuetime @3: UInt64 $C.mapname("queue_time");
starttime @4: UInt64 $C.mapname("start_time");
finishtime @5: UInt64 $C.mapname("finish_time");
state @6: UInt32;
allocs @7: JobAlloc $C.mapname("allocs");
runtime @8: UInt32 $C.mapname("run_time");
pidinfo @9: JobPIDInfo;
pendreason @10: JobPendReason $C.mapname("pend_reasons");
transientSince @11: UInt64 = 0 $C.mapname("transient_since"); # epoch seconds; set when job enters JOB_STAT_TRANSIENT
}
struct SchedJob $C.mapname("xce_job_t"){
jobid @0: UInt64;
submitData @1: JobSubmitData $C.mapname("submit");
subtime @2: UInt64 $C.mapname("sub_time");
queuetime @3: UInt64 $C.mapname("queue_time");
starttime @4: UInt64 $C.mapname("start_time");
finishtime @5: UInt64 $C.mapname("finish_time");
state @6: UInt32;
allocs @7: JobAlloc $C.mapname("allocs");
runtime @8: UInt32 $C.mapname("run_time");
}
struct SchedJobRusages $C.mapname("xce_job_rusages_t") {
jobid @0: UInt64 $C.mapname("jobid");
usages @1: List(ResUsage) $C.mapname("usages") $C.maplistcount("count");
}
struct JobData $C.mapname("xce_jobs_data_t") {
ntotal @0: UInt32 $C.mapname("n_total");
pos @1: UInt32;
jobs @2: List(Job) $C.maplistcount("count");
}
struct SchedJobData $C.mapname("xce_jobs_data_t") {
ntotal @0: UInt32 $C.mapname("n_total");
pos @1: UInt32;
jobs @2: List(SchedJob) $C.maplistcount("count");
}
struct WorkerData $C.mapname("xce_workers_data_t"){
ntotal @0: UInt32 $C.mapname("n_total");
pos @1: UInt32;
workers @2: List(Worker) $C.maplistcount("count");
}
struct ResourceData $C.mapname("xce_resource_data_t") {
ntotal @0: UInt32 $C.mapname("n_total");
pos @1: UInt32;
resources @2: List(Resource) $C.maplistcount("count");
}
struct ResourceVal $C.mapname("xce_resval_t") {
name @0: Text $C.mapname("name");
host @1: Text $C.mapname("host");
val @2: Value $C.mapname("val");
}
struct ResourceVals $C.mapname("xce_resval_data_t") {
ntotal @0: UInt32 $C.mapname("n_total");
pos @1: UInt32;
vals @2: List(ResourceVal) $C.mapname("vals") $C.maplistcount("count");
}
struct XceData $C.mapname("xce_data_t"){
data :union $C.mapuniontag("table") {
schedjobs @0: SchedJobData $C.mapname("jobs");
schedworkers @1: WorkerData $C.mapname("workers");
jobs @2: JobData $C.mapname("jobs");
workers @3: WorkerData $C.mapname("workers");
resources @4: ResourceData $C.mapname("resources");
resvals @5: ResourceVals $C.mapname("resvals");
jobArray @6: JobSubmit $C.mapname("job_array");
}
}
struct Get $C.mapname("xce_get_t") {
table @0: UInt32;
condition @1: MatchCondition;
}
struct ResValList $C.mapname("xce_resval_list_t") {
vals @0: List(ResourceVal) $C.mapname("vals") $C.maplistcount("count");
}
struct ResUsage $C.mapname("xce_rusage_t") {
name @0: Text $C.mapname("resname");
value @1: Float64 $C.mapname("value");
}
struct JobRusages $C.mapname("xce_job_rusages_t") {
jobid @0: UInt64 $C.mapname("jobid");
pids @1: List(Int32) $C.mapname("pids") $C.maplistcount("npids");
pgids @2: List(Int32) $C.mapname("pgids") $C.maplistcount("npgids");
usages @3: List(ResUsage) $C.mapname("usages") $C.maplistcount("count");
}
struct Update $C.mapname("xce_update_data_t") {
data :union $C.mapuniontag("table") {
nodata @0: Void;
resvals @1: ResValList $C.mapname("resvals");
jobrusages @2: JobRusages $C.mapname("jobrusages");
}
}
struct ResAlloc $C.mapname("xce_alloc_t"){
name @0: Text $C.mapname("resname");
resvId @1: Text $C.mapname("reserve");
instid @2: UInt64;
value @3: Float64;
from @4: UInt64; # alloc start time
duration @5: Int64;
}
struct HostAlloc $C.mapname("xce_host_alloc_t"){
host @0: Text;
allocs @1: List(ResAlloc) $C.mapname("allocs") $C.maplistcount("nallocs");
}
struct JobAlloc $C.mapname("xce_job_alloc_t"){
jobid @0: UInt64;
allocs @1: List(HostAlloc) $C.mapname("allocs") $C.maplistcount("nhosts");
allocsShared @2: List(ResAlloc) $C.mapname("allocs_shared") $C.maplistcount("nres_shared");
}
struct JobDispatch $C.mapname("xce_job_dispatch_t"){
allocs @0: List(JobAlloc) $C.maplistcount("njobs");
}
struct HostLaunch $C.mapname("xce_host_launch_t") {
host @0: Text $C.mapname("host");
nranks @1: UInt32 $C.mapname("nranks");
}
struct JobLaunch $C.mapname("xce_launch_t") {
hosts @0: List(HostLaunch) $C.mapname("hosts") $C.maplistcount("nhosts");
}
struct JobExecInfo $C.mapname("xce_job_exec_t"){
jobid @0: UInt64;
startinfo @1: JobStartInfo $C.mapname("start_info");
launchinfo @2: JobLaunch $C.mapname("launchinfo");
}
struct JobFinishInfo $C.mapname("xce_jobfinish_t") {
jobid @0: UInt64;
code @1: Int32 $C.mapname("exit_code");
}
struct TaskPidInfo $C.mapname("xce_task_pidinfo_t") {
jobid @0: UInt64 $C.mapname("jobid");
host @1: Text $C.mapname("host");
taskidx @2: Int32 $C.mapname("taskidx");
pids @3: List(UInt32) $C.mapname("pids") $C.maplistcount("npids");
pgids @4: List(UInt32) $C.mapname("pgids") $C.maplistcount("npgids");
exdata @5: Text $C.mapname("exdata");
clientidx @6: UInt32 $C.mapname("clientidx");
}
struct TaskFailInfo $C.mapname("xce_task_failinfo_t") {
jobid @0: UInt64 $C.mapname("jobid");
host @1: Text $C.mapname("host");
taskidx @2: Int32 $C.mapname("taskidx");
code @3: Int32 $C.mapname("code");
detail @4: Text $C.mapname("detail");
clientidx @5: Int32 $C.mapname("clientidx");
}
struct TaskFinish $C.mapname("xce_task_finish_t") {
jobid @0: UInt64 $C.mapname("jobid");
host @1: Text $C.mapname("host");
taskidx @2: UInt32 $C.mapname("taskidx");
exitcode @3: Int32 $C.mapname("exit_code");
clientidx @4: Int32 $C.mapname("clientidx");
}
struct NotifyData $C.mapname("xce_notify_data_t"){
data :union $C.mapuniontag("event") $C.mapname("data"){
jobPidInfo @0: JobPIDInfo $C.mapname("pidinfo");
jobFailInfo @1: JobFail $C.mapname("failinfo");
jobDispatchFail @2: JobFail $C.mapname("dispatchfail");
jobFinishInfo @3: JobFinishInfo $C.mapname("finishinfo");
schedStartJob @4: UInt64 $C.mapname("sched_start_job");
schedExitJob @5: UInt64 $C.mapname("sched_exit_job");
schedFailJob @6: UInt64 $C.mapname("sched_fail_job");
schedUpdateJob @7: SchedJob $C.mapname("sched_update_job");
schedUpdateResvals @8: ResValList $C.mapname("sched_update_resvals");
stoppedJob @9: UInt64 $C.mapname("stopped_job");
resumedJob @10: UInt64 $C.mapname("resumed_job");
ckptinfo @11: CheckpointInfo $C.mapname("ckptinfo");
schedUpdateQueue @12: QueueConf $C.mapname("sched_update_queue");
taskPidInfo @13: TaskPidInfo $C.mapname("taskinfo");
taskFailInfo @14: TaskFailInfo $C.mapname("taskfailinfo");
taskFinish @15: TaskFinish $C.mapname("taskfinish");
postDoneJob @16: UInt64 $C.mapname("pdone_job");
schedJobRusages @17: SchedJobRusages $C.mapname("sched_job_rusages");
updateJob @18: Job $C.mapname("update_job");
}
}
struct CtrlPeer $C.mapname("xce_ctrlpeer_t") {
name @0: Text;
host @1: Text;
port @2: UInt32;
}
struct CtrlStatus $C.mapname("xce_ctrlstatus_t") {
clusterName @0: Text;
primaryName @1: Text;
responderName @2: Text;
responderRole @3: UInt8;
term @4: UInt64;
configVersion @5: UInt64;
configChecksum @6: Text;
committedConfigVersion @7: UInt64;
committedLsn @8: UInt64;
appliedLsn @9: UInt64;
fenced @10: Bool;
peers @11: List(CtrlPeer) $C.mapname("peers.list") $C.maplistcount("peers.count");
peerCount @12: UInt32;
responderTimeMs @13: UInt64 $C.mapname("responder_time_ms"); # responder's wall-clock at sample time (epoch milliseconds)
}
struct ClusterConf $C.mapname("xce_clusterconf_t") {
name @0: Text;
resources @1: List(Resource) $C.mapname("reslist.res") $C.maplistcount("reslist.count");
queues @2: List(QueueConf) $C.mapname("qlist.queues") $C.maplistcount("qlist.count");
workers @3: List(Worker) $C.mapname("wlist.workers") $C.maplistcount("wlist.count");
}
struct JobSubmitData $C.mapname("job_submit_data_t") {
queue @0: Text;
user @1: Text;
mintasks @2: UInt32;
maxtasks @3: UInt32;
jobname @4: Text $C.mapname("job_name");
project @5: Text $C.mapname("project_name");
ugroup @6: Text $C.mapname("user_group");
description @7: Text $C.mapname("job_description");
resreq @8: Text;
startinfo @9: JobStartInfo $C.mapname("start_info");
}
struct JobSubmit $C.mapname("xce_job_submit_t") {
jobid @0: UInt64;
arraySize @1: UInt64 $C.mapname("array_size");
submit @2: JobSubmitData;
}
struct JobSignal $C.mapname("xce_signal_t") {
signo @0: UInt32 $C.mapname("signo");
force @1: Int32 $C.mapname("force");
}
struct CheckpointOptions $C.mapname("xce_ckpt_options_t"){
kill @0: UInt32 $C.mapname("kill");
method @1: Text $C.mapname("method");
}
struct CheckpointInfo $C.mapname("xce_ckptinfo_t") {
jobid @0: UInt64;
ckptinfo @1: Text;
}
struct JobControl $C.mapname("xce_jobctrl_t") {
jobid @0: UInt64 $C.mapname("jobid");
u :union $C.mapuniontag("action") $C.mapname("u") {
siginfo @1: JobSignal;
ckptoption @2: CheckpointOptions;
}
}
struct QueueControl $C.mapname("xce_queuectrl_t") {
action @0: UInt32 $C.mapname("action");
queue @1: Text $C.mapname("queue");
}
struct HostControl $C.mapname("xce_hostctrl_t") {
action @0: UInt32 $C.mapname("action");
hostname @1: Text $C.mapname("hostname");
}
struct RequestReply $C.mapname("xce_reply_t"){
seq @0: UInt64;
opcode @1: OPCode;
status @2: Int32;
data : union {
nodata @3: Void;
debugmsg @4: Text;
getdata @5: XceData;
jobid @6: UInt64;
clusterconf @7: ClusterConf;
replconfigreplymsg @8: ReplConfigReply;
replconfigpushreplymsg @9: ReplConfigPushReply;
upgradeconfigreplymsg @10: UpgradeConfigReply;
ctrlhelloreplymsg @13: CtrlHelloReply;
requestvotereplymsg @14: RequestVoteReply;
stateReportMsg @15: StateReport $C.mapname("state_report"); # heartbeat reply: standby state
walackreplymsg @16: WalAckReply $C.mapname("walackreplymsg"); # WAL apply ACK from standby
ctrlstatus @17: CtrlStatus; # ctrlstatus reply: identity/health snapshot
fetchfilereply @18: FetchFileReply;
}
redirectHost @11: Text $C.mapname("redirect_host");
redirectPort @12: UInt16 $C.mapname("redirect_port");
}
struct TaskHost $C.mapname("xce_taskhost_t") {
host @0: Text;
ntasks @1: UInt32;
exechome @2: Text;
execcwd @3: Text;
execuser @4: Text;
cmdline @5: Text;
exdata @6: Text;
launchtype @7: Text $C.mapname("launch_type");
}
struct RunTask $C.mapname("xce_taskrun_t") {
clientidx @0: Int32 $C.mapname("clientidx");
hosts @1: List(TaskHost) $C.mapname("taskhosts") $C.maplistcount("nhosts");
jobid @2: UInt64 $C.mapname("jobid");
}
struct PendReason $C.mapname("xce_pendreason_t") {
jobid @0: UInt64 $C.mapname("jobid");
reasons @1: JobPendReason $C.mapname("reasons");
}
struct PendReasonSet $C.mapname("xce_preason_set_t") {
reason @0: List(PendReason) $C.mapname("reasons") $C.maplistcount("nreasons");
}
struct ClearPReason $C.mapname("xce_clear_reason_t") {
jobs @0: List(UInt64) $C.mapname("jobs") $C.maplistcount("njobs");
}
struct FetchFileMsg $C.mapname("xce_fetchfile_t") {
jobid @0: UInt64 $C.mapname("jobid");
filepath @1: Text $C.mapname("filepath");
offset @2: UInt64 $C.mapname("offset");
maxBytes @3: UInt32 $C.mapname("max_bytes");
}
struct FetchFileReply $C.mapname("xce_fetchfile_reply_t") {
error @0: Int32 $C.mapname("error");
content @1: List(UInt8) $C.mapname("content") $C.maplistcount("bytes_read");
fileSize @2: UInt64 $C.mapname("file_size");
bytesRead @3: UInt32 $C.mapname("bytes_read");
jobid @4: UInt64 $C.mapname("jobid");
}
struct Request $C.mapname("xce_request_t"){
opcode @0: OPCode;
seq @1: UInt64;
from @2: PeerInfo;
body : union {
nomsg @3: Void;
replymsg @4: RequestReply;
hellomsg @5: Text;
joinmsg @6: JoinData;
configpushmsg @7: ConfigData;
pushmsg @8: XceData;
getmsg @9: Get;
datamsg @10: Dataset;
dispatchmsg @11: JobDispatch;
jobstartmsg @12: JobExecInfo;
notifymsg @13: NotifyData;
jobsubmsg @14: JobSubmit;
updatemsg @15: Update;
jobctrlmsg @16: JobControl;
queuectrlmsg @17: QueueControl;
runtaskmsg @18: RunTask;
preasonmsg @19: PendReasonSet;
clrpreasonmsg @20: ClearPReason;
hostctrlmsg @21: HostControl;
replconfigrequestmsg @22: ReplConfigRequest;
replconfigpushrequestmsg @23: ReplConfigPushRequest;
upgradeconfigrequestmsg @24: UpgradeConfigRequest;
heartbeatmsg @25: HeartbeatMsg;
ctrlhellomsg @26: CtrlHelloRequest;
requestvotemsg @27: RequestVoteRequest;
walcatchupentrymsg @28: WalCatchupEntry;
snapshottransfermsg @29: SnapshotTransfer;
fetchfilemsg @30: FetchFileMsg;
}
}
struct HostConfig $C.mapname("xce_hostconfig_t") {
name @0: Text $C.mapname("name");
model @1: Text $C.mapname("hostmodel");
type @2: Text $C.mapname("hosttype");
mxj @3: UInt32 $C.mapname("mxj");
resources @4: List(ConfigVar) $C.mapname("resources") $C.maplistcount("nresources");
thresholds @5: List(Threshold) $C.mapname("thresholds") $C.maplistcount("nthresholds");
dispatchwindows @6: TimeWindow $C.mapname("dispatchwindow");
}
struct ScalerConfig $C.mapname("scaler_config_t") {
name @0: Text $C.mapname("name");
type @1: Text $C.mapname("prov_type");
confPath @2: Text $C.mapname("conf_path");
scriptPath @3: Text $C.mapname("script_path");
scriptOption @4: Text $C.mapname("script_option");
}
struct LimitConfig $C.mapname("xce_limit_config_t") {
name @0: Text $C.mapname("name");
users @1: GroupConfig $C.mapname("users");
queues @2: GroupConfig $C.mapname("queues");
projects @3: GroupConfig $C.mapname("projects");
hosts @4: GroupConfig $C.mapname("hosts");
val @5: LimitValue $C.mapname("val");
perUser @6: Bool $C.mapname("per_user");
perQueue @7: Bool $C.mapname("per_queue");
perProject @8: Bool $C.mapname("per_project");
perHost @9: Bool $C.mapname("per_host");
}
struct ClusterConfig $C.mapname("cluster_config_t") {
clusterName @0: Text $C.mapname("clustername");
heartbeatInterval @1: UInt32 $C.mapname("heartbeat_interval");
inactiveHeartbeatCount @2: UInt32 $C.mapname("inactive_heartbeat_count");
fetchJobInterval @3: UInt32 $C.mapname("fetch_job_interval");
netioTimeout @4: UInt32 $C.mapname("netio_timeout");
resources @5: List(Resource) $C.mapname("resources") $C.maplistcount("nres");
queues @6: List(QueueConf) $C.mapname("queues") $C.maplistcount("nqueues");
ugroups @7: List(GroupConfig) $C.mapname("ugroups") $C.maplistcount("nugroups");
hgroups @8: List(GroupConfig) $C.mapname("hgroups") $C.maplistcount("nhgroups");
hostConfigs @9: List(HostConfig) $C.mapname("hconfigs") $C.maplistcount("nhconfigs");
hproviders @10: List(ScalerConfig) $C.mapname("hproviders") $C.maplistcount("nhproviders");
limits @11: List(LimitConfig) $C.mapname("limits") $C.maplistcount("nlimits");
configGeneration @12: UInt64 $C.mapname("config_generation");
}
# ── Persistence configuration (Part 2.6) ────────────────────────────
# $C.mapname uses capnp_persist_cfg_t (not persist_config_t) to avoid
# collision with the plain-C struct already defined in persist.h.
struct PersistConfig $C.mapname("capnp_persist_cfg_t") {
walSyncMs @0 :UInt32 = 10;
snapIntervalS @1 :UInt32 = 60;
snapWalSizeMb @2 :UInt32 = 64;
finishedRetainS @3 :UInt32 = 3600;
workerRetainS @4 :UInt32 = 86400;
syncTimeoutMs @5 :UInt32 = 50;
snapKeepN @6 :UInt32 = 2;
transientJobTimeoutS @7 :UInt32 = 300;
}
# ── Snapshot header (Part 2.5) ───────────────────────────────────────
struct SnapshotHeader $C.mapname("capnp_snap_hdr_t") {
lsn @0 :UInt64;
term @1 :UInt64;
timestamp @2 :UInt64;
version @3 :UInt32 = 1;
nJobs @4 :UInt32;
nQueues @5 :UInt32;
nWorkers @6 :UInt32;
checksum @7 :UInt32;
headerChecksum @8 :UInt32;
}
# ── Upgrade snapshot admin-state frames (config-upgrade-snapshot task 1,
# Req 1.9/5.7) ──────────────────────────────────────────────────────────
# Independently-extensible Cap'n Proto frames for the on-disk checkpoint's
# host/queue admin-state sections (SNAPSHOT_FORMAT_VERSION 2, persist.c).
# New admin-state fields (e.g. a lock reason or tag) get new ordinals under
# capnp's own schema-evolution rules -- no future SNAPSHOT_FORMAT_VERSION
# bump needed per field addition. Deliberately NOT mapname'd onto
# Worker/QueueConf (design.md Design Invariant 5): those live runtime
# structs bundle static attrs and dynamic state together, which a snapshot
# frame must never carry (Requirement 1.7 excludes dynamic fields). Each
# maps instead onto its own frame-only C counterpart in typemap.h, matching
# the existing capnp_snap_hdr_t/capnp_persist_cfg_t/capnp_repl_envelope_t
# convention already established below for schema-only wire concepts with
# no corresponding "live" C struct.
struct HostAdminState $C.mapname("capnp_host_admin_state_t") {
name @0: Text;
status @1: UInt32;
}
struct QueueAdminState $C.mapname("capnp_queue_admin_state_t") {
name @0: Text;
status @1: UInt32;
}
# ── HA heartbeat ────────────────────────────────────────────────────
struct HeartbeatMsg $C.mapname("heartbeat_msg_t") {
senderPriority @0: UInt32 $C.mapname("sender_priority");
term @1: UInt64 $C.mapname("term");
committedLsn @2: UInt64 $C.mapname("committed_lsn");
committedConfigTag @3: UInt64 $C.mapname("committed_config_tag");
}
# ── Config replication message structs ──────────────────────────────
struct ReplConfigRequest $C.mapname("repl_config_req_t") {
versionTag @0: UInt64 $C.mapname("version_tag");
}
struct ReplConfigReply $C.mapname("repl_config_reply_t") {
upToDate @0: Bool $C.mapname("up_to_date");
versionTag @1: UInt64 $C.mapname("version_tag");
sha256 @2: Data $C.mapname("sha256");
bytes @3: Data $C.mapname("bytes");
}
struct ReplConfigPushRequest $C.mapname("repl_config_push_req_t") {
versionTag @0: UInt64 $C.mapname("version_tag");
sha256 @1: Data $C.mapname("sha256");
bytes @2: Data $C.mapname("bytes");
}
struct ReplConfigPushReply $C.mapname("repl_config_push_reply_t") {
accepted @0: Bool $C.mapname("accepted");
versionTag @1: UInt64 $C.mapname("version_tag");
# raft-adapter-conformance Requirement 7.4: the replying member's current
# term, so a higher term can be discovered through this reply channel the
# same way it already is through heartbeat and WAL-NACK replies. Additive
# field (ordinal 2) — an old-code standby's reply decodes as term=0 on a
# new-code primary, which can never look like a higher term (terms start
# at 1), so no spurious adoption occurs under mixed-version rollout.
term @2: UInt64 $C.mapname("term");
}
struct UpgradeConfigRequest $C.mapname("upgrade_config_req_t") {
sha256 @0: Data $C.mapname("sha256");
bytes @1: Data $C.mapname("bytes");
}
struct UpgradeConfigReply $C.mapname("upgrade_config_reply_t") {
versionTag @0: UInt64 $C.mapname("version_tag");
error @1: Text $C.mapname("error");
ackedCount @2: UInt32 $C.mapname("acked_count");
}
# ── WAL replication envelope (Part 6 — NOT the on-disk format) ───────
# Named ReplEnvelope to avoid collision with the on-disk wal_entry_hdr_t.
struct ReplEnvelope $C.mapname("capnp_repl_envelope_t") {
term @0 :UInt64;
lsn @1 :UInt64;
entryType @2 :UInt32;
payload @3 :Data;
crc @4 :UInt32;
prevCrc @5 :UInt32;
}
# ── HA election and replication message structs (Task 1.1) ───────────
# Heartbeat reply state report — standby piggybacks its replication state
# onto every OPCode_nop reply so the primary can drive convergence decisions.
struct StateReport $C.mapname("state_report_t") {
appliedLsn @0 :UInt64 $C.mapname("applied_lsn"); # standby's last applied WAL LSN
configTag @1 :UInt64 $C.mapname("config_tag"); # standby's current config version tag
term @2 :UInt64 $C.mapname("term"); # standby's current raft term (bug-1421 term-discovery)
}
struct RequestVoteRequest $C.mapname("request_vote_req_t") {
term @0 :UInt64 $C.mapname("term");
candidateId @1 :Text $C.mapname("candidate_id");
configTag @2 :UInt64 $C.mapname("config_tag");
lastLogLsn @3 :UInt64 $C.mapname("last_log_lsn");
# Raft (lastLogTerm, lastLogIndex) freshness tuple (ha-term-safety task 1.2,
# Req 2.3/2.4/2.6). Distinct from the XCE freshness fields above: configTag /
# lastLogLsn drive the application-policy freshness gate (on_vote_eligible),
# while these two feed the library's logOk gate (raft.tla HandleRequestVoteRequest
# logOk). lastLogIndex == candidate WAL log_len; lastLogTerm == term of that entry.
lastLogTerm @4 :UInt64 $C.mapname("last_log_term");
lastLogIndex @5 :UInt64 $C.mapname("last_log_index");
}
struct RequestVoteReply $C.mapname("request_vote_reply_t") {
term @0 :UInt64 $C.mapname("term");
voteGranted @1 :Bool $C.mapname("vote_granted");
peerConfigTag @2 :UInt64 $C.mapname("peer_config_tag");
peerLastLogLsn @3 :UInt64 $C.mapname("peer_last_log_lsn");
}
struct ProbeConfigTagRequest $C.mapname("probe_config_tag_req_t") {
name @0 :Text $C.mapname("name");
}
struct ProbeConfigTagReply $C.mapname("probe_config_tag_reply_t") {
configTag @0 :UInt64 $C.mapname("config_tag");
}
struct WalAckRequest $C.mapname("wal_ack_req_t") {
term @0 :UInt64 $C.mapname("term");
lsn @1 :UInt64 $C.mapname("lsn");
}
struct WalAckReply $C.mapname("wal_ack_reply_t") {
term @0 :UInt64 $C.mapname("term");
lsn @1 :UInt64 $C.mapname("lsn");
success @2 :Bool $C.mapname("success");
}
struct UpgradeConfigAck $C.mapname("upgrade_config_ack_t") {
term @0 :UInt64 $C.mapname("term");
ackedTag @1 :UInt64 $C.mapname("acked_tag");
success @2 :Bool $C.mapname("success");
}
# ── Snapshot chunk transfer (Req 4.1–4.2) ───────────────────────────
# Used for OPCode_snapshotTransfer: full state snapshot transferred as
# a sequence of fixed-size chunks (64 KB max each). Restart-on-reconnect
# semantics — no resumption state needed. Fields @0 and @1 are preserved
# for wire-protocol continuity; @2–@5 carry the chunk envelope.
struct SnapshotTransfer $C.mapname("snapshot_transfer_t") {
snapshotLsn @0 :UInt64 $C.mapname("snapshot_lsn"); # checkpoint LSN this snapshot corresponds to
payload @1 :Data $C.mapname("payload"); # chunk payload (64 KB max)
chunkIndex @2 :UInt32 $C.mapname("chunk_index"); # 0-based chunk number
chunkOffset @3 :UInt64 $C.mapname("chunk_offset"); # byte offset in the full snapshot
totalSize @4 :UInt64 $C.mapname("total_size"); # total snapshot size in bytes
isLast @5 :Bool $C.mapname("is_last"); # true for the final chunk
# raft-ha-core-safety task 3.2 (Req 3.1/5.1): the leader's term for the
# checkpoint LSN (persist_entry_term(p, snapshotLsn) at send time). The
# receiver reconciles this into its own per-LSN term index after install so
# the snapshot boundary establishes a verifiable (term, lsn) pair and any
# divergent stale-term pre-snapshot entry at this LSN is authoritatively
# overwritten. Append-only field number (@6) — no collision with @0-@5
# above. 0 = unset (legacy sender that never stamped this field) — the
# receiver treats 0 as WAL_LEGACY_TERM, the same convention persist's
# existing legacy-0 term mapping already uses.
checkpointTerm @6 :UInt64 $C.mapname("checkpoint_term");
}
struct WalCatchupEntry $C.mapname("wal_catchup_entry_t") {
lsn @0 :UInt64 $C.mapname("lsn");
entryType @1 :UInt8 $C.mapname("entry_type");
payload @2 :Data $C.mapname("payload");
entries @3 :List(WalCatchupEntry) $C.mapname("entries") $C.maplistcount("n_entries");
# Raft AppendEntries term fields (ha-term-safety task 1.1, Req 1.3/1.4).
# This envelope is the replication-carrying message (WAL catch-up); the four
# log callbacks (tasks 2.x) need prevLog{Index,Term} for the AppendEntries
# logOk / conflict-truncation decision and `term` to stamp the entry. lsn ==
# this entry's 1-based log index; prevLogIndex == lsn-1; prevLogTerm == term of
# the entry at prevLogIndex (0 if absent); term == this entry's term stamp.
term @4 :UInt64 $C.mapname("term");
prevLogIndex @5 :UInt64 $C.mapname("prev_log_index");
prevLogTerm @6 :UInt64 $C.mapname("prev_log_term");
# ha-term-safety task 3.2 (Req 2.5/4.1): the leader's commit index, carried so
# the standby intake passes it into raft_on_append_entries_request. Append-only
# field number (@7) — no collision with the @4/@5/@6 term fields above.
leaderCommit @7 :UInt64 $C.mapname("leader_commit");
# bug-1067: the streaming leader's CURRENT term — the Raft AppendEntries header
# term (`term` arg of raft_on_append_entries_request), DISTINCT from `term` @4
# which is the entry's STORED term. For a live append the two are equal; for
# catch-up of a HISTORICAL entry written by a prior leader, the entry's stored
# term is LOWER than the current leader's term. Using the stored term as the AE
# header term made the library stale-reject every historical entry
# (ae_reject_stale), wedging cross-term catch-up. The standby intake uses this
# as the AE header term (UpdateTerm/stale-check) and keeps `term` @4 as the
# per-entry term (logOk / on_persist_entry). 0 = unset (legacy sender) → the
# intake falls back to the entry's stored term (the prior, live-only behaviour).
leaderCurrentTerm @8 :UInt64 $C.mapname("leader_current_term");
# bug-847: a PER-ELEMENT `payload` (@2) Data blob loses its pointer when a
# multi-entry catch-up batch spans more than one capnp segment (the
# underlying capnp-c library's far-pointer handling for a List(UInt8) whose
# segment differs from its referencing struct's segment) -- the receiver
# decodes raw_payload_len=0 for entries at/after the boundary even though
# the sender held the real bytes, silently persisting empty WAL entries.
# A SINGLE top-level Data blob does not exhibit this loss (only scattered
# per-element Data does), so the batch encoder (xce_wal_batch_encode_raw)
# now carries every sub-entry's payload concatenated in ONE top-level
# batchPayloads blob, sliced back apart on decode using each sub-entry's
# own wirePayloadLen (a plain scalar -- already immune, decoded like
# lsn/entryType/term by the generic generated decode, no manual extraction
# needed). Populated for every xce_wal_batch_encode_raw send regardless of
# n_entries (0/1/N); sub-entries no longer carry their own @2 payload on
# this path (kept for any other/legacy sender; decode still handles it
# defensively as a fallback when batchPayloads is absent).
wirePayloadLen @9 :UInt32 $C.mapname("wire_payload_len");
batchPayloads @10 :Data $C.mapname("batch_payloads");
}
struct CtrlHelloRequest $C.mapname("ctrl_hello_req_t") {
name @0 :Text $C.mapname("name");
key @1 :Data $C.mapname("key");
appliedLsn @2 :UInt64 $C.mapname("applied_lsn");
configTag @3 :UInt64 $C.mapname("config_tag");
}
struct CtrlHelloReply $C.mapname("ctrl_hello_reply_t") {
committedLsn @0 :UInt64 $C.mapname("committed_lsn");
needsSnapshot @1 :Bool $C.mapname("needs_snapshot");
configTag @2 :UInt64 $C.mapname("config_tag");
}