use of org.apache.ignite.internal.processors.cache.distributed.dht.GridDhtTxPrepareFuture in project ignite by apache.
the class GridCommandHandlerAbstractTest method checkUserFutures.
/**
* Checks if all non-system txs and non-system mvcc futures are finished.
*/
protected void checkUserFutures() {
for (Ignite ignite : G.allGrids()) {
IgniteEx ig = (IgniteEx) ignite;
final Collection<GridCacheFuture<?>> futs = ig.context().cache().context().mvcc().activeFutures();
boolean hasFutures = false;
for (GridCacheFuture<?> fut : futs) {
if (!fut.isDone()) {
// skipping system tx futures if possible
if (fut instanceof GridNearTxPrepareFutureAdapter && ((GridNearTxPrepareFutureAdapter) fut).tx().system())
continue;
if (fut instanceof GridDhtTxPrepareFuture && ((GridDhtTxPrepareFuture) fut).tx().system())
continue;
log.error("Expecting no active future [node=" + ig.localNode().id() + ", fut=" + fut + ']');
hasFutures = true;
}
}
if (hasFutures)
fail("Some mvcc futures are not finished");
Collection<IgniteInternalTx> txs = ig.context().cache().context().tm().activeTransactions().stream().filter(tx -> !tx.system()).collect(Collectors.toSet());
for (IgniteInternalTx tx : txs) log.error("Expecting no active transaction [node=" + ig.localNode().id() + ", tx=" + tx + ']');
if (!txs.isEmpty())
fail("Some transaction are not finished");
}
}
use of org.apache.ignite.internal.processors.cache.distributed.dht.GridDhtTxPrepareFuture in project ignite by apache.
the class GridNearTxLocal method prepareAsyncLocal.
/**
* Prepares next batch of entries in dht transaction.
*
* @param req Prepare request.
* @return Future that will be completed when locks are acquired.
*/
public IgniteInternalFuture<GridNearTxPrepareResponse> prepareAsyncLocal(GridNearTxPrepareRequest req) {
long timeout = remainingTime();
if (state() != PREPARING) {
if (timeout == -1)
return new GridFinishedFuture<>(timeoutException());
setRollbackOnly();
return new GridFinishedFuture<>(rollbackException());
}
if (timeout == -1)
return new GridFinishedFuture<>(timeoutException());
init();
GridDhtTxPrepareFuture fut = new GridDhtTxPrepareFuture(cctx, this, timeout, 0, Collections.<IgniteTxKey, GridCacheVersion>emptyMap(), req.last(), needReturnValue() && implicit());
try {
userPrepare((serializable() && optimistic()) ? F.concat(false, req.writes(), req.reads()) : req.writes());
// Make sure to add future before calling prepare on it.
cctx.mvcc().addFuture(fut);
if (isSystemInvalidate())
fut.complete();
else
fut.prepare(req);
} catch (IgniteTxTimeoutCheckedException | IgniteTxOptimisticCheckedException e) {
fut.onError(e);
} catch (IgniteCheckedException e) {
setRollbackOnly();
fut.onError(new IgniteTxRollbackCheckedException("Failed to prepare transaction: " + this, e));
}
return chainOnePhasePrepare(fut);
}
use of org.apache.ignite.internal.processors.cache.distributed.dht.GridDhtTxPrepareFuture in project ignite by apache.
the class GridNearTxLocal method prepareAsyncLocal.
/**
* Prepares next batch of entries in dht transaction.
*
* @param reads Read entries.
* @param writes Write entries.
* @param txNodes Transaction nodes mapping.
* @param last {@code True} if this is last prepare request.
* @return Future that will be completed when locks are acquired.
*/
@SuppressWarnings("TypeMayBeWeakened")
public IgniteInternalFuture<GridNearTxPrepareResponse> prepareAsyncLocal(@Nullable Collection<IgniteTxEntry> reads, @Nullable Collection<IgniteTxEntry> writes, Map<UUID, Collection<UUID>> txNodes, boolean last) {
long timeout = remainingTime();
if (state() != PREPARING) {
if (timeout == -1)
return new GridFinishedFuture<>(new IgniteTxTimeoutCheckedException("Transaction timed out: " + this));
setRollbackOnly();
return new GridFinishedFuture<>(new IgniteCheckedException("Invalid transaction state for prepare [state=" + state() + ", tx=" + this + ']'));
}
if (timeout == -1)
return new GridFinishedFuture<>(timeoutException());
init();
GridDhtTxPrepareFuture fut = new GridDhtTxPrepareFuture(cctx, this, timeout, 0, Collections.<IgniteTxKey, GridCacheVersion>emptyMap(), last, needReturnValue() && implicit());
try {
userPrepare((serializable() && optimistic()) ? F.concat(false, writes, reads) : writes);
// Make sure to add future before calling prepare on it.
cctx.mvcc().addFuture(fut);
if (isSystemInvalidate())
fut.complete();
else
fut.prepare(reads, writes, txNodes);
} catch (IgniteTxTimeoutCheckedException | IgniteTxOptimisticCheckedException e) {
fut.onError(e);
} catch (IgniteCheckedException e) {
setRollbackOnly();
fut.onError(new IgniteTxRollbackCheckedException("Failed to prepare transaction: " + this, e));
try {
rollback();
} catch (IgniteTxOptimisticCheckedException e1) {
if (log.isDebugEnabled())
log.debug("Failed optimistically to prepare transaction [tx=" + this + ", e=" + e1 + ']');
fut.onError(e);
} catch (IgniteCheckedException e1) {
U.error(log, "Failed to rollback transaction: " + this, e1);
}
}
return chainOnePhasePrepare(fut);
}
use of org.apache.ignite.internal.processors.cache.distributed.dht.GridDhtTxPrepareFuture in project ignite by apache.
the class IgniteTxHandler method processDhtTxPrepareResponse.
/**
* @param nodeId Node ID.
* @param res Response.
*/
private void processDhtTxPrepareResponse(UUID nodeId, GridDhtTxPrepareResponse res) {
try (TraceSurroundings ignored = MTC.support(ctx.kernalContext().tracing().create(TX_PROCESS_DHT_PREPARE_RESP, MTC.span()))) {
GridDhtTxPrepareFuture fut = (GridDhtTxPrepareFuture) ctx.mvcc().versionedFuture(res.version(), res.futureId());
if (fut == null) {
if (txPrepareMsgLog.isDebugEnabled()) {
txPrepareMsgLog.debug("Failed to find future for dht prepare response [txId=null" + ", dhtTxId=" + res.version() + ", node=" + nodeId + ", res=" + res + ']');
}
return;
} else if (txPrepareMsgLog.isDebugEnabled())
txPrepareMsgLog.debug("Received dht prepare response [txId=" + fut.tx().nearXidVersion() + ", node=" + nodeId + ']');
IgniteInternalTx tx = fut.tx();
assert tx != null;
res.txState(tx.txState());
fut.onResult(nodeId, res);
}
}
use of org.apache.ignite.internal.processors.cache.distributed.dht.GridDhtTxPrepareFuture in project ignite by apache.
the class TxRecoveryWithConcurrentRollbackTest method testTxDoesntBecomePreparedAfterError.
/**
* Start 3 servers,
* start 2 clients,
* start two OPTIMISTIC transactions with the same key from different client nodes,
* trying to transfer both to PREPARED state,
* stop one client node.
*/
@Test
public void testTxDoesntBecomePreparedAfterError() throws Exception {
backups = 2;
persistence = true;
syncMode = FULL_ASYNC;
final IgniteEx node0 = startGrids(3);
node0.cluster().state(ACTIVE);
final IgniteEx client1 = startGrid("client1");
final IgniteEx client2 = startGrid("client2");
awaitPartitionMapExchange();
final IgniteCache<Object, Object> cache = client1.cache(DEFAULT_CACHE_NAME);
final IgniteCache<Object, Object> cache2 = client2.cache(DEFAULT_CACHE_NAME);
final Integer pk = primaryKey(node0.cache(DEFAULT_CACHE_NAME));
CountDownLatch txPrepareLatch = new CountDownLatch(1);
GridTestUtils.runMultiThreadedAsync(() -> {
try (final Transaction tx = client1.transactions().withLabel("tx1").txStart(OPTIMISTIC, READ_COMMITTED, 5000, 1)) {
cache.put(pk, Boolean.TRUE);
TransactionProxyImpl p = (TransactionProxyImpl) tx;
// To prevent tx rollback on exit from try-with-resource block, this should cause another tx timeout fail.
spi(client1).blockMessages((node, msg) -> msg instanceof GridNearTxFinishRequest);
log.info("Test, preparing tx: xid=" + tx.xid() + ", tx=" + tx);
// Doing only prepare to try to lock the key, commit is not needed here.
p.tx().prepareNearTxLocal();
p.tx().currentPrepareFuture().listen(fut -> txPrepareLatch.countDown());
} catch (Exception e) {
// No-op.
}
}, 1, "tx1-thread");
try (final Transaction tx = client2.transactions().withLabel("tx2").txStart(OPTIMISTIC, READ_COMMITTED, 5000, 1)) {
cache2.put(pk, Boolean.TRUE);
TransactionProxyImpl p = (TransactionProxyImpl) tx;
log.info("Test, preparing tx: xid=" + tx.xid() + ", tx=" + tx);
p.tx().prepareNearTxLocal();
p.tx().currentPrepareFuture().listen(fut -> txPrepareLatch.countDown());
txPrepareLatch.await(6, TimeUnit.SECONDS);
if (txPrepareLatch.getCount() > 0)
fail("Failed to await for tx prepare.");
AtomicReference<GridDhtTxLocal> dhtTxLocRef = new AtomicReference<>();
assertTrue(waitForCondition(() -> {
dhtTxLocRef.set((GridDhtTxLocal) txs(node0).stream().filter(t -> t.state() == TransactionState.PREPARING).findFirst().orElse(null));
return dhtTxLocRef.get() != null;
}, 6_000));
assertNotNull(dhtTxLocRef.get());
UUID clientNodeToFail = dhtTxLocRef.get().eventNodeId();
GridDhtTxPrepareFuture prep = GridTestUtils.getFieldValue(dhtTxLocRef.get(), "prepFut");
prep.get();
List<IgniteInternalTx> txs = txs(node0);
String txsStr = txs.stream().map(Object::toString).collect(Collectors.joining(", "));
log.info("Transactions check point [count=" + txs.size() + ", txs=" + txsStr + "]");
if (clientNodeToFail.equals(client1.localNode().id()))
client1.close();
else if (clientNodeToFail.equals(client2.localNode().id()))
client2.close();
} catch (Exception e) {
log.error(e.getMessage(), e);
}
U.sleep(500);
assertEquals(3, grid(1).context().discovery().aliveServerNodes().size());
assertEquals(txs(client1).toString() + ", " + txs(client2).toString(), 1, txs(client1).size() + txs(client2).size());
}
Aggregations