use of org.infinispan.remoting.responses.ValidResponse in project infinispan by infinispan.
the class ClusteringInterceptor method visitTouchCommand.
@Override
public Object visitTouchCommand(InvocationContext ctx, TouchCommand command) throws Throwable {
if (command.hasAnyFlag(FlagBitSets.CACHE_MODE_LOCAL | FlagBitSets.SKIP_REMOTE_LOOKUP)) {
return invokeNext(ctx, command);
}
LocalizedCacheTopology cacheTopology = checkTopologyId(command);
DistributionInfo info = cacheTopology.getSegmentDistribution(command.getSegment());
// Scattered any node could be a backup, so we have to touch all members
List<Address> owners = isScattered ? cacheTopology.getActualMembers() : info.readOwners();
if (touchMode == TouchMode.ASYNC) {
if (ctx.isOriginLocal()) {
// Send to all the owners
rpcManager.sendToMany(owners, command, DeliverOrder.NONE);
}
return invokeNext(ctx, command);
}
if (info.isPrimary()) {
AbstractTouchResponseCollector collector = isScattered ? ScatteredTouchResponseCollector.INSTANCE : TouchResponseCollector.INSTANCE;
CompletionStage<Boolean> remoteInvocation = rpcManager.invokeCommand(owners, command, collector, rpcManager.getSyncRpcOptions());
return invokeNextThenApply(ctx, command, (rCtx, rCommand, rValue) -> {
Boolean touchedLocally = (Boolean) rValue;
if (touchedLocally) {
return asyncValue(remoteInvocation);
}
// If primary can't touch - it doesn't matter about others
return Boolean.FALSE;
});
} else if (ctx.isOriginLocal()) {
// Send to the primary owner
CompletionStage<ValidResponse> remoteInvocation = rpcManager.invokeCommand(info.primary(), command, SingleResponseCollector.validOnly(), rpcManager.getSyncRpcOptions());
return asyncValue(remoteInvocation).thenApply(ctx, command, (rCtx, rCommand, rResponse) -> ((ValidResponse) rResponse).getResponseValue());
}
return invokeNext(ctx, command);
}
use of org.infinispan.remoting.responses.ValidResponse in project infinispan by infinispan.
the class ScatteredDistributionInterceptor method handleWriteManyOnOrigin.
private <C extends WriteCommand, Container, Item> Object handleWriteManyOnOrigin(InvocationContext ctx, C command, WriteManyCommandHelper<C, Container, Item> helper) {
LocalizedCacheTopology cacheTopology = checkTopology(command);
Map<Address, Container> remoteEntries = new HashMap<>();
for (Item item : helper.getItems(command)) {
Object key = helper.item2key(item);
DistributionInfo info = cacheTopology.getDistribution(key);
Address primary = info.primary();
if (primary == null) {
throw AllOwnersLostException.INSTANCE;
} else {
Container currentEntries = remoteEntries.computeIfAbsent(primary, k -> helper.newContainer());
helper.accumulate(currentEntries, item);
}
}
Object[] results = command.loadType() == DONT_LOAD ? null : new Object[command.getAffectedKeys().size()];
MergingCompletableFuture<Object> allFuture = new SyncMergingCompletableFuture<>(remoteEntries.size(), results, helper::transformResult);
int offset = 0;
Container localEntries = remoteEntries.remove(rpcManager.getAddress());
if (localEntries != null) {
helper.containerSize(localEntries);
C localCommand = helper.copyForLocal(command, localEntries);
localCommand.setTopologyId(command.getTopologyId());
LocalWriteManyHandler handler = new LocalWriteManyHandler(allFuture, localCommand.getAffectedKeys(), cacheTopology);
invokeNextAndFinally(ctx, localCommand, handler);
}
// This will be null in a non-biased variant
MultiTargetCollector multiTargetCollector = createMultiTargetCollector(command, remoteEntries.size());
for (Map.Entry<Address, Container> ownerEntry : remoteEntries.entrySet()) {
Address owner = ownerEntry.getKey();
// TODO: copyForLocal just creates the command with given entries, not using the segment-aware map
Container container = ownerEntry.getValue();
C toPrimary = helper.copyForLocal(command, container);
toPrimary.setTopologyId(command.getTopologyId());
CompletionStage<ValidResponse> rpcFuture = manyWriteOnRemotePrimary(owner, toPrimary, multiTargetCollector);
int myOffset = offset;
offset += helper.containerSize(container);
rpcFuture.whenComplete((response, t) -> {
if (t != null) {
allFuture.completeExceptionally(t);
return;
}
Object responseValue = response.getResponseValue();
// Note: we could use PrimaryResponseHandler, but we would have to add the reference to allFuture, offset...
InternalCacheValue[] values;
try {
if (command.loadType() == DONT_LOAD) {
if (!(responseValue instanceof InternalCacheValue[])) {
allFuture.completeExceptionally(new CacheException("Response from " + owner + ": expected InternalCacheValue[] but it is " + responseValue));
return;
}
values = (InternalCacheValue[]) responseValue;
} else {
if (!(responseValue instanceof Object[]) || (((Object[]) responseValue).length != 2)) {
allFuture.completeExceptionally(new CacheException("Response from " + owner + ": expected Object[2] but it is " + responseValue));
return;
}
// We use Object[] { InternalCacheValue[], Object[] } structure to get benefit of same-type array marshalling
// TODO optimize returning entry itself
// Note: some interceptors relying on the return value *could* have a problem interpreting this
values = (InternalCacheValue[]) ((Object[]) responseValue)[0];
MergingCompletableFuture.moveListItemsToFuture(((Object[]) responseValue)[1], allFuture, myOffset);
}
AggregateCompletionStage<Void> aggregateCompletionStage = CompletionStages.aggregateCompletionStage();
synchronized (allFuture) {
if (allFuture.isDone()) {
return;
}
int i = 0;
for (Object key : helper.toKeys(container)) {
// we will serve as the backup
InternalCacheEntry ice = values[i++].toInternalCacheEntry(key);
entryFactory.wrapExternalEntry(ctx, key, ice, true, true);
RepeatableReadEntry entry = (RepeatableReadEntry) ctx.lookupEntry(key);
// we don't care about setCreated() since backup owner should not fire listeners
entry.setChanged(true);
aggregateCompletionStage.dependsOn(commitSingleEntryIfNewer(entry, ctx, command));
if (entry.isCommitted() && !command.hasAnyFlag(FlagBitSets.PUT_FOR_STATE_TRANSFER)) {
scheduleKeyInvalidation(entry.getKey(), entry.getMetadata().version(), entry.isRemoved());
}
}
assert i == values.length;
}
aggregateCompletionStage.freeze().thenRun(allFuture::countDown);
} catch (Throwable t2) {
allFuture.completeExceptionally(t2);
}
});
}
return asyncValue(allFuture);
}
use of org.infinispan.remoting.responses.ValidResponse in project infinispan by infinispan.
the class BaseDistributionInterceptor method invokeRemotely.
protected Object invokeRemotely(InvocationContext ctx, DataWriteCommand command, Address primaryOwner) {
if (log.isTraceEnabled())
getLog().tracef("I'm not the primary owner, so sending the command to the primary owner(%s) in order to be forwarded", primaryOwner);
boolean isSyncForwarding = isSynchronous(command) || command.isReturnValueExpected();
if (!isSyncForwarding) {
rpcManager.sendTo(primaryOwner, command, DeliverOrder.PER_SENDER);
return null;
}
CompletionStage<ValidResponse> remoteInvocation;
try {
remoteInvocation = rpcManager.invokeCommand(primaryOwner, command, SingleResponseCollector.validOnly(), rpcManager.getSyncRpcOptions());
} catch (Throwable t) {
command.setValueMatcher(command.getValueMatcher().matcherForRetry());
throw t;
}
return asyncValue(remoteInvocation).andHandle(ctx, command, (rCtx, dataWriteCommand, rv, t) -> {
dataWriteCommand.setValueMatcher(dataWriteCommand.getValueMatcher().matcherForRetry());
CompletableFutures.rethrowExceptionIfPresent(t);
Response response = ((Response) rv);
if (!response.isSuccessful()) {
dataWriteCommand.fail();
// FIXME A response cannot be successful and not valid
} else if (!(response instanceof ValidResponse)) {
throw unexpected(primaryOwner, response);
}
// We expect only successful/unsuccessful responses, not unsure
return ((ValidResponse) response).getResponseValue();
});
}
use of org.infinispan.remoting.responses.ValidResponse in project infinispan by infinispan.
the class BaseDistributionInterceptor method visitGetKeysInGroupCommand.
@Override
public final Object visitGetKeysInGroupCommand(InvocationContext ctx, GetKeysInGroupCommand command) throws Throwable {
if (command.isGroupOwner()) {
// don't go remote if we are an owner.
return invokeNext(ctx, command);
}
Address primaryOwner = distributionManager.getCacheTopology().getDistribution(command.getGroupName()).primary();
CompletionStage<ValidResponse> future = rpcManager.invokeCommand(primaryOwner, command, SingleResponseCollector.validOnly(), rpcManager.getSyncRpcOptions());
return asyncInvokeNext(ctx, command, future.thenAccept(response -> {
if (response instanceof SuccessfulResponse) {
// noinspection unchecked
List<CacheEntry> cacheEntries = (List<CacheEntry>) response.getResponseValue();
for (CacheEntry entry : cacheEntries) {
wrapRemoteEntry(ctx, entry.getKey(), entry, false);
}
}
}));
}
use of org.infinispan.remoting.responses.ValidResponse in project infinispan by infinispan.
the class RpcManagerTest method testInvokeCommand1.
public void testInvokeCommand1() throws Exception {
ClusteredGetCommand command = TestingUtil.extractCommandsFactory(cache(0)).buildClusteredGetCommand("key", 0, 0L);
RpcManager rpcManager0 = cache(0).getAdvancedCache().getRpcManager();
Exceptions.expectException(IllegalArgumentException.class, () -> rpcManager0.invokeCommand(address(0), command, SingleResponseCollector.validOnly(), rpcManager0.getSyncRpcOptions()));
command.setTopologyId(rpcManager0.getTopologyId());
CompletionStage<ValidResponse> stage1 = rpcManager0.invokeCommand(address(0), command, SingleResponseCollector.validOnly(), rpcManager0.getSyncRpcOptions());
assertResponse(null, stage1);
CompletionStage<ValidResponse> stage2 = rpcManager0.invokeCommand(address(1), command, SingleResponseCollector.validOnly(), rpcManager0.getSyncRpcOptions());
assertResponse(SUCCESSFUL_EMPTY_RESPONSE, stage2);
CompletionStage<ValidResponse> stage3 = rpcManager0.invokeCommand(SUSPECT, command, SingleResponseCollector.validOnly(), rpcManager0.getSyncRpcOptions());
Exceptions.expectExecutionException(SuspectException.class, stage3.toCompletableFuture());
}
Aggregations