use of org.infinispan.transaction.impl.LocalTransaction in project infinispan by infinispan.
the class StateProviderImpl method collectTransactionsToTransfer.
private void collectTransactionsToTransfer(Address destination, List<TransactionInfo> transactionsToTransfer, Collection<? extends CacheTransaction> transactions, IntSet segments, CacheTopology cacheTopology) {
int topologyId = cacheTopology.getTopologyId();
Set<Address> members = new HashSet<>(cacheTopology.getMembers());
// no need to filter out state transfer generated transactions because there should not be any such transactions running for any of the requested segments
for (CacheTransaction tx : transactions) {
final GlobalTransaction gtx = tx.getGlobalTransaction();
// Also skip transactions that originates after state transfer starts.
if (tx.getTopologyId() == topologyId || (transactionOriginatorChecker.isOriginatorMissing(gtx, members))) {
if (log.isTraceEnabled())
log.tracef("Skipping transaction %s as it was started in the current topology or by a leaver", tx);
continue;
}
// transfer only locked keys that belong to requested segments
Set<Object> filteredLockedKeys = new HashSet<>();
// avoids the warning about synchronizing in a local variable.
// and allows us to change the CacheTransaction internals without having to worry about it
Consumer<Object> lockFilter = key -> {
if (segments.contains(keyPartitioner.getSegment(key))) {
filteredLockedKeys.add(key);
}
};
tx.forEachLock(lockFilter);
tx.forEachBackupLock(lockFilter);
if (filteredLockedKeys.isEmpty()) {
if (log.isTraceEnabled())
log.tracef("Skipping transaction %s because the state requestor %s doesn't own any key", tx, destination);
continue;
}
if (log.isTraceEnabled())
log.tracef("Sending transaction %s to new owner %s", tx, destination);
List<WriteCommand> txModifications = tx.getModifications();
WriteCommand[] modifications = null;
if (!txModifications.isEmpty()) {
modifications = txModifications.toArray(new WriteCommand[0]);
}
// affected nodes set, so that the it receives the commit/rollback command. See ISPN-3389.
if (tx instanceof LocalTransaction) {
LocalTransaction localTx = (LocalTransaction) tx;
localTx.locksAcquired(Collections.singleton(destination));
if (log.isTraceEnabled())
log.tracef("Adding affected node %s to transferred transaction %s (keys %s)", destination, gtx, filteredLockedKeys);
}
transactionsToTransfer.add(new TransactionInfo(gtx, tx.getTopologyId(), modifications, filteredLockedKeys));
}
}
use of org.infinispan.transaction.impl.LocalTransaction in project infinispan by infinispan.
the class TxDistributionInterceptor method getCommitNodes.
private Collection<Address> getCommitNodes(TxInvocationContext ctx, TopologyAffectedCommand command) {
LocalTransaction localTx = (LocalTransaction) ctx.getCacheTransaction();
LocalizedCacheTopology cacheTopology = checkTopologyId(command);
Collection<Address> affectedNodes = isReplicated ? null : cacheTopology.getWriteOwners(ctx.getAffectedKeys());
return localTx.getCommitNodes(affectedNodes, cacheTopology);
}
use of org.infinispan.transaction.impl.LocalTransaction in project infinispan by infinispan.
the class TxDistributionInterceptor method visitPrepareCommand.
@Override
public Object visitPrepareCommand(TxInvocationContext ctx, PrepareCommand command) throws Throwable {
if (!ctx.isOriginLocal()) {
return invokeNext(ctx, command);
}
return invokeNextThenApply(ctx, command, (rCtx, rCommand, rv) -> {
if (!shouldInvokeRemoteTxCommand((TxInvocationContext) rCtx)) {
return rv;
}
TxInvocationContext<LocalTransaction> localTxCtx = (TxInvocationContext<LocalTransaction>) rCtx;
LocalTransaction localTx = localTxCtx.getCacheTransaction();
LocalizedCacheTopology cacheTopology = checkTopologyId(rCommand);
Collection<Address> writeOwners = cacheTopology.getWriteOwners(localTxCtx.getAffectedKeys());
localTx.locksAcquired(writeOwners);
Collection<Address> recipients = isReplicated ? null : localTx.getCommitNodes(writeOwners, cacheTopology);
CompletionStage<Object> remotePrepare = prepareOnAffectedNodes(localTxCtx, rCommand, recipients);
return asyncValue(remotePrepare);
});
}
use of org.infinispan.transaction.impl.LocalTransaction in project infinispan by infinispan.
the class PessimisticStateTransferLocksTest method checkLocksBeforeCommit.
private void checkLocksBeforeCommit(boolean backupLockOnCache1) throws Exception {
sequencer.enter("tx:check_locks");
assertFalse(getTransactionTable(cache(0)).getLocalTransactions().isEmpty());
assertTrue(getTransactionTable(cache(0)).getRemoteTransactions().isEmpty());
LocalTransaction localTx = getTransactionTable(cache(0)).getLocalTransactions().iterator().next();
assertEquals(Collections.singleton(KEY), localTx.getLockedKeys());
assertEquals(Collections.emptySet(), localTx.getBackupLockedKeys());
assertTrue(getTransactionTable(cache(1)).getLocalTransactions().isEmpty());
assertEquals(backupLockOnCache1, !getTransactionTable(cache(1)).getRemoteTransactions().isEmpty());
assertTrue(getTransactionTable(cache(2)).getLocalTransactions().isEmpty());
assertFalse(getTransactionTable(cache(2)).getRemoteTransactions().isEmpty());
RemoteTransaction remoteTx = getTransactionTable(cache(2)).getRemoteTransactions().iterator().next();
assertEquals(Collections.emptySet(), remoteTx.getLockedKeys());
assertEquals(Collections.singleton(KEY), remoteTx.getBackupLockedKeys());
sequencer.exit("tx:check_locks");
}
use of org.infinispan.transaction.impl.LocalTransaction in project infinispan by infinispan.
the class StaleLocksWithCommitDuringStateTransferTest method doTestSuspect.
/**
* Check that the transaction commit/rollback recovers if the remote node dies during the RPC
*/
private void doTestSuspect(boolean commit) throws Exception {
MagicKey k1 = new MagicKey("k1", c1);
MagicKey k2 = new MagicKey("k2", c2);
tm(c1).begin();
c1.put(k1, "v1");
c1.put(k2, "v2");
// We split the transaction commit in two phases by calling the TransactionCoordinator methods directly
TransactionTable txTable = TestingUtil.extractComponent(c1, TransactionTable.class);
TransactionCoordinator txCoordinator = TestingUtil.extractComponent(c1, TransactionCoordinator.class);
// Execute the prepare on both nodes
LocalTransaction localTx = txTable.getLocalTransaction(tm(c1).getTransaction());
CompletionStages.join(txCoordinator.prepare(localTx));
// Delay the commit on the remote node. Can't used blockNewTransactions because we don't want a StateTransferInProgressException
AsyncInterceptorChain c2ic = c2.getAdvancedCache().getAsyncInterceptorChain();
c2ic.addInterceptorBefore(new DelayCommandInterceptor(), StateTransferInterceptor.class);
// Schedule the remote node to stop on another thread since the main thread will be busy with the commit call
Thread worker = new Thread("RehasherSim,StaleLocksWithCommitDuringStateTransferTest") {
@Override
public void run() {
try {
// should be much larger than the lock acquisition timeout
Thread.sleep(1000);
manager(c2).stop();
// stLock.unblockNewTransactions(1000);
} catch (InterruptedException e) {
log.errorf(e, "Error stopping cache");
}
}
};
worker.start();
try {
// finally commit or rollback the transaction
if (commit) {
CompletionStages.join(txCoordinator.commit(localTx, false));
} else {
CompletionStages.join(txCoordinator.rollback(localTx));
}
// make the transaction manager forget about our tx so that we don't get rollback exceptions in the log
tm(c1).suspend();
} finally {
// don't leak threads
worker.join();
}
// test that we don't leak locks
assertEventuallyNotLocked(c1, k1);
assertEventuallyNotLocked(c1, k2);
}
Aggregations