private void raiseEarlyFailure(Exception e) { for (AtomicArray.Entry<FirstResult> entry : firstResults.asList()) { try { DiscoveryNode node = nodeIdToDiscoveryNode.apply(entry.value.shardTarget().nodeId()); sendReleaseSearchContext(entry.value.id(), node); } catch (Exception inner) { inner.addSuppressed(e); logger.trace("failed to release context", inner); } } listener.onFailure(e); }
@Override protected void doExecute( final KnapsackPullRequest request, ActionListener<KnapsackPullResponse> listener) { final KnapsackState state = new KnapsackState().setMode("pull").setNodeName(nodeService.nodeName()); final KnapsackPullResponse response = new KnapsackPullResponse().setState(state); try { final BulkTransportClient transportClient = ClientBuilder.builder() .put(ClientBuilder.MAX_ACTIONS_PER_REQUEST, request.getMaxActionsPerBulkRequest()) .put(ClientBuilder.MAX_CONCURRENT_REQUESTS, request.getMaxBulkConcurrency()) .put(ClientBuilder.FLUSH_INTERVAL, TimeValue.timeValueSeconds(5)) .put(clientSettings(client, request)) .toBulkTransportClient(); final BulkNodeClient nodeClient = ClientBuilder.builder() .put(ClientBuilder.MAX_ACTIONS_PER_REQUEST, request.getMaxActionsPerBulkRequest()) .put(ClientBuilder.MAX_CONCURRENT_REQUESTS, request.getMaxBulkConcurrency()) .put(ClientBuilder.FLUSH_INTERVAL, TimeValue.timeValueSeconds(5)) .toBulkNodeClient(client); state.setTimestamp(new DateTime()); response.setRunning(true); knapsack.submit( new Thread() { public void run() { performPull(request, state, transportClient, nodeClient); } }); listener.onResponse(response); } catch (Throwable e) { logger.error(e.getMessage(), e); listener.onFailure(e); } }
public void start() { if (shardsIts.size() == 0) { // no shards try { listener.onResponse(newResponse(request, new AtomicReferenceArray(0), clusterState)); } catch (Throwable e) { listener.onFailure(e); } return; } request.beforeStart(); // count the local operations, and perform the non local ones int shardIndex = -1; for (final ShardIterator shardIt : shardsIts) { shardIndex++; final ShardRouting shard = shardIt.nextOrNull(); if (shard != null) { performOperation(shardIt, shard, shardIndex); } else { // really, no shards active in this group onOperation( null, shardIt, shardIndex, new NoShardAvailableActionException(shardIt.shardId())); } } }
void finishHim() { try { listener.onResponse(newResponse(request, shardsResponses, clusterState)); } catch (Throwable e) { listener.onFailure(e); } }
void performOnPrimary( int primaryShardId, boolean fromDiscoveryListener, final ShardRouting shard, ClusterState clusterState) { try { PrimaryResponse<Response, ReplicaRequest> response = shardOperationOnPrimary( clusterState, new PrimaryOperationRequest(primaryShardId, request)); performReplicas(response); } catch (Exception e) { // shard has not been allocated yet, retry it here if (retryPrimaryException(e)) { primaryOperationStarted.set(false); retry(fromDiscoveryListener, null); return; } if (e instanceof ElasticSearchException && ((ElasticSearchException) e).status() == RestStatus.CONFLICT) { if (logger.isTraceEnabled()) { logger.trace(shard.shortSummary() + ": Failed to execute [" + request + "]", e); } } else { if (logger.isDebugEnabled()) { logger.debug(shard.shortSummary() + ": Failed to execute [" + request + "]", e); } } listener.onFailure(e); } }
@SuppressWarnings("unchecked") void onShardResponse(ShardId shardId, TransportShardMultiPercolateAction.Response response) { logger.trace("{} Percolate shard response", shardId); try { for (TransportShardMultiPercolateAction.Response.Item item : response.items()) { AtomicReferenceArray shardResults = responsesByItemAndShard.get(item.slot()); if (shardResults == null) { assert false : "shardResults can't be null"; continue; } if (item.failed()) { shardResults.set( shardId.id(), new BroadcastShardOperationFailedException(shardId, item.error().string())); } else { shardResults.set(shardId.id(), item.response()); } assert expectedOperationsPerItem.get(item.slot()).get() >= 1 : "slot[" + item.slot() + "] can't be lower than one"; if (expectedOperationsPerItem.get(item.slot()).decrementAndGet() == 0) { // Failure won't bubble up, since we fail the whole request now via the catch clause // below, // so expectedOperationsPerItem will not be decremented twice. reduce(item.slot()); } } } catch (Throwable e) { logger.error("{} Percolate original reduce error", e, shardId); finalListener.onFailure(e); } }
@Override public void login(final RestRequest request, final ActionListener<String[]> listener) { String username = request.param(usernameKey); String password = request.param(passwordKey); final BytesReference content = request.content(); final XContentType xContentType = XContentFactory.xContentType(content); XContentParser parser = null; try { parser = XContentFactory.xContent(xContentType).createParser(content); final XContentParser.Token t = parser.nextToken(); if (t != null) { final Map<String, Object> contentMap = parser.map(); username = MapUtil.getAsString(contentMap, usernameKey, username); password = MapUtil.getAsString(contentMap, passwordKey, password); } } catch (final Exception e) { listener.onFailure(e); return; } finally { if (parser != null) { parser.close(); } } if (username == null) { listener.onResponse(new String[0]); return; } processLogin(username, password, listener); }
private void finishHim() { try { innerFinishHim(); } catch (Exception e) { listener.onFailure(new ReduceSearchPhaseException("fetch", "", e, buildShardFailures())); } }
protected void onCompletion() { Response response = null; try { response = newResponse(request, responses, unavailableShardExceptions, nodeIds, clusterState); } catch (Throwable t) { logger.debug("failed to combine responses from nodes", t); listener.onFailure(t); } if (response != null) { try { listener.onResponse(response); } catch (Throwable t) { listener.onFailure(t); } } }
@Override public void nodeOperation( final NodeFetchRequest request, final ActionListener<NodeFetchResponse> fetchResponse) { statsTables.operationStarted(request.executionNodeId(), request.jobId(), "fetch"); String ramAccountingContextId = String.format(Locale.ENGLISH, "%s: %d", request.jobId(), request.executionNodeId()); final RamAccountingContext ramAccountingContext = new RamAccountingContext(ramAccountingContextId, circuitBreaker); NodeFetchOperation fetchOperation = new NodeFetchOperation( request.jobId(), request.executionNodeId(), request.jobSearchContextDocIds(), request.toFetchReferences(), request.closeContext(), jobContextService, threadPool, functions, ramAccountingContext); Streamer<?>[] streamers = outputStreamers(request.toFetchReferences()); SingleBucketBuilder bucketBuilder = new SingleBucketBuilder(streamers); final NodeFetchResponse response = new NodeFetchResponse(streamers); Futures.addCallback( bucketBuilder.result(), new FutureCallback<Bucket>() { @Override public void onSuccess(@Nullable Bucket result) { assert result != null; response.rows(result); fetchResponse.onResponse(response); statsTables.operationFinished( request.executionNodeId(), null, ramAccountingContext.totalBytes()); ramAccountingContext.close(); } @Override public void onFailure(@Nonnull Throwable t) { fetchResponse.onFailure(t); statsTables.operationFinished( request.executionNodeId(), Exceptions.messageOf(t), ramAccountingContext.totalBytes()); ramAccountingContext.close(); } }); try { fetchOperation.fetch(bucketBuilder); } catch (Throwable t) { fetchResponse.onFailure(t); statsTables.operationFinished( request.executionNodeId(), Exceptions.messageOf(t), ramAccountingContext.totalBytes()); ramAccountingContext.close(); } }
@Override public void onFailure(final Throwable e) { try { close(); } catch (final Exception e1) { // ignore } listener.onFailure(new DfContentException("Failed to write data.", e)); }
void finishAsFailed(Throwable failure) { if (finished.compareAndSet(false, true)) { Releasables.close(indexShardReference); logger.trace("operation failed", failure); listener.onFailure(failure); } else { assert false : "finishAsFailed called but operation is already finished"; } }
void finishWithUnexpectedFailure(Throwable failure) { logger.warn("unexpected error during the primary phase for action [{}]", failure, actionName); if (finished.compareAndSet(false, true)) { Releasables.close(indexShardReference); listener.onFailure(failure); } else { assert false : "finishWithUnexpectedFailure called but operation is already finished"; } }
@Override public void write( final File outputFile, final SearchResponse response, final ActionListener<Void> listener) { try { final OnLoadListener onLoadListener = new OnLoadListener(outputFile, listener); onLoadListener.onResponse(response); } catch (final Exception e) { listener.onFailure(new DfContentException("Failed to write data.", e)); } }
@Test public void testNonEsRejectedExceptionDoesNotResultInRetryButAborts() throws Throwable { expectedException.expect(RuntimeException.class); expectedException.expectMessage("a random exception"); final AtomicReference<ActionListener<ShardUpsertResponse>> ref = new AtomicReference<>(); SymbolBasedTransportShardUpsertActionDelegate transportShardBulkActionDelegate = new SymbolBasedTransportShardUpsertActionDelegate() { @Override public void execute( SymbolBasedShardUpsertRequest request, ActionListener<ShardUpsertResponse> listener) { ref.set(listener); } }; BulkRetryCoordinator bulkRetryCoordinator = new BulkRetryCoordinator(ImmutableSettings.EMPTY); BulkRetryCoordinatorPool coordinatorPool = mock(BulkRetryCoordinatorPool.class); when(coordinatorPool.coordinator(any(ShardId.class))).thenReturn(bulkRetryCoordinator); SymbolBasedShardUpsertRequest.Builder builder = new SymbolBasedShardUpsertRequest.Builder( TimeValue.timeValueMillis(10), false, false, null, new Reference[] {fooRef}, UUID.randomUUID()); final SymbolBasedBulkShardProcessor<SymbolBasedShardUpsertRequest, ShardUpsertResponse> bulkShardProcessor = new SymbolBasedBulkShardProcessor<>( clusterService, mock(TransportBulkCreateIndicesAction.class), ImmutableSettings.EMPTY, coordinatorPool, false, 1, builder, transportShardBulkActionDelegate, UUID.randomUUID()); bulkShardProcessor.add("foo", "1", new Object[] {"bar1"}, null, null); ActionListener<ShardUpsertResponse> listener = ref.get(); listener.onFailure(new RuntimeException("a random exception")); assertFalse(bulkShardProcessor.add("foo", "2", new Object[] {"bar2"}, null, null)); try { bulkShardProcessor.result().get(); } catch (ExecutionException e) { throw e.getCause(); } finally { bulkShardProcessor.close(); } }
@Override public void onFailure(Throwable e) { if (ExceptionsHelper.unwrapCause(e) instanceof ConnectTransportException) { int i = ++this.i; if (i >= nodes.size()) { listener.onFailure( new NoNodeAvailableException( "None of the configured nodes were available: " + nodes, e)); } else { try { callback.doWithNode(nodes.get((index + i) % nodes.size()), this); } catch (Throwable t) { // this exception can't come from the TransportService as it doesn't throw exceptions at // all listener.onFailure(t); } } } else { listener.onFailure(e); } }
public <Response> void execute( NodeListenerCallback<Response> callback, ActionListener<Response> listener) throws ElasticsearchException { ImmutableList<DiscoveryNode> nodes = this.nodes; ensureNodesAreAvailable(nodes); int index = getNodeNumber(); RetryListener<Response> retryListener = new RetryListener<>(callback, listener, nodes, index); DiscoveryNode node = nodes.get((index) % nodes.size()); try { callback.doWithNode(node, retryListener); } catch (Throwable t) { // this exception can't come from the TransportService as it doesn't throw exception at all listener.onFailure(t); } }
public void start() { if (scrollId.getContext().length == 0) { listener.onFailure( new SearchPhaseExecutionException( "query", "no nodes to search on", ShardSearchFailure.EMPTY_ARRAY)); return; } ScrollIdForNode[] context = scrollId.getContext(); for (int i = 0; i < context.length; i++) { ScrollIdForNode target = context[i]; DiscoveryNode node = nodes.get(target.getNode()); if (node != null) { executePhase(i, node, target.getScrollId()); } else { if (logger.isDebugEnabled()) { logger.debug( "Node [" + target.getNode() + "] not available for scroll request [" + scrollId.getSource() + "]"); } successfulOps.decrementAndGet(); if (counter.decrementAndGet() == 0) { finishHim(); } } } for (ScrollIdForNode target : scrollId.getContext()) { DiscoveryNode node = nodes.get(target.getNode()); if (node == null) { if (logger.isDebugEnabled()) { logger.debug( "Node [" + target.getNode() + "] not available for scroll request [" + scrollId.getSource() + "]"); } successfulOps.decrementAndGet(); if (counter.decrementAndGet() == 0) { finishHim(); } } } }
void retry(@Nullable final Throwable failure) { if (observer.isTimedOut()) { // we running as a last attempt after a timeout has happened. don't retry Throwable listenFailure = failure; if (listenFailure == null) { if (shardIt == null) { listenFailure = new UnavailableShardsException( request.concreteIndex(), -1, "Timeout waiting for [{}], request: {}", request.timeout(), actionName); } else { listenFailure = new UnavailableShardsException( shardIt.shardId(), "[{}] shardIt, [{}] active : Timeout waiting for [{}], request: {}", shardIt.size(), shardIt.sizeActive(), request.timeout(), actionName); } } listener.onFailure(listenFailure); return; } observer.waitForNextChange( new ClusterStateObserver.Listener() { @Override public void onNewClusterState(ClusterState state) { doStart(); } @Override public void onClusterServiceClose() { listener.onFailure(new NodeClosedException(nodes.getLocalNode())); } @Override public void onTimeout(TimeValue timeout) { // just to be on the safe side, see if we can start it now? doStart(); } }, request.timeout()); }
private void onPhaseFailure(Throwable t, long searchId, int shardIndex) { if (logger.isDebugEnabled()) { logger.debug("[{}] Failed to execute query phase", t, searchId); } addShardFailure(shardIndex, new ShardSearchFailure(t)); successfulOps.decrementAndGet(); if (counter.decrementAndGet() == 0) { if (successfulOps.get() == 0) { listener.onFailure( new SearchPhaseExecutionException( "query_fetch", "all shards failed", t, buildShardFailures())); } else { finishHim(); } } }
public void start() { if (nodeIds.size() == 0) { try { onCompletion(); } catch (Throwable e) { listener.onFailure(e); } } else { int nodeIndex = -1; for (Map.Entry<String, List<ShardRouting>> entry : nodeIds.entrySet()) { nodeIndex++; DiscoveryNode node = nodes.get(entry.getKey()); sendNodeRequest(node, entry.getValue(), nodeIndex); } } }
@Override public void updateUser( final String username, final String password, final String[] roles, final ActionListener<Void> listener) { try { final XContentBuilder builder = jsonBuilder().startObject().field("doc").startObject(); if (password != null) { builder.field("password", hashPassword(password)); } if (roles != null) { builder.field("roles", roles); } builder.endObject().endObject(); final String userId = getUserId(username); client .prepareUpdate(authIndex, userType, userId) .setSource(builder) .setRefresh(true) .execute( new ActionListener<UpdateResponse>() { @Override public void onResponse(final UpdateResponse response) { if (!userId.equals(response.getId())) { listener.onFailure( new AuthException(RestStatus.BAD_REQUEST, "Could not update " + username)); } else { listener.onResponse(null); } } @Override public void onFailure(final Throwable e) { listener.onFailure( new AuthException( RestStatus.INTERNAL_SERVER_ERROR, "Could not update " + username, e)); } }); } catch (final Exception e) { listener.onFailure( new AuthException(RestStatus.INTERNAL_SERVER_ERROR, "Could not update " + username, e)); } }
@Override public void performOn( ShardRouting replicaRouting, IndexRequest request, ActionListener<TransportResponse.Empty> listener) { try { IndexShard replica = replicationGroup .replicas .stream() .filter(s -> replicaRouting.isSameAllocation(s.routingEntry())) .findFirst() .get(); TransportIndexAction.executeIndexRequestOnReplica(request, replica); listener.onResponse(TransportResponse.Empty.INSTANCE); } catch (Exception t) { listener.onFailure(t); } }
@Override protected void doExecute( final KnapsackStateRequest request, ActionListener<KnapsackStateResponse> listener) { final KnapsackStateResponse response = new KnapsackStateResponse(); try { if (knapsack != null) { for (KnapsackState state : knapsack.getExports()) { response.addState(state); } for (KnapsackState state : knapsack.getImports()) { response.addState(state); } } listener.onResponse(response); } catch (Throwable e) { logger.error(e.getMessage(), e); listener.onFailure(e); } }
@Override public void createUser( final String username, final String password, final String[] roles, final ActionListener<Void> listener) { try { final XContentBuilder builder = jsonBuilder() // .startObject() // .field("username", username) // .field("password", hashPassword(password)) // .field("roles", roles) // .endObject(); client .prepareIndex(authIndex, userType, getUserId(username)) .setSource(builder) .setRefresh(true) .execute( new ActionListener<IndexResponse>() { @Override public void onResponse(final IndexResponse response) { listener.onResponse(null); } @Override public void onFailure(final Throwable e) { listener.onFailure( new AuthException( RestStatus.INTERNAL_SERVER_ERROR, "Could not create " + username, e)); } }); } catch (final Exception e) { listener.onFailure( new AuthException(RestStatus.INTERNAL_SERVER_ERROR, "Could not create " + username, e)); } }
@SuppressWarnings("unchecked") void onShardFailure(ShardId shardId, Throwable e) { logger.debug("{} Shard multi percolate failure", e, shardId); try { IntArrayList slots = shardToSlots.get(shardId); for (int i = 0; i < slots.size(); i++) { int slot = slots.get(i); AtomicReferenceArray shardResults = responsesByItemAndShard.get(slot); if (shardResults == null) { continue; } shardResults.set(shardId.id(), new BroadcastShardOperationFailedException(shardId, e)); assert expectedOperationsPerItem.get(slot).get() >= 1 : "slot[" + slot + "] can't be lower than one. Caused by: " + e.getMessage(); if (expectedOperationsPerItem.get(slot).decrementAndGet() == 0) { reduce(slot); } } } catch (Throwable t) { logger.error("{} Percolate original reduce error, original error {}", t, shardId, e); finalListener.onFailure(t); } }
protected void doStart() { final ClusterState clusterState = observer.observedState(); final Predicate<ClusterState> masterChangePredicate = MasterNodeChangePredicate.build(clusterState); final DiscoveryNodes nodes = clusterState.nodes(); if (nodes.isLocalNodeElectedMaster() || localExecute(request)) { // check for block, if blocked, retry, else, execute locally final ClusterBlockException blockException = checkBlock(request, clusterState); if (blockException != null) { if (!blockException.retryable()) { listener.onFailure(blockException); } else { logger.trace("can't execute due to a cluster block, retrying", blockException); retry( blockException, newState -> { ClusterBlockException newException = checkBlock(request, newState); return (newException == null || !newException.retryable()); }); } } else { ActionListener<Response> delegate = new ActionListener<Response>() { @Override public void onResponse(Response response) { listener.onResponse(response); } @Override public void onFailure(Exception t) { if (t instanceof Discovery.FailedToCommitClusterStateException || (t instanceof NotMasterException)) { logger.debug( (org.apache.logging.log4j.util.Supplier<?>) () -> new ParameterizedMessage( "master could not publish cluster state or stepped down before publishing action [{}], scheduling a retry", actionName), t); retry(t, masterChangePredicate); } else { listener.onFailure(t); } } }; taskManager.registerChildTask(task, nodes.getLocalNodeId()); threadPool .executor(executor) .execute( new ActionRunnable(delegate) { @Override protected void doRun() throws Exception { masterOperation(task, request, clusterState, delegate); } }); } } else { if (nodes.getMasterNode() == null) { logger.debug("no known master node, scheduling a retry"); retry(null, masterChangePredicate); } else { taskManager.registerChildTask(task, nodes.getMasterNode().getId()); transportService.sendRequest( nodes.getMasterNode(), actionName, request, new ActionListenerResponseHandler<Response>( listener, TransportMasterNodeAction.this::newResponse) { @Override public void handleException(final TransportException exp) { Throwable cause = exp.unwrapCause(); if (cause instanceof ConnectTransportException) { // we want to retry here a bit to see if a new master is elected logger.debug( "connection exception while trying to forward request with action name [{}] to master node [{}], scheduling a retry. Error: [{}]", actionName, nodes.getMasterNode(), exp.getDetailedMessage()); retry(cause, masterChangePredicate); } else { listener.onFailure(exp); } } }); } } }
public void start() { if (shardsIts.size() == 0) { // no shards try { listener.onResponse(newResponse(request, new AtomicReferenceArray(0), clusterState)); } catch (Throwable e) { listener.onFailure(e); } } request.beforeStart(); // count the local operations, and perform the non local ones int localOperations = 0; int shardIndex = -1; for (final ShardIterator shardIt : shardsIts) { shardIndex++; final ShardRouting shard = shardIt.firstOrNull(); if (shard != null) { if (shard.currentNodeId().equals(nodes.localNodeId())) { localOperations++; } else { // do the remote operation here, the localAsync flag is not relevant performOperation(shardIt, shardIndex, true); } } else { // really, no shards active in this group onOperation( null, shardIt, shardIndex, new NoShardAvailableActionException(shardIt.shardId())); } } // we have local operations, perform them now if (localOperations > 0) { if (request.operationThreading() == BroadcastOperationThreading.SINGLE_THREAD) { request.beforeLocalFork(); threadPool .executor(executor) .execute( new Runnable() { @Override public void run() { int shardIndex = -1; for (final ShardIterator shardIt : shardsIts) { shardIndex++; final ShardRouting shard = shardIt.firstOrNull(); if (shard != null) { if (shard.currentNodeId().equals(nodes.localNodeId())) { performOperation(shardIt, shardIndex, false); } } } } }); } else { boolean localAsync = request.operationThreading() == BroadcastOperationThreading.THREAD_PER_SHARD; if (localAsync) { request.beforeLocalFork(); } shardIndex = -1; for (final ShardIterator shardIt : shardsIts) { shardIndex++; final ShardRouting shard = shardIt.firstOrNull(); if (shard != null) { if (shard.currentNodeId().equals(nodes.localNodeId())) { performOperation(shardIt, shardIndex, localAsync); } } } } } }
protected boolean doStart() { nodes = observer.observedState().nodes(); try { ClusterBlockException blockException = checkGlobalBlock(observer.observedState()); if (blockException != null) { if (blockException.retryable()) { retry(blockException); return false; } else { throw blockException; } } internalRequest.concreteIndex( observer .observedState() .metaData() .concreteSingleIndex( internalRequest.request().index(), internalRequest.request().indicesOptions())); // check if we need to execute, and if not, return if (!resolveRequest(observer.observedState(), internalRequest, listener)) { return true; } blockException = checkRequestBlock(observer.observedState(), internalRequest); if (blockException != null) { if (blockException.retryable()) { retry(blockException); return false; } else { throw blockException; } } shardIt = shards(observer.observedState(), internalRequest); } catch (Throwable e) { listener.onFailure(e); return true; } // no shardIt, might be in the case between index gateway recovery and shardIt initialization if (shardIt.size() == 0) { retry(null); return false; } // this transport only make sense with an iterator that returns a single shard routing (like // primary) assert shardIt.size() == 1; ShardRouting shard = shardIt.nextOrNull(); assert shard != null; if (!shard.active()) { retry(null); return false; } if (!operationStarted.compareAndSet(false, true)) { return true; } internalRequest.request().shardId = shardIt.shardId().id(); if (shard.currentNodeId().equals(nodes.localNodeId())) { internalRequest.request().beforeLocalFork(); try { threadPool .executor(executor) .execute( new Runnable() { @Override public void run() { try { shardOperation(internalRequest, listener); } catch (Throwable e) { if (retryOnFailure(e)) { operationStarted.set(false); // we already marked it as started when we executed it (removed the // listener) so pass false // to re-add to the cluster listener retry(null); } else { listener.onFailure(e); } } } }); } catch (Throwable e) { if (retryOnFailure(e)) { retry(null); } else { listener.onFailure(e); } } } else { DiscoveryNode node = nodes.get(shard.currentNodeId()); transportService.sendRequest( node, actionName, internalRequest.request(), transportOptions(), new BaseTransportResponseHandler<Response>() { @Override public Response newInstance() { return newResponse(); } @Override public String executor() { return ThreadPool.Names.SAME; } @Override public void handleResponse(Response response) { listener.onResponse(response); } @Override public void handleException(TransportException exp) { // if we got disconnected from the node, or the node / shard is not in the right // state (being closed) if (exp.unwrapCause() instanceof ConnectTransportException || exp.unwrapCause() instanceof NodeClosedException || retryOnFailure(exp)) { operationStarted.set(false); // we already marked it as started when we executed it (removed the listener) so // pass false // to re-add to the cluster listener retry(null); } else { listener.onFailure(exp); } } }); } return true; }
@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)); } } }); } }