private boolean tryTaskPreemption(TaskInfo taskInfo) {
      // Find a lower priority task that can be preempted on a particular host.
      // ONLY if there's no pending preemptions on that host to avoid preempting twice for a task.
      Set<String> potentialHosts = null; // null => preempt on any host.
      readLock.lock();
      try {
        // Protect against a bad location being requested.
        if (taskInfo.requestedHosts != null && taskInfo.requestedHosts.length != 0) {
          potentialHosts = Sets.newHashSet(taskInfo.requestedHosts);
        }
        if (potentialHosts != null) {
          // Preempt on specific host
          boolean shouldPreempt = true;
          for (String host : potentialHosts) {
            // Preempt only if there are no pending preemptions on the same host
            // When the preemption registers, the request at the highest priority will be given the slot,
            // even if the initial preemption was caused by some other task.
            // TODO Maybe register which task the preemption was for, to avoid a bad non-local allocation.
            MutableInt pendingHostPreemptions = pendingPreemptionsPerHost.get(host);
            if (pendingHostPreemptions != null && pendingHostPreemptions.intValue() > 0) {
              shouldPreempt = false;
              LOG.debug("No preempt candidate for task={}. Found an existing preemption request on host={}, pendingPreemptionCount={}",
                  taskInfo.task, host, pendingHostPreemptions.intValue());
              break;
            }
          }

          if (!shouldPreempt) {
            LOG.debug("No preempt candidate for {} on potential hosts={}. An existing preemption request exists",
                taskInfo.task, potentialHosts);
            return false;
          }
        } else {
          // Unknown requested host -- Request for a preemption if there's none pending. If a single preemption is pending,
          // and this is the next task to be assigned, it will be assigned once that slot becomes available.
          if (pendingPreemptions.get() != 0) {
            LOG.debug("Skipping preempt candidate since there are {} pending preemption request. For task={}",
                pendingPreemptions.get(), taskInfo);
            return false;
          }
        }

        LOG.debug("Attempting preempt candidate for task={}, priority={} on potential hosts={}. pendingPreemptions={}",
            taskInfo.task, taskInfo.priority, potentialHosts == null ? "ANY" : potentialHosts, pendingPreemptions.get());
        return addTaskPreemptionCandidate(speculativeTasks, taskInfo, potentialHosts) ||
            addTaskPreemptionCandidate(guaranteedTasks, taskInfo, potentialHosts);
      } finally {
        readLock.unlock();
      }
    }
Go through the running tasks Tree in descending priority and find a candidate to preempt. The candidate should be:
1. lower priority than forTask
2. below forTask in the DAG
3. not considered already for preemption
A successful candidate is added to the preemptionCandidates queue for preemption by the scheduling loop.
@param runningTasks Tree of running tasks
@param forTask Task to find preemption candidate for
@param preemptHosts Hosts preference
@return true when preemption candidate is found
llap-tez/src/java/org/apache/hadoop/hive/llap/tezplugins/LlapTaskSchedulerService.java