func()

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)
		}
	}
}