}
}
}
private void handleWithWaitForBlocks(final CacheRpcCommand cmd, final ComponentRegistry cr, final org.jgroups.blocks.Response response, boolean preserveOrder) throws Throwable {
final StateTransferManager stm = cr.getStateTransferManager();
// We must have completed the join before handling commands
// (even if we didn't complete the initial state transfer)
if (cmd instanceof TotalOrderPrepareCommand && !stm.ownsData()) {
reply(response, null);
return;
}
CommandsFactory commandsFactory = cr.getCommandsFactory();
// initialize this command with components specific to the intended cache instance
commandsFactory.initializeReplicableCommand(cmd, true);
if (cmd instanceof TotalOrderPrepareCommand) {
final TotalOrderRemoteTransactionState state = ((TotalOrderPrepareCommand) cmd).getOrCreateState();
final TotalOrderManager totalOrderManager = cr.getTotalOrderManager();
totalOrderManager.ensureOrder(state, ((PrepareCommand) cmd).getAffectedKeysToLock(false));
totalOrderExecutorService.execute(new BlockingRunnable() {
@Override
public boolean isReady() {
for (TotalOrderLatch block : state.getConflictingTransactionBlocks()) {
if (block.isBlocked()) {
return false;
}
}
return true;
}
@Override
public void run() {
Response resp;
try {
resp = handleInternal(cmd, cr);
} catch (RetryPrepareException retry) {
log.debugf(retry, "Prepare [%s] conflicted with state transfer", cmd);
resp = new ExceptionResponse(retry);
} catch (Throwable throwable) {
log.exceptionHandlingCommand(cmd, throwable);
resp = new ExceptionResponse(new CacheException("Problems invoking command.", throwable));
}
//the ResponseGenerated is null in this case because the return value is a Response
reply(response, resp);
if (resp instanceof ExceptionResponse) {
totalOrderManager.release(state);
}
afterResponseSent(cmd, resp);
}
});
} else {
final StateTransferLock stateTransferLock = cr.getStateTransferLock();
// Command topology id -1 means the command is not topology-aware
final int commandTopologyId = extractCommandTopologyId(cmd);
// Always wait for the first topology (i.e. for the join to finish)
final int waitTopologyId = Math.max(commandTopologyId, 0);
if (!preserveOrder && cmd.canBlock()) {
remoteCommandsExecutor.execute(new BlockingRunnable() {
@Override
public boolean isReady() {
return stateTransferLock.transactionDataReceived(waitTopologyId);
}
@Override
public void run() {
if (0 <= commandTopologyId && commandTopologyId < stm.getFirstTopologyAsMember()) {
if (trace) log.tracef("Ignoring command sent before the local node was a member " +
"(command topology id is %d)", commandTopologyId);
reply(response, null);
return;
}
Response resp;
try {
resp = handleInternal(cmd, cr);
} catch (Throwable throwable) {
log.exceptionHandlingCommand(cmd, throwable);
resp = new ExceptionResponse(new CacheException("Problems invoking command.", throwable));
}
reply(response, resp);
afterResponseSent(cmd, resp);
}
});
} else {
// Non-OOB commands. We still have to wait for transaction data, but we should "never" time out
// In non-transactional caches, this just waits for the topology to be installed
stateTransferLock.waitForTransactionData(waitTopologyId, 1, TimeUnit.DAYS);
if (0 <= commandTopologyId && commandTopologyId < stm.getFirstTopologyAsMember()) {
if (trace) log.tracef("Ignoring command sent before the local node was a member " +
"(command topology id is %d)", commandTopologyId);
reply(response, null);
return;
}