use of org.apache.ignite.internal.processors.cache.distributed.dht.GridDhtTxRemote in project ignite by apache.
the class IgniteTxHandler method processDhtTxPrepareRequest.
/**
* @param nodeId Sender node ID.
* @param req Request.
*/
private void processDhtTxPrepareRequest(final UUID nodeId, final GridDhtTxPrepareRequest req) {
if (txPrepareMsgLog.isDebugEnabled()) {
txPrepareMsgLog.debug("Received dht prepare request [txId=" + req.nearXidVersion() + ", dhtTxId=" + req.version() + ", node=" + nodeId + ']');
}
assert nodeId != null;
assert req != null;
assert req.transactionNodes() != null;
GridDhtTxRemote dhtTx = null;
GridNearTxRemote nearTx = null;
GridDhtTxPrepareResponse res;
try {
res = new GridDhtTxPrepareResponse(req.partition(), req.version(), req.futureId(), req.miniId(), req.deployInfo() != null);
// Start near transaction first.
nearTx = !F.isEmpty(req.nearWrites()) ? startNearRemoteTx(ctx.deploy().globalLoader(), nodeId, req) : null;
dhtTx = startRemoteTx(nodeId, req, res);
// Set evicted keys from near transaction.
if (nearTx != null)
res.nearEvicted(nearTx.evicted());
if (dhtTx != null)
req.txState(dhtTx.txState());
else if (nearTx != null)
req.txState(nearTx.txState());
if (dhtTx != null && !F.isEmpty(dhtTx.invalidPartitions()))
res.invalidPartitionsByCacheId(dhtTx.invalidPartitions());
if (req.onePhaseCommit()) {
assert req.last();
if (dhtTx != null) {
dhtTx.onePhaseCommit(true);
dhtTx.needReturnValue(req.needReturnValue());
finish(dhtTx, req);
}
if (nearTx != null) {
nearTx.onePhaseCommit(true);
finish(nearTx, req);
}
}
} catch (IgniteCheckedException e) {
if (e instanceof IgniteTxRollbackCheckedException)
U.error(log, "Transaction was rolled back before prepare completed: " + req, e);
else if (e instanceof IgniteTxOptimisticCheckedException) {
if (log.isDebugEnabled())
log.debug("Optimistic failure for remote transaction (will rollback): " + req);
} else if (e instanceof IgniteTxHeuristicCheckedException) {
U.warn(log, "Failed to commit transaction (all transaction entries were invalidated): " + CU.txString(dhtTx));
} else
U.error(log, "Failed to process prepare request: " + req, e);
if (nearTx != null)
nearTx.rollbackRemoteTx();
res = new GridDhtTxPrepareResponse(req.partition(), req.version(), req.futureId(), req.miniId(), e, req.deployInfo() != null);
}
if (req.onePhaseCommit()) {
IgniteInternalFuture completeFut;
IgniteInternalFuture<IgniteInternalTx> dhtFin = dhtTx == null ? null : dhtTx.done() ? null : dhtTx.finishFuture();
final IgniteInternalFuture<IgniteInternalTx> nearFin = nearTx == null ? null : nearTx.done() ? null : nearTx.finishFuture();
if (dhtFin != null && nearFin != null) {
GridCompoundFuture fut = new GridCompoundFuture();
fut.add(dhtFin);
fut.add(nearFin);
fut.markInitialized();
completeFut = fut;
} else
completeFut = dhtFin != null ? dhtFin : nearFin;
if (completeFut != null) {
final GridDhtTxPrepareResponse res0 = res;
final GridDhtTxRemote dhtTx0 = dhtTx;
final GridNearTxRemote nearTx0 = nearTx;
completeFut.listen(new CI1<IgniteInternalFuture<IgniteInternalTx>>() {
@Override
public void apply(IgniteInternalFuture<IgniteInternalTx> fut) {
sendReply(nodeId, req, res0, dhtTx0, nearTx0);
}
});
} else
sendReply(nodeId, req, res, dhtTx, nearTx);
} else
sendReply(nodeId, req, res, dhtTx, nearTx);
assert req.txState() != null || res.error() != null || (ctx.tm().tx(req.version()) == null && ctx.tm().nearTx(req.version()) == null);
}
use of org.apache.ignite.internal.processors.cache.distributed.dht.GridDhtTxRemote in project ignite by apache.
the class IgniteTxHandler method startRemoteTx.
/**
* @param nodeId Node ID.
* @param req Request.
* @param res Response.
* @return Remote transaction.
* @throws IgniteCheckedException If failed.
*/
@Nullable
GridDhtTxRemote startRemoteTx(UUID nodeId, GridDhtTxPrepareRequest req, GridDhtTxPrepareResponse res) throws IgniteCheckedException {
if (!F.isEmpty(req.writes())) {
GridDhtTxRemote tx = ctx.tm().tx(req.version());
if (tx == null) {
boolean single = req.last() && req.writes().size() == 1;
tx = new GridDhtTxRemote(ctx, req.nearNodeId(), req.futureId(), nodeId, req.topologyVersion(), req.version(), null, req.system(), req.policy(), req.concurrency(), req.isolation(), req.isInvalidate(), req.timeout(), req.writes() != null ? Math.max(req.writes().size(), req.txSize()) : req.txSize(), req.nearXidVersion(), req.transactionNodes(), req.subjectId(), req.taskNameHash(), single);
tx.writeVersion(req.writeVersion());
tx = ctx.tm().onCreated(null, tx);
if (tx == null || !ctx.tm().onStarted(tx)) {
if (log.isDebugEnabled())
log.debug("Attempt to start a completed transaction (will ignore): " + tx);
return null;
}
if (ctx.discovery().node(nodeId) == null) {
tx.state(ROLLING_BACK);
tx.state(ROLLED_BACK);
ctx.tm().uncommitTx(tx);
return null;
}
} else {
tx.writeVersion(req.writeVersion());
tx.transactionNodes(req.transactionNodes());
}
if (!tx.isSystemInvalidate()) {
int idx = 0;
for (IgniteTxEntry entry : req.writes()) {
GridCacheContext cacheCtx = entry.context();
int part = cacheCtx.affinity().partition(entry.key());
GridDhtLocalPartition locPart = cacheCtx.topology().localPartition(part, req.topologyVersion(), false);
if (locPart != null && locPart.reserve()) {
try {
tx.addWrite(entry, ctx.deploy().globalLoader());
if (isNearEnabled(cacheCtx) && req.invalidateNearEntry(idx))
invalidateNearEntry(cacheCtx, entry.key(), req.version());
if (req.needPreloadKey(idx)) {
GridCacheEntryEx cached = entry.cached();
if (cached == null)
cached = cacheCtx.cache().entryEx(entry.key(), req.topologyVersion());
GridCacheEntryInfo info = cached.info();
if (info != null && !info.isNew() && !info.isDeleted())
res.addPreloadEntry(info);
}
if (cacheCtx.readThroughConfigured() && !entry.skipStore() && entry.op() == TRANSFORM && entry.oldValueOnPrimary() && !entry.hasValue()) {
while (true) {
try {
GridCacheEntryEx cached = entry.cached();
if (cached == null) {
cached = cacheCtx.cache().entryEx(entry.key(), req.topologyVersion());
entry.cached(cached);
}
CacheObject val = cached.innerGet(/*ver*/
null, tx, /*readThrough*/
false, /*updateMetrics*/
false, /*evt*/
false, tx.subjectId(), /*transformClo*/
null, tx.resolveTaskName(), /*expiryPlc*/
null, /*keepBinary*/
true);
if (val == null)
val = cacheCtx.toCacheObject(cacheCtx.store().load(null, entry.key()));
if (val != null)
entry.readValue(val);
break;
} catch (GridCacheEntryRemovedException ignored) {
if (log.isDebugEnabled())
log.debug("Got entry removed exception, will retry: " + entry.txKey());
entry.cached(cacheCtx.cache().entryEx(entry.key(), req.topologyVersion()));
}
}
}
} catch (GridDhtInvalidPartitionException e) {
tx.addInvalidPartition(cacheCtx, e.partition());
tx.clearEntry(entry.txKey());
} finally {
locPart.release();
}
} else
tx.addInvalidPartition(cacheCtx, part);
idx++;
}
}
// Prepare prior to reordering, so the pending locks added
// in prepare phase will get properly ordered as well.
tx.prepareRemoteTx();
if (req.last()) {
assert !F.isEmpty(req.transactionNodes()) : "Received last prepare request with empty transaction nodes: " + req;
tx.state(PREPARED);
}
res.invalidPartitionsByCacheId(tx.invalidPartitions());
if (tx.empty() && req.last()) {
tx.rollbackRemoteTx();
return null;
}
return tx;
}
return null;
}
use of org.apache.ignite.internal.processors.cache.distributed.dht.GridDhtTxRemote in project ignite by apache.
the class IgniteTxHandler method processDhtTxFinishRequest.
/**
* @param nodeId Node ID.
* @param req Request.
*/
@SuppressWarnings({ "unchecked" })
private void processDhtTxFinishRequest(final UUID nodeId, final GridDhtTxFinishRequest req) {
assert nodeId != null;
assert req != null;
if (req.checkCommitted()) {
boolean committed = req.waitRemoteTransactions() || !ctx.tm().addRolledbackTx(null, req.version());
if (!committed || req.syncMode() != FULL_SYNC)
sendReply(nodeId, req, committed, null);
else {
IgniteInternalFuture<?> fut = ctx.tm().remoteTxFinishFuture(req.version());
fut.listen(new CI1<IgniteInternalFuture<?>>() {
@Override
public void apply(IgniteInternalFuture<?> fut) {
sendReply(nodeId, req, true, null);
}
});
}
return;
}
final GridDhtTxRemote dhtTx = ctx.tm().tx(req.version());
GridNearTxRemote nearTx = ctx.tm().nearTx(req.version());
final GridCacheVersion nearTxId = (dhtTx != null ? dhtTx.nearXidVersion() : (nearTx != null ? nearTx.nearXidVersion() : null));
if (txFinishMsgLog.isDebugEnabled()) {
txFinishMsgLog.debug("Received dht finish request [txId=" + nearTxId + ", dhtTxId=" + req.version() + ", node=" + nodeId + ']');
}
// Safety - local transaction will finish explicitly.
if (nearTx != null && nearTx.local())
nearTx = null;
finish(nodeId, dhtTx, req);
if (nearTx != null)
finish(nodeId, nearTx, req);
if (req.replyRequired()) {
IgniteInternalFuture completeFut;
IgniteInternalFuture<IgniteInternalTx> dhtFin = dhtTx == null ? null : dhtTx.done() ? null : dhtTx.finishFuture();
final IgniteInternalFuture<IgniteInternalTx> nearFin = nearTx == null ? null : nearTx.done() ? null : nearTx.finishFuture();
if (dhtFin != null && nearFin != null) {
GridCompoundFuture fut = new GridCompoundFuture();
fut.add(dhtFin);
fut.add(nearFin);
fut.markInitialized();
completeFut = fut;
} else
completeFut = dhtFin != null ? dhtFin : nearFin;
if (completeFut != null) {
completeFut.listen(new CI1<IgniteInternalFuture<IgniteInternalTx>>() {
@Override
public void apply(IgniteInternalFuture<IgniteInternalTx> fut) {
sendReply(nodeId, req, true, nearTxId);
}
});
} else
sendReply(nodeId, req, true, nearTxId);
} else
sendReply(nodeId, req, true, null);
IgniteInternalTx tx0 = ctx.tm().tx(req.version());
IgniteInternalTx nearTx0 = ctx.tm().nearTx(req.version());
assert req.txState() != null || (tx0 == null && nearTx0 == null) : req + " tx=" + tx0 + " nearTx=" + nearTx0;
}
use of org.apache.ignite.internal.processors.cache.distributed.dht.GridDhtTxRemote in project ignite by apache.
the class IgniteTxManager method commitIfPrepared.
/**
* Commits transaction in case when node started transaction failed, but all related
* transactions were prepared (invalidates transaction if it is not fully prepared).
*
* @param tx Transaction.
* @param failedNodeIds Failed nodes IDs.
*/
public void commitIfPrepared(IgniteInternalTx tx, Set<UUID> failedNodeIds) {
assert tx instanceof GridDhtTxLocal || tx instanceof GridDhtTxRemote : tx;
assert !F.isEmpty(tx.transactionNodes()) : tx;
assert tx.nearXidVersion() != null : tx;
GridCacheTxRecoveryFuture fut = new GridCacheTxRecoveryFuture(cctx, tx, failedNodeIds, tx.transactionNodes());
cctx.mvcc().addFuture(fut, fut.futureId());
if (log.isDebugEnabled())
log.debug("Checking optimistic transaction state on remote nodes [tx=" + tx + ", fut=" + fut + ']');
fut.prepare();
}
Aggregations