use of org.apache.ignite.internal.processors.cache.distributed.dht.GridDhtTxFinishRequest in project ignite by apache.
the class TxPartitionCounterStateAbstractTest method createPrimaryMessagePredicate.
/**
* @param wrappedPrimSpi Wrapped prim spi.
* @param futMap Future map.
* @param nearToLocVerMap Near to local version map.
* @param cb Callback.
*/
private IgniteBiPredicate<ClusterNode, Message> createPrimaryMessagePredicate(TestRecordingCommunicationSpi wrappedPrimSpi, Map<IgniteUuid, GridCacheVersion> futMap, Map<GridCacheVersion, GridCacheVersion> nearToLocVerMap, TxCallback cb) {
return (node, msg) -> {
if (msg instanceof GridDhtTxPrepareRequest) {
IgniteEx to = IgnitionEx.gridxx(node.id());
GridDhtTxPrepareRequest req = (GridDhtTxPrepareRequest) msg;
if (!req.last())
return false;
futMap.put(req.futureId(), req.nearXidVersion());
nearToLocVerMap.put(req.version(), req.nearXidVersion());
IgniteEx from = fromNode(wrappedPrimSpi);
IgniteInternalTx primTx = findTx(from, req.nearXidVersion(), true);
return cb.beforeBackupPrepare(from, to, primTx, createSendFuture(wrappedPrimSpi, msg));
} else if (msg instanceof GridDhtTxFinishRequest) {
IgniteEx to = IgnitionEx.gridxx(node.id());
GridDhtTxFinishRequest req = (GridDhtTxFinishRequest) msg;
GridCacheVersion nearVer = nearToLocVerMap.get(req.version());
futMap.put(req.futureId(), nearVer);
IgniteEx from = fromNode(wrappedPrimSpi);
IgniteInternalTx primTx = findTx(from, nearVer, true);
IgniteInternalTx backupTx = findTx(to, nearVer, false);
return cb.beforeBackupFinish(from, to, primTx, backupTx, nearVer.asIgniteUuid(), createSendFuture(wrappedPrimSpi, msg));
} else if (msg instanceof GridNearTxPrepareResponse) {
GridNearTxPrepareResponse resp = (GridNearTxPrepareResponse) msg;
IgniteEx from = fromNode(wrappedPrimSpi);
GridCacheVersion ver = futMap.get(resp.futureId());
IgniteInternalTx primTx = findTx(from, ver, true);
return cb.afterPrimaryPrepare(from, primTx, ver.asIgniteUuid(), createSendFuture(wrappedPrimSpi, msg));
} else if (msg instanceof GridNearTxFinishResponse) {
IgniteEx to = IgnitionEx.gridxx(node.id());
GridNearTxFinishResponse req = (GridNearTxFinishResponse) msg;
IgniteEx from = fromNode(wrappedPrimSpi);
IgniteUuid nearVer = futMap.get(req.futureId()).asIgniteUuid();
return cb.afterPrimaryFinish(from, nearVer, createSendFuture(wrappedPrimSpi, msg));
}
return false;
};
}
use of org.apache.ignite.internal.processors.cache.distributed.dht.GridDhtTxFinishRequest in project ignite by apache.
the class GridNearTxFinishFuture method checkBackup.
/**
*/
private void checkBackup() {
assert !hasFutures() : futures();
GridDistributedTxMapping mapping = mappings.singleMapping();
if (mapping != null) {
UUID nodeId = mapping.primary().id();
Collection<UUID> backups = tx.transactionNodes().get(nodeId);
if (!F.isEmpty(backups)) {
assert backups.size() == 1;
UUID backupId = F.first(backups);
ClusterNode backup = cctx.discovery().node(backupId);
// Nothing to do if backup has left the grid.
if (backup == null) {
readyNearMappingFromBackup(mapping);
ClusterTopologyCheckedException cause = new ClusterTopologyCheckedException("Backup node left grid: " + backupId);
cause.retryReadyFuture(cctx.nextAffinityReadyFuture(tx.topologyVersion()));
onDone(new IgniteTxRollbackCheckedException("Failed to commit transaction " + "(backup has left grid): " + tx.xidVersion(), cause));
} else {
final CheckBackupMiniFuture mini = new CheckBackupMiniFuture(1, backup, mapping);
add(mini);
if (backup.isLocal()) {
boolean committed = !cctx.tm().addRolledbackTx(tx);
readyNearMappingFromBackup(mapping);
if (committed) {
try {
if (tx.needReturnValue() && tx.implicit()) {
GridCacheReturnCompletableWrapper wrapper = cctx.tm().getCommittedTxReturn(tx.xidVersion());
assert wrapper != null : tx.xidVersion();
GridCacheReturn retVal = wrapper.fut().get();
assert retVal != null;
tx.implicitSingleResult(retVal);
}
if (tx.syncMode() == FULL_SYNC) {
GridCacheVersion nearXidVer = tx.nearXidVersion();
assert nearXidVer != null : tx;
IgniteInternalFuture<?> fut = cctx.tm().remoteTxFinishFuture(nearXidVer);
fut.listen(new CI1<IgniteInternalFuture<?>>() {
@Override
public void apply(IgniteInternalFuture<?> fut) {
mini.onDone(tx);
}
});
return;
}
mini.onDone(tx);
} catch (IgniteCheckedException e) {
if (msgLog.isDebugEnabled()) {
msgLog.debug("Near finish fut, failed to finish [" + "txId=" + tx.nearXidVersion() + ", node=" + backup.id() + ", err=" + e + ']');
}
mini.onDone(e);
}
} else {
ClusterTopologyCheckedException cause = new ClusterTopologyCheckedException("Primary node left grid: " + nodeId);
cause.retryReadyFuture(cctx.nextAffinityReadyFuture(tx.topologyVersion()));
mini.onDone(new IgniteTxRollbackCheckedException("Failed to commit transaction " + "(transaction has been rolled back on backup node): " + tx.xidVersion(), cause));
}
} else {
GridDhtTxFinishRequest finishReq = checkCommittedRequest(mini.futureId(), false);
try {
cctx.io().send(backup, finishReq, tx.ioPolicy());
if (msgLog.isDebugEnabled()) {
msgLog.debug("Near finish fut, sent check committed request [" + "txId=" + tx.nearXidVersion() + ", node=" + backup.id() + ']');
}
} catch (ClusterTopologyCheckedException ignored) {
mini.onNodeLeft(backupId, false);
} catch (IgniteCheckedException e) {
if (msgLog.isDebugEnabled()) {
msgLog.debug("Near finish fut, failed to send check committed request [" + "txId=" + tx.nearXidVersion() + ", node=" + backup.id() + ", err=" + e + ']');
}
mini.onDone(e);
}
}
}
} else
readyNearMappingFromBackup(mapping);
}
}
use of org.apache.ignite.internal.processors.cache.distributed.dht.GridDhtTxFinishRequest in project ignite by apache.
the class GridNearTxFinishFuture method checkCommittedRequest.
/**
* @param miniId Mini future ID.
* @param waitRemoteTxs Wait for remote txs.
* @return Finish request.
*/
private GridDhtTxFinishRequest checkCommittedRequest(int miniId, boolean waitRemoteTxs) {
GridDhtTxFinishRequest finishReq = new GridDhtTxFinishRequest(cctx.localNodeId(), futureId(), miniId, tx.topologyVersion(), tx.xidVersion(), tx.commitVersion(), tx.threadId(), tx.isolation(), true, false, tx.system(), tx.ioPolicy(), false, tx.syncMode(), null, null, null, null, 0, 0, tx.activeCachesDeploymentEnabled(), !waitRemoteTxs && (tx.needReturnValue() && tx.implicit()), waitRemoteTxs, null, null);
finishReq.checkCommitted(true);
return finishReq;
}
use of org.apache.ignite.internal.processors.cache.distributed.dht.GridDhtTxFinishRequest in project ignite by apache.
the class GridCommandHandlerTest method testKillHangingRemoteTransactions.
/**
* Simulate uncommitted backup transactions and test rolling back using utility.
*/
@Test
public void testKillHangingRemoteTransactions() throws Exception {
final int cnt = 3;
startGridsMultiThreaded(cnt);
Ignite[] clients = new Ignite[] { startGrid("client1"), startGrid("client2"), startGrid("client3"), startGrid("client4") };
clients[0].getOrCreateCache(new CacheConfiguration<>(DEFAULT_CACHE_NAME).setBackups(2).setAtomicityMode(TRANSACTIONAL).setWriteSynchronizationMode(FULL_SYNC).setAffinity(new RendezvousAffinityFunction(false, 64)));
awaitPartitionMapExchange();
for (Ignite client : clients) {
assertTrue(client.configuration().isClientMode());
assertNotNull(client.cache(DEFAULT_CACHE_NAME));
}
LongAdder progress = new LongAdder();
AtomicInteger idx = new AtomicInteger();
int tc = clients.length;
CountDownLatch lockLatch = new CountDownLatch(1);
CountDownLatch commitLatch = new CountDownLatch(1);
Ignite prim = primaryNode(0L, DEFAULT_CACHE_NAME);
TestRecordingCommunicationSpi primSpi = TestRecordingCommunicationSpi.spi(prim);
primSpi.blockMessages(new IgniteBiPredicate<ClusterNode, Message>() {
@Override
public boolean apply(ClusterNode node, Message message) {
return message instanceof GridDhtTxFinishRequest;
}
});
Set<IgniteUuid> xidSet = new GridConcurrentHashSet<>();
IgniteInternalFuture<?> fut = multithreadedAsync(new Runnable() {
@Override
public void run() {
int id = idx.getAndIncrement();
Ignite client = clients[id];
try (Transaction tx = client.transactions().txStart(PESSIMISTIC, READ_COMMITTED, 0, 1)) {
xidSet.add(tx.xid());
IgniteCache<Long, Long> cache = client.cache(DEFAULT_CACHE_NAME);
if (id != 0)
U.awaitQuiet(lockLatch);
cache.invoke(0L, new IncrementClosure(), null);
if (id == 0) {
lockLatch.countDown();
U.awaitQuiet(commitLatch);
// Wait until candidates will enqueue.
doSleep(500);
}
tx.commit();
} catch (Exception e) {
assertTrue(X.hasCause(e, TransactionTimeoutException.class));
}
progress.increment();
}
}, tc, "invoke-thread");
U.awaitQuiet(lockLatch);
commitLatch.countDown();
primSpi.waitForBlocked(clients.length);
// Unblock only finish messages from clients from 2 to 4.
primSpi.stopBlock(true, blockedMsg -> {
GridIoMessage iom = blockedMsg.ioMessage();
Message m = iom.message();
if (m instanceof GridDhtTxFinishRequest) {
GridDhtTxFinishRequest r = (GridDhtTxFinishRequest) m;
return !r.nearNodeId().equals(clients[0].cluster().localNode().id());
}
return true;
});
// Wait until queue is stable
for (Ignite ignite : G.allGrids()) {
if (ignite.configuration().isClientMode())
continue;
Collection<IgniteInternalTx> txs = ((IgniteEx) ignite).context().cache().context().tm().activeTransactions();
waitForCondition(new GridAbsPredicate() {
@Override
public boolean apply() {
for (IgniteInternalTx tx : txs) if (!tx.local()) {
IgniteTxEntry entry = tx.writeEntries().iterator().next();
GridCacheEntryEx cached = entry.cached();
Collection<GridCacheMvccCandidate> candidates = cached.remoteMvccSnapshot();
if (candidates.size() != clients.length)
return false;
}
return true;
}
}, 10_000);
}
CommandHandler h = new CommandHandler();
// Check listing.
validate(h, map -> {
for (int i = 0; i < cnt; i++) {
IgniteEx grid = grid(i);
// Skip primary.
if (grid.localNode().id().equals(prim.cluster().localNode().id()))
continue;
VisorTxTaskResult res = map.get(grid.localNode());
List<VisorTxInfo> infos = res.getInfos().stream().filter(info -> xidSet.contains(info.getNearXid())).collect(Collectors.toList());
// Validate queue length on backups.
assertEquals(clients.length, infos.size());
}
}, "--tx");
// Check kill.
validate(h, map -> {
// No-op.
}, "--tx", "--kill");
// Wait for all remote txs to finish.
for (Ignite ignite : G.allGrids()) {
if (ignite.configuration().isClientMode())
continue;
Collection<IgniteInternalTx> txs = ((IgniteEx) ignite).context().cache().context().tm().activeTransactions();
for (IgniteInternalTx tx : txs) if (!tx.local())
tx.finishFuture().get();
}
// Unblock finish message from client1.
primSpi.stopBlock(true);
fut.get();
Long cur = (Long) clients[0].cache(DEFAULT_CACHE_NAME).get(0L);
assertEquals(tc - 1, cur.longValue());
checkUserFutures();
}
use of org.apache.ignite.internal.processors.cache.distributed.dht.GridDhtTxFinishRequest in project ignite by apache.
the class IgniteTxCachePrimarySyncTest method singleKeyCommitFromPrimary.
/**
* @param ignite Node executing cache operation.
* @param ccfg Cache configuration.
* @param c Cache update closure.
* @throws Exception If failed.
*/
private void singleKeyCommitFromPrimary(Ignite ignite, final CacheConfiguration<Object, Object> ccfg, IgniteBiInClosure<Integer, IgniteCache<Object, Object>> c) throws Exception {
TestRecordingCommunicationSpi commSpi0 = (TestRecordingCommunicationSpi) ignite.configuration().getCommunicationSpi();
IgniteCache<Object, Object> cache = ignite.cache(ccfg.getName());
final Integer key = primaryKey(cache);
cache.remove(key);
waitKeyRemoved(ccfg.getName(), key);
commSpi0.record(GridDhtTxFinishRequest.class);
commSpi0.blockMessages(new IgniteBiPredicate<ClusterNode, Message>() {
@Override
public boolean apply(ClusterNode node, Message msg) {
return msg instanceof GridDhtTxFinishRequest;
}
});
c.apply(key, cache);
assertEquals(key, cache.localPeek(key));
U.sleep(50);
for (int i = 0; i < SRVS; i++) {
Ignite node = ignite(i);
if (node != ignite)
assertNull(node.cache(DEFAULT_CACHE_NAME).localPeek(key));
}
commSpi0.stopBlock(true);
waitKeyUpdated(ignite, ccfg.getBackups() + 1, ccfg.getName(), key);
List<Object> msgs = commSpi0.recordedMessages(true);
assertEquals(ccfg.getBackups(), msgs.size());
cache.remove(key);
waitKeyRemoved(ccfg.getName(), key);
c.apply(key, cache);
waitKeyUpdated(ignite, ccfg.getBackups() + 1, ccfg.getName(), key);
}
Aggregations