@Override
  protected void doExecute(
      final UpdateRequest request, final ActionListener<UpdateResponse> listener) {
    // if we don't have a master, we don't have metadata, that's fine, let it find a master using
    // create index API
    if (autoCreateIndex.shouldAutoCreate(request.index(), clusterService.state())) {
      request.beforeLocalFork(); // we fork on another thread...
      createIndexAction.execute(
          new CreateIndexRequest(request.index())
              .cause("auto(update api)")
              .masterNodeTimeout(request.timeout()),
          new ActionListener<CreateIndexResponse>() {
            @Override
            public void onResponse(CreateIndexResponse result) {
              innerExecute(request, listener);
            }

            @Override
            public void onFailure(Throwable e) {
              if (ExceptionsHelper.unwrapCause(e) instanceof IndexAlreadyExistsException) {
                // we have the index, do it
                try {
                  innerExecute(request, listener);
                } catch (Exception e1) {
                  listener.onFailure(e1);
                }
              } else {
                listener.onFailure(e);
              }
            }
          });
    } else {
      innerExecute(request, listener);
    }
  }
  private void handleUpdateRequests(UpdateRequest<K> request) {
    final Set<K> keys = request.keys();
    final NodeId sender = request.sender();
    final List<NodeId> peers = ImmutableList.of(sender);

    keys.forEach(key -> queueUpdate(new UpdateEntry<>(key, items.get(key)), peers));
  }
Exemple #3
0
  /** {@inheritDoc} */
  @Override
  public void run() {

    while (requests != null) {

      /* Not processing a request. */
      currentRequest = null;

      /* Take a new request from the queue, waiting for one if none is available yet. */
      try {
        currentRequest = requests.take();
      }

      /* Interrupted? Well, try again! */
      catch (InterruptedException ignored) {
        continue;
      }

      /* Process the request. */
      try {
        ui.process(currentRequest.getRequest());
      }

      /* Uncaught exception occurred during the request. */
      catch (Throwable e) {
        e.initCause(currentRequest.getCause());
        logger.err(e, "Unexpected error occurred.");
      }
    }
  }
 @Override
 protected boolean resolveRequest(
     ClusterState state, UpdateRequest request, ActionListener<UpdateResponse> listener) {
   MetaData metaData = clusterService.state().metaData();
   String aliasOrIndex = request.index();
   request.routing((metaData.resolveIndexRouting(request.routing(), aliasOrIndex)));
   request.index(metaData.concreteIndex(request.index()));
   return true;
 }
    @Test
    public void shouldRequestUpdatesForAllPlayersScreen() throws IOException, ServletException {
        request.addParameter("vasya", "vasya");
        request.addParameter("allPlayersScreen", "true");

        screenController.handleRequest(request, new MockHttpServletResponse());

        verify(screenSender).scheduleUpdate(updateRequestCaptor.capture());
        UpdateRequest updateRequest = updateRequestCaptor.getValue();
        assertTrue(updateRequest.isForAllPlayers());
        assertNull(updateRequest.getPlayersToUpdate());
    }
 public DelayedReply messageArrived(CellMessage envelope, PoolMgrGetUpdatedHandler message) {
   SerializablePoolManagerHandler handler = this.handler;
   UpdateRequest request = new UpdateRequest(envelope, message);
   requests.add(request);
   if (message.getVersion().equals(handler.getVersion())) {
     delays.put(request);
     UpdateRequest expired;
     while ((expired = delays.poll()) != null) {
       requests.remove(expired);
     }
   } else if (requests.remove(request)) {
     request.send(handler);
   }
   return request;
 }
 @Override
 protected ShardIterator shards(ClusterState clusterState, UpdateRequest request)
     throws ElasticSearchException {
   if (request.shardId() != -1) {
     return clusterState
         .routingTable()
         .index(request.index())
         .shard(request.shardId())
         .primaryShardIt();
   }
   ShardIterator shardIterator =
       clusterService
           .operationRouting()
           .indexShards(
               clusterService.state(),
               request.index(),
               request.type(),
               request.id(),
               request.routing());
   ShardRouting shard;
   while ((shard = shardIterator.nextOrNull()) != null) {
     if (shard.primary()) {
       return new PlainShardIterator(shardIterator.shardId(), ImmutableList.of(shard));
     }
   }
   return new PlainShardIterator(shardIterator.shardId(), ImmutableList.<ShardRouting>of());
 }
 @Override
 public void handleUpdate(
     final ServerContext context,
     final UpdateRequest request,
     final ResultHandler<Resource> handler) {
   // TODO: i18n
   handler.handleError(
       newBadRequestException(
           "The resource collection %s cannot be updated", request.getResourceName()));
 }
 /**
  * Prepares an update request by converting it into an index or delete request or an update
  * response (no action).
  */
 @SuppressWarnings("unchecked")
 public Result prepare(UpdateRequest request, IndexShard indexShard) {
   final GetResult getResult =
       indexShard
           .getService()
           .get(
               request.type(),
               request.id(),
               new String[] {
                 RoutingFieldMapper.NAME,
                 ParentFieldMapper.NAME,
                 TTLFieldMapper.NAME,
                 TimestampFieldMapper.NAME
               },
               true,
               request.version(),
               request.versionType(),
               FetchSourceContext.FETCH_SOURCE,
               false);
   return prepare(indexShard.shardId(), request, getResult);
 }
Exemple #10
0
  /**
   * Add a request to the stack of requests to execute in the update thread.
   *
   * @param uiRequest The request to execute in the update thread.
   */
  public void request(Request uiRequest) {

    UpdateRequest newRequest =
        new UpdateRequest(
            uiRequest,
            new RuntimeException(
                Locale.explain("err.originates")
                    + Thread.currentThread().getName())); // $NON-NLS-1$

    /* Don't process a request if the next pending or currently executing request is the same. */
    if (newRequest.equals(currentRequest) || requests.contains(newRequest)) return;

    /* Add this request to the request list. */
    synchronized (requests) {
      try {
        if (!requests.offer(newRequest, 500, TimeUnit.MILLISECONDS))
          throw new InterruptedException("Maximum wait time elapsed.");
      } catch (InterruptedException e) {
        logger.err(e, "err.updateQueueFull", newRequest);
      }
    }
  }
  @Nullable
  protected GetResult extractGetResult(
      final UpdateRequest request,
      long version,
      final Map<String, Object> source,
      XContentType sourceContentType,
      @Nullable final BytesReference sourceAsBytes) {
    if (request.fields() == null || request.fields().length == 0) {
      return null;
    }
    boolean sourceRequested = false;
    Map<String, GetField> fields = null;
    if (request.fields() != null && request.fields().length > 0) {
      SourceLookup sourceLookup = new SourceLookup();
      sourceLookup.setNextSource(source);
      for (String field : request.fields()) {
        if (field.equals("_source")) {
          sourceRequested = true;
          continue;
        }
        Object value = sourceLookup.extractValue(field);
        if (value != null) {
          if (fields == null) {
            fields = newHashMapWithExpectedSize(2);
          }
          GetField getField = fields.get(field);
          if (getField == null) {
            getField = new GetField(field, new ArrayList<Object>(2));
            fields.put(field, getField);
          }
          getField.getValues().add(value);
        }
      }
    }

    // TODO when using delete/none, we can still return the source as bytes by generating it (using
    // the sourceContentType)

    return new GetResult(
        request.index(),
        request.type(),
        request.id(),
        version,
        true,
        sourceRequested ? sourceAsBytes : null,
        fields);
  }
  @Test
  public void testIteratable() throws IOException {
    final List<String> values = new ArrayList<String>();
    values.add("iterItem1");
    values.add("iterItem2");

    UpdateRequest updateRequest = new UpdateRequest();
    updateRequest.deleteByQuery("*:*");

    SolrInputDocument doc = new SolrInputDocument();
    doc.addField("id", 1);
    doc.addField("desc", "one", 2.0f);
    // imagine someone adding a custom Bean that implements Iterable
    // but is not a Collection
    doc.addField(
        "iter",
        new Iterable<String>() {
          @Override
          public Iterator<String> iterator() {
            return values.iterator();
          }
        });
    doc.addField("desc", "1");
    updateRequest.add(doc);

    JavaBinUpdateRequestCodec codec = new JavaBinUpdateRequestCodec();
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    codec.marshal(updateRequest, baos);
    final List<SolrInputDocument> docs = new ArrayList<SolrInputDocument>();
    JavaBinUpdateRequestCodec.StreamingUpdateHandler handler =
        new JavaBinUpdateRequestCodec.StreamingUpdateHandler() {
          @Override
          public void update(SolrInputDocument document, UpdateRequest req) {
            Assert.assertNotNull(req.getParams());
            docs.add(document);
          }
        };

    UpdateRequest updateUnmarshalled =
        codec.unmarshal(new ByteArrayInputStream(baos.toByteArray()), handler);
    Assert.assertNull(updateUnmarshalled.getDocuments());
    for (SolrInputDocument document : docs) {
      updateUnmarshalled.add(document);
    }

    SolrInputDocument outDoc = updateUnmarshalled.getDocuments().get(0);
    SolrInputField iter = outDoc.getField("iter");
    Assert.assertNotNull("iter field is null", iter);
    Object iterVal = iter.getValue();
    Assert.assertTrue("iterVal is not a Collection", iterVal instanceof Collection);
    Assert.assertEquals("iterVal contents", values, iterVal);
  }
  @Test
  public void simple() throws IOException {
    UpdateRequest updateRequest = new UpdateRequest();
    updateRequest.deleteById("*:*");
    updateRequest.deleteById("id:5");
    updateRequest.deleteByQuery("2*");
    updateRequest.deleteByQuery("1*");
    updateRequest.setParam("a", "b");
    SolrInputDocument doc = new SolrInputDocument();
    doc.addField("id", 1);
    doc.addField("desc", "one", 2.0f);
    doc.addField("desc", "1");
    updateRequest.add(doc);

    doc = new SolrInputDocument();
    doc.addField("id", 2);
    doc.setDocumentBoost(10.0f);
    doc.addField("desc", "two", 3.0f);
    doc.addField("desc", "2");
    updateRequest.add(doc);

    doc = new SolrInputDocument();
    doc.addField("id", 3);
    doc.addField("desc", "three", 3.0f);
    doc.addField("desc", "3");
    updateRequest.add(doc);

    doc = new SolrInputDocument();
    Collection<String> foobar = new HashSet<String>();
    foobar.add("baz1");
    foobar.add("baz2");
    doc.addField("foobar", foobar);
    updateRequest.add(doc);

    //    updateRequest.setWaitFlush(true);
    updateRequest.deleteById("2");
    updateRequest.deleteByQuery("id:3");
    JavaBinUpdateRequestCodec codec = new JavaBinUpdateRequestCodec();
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    codec.marshal(updateRequest, baos);
    final List<SolrInputDocument> docs = new ArrayList<SolrInputDocument>();
    JavaBinUpdateRequestCodec.StreamingUpdateHandler handler =
        new JavaBinUpdateRequestCodec.StreamingUpdateHandler() {
          @Override
          public void update(SolrInputDocument document, UpdateRequest req) {
            Assert.assertNotNull(req.getParams());
            docs.add(document);
          }
        };

    UpdateRequest updateUnmarshalled =
        codec.unmarshal(new ByteArrayInputStream(baos.toByteArray()), handler);
    Assert.assertNull(updateUnmarshalled.getDocuments());
    for (SolrInputDocument document : docs) {
      updateUnmarshalled.add(document);
    }
    for (int i = 0; i < updateRequest.getDocuments().size(); i++) {
      SolrInputDocument inDoc = updateRequest.getDocuments().get(i);
      SolrInputDocument outDoc = updateUnmarshalled.getDocuments().get(i);
      compareDocs("doc#" + i, inDoc, outDoc);
    }
    Assert.assertEquals(
        updateUnmarshalled.getDeleteById().get(0), updateRequest.getDeleteById().get(0));
    Assert.assertEquals(
        updateUnmarshalled.getDeleteQuery().get(0), updateRequest.getDeleteQuery().get(0));

    assertEquals("b", updateUnmarshalled.getParams().get("a"));
  }
  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());
    }
  }
  @Override
  protected boolean resolveRequest(
      ClusterState state, UpdateRequest request, ActionListener<UpdateResponse> listener) {
    MetaData metaData = clusterService.state().metaData();
    String aliasOrIndex = request.index();
    request.routing((metaData.resolveIndexRouting(request.routing(), aliasOrIndex)));
    request.index(metaData.concreteSingleIndex(request.index(), request.indicesOptions()));

    // Fail fast on the node that received the request, rather than failing when translating on the
    // index or delete request.
    if (request.routing() == null
        && state.getMetaData().routingRequired(request.index(), request.type())) {
      throw new RoutingMissingException(request.index(), request.type(), request.id());
    }
    return true;
  }
 private static void execute$(Update update, GraphStore graphStore, Binding binding) {
   UpdateRequest request = new UpdateRequest();
   request.add(update);
   execute$(request, graphStore, binding);
 }
  @SuppressWarnings({"unchecked", "rawtypes"})
  private <T extends Request> RestRequest clientGeneratedRequest(
      Class<T> requestClass,
      ResourceMethod method,
      DataMap entityBody,
      RestClient.ContentType contentType,
      List<RestClient.AcceptType> acceptTypes)
      throws URISyntaxException {
    // massive setup...
    Client mockClient = EasyMock.createMock(Client.class);

    @SuppressWarnings({"rawtypes"})
    Request<?> mockRequest = EasyMock.createMock(requestClass);
    RecordTemplate mockRecordTemplate = EasyMock.createMock(RecordTemplate.class);
    @SuppressWarnings({"rawtypes"})
    RestResponseDecoder mockResponseDecoder = EasyMock.createMock(RestResponseDecoder.class);

    setCommonExpectations(mockRequest, method, mockRecordTemplate, mockResponseDecoder);

    if (method == ResourceMethod.BATCH_PARTIAL_UPDATE || method == ResourceMethod.BATCH_UPDATE) {
      buildInputForBatchPathAndUpdate(mockRequest);
    } else {
      EasyMock.expect(mockRequest.getInputRecord()).andReturn(mockRecordTemplate).times(2);
      EasyMock.expect(mockRequest.getResourceSpec()).andReturn(new ResourceSpecImpl()).once();
    }

    if (method == ResourceMethod.GET) {
      EasyMock.expect(((GetRequest) mockRequest).getObjectId()).andReturn(null).once();
      EasyMock.expect(((GetRequest) mockRequest).getResourceSpec())
          .andReturn(new ResourceSpecImpl())
          .once();
      EasyMock.expect(mockRequest.getMethodName()).andReturn(null);
    } else if (method == ResourceMethod.BATCH_GET) {
      EasyMock.expect(mockRequest.getMethodName()).andReturn(null);
    } else if (method == ResourceMethod.ACTION) {
      EasyMock.expect(((ActionRequest) mockRequest).getId()).andReturn(null);
      EasyMock.expect(mockRequest.getMethodName()).andReturn("testAction");
    } else if (method == ResourceMethod.FINDER) {
      EasyMock.expect(((FindRequest) mockRequest).getAssocKey()).andReturn(new CompoundKey());
      EasyMock.expect(mockRequest.getMethodName()).andReturn("testFinder");
    } else if (method == ResourceMethod.GET_ALL) {
      EasyMock.expect(((GetAllRequest) mockRequest).getAssocKey()).andReturn(new CompoundKey());
      EasyMock.expect(mockRequest.getMethodName()).andReturn(null);
    } else if (method == ResourceMethod.UPDATE) {
      EasyMock.expect(((UpdateRequest) mockRequest).getResourceSpec())
          .andReturn(new ResourceSpecImpl())
          .once();
      EasyMock.expect(((UpdateRequest) mockRequest).getId()).andReturn(null);
      EasyMock.expect(mockRequest.getMethodName()).andReturn(null);
    } else if (method == ResourceMethod.PARTIAL_UPDATE) {
      EasyMock.expect(mockRequest.getResourceSpec()).andReturn(new ResourceSpecImpl()).times(2);
      EasyMock.expect(((PartialUpdateRequest) mockRequest).getId()).andReturn(null);
      EasyMock.expect(mockRequest.getMethodName()).andReturn(null);
    } else if (method == ResourceMethod.DELETE) {
      EasyMock.expect(((DeleteRequest) mockRequest).getResourceSpec())
          .andReturn(new ResourceSpecImpl())
          .once();
      EasyMock.expect(((DeleteRequest) mockRequest).getId()).andReturn(null);
      EasyMock.expect(mockRequest.getMethodName()).andReturn(null);
    } else {
      EasyMock.expect(mockRequest.getMethodName()).andReturn(null);
    }

    EasyMock.expect(mockRecordTemplate.data()).andReturn(entityBody).once();

    Capture<RestRequest> restRequestCapture = new Capture<RestRequest>();

    EasyMock.expect(mockClient.getMetadata(new URI(HOST + SERVICE_NAME)))
        .andReturn(Collections.<String, Object>emptyMap())
        .once();

    mockClient.restRequest(
        EasyMock.capture(restRequestCapture),
        (RequestContext) EasyMock.anyObject(),
        (Callback<RestResponse>) EasyMock.anyObject());
    EasyMock.expectLastCall().once();

    EasyMock.replay(mockClient, mockRequest, mockRecordTemplate);

    // do work!
    RestClient restClient;
    if (acceptTypes == null) {
      restClient = new RestClient(mockClient, HOST);
    } else if (contentType == null) {
      restClient = new RestClient(mockClient, HOST, acceptTypes);
    } else {
      restClient = new RestClient(mockClient, HOST, contentType, acceptTypes);
    }

    restClient.sendRequest(mockRequest);

    return restRequestCapture.getValue();
  }
 @Override
 protected ClusterBlockException checkRequestBlock(ClusterState state, UpdateRequest request) {
   return state.blocks().indexBlockedException(ClusterBlockLevel.WRITE, request.index());
 }
  /**
   * Prepares an update request by converting it into an index or delete request or an update
   * response (no action).
   */
  @SuppressWarnings("unchecked")
  protected Result prepare(ShardId shardId, UpdateRequest request, final GetResult getResult) {
    long getDateNS = System.nanoTime();
    if (!getResult.isExists()) {
      if (request.upsertRequest() == null && !request.docAsUpsert()) {
        throw new DocumentMissingException(shardId, request.type(), request.id());
      }
      IndexRequest indexRequest = request.docAsUpsert() ? request.doc() : request.upsertRequest();
      TimeValue ttl = indexRequest.ttl();
      if (request.scriptedUpsert() && request.script() != null) {
        // Run the script to perform the create logic
        IndexRequest upsert = request.upsertRequest();
        Map<String, Object> upsertDoc = upsert.sourceAsMap();
        Map<String, Object> ctx = new HashMap<>(2);
        // Tell the script that this is a create and not an update
        ctx.put("op", "create");
        ctx.put("_source", upsertDoc);
        ctx = executeScript(request.script, ctx);
        // Allow the script to set TTL using ctx._ttl
        if (ttl == null) {
          ttl = getTTLFromScriptContext(ctx);
        }

        // Allow the script to abort the create by setting "op" to "none"
        String scriptOpChoice = (String) ctx.get("op");

        // Only valid options for an upsert script are "create"
        // (the default) or "none", meaning abort upsert
        if (!"create".equals(scriptOpChoice)) {
          if (!"none".equals(scriptOpChoice)) {
            logger.warn(
                "Used upsert operation [{}] for script [{}], doing nothing...",
                scriptOpChoice,
                request.script.getScript());
          }
          UpdateResponse update =
              new UpdateResponse(
                  shardId, getResult.getType(), getResult.getId(), getResult.getVersion(), false);
          update.setGetResult(getResult);
          return new Result(update, Operation.NONE, upsertDoc, XContentType.JSON);
        }
        indexRequest.source((Map) ctx.get("_source"));
      }

      indexRequest
          .index(request.index())
          .type(request.type())
          .id(request.id())
          // it has to be a "create!"
          .create(true)
          .ttl(ttl)
          .refresh(request.refresh())
          .routing(request.routing())
          .parent(request.parent())
          .consistencyLevel(request.consistencyLevel());
      if (request.versionType() != VersionType.INTERNAL) {
        // in all but the internal versioning mode, we want to create the new document using the
        // given version.
        indexRequest.version(request.version()).versionType(request.versionType());
      }
      return new Result(indexRequest, Operation.UPSERT, null, null);
    }

    long updateVersion = getResult.getVersion();

    if (request.versionType() != VersionType.INTERNAL) {
      assert request.versionType() == VersionType.FORCE;
      updateVersion = request.version(); // remember, match_any is excluded by the conflict test
    }

    if (getResult.internalSourceRef() == null) {
      // no source, we can't do nothing, through a failure...
      throw new DocumentSourceMissingException(shardId, request.type(), request.id());
    }

    Tuple<XContentType, Map<String, Object>> sourceAndContent =
        XContentHelper.convertToMap(getResult.internalSourceRef(), true);
    String operation = null;
    String timestamp = null;
    TimeValue ttl = null;
    final Map<String, Object> updatedSourceAsMap;
    final XContentType updateSourceContentType = sourceAndContent.v1();
    String routing =
        getResult.getFields().containsKey(RoutingFieldMapper.NAME)
            ? getResult.field(RoutingFieldMapper.NAME).getValue().toString()
            : null;
    String parent =
        getResult.getFields().containsKey(ParentFieldMapper.NAME)
            ? getResult.field(ParentFieldMapper.NAME).getValue().toString()
            : null;

    if (request.script() == null && request.doc() != null) {
      IndexRequest indexRequest = request.doc();
      updatedSourceAsMap = sourceAndContent.v2();
      if (indexRequest.ttl() != null) {
        ttl = indexRequest.ttl();
      }
      timestamp = indexRequest.timestamp();
      if (indexRequest.routing() != null) {
        routing = indexRequest.routing();
      }
      if (indexRequest.parent() != null) {
        parent = indexRequest.parent();
      }
      boolean noop =
          !XContentHelper.update(
              updatedSourceAsMap, indexRequest.sourceAsMap(), request.detectNoop());
      // noop could still be true even if detectNoop isn't because update detects empty maps as
      // noops.  BUT we can only
      // actually turn the update into a noop if detectNoop is true to preserve backwards
      // compatibility and to handle
      // cases where users repopulating multi-fields or adding synonyms, etc.
      if (request.detectNoop() && noop) {
        operation = "none";
      }
    } else {
      Map<String, Object> ctx = new HashMap<>(16);
      Long originalTtl =
          getResult.getFields().containsKey(TTLFieldMapper.NAME)
              ? (Long) getResult.field(TTLFieldMapper.NAME).getValue()
              : null;
      Long originalTimestamp =
          getResult.getFields().containsKey(TimestampFieldMapper.NAME)
              ? (Long) getResult.field(TimestampFieldMapper.NAME).getValue()
              : null;
      ctx.put("_index", getResult.getIndex());
      ctx.put("_type", getResult.getType());
      ctx.put("_id", getResult.getId());
      ctx.put("_version", getResult.getVersion());
      ctx.put("_routing", routing);
      ctx.put("_parent", parent);
      ctx.put("_timestamp", originalTimestamp);
      ctx.put("_ttl", originalTtl);
      ctx.put("_source", sourceAndContent.v2());

      ctx = executeScript(request.script, ctx);

      operation = (String) ctx.get("op");

      Object fetchedTimestamp = ctx.get("_timestamp");
      if (fetchedTimestamp != null) {
        timestamp = fetchedTimestamp.toString();
      } else if (originalTimestamp != null) {
        // No timestamp has been given in the update script, so we keep the previous timestamp if
        // there is one
        timestamp = originalTimestamp.toString();
      }

      ttl = getTTLFromScriptContext(ctx);

      updatedSourceAsMap = (Map<String, Object>) ctx.get("_source");
    }

    // apply script to update the source
    // No TTL has been given in the update script so we keep previous TTL value if there is one
    if (ttl == null) {
      Long ttlAsLong =
          getResult.getFields().containsKey(TTLFieldMapper.NAME)
              ? (Long) getResult.field(TTLFieldMapper.NAME).getValue()
              : null;
      if (ttlAsLong != null) {
        ttl =
            new TimeValue(
                ttlAsLong
                    - TimeValue.nsecToMSec(
                        System.nanoTime()
                            - getDateNS)); // It is an approximation of exact TTL value, could be
                                           // improved
      }
    }

    if (operation == null || "index".equals(operation)) {
      final IndexRequest indexRequest =
          Requests.indexRequest(request.index())
              .type(request.type())
              .id(request.id())
              .routing(routing)
              .parent(parent)
              .source(updatedSourceAsMap, updateSourceContentType)
              .version(updateVersion)
              .versionType(request.versionType())
              .consistencyLevel(request.consistencyLevel())
              .timestamp(timestamp)
              .ttl(ttl)
              .refresh(request.refresh());
      return new Result(indexRequest, Operation.INDEX, updatedSourceAsMap, updateSourceContentType);
    } else if ("delete".equals(operation)) {
      DeleteRequest deleteRequest =
          Requests.deleteRequest(request.index())
              .type(request.type())
              .id(request.id())
              .routing(routing)
              .parent(parent)
              .version(updateVersion)
              .versionType(request.versionType())
              .consistencyLevel(request.consistencyLevel());
      return new Result(
          deleteRequest, Operation.DELETE, updatedSourceAsMap, updateSourceContentType);
    } else if ("none".equals(operation)) {
      UpdateResponse update =
          new UpdateResponse(
              shardId, getResult.getType(), getResult.getId(), getResult.getVersion(), false);
      update.setGetResult(
          extractGetResult(
              request,
              request.index(),
              getResult.getVersion(),
              updatedSourceAsMap,
              updateSourceContentType,
              getResult.internalSourceRef()));
      return new Result(update, Operation.NONE, updatedSourceAsMap, updateSourceContentType);
    } else {
      logger.warn(
          "Used update operation [{}] for script [{}], doing nothing...",
          operation,
          request.script.getScript());
      UpdateResponse update =
          new UpdateResponse(
              shardId, getResult.getType(), getResult.getId(), getResult.getVersion(), false);
      return new Result(update, Operation.NONE, updatedSourceAsMap, updateSourceContentType);
    }
  }
  protected void shardOperation(
      final UpdateRequest request,
      final ActionListener<UpdateResponse> listener,
      final int retryCount)
      throws ElasticSearchException {
    IndexService indexService = indicesService.indexServiceSafe(request.index());
    IndexShard indexShard = indexService.shardSafe(request.shardId());

    long getDate = System.currentTimeMillis();
    final GetResult getResult =
        indexShard
            .getService()
            .get(
                request.type(),
                request.id(),
                new String[] {
                  SourceFieldMapper.NAME,
                  RoutingFieldMapper.NAME,
                  ParentFieldMapper.NAME,
                  TTLFieldMapper.NAME
                },
                true);

    // no doc, what to do, what to do...
    if (!getResult.isExists()) {
      if (request.upsertRequest() == null) {
        listener.onFailure(
            new DocumentMissingException(
                new ShardId(request.index(), request.shardId()), request.type(), request.id()));
        return;
      }
      final IndexRequest indexRequest = request.upsertRequest();
      indexRequest
          .index(request.index())
          .type(request.type())
          .id(request.id())
          // it has to be a "create!"
          .create(true)
          .routing(request.routing())
          .percolate(request.percolate())
          .refresh(request.refresh())
          .replicationType(request.replicationType())
          .consistencyLevel(request.consistencyLevel());
      indexRequest.operationThreaded(false);
      // we fetch it from the index request so we don't generate the bytes twice, its already done
      // in the index request
      final BytesReference updateSourceBytes = 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());
              update.setMatches(response.getMatches());
              if (request.fields() != null && request.fields().length > 0) {
                Tuple<XContentType, Map<String, Object>> sourceAndContent =
                    XContentHelper.convertToMap(updateSourceBytes, true);
                update.setGetResult(
                    extractGetResult(
                        request,
                        response.getVersion(),
                        sourceAndContent.v2(),
                        sourceAndContent.v1(),
                        updateSourceBytes));
              } 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 Runnable() {
                            @Override
                            public void run() {
                              shardOperation(request, listener, retryCount + 1);
                            }
                          });
                  return;
                }
              }
              listener.onFailure(e);
            }
          });
      return;
    }

    if (getResult.internalSourceRef() == null) {
      // no source, we can't do nothing, through a failure...
      listener.onFailure(
          new DocumentSourceMissingException(
              new ShardId(request.index(), request.shardId()), request.type(), request.id()));
      return;
    }

    Tuple<XContentType, Map<String, Object>> sourceAndContent =
        XContentHelper.convertToMap(getResult.internalSourceRef(), true);
    String operation = null;
    String timestamp = null;
    Long ttl = null;
    Object fetchedTTL = null;
    final Map<String, Object> updatedSourceAsMap;
    final XContentType updateSourceContentType = sourceAndContent.v1();
    String routing =
        getResult.getFields().containsKey(RoutingFieldMapper.NAME)
            ? getResult.field(RoutingFieldMapper.NAME).getValue().toString()
            : null;
    String parent =
        getResult.getFields().containsKey(ParentFieldMapper.NAME)
            ? getResult.field(ParentFieldMapper.NAME).getValue().toString()
            : null;

    if (request.script() == null && request.doc() != null) {
      IndexRequest indexRequest = request.doc();
      updatedSourceAsMap = sourceAndContent.v2();
      if (indexRequest.ttl() > 0) {
        ttl = indexRequest.ttl();
      }
      timestamp = indexRequest.timestamp();
      if (indexRequest.routing() != null) {
        routing = indexRequest.routing();
      }
      if (indexRequest.parent() != null) {
        parent = indexRequest.parent();
      }
      XContentHelper.update(updatedSourceAsMap, indexRequest.sourceAsMap());
    } else {
      Map<String, Object> ctx = new HashMap<String, Object>(2);
      ctx.put("_source", sourceAndContent.v2());

      try {
        ExecutableScript script =
            scriptService.executable(request.scriptLang, request.script, request.scriptParams);
        script.setNextVar("ctx", ctx);
        script.run();
        // we need to unwrap the ctx...
        ctx = (Map<String, Object>) script.unwrap(ctx);
      } catch (Exception e) {
        throw new ElasticSearchIllegalArgumentException("failed to execute script", e);
      }

      operation = (String) ctx.get("op");
      timestamp = (String) ctx.get("_timestamp");
      fetchedTTL = ctx.get("_ttl");
      if (fetchedTTL != null) {
        if (fetchedTTL instanceof Number) {
          ttl = ((Number) fetchedTTL).longValue();
        } else {
          ttl = TimeValue.parseTimeValue((String) fetchedTTL, null).millis();
        }
      }

      updatedSourceAsMap = (Map<String, Object>) ctx.get("_source");
    }

    // apply script to update the source
    // No TTL has been given in the update script so we keep previous TTL value if there is one
    if (ttl == null) {
      ttl =
          getResult.getFields().containsKey(TTLFieldMapper.NAME)
              ? (Long) getResult.field(TTLFieldMapper.NAME).getValue()
              : null;
      if (ttl != null) {
        ttl =
            ttl
                - (System.currentTimeMillis()
                    - getDate); // It is an approximation of exact TTL value, could be improved
      }
    }

    // TODO: external version type, does it make sense here? does not seem like it...

    if (operation == null || "index".equals(operation)) {
      final IndexRequest indexRequest =
          Requests.indexRequest(request.index())
              .type(request.type())
              .id(request.id())
              .routing(routing)
              .parent(parent)
              .source(updatedSourceAsMap, updateSourceContentType)
              .version(getResult.getVersion())
              .replicationType(request.replicationType())
              .consistencyLevel(request.consistencyLevel())
              .timestamp(timestamp)
              .ttl(ttl)
              .percolate(request.percolate())
              .refresh(request.refresh());
      indexRequest.operationThreaded(false);
      // we fetch it from the index request so we don't generate the bytes twice, its already done
      // in the index request
      final BytesReference updateSourceBytes = 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());
              update.setMatches(response.getMatches());
              update.setGetResult(
                  extractGetResult(
                      request,
                      response.getVersion(),
                      updatedSourceAsMap,
                      updateSourceContentType,
                      updateSourceBytes));
              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 Runnable() {
                            @Override
                            public void run() {
                              shardOperation(request, listener, retryCount + 1);
                            }
                          });
                  return;
                }
              }
              listener.onFailure(e);
            }
          });
    } else if ("delete".equals(operation)) {
      DeleteRequest deleteRequest =
          Requests.deleteRequest(request.index())
              .type(request.type())
              .id(request.id())
              .routing(routing)
              .parent(parent)
              .version(getResult.getVersion())
              .replicationType(request.replicationType())
              .consistencyLevel(request.consistencyLevel());
      deleteRequest.operationThreaded(false);
      deleteAction.execute(
          deleteRequest,
          new ActionListener<DeleteResponse>() {
            @Override
            public void onResponse(DeleteResponse response) {
              UpdateResponse update =
                  new UpdateResponse(
                      response.getIndex(),
                      response.getType(),
                      response.getId(),
                      response.getVersion());
              update.setGetResult(
                  extractGetResult(
                      request,
                      response.getVersion(),
                      updatedSourceAsMap,
                      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 Runnable() {
                            @Override
                            public void run() {
                              shardOperation(request, listener, retryCount + 1);
                            }
                          });
                  return;
                }
              }
              listener.onFailure(e);
            }
          });
    } else if ("none".equals(operation)) {
      UpdateResponse update =
          new UpdateResponse(
              getResult.getIndex(), getResult.getType(), getResult.getId(), getResult.getVersion());
      update.setGetResult(
          extractGetResult(
              request, getResult.getVersion(), updatedSourceAsMap, updateSourceContentType, null));
      listener.onResponse(update);
    } else {
      logger.warn(
          "Used update operation [{}] for script [{}], doing nothing...",
          operation,
          request.script);
      listener.onResponse(
          new UpdateResponse(
              getResult.getIndex(),
              getResult.getType(),
              getResult.getId(),
              getResult.getVersion()));
    }
  }