use of org.infinispan.commons.util.ArrayCollector in project infinispan by infinispan.
the class ScatteredDistributionInterceptor method visitReadOnlyManyCommand.
@Override
public Object visitReadOnlyManyCommand(InvocationContext ctx, ReadOnlyManyCommand command) throws Throwable {
if (command.hasAnyFlag(FlagBitSets.CACHE_MODE_LOCAL | FlagBitSets.SKIP_REMOTE_LOOKUP)) {
return handleLocalOnlyReadManyCommand(ctx, command, command.getKeys());
}
LocalizedCacheTopology cacheTopology = checkTopology(command);
if (!ctx.isOriginLocal()) {
return handleRemoteReadManyCommand(ctx, command, command.getKeys());
}
if (command.getKeys().isEmpty()) {
return Stream.empty();
}
ConsistentHash ch = cacheTopology.getReadConsistentHash();
int estimateForOneNode = 2 * command.getKeys().size() / ch.getMembers().size();
Function<Address, List<Object>> createList = k -> new ArrayList<>(estimateForOneNode);
Map<Address, List<Object>> requestedKeys = new HashMap<>();
List<Object> localKeys = null;
for (Object key : command.getKeys()) {
if (ctx.lookupEntry(key) != null) {
if (localKeys == null) {
localKeys = new ArrayList<>();
}
localKeys.add(key);
continue;
}
DistributionInfo info = cacheTopology.getDistribution(key);
assert !info.isPrimary();
if (info.primary() == null) {
throw AllOwnersLostException.INSTANCE;
}
requestedKeys.computeIfAbsent(info.primary(), createList).add(key);
}
MergingCompletableFuture<Object> allFuture = new MergingCompletableFuture<>(requestedKeys.size() + (localKeys == null ? 0 : 1), new Object[command.getKeys().size()], Arrays::stream);
int offset = 0;
if (localKeys != null) {
offset += localKeys.size();
ReadOnlyManyCommand localCommand = new ReadOnlyManyCommand(command).withKeys(localKeys);
invokeNextAndFinally(ctx, localCommand, (rCtx, rCommand, rv, throwable) -> {
if (throwable != null) {
allFuture.completeExceptionally(throwable);
} else {
try {
((Stream) rv).collect(new ArrayCollector(allFuture.results));
allFuture.countDown();
} catch (Throwable t) {
allFuture.completeExceptionally(t);
}
}
});
}
for (Map.Entry<Address, List<Object>> addressKeys : requestedKeys.entrySet()) {
List<Object> keysForAddress = addressKeys.getValue();
ReadOnlyManyCommand remoteCommand = new ReadOnlyManyCommand(command).withKeys(keysForAddress);
remoteCommand.setTopologyId(command.getTopologyId());
Set<Address> target = Collections.singleton(addressKeys.getKey());
int myOffset = offset;
SingletonMapResponseCollector collector = SingletonMapResponseCollector.ignoreLeavers();
CompletionStage<Map<Address, Response>> rpc = rpcManager.invokeCommand(target, remoteCommand, collector, rpcManager.getSyncRpcOptions());
rpc.whenComplete((responseMap, throwable) -> {
if (throwable != null) {
allFuture.completeExceptionally(throwable);
return;
}
SuccessfulResponse response = getSuccessfulResponseOrFail(responseMap, allFuture, rsp -> allFuture.completeExceptionally(rsp instanceof UnsureResponse ? OutdatedTopologyException.RETRY_NEXT_TOPOLOGY : AllOwnersLostException.INSTANCE));
if (response == null) {
return;
}
try {
Object[] values = (Object[]) response.getResponseValue();
if (values != null) {
System.arraycopy(values, 0, allFuture.results, myOffset, values.length);
allFuture.countDown();
} else {
allFuture.completeExceptionally(new IllegalStateException("Unexpected response value " + response.getResponseValue()));
}
} catch (Throwable t) {
allFuture.completeExceptionally(t);
}
});
offset += keysForAddress.size();
}
return asyncValue(allFuture);
}
Aggregations