private UpdateResult shardUpdateOperation(
     ClusterState clusterState,
     BulkShardRequest bulkShardRequest,
     UpdateRequest updateRequest,
     IndexShard indexShard) {
   UpdateHelper.Result translate = updateHelper.prepare(updateRequest, indexShard);
   switch (translate.operation()) {
     case UPSERT:
     case INDEX:
       IndexRequest indexRequest = translate.action();
       try {
         WriteResult result =
             shardIndexOperation(bulkShardRequest, indexRequest, clusterState, indexShard, false);
         return new UpdateResult(translate, indexRequest, result);
       } catch (Throwable t) {
         t = ExceptionsHelper.unwrapCause(t);
         boolean retry = false;
         if (t instanceof VersionConflictEngineException
             || (t instanceof DocumentAlreadyExistsException
                 && translate.operation() == UpdateHelper.Operation.UPSERT)) {
           retry = true;
         }
         return new UpdateResult(translate, indexRequest, retry, t, null);
       }
     case DELETE:
       DeleteRequest deleteRequest = translate.action();
       try {
         WriteResult result = shardDeleteOperation(bulkShardRequest, deleteRequest, indexShard);
         return new UpdateResult(translate, deleteRequest, result);
       } catch (Throwable t) {
         t = ExceptionsHelper.unwrapCause(t);
         boolean retry = false;
         if (t instanceof VersionConflictEngineException) {
           retry = true;
         }
         return new UpdateResult(translate, deleteRequest, retry, t, null);
       }
     case NONE:
       UpdateResponse updateResponse = translate.action();
       indexShard.indexingService().noopUpdate(updateRequest.type());
       return new UpdateResult(translate, updateResponse);
     default:
       throw new IllegalStateException("Illegal update operation " + translate.operation());
   }
 }
  protected void shardOperation(
      final UpdateRequest request,
      final ActionListener<UpdateResponse> listener,
      final int retryCount)
      throws ElasticsearchException {
    final UpdateHelper.Result result = updateHelper.prepare(request);
    switch (result.operation()) {
      case UPSERT:
        IndexRequest upsertRequest = result.action();
        // we fetch it from the index request so we don't generate the bytes twice, its already done
        // in the index request
        final BytesReference upsertSourceBytes = upsertRequest.source();
        indexAction.execute(
            upsertRequest,
            new ActionListener<IndexResponse>() {
              @Override
              public void onResponse(IndexResponse response) {
                UpdateResponse update =
                    new UpdateResponse(
                        response.getIndex(),
                        response.getType(),
                        response.getId(),
                        response.getVersion(),
                        response.isCreated());
                if (request.fields() != null && request.fields().length > 0) {
                  Tuple<XContentType, Map<String, Object>> sourceAndContent =
                      XContentHelper.convertToMap(upsertSourceBytes, true);
                  update.setGetResult(
                      updateHelper.extractGetResult(
                          request,
                          response.getVersion(),
                          sourceAndContent.v2(),
                          sourceAndContent.v1(),
                          upsertSourceBytes));
                } else {
                  update.setGetResult(null);
                }
                listener.onResponse(update);
              }

              @Override
              public void onFailure(Throwable e) {
                e = ExceptionsHelper.unwrapCause(e);
                if (e instanceof VersionConflictEngineException
                    || e instanceof DocumentAlreadyExistsException) {
                  if (retryCount < request.retryOnConflict()) {
                    threadPool
                        .executor(executor())
                        .execute(
                            new ActionRunnable<UpdateResponse>(listener) {
                              @Override
                              protected void doRun() {
                                shardOperation(request, listener, retryCount + 1);
                              }
                            });
                    return;
                  }
                }
                listener.onFailure(e);
              }
            });
        break;
      case INDEX:
        IndexRequest indexRequest = result.action();
        // we fetch it from the index request so we don't generate the bytes twice, its already done
        // in the index request
        final BytesReference indexSourceBytes = indexRequest.source();
        indexAction.execute(
            indexRequest,
            new ActionListener<IndexResponse>() {
              @Override
              public void onResponse(IndexResponse response) {
                UpdateResponse update =
                    new UpdateResponse(
                        response.getIndex(),
                        response.getType(),
                        response.getId(),
                        response.getVersion(),
                        response.isCreated());
                update.setGetResult(
                    updateHelper.extractGetResult(
                        request,
                        response.getVersion(),
                        result.updatedSourceAsMap(),
                        result.updateSourceContentType(),
                        indexSourceBytes));
                listener.onResponse(update);
              }

              @Override
              public void onFailure(Throwable e) {
                e = ExceptionsHelper.unwrapCause(e);
                if (e instanceof VersionConflictEngineException) {
                  if (retryCount < request.retryOnConflict()) {
                    threadPool
                        .executor(executor())
                        .execute(
                            new ActionRunnable<UpdateResponse>(listener) {
                              @Override
                              protected void doRun() {
                                shardOperation(request, listener, retryCount + 1);
                              }
                            });
                    return;
                  }
                }
                listener.onFailure(e);
              }
            });
        break;
      case DELETE:
        DeleteRequest deleteRequest = result.action();
        deleteAction.execute(
            deleteRequest,
            new ActionListener<DeleteResponse>() {
              @Override
              public void onResponse(DeleteResponse response) {
                UpdateResponse update =
                    new UpdateResponse(
                        response.getIndex(),
                        response.getType(),
                        response.getId(),
                        response.getVersion(),
                        false);
                update.setGetResult(
                    updateHelper.extractGetResult(
                        request,
                        response.getVersion(),
                        result.updatedSourceAsMap(),
                        result.updateSourceContentType(),
                        null));
                listener.onResponse(update);
              }

              @Override
              public void onFailure(Throwable e) {
                e = ExceptionsHelper.unwrapCause(e);
                if (e instanceof VersionConflictEngineException) {
                  if (retryCount < request.retryOnConflict()) {
                    threadPool
                        .executor(executor())
                        .execute(
                            new ActionRunnable<UpdateResponse>(listener) {
                              @Override
                              protected void doRun() {
                                shardOperation(request, listener, retryCount + 1);
                              }
                            });
                    return;
                  }
                }
                listener.onFailure(e);
              }
            });
        break;
      case NONE:
        UpdateResponse update = result.action();
        listener.onResponse(update);
        indicesService
            .indexService(request.index())
            .shard(request.shardId())
            .indexingService()
            .noopUpdate(request.type());
        break;
      default:
        throw new ElasticsearchIllegalStateException("Illegal operation " + result.operation());
    }
  }