public void execute() throws Exception {
    final String activeShardCountFailure = checkActiveShardCount();
    final ShardRouting primaryRouting = primary.routingEntry();
    final ShardId primaryId = primaryRouting.shardId();
    if (activeShardCountFailure != null) {
      finishAsFailed(
          new UnavailableShardsException(
              primaryId,
              "{} Timeout: [{}], request: [{}]",
              activeShardCountFailure,
              request.timeout(),
              request));
      return;
    }

    totalShards.incrementAndGet();
    pendingShards.incrementAndGet();
    primaryResult = primary.perform(request);
    final ReplicaRequest replicaRequest = primaryResult.replicaRequest();
    assert replicaRequest.primaryTerm() > 0 : "replicaRequest doesn't have a primary term";
    if (logger.isTraceEnabled()) {
      logger.trace(
          "[{}] op [{}] completed on primary for request [{}]", primaryId, opType, request);
    }

    performOnReplicas(primaryId, replicaRequest);

    successfulShards.incrementAndGet();
    decPendingAndFinishIfNeeded();
  }
 @Override
 public void readFrom(StreamInput in) throws IOException {
   shardId = in.readVInt();
   request = newReplicaRequestInstance();
   request.readFrom(in);
 }
 @Override
 public void writeTo(StreamOutput out) throws IOException {
   out.writeVInt(shardId);
   request.writeTo(out);
 }
    /** send operation to the given node or perform it if local */
    void performOnReplica(final ShardRouting shard, final String nodeId) {
      // if we don't have that node, it means that it might have failed and will be created again,
      // in
      // this case, we don't have to do the operation, and just let it failover
      if (!observer.observedState().nodes().nodeExists(nodeId)) {
        onReplicaFailure(nodeId, null);
        return;
      }

      replicaRequest.internalShardId = shardIt.shardId();

      if (!nodeId.equals(observer.observedState().nodes().localNodeId())) {
        final DiscoveryNode node = observer.observedState().nodes().get(nodeId);
        transportService.sendRequest(
            node,
            transportReplicaAction,
            replicaRequest,
            transportOptions,
            new EmptyTransportResponseHandler(ThreadPool.Names.SAME) {
              @Override
              public void handleResponse(TransportResponse.Empty vResponse) {
                onReplicaSuccess();
              }

              @Override
              public void handleException(TransportException exp) {
                logger.trace(
                    "[{}] transport failure during replica request [{}] ",
                    exp,
                    node,
                    replicaRequest);
                if (ignoreReplicaException(exp)) {
                  onReplicaFailure(nodeId, exp);
                } else {
                  logger.warn(
                      "{} failed to perform {} on node {}",
                      exp,
                      shardIt.shardId(),
                      actionName,
                      node);
                  shardStateAction.shardFailed(
                      shard,
                      indexMetaData.getIndexUUID(),
                      "failed to perform " + actionName + " on replica on node " + node,
                      exp,
                      shardFailedTimeout,
                      new ReplicationFailedShardStateListener(nodeId, exp));
                }
              }
            });
      } else {
        try {
          threadPool
              .executor(executor)
              .execute(
                  new AbstractRunnable() {
                    @Override
                    protected void doRun() {
                      try {
                        shardOperationOnReplica(shard.shardId(), replicaRequest);
                        onReplicaSuccess();
                      } catch (Throwable e) {
                        onReplicaFailure(nodeId, e);
                        failReplicaIfNeeded(shard.index(), shard.id(), e);
                      }
                    }

                    // we must never reject on because of thread pool capacity on replicas
                    @Override
                    public boolean isForceExecution() {
                      return true;
                    }

                    @Override
                    public void onFailure(Throwable t) {
                      onReplicaFailure(nodeId, t);
                    }
                  });
        } catch (Throwable e) {
          failReplicaIfNeeded(shard.index(), shard.id(), e);
          onReplicaFailure(nodeId, e);
        }
      }
    }