private boolean hasPreviousStageFailed(Stage stage) {
    boolean failed = false;

    long prevStageId = stage.getStageId() - 1;

    if (prevStageId >= 0) {
      // Find previous stage instance
      String actionId = StageUtils.getActionId(stage.getRequestId(), prevStageId);
      Stage prevStage = db.getStage(actionId);

      // If the previous stage is skippable then we shouldn't automatically fail the given stage
      if (prevStage == null || prevStage.isSkippable()) {
        return false;
      }

      Map<Role, Integer> hostCountsForRoles = new HashMap<>();
      Map<Role, Integer> failedHostCountsForRoles = new HashMap<>();

      for (String host : prevStage.getHostRoleCommands().keySet()) {
        Map<String, HostRoleCommand> roleCommandMap = prevStage.getHostRoleCommands().get(host);
        for (String role : roleCommandMap.keySet()) {
          HostRoleCommand c = roleCommandMap.get(role);
          if (hostCountsForRoles.get(c.getRole()) == null) {
            hostCountsForRoles.put(c.getRole(), 0);
            failedHostCountsForRoles.put(c.getRole(), 0);
          }
          int hostCount = hostCountsForRoles.get(c.getRole());
          hostCountsForRoles.put(c.getRole(), hostCount + 1);
          if (c.getStatus().isFailedAndNotSkippableState()) {
            int failedHostCount = failedHostCountsForRoles.get(c.getRole());
            failedHostCountsForRoles.put(c.getRole(), failedHostCount + 1);
          }
        }
      }

      for (Role role : hostCountsForRoles.keySet()) {
        float failedHosts = failedHostCountsForRoles.get(role);
        float totalHosts = hostCountsForRoles.get(role);
        if (((totalHosts - failedHosts) / totalHosts) < prevStage.getSuccessFactor(role)) {
          failed = true;
        }
      }
    }
    return failed;
  }
Returns filtered list of stages such that the returned list is an ordered
list of stages that may be executed in parallel or in the order in which
they are presented.
<p/>
The specified stages must be ordered by request ID and may only contain the
next stage in progress per request (as returned by
{@link ActionDBAccessor#getFirstStageInProgressPerRequest()}. This is
because there is a requirement that within a request, no two stages may
ever run in parallel.
<p/>
The following rules will be applied to the list:
<ul>
<li>Stages are filtered such that the first stage in the list (assumed to
be the first pending stage from the earliest active request) has priority.
</li>
<li>No stage in any request may be executed before an earlier stage in the
same request. This requirement is automatically covered by virtue of the
supplied stages only being for the next stage in progress per request.</li>
<li>A stage in different request may be performed in parallel
if-and-only-if the relevant hosts for the stage in the later requests do
not intersect with the union of hosts from (pending) stages in earlier
requests. In order to accomplish this</li>
</ul>

@param firstStageInProgressPerRequest
         the stages to process, one stage per request
@return a list of stages that may be executed in parallel
ambari-server/src/main/java/org/apache/ambari/server/actionmanager/ActionScheduler.java