private void addReplicasToPool(List<? extends ReplicaId> replicas, List<? extends ReplicaId> offlineReplicas,
      boolean shuffleReplicas, boolean crossColoEnabled) {
    LinkedList<ReplicaId> backupReplicas = new LinkedList<>();
    LinkedList<ReplicaId> downReplicas = new LinkedList<>();
    if (shuffleReplicas) {
      Collections.shuffle(replicas);
    }

    // The priority here is local dc replicas, originating dc replicas, other dc replicas, down replicas.
    // To improve read-after-write performance across DC, we prefer to take local and originating replicas only,
    // which can be done by setting includeNonOriginatingDcReplicas False.
    List<ReplicaId> examinedReplicas = new ArrayList<>();
    int numLocalAndLiveReplicas = 0;
    int numRemoteOriginatingDcAndLiveReplicas = 0;
    for (ReplicaId replicaId : replicas) {
      examinedReplicas.add(replicaId);
      String replicaDcName = replicaId.getDataNodeId().getDatacenterName();
      boolean isLocalDcReplica = replicaDcName.equals(datacenterName);
      boolean isOriginatingDcReplica = replicaDcName.equals(originatingDcName);

      if (!replicaId.isDown()) {
        if (isLocalDcReplica) {
          numLocalAndLiveReplicas++;
          addToBeginningOfPool(replicaId);
        } else if (crossColoEnabled && isOriginatingDcReplica) {
          numRemoteOriginatingDcAndLiveReplicas++;
          addToEndOfPool(replicaId);
        } else if (crossColoEnabled) {
          backupReplicas.addFirst(replicaId);
        }
      } else {
        if (isLocalDcReplica) {
          downReplicas.addFirst(replicaId);
        } else if (crossColoEnabled) {
          downReplicas.addLast(replicaId);
        }
      }
    }
    List<ReplicaId> backupReplicasToCheck = new ArrayList<>(backupReplicas);
    List<ReplicaId> downReplicasToCheck = new ArrayList<>(downReplicas);

    // Add replicas that are neither in local dc nor in originating dc.
    backupReplicas.forEach(this::addToEndOfPool);

    if (routerConfig.routerOperationTrackerIncludeDownReplicas) {
      // Add those replicas deemed by native failure detector to be down
      downReplicas.forEach(this::addToEndOfPool);
      // Add those replicas deemed by Helix to be down (offline). This only applies to GET operation.
      // Adding this logic to mitigate situation where one or more Zookeeper clusters are suddenly unavailable while
      // ambry servers are still up.
      if (routerOperation == RouterOperation.GetBlobOperation
          || routerOperation == RouterOperation.GetBlobInfoOperation) {
        List<ReplicaId> remoteOfflineReplicas = new ArrayList<>();
        for (ReplicaId replica : offlineReplicas) {
          if (replica.getDataNodeId().getDatacenterName().equals(datacenterName)) {
            addToEndOfPool(replica);
          } else {
            remoteOfflineReplicas.add(replica);
          }
        }
        remoteOfflineReplicas.forEach(this::addToEndOfPool);
      }
    }

    maybeDeprioritizeLocalBootstrapReplicas(numLocalAndLiveReplicas);
    maybeShuffleWithRemoteReplicas(numLocalAndLiveReplicas, numRemoteOriginatingDcAndLiveReplicas);
    int replicaPoolSize = replicaPool.size();
    possibleRunOfflineRepair = possibleRunOfflineRepair(replicaPoolSize);
    if (replicaPoolSize < getSuccessTarget()) {
      if (possibleRunOfflineRepair) {
        logger.info("RepairRequest: Not enough quorum for delete but give it a try since offline repair is enabled {}",
            blobId);
      } else {
        // MockPartitionId.getReplicaIds() is returning a shared reference which may cause race condition.
        // Please report the test failure if you run into this exception.
        throw new IllegalArgumentException(
            generateErrorMessage(partitionId, examinedReplicas, replicaPool, backupReplicasToCheck, downReplicasToCheck,
                routerOperation));
      }
    }
  }
In a case where a certain dc is decommissioned and blobs previously uploaded to this dc now have an unrecognizable
dc id. Current clustermap code will treat originating dc as null if dc id is not identifiable. To improve success
rate of cross-colo requests(GET/DELETE/TTLUpdate), operation tracker should be allowed to try remote dc with most
replicas first. This is useful in cluster with "unbalanced" replica distribution (i.e. 3 replicas in local dc and
1 replica per remote dc)
@param originatingDcName The originating Dc name
@param replicas The list of replicas
@return The reassigned originating dc name.
ambry-router/src/main/java/com/github/ambry/router/SimpleOperationTracker.java