in pkg/scheduler/objects/queue.go [1862:1945]
func (sq *Queue) findEligiblePreemptionVictims(results map[string]*QueuePreemptionSnapshot, queuePath string, ask *Allocation, priorityMap map[string]int64, askPriority int64, fenced bool) {
if sq == nil {
return
}
if sq.GetQueuePath() == queuePath {
return
}
if sq.IsLeafQueue() {
// leaf queue, skip queue if preemption is disabled
if sq.GetPreemptionPolicy() == policies.DisabledPreemptionPolicy {
return
}
victims := sq.createPreemptionSnapshot(results, queuePath)
// skip this queue if we are within guaranteed limits
remaining := results[sq.QueuePath].GetRemainingGuaranteedResource()
if remaining != nil && resources.StrictlyGreaterThanOrEquals(remaining, resources.Zero) {
return
}
// walk allocations and select those that are equal or lower than current priority
for _, app := range sq.GetCopyOfApps() {
for _, alloc := range app.GetAllAllocations() {
// at least any one of the ask resource type should match with potential victim
if !ask.GetAllocatedResource().MatchAny(alloc.GetAllocatedResource()) {
continue
}
// skip tasks which require a specific node
if alloc.GetRequiredNode() != "" {
continue
}
// skip placeholder tasks which are marked released
if alloc.IsReleased() {
continue
}
// skip allocs which have already been preempted
if alloc.IsPreempted() {
continue
}
// if we have encountered a fence then all tasks are eligible for preemption
// otherwise the task is a candidate if its priority is less than or equal to the ask priority
if fenced || int64(alloc.GetPriority()) <= askPriority {
victims.PotentialVictims = append(victims.PotentialVictims, alloc)
}
}
}
// remove from potential victim list if there are no potential victims
if len(victims.PotentialVictims) == 0 {
delete(results, sq.QueuePath)
}
} else {
// parent queue, walk child queues and evaluate
for _, child := range sq.GetCopyOfChildren() {
childFenced := false
childPriority, ok := priorityMap[child.QueuePath]
if !ok {
// we are evaluating a distinct subtree from the one containing the ask, so check policy to compute relative priority
policy, offset := child.GetPriorityPolicyAndOffset()
if policy == policies.FencePriorityPolicy {
// if the queue offset is greater than the ask priority, then none of the child subtasks may be preempted
if int64(offset) > askPriority {
continue
}
// all tasks in subtree can be preempted, so mark fenced as true
childFenced = true
childPriority = askPriority
} else {
// queue is not fenced, evaluate child by subtracting the offset from the ask when traversing downward
childPriority = askPriority - int64(offset)
}
}
// retrieve candidate tasks from child queue
child.findEligiblePreemptionVictims(results, queuePath, ask, priorityMap, childPriority, fenced || childFenced)
}
}
}