Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions session_manager/src/scheduler/plugins/gang.rs
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,7 @@ impl Plugin for GangPlugin {
fn on_session_bind(&mut self, ssn: SessionInfoPtr) {
if let Some(state) = self.ssn_state.get_mut(&ssn.id) {
state.bound += 1;
state.incomplete_tasks = state.incomplete_tasks.saturating_sub(1);
Comment on lines 156 to +157

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

critical

Double-Counting & Premature Fulfillment Bug

Decrementing incomplete_tasks here introduces a critical logic bug:

  1. Conceptual Issue: A task bound to an executor is still incomplete (it is in Running or Binding state, not Succeed/Failed/Cancelled). Therefore, binding a task does not reduce the number of incomplete tasks.
  2. Double-Counting: The gang plugin evaluates fulfillment using total >= needed, where total = allocated + bound and needed = div_ceil(incomplete_tasks, batch_size) * batch_size. If you decrement incomplete_tasks (reducing needed) and increment bound (increasing total) simultaneously, you double-count the progress.

For example, with batch_size = 2 and 4 pending tasks:

  • Initially: needed = 4, total = 0.
  • Bind 1 task: needed = 4, total = 1.
  • Bind 2 tasks: needed = 2, total = 2 -> is_fulfilled becomes true prematurely, leaving the remaining 2 tasks without executors.

Revert this change to keep incomplete_tasks static during the scheduling cycle.

Suggested change
state.bound += 1;
state.incomplete_tasks = state.incomplete_tasks.saturating_sub(1);
state.bound += 1;

}
}

Expand All @@ -166,6 +167,7 @@ impl Plugin for GangPlugin {
fn on_session_unbind(&mut self, ssn: SessionInfoPtr) {
if let Some(state) = self.ssn_state.get_mut(&ssn.id) {
state.bound = state.bound.saturating_sub(1);
state.incomplete_tasks = state.incomplete_tasks.saturating_add(1);
Comment on lines 169 to +170

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

critical

Double-Counting & Premature Fulfillment Bug

Incrementing incomplete_tasks here is the inverse of the double-counting bug introduced in on_session_bind. Since unbinding a task does not change its completion status (it remains incomplete), incomplete_tasks should not be modified here. Revert this change to keep incomplete_tasks static during the scheduling cycle.

Suggested change
state.bound = state.bound.saturating_sub(1);
state.incomplete_tasks = state.incomplete_tasks.saturating_add(1);
state.bound = state.bound.saturating_sub(1);

}
}
}
Expand Down
Loading