Commit graph

12 commits

Author SHA1 Message Date
5bf123cc20
refactor(controller,xceadmin): drop generic Resource.unit, hardcode bytes for maxmem
Simplification per review feedback on e3b3ffa: a generic schema-driven
unit field touched the capnp wire schema (2 structs), C structs
(xce_resource_t/xce_resval_t), resobj.c's deep-copy/destroy, opget.c's
reply-build lookup, resources.yaml/resources.schema.json, and mapping.py
-- real cross-cutting cost for a mechanism only one resource (maxmem)
actually needs today.

Reverted all of that. The controller CLI (test.c) now just knows
"maxmem" is bytes-valued via a small explicit is_bytes_valued_resource()
name list, and adaptively picks the best-fit human unit at display time
(format_bytes_human, unchanged) -- same observable behavior (resval/
workerlist render maxmem as e.g. "30.90 GB"), zero wire schema surface.
Regenerated the xceadmin golden fixture back to its pre-unit-field size
(5304 bytes, exactly matching the size right after the mxj-only fix,
confirming a clean, complete removal).

Verified: 1095/1095 controller_unit_test (3 runs; one hit the
pre-existing flaky segfault already logged as bug-1553, unrelated),
228/228 xceadmin pytest, clean rebuild of lib/controller/xceadmin/xce_test.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-13 08:27:16 +00:00
e3b3ffaa97
fix(controller,xceadmin): fix zero-slot scheduling block, misleading resval logs, byte-unit display
Three bugs found while diagnosing a live controller log, all in the
worker resource-value path:

1. Every host relying on the documented hosts.yaml auto-detect default
   (no max_slot, meaning "use CPU count") got 0 scheduling slots,
   permanently blocking the scheduler from placing jobs on it. mxj is
   UInt32 on the wire and can't carry the schema's -1 sentinel; mapping.py
   worked around this by leaving it unset, which defaults to 0 -- and 0 is
   never < 0, so apply_join_state()'s auto-detect fallback never fired.
   Fixed by encoding the sentinel as 0xFFFFFFFF, which the controller's
   `int mxj` field reinterprets back to -1 via its existing implicit
   uint32_t->int conversion. No C-side or wire schema change needed for
   this part; the fallback itself was already correct but had zero test
   coverage for a negative mxj, now added.

2. update_resvals()/update_resval_list() logged the failure reason via
   PERROR, which reads process-global errno -- but update_resval()'s
   failure paths return raw negative codes directly and never touch
   errno, so the controller log filled with misleading "update_resval:
   Success" / "update_resval: Resource temporarily unavailable" lines
   instead of the real reason. Fixed to decode the actual rc via
   xce_strerror_r and name the failing resource.

3. maxmem is canonically stored/wired as raw bytes but had no unit
   metadata, so resval/workerlist printed it as a bare number that read
   as garbage (e.g. workerlist's fixed-width columns visually smeared a
   multi-GB byte count across the MaxCPU/MaxMem headers). Added an
   optional `unit` field to the Resource/ResourceVal capnp structs (and
   xce_resource_t/xce_resval_t/resources.yaml) so resval and workerlist
   can render a human-readable value (e.g. "30.90 GB") while the stored
   value stays raw bytes -- display-only, every other resource unaffected.

Regenerated the xceadmin golden fixture (fixtures/full/expected.bin)
twice: once for the mxj sentinel encoding change, once for the new
Resource.unit field growing every resource's wire size by one pointer
slot. Both diffs verified byte-for-byte isolated to exactly the expected
change before regenerating.

Verified: 1095/1095 controller_unit_test (stable across repeated runs),
229/229 xceadmin pytest, clean rebuild of lib/controller/xceadmin/xce_test.
Two related findings logged to .wolf/buglog.json but deliberately not
fixed here (out of scope per discussion): a pre-existing flaky segfault
in the combined controller_unit_test binary, and maxswap/maxtmp being
hardcoded stub values on the worker side.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-13 08:12:09 +00:00
e53c086ec5 fix(schema): rename struct Data -> XceData to unshadow capnp builtin blob type
controller.capnp declared `struct Data $C.mapname("xce_data_t")` (an
OPCode_get query-result tagged union) at file scope, which shadows
Cap'n Proto's builtin Data blob type for every later `: Data` field in
the same file. This silently miscompiled 7 fields across 6 structs as
a struct-pointer type instead of a raw byte blob: UpgradeConfigRequest
.sha256/.bytes, ReplConfigReply.sha256/.bytes, ReplConfigPushRequest
.sha256/.bytes, ReplEnvelope.payload, SnapshotTransfer's chunk
payload, WalCatchupEntry.payload/.batchPayloads, and CtrlHelloRequest
.key. Production C code had already routed around it for years via
hand-rolled raw capn_ptr manipulation (see request.c's own comments);
nothing before now needed the generated codec/accessors to actually
work for these fields.

Renamed the local struct to XceData (capnp-level name only; the
$C.mapname("xce_data_t") C typedef is unchanged) and explicitly
repointed getdata/pushmsg at XceData by name, since those two fields
correctly want the local tagged union. Updated every derived
generated-identifier reference across 19 hand-written files spanning
controller, lib, scheduler, and the Go apiserver/xcecli CGo bindings.
Fixed 5 call sites in lib/request.c that had been typed against the
old workaround alias but now legitimately receive the correct
capn_data type (a pure type-name swap -- Data_ptr/XceData_ptr and
capn_data share the identical {capn_ptr p} layout).

Verified via full rebuild+test: lib (1/1), controller (3/3, incl. the
job-array push regression tests), scheduler (15/15), Go apiserver +
xcecli (all packages green), and a direct pycapnp round-trip proving
UpgradeConfigRequest.sha256/.bytes now encode/decode correctly.

Bug: bug-1461 (.wolf/buglog.json). Unblocks admin-config-tool task 3.3.
2026-07-22 09:22:04 +00:00
e5fde7b55f fix(persist): zero nresvals_to_sched after free_name_val_list
Crash: encode_NameValue_list called with count=21, s=NULL on worker
rejoin, causing SIGSEGV in persist_worker_hook_fun.

Root cause: free_name_val_list(xce_name_val_t***, int) accepted count by
value. It zeroed *vals (resvals_to_sched = NULL) but could not zero
nresvals_to_sched. Any caller that freed the scheduler resource snapshot
(opget.c workerlist, reply.c clusterconf, dataex.c, sched.c dispatch)
left nresvals_to_sched stale. When the worker later rejoined and the
WAL HOOK fired, the WAL encoder read count=21 with a NULL pointer.

Fix: change signature to free_name_val_list(xce_name_val_t***, int*)
so both fields are zeroed atomically. Update all 7 call sites.
2026-05-20 09:39:07 +00:00
d47b3375e7 controller will pass resource <name, value> pair than <idx, value> pair 2026-05-13 07:18:03 +00:00
3f74f14687 save works 2026-03-04 18:18:53 +08:00
acfbec875b save works 2026-03-03 16:49:26 +08:00
f4b1ba4cd7 save works 2026-03-02 12:14:30 +08:00
b748e30d20 save works 2026-02-28 17:55:50 +08:00
cb0c7fe9e7 merge job rusage and pending reason support 2025-12-16 14:36:28 +08:00
9ff857db9f reformat code and job array 2025-11-07 16:14:27 +08:00
Rongsong Shen
41f56fa6ed update controller code 2025-11-05 16:58:57 +08:00