use of org.infinispan.remoting.responses.UnsureResponse in project infinispan by infinispan.
the class ClusteringInterceptor method getSuccessfulResponseOrFail.
protected static SuccessfulResponse getSuccessfulResponseOrFail(Map<Address, Response> responseMap, CompletableFuture<?> future, Consumer<Response> cacheNotFound) {
Iterator<Map.Entry<Address, Response>> it = responseMap.entrySet().iterator();
if (!it.hasNext()) {
future.completeExceptionally(AllOwnersLostException.INSTANCE);
return null;
}
Map.Entry<Address, Response> e = it.next();
Address sender = e.getKey();
Response response = e.getValue();
if (it.hasNext()) {
future.completeExceptionally(new IllegalStateException("Too many responses " + responseMap));
} else if (response instanceof SuccessfulResponse) {
return (SuccessfulResponse) response;
} else if (response instanceof CacheNotFoundResponse || response instanceof UnsureResponse) {
if (cacheNotFound == null) {
future.completeExceptionally(unexpected(sender, response));
} else {
try {
cacheNotFound.accept(response);
} catch (Throwable t) {
future.completeExceptionally(t);
}
}
} else {
future.completeExceptionally(unexpected(sender, response));
}
return null;
}
use of org.infinispan.remoting.responses.UnsureResponse in project infinispan by infinispan.
the class ScatteredDistributionInterceptor method handleReadCommand.
private Object handleReadCommand(InvocationContext ctx, AbstractDataCommand command) throws Throwable {
LocalizedCacheTopology cacheTopology = checkTopology(command);
// SKIP_OWNERSHIP_CHECK is added when the entry is prefetched from remote node
// TODO [rvansa]: local lookup and hinted read, see improvements in package-info
CacheEntry entry = ctx.lookupEntry(command.getKey());
if (entry != null) {
return invokeNext(ctx, command);
}
DistributionInfo info = cacheTopology.getSegmentDistribution(command.getSegment());
if (info.isPrimary()) {
if (log.isTraceEnabled()) {
log.tracef("In topology %d this is primary owner", cacheTopology.getTopologyId());
}
return invokeNext(ctx, command);
} else if (command.hasAnyFlag(FlagBitSets.SKIP_OWNERSHIP_CHECK)) {
if (log.isTraceEnabled()) {
log.trace("Ignoring ownership");
}
return invokeNext(ctx, command);
} else if (info.primary() == null) {
throw OutdatedTopologyException.RETRY_NEXT_TOPOLOGY;
} else if (ctx.isOriginLocal()) {
if (isLocalModeForced(command) || command.hasAnyFlag(FlagBitSets.SKIP_REMOTE_LOOKUP)) {
entryFactory.wrapExternalEntry(ctx, command.getKey(), NullCacheEntry.getInstance(), false, false);
return invokeNext(ctx, command);
}
ClusteredGetCommand clusteredGetCommand = cf.buildClusteredGetCommand(command.getKey(), info.segmentId(), command.getFlagsBitSet());
clusteredGetCommand.setTopologyId(command.getTopologyId());
ResponseCollector<Response> collector = PassthroughSingleResponseCollector.INSTANCE;
CompletionStage<Response> rpcFuture = rpcManager.invokeCommand(info.primary(), clusteredGetCommand, collector, rpcManager.getSyncRpcOptions());
Object key = clusteredGetCommand.getKey();
return asyncInvokeNext(ctx, command, rpcFuture.thenAccept(response -> {
if (response.isSuccessful()) {
InternalCacheValue value = (InternalCacheValue) ((SuccessfulResponse) response).getResponseValue();
if (value != null) {
InternalCacheEntry cacheEntry = value.toInternalCacheEntry(key);
entryFactory.wrapExternalEntry(ctx, key, cacheEntry, true, false);
} else {
entryFactory.wrapExternalEntry(ctx, key, NullCacheEntry.getInstance(), false, false);
}
} else if (response instanceof UnsureResponse) {
throw OutdatedTopologyException.RETRY_NEXT_TOPOLOGY;
} else if (response instanceof CacheNotFoundResponse) {
throw AllOwnersLostException.INSTANCE;
} else if (response instanceof ExceptionResponse) {
throw ResponseCollectors.wrapRemoteException(info.primary(), ((ExceptionResponse) response).getException());
} else {
throw new IllegalArgumentException("Unexpected response " + response);
}
}));
} else {
return UnsureResponse.INSTANCE;
}
}
use of org.infinispan.remoting.responses.UnsureResponse in project infinispan by infinispan.
the class ScatteredDistributionInterceptor method visitReadOnlyKeyCommand.
@Override
public Object visitReadOnlyKeyCommand(InvocationContext ctx, ReadOnlyKeyCommand command) throws Throwable {
Object key = command.getKey();
CacheEntry entry = ctx.lookupEntry(key);
if (entry != null) {
// the entry is owned locally (it is NullCacheEntry if it was not found), no need to go remote
return invokeNext(ctx, command);
}
if (!ctx.isOriginLocal()) {
return UnsureResponse.INSTANCE;
}
if (isLocalModeForced(command) || command.hasAnyFlag(FlagBitSets.SKIP_REMOTE_LOOKUP)) {
if (ctx.lookupEntry(command.getKey()) == null) {
entryFactory.wrapExternalEntry(ctx, command.getKey(), NullCacheEntry.getInstance(), false, false);
}
return invokeNext(ctx, command);
}
DistributionInfo info = checkTopology(command).getDistribution(command.getKey());
if (info.primary() == null) {
throw AllOwnersLostException.INSTANCE;
}
ResponseCollector<Response> collector = PassthroughSingleResponseCollector.INSTANCE;
CompletionStage<Response> rpc = rpcManager.invokeCommand(info.primary(), command, collector, rpcManager.getSyncRpcOptions());
return asyncValue(rpc.thenApply(response -> {
if (response.isSuccessful()) {
return ((SuccessfulResponse) response).getResponseValue();
} else if (response instanceof UnsureResponse) {
throw OutdatedTopologyException.RETRY_NEXT_TOPOLOGY;
} else if (response instanceof CacheNotFoundResponse) {
throw AllOwnersLostException.INSTANCE;
} else if (response instanceof ExceptionResponse) {
throw ResponseCollectors.wrapRemoteException(info.primary(), ((ExceptionResponse) response).getException());
} else {
throw new IllegalArgumentException("Unexpected response " + response);
}
}));
}
use of org.infinispan.remoting.responses.UnsureResponse 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);
}
use of org.infinispan.remoting.responses.UnsureResponse in project infinispan by infinispan.
the class ScatteredDistributionInterceptor method handleGetAllResponse.
private void handleGetAllResponse(Map<Address, Response> responseMap, Throwable throwable, InvocationContext ctx, List<?> keys, ClusteredGetAllFuture allFuture) {
if (throwable != null) {
allFuture.completeExceptionally(throwable);
return;
}
// While upon lost owners in dist/repl mode we only return a map with less entries, in scattered mode
// we need to retry the operation in next topology which should have the new primary owners assigned
SuccessfulResponse response = getSuccessfulResponseOrFail(responseMap, allFuture, rsp -> allFuture.completeExceptionally(rsp instanceof UnsureResponse ? OutdatedTopologyException.RETRY_NEXT_TOPOLOGY : AllOwnersLostException.INSTANCE));
if (response == null) {
return;
}
Object responseValue = response.getResponseValue();
if (!(responseValue instanceof InternalCacheValue[])) {
allFuture.completeExceptionally(new IllegalStateException("Unexpected response value: " + responseValue));
return;
}
InternalCacheValue[] values = (InternalCacheValue[]) responseValue;
if (keys.size() != values.length) {
allFuture.completeExceptionally(new CacheException("Request and response lengths differ: keys=" + keys + ", response=" + Arrays.toString(values)));
return;
}
synchronized (allFuture) {
if (allFuture.isDone()) {
return;
}
for (int i = 0; i < values.length; ++i) {
Object key = keys.get(i);
InternalCacheValue value = values[i];
CacheEntry entry = value == null ? NullCacheEntry.getInstance() : value.toInternalCacheEntry(key);
entryFactory.wrapExternalEntry(ctx, key, entry, true, false);
}
if (--allFuture.counter == 0) {
allFuture.complete(null);
}
}
}
Aggregations