From 6577e04196595c402aae342c4fd1af49fcbf398b Mon Sep 17 00:00:00 2001 From: Rongsong Shen Date: Sun, 6 Sep 2026 04:28:48 +0000 Subject: [PATCH] feat(resreq-maxtasks-wiring): wire snapshot-restore ingest to real task count snapshot_load.c's job-restore path now calls apply_job_task_count() with the job's already-restored mintasks/maxtasks, right after its resreq parse succeeds and before snapshot_build_schedobj() reads the resreq's task count for its fingerprint. This is the simulation/replay driver's only live call site (xce_sched_core_load_snapshot(), reached via --sim), independent of and parallel to task 2.1's fresh-ingest wiring in core_events.c. Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_01XYdtrEWWZfKRRGED7raEYg --- .kiro/specs/resreq-maxtasks-wiring/tasks.md | 2 +- src/scheduler/src/snapshot_load.c | 16 +++++ .../testsuite/test_snapshot_save_load.c | 71 +++++++++++++++++++ 3 files changed, 88 insertions(+), 1 deletion(-) diff --git a/.kiro/specs/resreq-maxtasks-wiring/tasks.md b/.kiro/specs/resreq-maxtasks-wiring/tasks.md index 3cdf6238..bdc7537f 100644 --- a/.kiro/specs/resreq-maxtasks-wiring/tasks.md +++ b/.kiro/specs/resreq-maxtasks-wiring/tasks.md @@ -16,7 +16,7 @@ - _Requirements: 1.1_ - _Boundary: core_events.c (core_build_job)_ -- [ ] 2.2 (P) Wire simulation/replay snapshot-restore ingest to apply the same real task count +- [x] 2.2 (P) Wire simulation/replay snapshot-restore ingest to apply the same real task count - Call the new helper immediately after the snapshot-restore path's existing resource-request parse, using the job's already-restored minimum/maximum task count - Observable: a job reconstructed from a saved snapshot via the simulation/replay driver has its dispatched resource request reflect the same real task count fresh ingest would produce - _Requirements: 1.3_ diff --git a/src/scheduler/src/snapshot_load.c b/src/scheduler/src/snapshot_load.c index f2e77924..3bca0c51 100644 --- a/src/scheduler/src/snapshot_load.c +++ b/src/scheduler/src/snapshot_load.c @@ -444,6 +444,22 @@ int xce_sched_core_load_snapshot(xce_sched_core_t* core, errmsg ? errmsg : "(null)"); FREEUP(errmsg); FREEUP(job->resreq); + } else { + /* resreq-maxtasks-wiring task 2.2 (bug-1770, Req 1.3): + * overwrite the just-parsed resreq's standalone + * primary minTasks/maxTasks with the job's real + * restored task count -- job->mintasks/maxtasks are + * already correctly restored from wj->submit-> + * mintasks/maxtasks above, BEFORE this parse (unlike + * core_build_job()'s ordering in core_events.c, task + * 2.1). Must run strictly before + * snapshot_build_schedobj() below reads the resreq's + * task count for its own fingerprint computation. No-op + * for a COMPOUND/ALTER resreq (apply_job_task_count()'s + * own tag gate) -- out of this task's boundary per + * design.md. */ + apply_job_task_count(job->resreq, job->mintasks, + job->maxtasks); } } diff --git a/src/scheduler/testsuite/test_snapshot_save_load.c b/src/scheduler/testsuite/test_snapshot_save_load.c index 2e8b40db..706a2b63 100644 --- a/src/scheduler/testsuite/test_snapshot_save_load.c +++ b/src/scheduler/testsuite/test_snapshot_save_load.c @@ -1175,6 +1175,76 @@ test_snapshot_load_builds_schedobj_for_primary_compound_and_alter_resreq(void) restored_alter->schedobj->project); } +/* + * resreq-maxtasks-wiring task 2.2 (bug-1770, Req 1.3): a job restored from a + * saved snapshot -- live only via the simulation/replay driver + * (design.md's "Existing Architecture Analysis": xce_sched_core_load_ + * snapshot()'s only real caller is sim.c's sim_locate_and_load_snapshot(), + * reachable only through main.c's --sim FILE offline-replay flag) -- must + * derive the SAME standalone primary resreq task count fresh ingest would + * (core_events.c's core_build_job(), task 2.1). job->mintasks/maxtasks are + * already correctly restored from wj->submit->mintasks/maxtasks earlier in + * this same function (before the resreq parse, unlike core_build_job()'s + * ordering) -- but before this fix, nothing applied them onto the just- + * parsed resreq's standalone primary, which parse_resreq_primary() always + * leaves at minTasks==maxTasks==1 regardless of the job's real requested + * count. */ +static void +test_snapshot_load_wires_real_task_count_into_resreq_primary(void) +{ + xce_sched_core_t core; + sched_snapshot_data_t in; + xce_jobs_data_t jobs_data; + xce_queue_t wire_queue; + xce_queue_t* queues[1]; + xce_job_t* job; + xce_job_t* jobs[1]; + xce_sched_job_t* restored; + int rc; + + memset(&g_stub_state_a, 0, sizeof(g_stub_state_a)); + fixture_init(&core, &g_stub_plugin_a); + + memset(&wire_queue, 0, sizeof(wire_queue)); + wire_queue.queue = "normal"; + wire_queue.priority = 1; + wire_queue.status = QUEUE_STAT_OPEN; + queues[0] = &wire_queue; + + job = make_job_with_resreq(601, JOB_STAT_PEND, "normal", "alice", "proj1", + "type == any"); + job->submit->mintasks = 4; + job->submit->maxtasks = 6; + jobs[0] = job; + + memset(&jobs_data, 0, sizeof(jobs_data)); + jobs_data.count = 1; + jobs_data.jobs = jobs; + + memset(&in, 0, sizeof(in)); + in.jobs = &jobs_data; + in.queues = queues; + in.n_queues = 1; + + rc = xce_sched_core_load_snapshot(&core, &in); + TEST_ASSERT_EQUAL_INT(0, rc); + + restored = sched_get_job(&core, 601); + TEST_ASSERT_NOT_NULL(restored); + TEST_ASSERT_EQUAL_UINT32(4, restored->mintasks); + TEST_ASSERT_EQUAL_UINT32(6, restored->maxtasks); + + TEST_ASSERT_NOT_NULL(restored->resreq); + TEST_ASSERT_EQUAL_INT(XCE_RESREQ_PRIMARY, restored->resreq->tag); + TEST_ASSERT_NOT_NULL(restored->resreq->u.primary); + + /* The fix under test: the standalone primary's minTasks/maxTasks must + * reflect the job's real restored task count, not parse_resreq_ + * primary()'s always-1 default. */ + TEST_ASSERT_EQUAL_INT(4, restored->resreq->u.primary->minTasks); + TEST_ASSERT_EQUAL_INT(6, restored->resreq->u.primary->maxTasks); +} + /* Regression-safety test (NOT a new feature): a job whose resreq fails to * parse on load is a pre-existing, out-of-boundary gap (design.md "Known * limitation") that task 1.2 must NOT try to fix -- it must only make sure @@ -2473,6 +2543,7 @@ int main(void) test_snapshot_save_then_load_produces_behaviorally_equivalent_core); RUN_TEST( test_snapshot_load_builds_schedobj_for_primary_compound_and_alter_resreq); + RUN_TEST(test_snapshot_load_wires_real_task_count_into_resreq_primary); RUN_TEST( test_snapshot_load_leaves_schedobj_null_when_resreq_fails_to_parse); RUN_TEST(