feat(scheduler-core): extract xce_sched_core_t from monolithic scheduler struct (task 4.1)

Splits xce_scheduler_t along the controller-I/O seam: xce_sched_core_t
(new core.h/core.c) now holds all scheduling state (jobs/queues/workers/
users/projects/resource managers/plugins/three-thread-cbuf pipeline),
while xce_scheduler_t shrinks to {core; apictx; cluster_cfg}. Proven via
an nm-based link-time isolation test (zero netio/xcecli/idgen/delaymgr
symbols reachable from core.c) plus a reproducible wall-clock-call guard.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019dw5WnN3DXStaEaPYfACU1
This commit is contained in:
Rongsong Shen 2026-08-03 10:55:58 +00:00
parent 604a564904
commit 7c229284e2
Signed by: rshen
SSH key fingerprint: SHA256:8Vf2pZ3h6rJa7EhGK+WaAQ9Mta/apZvteW6g9U/WKKk
26 changed files with 1233 additions and 661 deletions

View file

@ -31,12 +31,16 @@
/* Stubs for scheduler-internal externs schedobj.c references but which are
* defined in other .c files not linked into this test. (make_sched_obj and
* kill_sched_job are static in schedobj.c and come in via the #include.) */
xce_sched_user_t* sched_get_user(xce_scheduler_t* s, char* n)
* kill_sched_job are static in schedobj.c and come in via the #include.)
* sched_get_user/sched_get_project/sched_get_queue/sched_add_user/
* sched_add_project/sched_add_job/sched_get_job relocated to core.h
* (scheduler-core spec, task 4.1) -- now operate on xce_sched_core_t*, not
* xce_scheduler_t*. */
xce_sched_user_t* sched_get_user(xce_sched_core_t* s, char* n)
{
(void)s; (void)n; return NULL;
}
xce_sched_project_t* sched_get_project(xce_scheduler_t* s, char* n)
xce_sched_project_t* sched_get_project(xce_sched_core_t* s, char* n)
{
(void)s; (void)n; return NULL;
}
@ -48,8 +52,18 @@ int plugin_job_rusage_update(void* s, xce_sched_job_t* j, xce_job_rusages_t* r)
}
xce_job_account_t* make_job_account(xce_job_alloc_t* a) { (void)a; return NULL; }
void free_job_account(xce_job_account_t* a) { (void)a; }
int sched_add_user(xce_scheduler_t* s, xce_sched_user_t* u) { (void)s; (void)u; return 0; }
int sched_add_project(xce_scheduler_t* s, xce_sched_project_t* p) { (void)s; (void)p; return 0; }
int sched_add_user(xce_sched_core_t* s, xce_sched_user_t* u)
{
(void)s;
(void)u;
return 0;
}
int sched_add_project(xce_sched_core_t* s, xce_sched_project_t* p)
{
(void)s;
(void)p;
return 0;
}
void sched_worker_release_host_ctx(xce_sched_worker_t* w) { (void)w; }
int plugin_prepare_allocation(void* s, xce_sched_ctx_t* c) { (void)s; (void)c; return 0; }
@ -57,7 +71,7 @@ int plugin_prepare_allocation(void* s, xce_sched_ctx_t* c) { (void)s; (void)c; r
static xce_sched_queue_t* g_test_queues[8];
static int g_test_nqueues;
xce_sched_queue_t* sched_get_queue(xce_scheduler_t* s, char* name)
xce_sched_queue_t* sched_get_queue(xce_sched_core_t* s, char* name)
{
int i;
(void)s;
@ -74,22 +88,22 @@ xce_sched_queue_t* sched_get_queue(xce_scheduler_t* s, char* name)
}
/* REAL kvmgr-backed job add/get - same rtti path the production code uses. */
int sched_add_job(xce_scheduler_t* sched, xce_sched_job_t* j)
int sched_add_job(xce_sched_core_t* core, xce_sched_job_t* j)
{
int rc;
lock(sched->jobs, RTTI_LOCK_WRITE);
rc = key_add(sched->jobs, (void*)j->jobid, j);
unlock(sched->jobs);
lock(core->jobs, RTTI_LOCK_WRITE);
rc = key_add(core->jobs, (void*)j->jobid, j);
unlock(core->jobs);
return rc;
}
xce_sched_job_t* sched_get_job(xce_scheduler_t* sched, uint64_t jobid)
xce_sched_job_t* sched_get_job(xce_sched_core_t* core, uint64_t jobid)
{
int rc;
xce_sched_job_t* job = NULL;
lock(sched->jobs, RTTI_LOCK_READ);
rc = key_find(sched->jobs, (void*)jobid, (void**)&job);
unlock(sched->jobs);
lock(core->jobs, RTTI_LOCK_READ);
rc = key_find(core->jobs, (void*)jobid, (void**)&job);
unlock(core->jobs);
if (rc <= 0) {
return NULL;
}
@ -120,8 +134,8 @@ static void fixture_init(xce_scheduler_t* sched)
resreq_init(1);
xstring_table_init(1024 * 16);
sched->jobs = makeInstance(&xkvmgr_type, &jobs_params);
sched->resmgr = makeInstance(&xkvmgr_type, &res_params);
sched->core.jobs = makeInstance(&xkvmgr_type, &jobs_params);
sched->core.resmgr = makeInstance(&xkvmgr_type, &res_params);
g_test_nqueues = 0;
memset(g_test_queues, 0, sizeof(g_test_queues));
@ -146,7 +160,7 @@ static xce_sched_job_t* seed_job(xce_scheduler_t* sched, uint64_t jobid)
job->resreq = (xce_resreq_t*)calloc(1, sizeof(*job->resreq));
/* schedobj is live runtime state that MUST survive an in-place update */
job->schedobj = (xce_sched_obj_t*)calloc(1, sizeof(*job->schedobj));
sched_add_job(sched, job);
sched_add_job(&(sched->core), job);
return job;
}
@ -182,7 +196,7 @@ test_update_existing_job_mutates_in_place(void)
TEST_ASSERT_EQUAL_INT(0, rc);
/* SAME object mutated in place, not replaced */
TEST_ASSERT_EQUAL_PTR(job, sched_get_job(&sched, 42));
TEST_ASSERT_EQUAL_PTR(job, sched_get_job(&sched.core, 42));
/* mutable fields updated */
TEST_ASSERT_EQUAL_UINT(JOB_STAT_RUN, job->state);
TEST_ASSERT_EQUAL_PTR(g_test_queues[0], job->queue);
@ -209,7 +223,7 @@ test_update_unknown_job_returns_enoent_no_create(void)
TEST_ASSERT_EQUAL_INT(-ENOENT, rc);
/* And NO job was created via the update path */
TEST_ASSERT_NULL(sched_get_job(&sched, 999));
TEST_ASSERT_NULL(sched_get_job(&sched.core, 999));
free(upd->submit);
free(upd);
@ -250,7 +264,7 @@ test_rusage_stored_on_existing_job(void)
/* stored ON the job (ownership transferred to the job) */
TEST_ASSERT_EQUAL_PTR(ru, job->rusages);
/* the job object itself is unchanged identity */
TEST_ASSERT_EQUAL_PTR(job, sched_get_job(&sched, 42));
TEST_ASSERT_EQUAL_PTR(job, sched_get_job(&sched.core, 42));
/* job owns ru now; kill_sched_job/free_job_rusages will release it */
}