private AsyncSingleAction(Request request, ActionListener<Response> listener) {
      this.listener = listener;

      ClusterState clusterState = clusterService.state();
      nodes = clusterState.nodes();
      ClusterBlockException blockException = checkGlobalBlock(clusterState);
      if (blockException != null) {
        throw blockException;
      }

      String concreteSingleIndex;
      if (resolveIndex(request)) {
        concreteSingleIndex =
            clusterState.metaData().concreteSingleIndex(request.index(), request.indicesOptions());
      } else {
        concreteSingleIndex = request.index();
      }
      this.internalRequest = new InternalRequest(request, concreteSingleIndex);

      blockException = checkRequestBlock(clusterState, internalRequest);
      if (blockException != null) {
        throw blockException;
      }
      this.shardsIt = shards(clusterState, internalRequest);
    }
    private AsyncSingleAction(Request request, ActionListener<Response> listener) {
      this.listener = listener;

      ClusterState clusterState = clusterService.state();
      if (logger.isTraceEnabled()) {
        logger.trace(
            "executing [{}] based on cluster state version [{}]", request, clusterState.version());
      }
      nodes = clusterState.nodes();
      ClusterBlockException blockException = checkGlobalBlock(clusterState);
      if (blockException != null) {
        throw blockException;
      }

      String concreteSingleIndex;
      if (resolveIndex(request)) {
        concreteSingleIndex =
            indexNameExpressionResolver.concreteSingleIndex(clusterState, request).getName();
      } else {
        concreteSingleIndex = request.index();
      }
      this.internalRequest = new InternalRequest(request, concreteSingleIndex);
      resolveRequest(clusterState, internalRequest);

      blockException = checkRequestBlock(clusterState, internalRequest);
      if (blockException != null) {
        throw blockException;
      }

      this.shardIt = shards(clusterState, internalRequest);
    }
 @Override
 public void readFrom(StreamInput in) throws IOException {
   super.readFrom(in);
   request = newRequest();
   request.readFrom(in);
   if (in.getVersion().onOrAfter(Version.V_1_4_0)) {
     shardId = ShardId.readShardId(in);
   } else {
     // older nodes will send the concrete index as part of the request
     shardId = new ShardId(request.index(), in.readVInt());
   }
 }
 @Override
 public void writeTo(StreamOutput out) throws IOException {
   super.writeTo(out);
   if (out.getVersion().before(Version.V_1_4_0)) {
     // older nodes expect the concrete index as part of the request
     request.index(shardId.getIndex());
   }
   request.writeTo(out);
   if (out.getVersion().onOrAfter(Version.V_1_4_0)) {
     shardId.writeTo(out);
   } else {
     out.writeVInt(shardId.id());
   }
 }
  @Override
  protected void doExecute(final Request request, final ActionListener<Response> listener) {
    ClusterState clusterState = clusterService.state();
    ClusterBlockException blockException = checkGlobalBlock(clusterState, request);
    if (blockException != null) {
      throw blockException;
    }
    // update to concrete index
    request.index(
        clusterState.metaData().concreteSingleIndex(request.index(), request.indicesOptions()));
    blockException = checkRequestBlock(clusterState, request);
    if (blockException != null) {
      throw blockException;
    }

    GroupShardsIterator groups;
    try {
      groups = shards(request);
    } catch (Throwable e) {
      listener.onFailure(e);
      return;
    }
    final AtomicInteger indexCounter = new AtomicInteger();
    final AtomicInteger failureCounter = new AtomicInteger();
    final AtomicInteger completionCounter = new AtomicInteger(groups.size());
    final AtomicReferenceArray<ShardActionResult> shardsResponses =
        new AtomicReferenceArray<>(groups.size());

    for (final ShardIterator shardIt : groups) {
      ShardRequest shardRequest = newShardRequestInstance(request, shardIt.shardId().id());

      // TODO for now, we fork operations on shardIt of the index
      shardRequest.beforeLocalFork(); // optimize for local fork
      shardRequest.operationThreaded(true);

      // no need for threaded listener, we will fork when its done based on the index request
      shardRequest.listenerThreaded(false);
      shardAction.execute(
          shardRequest,
          new ActionListener<ShardResponse>() {
            @Override
            public void onResponse(ShardResponse result) {
              shardsResponses.set(indexCounter.getAndIncrement(), new ShardActionResult(result));
              returnIfNeeded();
            }

            @Override
            public void onFailure(Throwable e) {
              failureCounter.getAndIncrement();
              int index = indexCounter.getAndIncrement();
              if (accumulateExceptions()) {
                shardsResponses.set(
                    index,
                    new ShardActionResult(
                        new DefaultShardOperationFailedException(
                            request.index, shardIt.shardId().id(), e)));
              }
              returnIfNeeded();
            }

            private void returnIfNeeded() {
              if (completionCounter.decrementAndGet() == 0) {
                List<ShardResponse> responses = Lists.newArrayList();
                List<ShardOperationFailedException> failures = Lists.newArrayList();
                for (int i = 0; i < shardsResponses.length(); i++) {
                  ShardActionResult shardActionResult = shardsResponses.get(i);
                  if (shardActionResult == null) {
                    assert !accumulateExceptions();
                    continue;
                  }
                  if (shardActionResult.isFailure()) {
                    assert accumulateExceptions() && shardActionResult.shardFailure != null;
                    failures.add(shardActionResult.shardFailure);
                  } else {
                    responses.add(shardActionResult.shardResponse);
                  }
                }

                assert failures.size() == 0 || failures.size() == failureCounter.get();
                listener.onResponse(
                    newResponseInstance(request, responses, failureCounter.get(), failures));
              }
            }
          });
    }
  }
 /**
  * Resolves the request, by default, simply setting the concrete index (if its aliased one). If
  * the resolve means a different execution, then return false here to indicate not to continue and
  * execute this request.
  */
 protected boolean resolveRequest(
     ClusterState state, Request request, ActionListener<Response> listener) {
   request.index(state.metaData().concreteIndex(request.index()));
   return true;
 }