private void fillDataNodeTrackers() {
      Map<DataNodeId, List<RemoteReplicaInfo>> dataNodeToRemoteReplicaInfo = selectReplicas(getRemoteReplicaInfos());

      int currentStartGroupId = 0;

      for (Map.Entry<DataNodeId, List<RemoteReplicaInfo>> entry : dataNodeToRemoteReplicaInfo.entrySet()) {
        DataNodeId remoteHost = entry.getKey();
        List<RemoteReplicaInfo> remoteReplicasPerNode = entry.getValue();

        DataNodeTracker dataNodeTracker =
            new DataNodeTracker(remoteHost, remoteReplicasPerNode, maxReplicaCountPerRequest, currentStartGroupId, time,
                threadThrottleDurationMs);
        logger.trace("Thread name: {} for datanode {} create datanode tracker {}", threadName, remoteHost,
            dataNodeTracker);

        dataNodeTrackers.add(dataNodeTracker);
        currentStartGroupId = dataNodeTracker.getMaxGroupId() + 1;
      }
    }
Creates Data node trackers for every data node
Every datanode tracker has active groups and standby group
For each data node tracker, only one stand by group is present to reduce cross colo requests
Active groups have maximum {@link #maxReplicaCountPerRequest}  preassigned replicas
Across all datanode tracker group ids are unique
ambry-replication/src/main/java/com/github/ambry/replication/ReplicaThread.java