package org.infinispan.remoting.inboundhandler;
import java.util.concurrent.CompletableFuture;
import org.infinispan.commands.remote.CacheRpcCommand;
import org.infinispan.remoting.responses.CacheNotFoundResponse;
import org.infinispan.remoting.responses.Response;
/**
* The default {@link Runnable} for the remote commands receives.
* <p/>
* It checks the command topology and ensures that the topology higher or equal is installed in this node.
*
* @author Pedro Ruivo
* @since 8.0
*/
public class DefaultTopologyRunnable extends BaseBlockingRunnable {
private final TopologyMode topologyMode;
protected final int commandTopologyId;
public DefaultTopologyRunnable(BasePerCacheInboundInvocationHandler handler, CacheRpcCommand command, Reply reply,
TopologyMode topologyMode, int commandTopologyId, boolean sync) {
super(handler, command, reply, sync);
this.topologyMode = topologyMode;
this.commandTopologyId = commandTopologyId;
}
@Override
public boolean isReady() {
switch (topologyMode) {
case READY_TOPOLOGY:
return handler.getStateTransferLock().topologyReceived(waitTopology());
case READY_TX_DATA:
return handler.getStateTransferLock().transactionDataReceived(waitTopology());
default:
return true;
}
}
@Override
protected CompletableFuture<Response> beforeInvoke() {
CompletableFuture<Void> future = null;
switch (topologyMode) {
case WAIT_TOPOLOGY:
future = handler.getStateTransferLock().topologyFuture(waitTopology());
break;
case WAIT_TX_DATA:
future = handler.getStateTransferLock().transactionDataFuture(waitTopology());
break;
default:
break;
}
if (future != null) {
return future.thenApply(nil -> handler.isCommandSentBeforeFirstTopology(commandTopologyId) ?
CacheNotFoundResponse.INSTANCE :
null);
} else {
return handler.isCommandSentBeforeFirstTopology(commandTopologyId) ?
CompletableFuture.completedFuture(CacheNotFoundResponse.INSTANCE) :
null;
}
}
private int waitTopology() {
// Always wait for the first topology (i.e. for the join to finish)
return Math.max(commandTopologyId, 0);
}
}