fix(scheduler): a failed COMPOUND leaves no partial allocation (bug-1766)
When a later primary of a COMPOUND failed, sched_make_compound_alloc_
still moved the earlier primaries' merged allocation onto the schedobj,
so a job decided PEND carried a partial allocation that the next
successful round overwrote and leaked. The merged allocation is now
published only when every primary succeeds and freed otherwise. No
resource-state rollback is needed: the primaries' uncommitted debits live
in ctx.uncomitted, per-attempt scratch freed by sched_ctx_fini(), and
schedobj->alloc's only reader is the dispatch path. The ALTER loop's
per-alternative cleanup (added with bug-1769) is now redundant and removed.
Test: "1*{..} + 5*{..}" on 2x2 slots PENDs with schedobj->alloc NULL
(held the first primary's allocation before). Scheduler suite 87/87.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
b63bb581d4
commit
601b245e5a
2 changed files with 39 additions and 7 deletions
|
|
@ -315,8 +315,17 @@ static int sched_make_compound_alloc_(xce_sched_core_t* core,
|
|||
}
|
||||
}
|
||||
|
||||
/* bug-1766: a compound is allocated only if EVERY primary is -- when a
|
||||
* later primary fails, drop the earlier primaries' allocation instead
|
||||
* of leaving a partial one on obj. Their uncommitted debits live in
|
||||
* ctx.uncomitted, per-attempt scratch freed by sched_ctx_fini(), so
|
||||
* nothing else needs undoing. */
|
||||
if (merged != NULL) {
|
||||
MOVE_PTR(obj->alloc, merged);
|
||||
if (rc > 0) {
|
||||
MOVE_PTR(obj->alloc, merged);
|
||||
} else {
|
||||
free_JobAlloc_ptr(&merged);
|
||||
}
|
||||
}
|
||||
|
||||
if (ctx.reason != NULL) {
|
||||
|
|
@ -356,12 +365,6 @@ static int sched_make_alter_allocation(xce_sched_core_t* core,
|
|||
if (rc > 0) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* a failed alternative may leave a partial allocation (no
|
||||
* rollback yet, bug-1766) -- drop it before trying the next one */
|
||||
if (obj->alloc != NULL) {
|
||||
free_JobAlloc_ptr(&(obj->alloc));
|
||||
}
|
||||
}
|
||||
|
||||
/* FIXME: merge pend reason from all children */
|
||||
|
|
|
|||
|
|
@ -847,6 +847,34 @@ static void test_compound_primaries_on_same_host_merge(void)
|
|||
"entry");
|
||||
}
|
||||
|
||||
/*
|
||||
* bug-1766: when a later primary of a COMPOUND fails, the earlier
|
||||
* primaries' (merged) allocation was still moved onto the schedobj, so a
|
||||
* job reported PEND carried a partial allocation that the next successful
|
||||
* round overwrote and leaked. A failed compound must leave no allocation
|
||||
* (its uncommitted debits are per-attempt scratch, freed with the ctx).
|
||||
*/
|
||||
static void test_failed_compound_leaves_no_partial_allocation(void)
|
||||
{
|
||||
xce_scheduler_t* sched = start_sched();
|
||||
xce_decision_t* decision;
|
||||
xce_sched_job_t* sjob;
|
||||
|
||||
e2e_push_queue_and_workers(sched, "cmp4_queue");
|
||||
decision = e2e_dispatch_resreq(sched, JOB_ID + 7, "cmp4_queue",
|
||||
"1*{rusage[mem=1]} + 5*{rusage[mem=1]}");
|
||||
TEST_ASSERT_NOT_NULL(decision);
|
||||
TEST_ASSERT_EQUAL_INT_MESSAGE(XCE_DECISION_PEND, decision->op,
|
||||
"the 5-task primary cannot fit on 4 slots");
|
||||
|
||||
sjob = sched_get_job(&(sched->core), JOB_ID + 7);
|
||||
TEST_ASSERT_NOT_NULL(sjob);
|
||||
TEST_ASSERT_NULL_MESSAGE(sjob->schedobj->alloc,
|
||||
"a failed compound must not keep the first primary's partial "
|
||||
"allocation");
|
||||
TEST_ASSERT_NULL(sjob->allocs);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
UNITY_BEGIN();
|
||||
|
|
@ -858,5 +886,6 @@ int main(void)
|
|||
RUN_TEST(test_alter_falls_back_to_alternative_that_fits);
|
||||
RUN_TEST(test_compound_allocation_includes_every_primary);
|
||||
RUN_TEST(test_compound_primaries_on_same_host_merge);
|
||||
RUN_TEST(test_failed_compound_leaves_no_partial_allocation);
|
||||
return UNITY_END();
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue