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

@ -67,25 +67,31 @@
* which the REAL plugin.c now provides in this TU) as
* test_picker_config_fields.c uses for its own schedobj.c-only include.
* ---------------------------------------------------------------------- */
xce_sched_user_t* sched_get_user(xce_scheduler_t* s, char* n)
/* sched_get_user/sched_get_project/sched_get_queue/sched_get_job/
* sched_add_user/sched_add_project relocated to core.h (scheduler-core
* spec, task 4.1) -- now operate on xce_sched_core_t*, not
* xce_scheduler_t*. Kept as stubs here (not pulling in core.c's real
* implementations): this file never exercises make_sched_job/queue
* lookup, only picker registration/resolution. */
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;
}
xce_sched_queue_t* sched_get_queue(xce_scheduler_t* s, char* n)
xce_sched_queue_t* sched_get_queue(xce_sched_core_t* s, char* n)
{
(void)s;
(void)n;
return NULL;
}
xce_sched_job_t* sched_get_job(xce_scheduler_t* s, uint64_t jobid)
xce_sched_job_t* sched_get_job(xce_sched_core_t* s, uint64_t jobid)
{
(void)s;
(void)jobid;
@ -97,13 +103,13 @@ xce_job_account_t* make_job_account(xce_job_alloc_t* 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)
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_scheduler_t* s, xce_sched_project_t* p)
int sched_add_project(xce_sched_core_t* s, xce_sched_project_t* p)
{
(void)s;
(void)p;
@ -146,7 +152,7 @@ void setUp(void) { return; }
void tearDown(void) { return; }
/* ---------------------------------------------------------------------- */
/* Fixture: a real sched->plugins kvmgr (same setup scheduler.c's
/* Fixture: a real sched->core.plugins kvmgr (same setup scheduler.c's
* sched_plugin_init() uses) plus the xstring/CSE intern tables
* sched_set_default_job_pick_plugin()'s makeString() call needs. Nothing is
* torn down between tests (suite convention, ASAN_OPTIONS=detect_leaks=0). */
@ -161,8 +167,8 @@ static void fixture_init(xce_scheduler_t* sched)
memset(sched, 0, sizeof(*sched));
resreq_init(1);
xstring_table_init(1024 * 16);
sched->plugins = makeInstance(&xkvmgr_type, &params);
TEST_ASSERT_NOT_NULL(sched->plugins);
sched->core.plugins = makeInstance(&xkvmgr_type, &params);
TEST_ASSERT_NOT_NULL(sched->core.plugins);
}
/* Minimal legacy (job_elect_fn-only) plugin, mirroring
@ -202,9 +208,9 @@ static void test_register_builtin_fcfs_registers_under_name_builtin_fcfs(void)
rc = register_builtin_fcfs(&sched);
TEST_ASSERT_GREATER_OR_EQUAL(0, rc);
lock(sched.plugins, RTTI_LOCK_READ);
rc = key_find(sched.plugins, "builtin_fcfs", (void**)&found);
unlock(sched.plugins);
lock(sched.core.plugins, RTTI_LOCK_READ);
rc = key_find(sched.core.plugins, "builtin_fcfs", (void**)&found);
unlock(sched.core.plugins);
TEST_ASSERT_GREATER_THAN(0, rc);
TEST_ASSERT_NOT_NULL(found);
@ -224,9 +230,9 @@ static void test_register_builtin_fcfs_is_native_not_legacy(void)
fixture_init(&sched);
TEST_ASSERT_GREATER_OR_EQUAL(0, register_builtin_fcfs(&sched));
lock(sched.plugins, RTTI_LOCK_READ);
key_find(sched.plugins, "builtin_fcfs", (void**)&found);
unlock(sched.plugins);
lock(sched.core.plugins, RTTI_LOCK_READ);
key_find(sched.core.plugins, "builtin_fcfs", (void**)&found);
unlock(sched.core.plugins);
TEST_ASSERT_NOT_NULL(found);
TEST_ASSERT_NULL(found->job_elect_fn);
@ -264,9 +270,9 @@ static void test_register_builtin_fcfs_runs_init_via_init_fn_adapter(void)
fixture_init(&sched);
TEST_ASSERT_GREATER_OR_EQUAL(0, register_builtin_fcfs(&sched));
lock(sched.plugins, RTTI_LOCK_READ);
key_find(sched.plugins, "builtin_fcfs", (void**)&found);
unlock(sched.plugins);
lock(sched.core.plugins, RTTI_LOCK_READ);
key_find(sched.core.plugins, "builtin_fcfs", (void**)&found);
unlock(sched.core.plugins);
TEST_ASSERT_NOT_NULL(found);
TEST_ASSERT_NOT_NULL(found->data);
@ -286,10 +292,10 @@ static void test_unset_job_pick_plugin_resolves_to_builtin_fcfs_by_default(void)
fixture_init(&sched);
TEST_ASSERT_GREATER_OR_EQUAL(0, register_builtin_fcfs(&sched));
TEST_ASSERT_NULL(sched.job_pick_plugin);
TEST_ASSERT_NULL(sched.core.job_pick_plugin);
sched_set_default_job_pick_plugin(&sched);
TEST_ASSERT_EQUAL_STRING("builtin_fcfs", sched.job_pick_plugin);
TEST_ASSERT_EQUAL_STRING("builtin_fcfs", sched.core.job_pick_plugin);
rc = sched_resolve_job_picker(&sched, &resolved);
@ -316,7 +322,7 @@ test_unregistered_configured_name_fails_with_enoent_not_silent_fallback(void)
fixture_init(&sched);
TEST_ASSERT_GREATER_OR_EQUAL(0, register_builtin_fcfs(&sched));
sched.job_pick_plugin = "totally_unregistered_picker_name";
sched.core.job_pick_plugin = "totally_unregistered_picker_name";
rc = sched_resolve_job_picker(&sched, &resolved);
@ -350,7 +356,7 @@ static void test_registered_but_not_a_picker_fails_with_einval_not_enoent(void)
* categories), which plugin_register() leaves untouched (task 1.2). */
TEST_ASSERT_GREATER_OR_EQUAL(0, plugin_register(&sched, non_picker));
sched.job_pick_plugin = "not_a_picker";
sched.core.job_pick_plugin = "not_a_picker";
rc = sched_resolve_job_picker(&sched, &resolved);
@ -369,7 +375,7 @@ test_unset_job_pick_plugin_without_defaulting_fails_with_einval(void)
int rc;
fixture_init(&sched);
TEST_ASSERT_NULL(sched.job_pick_plugin);
TEST_ASSERT_NULL(sched.core.job_pick_plugin);
rc = sched_resolve_job_picker(&sched, &resolved);
@ -403,7 +409,7 @@ test_resolved_legacy_plugin_has_job_elect_fn_set_selecting_legacy_branch(void)
legacy = make_legacy_plugin("test_legacy_picker_for_wiring");
TEST_ASSERT_GREATER_OR_EQUAL(0, plugin_register(&sched, legacy));
sched.job_pick_plugin = "test_legacy_picker_for_wiring";
sched.core.job_pick_plugin = "test_legacy_picker_for_wiring";
rc = sched_resolve_job_picker(&sched, &resolved);
@ -429,7 +435,7 @@ test_resolved_builtin_fcfs_has_job_elect_fn_null_selecting_native_branch(void)
fixture_init(&sched);
TEST_ASSERT_GREATER_OR_EQUAL(0, register_builtin_fcfs(&sched));
sched.job_pick_plugin = "builtin_fcfs"; /* explicit, not defaulted */
sched.core.job_pick_plugin = "builtin_fcfs"; /* explicit, not defaulted */
rc = sched_resolve_job_picker(&sched, &resolved);
@ -460,12 +466,12 @@ test_legacy_and_native_pickers_coexist_and_resolve_independently(void)
TEST_ASSERT_GREATER_OR_EQUAL(0, plugin_register(&sched, legacy));
TEST_ASSERT_GREATER_OR_EQUAL(0, register_builtin_fcfs(&sched));
sched.job_pick_plugin = "xce_sched_fcfs_stub";
sched.core.job_pick_plugin = "xce_sched_fcfs_stub";
rc = sched_resolve_job_picker(&sched, &resolved);
TEST_ASSERT_EQUAL_INT(0, rc);
TEST_ASSERT_NOT_NULL(resolved->job_elect_fn);
sched.job_pick_plugin = "builtin_fcfs";
sched.core.job_pick_plugin = "builtin_fcfs";
rc = sched_resolve_job_picker(&sched, &resolved);
TEST_ASSERT_EQUAL_INT(0, rc);
TEST_ASSERT_NULL(resolved->job_elect_fn);