@Override protected void doExecute( final MultiPercolateRequest request, final ActionListener<MultiPercolateResponse> listener) { final ClusterState clusterState = clusterService.state(); clusterState.blocks().globalBlockedRaiseException(ClusterBlockLevel.READ); final List<Object> percolateRequests = new ArrayList<>(request.requests().size()); // Can have a mixture of percolate requests. (normal percolate requests & percolate existing // doc), // so we need to keep track for what percolate request we had a get request final IntArrayList getRequestSlots = new IntArrayList(); List<GetRequest> existingDocsRequests = new ArrayList<>(); for (int slot = 0; slot < request.requests().size(); slot++) { PercolateRequest percolateRequest = request.requests().get(slot); percolateRequest.startTime = System.currentTimeMillis(); percolateRequests.add(percolateRequest); if (percolateRequest.getRequest() != null) { existingDocsRequests.add(percolateRequest.getRequest()); getRequestSlots.add(slot); } } if (!existingDocsRequests.isEmpty()) { final MultiGetRequest multiGetRequest = new MultiGetRequest(request); for (GetRequest getRequest : existingDocsRequests) { multiGetRequest.add( new MultiGetRequest.Item(getRequest.index(), getRequest.type(), getRequest.id()) .routing(getRequest.routing())); } multiGetAction.execute( multiGetRequest, new ActionListener<MultiGetResponse>() { @Override public void onResponse(MultiGetResponse multiGetItemResponses) { for (int i = 0; i < multiGetItemResponses.getResponses().length; i++) { MultiGetItemResponse itemResponse = multiGetItemResponses.getResponses()[i]; int slot = getRequestSlots.get(i); if (!itemResponse.isFailed()) { GetResponse getResponse = itemResponse.getResponse(); if (getResponse.isExists()) { PercolateRequest originalRequest = (PercolateRequest) percolateRequests.get(slot); percolateRequests.set( slot, new PercolateRequest(originalRequest, getResponse.getSourceAsBytesRef())); } else { logger.trace("mpercolate existing doc, item[{}] doesn't exist", slot); percolateRequests.set( slot, new DocumentMissingException( null, getResponse.getType(), getResponse.getId())); } } else { logger.trace( "mpercolate existing doc, item[{}] failure {}", slot, itemResponse.getFailure()); percolateRequests.set(slot, itemResponse.getFailure()); } } new ASyncAction(request, percolateRequests, listener, clusterState).run(); } @Override public void onFailure(Throwable e) { listener.onFailure(e); } }); } else { new ASyncAction(request, percolateRequests, listener, clusterState).run(); } }
ASyncAction( MultiPercolateRequest multiPercolateRequest, List<Object> percolateRequests, ActionListener<MultiPercolateResponse> finalListener, ClusterState clusterState) { this.finalListener = finalListener; this.multiPercolateRequest = multiPercolateRequest; this.percolateRequests = percolateRequests; responsesByItemAndShard = new AtomicReferenceArray<>(percolateRequests.size()); expectedOperationsPerItem = new AtomicReferenceArray<>(percolateRequests.size()); reducedResponses = new AtomicArray<>(percolateRequests.size()); // Resolving concrete indices and routing and grouping the requests by shard requestsByShard = new HashMap<>(); // Keep track what slots belong to what shard, in case a request to a shard fails on all // copies shardToSlots = new HashMap<>(); int expectedResults = 0; for (int slot = 0; slot < percolateRequests.size(); slot++) { Object element = percolateRequests.get(slot); assert element != null; if (element instanceof PercolateRequest) { PercolateRequest percolateRequest = (PercolateRequest) element; String[] concreteIndices; try { concreteIndices = indexNameExpressionResolver.concreteIndices(clusterState, percolateRequest); } catch (IndexNotFoundException e) { reducedResponses.set(slot, e); responsesByItemAndShard.set(slot, new AtomicReferenceArray(0)); expectedOperationsPerItem.set(slot, new AtomicInteger(0)); continue; } Map<String, Set<String>> routing = indexNameExpressionResolver.resolveSearchRouting( clusterState, percolateRequest.routing(), percolateRequest.indices()); // TODO: I only need shardIds, ShardIterator(ShardRouting) is only needed in // TransportShardMultiPercolateAction GroupShardsIterator shards = clusterService .operationRouting() .searchShards( clusterState, concreteIndices, routing, percolateRequest.preference()); if (shards.size() == 0) { reducedResponses.set(slot, new UnavailableShardsException(null, "No shards available")); responsesByItemAndShard.set(slot, new AtomicReferenceArray(0)); expectedOperationsPerItem.set(slot, new AtomicInteger(0)); continue; } // The shard id is used as index in the atomic ref array, so we need to find out how many // shards there are regardless of routing: int numShards = clusterService .operationRouting() .searchShardsCount(clusterState, concreteIndices, null); responsesByItemAndShard.set(slot, new AtomicReferenceArray(numShards)); expectedOperationsPerItem.set(slot, new AtomicInteger(shards.size())); for (ShardIterator shard : shards) { ShardId shardId = shard.shardId(); TransportShardMultiPercolateAction.Request requests = requestsByShard.get(shardId); if (requests == null) { requestsByShard.put( shardId, requests = new TransportShardMultiPercolateAction.Request( multiPercolateRequest, shardId.getIndex(), shardId.getId(), percolateRequest.preference())); } logger.trace("Adding shard[{}] percolate request for item[{}]", shardId, slot); requests.add( new TransportShardMultiPercolateAction.Request.Item( slot, new PercolateShardRequest(shardId, percolateRequest))); IntArrayList items = shardToSlots.get(shardId); if (items == null) { shardToSlots.put(shardId, items = new IntArrayList()); } items.add(slot); } expectedResults++; } else if (element instanceof Throwable || element instanceof MultiGetResponse.Failure) { logger.trace("item[{}] won't be executed, reason: {}", slot, element); reducedResponses.set(slot, element); responsesByItemAndShard.set(slot, new AtomicReferenceArray(0)); expectedOperationsPerItem.set(slot, new AtomicInteger(0)); } } expectedOperations = new AtomicInteger(expectedResults); }