void performOnReplica( final PrimaryResponse<Response, ReplicaRequest> response, final AtomicInteger counter, final ShardRouting shard, String nodeId) { // if we don't have that node, it means that it might have failed and will be created again, // in // this case, we don't have to do the operation, and just let it failover if (!nodes.nodeExists(nodeId)) { if (counter.decrementAndGet() == 0) { listener.onResponse(response.response()); } return; } final ReplicaOperationRequest shardRequest = new ReplicaOperationRequest(shardIt.shardId().id(), response.replicaRequest()); if (!nodeId.equals(nodes.localNodeId())) { DiscoveryNode node = nodes.get(nodeId); transportService.sendRequest( node, transportReplicaAction, shardRequest, transportOptions, new VoidTransportResponseHandler(ThreadPool.Names.SAME) { @Override public void handleResponse(VoidStreamable vResponse) { finishIfPossible(); } @Override public void handleException(TransportException exp) { if (!ignoreReplicaException(exp.unwrapCause())) { logger.warn( "Failed to perform " + transportAction + " on replica " + shardIt.shardId(), exp); shardStateAction.shardFailed( shard, "Failed to perform [" + transportAction + "] on replica, message [" + detailedMessage(exp) + "]"); } finishIfPossible(); } private void finishIfPossible() { if (counter.decrementAndGet() == 0) { listener.onResponse(response.response()); } } }); } else { if (request.operationThreaded()) { request.beforeLocalFork(); threadPool .executor(executor) .execute( new Runnable() { @Override public void run() { try { shardOperationOnReplica(shardRequest); } catch (Exception e) { if (!ignoreReplicaException(e)) { logger.warn( "Failed to perform " + transportAction + " on replica " + shardIt.shardId(), e); shardStateAction.shardFailed( shard, "Failed to perform [" + transportAction + "] on replica, message [" + detailedMessage(e) + "]"); } } if (counter.decrementAndGet() == 0) { listener.onResponse(response.response()); } } }); } else { try { shardOperationOnReplica(shardRequest); } catch (Exception e) { if (!ignoreReplicaException(e)) { logger.warn( "Failed to perform " + transportAction + " on replica" + shardIt.shardId(), e); shardStateAction.shardFailed( shard, "Failed to perform [" + transportAction + "] on replica, message [" + detailedMessage(e) + "]"); } } if (counter.decrementAndGet() == 0) { listener.onResponse(response.response()); } } } }
void performReplicas(final PrimaryResponse<Response, ReplicaRequest> response) { if (ignoreReplicas() || shardIt.size() == 1 /* no replicas */) { postPrimaryOperation(request, response); listener.onResponse(response.response()); return; } // initialize the counter int replicaCounter = shardIt.assignedReplicasIncludingRelocating(); if (replicaCounter == 0) { postPrimaryOperation(request, response); listener.onResponse(response.response()); return; } if (replicationType == ReplicationType.ASYNC) { postPrimaryOperation(request, response); // async replication, notify the listener listener.onResponse(response.response()); // now, trick the counter so it won't decrease to 0 and notify the listeners replicaCounter = Integer.MIN_VALUE; } // we add one to the replica count to do the postPrimaryOperation replicaCounter++; AtomicInteger counter = new AtomicInteger(replicaCounter); shardIt.reset(); // reset the iterator ShardRouting shard; while ((shard = shardIt.nextOrNull()) != null) { // if its unassigned, nothing to do here... if (shard.unassigned()) { continue; } // if the shard is primary and relocating, add one to the counter since we perform it on the // replica as well // (and we already did it on the primary) boolean doOnlyOnRelocating = false; if (shard.primary()) { if (shard.relocating()) { doOnlyOnRelocating = true; } else { continue; } } // we index on a replica that is initializing as well since we might not have got the event // yet that it was started. We will get an exception IllegalShardState exception if its not // started // and that's fine, we will ignore it if (!doOnlyOnRelocating) { performOnReplica(response, counter, shard, shard.currentNodeId()); } if (shard.relocating()) { performOnReplica(response, counter, shard, shard.relocatingNodeId()); } } // now do the postPrimary operation, and check if the listener needs to be invoked postPrimaryOperation(request, response); // we also invoke here in case replicas finish before postPrimaryAction does if (counter.decrementAndGet() == 0) { listener.onResponse(response.response()); } }