public synchronized void startAll() throws IOException {
   final DiscoveryNode pNode = getDiscoveryNode(primary.routingEntry().currentNodeId());
   primary.markAsRecovering(
       "store",
       new RecoveryState(primary.shardId(), true, RecoveryState.Type.STORE, pNode, pNode));
   primary.recoverFromStore();
   primary.updateRoutingEntry(ShardRoutingHelper.moveToStarted(primary.routingEntry()));
   for (IndexShard replicaShard : replicas) {
     recoverReplica(
         replicaShard,
         (replica, sourceNode) ->
             new RecoveryTarget(replica, sourceNode, recoveryListener, version -> {}));
   }
 }
 public void recoverReplica(
     IndexShard replica,
     BiFunction<IndexShard, DiscoveryNode, RecoveryTarget> targetSupplier,
     boolean markAsRecovering)
     throws IOException {
   final DiscoveryNode pNode = getPrimaryNode();
   final DiscoveryNode rNode = getDiscoveryNode(replica.routingEntry().currentNodeId());
   if (markAsRecovering) {
     replica.markAsRecovering(
         "remote",
         new RecoveryState(replica.shardId(), false, RecoveryState.Type.REPLICA, pNode, rNode));
   } else {
     assertEquals(replica.state(), IndexShardState.RECOVERING);
   }
   replica.prepareForIndexRecovery();
   RecoveryTarget recoveryTarget = targetSupplier.apply(replica, pNode);
   StartRecoveryRequest request =
       new StartRecoveryRequest(
           replica.shardId(),
           pNode,
           rNode,
           getMetadataSnapshotOrEmpty(replica),
           RecoveryState.Type.REPLICA,
           0);
   RecoverySourceHandler recovery =
       new RecoverySourceHandler(
           primary,
           recoveryTarget,
           request,
           () -> 0L,
           e -> () -> {},
           (int) ByteSizeUnit.MB.toKB(1),
           logger);
   recovery.recoverToTarget();
   recoveryTarget.markAsDone();
   replica.updateRoutingEntry(ShardRoutingHelper.moveToStarted(replica.routingEntry()));
 }