use of org.apache.ignite.internal.processors.cache.transactions.TransactionProxyImpl in project ignite by apache.
the class IgniteTxPessimisticOriginatingNodeFailureAbstractSelfTest method checkPrimaryNodeCrash.
/**
* Checks tx data consistency in case when primary node crashes.
*
* @param commmit Whether to commit or rollback a transaction.
* @throws Exception If failed.
*/
private void checkPrimaryNodeCrash(final boolean commmit) throws Exception {
Set<Integer> keys = new HashSet<>();
for (int i = 0; i < 20; i++) keys.add(i);
final Collection<IgniteKernal> grids = new ArrayList<>();
ClusterNode primaryNode = grid(1).localNode();
for (int i = 0; i < gridCount(); i++) {
if (i != 1)
grids.add((IgniteKernal) grid(i));
}
failingNodeId = primaryNode.id();
final Map<Integer, String> map = new HashMap<>();
final String initVal = "initialValue";
for (Integer key : keys) {
grid(originatingNode()).cache(DEFAULT_CACHE_NAME).put(key, initVal);
map.put(key, String.valueOf(key));
}
Map<Integer, Collection<ClusterNode>> nodeMap = new HashMap<>();
IgniteCache<Integer, String> cache = grid(0).cache(DEFAULT_CACHE_NAME);
info("Failing node ID: " + grid(1).localNode().id());
for (Integer key : keys) {
Collection<ClusterNode> nodes = new ArrayList<>();
nodes.addAll(affinity(cache).mapKeyToPrimaryAndBackups(key));
nodes.remove(primaryNode);
nodeMap.put(key, nodes);
}
info("Starting tx [values=" + map + ", topVer=" + grid(1).context().discovery().topologyVersion() + ']');
assertNotNull(cache);
try (Transaction tx = grid(0).transactions().txStart()) {
cache.getAll(keys);
// Should not send any messages.
cache.putAll(map);
TransactionProxyImpl txProxy = (TransactionProxyImpl) tx;
GridNearTxLocal txEx = txProxy.tx();
assertTrue(txEx.pessimistic());
if (commmit) {
txEx.prepare(true);
// Fail the node in the middle of transaction.
info(">>> Stopping primary node " + primaryNode);
G.stop(Ignition.ignite(primaryNode.id()).name(), true);
info(">>> Stopped originating node, finishing transaction: " + primaryNode.id());
tx.commit();
} else {
// Fail the node in the middle of transaction.
info(">>> Stopping primary node " + primaryNode);
G.stop(G.ignite(primaryNode.id()).name(), true);
info(">>> Stopped originating node, finishing transaction: " + primaryNode.id());
tx.rollback();
}
}
boolean txFinished = GridTestUtils.waitForCondition(new GridAbsPredicate() {
@Override
public boolean apply() {
for (IgniteKernal g : grids) {
GridCacheAdapter<?, ?> cache = g.internalCache(DEFAULT_CACHE_NAME);
IgniteTxManager txMgr = cache.isNear() ? ((GridNearCacheAdapter) cache).dht().context().tm() : cache.context().tm();
int txNum = txMgr.idMapSize();
if (txNum != 0)
return false;
}
return true;
}
}, 10000);
assertTrue(txFinished);
info("Transactions finished.");
for (Map.Entry<Integer, Collection<ClusterNode>> e : nodeMap.entrySet()) {
final Integer key = e.getKey();
final String val = map.get(key);
assertFalse(e.getValue().isEmpty());
if (atomicityMode() == TRANSACTIONAL_SNAPSHOT)
continue;
for (ClusterNode node : e.getValue()) {
final UUID checkNodeId = node.id();
compute(G.ignite(checkNodeId).cluster().forNode(node)).call(new IgniteCallable<Void>() {
/**
*/
@IgniteInstanceResource
private Ignite ignite;
@Override
public Void call() throws Exception {
IgniteCache<Integer, String> cache = ignite.cache(DEFAULT_CACHE_NAME);
assertNotNull(cache);
assertEquals("Failed to check entry value on node: " + checkNodeId, !commmit ? initVal : val, cache.localPeek(key));
return null;
}
});
}
}
awaitPartitionMapExchange();
for (Map.Entry<Integer, String> e : map.entrySet()) {
long cntr0 = -1;
for (Ignite g : G.allGrids()) {
Integer key = e.getKey();
assertEquals(!commmit ? initVal : e.getValue(), g.cache(DEFAULT_CACHE_NAME).get(key));
if (g.affinity(DEFAULT_CACHE_NAME).isPrimaryOrBackup(((IgniteEx) g).localNode(), key)) {
long nodeCntr = updateCoutner(g, key);
if (cntr0 == -1)
cntr0 = nodeCntr;
assertEquals(cntr0, nodeCntr);
}
}
}
}
use of org.apache.ignite.internal.processors.cache.transactions.TransactionProxyImpl in project ignite by apache.
the class IgniteTxOriginatingNodeFailureAbstractSelfTest method testTxOriginatingNodeFails.
/**
* @param keys Keys to update.
* @param partial Flag indicating whether to simulate partial prepared state.
* @throws Exception If failed.
*/
protected void testTxOriginatingNodeFails(Collection<Integer> keys, final boolean partial) throws Exception {
assertFalse(keys.isEmpty());
final Collection<IgniteKernal> grids = new ArrayList<>();
ClusterNode txNode = grid(originatingNode()).localNode();
for (int i = 1; i < gridCount(); i++) grids.add((IgniteKernal) grid(i));
final Map<Integer, String> map = new HashMap<>();
final String initVal = "initialValue";
for (Integer key : keys) {
grid(originatingNode()).cache(DEFAULT_CACHE_NAME).put(key, initVal);
map.put(key, String.valueOf(key));
}
Map<Integer, Collection<ClusterNode>> nodeMap = new HashMap<>();
info("Node being checked: " + grid(1).localNode().id());
for (Integer key : keys) {
Collection<ClusterNode> nodes = new ArrayList<>();
nodes.addAll(grid(1).affinity(DEFAULT_CACHE_NAME).mapKeyToPrimaryAndBackups(key));
nodes.remove(txNode);
nodeMap.put(key, nodes);
}
info("Starting optimistic tx " + "[values=" + map + ", topVer=" + (grid(1)).context().discovery().topologyVersion() + ']');
if (partial)
ignoreMessages(grid(1).localNode().id(), ignoreMessageClass());
final Ignite txIgniteNode = G.ignite(txNode.id());
GridTestUtils.runAsync(new Callable<Object>() {
@Override
public Object call() throws Exception {
IgniteCache<Integer, String> cache = txIgniteNode.cache(DEFAULT_CACHE_NAME);
assertNotNull(cache);
TransactionProxyImpl tx = (TransactionProxyImpl) txIgniteNode.transactions().txStart();
GridNearTxLocal txEx = tx.tx();
assertTrue(txEx.optimistic());
cache.putAll(map);
try {
txEx.prepareNearTxLocal().get(3, TimeUnit.SECONDS);
} catch (IgniteFutureTimeoutCheckedException ignored) {
info("Failed to wait for prepare future completion: " + partial);
}
return null;
}
}).get();
info("Stopping originating node " + txNode);
G.stop(G.ignite(txNode.id()).name(), true);
info("Stopped grid, waiting for transactions to complete.");
boolean txFinished = GridTestUtils.waitForCondition(new GridAbsPredicate() {
@Override
public boolean apply() {
for (IgniteKernal g : grids) {
GridCacheSharedContext<Object, Object> ctx = g.context().cache().context();
int txNum = ctx.tm().idMapSize();
if (txNum != 0)
return false;
}
return true;
}
}, 10000);
assertTrue(txFinished);
info("Transactions finished.");
for (Map.Entry<Integer, Collection<ClusterNode>> e : nodeMap.entrySet()) {
final Integer key = e.getKey();
final String val = map.get(key);
assertFalse(e.getValue().isEmpty());
for (ClusterNode node : e.getValue()) {
compute(G.ignite(node.id()).cluster().forNode(node)).call(new IgniteCallable<Void>() {
/**
*/
@IgniteInstanceResource
private Ignite ignite;
@Override
public Void call() throws Exception {
IgniteCache<Integer, String> cache = ignite.cache(DEFAULT_CACHE_NAME);
assertNotNull(cache);
assertEquals(partial ? initVal : val, cache.localPeek(key));
return null;
}
});
}
}
for (Map.Entry<Integer, String> e : map.entrySet()) {
for (Ignite g : G.allGrids()) {
UUID locNodeId = g.cluster().localNode().id();
assertEquals("Check failed for node: " + locNodeId, partial ? initVal : e.getValue(), g.cache(DEFAULT_CACHE_NAME).get(e.getKey()));
}
}
}
use of org.apache.ignite.internal.processors.cache.transactions.TransactionProxyImpl in project ignite by apache.
the class GridExchangeFreeCellularSwitchIsolationTest method testOnlyAffectedNodesWaitForRecovery.
/**
* Test checks than non-affected nodes (alive cells) finishes the switch asap,
* that they wait only for the recovery related to these nodes (eg. replicated caches recovery that affects every node).
*/
@Test
public void testOnlyAffectedNodesWaitForRecovery() throws Exception {
int nodes = 6;
String recoveryStatusMsg = "TxRecovery Status and Timings [txs=";
// Any.
LogListener lsnrAny = matches(recoveryStatusMsg).build();
LogListener lsnrBrokenCell = matches(recoveryStatusMsg).times((nodes / 2) - 1).build();
LogListener lsnrAliveCell = matches(recoveryStatusMsg).times((nodes / 2)).build();
listeningLog.registerListener(lsnrAny);
startGridsMultiThreaded(nodes);
blockRecoveryMessages();
CellularCluster cluster = resolveCellularCluster(nodes, startFrom);
Ignite orig = cluster.orig;
Ignite failed = cluster.failed;
List<Ignite> brokenCellNodes = cluster.brokenCellNodes;
List<Ignite> aliveCellNodes = cluster.aliveCellNodes;
List<Integer> partKeys = new ArrayList<>();
List<Integer> replKeys = new ArrayList<>();
for (Ignite node : G.allGrids()) {
if (!node.configuration().isClientMode()) {
partKeys.add(primaryKey(node.getOrCreateCache(PART_CACHE_NAME)));
replKeys.add(primaryKey(node.getOrCreateCache(REPL_CACHE_NAME)));
}
}
CountDownLatch partPreparedLatch = new CountDownLatch(nodes);
CountDownLatch replPreparedLatch = new CountDownLatch(nodes);
CountDownLatch partCommitLatch = new CountDownLatch(1);
CountDownLatch replCommitLatch = new CountDownLatch(1);
AtomicInteger partKeyIdx = new AtomicInteger();
AtomicInteger replKeyIdx = new AtomicInteger();
Set<GridCacheVersion> partTxVers = new GridConcurrentHashSet<>();
Set<GridCacheVersion> replTxVers = new GridConcurrentHashSet<>();
IgniteInternalFuture<?> partFut = multithreadedAsync(() -> {
try {
int idx = partKeyIdx.getAndIncrement();
Transaction tx = orig.transactions().txStart();
partTxVers.add(((TransactionProxyImpl<?, ?>) tx).tx().nearXidVersion());
int key = partKeys.get(idx);
orig.getOrCreateCache(PART_CACHE_NAME).put(key, key);
((TransactionProxyImpl<?, ?>) tx).tx().prepare(true);
partPreparedLatch.countDown();
partCommitLatch.await();
if (orig != failed)
((TransactionProxyImpl<?, ?>) tx).commit();
} catch (Exception e) {
fail("Should not happen [exception=" + e + "]");
}
}, nodes);
IgniteInternalFuture<?> replFut = multithreadedAsync(() -> {
try {
int idx = replKeyIdx.getAndIncrement();
Transaction tx = orig.transactions().txStart();
replTxVers.add(((TransactionProxyImpl<?, ?>) tx).tx().nearXidVersion());
int key = replKeys.get(idx);
orig.getOrCreateCache(REPL_CACHE_NAME).put(key, key);
((TransactionProxyImpl<?, ?>) tx).tx().prepare(true);
replPreparedLatch.countDown();
replCommitLatch.await();
if (orig != failed)
((TransactionProxyImpl<?, ?>) tx).commit();
} catch (Exception e) {
fail("Should not happen [exception=" + e + "]");
}
}, nodes);
partPreparedLatch.await();
replPreparedLatch.await();
checkTransactionsCount(orig, nodes, brokenCellNodes, nodes / 2, aliveCellNodes, nodes / 2, partTxVers);
checkTransactionsCount(orig, nodes, brokenCellNodes, nodes, aliveCellNodes, nodes, replTxVers);
assertFalse(lsnrAny.check());
listeningLog.registerListener(lsnrAliveCell);
// Stopping node.
failed.close();
awaitForSwitchOnNodeLeft(failed);
// In case of originating node failed all alive primaries will recover (commit) txs on tx cordinator falure.
// Txs with failed primary will start recovery, but can't finish it since recovery messages are blocked.
// Broken cell's nodes will have 1 unrecovered tx for partitioned cache.
checkTransactionsCount(orig != failed ? orig : null, /*stopped*/
nodes, brokenCellNodes, orig == failed ? 1 : nodes / 2, aliveCellNodes, orig == failed ? 0 : nodes / 2, partTxVers);
// All cell's nodes will have 1 unrecovered tx for replicated cache.
checkTransactionsCount(orig != failed ? orig : null, /*stopped*/
nodes, brokenCellNodes, orig == failed ? 1 : nodes, aliveCellNodes, orig == failed ? 1 : nodes, replTxVers);
// Counts tx's creations and preparations.
BiConsumer<T2<Ignite, String>, T3<CountDownLatch, CountDownLatch, CountDownLatch>> txRun = (T2<Ignite, String> pair, T3</*create*/
CountDownLatch, /*put*/
CountDownLatch, /*commit*/
CountDownLatch> latches) -> {
try {
Ignite ignite = pair.get1();
String cacheName = pair.get2();
IgniteCache<Integer, Integer> cache = ignite.getOrCreateCache(cacheName);
try (Transaction tx = ignite.transactions().txStart()) {
// Create.
latches.get1().countDown();
// Avoiding intersection with prepared keys.
cache.put(primaryKeys(cache, 1, 1_000).get(0), 42);
// Put.
latches.get2().countDown();
tx.commit();
// Commit.
latches.get3().countDown();
}
} catch (Exception e) {
fail("Should not happen [exception=" + e + "]");
}
};
CountDownLatch partBrokenCellCreateLatch = new CountDownLatch(brokenCellNodes.size());
CountDownLatch partBrokenCellPutLatch = new CountDownLatch(brokenCellNodes.size());
CountDownLatch partBrokenCellCommitLatch = new CountDownLatch(brokenCellNodes.size());
CountDownLatch partAliveCellCreateLatch = new CountDownLatch(aliveCellNodes.size());
CountDownLatch partAliveCellPutLatch = new CountDownLatch(aliveCellNodes.size());
CountDownLatch partAliveCellCommitLatch = new CountDownLatch(aliveCellNodes.size());
CountDownLatch replBrokenCellCreateLatch = new CountDownLatch(brokenCellNodes.size());
CountDownLatch replBrokenCellPutLatch = new CountDownLatch(brokenCellNodes.size());
CountDownLatch replBrokenCellCommitLatch = new CountDownLatch(brokenCellNodes.size());
CountDownLatch replAliveCellCreateLatch = new CountDownLatch(aliveCellNodes.size());
CountDownLatch replAliveCellPutLatch = new CountDownLatch(aliveCellNodes.size());
CountDownLatch replAliveCellCommitLatch = new CountDownLatch(aliveCellNodes.size());
List<IgniteInternalFuture<?>> futs = new ArrayList<>();
for (Ignite brokenCellNode : brokenCellNodes) {
futs.add(multithreadedAsync(() -> txRun.accept(new T2<>(brokenCellNode, REPL_CACHE_NAME), new T3<>(replBrokenCellCreateLatch, replBrokenCellPutLatch, replBrokenCellCommitLatch)), 1));
futs.add(multithreadedAsync(() -> txRun.accept(new T2<>(brokenCellNode, PART_CACHE_NAME), new T3<>(partBrokenCellCreateLatch, partBrokenCellPutLatch, partBrokenCellCommitLatch)), 1));
}
for (Ignite aliveCellNode : aliveCellNodes) {
futs.add(multithreadedAsync(() -> txRun.accept(new T2<>(aliveCellNode, REPL_CACHE_NAME), new T3<>(replAliveCellCreateLatch, replAliveCellPutLatch, replAliveCellCommitLatch)), 1));
futs.add(multithreadedAsync(() -> txRun.accept(new T2<>(aliveCellNode, PART_CACHE_NAME), new T3<>(partAliveCellCreateLatch, partAliveCellPutLatch, partAliveCellCommitLatch)), 1));
}
// Switch in progress cluster-wide.
// Alive nodes switch blocked until replicated caches recovery happen.
checkUpcomingTransactionsState(// Started.
partBrokenCellCreateLatch, // Started.
0, partBrokenCellPutLatch, brokenCellNodes.size(), partBrokenCellCommitLatch, brokenCellNodes.size(), // Started. Blocked by replicated cache recovery.
partAliveCellCreateLatch, // Started. Blocked by replicated cache recovery.
0, partAliveCellPutLatch, aliveCellNodes.size(), partAliveCellCommitLatch, aliveCellNodes.size());
checkUpcomingTransactionsState(// Started.
replBrokenCellCreateLatch, // Started.
0, replBrokenCellPutLatch, brokenCellNodes.size(), replBrokenCellCommitLatch, brokenCellNodes.size(), // Started. Blocked by replicated cache recovery.
replAliveCellCreateLatch, // Started. Blocked by replicated cache recovery.
0, replAliveCellPutLatch, aliveCellNodes.size(), replAliveCellCommitLatch, aliveCellNodes.size());
checkTransactionsCount(orig != failed ? orig : null, /*stopped*/
nodes, brokenCellNodes, orig == failed ? 1 : nodes / 2, aliveCellNodes, orig == failed ? 0 : nodes / 2, partTxVers);
checkTransactionsCount(orig != failed ? orig : null, /*stopped*/
nodes, brokenCellNodes, orig == failed ? 1 : nodes, aliveCellNodes, orig == failed ? 1 : nodes, replTxVers);
// Replicated recovery.
for (Ignite ignite : G.allGrids()) {
TestRecordingCommunicationSpi spi = (TestRecordingCommunicationSpi) ignite.configuration().getCommunicationSpi();
spi.stopBlock(true, blockedMsg -> {
Message msg = blockedMsg.ioMessage().message();
return replTxVers.contains(((GridCacheTxRecoveryRequest) msg).nearXidVersion());
});
}
replCommitLatch.countDown();
replFut.get();
// Switch partially finished.
// Broken cell still in switch.
// Alive cell finished the switch.
checkUpcomingTransactionsState(// Started.
partBrokenCellCreateLatch, // Started.
0, partBrokenCellPutLatch, brokenCellNodes.size(), partBrokenCellCommitLatch, brokenCellNodes.size(), // Started.
partAliveCellCreateLatch, // Started.
0, // Alive cell nodes's able to start transactions on primaries,
partAliveCellPutLatch, // Alive cell nodes's able to start transactions on primaries,
0, partAliveCellCommitLatch, // Able to commit, since all primaries and backups are inside the alive cell.
0);
checkUpcomingTransactionsState(// Started.
replBrokenCellCreateLatch, // Started.
0, replBrokenCellPutLatch, brokenCellNodes.size(), replBrokenCellCommitLatch, brokenCellNodes.size(), // Started.
replAliveCellCreateLatch, // Started.
0, // Alive cell's nodes able to start transactions on primaries,
replAliveCellPutLatch, // Alive cell's nodes able to start transactions on primaries,
0, replAliveCellCommitLatch, // But not able to commit, since broken cell's nodes still in switch.
aliveCellNodes.size());
checkTransactionsCount(orig != failed ? orig : null, /*stopped*/
nodes, brokenCellNodes, orig == failed ? 1 : nodes / 2, // New txs able to start while previous are in progress.
aliveCellNodes, // New txs able to start while previous are in progress.
orig == failed ? 0 : nodes / 2, /*to be committed*/
partTxVers);
checkTransactionsCount(orig != failed ? orig : null, /*stopped*/
0, brokenCellNodes, 0, aliveCellNodes, 0, replTxVers);
// Recovery finished on alive cell.
assertTrue(waitForCondition(lsnrAliveCell::check, 5000));
listeningLog.registerListener(lsnrBrokenCell);
// Partitioned recovery.
for (Ignite ignite : G.allGrids()) {
TestRecordingCommunicationSpi spi = (TestRecordingCommunicationSpi) ignite.configuration().getCommunicationSpi();
spi.stopBlock(true, blockedMsg -> {
Message msg = blockedMsg.ioMessage().message();
return partTxVers.contains(((GridCacheTxRecoveryRequest) msg).nearXidVersion());
});
}
partCommitLatch.countDown();
partFut.get();
// Switches finished cluster-wide, all transactions can be committed.
checkUpcomingTransactionsState(replBrokenCellCreateLatch, 0, replBrokenCellPutLatch, 0, replBrokenCellCommitLatch, 0, replAliveCellCreateLatch, 0, replAliveCellPutLatch, 0, replAliveCellCommitLatch, 0);
checkUpcomingTransactionsState(partBrokenCellCreateLatch, 0, partBrokenCellPutLatch, 0, partBrokenCellCommitLatch, 0, partAliveCellCreateLatch, 0, partAliveCellPutLatch, 0, partAliveCellCommitLatch, 0);
// Check that pre-failure transactions are absent.
checkTransactionsCount(orig != failed ? orig : null, /*stopped*/
0, brokenCellNodes, 0, aliveCellNodes, 0, partTxVers);
checkTransactionsCount(orig != failed ? orig : null, /*stopped*/
0, brokenCellNodes, 0, aliveCellNodes, 0, replTxVers);
// Recovery finished on broken cell.
assertTrue(waitForCondition(lsnrBrokenCell::check, 5000));
for (IgniteInternalFuture<?> fut : futs) fut.get();
for (Ignite node : G.allGrids()) {
for (int key : partKeys) assertEquals(key, node.getOrCreateCache(PART_CACHE_NAME).get(key));
for (int key : replKeys) assertEquals(key, node.getOrCreateCache(REPL_CACHE_NAME).get(key));
}
// Final check that any transactions are absent.
checkTransactionsCount(null, 0, brokenCellNodes, 0, aliveCellNodes, 0, null);
}
use of org.apache.ignite.internal.processors.cache.transactions.TransactionProxyImpl in project ignite by apache.
the class GridExchangeFreeCellularSwitchTxContinuationTest method testAlreadyStartedTxsContinuationDuringAndAfterTheSwitch.
/**
* Tests checks that txs started before the switch can be continued after the switch if they are not affected by
* node fail.
*/
@Test
public void testAlreadyStartedTxsContinuationDuringAndAfterTheSwitch() throws Exception {
int nodes = 6;
startGridsMultiThreaded(nodes);
blockRecoveryMessages();
CellularCluster cluster = resolveCellularCluster(nodes, startFrom);
Ignite orig = cluster.orig;
Ignite failed = cluster.failed;
int txCnt = 1024;
// See puts count inside the closure.
int keysPerTx = 6;
int prepTxCnt = 100;
int dataAmount = txCnt * keysPerTx + prepTxCnt;
int totalDataAmount = dataAmount + prepTxCnt;
Queue<Integer> keys = new ConcurrentLinkedDeque<>();
Queue<Integer> primaryOnFailedKeys = new ConcurrentLinkedDeque<>();
Queue<Integer> keysToCheck = new ConcurrentLinkedDeque<>();
for (int i = 0; keys.size() < dataAmount; i++) if (// Will not cause node failed exception on put.
!primaryNode(i, PART_CACHE_NAME).equals(failed))
keys.add(i);
for (int i = 0; primaryOnFailedKeys.size() < prepTxCnt; i++) if (// Will cause explicit recovery on node fail.
primaryNode(i, PART_CACHE_NAME).equals(failed))
primaryOnFailedKeys.add(i);
CountDownLatch putInitLatch = new CountDownLatch(txCnt);
CountDownLatch prepLatch = new CountDownLatch(prepTxCnt * 2);
CountDownLatch nodeFailedLatch = new CountDownLatch(1);
CountDownLatch nodesAwareOfFailLatch = new CountDownLatch(1);
CountDownLatch txsRecoveryAllowedLatch = new CountDownLatch(1);
CountDownLatch txsRecoveryFinishedLatch = new CountDownLatch(1);
IgniteInternalFuture<?> txFut = multithreadedAsync(() -> {
try {
Transaction tx = orig.transactions().txStart(concurrency, isolation);
IgniteCache<Integer, Integer> cache = orig.getOrCreateCache(PART_CACHE_NAME);
// Put before node fail.
put(cache, keys, keysToCheck);
long initTopVer = ((IgniteEx) orig).context().cache().context().exchange().readyAffinityVersion().topologyVersion();
putInitLatch.countDown();
nodeFailedLatch.await();
// Put right after node fail.
put(cache, keys, keysToCheck);
nodesAwareOfFailLatch.await();
// Put when nodes are aware of fail.
put(cache, keys, keysToCheck);
txsRecoveryAllowedLatch.await();
// Put right after recovery allowed.
put(cache, keys, keysToCheck);
txsRecoveryFinishedLatch.await();
// Put right after recovery finished.
put(cache, keys, keysToCheck);
// Put with some random delay after recovery happen.
U.sleep(ThreadLocalRandom.current().nextInt(5_000));
put(cache, keys, keysToCheck);
((TransactionProxyImpl<?, ?>) tx).commit();
long commitTopVer = ((IgniteEx) orig).context().cache().context().exchange().readyAffinityVersion().topologyVersion();
// Started before the switch, but continued after it.
assertTrue(commitTopVer > initTopVer);
} catch (Exception e) {
fail("Should not happen [exception=" + e + "]");
}
}, txCnt);
IgniteInternalFuture<?> prepFut1 = multithreadedAsync(() -> {
// Keys with unaffected primary.
try {
putInitLatch.await();
Transaction tx = failed.transactions().txStart();
IgniteCache<Integer, Integer> cache = failed.getOrCreateCache(PART_CACHE_NAME);
put(cache, keys, keysToCheck);
((TransactionProxyImpl<?, ?>) tx).tx().prepare(true);
prepLatch.countDown();
txsRecoveryFinishedLatch.await();
} catch (Exception e) {
fail("Should not happen [exception=" + e + "]");
}
}, prepTxCnt);
IgniteInternalFuture<?> prepFut2 = multithreadedAsync(() -> {
// Primary keys of failed primary.
try {
putInitLatch.await();
Transaction tx = failed.transactions().txStart();
IgniteCache<Integer, Integer> cache = failed.getOrCreateCache(PART_CACHE_NAME);
put(cache, primaryOnFailedKeys, keysToCheck);
((TransactionProxyImpl<?, ?>) tx).tx().prepare(true);
prepLatch.countDown();
txsRecoveryFinishedLatch.await();
} catch (Exception e) {
fail("Should not happen [exception=" + e + "]");
}
}, prepTxCnt);
prepLatch.await();
// Stopping node.
failed.close();
nodeFailedLatch.countDown();
awaitForSwitchOnNodeLeft(failed);
nodesAwareOfFailLatch.countDown();
// Allowing recovery.
for (Ignite ignite : G.allGrids()) {
TestRecordingCommunicationSpi spi = (TestRecordingCommunicationSpi) ignite.configuration().getCommunicationSpi();
spi.stopBlock(true, blockedMsg -> true);
}
txsRecoveryAllowedLatch.countDown();
for (Ignite ignite : G.allGrids()) {
for (IgniteInternalTx tx : ((IgniteEx) ignite).context().cache().context().tm().activeTransactions()) {
while (tx.state() == TransactionState.PREPARED) U.sleep(100);
}
}
txsRecoveryFinishedLatch.countDown();
prepFut1.get();
prepFut2.get();
txFut.get();
assertTrue(keys.isEmpty());
assertTrue(primaryOnFailedKeys.isEmpty());
assertEquals(totalDataAmount, keysToCheck.size());
IgniteCache<Integer, Integer> cache = orig.getOrCreateCache(PART_CACHE_NAME);
for (Integer i : keysToCheck) assertEquals(i, cache.get(i));
}
use of org.apache.ignite.internal.processors.cache.transactions.TransactionProxyImpl in project ignite by apache.
the class WalRecoveryTxLogicalRecordsTest method prepareTx.
/**
* @param ignite Ignite.
* @param keys Keys.
*/
private int prepareTx(Ignite ignite, List<Integer> keys) throws IgniteCheckedException {
try (Transaction tx = ignite.transactions().txStart()) {
for (Integer key : keys) ignite.cache(CACHE_NAME).put(key, key);
GridNearTxLocal tx0 = ((TransactionProxyImpl) tx).tx();
tx0.prepare(true);
tx0.rollback();
}
return keys.size();
}
Aggregations