Replace monolithic add_worker with three focused functions: - apply_join_state (static under production, exported under XCE_TESTING): shared status/resource update called by both create and rejoin paths; clears XCE_WORKER_UNAVAIL, applies hconfig overrides, updates resources - init_worker: first-time join path via makeWorker + apply_join_state - rejoin_worker: reconnect path with explicit admin-bit preservation (XCE_WORKER_ADMIN_MASK = LOCKEDU|CLOSED|HIDDEN|CLOSED_BY_ADMIN) Also makes find_matched_hostconfig non-static so join.c can call it via the extern declaration already in worker.h. Removes add_worker (no longer declared in worker.h, no callers). All 7 tests in test_worker_join pass: apply_join_state (clears UNAVAIL, hosttype override, resource values), init_worker (creates entry, returns correct idx), rejoin_worker (updates attrs/ep, preserves admin bits).
6.5 KiB
6.5 KiB
Implementation Plan
Task Format
- Major task number and description
- Sub-task number and description
- Detail items
- Observable completion condition
- Requirements: X.X, Y.Y
-
1. Foundation: write failing tests for all new worker join behaviors (TDD Red)
-
1.1 Write failing tests for the shared status and resource update step
- Add a new test file (e.g.,
test_worker_join.c) tosrc/controller/testsuite/and register it incontroller_test.c - Tests assert: after the helper runs,
XCE_WORKER_UNAVAILis cleared on the worker's status, hosttype/model match the hconfig override values, slot count equals the hconfig mxj value, and host-attribute resources (type, model, cpuf, maxcpus, maxmem, maxswap, maxtmp, ndisks) hold the expected values - Tests compile but fail because the helper does not yet exist
- Requirements: 4.1, 4.2, 4.3
- Add a new test file (e.g.,
-
1.2 Write failing tests for the first-time worker creation path
- Tests assert: calling the creation function with a previously-unknown hostname produces a non-negative index;
key_findonworkermgrwith that name succeeds after the call - Tests assert: when the creation function returns an error, the error code is negative and no
on_worker_joinside effect occurs - Tests compile but fail because the function does not yet exist
- Requirements: 2.1, 2.2, 2.3
- Tests assert: calling the creation function with a previously-unknown hostname produces a non-negative index;
-
1.3 Write failing tests for the rejoin update path with admin-bit preservation
- Tests assert: after the update function runs, the worker's
host.attrsreflects the new values andw->epmatches the new endpoint - Tests assert: admin status bits (
XCE_WORKER_LOCKEDU,XCE_WORKER_CLOSED,XCE_WORKER_HIDDEN,XCE_WORKER_CLOSED_BY_ADMIN) present before the call are still set after it - Tests compile but fail because the function does not yet exist
- Requirements: 3.1, 3.2, 3.3
- Tests assert: after the update function runs, the worker's
- 2. Core: extract shared status and resource update into a standalone helper (TDD Green — 1.1)
- Move the status-clear + hconfig-override + resource-update block out of
add_workerinworker.cinto a newstatichelper function - The helper covers: clearing
XCE_WORKER_UNAVAIL, assigningw->ep, overriding hosttype/model strings from hconfig (withdereference/makeString), callingadd_hostattrs_resvals, computing mxj slots viaset_host_slots, replacingdispatch_window_configandthresholdsfrom hconfig, and looping overhconfig->nresourceswithmark_host_res - Must be called under the caller-held per-worker write lock; document this precondition with a comment
- Tests from 1.1 turn green;
add_workerstill compiles by delegating to the new helper - Requirements: 4.1, 4.2, 4.3
- Move the status-clear + hconfig-override + resource-update block out of
-
3. Core: implement the first-time creation and rejoin update helpers
-
3.1 Implement the first-time worker creation function (TDD Green — 1.2)
- Build a temporary
xce_worker_tfrom the incoming hostname and attrs, then callmakeWorkerto register it inworkermgr(makeWorker manages its own write lock) - On a
NULLreturn frommakeWorker, log the failure and return-errnoto the caller without touchingon_worker_join - On success, acquire the per-worker write lock, call the shared helper from Task 2, release the lock, and return
w->idx - Tests from 1.2 turn green
- Requirements: 2.1, 2.2, 2.3
- Build a temporary
-
3.2 Implement the rejoin worker update function (TDD Green — 1.3)
- Acquire the per-worker write lock at the start; save
admin_status = w->host.status & XCE_WORKER_ADMIN_MASKbefore any modification - Free and replace the existing
hosttypeandhostmodelstrings; overwrite numeric attrs fields (cpufactor,maxcpus,maxmem,maxswap,maxtmp,ndisks) from the incoming attrs argument - Call the shared helper from Task 2 (status/resource update, ep assignment), then restore admin bits via
w->host.status |= admin_status; release the lock - Return
w->idx; tests from 1.3 turn green and admin bits are unchanged after a full round-trip - Requirements: 3.1, 3.2, 3.3
- Acquire the per-worker write lock at the start; save
-
4. Integration: wire the explicit existence check and new helpers into the join handler
-
4.1 Update exported worker function declarations
- Remove the
add_workerdeclaration fromsrc/controller/include/worker.h - Add declarations for the first-time creation function and the rejoin update function with their full parameter lists (including the
xce_hostconfig_t*parameter) - Verify that the only direct caller of
add_workerwashandle_worker_join; if any other callers exist, update them to use the appropriate new function worker.hcompiles cleanly with no remaining reference toadd_worker- Requirements: 5.4
- Remove the
-
4.2 Rewrite the worker join handler with explicit existence check and branching
- Remove the outer
lock(c->workermgr, RTTI_LOCK_WRITE)/unlockpair that currently wraps theadd_workercall (eliminates the double write-lock deadlock) - Move
find_matched_hostconfigto the top of the handler, before any lock; reject the join with the appropriate error code and setreply.statusif it returnsNULL - Acquire a brief workermgr read lock, call
key_find, release the read lock immediately - On
-ENOENTcall the first-time creation function; on a found entry call the rejoin update function; on any other error fromkey_findreject the join and return that error code - Fire
BEFORE_EVENT / HOOK_DETAIL_WORKER_JOINbefore thekey_findstep; fireAFTER_EVENTafter the create-or-update completes; callxce_replyandon_worker_joinoutside any lock - Set
priv->u.idxbefore callingon_worker_join; if create or update returned an error, setreply.status, callxce_reply, and return without callingon_worker_join - The join handler compiles and the sequence check → create-or-update → status/resource-update is visible at the call site with no hidden branching inside
makeWorker - Requirements: 1.1, 1.2, 1.3, 2.2, 2.3, 4.4, 5.1, 5.2, 5.3
- Remove the outer
- 5. Validation: run full test suite and confirm behavioral preservation
- Build the controller test binary and run all suites in
src/controller/testsuite/ - Confirm
test_e2e_hooksrecordsBEFORE_EVENTbefore any workermgr mutation andAFTER_EVENTafter it, matching the pre-refactor ordering - If any test fixture in the suite constructed workers by calling
add_workerdirectly, update the fixture to call the creation function with the addedxce_hostconfig_t*argument make testexits 0; no previously-passing test is broken by the refactor- Requirements: 5.1, 5.2, 5.3, 5.4
- Build the controller test binary and run all suites in