use of org.infinispan.util.ControlledRpcManager in project infinispan by infinispan.
the class NonTxInvalidationLockingTest method testConcurrentWritesFromDifferentNodes.
public void testConcurrentWritesFromDifferentNodes() throws Exception {
Cache<Object, Object> cache1 = cache(0, CACHE);
ControlledRpcManager rpc1 = ControlledRpcManager.replaceRpcManager(cache1);
Cache<Object, Object> cache2 = cache(1, CACHE);
ControlledRpcManager rpc2 = ControlledRpcManager.replaceRpcManager(cache2);
CompletableFuture<ControlledRpcManager.BlockedRequest<InvalidateCommand>> invalidate1 = rpc1.expectCommandAsync(InvalidateCommand.class);
CompletableFuture<Object> put1 = cache1.putAsync(KEY, VALUE1);
CompletableFuture<ControlledRpcManager.BlockedRequest<InvalidateCommand>> invalidate2 = rpc2.expectCommandAsync(InvalidateCommand.class);
CompletableFuture<Object> put2 = cache2.putAsync(KEY, VALUE2);
ControlledRpcManager.SentRequest sentInvalidate1 = invalidate1.join().send();
ControlledRpcManager.SentRequest sentInvalidate2 = invalidate2.join().send();
sentInvalidate1.expectAllResponses().receive();
sentInvalidate2.expectAllResponses().receive();
put1.get(10, TimeUnit.SECONDS);
put2.get(10, TimeUnit.SECONDS);
assertEquals(VALUE1, cache1.get(KEY));
assertEquals(VALUE2, cache2.get(KEY));
}
use of org.infinispan.util.ControlledRpcManager in project infinispan by infinispan.
the class ReplicationTxExceptionTest method testReplicationFailure.
public void testReplicationFailure() throws Exception {
Cache<?, ?> cache = cache(0);
ControlledRpcManager controlledRpcManager = ControlledRpcManager.replaceRpcManager(cache);
try {
Future<Void> future = fork(() -> {
controlledRpcManager.expectCommand(VersionedPrepareCommand.class).fail();
controlledRpcManager.expectCommand(RollbackCommand.class).send().receiveAll();
});
TransactionManager tm = cache(0).getAdvancedCache().getTransactionManager();
tm.begin();
cache(0).put("k0", "v");
Exceptions.expectException(RollbackException.class, tm::commit);
future.get(30, TimeUnit.SECONDS);
} finally {
controlledRpcManager.revertRpcManager();
}
}
use of org.infinispan.util.ControlledRpcManager in project infinispan by infinispan.
the class NonTxPrimaryOwnerLeavingTest method doTest.
private void doTest(TestWriteOperation operation, boolean blockTopologyOnOriginator) throws Exception {
final AdvancedCache<Object, Object> cache0 = advancedCache(0);
AdvancedCache<Object, Object> cache1 = advancedCache(1);
AdvancedCache<Object, Object> cache2 = advancedCache(2);
TopologyUpdateListener listener0 = new TopologyUpdateListener();
cache0.addListener(listener0);
TopologyUpdateListener listener2 = new TopologyUpdateListener();
cache2.addListener(listener2);
// Block remote put commands invoked from cache0
ControlledRpcManager crm = ControlledRpcManager.replaceRpcManager(cache0);
crm.excludeCommands(StateTransferStartCommand.class, StateResponseCommand.class);
// Try to put a key/value from cache0 with cache1 the primary owner
final MagicKey key = new MagicKey(cache1);
Future<Object> future = fork(() -> operation.perform(cache0, key));
// After the write command was sent, kill cache1
ControlledRpcManager.BlockedRequest blockedWrite = crm.expectCommand(operation.getCommandClass());
cache1.stop();
if (!blockTopologyOnOriginator) {
listener0.unblockOnce();
listener0.waitForTopologyToFinish();
}
// Now that cache1 is stopped, unblock the write command and wait for the responses
blockedWrite.send().expectResponse(address(1), CacheNotFoundResponse.INSTANCE).receive();
if (blockTopologyOnOriginator) {
// The retry should be blocked on the originator until we unblock the topology update
crm.expectNoCommand(100, TimeUnit.MILLISECONDS);
listener0.unblockOnce();
listener0.waitForTopologyToFinish();
}
// Install the new topology without cache1 on cache2 as well
listener2.unblockOnce();
listener2.waitForTopologyToFinish();
// Retry the write command with a single owner (rebalance topology is blocked).
if (!cache0.getDistributionManager().getCacheTopology().getDistribution(key).isPrimary()) {
crm.expectCommand(operation.getCommandClass()).send().receiveAll();
}
// Check that the put command didn't fail
Object result = future.get(10, TimeUnit.SECONDS);
assertNull(result);
log.tracef("Write operation is done");
cache0.removeListener(listener0);
cache2.removeListener(listener2);
listener0.unblockOnce();
listener0.unblockOnce();
crm.stopBlocking();
// Check the value on the remaining node
assertEquals(operation.getValue(), cache0.get(key));
assertEquals(operation.getValue(), cache2.get(key));
}
use of org.infinispan.util.ControlledRpcManager in project infinispan by infinispan.
the class NonTxStateTransferOverwritingValue2Test method doTest.
private void doTest(final TestWriteOperation op) throws Exception {
// Test scenario:
// cache0 is the only member in the cluster, cache1 joins
// Key k is in the cache, and is transferred to cache1
// A user operation/tx also modifies key k
// Even if both state transfer and the user tx try to commit the entry for k concurrently,
// the value of k at the end should be the one set by the user tx.
final AdvancedCache<Object, Object> cache0 = advancedCache(0);
final String key = "key";
// Prepare for replace/remove: put a previous value in cache0
final Object previousValue = op.getPreviousValue();
if (previousValue != null) {
cache0.put(key, previousValue);
assertEquals(previousValue, cache0.get(key));
log.tracef("Previous value inserted: %s = %s", key, previousValue);
}
int preJoinTopologyId = cache0.getDistributionManager().getCacheTopology().getTopologyId();
// Block any state response commands on cache0
// So that we can install the spy ClusteringDependentLogic on cache1 before state transfer is applied
final CheckPoint checkPoint = new CheckPoint();
ControlledRpcManager blockingRpcManager0 = ControlledRpcManager.replaceRpcManager(cache0);
blockingRpcManager0.excludeCommands(BackupWriteCommand.class, BackupAckCommand.class);
// Block the rebalance confirmation on coordinator (to avoid the retrying of commands)
blockRebalanceConfirmation(manager(0), checkPoint, preJoinTopologyId + 1);
// Start the joiner
log.tracef("Starting the cache on the joiner");
ConfigurationBuilder c = getConfigurationBuilder();
c.clustering().stateTransfer().awaitInitialTransfer(false);
addClusterEnabledCacheManager(c);
final AdvancedCache<Object, Object> cache1 = advancedCache(1);
// Wait for the write CH to contain the joiner everywhere
eventually(() -> cache0.getRpcManager().getMembers().size() == 2 && cache1.getRpcManager().getMembers().size() == 2);
// Every PutKeyValueCommand will be blocked before committing the entry on cache1
blockEntryCommit(checkPoint, cache1);
// Wait for cache0 to collect the state to send to cache1 (including our previous value).
ControlledRpcManager.BlockedRequest blockedStateResponse = blockingRpcManager0.expectCommand(StateResponseCommand.class);
// Allow the state to be applied on cache1 (writing the old value for our entry)
ControlledRpcManager.SentRequest sentStateResponse = blockedStateResponse.send();
// Wait for state transfer tx/operation to call commitEntry on cache1 and block
checkPoint.awaitStrict("pre_commit_entry_" + key + "_from_" + null, 5, SECONDS);
// Put/Replace/Remove from cache0 with cache0 as primary owner, cache1 as backup owner
// The put command will be blocked on cache1 just before committing the entry.
Future<Object> future = fork(() -> op.perform(cache0, key));
// Check that the user write is blocked by the state transfer write
boolean blocked = checkPoint.peek(1, SECONDS, "pre_commit_entry_" + key + "_from_" + address(0)) == null;
assertTrue(blocked);
// Allow state transfer to commit
checkPoint.trigger("resume_commit_entry_" + key + "_from_" + null);
// Check that the user operation can now commit the entry
checkPoint.awaitStrict("pre_commit_entry_" + key + "_from_" + address(0), 5, SECONDS);
// Allow the user put to commit
checkPoint.trigger("resume_commit_entry_" + key + "_from_" + address(0));
// Wait for both state transfer and the command to commit
checkPoint.awaitStrict("post_commit_entry_" + key + "_from_" + null, 10, SECONDS);
checkPoint.awaitStrict("post_commit_entry_" + key + "_from_" + address(0), 10, SECONDS);
// Wait for the command to finish and check that it didn't fail
Object result = future.get(10, TimeUnit.SECONDS);
assertEquals(op.getReturnValue(), result);
log.tracef("%s operation is done", op);
// Receive the response for the state response command (only after all commits have finished)
sentStateResponse.receiveAll();
// Allow the rebalance confirmation to proceed and wait for the topology to change everywhere
int rebalanceTopologyId = preJoinTopologyId + 1;
checkPoint.trigger("resume_rebalance_confirmation_" + rebalanceTopologyId + "_from_" + address(0));
checkPoint.trigger("resume_rebalance_confirmation_" + rebalanceTopologyId + "_from_" + address(1));
TestingUtil.waitForNoRebalance(cache0, cache1);
// Check the value on all the nodes
assertEquals(op.getValue(), cache0.get(key));
assertEquals(op.getValue(), cache1.get(key));
blockingRpcManager0.stopBlocking();
}
use of org.infinispan.util.ControlledRpcManager in project infinispan by infinispan.
the class BaseTxStateTransferOverwriteTest method doTestWhereCommitOccursAfterStateTransferBeginsBeforeCompletion.
/**
* When L1 is enabled this test should not be ran when a previous value is present as it will cause timeouts. Due
* to how locking works with L1 this cannot occur when the previous value exists.
*/
protected void doTestWhereCommitOccursAfterStateTransferBeginsBeforeCompletion(final TestWriteOperation op) throws Exception {
if (l1Enabled() && op.getPreviousValue() != null) {
fail("This test cannot be ran with L1 when a previous value is set");
}
// Test scenario:
// cache0,1,2 are in the cluster, an owner leaves
// Key k is in the cache, and is transferred to the non owner
// A user operation also modifies key k causing an invalidation
// on the non owner which is getting the state transfer
final AdvancedCache<Object, Object> primaryOwnerCache = cache(0, cacheName).getAdvancedCache();
final AdvancedCache<Object, Object> backupOwnerCache = cache(1, cacheName).getAdvancedCache();
final AdvancedCache<Object, Object> nonOwnerCache = cache(2, cacheName).getAdvancedCache();
final MagicKey key = new MagicKey(primaryOwnerCache, backupOwnerCache);
// Prepare for replace/remove: put a previous value in cache0
final Object previousValue = op.getPreviousValue();
if (previousValue != null) {
primaryOwnerCache.put(key, previousValue);
assertEquals(previousValue, primaryOwnerCache.get(key));
log.tracef("Previous value inserted: %s = %s", key, previousValue);
assertEquals(previousValue, nonOwnerCache.get(key));
if (l1Enabled()) {
assertIsInL1(nonOwnerCache, key);
}
}
int preJoinTopologyId = primaryOwnerCache.getDistributionManager().getCacheTopology().getTopologyId();
// Block any state response commands on cache0
CheckPoint checkPoint = new CheckPoint();
ControlledRpcManager blockingRpcManager0 = ControlledRpcManager.replaceRpcManager(primaryOwnerCache);
ControlledRpcManager blockingRpcManager2 = ControlledRpcManager.replaceRpcManager(nonOwnerCache);
// The execution of the write/prepare/commit commands is controlled with the BlockingInterceptor
blockingRpcManager0.excludeCommands(BackupWriteCommand.class, PrepareCommand.class, CommitCommand.class, TxCompletionNotificationCommand.class);
blockingRpcManager2.excludeCommands(BackupAckCommand.class);
// Block the rebalance confirmation on cache0
int rebalanceTopologyId = preJoinTopologyId + 2;
blockRebalanceConfirmation(primaryOwnerCache.getCacheManager(), checkPoint, rebalanceTopologyId);
assertEquals(primaryOwnerCache.getCacheManager().getCoordinator(), primaryOwnerCache.getCacheManager().getAddress());
// Remove the leaver
log.trace("Stopping the cache");
backupOwnerCache.getCacheManager().stop();
// Wait for the write CH to contain the joiner everywhere
eventuallyEquals(2, () -> primaryOwnerCache.getRpcManager().getMembers().size());
eventuallyEquals(2, () -> nonOwnerCache.getRpcManager().getMembers().size());
assertEquals(primaryOwnerCache.getCacheManager().getCoordinator(), primaryOwnerCache.getCacheManager().getAddress());
// Wait for both nodes to start state transfer
if (transactional) {
blockingRpcManager0.expectCommand(StateTransferGetTransactionsCommand.class).send().receiveAll();
blockingRpcManager2.expectCommand(StateTransferGetTransactionsCommand.class).send().receiveAll();
}
ControlledRpcManager.BlockedRequest<StateTransferStartCommand> blockedStateRequest0 = blockingRpcManager0.expectCommand(StateTransferStartCommand.class);
ControlledRpcManager.BlockedRequest<StateTransferStartCommand> blockedStateRequest2 = blockingRpcManager2.expectCommand(StateTransferStartCommand.class);
// Unblock the state request from node 2
// Don't wait for response, because node 2 might be sending the first state response on the request thread
blockedStateRequest2.send().receiveAllAsync();
// Wait for cache0 to collect the state to send to node 2 (including our previous value).
ControlledRpcManager.BlockedRequest<StateResponseCommand> blockedStateResponse0 = blockingRpcManager0.expectCommand(StateResponseCommand.class);
// Every PutKeyValueCommand will be blocked before committing the entry on cache1
CyclicBarrier beforeCommitCache1Barrier = new CyclicBarrier(2);
BlockingInterceptor<?> blockingInterceptor1 = new BlockingInterceptor<>(beforeCommitCache1Barrier, op.getCommandClass(), true, false);
extractInterceptorChain(nonOwnerCache).addInterceptorAfter(blockingInterceptor1, EntryWrappingInterceptor.class);
// Put/Replace/Remove from cache0 with cache0 as primary owner, cache1 will become a backup owner for the retry
// The put command will be blocked on cache1 just before committing the entry.
Future<Object> future = fork(() -> op.perform(primaryOwnerCache, key));
// Wait for the entry to be wrapped on node 2
// The replicated command could be either a non-tx BackupWriteCommand or a PrepareCommand
beforeCommitCache1Barrier.await(10, TimeUnit.SECONDS);
// Remove the interceptor so we don't mess up any other state transfer puts
removeAllBlockingInterceptorsFromCache(nonOwnerCache);
// Allow the state to be applied on cache1 (writing the old value for our entry)
blockedStateResponse0.send().receiveAll();
// Wait for second in line to finish applying the state, but don't allow the rebalance confirmation to be processed.
// (It would change the topology and it would trigger a retry for the command.)
// Don't wait for response, because node 2 might be sending the first state response on the request thread
blockedStateRequest0.send().receiveAllAsync();
blockingRpcManager2.expectCommand(StateResponseCommand.class).send().receiveAll();
checkPoint.awaitStrict("pre_rebalance_confirmation_" + rebalanceTopologyId + "_from_" + primaryOwnerCache.getCacheManager().getAddress(), 10, SECONDS);
// Now allow the command to commit on cache1
beforeCommitCache1Barrier.await(10, TimeUnit.SECONDS);
// Wait for the command to finish and check that it didn't fail
Object result = future.get(10, TimeUnit.SECONDS);
assertEquals(op.getReturnValue(), result);
log.tracef("%s operation is done", op);
// Allow the rebalance confirmation to proceed and wait for the topology to change everywhere
checkPoint.trigger("resume_rebalance_confirmation_" + rebalanceTopologyId + "_from_" + primaryOwnerCache.getCacheManager().getAddress());
checkPoint.trigger("resume_rebalance_confirmation_" + rebalanceTopologyId + "_from_" + nonOwnerCache.getCacheManager().getAddress());
TestingUtil.waitForNoRebalance(primaryOwnerCache, nonOwnerCache);
switch(op) {
case REMOVE:
case REMOVE_EXACT:
break;
default:
assertIsInContainerImmortal(primaryOwnerCache, key);
assertIsInContainerImmortal(nonOwnerCache, key);
break;
}
// Check the value to make sure data container contains correct value
assertEquals(op.getValue(), primaryOwnerCache.get(key));
assertEquals(op.getValue(), nonOwnerCache.get(key));
}
Aggregations