You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by ag...@apache.org on 2018/04/23 16:03:49 UTC
[1/6] ignite git commit: IGNITE-6827 Configurable rollback for long
running transactions before partition exchange IGNITE-7910 Improved
transaction debugging support
Repository: ignite
Updated Branches:
refs/heads/master 74f465153 -> 2b5d2fc5f
http://git-wip-us.apache.org/repos/asf/ignite/blob/2b5d2fc5/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/CacheAbstractTransactionalTest.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/CacheAbstractTransactionalTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/CacheAbstractTransactionalTest.cs
index 3d0168c..a414a2f 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/CacheAbstractTransactionalTest.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/CacheAbstractTransactionalTest.cs
@@ -439,7 +439,6 @@ namespace Apache.Ignite.Core.Tests.Cache
Assert.AreEqual(TransactionState.MarkedRollback, tx.State);
var ex = Assert.Throws<TransactionRollbackException>(() => tx.Commit());
- Assert.IsTrue(ex.Message.StartsWith("Invalid transaction state for prepare [state=MARKED_ROLLBACK"));
tx.Dispose();
@@ -612,7 +611,7 @@ namespace Apache.Ignite.Core.Tests.Cache
}
/// <summary>
- /// Test Ignite transaction enlistment in ambient <see cref="TransactionScope"/>
+ /// Test Ignite transaction enlistment in ambient <see cref="TransactionScope"/>
/// with multiple participating caches.
/// </summary>
[Test]
@@ -668,7 +667,7 @@ namespace Apache.Ignite.Core.Tests.Cache
}
/// <summary>
- /// Test Ignite transaction enlistment in ambient <see cref="TransactionScope"/>
+ /// Test Ignite transaction enlistment in ambient <see cref="TransactionScope"/>
/// when Ignite tx is started manually.
/// </summary>
[Test]
@@ -680,7 +679,7 @@ namespace Apache.Ignite.Core.Tests.Cache
cache[1] = 1;
// When Ignite tx is started manually, it won't be enlisted in TransactionScope.
- using (var tx = transactions.TxStart())
+ using (var tx = transactions.TxStart())
{
using (new TransactionScope())
{
@@ -747,7 +746,7 @@ namespace Apache.Ignite.Core.Tests.Cache
cache[1] = 5;
}
-
+
// In case with Required option there is a single tx
// that gets aborted, second put executes outside the tx.
Assert.AreEqual(option == TransactionScopeOption.Required ? 5 : 3, cache[1], option.ToString());
@@ -927,4 +926,4 @@ namespace Apache.Ignite.Core.Tests.Cache
}
}
}
-}
\ No newline at end of file
+}
[4/6] ignite git commit: IGNITE-6827 Configurable rollback for long
running transactions before partition exchange IGNITE-7910 Improved
transaction debugging support
Posted by ag...@apache.org.
http://git-wip-us.apache.org/repos/asf/ignite/blob/2b5d2fc5/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearTxFinishFuture.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearTxFinishFuture.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearTxFinishFuture.java
index b6a8855..da8c6c8 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearTxFinishFuture.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearTxFinishFuture.java
@@ -39,6 +39,7 @@ import org.apache.ignite.internal.processors.cache.GridCacheFuture;
import org.apache.ignite.internal.processors.cache.GridCacheReturn;
import org.apache.ignite.internal.processors.cache.GridCacheReturnCompletableWrapper;
import org.apache.ignite.internal.processors.cache.GridCacheSharedContext;
+import org.apache.ignite.internal.processors.cache.GridCacheVersionedFuture;
import org.apache.ignite.internal.processors.cache.distributed.GridDistributedTxMapping;
import org.apache.ignite.internal.processors.cache.distributed.dht.GridDhtTxFinishRequest;
import org.apache.ignite.internal.processors.cache.distributed.dht.GridDhtTxFinishResponse;
@@ -55,6 +56,7 @@ import org.apache.ignite.internal.util.typedef.F;
import org.apache.ignite.internal.util.typedef.internal.CU;
import org.apache.ignite.internal.util.typedef.internal.S;
import org.apache.ignite.internal.util.typedef.internal.U;
+import org.apache.ignite.lang.IgniteInClosure;
import org.apache.ignite.lang.IgniteUuid;
import org.apache.ignite.transactions.TransactionRollbackException;
@@ -120,14 +122,8 @@ public final class GridNearTxFinishFuture<K, V> extends GridCacheCompoundIdentit
futId = IgniteUuid.randomUuid();
- CacheWriteSynchronizationMode syncMode;
-
if (tx.explicitLock())
- syncMode = FULL_SYNC;
- else
- syncMode = tx.syncMode();
-
- tx.syncMode(syncMode);
+ tx.syncMode(FULL_SYNC);
if (log == null) {
msgLog = cctx.txFinishMessageLogger();
@@ -399,9 +395,10 @@ public final class GridNearTxFinishFuture<K, V> extends GridCacheCompoundIdentit
*
* @param commit Commit flag.
* @param clearThreadMap If {@code true} removes {@link GridNearTxLocal} from thread map.
+ * @param onTimeout If {@code true} called from timeout handler.
*/
@SuppressWarnings("ForLoopReplaceableByForEach")
- public void finish(boolean commit, boolean clearThreadMap) {
+ public void finish(final boolean commit, final boolean clearThreadMap, final boolean onTimeout) {
if (tx.onNeedCheckBackup()) {
assert tx.onePhaseCommit();
@@ -414,6 +411,58 @@ public final class GridNearTxFinishFuture<K, V> extends GridCacheCompoundIdentit
return;
}
+ if (!commit && !clearThreadMap)
+ tryRollbackAsync(onTimeout); // Asynchronous rollback.
+ else
+ doFinish(commit, clearThreadMap);
+ }
+
+ /**
+ * Does async rollback when it's safe.
+ * If current future is not lock future (enlist future) waits until completion and tries again.
+ * Else terminates or waits for lock future depending on rollback mode.
+ *
+ * @param onTimeout If {@code true} called from timeout handler.
+ */
+ private void tryRollbackAsync(boolean onTimeout) {
+ IgniteInternalFuture<?> curFut = tx.tryRollbackAsync();
+
+ if (curFut == null) { // Safe to rollback.
+ doFinish(false, false);
+
+ return;
+ }
+
+ if (curFut instanceof GridCacheVersionedFuture && !onTimeout) {
+ try {
+ curFut.cancel(); // Force cancellation.
+ }
+ catch (IgniteCheckedException e) {
+ log.error("Failed to cancel lock for the transaction: " + CU.txString(tx), e);
+ }
+ }
+
+ curFut.listen(new IgniteInClosure<IgniteInternalFuture<?>>() {
+ @Override public void apply(IgniteInternalFuture<?> fut) {
+ try {
+ fut.get();
+
+ tryRollbackAsync(onTimeout);
+ }
+ catch (IgniteCheckedException e) {
+ doFinish(false, false);
+ }
+ }
+ });
+ }
+
+ /**
+ * Finishes a transaction.
+ *
+ * @param commit Commit.
+ * @param clearThreadMap Clear thread map.
+ */
+ private void doFinish(boolean commit, boolean clearThreadMap) {
try {
if (tx.localFinish(commit, clearThreadMap) || (!commit && tx.state() == UNKNOWN)) {
if ((tx.onePhaseCommit() && needFinishOnePhase(commit)) || (!tx.onePhaseCommit() && mappings != null)) {
@@ -423,17 +472,18 @@ public final class GridNearTxFinishFuture<K, V> extends GridCacheCompoundIdentit
if (mapping != null) {
assert !hasFutures() : futures();
- finish(1, mapping, commit);
+ finish(1, mapping, commit, !clearThreadMap);
}
}
else
- finish(mappings.mappings(), commit);
+ finish(mappings.mappings(), commit, !clearThreadMap);
}
markInitialized();
}
else
- onDone(new IgniteCheckedException("Failed to commit transaction: " + CU.txString(tx)));
+ onDone(new IgniteCheckedException("Failed to " + (commit ? "commit" : "rollback") +
+ " transaction: " + CU.txString(tx)));
}
catch (Error | RuntimeException e) {
onDone(e);
@@ -679,26 +729,28 @@ public final class GridNearTxFinishFuture<K, V> extends GridCacheCompoundIdentit
/**
* @param mappings Mappings.
* @param commit Commit flag.
+ * @param {@code true} If need to add completed version on finish.
*/
- private void finish(Iterable<GridDistributedTxMapping> mappings, boolean commit) {
+ private void finish(Iterable<GridDistributedTxMapping> mappings, boolean commit, boolean useCompletedVer) {
assert !hasFutures() : futures();
int miniId = 0;
// Create mini futures.
for (GridDistributedTxMapping m : mappings)
- finish(++miniId, m, commit);
+ finish(++miniId, m, commit, useCompletedVer);
}
/**
* @param miniId Mini future ID.
* @param m Mapping.
* @param commit Commit flag.
+ * @param useCompletedVer {@code True} if need to add completed version on finish.
*/
- private void finish(int miniId, GridDistributedTxMapping m, boolean commit) {
+ private void finish(int miniId, GridDistributedTxMapping m, boolean commit, boolean useCompletedVer) {
ClusterNode n = m.primary();
- assert !m.empty() : m;
+ assert !m.empty() : m + " " + tx.state();
CacheWriteSynchronizationMode syncMode = tx.syncMode();
@@ -706,7 +758,7 @@ public final class GridNearTxFinishFuture<K, V> extends GridCacheCompoundIdentit
syncMode = FULL_SYNC;
// Version to be added in completed versions on primary node.
- GridCacheVersion completedVer = !commit && tx.timeout() > 0 ? tx.xidVersion() : null;
+ GridCacheVersion completedVer = !commit && useCompletedVer ? tx.xidVersion() : null;
GridNearTxFinishRequest req = new GridNearTxFinishRequest(
futId,
@@ -746,7 +798,7 @@ public final class GridNearTxFinishFuture<K, V> extends GridCacheCompoundIdentit
add(fut); // Append new future.
- if (tx.pessimistic())
+ if (tx.pessimistic() && !useCompletedVer)
cctx.tm().beforeFinishRemote(n.id(), tx.threadId());
try {
@@ -1000,7 +1052,15 @@ public final class GridNearTxFinishFuture<K, V> extends GridCacheCompoundIdentit
*/
void onNearFinishResponse(GridNearTxFinishResponse res) {
if (res.error() != null)
- onDone(res.error());
+ if (res.error() instanceof IgniteTxRollbackCheckedException) {
+ // This exception is expected on asynchronous rollback.
+ if (log.isDebugEnabled())
+ log.debug("Transaction was rolled back: " + tx);
+
+ onDone(tx);
+ }
+ else
+ onDone(res.error());
else
onDone(tx);
}
http://git-wip-us.apache.org/repos/asf/ignite/blob/2b5d2fc5/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearTxLocal.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearTxLocal.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearTxLocal.java
index e339750..9c0b220 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearTxLocal.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearTxLocal.java
@@ -34,7 +34,6 @@ import javax.cache.CacheException;
import javax.cache.expiry.ExpiryPolicy;
import javax.cache.processor.EntryProcessor;
import org.apache.ignite.IgniteCheckedException;
-import org.apache.ignite.IgniteException;
import org.apache.ignite.cluster.ClusterNode;
import org.apache.ignite.internal.IgniteInternalFuture;
import org.apache.ignite.internal.NodeStoppingException;
@@ -67,6 +66,7 @@ import org.apache.ignite.internal.processors.cache.transactions.IgniteTxEntry;
import org.apache.ignite.internal.processors.cache.transactions.IgniteTxKey;
import org.apache.ignite.internal.processors.cache.transactions.TransactionProxy;
import org.apache.ignite.internal.processors.cache.transactions.TransactionProxyImpl;
+import org.apache.ignite.internal.processors.cache.transactions.TransactionProxyRollbackOnlyImpl;
import org.apache.ignite.internal.processors.cache.version.GridCacheVersion;
import org.apache.ignite.internal.processors.timeout.GridTimeoutObject;
import org.apache.ignite.internal.transactions.IgniteTxOptimisticCheckedException;
@@ -166,17 +166,24 @@ public class GridNearTxLocal extends GridDhtTxLocalAdapter implements GridTimeou
protected boolean transform;
/** */
- private final boolean trackTimeout;
+ private boolean trackTimeout;
/** */
@GridToStringExclude
private TransactionProxyImpl proxy;
+ /** */
+ @GridToStringExclude
+ private TransactionProxyImpl rollbackOnlyProxy;
+
+ /** Tx label. */
+ private @Nullable String lb;
+
/**
* Empty constructor required for {@link Externalizable}.
*/
public GridNearTxLocal() {
- this.trackTimeout = false;
+ // No-op.
}
/**
@@ -192,6 +199,7 @@ public class GridNearTxLocal extends GridDhtTxLocalAdapter implements GridTimeou
* @param txSize Transaction size.
* @param subjId Subject ID.
* @param taskNameHash Task name hash code.
+ * @param lb Label.
*/
public GridNearTxLocal(
GridCacheSharedContext ctx,
@@ -205,7 +213,8 @@ public class GridNearTxLocal extends GridDhtTxLocalAdapter implements GridTimeou
boolean storeEnabled,
int txSize,
@Nullable UUID subjId,
- int taskNameHash
+ int taskNameHash,
+ @Nullable String lb
) {
super(
ctx,
@@ -224,6 +233,7 @@ public class GridNearTxLocal extends GridDhtTxLocalAdapter implements GridTimeou
txSize,
subjId,
taskNameHash);
+ this.lb = lb;
mappings = implicitSingle ? new IgniteTxMappingsSingleImpl() : new IgniteTxMappingsImpl();
@@ -343,6 +353,24 @@ public class GridNearTxLocal extends GridDhtTxLocalAdapter implements GridTimeou
}
/** {@inheritDoc} */
+ @Override public long timeout(long timeout) {
+ long old = super.timeout(timeout);
+
+ if (old == timeout)
+ return old;
+
+ if (trackTimeout) {
+ if (!cctx.time().removeTimeoutObject(this))
+ return old; // Do nothing, because transaction is started to roll back.
+ }
+
+ if (timeout() > 0) // Method can be called only for explicit transactions.
+ trackTimeout = cctx.time().addTimeoutObject(this);
+
+ return old;
+ }
+
+ /** {@inheritDoc} */
@Override public boolean ownsLock(GridCacheEntryEx entry) throws GridCacheEntryRemovedException {
return entry.detached() || super.ownsLock(entry);
}
@@ -550,23 +578,28 @@ public class GridNearTxLocal extends GridDhtTxLocalAdapter implements GridTimeou
opCtx != null && opCtx.recovery(),
dataCenterId);
- if (pessimistic()) {
- assert loadFut == null || loadFut.isDone() : loadFut;
+ try {
+ loadFut.get();
+ }
+ catch (IgniteCheckedException e) {
+ return new GridFinishedFuture(e);
+ }
+
+ long timeout = remainingTime();
+
+ if (timeout == -1)
+ return new GridFinishedFuture<>(timeoutException());
- if (loadFut != null)
- loadFut.get();
+ if (isRollbackOnly())
+ return new GridFinishedFuture<>(rollbackException());
+ if (pessimistic()) {
final Collection<KeyCacheObject> enlisted = Collections.singleton(cacheKey);
if (log.isDebugEnabled())
log.debug("Before acquiring transaction lock for put on key: " + enlisted);
- long timeout = remainingTime();
-
- if (timeout == -1)
- return new GridFinishedFuture<>(timeoutException());
-
- IgniteInternalFuture<Boolean> fut = cacheCtx.cache().txLockAsync(enlisted,
+ IgniteInternalFuture<Boolean>fut = cacheCtx.cache().txLockAsync(enlisted,
timeout,
this,
/*read*/entryProcessor != null, // Needed to force load from store.
@@ -726,25 +759,24 @@ public class GridNearTxLocal extends GridDhtTxLocalAdapter implements GridTimeou
opCtx != null && opCtx.recovery(),
dataCenterId);
- if (pessimistic()) {
- assert loadFut == null || loadFut.isDone() : loadFut;
+ try {
+ loadFut.get();
+ }
+ catch (IgniteCheckedException e) {
+ return new GridFinishedFuture(e);
+ }
- if (loadFut != null) {
- try {
- loadFut.get();
- }
- catch (IgniteCheckedException e) {
- return new GridFinishedFuture(e);
- }
- }
+ long timeout = remainingTime();
- if (log.isDebugEnabled())
- log.debug("Before acquiring transaction lock for put on keys: " + enlisted);
+ if (timeout == -1)
+ return new GridFinishedFuture<>(timeoutException());
- long timeout = remainingTime();
+ if (isRollbackOnly())
+ return new GridFinishedFuture<>(rollbackException());
- if (timeout == -1)
- return new GridFinishedFuture<>(timeoutException());
+ if (pessimistic()) {
+ if (log.isDebugEnabled())
+ log.debug("Before acquiring transaction lock for put on keys: " + enlisted);
IgniteInternalFuture<Boolean> fut = cacheCtx.cache().txLockAsync(enlisted,
timeout,
@@ -842,7 +874,12 @@ public class GridNearTxLocal extends GridDhtTxLocalAdapter implements GridTimeou
boolean keepBinary,
boolean recovery,
Byte dataCenterId) {
+ GridFutureAdapter<Void> enlistFut = new GridFutureAdapter<>();
+
try {
+ if (!updateLockFuture(null, enlistFut))
+ return finishFuture(enlistFut, timedOut() ? timeoutException() : rollbackException(), false);
+
addActiveCache(cacheCtx, recovery);
final boolean hasFilters = !F.isEmptyOrNulls(filter) && !F.isAlwaysTrue(filter);
@@ -883,7 +920,7 @@ public class GridNearTxLocal extends GridDhtTxLocalAdapter implements GridTimeou
if (topVer == null)
topVer = entryTopVer;
- return loadMissing(cacheCtx,
+ IgniteInternalFuture<Void> loadFut = loadMissing(cacheCtx,
topVer != null ? topVer : topologyVersion(),
Collections.singleton(cacheKey),
filter,
@@ -896,12 +933,29 @@ public class GridNearTxLocal extends GridDhtTxLocalAdapter implements GridTimeou
keepBinary,
recovery,
expiryPlc);
+
+ loadFut.listen(new IgniteInClosure<IgniteInternalFuture<Void>>() {
+ @Override public void apply(IgniteInternalFuture<Void> fut) {
+ try {
+ fut.get();
+
+ finishFuture(enlistFut, null, true);
+ }
+ catch (IgniteCheckedException e) {
+ finishFuture(enlistFut, e, true);
+ }
+ }
+ });
+
+ return enlistFut;
}
- return new GridFinishedFuture<>();
+ finishFuture(enlistFut, null, true);
+
+ return enlistFut;
}
catch (IgniteCheckedException e) {
- return new GridFinishedFuture<>(e);
+ return finishFuture(enlistFut, e, true);
}
}
@@ -925,7 +979,7 @@ public class GridNearTxLocal extends GridDhtTxLocalAdapter implements GridTimeou
* @param singleRmv {@code True} for single key remove operation ({@link Cache#remove(Object)}.
* @param keepBinary Keep binary flag.
* @param dataCenterId Optional data center ID.
- * @return Future for missing values loading.
+ * @return Future for enlisting writes.
*/
private <K, V> IgniteInternalFuture<Void> enlistWrite(
final GridCacheContext cacheCtx,
@@ -950,11 +1004,16 @@ public class GridNearTxLocal extends GridDhtTxLocalAdapter implements GridTimeou
) {
assert retval || invokeMap == null;
+ GridFutureAdapter<Void> enlistFut = new GridFutureAdapter<>();
+
+ if (!updateLockFuture(null, enlistFut))
+ return finishFuture(enlistFut, timedOut() ? timeoutException() : rollbackException(), false);
+
try {
addActiveCache(cacheCtx, recovery);
}
catch (IgniteCheckedException e) {
- return new GridFinishedFuture<>(e);
+ return finishFuture(enlistFut, e, false);
}
boolean rmv = lookup == null && invokeMap == null;
@@ -971,6 +1030,9 @@ public class GridNearTxLocal extends GridDhtTxLocalAdapter implements GridTimeou
Set<KeyCacheObject> missedForLoad = null;
for (Object key : keys) {
+ if (isRollbackOnly())
+ return finishFuture(enlistFut, timedOut() ? timeoutException() : rollbackException(), false);
+
if (key == null) {
rollback();
@@ -1056,7 +1118,7 @@ public class GridNearTxLocal extends GridDhtTxLocalAdapter implements GridTimeou
if (topVer == null)
topVer = entryTopVer;
- return loadMissing(cacheCtx,
+ IgniteInternalFuture<Void> loadFut = loadMissing(cacheCtx,
topVer != null ? topVer : topologyVersion(),
missedForLoad,
filter,
@@ -1069,12 +1131,27 @@ public class GridNearTxLocal extends GridDhtTxLocalAdapter implements GridTimeou
keepBinary,
recovery,
expiryPlc);
+
+ loadFut.listen(new IgniteInClosure<IgniteInternalFuture<Void>>() {
+ @Override public void apply(IgniteInternalFuture<Void> fut) {
+ try {
+ fut.get();
+
+ finishFuture(enlistFut, null, true);
+ }
+ catch (IgniteCheckedException e) {
+ finishFuture(enlistFut, e, true);
+ }
+ }
+ });
+
+ return enlistFut;
}
- return new GridFinishedFuture<>();
+ return finishFuture(enlistFut, null, true);
}
catch (IgniteCheckedException e) {
- return new GridFinishedFuture<>(e);
+ return finishFuture(enlistFut, e, true);
}
}
@@ -1537,6 +1614,21 @@ public class GridNearTxLocal extends GridDhtTxLocalAdapter implements GridTimeou
dataCenterId
);
+ try {
+ loadFut.get();
+ }
+ catch (IgniteCheckedException e) {
+ return new GridFinishedFuture(e);
+ }
+
+ long timeout = remainingTime();
+
+ if (timeout == -1)
+ return new GridFinishedFuture<>(timeoutException());
+
+ if (isRollbackOnly())
+ return new GridFinishedFuture<>(rollbackException());
+
if (log.isDebugEnabled())
log.debug("Remove keys: " + enlisted);
@@ -1544,25 +1636,9 @@ public class GridNearTxLocal extends GridDhtTxLocalAdapter implements GridTimeou
// Otherwise, during rollback we will not know whether locks need
// to be rolled back.
if (pessimistic()) {
- assert loadFut == null || loadFut.isDone() : loadFut;
-
- if (loadFut != null) {
- try {
- loadFut.get();
- }
- catch (IgniteCheckedException e) {
- return new GridFinishedFuture<>(e);
- }
- }
-
if (log.isDebugEnabled())
log.debug("Before acquiring transaction lock for remove on keys: " + enlisted);
- long timeout = remainingTime();
-
- if (timeout == -1)
- return new GridFinishedFuture<>(timeoutException());
-
IgniteInternalFuture<Boolean> fut = cacheCtx.cache().txLockAsync(enlisted,
timeout,
this,
@@ -1684,6 +1760,11 @@ public class GridNearTxLocal extends GridDhtTxLocalAdapter implements GridTimeou
try {
checkValid();
+ GridFutureAdapter<?> enlistFut = new GridFutureAdapter<>();
+
+ if (!updateLockFuture(null, enlistFut))
+ return new GridFinishedFuture<>(timedOut() ? timeoutException() : rollbackException());
+
final Map<K, V> retMap = new GridLeanMap<>(keysCnt);
final Map<KeyCacheObject, GridCacheVersion> missed = new GridLeanMap<>(pessimistic() ? keysCnt : 0);
@@ -1692,19 +1773,32 @@ public class GridNearTxLocal extends GridDhtTxLocalAdapter implements GridTimeou
ExpiryPolicy expiryPlc = opCtx != null ? opCtx.expiry() : null;
- final Collection<KeyCacheObject> lockKeys = enlistRead(cacheCtx,
- entryTopVer,
- keys,
- expiryPlc,
- retMap,
- missed,
- keysCnt,
- deserializeBinary,
- skipVals,
- keepCacheObjects,
- skipStore,
- recovery,
- needVer);
+ final Collection<KeyCacheObject> lockKeys;
+
+ try {
+ lockKeys = enlistRead(cacheCtx,
+ entryTopVer,
+ keys,
+ expiryPlc,
+ retMap,
+ missed,
+ keysCnt,
+ deserializeBinary,
+ skipVals,
+ keepCacheObjects,
+ skipStore,
+ recovery,
+ needVer);
+ }
+ catch (IgniteCheckedException e) {
+ return new GridFinishedFuture<>(e);
+ }
+ finally {
+ finishFuture(enlistFut, null, true);
+ }
+
+ if (isRollbackOnly())
+ return new GridFinishedFuture<>(timedOut() ? timeoutException() : rollbackException());
if (single && missed.isEmpty())
return new GridFinishedFuture<>(retMap);
@@ -1996,6 +2090,9 @@ public class GridNearTxLocal extends GridDhtTxLocalAdapter implements GridTimeou
// Transactions that are pessimistic and not read-committed are covered
// outside of this loop.
for (KeyCacheObject key : keys) {
+ if (isRollbackOnly())
+ throw timedOut() ? timeoutException() : rollbackException();
+
if ((pessimistic() || needReadVer) && !readCommitted() && !skipVals)
addActiveCache(cacheCtx, recovery);
@@ -2383,13 +2480,6 @@ public class GridNearTxLocal extends GridDhtTxLocalAdapter implements GridTimeou
// with prepare response, if required.
assert loadFut.isDone();
- try {
- loadFut.get();
- }
- catch (IgniteCheckedException e) {
- return new GridFinishedFuture<>(e);
- }
-
return nonInterruptable(commitNearTxLocalAsync().chain(
new CX1<IgniteInternalFuture<IgniteInternalTx>, GridCacheReturn>() {
@Override public GridCacheReturn applyx(IgniteInternalFuture<IgniteInternalTx> txFut)
@@ -2805,7 +2895,7 @@ public class GridNearTxLocal extends GridDhtTxLocalAdapter implements GridTimeou
/**
* @return DHT map.
*/
- IgniteTxMappings mappings() {
+ public IgniteTxMappings mappings() {
return mappings;
}
@@ -2887,16 +2977,17 @@ public class GridNearTxLocal extends GridDhtTxLocalAdapter implements GridTimeou
* @throws IgniteCheckedException If the transaction is in an incorrect state, or timed out.
*/
public void resume() throws IgniteCheckedException {
- resume(true);
+ resume(true, Thread.currentThread().getId());
}
/**
* Resumes transaction (possibly in another thread) if it was previously suspended.
*
* @param checkTimeout Whether timeout should be checked.
+ * @param threadId Thread id to restore.
* @throws IgniteCheckedException If the transaction is in an incorrect state, or timed out.
*/
- private void resume(boolean checkTimeout) throws IgniteCheckedException {
+ private void resume(boolean checkTimeout, long threadId) throws IgniteCheckedException {
if (log.isDebugEnabled())
log.debug("Resume near local tx: " + this);
@@ -2906,7 +2997,7 @@ public class GridNearTxLocal extends GridDhtTxLocalAdapter implements GridTimeou
synchronized (this) {
checkValid(checkTimeout);
- cctx.tm().resumeTx(this);
+ cctx.tm().resumeTx(this, threadId);
}
}
@@ -3062,7 +3153,8 @@ public class GridNearTxLocal extends GridDhtTxLocalAdapter implements GridTimeou
TransactionState state = state();
if (state != COMMITTING && state != COMMITTED)
- throw new IgniteCheckedException("Invalid transaction state for commit [state=" + state() +
+ throw isRollbackOnly() ? timedOut() ? timeoutException() : rollbackException() :
+ new IgniteCheckedException("Invalid transaction state for commit [state=" + state() +
", tx=" + this + ']');
else {
if (log.isDebugEnabled())
@@ -3215,15 +3307,15 @@ public class GridNearTxLocal extends GridDhtTxLocalAdapter implements GridTimeou
NearTxFinishFuture fut = finishFut;
if (fut != null)
- return chainFinishFuture(fut, true);
+ return chainFinishFuture(fut, true, true, false);
if (fastFinish()) {
GridNearTxFastFinishFuture fut0;
- if (!FINISH_FUT_UPD.compareAndSet(this, null, fut0 = new GridNearTxFastFinishFuture(this, true, false)))
- return chainFinishFuture(finishFut, true);
+ if (!FINISH_FUT_UPD.compareAndSet(this, null, fut0 = new GridNearTxFastFinishFuture(this, true)))
+ return chainFinishFuture(finishFut, true, true, false);
- fut0.finish();
+ fut0.finish(false);
return fut0;
}
@@ -3231,7 +3323,7 @@ public class GridNearTxLocal extends GridDhtTxLocalAdapter implements GridTimeou
final GridNearTxFinishFuture fut0;
if (!FINISH_FUT_UPD.compareAndSet(this, null, fut0 = new GridNearTxFinishFuture<>(cctx, this, true)))
- return chainFinishFuture(finishFut, true);
+ return chainFinishFuture(finishFut, true, true, false);
cctx.mvcc().addFuture(fut0, fut0.futureId());
@@ -3243,14 +3335,12 @@ public class GridNearTxLocal extends GridDhtTxLocalAdapter implements GridTimeou
// Make sure that here are no exceptions.
prepareFut.get();
- TransactionState state = state();
-
- fut0.finish(state == PREPARED || state == COMMITTING || state == COMMITTED, true);
+ fut0.finish(true, true, false);
}
catch (Error | RuntimeException e) {
COMMIT_ERR_UPD.compareAndSet(GridNearTxLocal.this, null, e);
- fut0.finish(false, true);
+ fut0.finish(false, true, false);
throw e;
}
@@ -3258,7 +3348,7 @@ public class GridNearTxLocal extends GridDhtTxLocalAdapter implements GridTimeou
COMMIT_ERR_UPD.compareAndSet(GridNearTxLocal.this, null, e);
if (!(e instanceof NodeStoppingException))
- fut0.finish(false, true);
+ fut0.finish(false, true, true);
}
}
});
@@ -3282,14 +3372,20 @@ public class GridNearTxLocal extends GridDhtTxLocalAdapter implements GridTimeou
* @return Rollback future.
*/
public IgniteInternalFuture<IgniteInternalTx> rollbackNearTxLocalAsync() {
- return rollbackNearTxLocalAsync(false);
+ return rollbackNearTxLocalAsync(true, false);
}
/**
- * @param onTimeout {@code True} if rolled back asynchronously on timeout.
+ * @param clearThreadMap {@code True} if needed to clear thread map.
+ * @param onTimeout {@code True} if called from timeout handler.
+ * Note: For async rollbacks (from timeouts or another thread) should not clear thread map
+ * since thread started tx still should be able to see this tx to prevent subsequent operations.
+ *
* @return Rollback future.
*/
- public IgniteInternalFuture<IgniteInternalTx> rollbackNearTxLocalAsync(final boolean onTimeout) {
+ @SuppressWarnings("ThrowableResultOfMethodCallIgnored")
+ public IgniteInternalFuture<IgniteInternalTx> rollbackNearTxLocalAsync(final boolean clearThreadMap,
+ final boolean onTimeout) {
if (log.isDebugEnabled())
log.debug("Rolling back near tx: " + this);
@@ -3299,15 +3395,16 @@ public class GridNearTxLocal extends GridDhtTxLocalAdapter implements GridTimeou
NearTxFinishFuture fut = finishFut;
if (fut != null)
- return chainFinishFuture(finishFut, false, !onTimeout);
+ return chainFinishFuture(finishFut, false, clearThreadMap, onTimeout);
- if (fastFinish()) {
+ // Enable fast finish only from tx thread.
+ if (clearThreadMap && fastFinish()) {
GridNearTxFastFinishFuture fut0;
- if (!FINISH_FUT_UPD.compareAndSet(this, null, fut0 = new GridNearTxFastFinishFuture(this, false, onTimeout)))
- return chainFinishFuture(finishFut, false, !onTimeout);
+ if (!FINISH_FUT_UPD.compareAndSet(this, null, fut0 = new GridNearTxFastFinishFuture(this, false)))
+ return chainFinishFuture(finishFut, false, true, onTimeout);
- fut0.finish();
+ fut0.finish(true);
return fut0;
}
@@ -3315,7 +3412,7 @@ public class GridNearTxLocal extends GridDhtTxLocalAdapter implements GridTimeou
final GridNearTxFinishFuture fut0;
if (!FINISH_FUT_UPD.compareAndSet(this, null, fut0 = new GridNearTxFinishFuture<>(cctx, this, false)))
- return chainFinishFuture(finishFut, false, !onTimeout);
+ return chainFinishFuture(finishFut, false, clearThreadMap, onTimeout);
cctx.mvcc().addFuture(fut0, fut0.futureId());
@@ -3332,9 +3429,9 @@ public class GridNearTxLocal extends GridDhtTxLocalAdapter implements GridTimeou
log.debug("Got optimistic tx failure [tx=" + this + ", err=" + e + ']');
}
- fut0.finish(false, !onTimeout);
+ fut0.finish(false, clearThreadMap, onTimeout);
}
- else if (!onTimeout) {
+ else {
prepFut.listen(new CI1<IgniteInternalFuture<?>>() {
@Override public void apply(IgniteInternalFuture<?> f) {
try {
@@ -3346,11 +3443,10 @@ public class GridNearTxLocal extends GridDhtTxLocalAdapter implements GridTimeou
log.debug("Got optimistic tx failure [tx=" + this + ", err=" + e + ']');
}
- fut0.finish(false, true);
+ fut0.finish(false, clearThreadMap, onTimeout);
}
});
- } else
- fut0.finish(false, false);
+ }
return fut0;
}
@@ -3360,17 +3456,14 @@ public class GridNearTxLocal extends GridDhtTxLocalAdapter implements GridTimeou
return rollbackNearTxLocalAsync();
}
- /** */
- private IgniteInternalFuture<IgniteInternalTx> chainFinishFuture(final NearTxFinishFuture fut, final boolean commit) {
- return chainFinishFuture(fut, commit, true);
- }
-
/**
* @param fut Already started finish future.
* @param commit Commit flag.
+ * @param clearThreadMap Clear thread map.
* @return Finish future.
*/
- private IgniteInternalFuture<IgniteInternalTx> chainFinishFuture(final NearTxFinishFuture fut, final boolean commit, final boolean clearThreadMap) {
+ private IgniteInternalFuture<IgniteInternalTx> chainFinishFuture(final NearTxFinishFuture fut, final boolean commit,
+ final boolean clearThreadMap, final boolean onTimeout) {
assert fut != null;
if (fut.commit() != commit) {
@@ -3394,9 +3487,23 @@ public class GridNearTxLocal extends GridDhtTxLocalAdapter implements GridTimeou
if (!cctx.mvcc().addFuture(rollbackFut, rollbackFut.futureId()))
return;
- rollbackFut.finish(false, clearThreadMap);
+ rollbackFut.finish(false, clearThreadMap, onTimeout);
}
}
+ else {
+ finishFut.listen(new IgniteInClosure<IgniteInternalFuture<IgniteInternalTx>>() {
+ @Override public void apply(IgniteInternalFuture<IgniteInternalTx> fut) {
+ try {
+ fut.get();
+
+ rollbackFut.markInitialized();
+ }
+ catch (IgniteCheckedException e) {
+ rollbackFut.onDone(e);
+ }
+ }
+ });
+ }
}
});
@@ -3411,7 +3518,7 @@ public class GridNearTxLocal extends GridDhtTxLocalAdapter implements GridTimeou
fut0.onDone(new IgniteTxTimeoutCheckedException("Failed to commit transaction, " +
"transaction is concurrently rolled back on timeout: " + tx));
else
- fut0.onDone(new IgniteCheckedException("Failed to commit transaction, " +
+ fut0.onDone(new IgniteTxRollbackCheckedException("Failed to commit transaction, " +
"transaction is concurrently rolled back: " + tx));
}
});
@@ -3442,13 +3549,11 @@ public class GridNearTxLocal extends GridDhtTxLocalAdapter implements GridTimeou
if (state() != PREPARING) {
if (timeout == -1)
- return new GridFinishedFuture<>(
- new IgniteTxTimeoutCheckedException("Transaction timed out: " + this));
+ return new GridFinishedFuture<>(timeoutException());
setRollbackOnly();
- return new GridFinishedFuture<>(
- new IgniteCheckedException("Invalid transaction state for prepare [state=" + state() + ", tx=" + this + ']'));
+ return new GridFinishedFuture<>(rollbackException());
}
if (timeout == -1)
@@ -3483,19 +3588,6 @@ public class GridNearTxLocal extends GridDhtTxLocalAdapter implements GridTimeou
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);
@@ -3788,17 +3880,26 @@ public class GridNearTxLocal extends GridDhtTxLocalAdapter implements GridTimeou
/** {@inheritDoc} */
@Override public void close() throws IgniteCheckedException {
+ close(true);
+ }
+
+ /**
+ * @param clearThreadMap Clear thread map.
+ */
+ public void close(boolean clearThreadMap) throws IgniteCheckedException {
TransactionState state = state();
try {
if (state == COMMITTED || state == ROLLED_BACK)
return;
+ boolean rmv = false;
+
if (trackTimeout)
- removeTimeoutHandler();
+ rmv = removeTimeoutHandler();
- if (state != ROLLING_BACK && state != COMMITTING)
- rollback();
+ if (state != COMMITTING && state != ROLLING_BACK && (!trackTimeout || rmv))
+ rollbackNearTxLocalAsync(clearThreadMap, false).get();
synchronized (this) {
try {
@@ -3815,10 +3916,7 @@ public class GridNearTxLocal extends GridDhtTxLocalAdapter implements GridTimeou
}
}
finally {
- // It is possible tx was rolled back asynchronously on timeout and thread map is not cleared yet.
- boolean cleanup = state == ROLLED_BACK && timedOut();
-
- if (cleanup)
+ if (clearThreadMap)
cctx.tm().clearThreadMap(this);
if (accessMap != null) {
@@ -3891,6 +3989,16 @@ public class GridNearTxLocal extends GridDhtTxLocalAdapter implements GridTimeou
}
/**
+ * @return Public API proxy.
+ */
+ public TransactionProxy rollbackOnlyProxy() {
+ if (rollbackOnlyProxy == null)
+ rollbackOnlyProxy = new TransactionProxyRollbackOnlyImpl<>(this, cctx, false);
+
+ return rollbackOnlyProxy;
+ }
+
+ /**
* @param cacheCtx Cache context.
* @param topVer Topology version.
* @param map Return map.
@@ -3954,14 +4062,6 @@ public class GridNearTxLocal extends GridDhtTxLocalAdapter implements GridTimeou
expiryPlc,
new GridInClosure3<KeyCacheObject, Object, GridCacheVersion>() {
@Override public void apply(KeyCacheObject key, Object val, GridCacheVersion loadVer) {
- if (isRollbackOnly()) {
- if (log.isDebugEnabled())
- log.debug("Ignoring loaded value for read because transaction was rolled back: " +
- GridNearTxLocal.this);
-
- return;
- }
-
CacheObject cacheVal = cacheCtx.toCacheObject(val);
CacheObject visibleVal = cacheVal;
@@ -4163,11 +4263,18 @@ public class GridNearTxLocal extends GridDhtTxLocalAdapter implements GridTimeou
return startTime() + timeout();
}
+ /**
+ * @return Tx label.
+ */
+ public String label() {
+ return lb;
+ }
+
/** {@inheritDoc} */
@Override public void onTimeout() {
if (state() == SUSPENDED) {
try {
- resume(false);
+ resume(false, threadId());
}
catch (IgniteCheckedException e) {
log.warning("Error resuming suspended transaction on timeout: " + this, e);
@@ -4185,9 +4292,10 @@ public class GridNearTxLocal extends GridDhtTxLocalAdapter implements GridTimeou
@Override public void run() {
// Note: if rollback asynchronously on timeout should not clear thread map
// since thread started tx still should be able to see this tx.
- rollbackNearTxLocalAsync(true);
+ rollbackNearTxLocalAsync(false, true);
- U.warn(log, "Transaction was rolled back because the timeout is reached: " + GridNearTxLocal.this);
+ U.warn(log, "The transaction was forcibly rolled back because a timeout is reached: " +
+ CU.txString(GridNearTxLocal.this));
}
});
}
http://git-wip-us.apache.org/repos/asf/ignite/blob/2b5d2fc5/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/local/GridLocalLockFuture.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/local/GridLocalLockFuture.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/local/GridLocalLockFuture.java
index 93d82c9..18a8431 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/local/GridLocalLockFuture.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/local/GridLocalLockFuture.java
@@ -36,20 +36,21 @@ import org.apache.ignite.internal.processors.cache.GridCacheFutureAdapter;
import org.apache.ignite.internal.processors.cache.GridCacheMvccCandidate;
import org.apache.ignite.internal.processors.cache.GridCacheVersionedFuture;
import org.apache.ignite.internal.processors.cache.KeyCacheObject;
+import org.apache.ignite.internal.processors.cache.distributed.near.GridNearTxLocal;
import org.apache.ignite.internal.processors.cache.transactions.IgniteTxKey;
import org.apache.ignite.internal.processors.cache.transactions.IgniteTxLocalEx;
import org.apache.ignite.internal.processors.cache.transactions.TxDeadlock;
import org.apache.ignite.internal.processors.cache.version.GridCacheVersion;
import org.apache.ignite.internal.processors.timeout.GridTimeoutObjectAdapter;
import org.apache.ignite.internal.transactions.IgniteTxTimeoutCheckedException;
+import org.apache.ignite.internal.util.typedef.internal.CU;
+import org.apache.ignite.transactions.TransactionDeadlockException;
import org.apache.ignite.internal.util.tostring.GridToStringExclude;
import org.apache.ignite.internal.util.tostring.GridToStringInclude;
-import org.apache.ignite.internal.util.typedef.F;
import org.apache.ignite.internal.util.typedef.internal.S;
import org.apache.ignite.internal.util.typedef.internal.U;
import org.apache.ignite.lang.IgniteInClosure;
import org.apache.ignite.lang.IgniteUuid;
-import org.apache.ignite.transactions.TransactionDeadlockException;
import org.jetbrains.annotations.Nullable;
/**
@@ -155,6 +156,12 @@ public final class GridLocalLockFuture<K, V> extends GridCacheFutureAdapter<Bool
if (log == null)
log = U.logger(cctx.kernalContext(), logRef, GridLocalLockFuture.class);
+
+ if (tx != null && tx instanceof GridNearTxLocal && !((GridNearTxLocal)tx).updateLockFuture(null, this)) {
+ GridNearTxLocal tx0 = (GridNearTxLocal)tx;
+
+ onError(tx0.timedOut() ? tx0.timeoutException() : tx0.rollbackException());
+ }
}
/**
@@ -457,6 +464,9 @@ public final class GridLocalLockFuture<K, V> extends GridCacheFutureAdapter<Bool
if (!success)
undoLocks();
+ if (tx != null && success)
+ ((GridNearTxLocal)tx).clearLockFuture(this);
+
if (onDone(success, err)) {
if (log.isDebugEnabled())
log.debug("Completing future: " + this);
@@ -490,47 +500,51 @@ public final class GridLocalLockFuture<K, V> extends GridCacheFutureAdapter<Bool
if (log.isDebugEnabled())
log.debug("Timed out waiting for lock response: " + this);
- if (inTx() && cctx.tm().deadlockDetectionEnabled()) {
- Set<IgniteTxKey> keys = new HashSet<>();
+ if (inTx()) {
+ if (cctx.tm().deadlockDetectionEnabled()) {
+ Set<IgniteTxKey> keys = new HashSet<>();
- List<GridLocalCacheEntry> entries = entries();
+ List<GridLocalCacheEntry> entries = entries();
- for (int i = 0; i < entries.size(); i++) {
- GridLocalCacheEntry e = entries.get(i);
+ for (int i = 0; i < entries.size(); i++) {
+ GridLocalCacheEntry e = entries.get(i);
- List<GridCacheMvccCandidate> mvcc = e.mvccAllLocal();
+ List<GridCacheMvccCandidate> mvcc = e.mvccAllLocal();
- if (mvcc == null)
- continue;
+ if (mvcc == null)
+ continue;
- GridCacheMvccCandidate cand = mvcc.get(0);
+ GridCacheMvccCandidate cand = mvcc.get(0);
- if (cand.owner() && cand.tx() && !cand.version().equals(tx.xidVersion()))
- keys.add(e.txKey());
- }
+ if (cand.owner() && cand.tx() && !cand.version().equals(tx.xidVersion()))
+ keys.add(e.txKey());
+ }
- IgniteInternalFuture<TxDeadlock> fut = cctx.tm().detectDeadlock(tx, keys);
+ IgniteInternalFuture<TxDeadlock> fut = cctx.tm().detectDeadlock(tx, keys);
- fut.listen(new IgniteInClosure<IgniteInternalFuture<TxDeadlock>>() {
- @Override public void apply(IgniteInternalFuture<TxDeadlock> fut) {
- try {
- TxDeadlock deadlock = fut.get();
+ fut.listen(new IgniteInClosure<IgniteInternalFuture<TxDeadlock>>() {
+ @Override public void apply(IgniteInternalFuture<TxDeadlock> fut) {
+ try {
+ TxDeadlock deadlock = fut.get();
- if (deadlock != null)
- ERR_UPD.compareAndSet(GridLocalLockFuture.this, null,
- new IgniteTxTimeoutCheckedException("Failed to acquire lock within provided timeout for " +
- "transaction [timeout=" + tx.timeout() + ", tx=" + tx + ']',
- new TransactionDeadlockException(deadlock.toString(cctx.shared()))));
- }
- catch (IgniteCheckedException e) {
- U.warn(log, "Failed to detect deadlock.", e);
+ err = new IgniteTxTimeoutCheckedException("Failed to acquire lock within provided " +
+ "timeout for transaction [timeout=" + tx.timeout() + ", tx=" + CU.txString(tx) + ']',
+ deadlock != null ? new TransactionDeadlockException(deadlock.toString(cctx.shared())) :
+ null);
+ }
+ catch (IgniteCheckedException e) {
+ err = e;
- ERR_UPD.compareAndSet(GridLocalLockFuture.this, null, e);
- }
+ U.warn(log, "Failed to detect deadlock.", e);
+ }
- onComplete(false);
- }
- });
+ onComplete(false);
+ }
+ });
+ }
+ else
+ err = new IgniteTxTimeoutCheckedException("Failed to acquire lock within provided " +
+ "timeout for transaction [timeout=" + tx.timeout() + ", tx=" + CU.txString(tx) + ']');
}
else
onComplete(false);
@@ -541,4 +555,4 @@ public final class GridLocalLockFuture<K, V> extends GridCacheFutureAdapter<Bool
return S.toString(LockTimeoutObject.class, this);
}
}
-}
\ No newline at end of file
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/2b5d2fc5/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/GridCacheDatabaseSharedManager.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/GridCacheDatabaseSharedManager.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/GridCacheDatabaseSharedManager.java
index e20abd6..1122e9b 100755
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/GridCacheDatabaseSharedManager.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/GridCacheDatabaseSharedManager.java
@@ -2408,7 +2408,6 @@ public class GridCacheDatabaseSharedManager extends IgniteCacheDatabaseSharedMan
if (stateId == GridDhtPartitionState.OWNING.ordinal()
|| (stateId == GridDhtPartitionState.MOVING.ordinal()
-
&& part.initialUpdateCounter() < restore.get2())) {
part.initialUpdateCounter(restore.get2());
http://git-wip-us.apache.org/repos/asf/ignite/blob/2b5d2fc5/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/store/GridCacheStoreManagerAdapter.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/store/GridCacheStoreManagerAdapter.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/store/GridCacheStoreManagerAdapter.java
index 6c5922a..64a052d 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/store/GridCacheStoreManagerAdapter.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/store/GridCacheStoreManagerAdapter.java
@@ -1431,6 +1431,11 @@ public abstract class GridCacheStoreManagerAdapter extends GridCacheManagerAdapt
}
/** {@inheritDoc} */
+ @Nullable @Override public String label() {
+ return null;
+ }
+
+ /** {@inheritDoc} */
@Override public long timeout() {
return tx.timeout();
}
http://git-wip-us.apache.org/repos/asf/ignite/blob/2b5d2fc5/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTransactionsImpl.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTransactionsImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTransactionsImpl.java
index 12f655a..25ba849 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTransactionsImpl.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTransactionsImpl.java
@@ -17,13 +17,18 @@
package org.apache.ignite.internal.processors.cache.transactions;
+import java.util.Collection;
+import org.apache.ignite.IgniteTransactions;
import org.apache.ignite.configuration.TransactionConfiguration;
import org.apache.ignite.internal.IgniteTransactionsEx;
import org.apache.ignite.internal.processors.cache.GridCacheContext;
import org.apache.ignite.internal.processors.cache.GridCacheSharedContext;
import org.apache.ignite.internal.processors.cache.distributed.near.GridNearTxLocal;
+import org.apache.ignite.internal.util.typedef.F;
import org.apache.ignite.internal.util.typedef.internal.A;
import org.apache.ignite.internal.util.typedef.internal.CU;
+import org.apache.ignite.lang.IgniteClosure;
+import org.apache.ignite.lang.IgnitePredicate;
import org.apache.ignite.transactions.Transaction;
import org.apache.ignite.transactions.TransactionConcurrency;
import org.apache.ignite.transactions.TransactionIsolation;
@@ -38,11 +43,15 @@ public class IgniteTransactionsImpl<K, V> implements IgniteTransactionsEx {
/** Cache shared context. */
private GridCacheSharedContext<K, V> cctx;
+ /** Label. */
+ private String lb;
+
/**
* @param cctx Cache shared context.
*/
- public IgniteTransactionsImpl(GridCacheSharedContext<K, V> cctx) {
+ public IgniteTransactionsImpl(GridCacheSharedContext<K, V> cctx, @Nullable String lb) {
this.cctx = cctx;
+ this.lb = lb;
}
/** {@inheritDoc} */
@@ -166,7 +175,8 @@ public class IgniteTransactionsImpl<K, V> implements IgniteTransactionsEx {
isolation,
timeout,
true,
- txSize
+ txSize,
+ lb
);
assert tx != null;
@@ -195,6 +205,26 @@ public class IgniteTransactionsImpl<K, V> implements IgniteTransactionsEx {
cctx.resetTxMetrics();
}
+ /** {@inheritDoc} */
+ @Override public Collection<Transaction> localActiveTransactions() {
+ return F.viewReadOnly(cctx.tm().activeTransactions(), new IgniteClosure<IgniteInternalTx, Transaction>() {
+ @Override public Transaction apply(IgniteInternalTx tx) {
+ return ((GridNearTxLocal)tx).rollbackOnlyProxy();
+ }
+ }, new IgnitePredicate<IgniteInternalTx>() {
+ @Override public boolean apply(IgniteInternalTx tx) {
+ return tx.local() && tx.near();
+ }
+ });
+ }
+
+ /** {@inheritDoc} */
+ @Override public IgniteTransactions withLabel(String lb) {
+ A.notNull(lb, "label should not be empty.");
+
+ return new IgniteTransactionsImpl<>(cctx, lb);
+ }
+
/**
* @param ctx Cache context.
*/
@@ -202,4 +232,4 @@ public class IgniteTransactionsImpl<K, V> implements IgniteTransactionsEx {
if (!ctx.transactional())
throw new TransactionException("Failed to start transaction on non-transactional cache: " + ctx.name());
}
-}
\ No newline at end of file
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/2b5d2fc5/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTxAdapter.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTxAdapter.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTxAdapter.java
index 945ef48..3cf1146 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTxAdapter.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTxAdapter.java
@@ -65,6 +65,7 @@ import org.apache.ignite.internal.processors.cache.version.GridCacheLazyPlainVer
import org.apache.ignite.internal.processors.cache.version.GridCacheVersion;
import org.apache.ignite.internal.processors.cache.version.GridCacheVersionConflictContext;
import org.apache.ignite.internal.processors.cache.version.GridCacheVersionedEntryEx;
+import org.apache.ignite.internal.transactions.IgniteTxRollbackCheckedException;
import org.apache.ignite.internal.processors.cluster.BaselineTopology;
import org.apache.ignite.internal.transactions.IgniteTxTimeoutCheckedException;
import org.apache.ignite.internal.util.GridSetWrapper;
@@ -706,7 +707,15 @@ public abstract class IgniteTxAdapter extends GridMetadataAwareAdapter implement
*/
public final IgniteCheckedException timeoutException() {
return new IgniteTxTimeoutCheckedException("Failed to acquire lock within provided timeout " +
- "for transaction [timeout=" + timeout() + ", tx=" + this + ']');
+ "for transaction [timeout=" + timeout() + ", tx=" + CU.txString(this) + ']');
+ }
+
+ /**
+ * @return Rollback exception.
+ */
+ public final IgniteCheckedException rollbackException() {
+ return new IgniteTxRollbackCheckedException("Failed to finish transaction because it has been rolled back " +
+ "[timeout=" + timeout() + ", tx=" + CU.txString(this) + ']');
}
/** {@inheritDoc} */
@@ -993,9 +1002,9 @@ public abstract class IgniteTxAdapter extends GridMetadataAwareAdapter implement
*
* @param state State to set.
* @param timedOut Timeout flag.
+ *
* @return {@code True} if state changed.
*/
- @SuppressWarnings({"TooBroadScope"})
protected final boolean state(TransactionState state, boolean timedOut) {
boolean valid = false;
@@ -1058,7 +1067,7 @@ public abstract class IgniteTxAdapter extends GridMetadataAwareAdapter implement
}
case MARKED_ROLLBACK: {
- valid = prev == ACTIVE || prev == PREPARING || prev == PREPARED || prev == SUSPENDED;
+ valid = prev == ACTIVE || prev == PREPARING || prev == PREPARED || prev == SUSPENDED;
break;
}
@@ -1099,11 +1108,9 @@ public abstract class IgniteTxAdapter extends GridMetadataAwareAdapter implement
if (state != ACTIVE && state != SUSPENDED)
seal();
- if (cctx.wal() != null && cctx.tm().logTxRecords()) {
+ if (cctx.wal() != null && cctx.tm().logTxRecords() && txNodes != null) {
// Log tx state change to WAL.
if (state == PREPARED || state == COMMITTED || state == ROLLED_BACK) {
- assert txNodes != null || state == ROLLED_BACK : "txNodes=" + txNodes + " state=" + state;
-
BaselineTopology baselineTop = cctx.kernalContext().state().clusterState().baselineTopology();
Map<Short, Collection<Short>> participatingNodes = consistentIdMapper
http://git-wip-us.apache.org/repos/asf/ignite/blob/2b5d2fc5/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTxHandler.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTxHandler.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTxHandler.java
index 38c877b..44482ab 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTxHandler.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTxHandler.java
@@ -256,9 +256,6 @@ public class IgniteTxHandler {
IgniteInternalFuture<GridNearTxPrepareResponse> fut = locTx.prepareAsyncLocal(req);
- if (locTx.isRollbackOnly())
- locTx.rollbackNearTxLocalAsync();
-
return fut.chain(new C1<IgniteInternalFuture<GridNearTxPrepareResponse>, GridNearTxPrepareResponse>() {
@Override public GridNearTxPrepareResponse apply(IgniteInternalFuture<GridNearTxPrepareResponse> f) {
try {
@@ -885,7 +882,7 @@ public class IgniteTxHandler {
req.threadId(),
req.futureId(),
req.miniId(),
- new IgniteCheckedException("Transaction has been already completed."));
+ new IgniteTxRollbackCheckedException("Transaction has been already completed or not started yet."));
try {
ctx.io().send(nodeId, res, req.policy());
@@ -1698,6 +1695,8 @@ public class IgniteTxHandler {
res.invalidPartitionsByCacheId(tx.invalidPartitions());
if (tx.empty() && req.last()) {
+ tx.skipCompletedVersions(req.skipCompletedVersion());
+
tx.rollbackRemoteTx();
return null;
http://git-wip-us.apache.org/repos/asf/ignite/blob/2b5d2fc5/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTxLocalAdapter.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTxLocalAdapter.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTxLocalAdapter.java
index 7a7f65f..54b7ae2 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTxLocalAdapter.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTxLocalAdapter.java
@@ -18,7 +18,6 @@
package org.apache.ignite.internal.processors.cache.transactions;
import java.io.Externalizable;
-import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
@@ -963,7 +962,7 @@ public abstract class IgniteTxLocalAdapter extends IgniteTxAdapter implements Ig
if (commit)
cctx.tm().commitTx(this);
else
- cctx.tm().rollbackTx(this, clearThreadMap);
+ cctx.tm().rollbackTx(this, clearThreadMap, false);
}
state(commit ? COMMITTED : ROLLED_BACK);
@@ -1028,7 +1027,7 @@ public abstract class IgniteTxLocalAdapter extends IgniteTxAdapter implements Ig
}
if (DONE_FLAG_UPD.compareAndSet(this, 0, 1)) {
- cctx.tm().rollbackTx(this, clearThreadMap);
+ cctx.tm().rollbackTx(this, clearThreadMap, false);
if (!internal()) {
Collection<CacheStoreManager> stores = txState.stores(cctx);
@@ -1310,7 +1309,7 @@ public abstract class IgniteTxLocalAdapter extends IgniteTxAdapter implements Ig
if (isRollbackOnly()) {
if (remainingTime() == -1)
- throw new IgniteTxTimeoutCheckedException("Cache transaction timed out: " + this);
+ throw new IgniteTxTimeoutCheckedException("Cache transaction timed out: " + CU.txString(this));
TransactionState state = state();
@@ -1322,7 +1321,7 @@ public abstract class IgniteTxLocalAdapter extends IgniteTxAdapter implements Ig
throw new IgniteTxHeuristicCheckedException("Cache transaction is in unknown state " +
"(remote transactions will be invalidated): " + this);
- throw new IgniteCheckedException("Cache transaction marked as rollback-only: " + this);
+ throw rollbackException();
}
}
@@ -1367,12 +1366,6 @@ public abstract class IgniteTxLocalAdapter extends IgniteTxAdapter implements Ig
checkInternal(key);
- TransactionState state = state();
-
- assert state == TransactionState.ACTIVE || remainingTime() == -1 :
- "Invalid tx state for adding entry [op=" + op + ", val=" + val + ", entry=" + entry + ", filter=" +
- Arrays.toString(filter) + ", txCtx=" + cctx.tm().txContextVersion() + ", tx=" + this + ']';
-
IgniteTxEntry old = entry(key);
// Keep old filter if already have one (empty filter is always overridden).
@@ -1692,7 +1685,8 @@ public abstract class IgniteTxLocalAdapter extends IgniteTxAdapter implements Ig
final GridClosureException ex = new GridClosureException(
new IgniteTxTimeoutCheckedException("Failed to acquire lock within provided timeout " +
- "for transaction [timeout=" + timeout() + ", tx=" + this + ']', deadlockErr)
+ "for transaction [timeout=" + timeout() + ", tx=" + CU.txString(IgniteTxLocalAdapter.this) +
+ ']', deadlockErr)
);
if (commit && commitAfterLock())
@@ -1773,7 +1767,7 @@ public abstract class IgniteTxLocalAdapter extends IgniteTxAdapter implements Ig
if (!locked)
throw new GridClosureException(new IgniteTxTimeoutCheckedException("Failed to acquire lock " +
"within provided timeout for transaction [timeout=" + timeout() +
- ", tx=" + IgniteTxLocalAdapter.this + ']'));
+ ", tx=" + CU.txString(IgniteTxLocalAdapter.this) + ']'));
IgniteInternalFuture<T> fut = postLock();
http://git-wip-us.apache.org/repos/asf/ignite/blob/2b5d2fc5/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTxManager.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTxManager.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTxManager.java
index 7fa31bf..dc8bc46 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTxManager.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTxManager.java
@@ -294,6 +294,22 @@ public class IgniteTxManager extends GridCacheSharedManagerAdapter {
}
/**
+ * Rollback transactions blocking partition map exchange.
+ *
+ * @param topVer Initial exchange version.
+ */
+ public void rollbackOnTopologyChange(AffinityTopologyVersion topVer) {
+ for (IgniteInternalTx tx : activeTransactions()) {
+ if (tx.local() && tx.near() && needWaitTransaction(tx, topVer)) {
+ U.warn(log, "The transaction was forcibly rolled back on partition map exchange because a timeout is " +
+ "reached: [tx=" + CU.txString(tx) + ", topVer=" + topVer + ']');
+
+ ((GridNearTxLocal)tx).rollbackNearTxLocalAsync(false, false);
+ }
+ }
+ }
+
+ /**
* @param cacheId Cache ID.
* @param txMap Transactions map.
*/
@@ -303,7 +319,7 @@ public class IgniteTxManager extends GridCacheSharedManagerAdapter {
for (IgniteTxEntry entry : tx.allEntries()) {
if (entry.cacheId() == cacheId) {
- rollbackTx(tx, false);
+ rollbackTx(tx, false, false);
break;
}
@@ -316,9 +332,9 @@ public class IgniteTxManager extends GridCacheSharedManagerAdapter {
txFinishSync.onDisconnected(reconnectFut);
for (IgniteInternalTx tx : idMap.values())
- rollbackTx(tx, true);
+ rollbackTx(tx, true, false);
for (IgniteInternalTx tx : nearIdMap.values())
- rollbackTx(tx, true);
+ rollbackTx(tx, true, false);
IgniteClientDisconnectedException err =
new IgniteClientDisconnectedException(reconnectFut, "Client node disconnected.");
@@ -414,8 +430,9 @@ public class IgniteTxManager extends GridCacheSharedManagerAdapter {
private boolean isCompleted(IgniteInternalTx tx) {
boolean completed = completedVersHashMap.containsKey(tx.xidVersion());
- // Need check that for tx with timeout rollback message was not received before lock.
- if (!completed && tx.local() && tx.dht() && tx.timeout() > 0)
+ // Need check that for tx rollback message was not received before lock.
+ // This could happen on timeout or async rollback.
+ if (!completed && tx.local() && tx.dht())
return completedVersHashMap.containsKey(tx.nearXidVersion());
return completed;
@@ -428,6 +445,7 @@ public class IgniteTxManager extends GridCacheSharedManagerAdapter {
* @param isolation Isolation.
* @param timeout transaction timeout.
* @param txSize Expected transaction size.
+ * @param lb Label.
* @return New transaction.
*/
public GridNearTxLocal newTx(
@@ -438,7 +456,8 @@ public class IgniteTxManager extends GridCacheSharedManagerAdapter {
TransactionIsolation isolation,
long timeout,
boolean storeEnabled,
- int txSize
+ int txSize,
+ @Nullable String lb
) {
assert sysCacheCtx == null || sysCacheCtx.systemTx();
@@ -458,7 +477,8 @@ public class IgniteTxManager extends GridCacheSharedManagerAdapter {
storeEnabled,
txSize,
subjId,
- taskNameHash);
+ taskNameHash,
+ lb);
if (tx.system()) {
AffinityTopologyVersion topVer = cctx.tm().lockedTopologyVersion(Thread.currentThread().getId(), tx);
@@ -560,10 +580,9 @@ public class IgniteTxManager extends GridCacheSharedManagerAdapter {
}
});
- for (IgniteInternalTx tx : txs()) {
- if (needWaitTransaction(tx, topVer)) {
+ for (IgniteInternalTx tx : activeTransactions()) {
+ if (needWaitTransaction(tx, topVer))
res.add(tx.finishFuture());
- }
}
res.markInitialized();
@@ -960,7 +979,7 @@ public class IgniteTxManager extends GridCacheSharedManagerAdapter {
/**
* @param tx Committed transaction.
- * @return If transaction was not already present in committed set.
+ * @return If transaction was not already present in completed set.
*/
public boolean addRolledbackTx(IgniteInternalTx tx) {
return addRolledbackTx(tx, tx.xidVersion());
@@ -1293,15 +1312,17 @@ public class IgniteTxManager extends GridCacheSharedManagerAdapter {
*
* @param tx Transaction to rollback.
* @param clearThreadMap {@code True} if need remove tx from thread map.
+ * @param skipCompletedVers {@code True} if tx should skip adding itself to completed versions map on finish.
*/
- public void rollbackTx(IgniteInternalTx tx, boolean clearThreadMap) {
+ public void rollbackTx(IgniteInternalTx tx, boolean clearThreadMap, boolean skipCompletedVers) {
assert tx != null;
if (log.isDebugEnabled())
log.debug("Rolling back from TM [locNodeId=" + cctx.localNodeId() + ", tx=" + tx + ']');
// 1. Record transaction version to avoid duplicates.
- addRolledbackTx(tx);
+ if (!skipCompletedVers)
+ addRolledbackTx(tx);
ConcurrentMap<GridCacheVersion, IgniteInternalTx> txIdMap = transactionMap(tx);
@@ -1355,10 +1376,11 @@ public class IgniteTxManager extends GridCacheSharedManagerAdapter {
*
* @param tx Transaction to finish.
* @param commit {@code True} if transaction is committed, {@code false} if rolled back.
+ * @param clearThreadMap {@code True} if need remove tx from thread map.
*/
public void fastFinishTx(GridNearTxLocal tx, boolean commit, boolean clearThreadMap) {
assert tx != null;
- assert tx.writeMap().isEmpty();
+ tx.writeMap().isEmpty();
assert tx.optimistic() || tx.readMap().isEmpty();
ConcurrentMap<GridCacheVersion, IgniteInternalTx> txIdMap = transactionMap(tx);
@@ -1683,7 +1705,14 @@ public class IgniteTxManager extends GridCacheSharedManagerAdapter {
private void txUnlock(IgniteInternalTx tx, IgniteTxEntry txEntry) {
while (true) {
try {
- txEntry.cached().txUnlock(tx);
+ GridCacheEntryEx entry = txEntry.cached();
+
+ assert entry != null;
+
+ if (entry.detached())
+ break;
+
+ entry.txUnlock(tx);
break;
}
@@ -1691,14 +1720,7 @@ public class IgniteTxManager extends GridCacheSharedManagerAdapter {
if (log.isDebugEnabled())
log.debug("Got removed entry in TM txUnlock(..) method (will retry): " + txEntry);
- try {
- txEntry.cached(txEntry.context().cache().entryEx(txEntry.key(), tx.topologyVersion()));
- }
- catch (GridDhtInvalidPartitionException e) {
- tx.addInvalidPartition(txEntry.context(), e.partition());
-
- break;
- }
+ txEntry.cached(txEntry.context().cache().entryEx(txEntry.key(), tx.topologyVersion()));
}
}
}
@@ -1708,31 +1730,8 @@ public class IgniteTxManager extends GridCacheSharedManagerAdapter {
* @param entries Entries to unlock.
*/
private void unlockMultiple(IgniteInternalTx tx, Iterable<IgniteTxEntry> entries) {
- for (IgniteTxEntry txEntry : entries) {
- GridCacheContext cacheCtx = txEntry.context();
-
- while (true) {
- try {
- GridCacheEntryEx entry = txEntry.cached();
-
- assert entry != null;
-
- if (entry.detached())
- break;
-
- entry.txUnlock(tx);
-
- break;
- }
- catch (GridCacheEntryRemovedException ignored) {
- if (log.isDebugEnabled())
- log.debug("Got removed entry in TM unlockMultiple(..) method (will retry): " + txEntry);
-
- // Renew cache entry.
- txEntry.cached(cacheCtx.cache().entryEx(txEntry.key(), tx.topologyVersion()));
- }
- }
- }
+ for (IgniteTxEntry txEntry : entries)
+ txUnlock(tx, txEntry);
}
/**
@@ -1772,13 +1771,6 @@ public class IgniteTxManager extends GridCacheSharedManagerAdapter {
}
/**
- * @return All transactions.
- */
- public Collection<IgniteInternalTx> txs() {
- return F.concat(false, idMap.values(), nearIdMap.values());
- }
-
- /**
* @return Slow tx warn timeout.
*/
public int slowTxWarnTimeout() {
@@ -1859,12 +1851,12 @@ public class IgniteTxManager extends GridCacheSharedManagerAdapter {
* @return Finish future for related remote transactions.
*/
@SuppressWarnings("unchecked")
- public IgniteInternalFuture<IgniteInternalTx> remoteTxFinishFuture(GridCacheVersion nearVer) {
- GridCompoundFuture<IgniteInternalTx, IgniteInternalTx> fut = new GridCompoundFuture<>();
+ public IgniteInternalFuture<?> remoteTxFinishFuture(GridCacheVersion nearVer) {
+ GridCompoundFuture<Void, Void> fut = new GridCompoundFuture<>();
- for (final IgniteInternalTx tx : txs()) {
+ for (final IgniteInternalTx tx : activeTransactions()) {
if (!tx.local() && nearVer.equals(tx.nearXidVersion()))
- fut.add(tx.finishFuture());
+ fut.add((IgniteInternalFuture) tx.finishFuture());
}
fut.markInitialized();
@@ -1884,7 +1876,7 @@ public class IgniteTxManager extends GridCacheSharedManagerAdapter {
@Nullable GridFutureAdapter<Boolean> fut,
@Nullable Collection<GridCacheVersion> processedVers)
{
- for (final IgniteInternalTx tx : txs()) {
+ for (final IgniteInternalTx tx : activeTransactions()) {
if (nearVer.equals(tx.nearXidVersion())) {
IgniteInternalFuture<?> prepFut = tx.currentPrepareFuture();
@@ -2308,7 +2300,7 @@ public class IgniteTxManager extends GridCacheSharedManagerAdapter {
*
* @param tx Transaction to be suspended.
*
- * @see #resumeTx(GridNearTxLocal)
+ * @see #resumeTx(GridNearTxLocal, long)
* @see GridNearTxLocal#suspend()
* @see GridNearTxLocal#resume()
* @throws IgniteCheckedException If failed to suspend transaction.
@@ -2331,13 +2323,14 @@ public class IgniteTxManager extends GridCacheSharedManagerAdapter {
* Please don't use directly. Use tx.resume() instead.
*
* @param tx Transaction to be resumed.
+ * @param threadId Thread id to restore.
*
* @see #suspendTx(GridNearTxLocal)
* @see GridNearTxLocal#suspend()
* @see GridNearTxLocal#resume()
* @throws IgniteCheckedException If failed to resume tx.
*/
- public void resumeTx(GridNearTxLocal tx) throws IgniteCheckedException {
+ public void resumeTx(GridNearTxLocal tx, long threadId) throws IgniteCheckedException {
assert tx != null && !tx.system() : tx;
if (!tx.state(ACTIVE)) {
@@ -2349,8 +2342,6 @@ public class IgniteTxManager extends GridCacheSharedManagerAdapter {
assert !transactionMap(tx).containsValue(tx) : tx;
assert !haveSystemTxForThread(Thread.currentThread().getId());
- long threadId = Thread.currentThread().getId();
-
if (threadMap.putIfAbsent(threadId, tx) != null)
throw new IgniteCheckedException("Thread already has started a transaction.");
@@ -2420,7 +2411,7 @@ public class IgniteTxManager extends GridCacheSharedManagerAdapter {
log.debug("Processing node failed event [locNodeId=" + cctx.localNodeId() +
", failedNodeId=" + evtNodeId + ']');
- for (final IgniteInternalTx tx : txs()) {
+ for (final IgniteInternalTx tx : activeTransactions()) {
if ((tx.near() && !tx.local()) || (tx.storeWriteThrough() && tx.masterNodeIds().contains(evtNodeId))) {
// Invalidate transactions.
salvageTx(tx, RECOVERY_FINISH);
http://git-wip-us.apache.org/repos/asf/ignite/blob/2b5d2fc5/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/TransactionProxyImpl.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/TransactionProxyImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/TransactionProxyImpl.java
index f25fc36..628b813 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/TransactionProxyImpl.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/TransactionProxyImpl.java
@@ -43,6 +43,7 @@ import org.apache.ignite.transactions.Transaction;
import org.apache.ignite.transactions.TransactionConcurrency;
import org.apache.ignite.transactions.TransactionIsolation;
import org.apache.ignite.transactions.TransactionState;
+import org.jetbrains.annotations.Nullable;
import static org.apache.ignite.transactions.TransactionState.SUSPENDED;
@@ -233,6 +234,14 @@ public class TransactionProxyImpl<K, V> implements TransactionProxy, Externaliza
}
/** {@inheritDoc} */
+ @Nullable @Override public String label() {
+ if (async)
+ save(tx.label());
+
+ return tx.label();
+ }
+
+ /** {@inheritDoc} */
@Override public long timeout(long timeout) {
return tx.timeout(timeout);
}
http://git-wip-us.apache.org/repos/asf/ignite/blob/2b5d2fc5/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/TransactionProxyRollbackOnlyImpl.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/TransactionProxyRollbackOnlyImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/TransactionProxyRollbackOnlyImpl.java
new file mode 100644
index 0000000..74735f9
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/TransactionProxyRollbackOnlyImpl.java
@@ -0,0 +1,80 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.processors.cache.transactions;
+
+import java.io.Externalizable;
+import org.apache.ignite.IgniteException;
+import org.apache.ignite.internal.processors.cache.GridCacheSharedContext;
+import org.apache.ignite.internal.processors.cache.distributed.near.GridNearTxLocal;
+import org.apache.ignite.lang.IgniteFuture;
+
+/**
+ * Cache transaction proxy which support only rollback or close operations and getters.
+ */
+@SuppressWarnings("unchecked")
+public class TransactionProxyRollbackOnlyImpl<K, V> extends TransactionProxyImpl<K, V> {
+ /** */
+ private static final long serialVersionUID = 0L;
+
+ /**
+ * Empty constructor required for {@link Externalizable}.
+ */
+ public TransactionProxyRollbackOnlyImpl() {
+ // No-op.
+ }
+
+ /**
+ * @param tx Tx.
+ * @param cctx Cctx.
+ * @param async Async.
+ */
+ public TransactionProxyRollbackOnlyImpl(GridNearTxLocal tx,
+ GridCacheSharedContext<K, V> cctx, boolean async) {
+ super(tx, cctx, async);
+ }
+
+ /** {@inheritDoc} */
+ @Override public boolean setRollbackOnly() {
+ throw new UnsupportedOperationException();
+ }
+
+ /** {@inheritDoc} */
+ @Override public void commit() {
+ throw new UnsupportedOperationException();
+ }
+
+ /** {@inheritDoc} */
+ @Override public IgniteFuture<Void> commitAsync() throws IgniteException {
+ throw new UnsupportedOperationException();
+ }
+
+ /** {@inheritDoc} */
+ @Override public void suspend() throws IgniteException {
+ throw new UnsupportedOperationException();
+ }
+
+ /** {@inheritDoc} */
+ @Override public void resume() throws IgniteException {
+ throw new UnsupportedOperationException();
+ }
+
+ /** {@inheritDoc} */
+ @Override public long timeout(long timeout) {
+ throw new UnsupportedOperationException();
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/2b5d2fc5/modules/core/src/main/java/org/apache/ignite/internal/util/GridPartitionStateMap.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/util/GridPartitionStateMap.java b/modules/core/src/main/java/org/apache/ignite/internal/util/GridPartitionStateMap.java
index 173ddbe..f5893c0 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/util/GridPartitionStateMap.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/util/GridPartitionStateMap.java
@@ -52,7 +52,7 @@ public class GridPartitionStateMap extends AbstractMap<Integer, GridDhtPartition
@Override public Set<Entry<Integer, GridDhtPartitionState>> entrySet() {
return new AbstractSet<Entry<Integer, GridDhtPartitionState>>() {
@Override public Iterator<Entry<Integer, GridDhtPartitionState>> iterator() {
- final int size = states.isEmpty() ? 0 : (states.length() - 1)/ BITS + 1;
+ final int size = states.isEmpty() ? 0 : (states.length() - 1) / BITS + 1;
return new Iterator<Entry<Integer, GridDhtPartitionState>>() {
private int next;
[6/6] ignite git commit: IGNITE-6827 Configurable rollback for long
running transactions before partition exchange IGNITE-7910 Improved
transaction debugging support
Posted by ag...@apache.org.
IGNITE-6827 Configurable rollback for long running transactions before partition exchange
IGNITE-7910 Improved transaction debugging support
Signed-off-by: Andrey Gura <ag...@apache.org>
Project: http://git-wip-us.apache.org/repos/asf/ignite/repo
Commit: http://git-wip-us.apache.org/repos/asf/ignite/commit/2b5d2fc5
Tree: http://git-wip-us.apache.org/repos/asf/ignite/tree/2b5d2fc5
Diff: http://git-wip-us.apache.org/repos/asf/ignite/diff/2b5d2fc5
Branch: refs/heads/master
Commit: 2b5d2fc5fee9b8d722f919b2d92750f139d07876
Parents: 74f4651
Author: Aleksei Scherbakov <al...@gmail.com>
Authored: Mon Apr 23 18:59:04 2018 +0300
Committer: Andrey Gura <ag...@apache.org>
Committed: Mon Apr 23 18:59:04 2018 +0300
----------------------------------------------------------------------
.../ignite/tests/utils/TestTransaction.java | 5 +
.../java/org/apache/ignite/IgniteCluster.java | 7 +
.../org/apache/ignite/IgniteTransactions.java | 23 +-
.../configuration/TransactionConfiguration.java | 41 +
.../apache/ignite/internal/IgniteKernal.java | 9 +-
.../ignite/internal/TransactionsMXBeanImpl.java | 162 ++++
.../cluster/IgniteClusterAsyncImpl.java | 5 +
.../internal/cluster/IgniteClusterImpl.java | 15 +
.../ignite/internal/commandline/Arguments.java | 16 +-
.../ignite/internal/commandline/Command.java | 5 +-
.../internal/commandline/CommandHandler.java | 345 ++++++-
.../optimized/OptimizedMarshallerUtils.java | 2 +-
.../processors/cache/GridCacheAdapter.java | 96 +-
.../GridCachePartitionExchangeManager.java | 29 +-
.../processors/cache/GridCacheProcessor.java | 103 +-
.../cache/GridCacheSharedContext.java | 19 +-
.../processors/cache/GridCacheUtils.java | 4 +-
...eoutOnPartitionMapExchangeChangeMessage.java | 128 +++
...TimeoutOnPartitionMapExchangeChangeTask.java | 57 ++
.../distributed/GridCacheTxFinishSync.java | 3 +-
.../distributed/GridDistributedTxMapping.java | 2 +-
.../GridDistributedTxRemoteAdapter.java | 23 +-
.../distributed/dht/GridDhtLockFuture.java | 363 +++----
.../dht/GridDhtTransactionalCacheAdapter.java | 48 +-
.../cache/distributed/dht/GridDhtTxLocal.java | 29 +-
.../distributed/dht/GridDhtTxLocalAdapter.java | 187 +++-
.../distributed/dht/GridDhtTxPrepareFuture.java | 2 +-
.../dht/GridDhtTxPrepareRequest.java | 36 +-
.../dht/colocated/GridDhtColocatedCache.java | 4 +-
.../colocated/GridDhtColocatedLockFuture.java | 121 ++-
.../GridDhtPartitionsExchangeFuture.java | 25 +-
.../distributed/near/GridNearLockFuture.java | 115 ++-
...arOptimisticSerializableTxPrepareFuture.java | 8 +-
.../near/GridNearOptimisticTxPrepareFuture.java | 13 +-
.../GridNearPessimisticTxPrepareFuture.java | 7 +-
.../near/GridNearTxFastFinishFuture.java | 12 +-
.../near/GridNearTxFinishFuture.java | 96 +-
.../cache/distributed/near/GridNearTxLocal.java | 398 +++++---
.../cache/local/GridLocalLockFuture.java | 80 +-
.../GridCacheDatabaseSharedManager.java | 1 -
.../store/GridCacheStoreManagerAdapter.java | 5 +
.../transactions/IgniteTransactionsImpl.java | 36 +-
.../cache/transactions/IgniteTxAdapter.java | 19 +-
.../cache/transactions/IgniteTxHandler.java | 7 +-
.../transactions/IgniteTxLocalAdapter.java | 20 +-
.../cache/transactions/IgniteTxManager.java | 121 ++-
.../transactions/TransactionProxyImpl.java | 9 +
.../TransactionProxyRollbackOnlyImpl.java | 80 ++
.../internal/util/GridPartitionStateMap.java | 2 +-
.../ignite/internal/visor/tx/VisorTxInfo.java | 174 ++++
.../internal/visor/tx/VisorTxOperation.java | 43 +
.../internal/visor/tx/VisorTxProjection.java | 42 +
.../internal/visor/tx/VisorTxSortOrder.java | 55 ++
.../ignite/internal/visor/tx/VisorTxTask.java | 248 +++++
.../internal/visor/tx/VisorTxTaskArg.java | 205 ++++
.../internal/visor/tx/VisorTxTaskResult.java | 80 ++
.../ignite/mxbean/TransactionsMXBean.java | 99 ++
.../apache/ignite/transactions/Transaction.java | 18 +-
.../resources/META-INF/classnames.properties | 7 +
.../internal/TestRecordingCommunicationSpi.java | 3 +-
.../TransactionMetricsMxBeanImplTest.java | 8 +-
.../internal/TransactionsMXBeanImplTest.java | 118 +++
.../commandline/CommandHandlerParsingTest.java | 100 ++
...tEntryPessimisticRepeatableReadSeltTest.java | 6 +-
.../SetTxTimeoutOnPartitionMapExchangeTest.java | 166 ++++
.../CacheLateAffinityAssignmentTest.java | 5 -
.../IgniteTxRemoveTimeoutObjectsNearTest.java | 30 +
.../IgniteTxRemoveTimeoutObjectsTest.java | 6 +
...ePrimaryNodeFailureRecoveryAbstractTest.java | 2 +-
.../dht/IgniteCacheTxRecoveryRollbackTest.java | 2 +-
.../near/GridCacheNearTxMultiNodeSelfTest.java | 2 +-
.../GridCachePartitionedTxSalvageSelfTest.java | 8 +-
.../GridCacheLocalTxMultiThreadedSelfTest.java | 2 +-
.../cache/transactions/TxLabelTest.java | 63 ++
.../transactions/TxMultiCacheAsyncOpsTest.java | 140 +++
...OptimisticPrepareOnUnstableTopologyTest.java | 250 +++++
.../TxPessimisticDeadlockDetectionTest.java | 2 +-
.../TxRollbackAsyncNearCacheTest.java | 28 +
.../cache/transactions/TxRollbackAsyncTest.java | 938 +++++++++++++++++++
.../TxRollbackAsyncWithPersistenceTest.java | 59 ++
...ollbackOnTimeoutNoDeadlockDetectionTest.java | 6 +-
.../transactions/TxRollbackOnTimeoutTest.java | 118 ++-
.../TxRollbackOnTopologyChangeTest.java | 228 +++++
.../igfs/IgfsDataManagerSelfTest.java | 6 +-
.../cache/GridAbstractCacheStoreSelfTest.java | 7 +-
.../multijvm/IgniteClusterProcessProxy.java | 5 +
.../ignite/testsuites/IgniteBasicTestSuite.java | 4 +
.../testsuites/IgniteCacheTestSuite3.java | 2 +
.../testsuites/IgniteCacheTestSuite6.java | 18 +-
.../ignite/util/GridCommandHandlerTest.java | 247 +++++
.../processors/cache/jta/CacheJtaManager.java | 3 +-
.../ApiParity/ClusterParityTest.cs | 3 +-
.../ApiParity/TransactionsParityTest.cs | 13 +-
.../Cache/CacheAbstractTransactionalTest.cs | 11 +-
94 files changed, 5695 insertions(+), 828 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/ignite/blob/2b5d2fc5/modules/cassandra/store/src/test/java/org/apache/ignite/tests/utils/TestTransaction.java
----------------------------------------------------------------------
diff --git a/modules/cassandra/store/src/test/java/org/apache/ignite/tests/utils/TestTransaction.java b/modules/cassandra/store/src/test/java/org/apache/ignite/tests/utils/TestTransaction.java
index e587bd7..be2211f 100644
--- a/modules/cassandra/store/src/test/java/org/apache/ignite/tests/utils/TestTransaction.java
+++ b/modules/cassandra/store/src/test/java/org/apache/ignite/tests/utils/TestTransaction.java
@@ -147,6 +147,11 @@ public class TestTransaction implements Transaction {
}
/** {@inheritDoc} */
+ @Nullable @Override public String label() {
+ return null;
+ }
+
+ /** {@inheritDoc} */
@Override public void resume() throws IgniteException {
// No-op.
}
http://git-wip-us.apache.org/repos/asf/ignite/blob/2b5d2fc5/modules/core/src/main/java/org/apache/ignite/IgniteCluster.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/IgniteCluster.java b/modules/core/src/main/java/org/apache/ignite/IgniteCluster.java
index 7329d68..b501333 100644
--- a/modules/core/src/main/java/org/apache/ignite/IgniteCluster.java
+++ b/modules/core/src/main/java/org/apache/ignite/IgniteCluster.java
@@ -421,6 +421,13 @@ public interface IgniteCluster extends ClusterGroup, IgniteAsyncSupport {
public void enableStatistics(Collection<String> caches, boolean enabled);
/**
+ * Sets transaction timeout on partition map exchange.
+ *
+ * @param timeout Transaction timeout on partition map exchange in milliseconds.
+ */
+ public void setTxTimeoutOnPartitionMapExchange(long timeout);
+
+ /**
* If local client node disconnected from cluster returns future
* that will be completed when client reconnected.
*
http://git-wip-us.apache.org/repos/asf/ignite/blob/2b5d2fc5/modules/core/src/main/java/org/apache/ignite/IgniteTransactions.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/IgniteTransactions.java b/modules/core/src/main/java/org/apache/ignite/IgniteTransactions.java
index dfe6a1a..2bb7101 100644
--- a/modules/core/src/main/java/org/apache/ignite/IgniteTransactions.java
+++ b/modules/core/src/main/java/org/apache/ignite/IgniteTransactions.java
@@ -17,6 +17,7 @@
package org.apache.ignite;
+import java.util.Collection;
import org.apache.ignite.cache.CacheMode;
import org.apache.ignite.configuration.TransactionConfiguration;
import org.apache.ignite.transactions.Transaction;
@@ -103,4 +104,24 @@ public interface IgniteTransactions {
* Resets transaction metrics.
*/
public void resetMetrics();
-}
\ No newline at end of file
+
+ /**
+ * Returns a list of active transactions initiated by this node.
+ * <p>
+ * Note: returned transaction handle will only support getters, {@link Transaction#close()},
+ * {@link Transaction#rollback()}, {@link Transaction#rollbackAsync()} methods.
+ * Trying to invoke other methods will lead to UnsupportedOperationException.
+ *
+ * @return Transactions started on local node.
+ */
+ public Collection<Transaction> localActiveTransactions();
+
+ /**
+ * Returns instance of Ignite Transactions to mark a transaction with a special label.
+ *
+ * @param lb label.
+ * @return {@code This} for chaining.
+ * @throws NullPointerException if label is null.
+ */
+ public IgniteTransactions withLabel(String lb);
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/2b5d2fc5/modules/core/src/main/java/org/apache/ignite/configuration/TransactionConfiguration.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/configuration/TransactionConfiguration.java b/modules/core/src/main/java/org/apache/ignite/configuration/TransactionConfiguration.java
index 0063afc..818f823 100644
--- a/modules/core/src/main/java/org/apache/ignite/configuration/TransactionConfiguration.java
+++ b/modules/core/src/main/java/org/apache/ignite/configuration/TransactionConfiguration.java
@@ -42,6 +42,9 @@ public class TransactionConfiguration implements Serializable {
/** Default transaction timeout. */
public static final long DFLT_TRANSACTION_TIMEOUT = 0;
+ /** Transaction timeout on partition map synchronization. */
+ public static final long TX_TIMEOUT_ON_PARTITION_MAP_EXCHANGE = 0;
+
/** Default size of pessimistic transactions log. */
public static final int DFLT_PESSIMISTIC_TX_LOG_LINGER = 10_000;
@@ -57,6 +60,9 @@ public class TransactionConfiguration implements Serializable {
/** Default transaction timeout. */
private long dfltTxTimeout = DFLT_TRANSACTION_TIMEOUT;
+ /** Transaction timeout on partition map exchange. */
+ private volatile long txTimeoutOnPartitionMapExchange = TX_TIMEOUT_ON_PARTITION_MAP_EXCHANGE;
+
/** Pessimistic tx log size. */
private int pessimisticTxLogSize;
@@ -89,6 +95,7 @@ public class TransactionConfiguration implements Serializable {
dfltConcurrency = cfg.getDefaultTxConcurrency();
dfltIsolation = cfg.getDefaultTxIsolation();
dfltTxTimeout = cfg.getDefaultTxTimeout();
+ txTimeoutOnPartitionMapExchange = cfg.getTxTimeoutOnPartitionMapExchange();
pessimisticTxLogLinger = cfg.getPessimisticTxLogLinger();
pessimisticTxLogSize = cfg.getPessimisticTxLogSize();
txSerEnabled = cfg.isTxSerializableEnabled();
@@ -192,6 +199,40 @@ public class TransactionConfiguration implements Serializable {
}
/**
+ * Some Ignite operations provoke partition map exchange process within Ignite to ensure the partitions distribution
+ * state is synchronized cluster-wide. Topology update events and a start of a new distributed cache are examples
+ * of those operations.
+ * <p>
+ * When the partition map exchange starts, Ignite acquires a global lock at a particular stage. The lock can't be
+ * obtained until pending transactions are running in parallel. If there is a transaction that runs for a while,
+ * then it will prevent the partition map exchange process from the start freezing some operations such as a new
+ * node join process.
+ * <p>
+ * This property allows to rollback such long transactions to let Ignite acquire the lock faster and initiate the
+ * partition map exchange process. The timeout is enforced only at the time of the partition map exchange process.
+ * <p>
+ * If not set, default value is {@link #TX_TIMEOUT_ON_PARTITION_MAP_EXCHANGE} which means transactions will never be
+ * rolled back on partition map exchange.
+ *
+ * @return Transaction timeout for partition map synchronization in milliseconds.
+ */
+ public long getTxTimeoutOnPartitionMapExchange() {
+ return txTimeoutOnPartitionMapExchange;
+ }
+
+ /**
+ * Sets the transaction timeout that will be enforced if the partition map exchange process starts.
+ *
+ * @param txTimeoutOnPartitionMapExchange Transaction timeout value in milliseconds.
+ * @return {@code this} for chaining.
+ */
+ public TransactionConfiguration setTxTimeoutOnPartitionMapExchange(long txTimeoutOnPartitionMapExchange) {
+ this.txTimeoutOnPartitionMapExchange = txTimeoutOnPartitionMapExchange;
+
+ return this;
+ }
+
+ /**
* Gets size of pessimistic transactions log stored on node in order to recover transaction commit if originating
* node has left grid before it has sent all messages to transaction nodes.
* <p>
http://git-wip-us.apache.org/repos/asf/ignite/blob/2b5d2fc5/modules/core/src/main/java/org/apache/ignite/internal/IgniteKernal.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/IgniteKernal.java b/modules/core/src/main/java/org/apache/ignite/internal/IgniteKernal.java
index 920f519..f17f7eb 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/IgniteKernal.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/IgniteKernal.java
@@ -201,6 +201,7 @@ import org.apache.ignite.mxbean.IgniteMXBean;
import org.apache.ignite.mxbean.StripedExecutorMXBean;
import org.apache.ignite.mxbean.WorkersControlMXBean;
import org.apache.ignite.mxbean.ThreadPoolMXBean;
+import org.apache.ignite.mxbean.TransactionsMXBean;
import org.apache.ignite.mxbean.TransactionMetricsMxBean;
import org.apache.ignite.plugin.IgnitePlugin;
import org.apache.ignite.plugin.PluginNotFoundException;
@@ -4191,9 +4192,13 @@ public class IgniteKernal implements IgniteEx, IgniteMXBean, Externalizable {
ClusterMetricsMXBean metricsBean = new ClusterMetricsMXBeanImpl(cluster());
registerMBean("Kernal", metricsBean.getClass().getSimpleName(), metricsBean, ClusterMetricsMXBean.class);
+ // Transaction metrics
+ TransactionMetricsMxBean txMetricsMXBean = new TransactionMetricsMxBeanImpl(ctx.cache().transactions().metrics());
+ registerMBean("TransactionMetrics", txMetricsMXBean.getClass().getSimpleName(), txMetricsMXBean, TransactionMetricsMxBean.class);
+
// Transactions
- TransactionMetricsMxBean txMXBean = new TransactionMetricsMxBeanImpl(ctx.cache().transactions().metrics());
- registerMBean("Transactions", txMXBean.getClass().getSimpleName(), txMXBean, TransactionMetricsMxBean.class);
+ TransactionsMXBean txMXBean = new TransactionsMXBeanImpl(ctx);
+ registerMBean("Transactions", txMXBean.getClass().getSimpleName(), txMXBean, TransactionsMXBean.class);
// Executors
registerExecutorMBean("GridUtilityCacheExecutor", utilityCachePool);
http://git-wip-us.apache.org/repos/asf/ignite/blob/2b5d2fc5/modules/core/src/main/java/org/apache/ignite/internal/TransactionsMXBeanImpl.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/TransactionsMXBeanImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/TransactionsMXBeanImpl.java
new file mode 100644
index 0000000..6937ebd
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/internal/TransactionsMXBeanImpl.java
@@ -0,0 +1,162 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+import java.util.stream.Collectors;
+import org.apache.ignite.IgniteCompute;
+import org.apache.ignite.IgniteException;
+import org.apache.ignite.cluster.ClusterNode;
+import org.apache.ignite.internal.util.typedef.F;
+import org.apache.ignite.internal.util.typedef.internal.S;
+import org.apache.ignite.internal.util.typedef.internal.U;
+import org.apache.ignite.internal.visor.VisorTaskArgument;
+import org.apache.ignite.internal.visor.tx.VisorTxInfo;
+import org.apache.ignite.internal.visor.tx.VisorTxOperation;
+import org.apache.ignite.internal.visor.tx.VisorTxProjection;
+import org.apache.ignite.internal.visor.tx.VisorTxSortOrder;
+import org.apache.ignite.internal.visor.tx.VisorTxTask;
+import org.apache.ignite.internal.visor.tx.VisorTxTaskArg;
+import org.apache.ignite.internal.visor.tx.VisorTxTaskResult;
+import org.apache.ignite.lang.IgniteClosure;
+import org.apache.ignite.mxbean.TransactionsMXBean;
+
+/**
+ * TransactionsMXBean implementation.
+ */
+public class TransactionsMXBeanImpl implements TransactionsMXBean {
+ /** */
+ private final GridKernalContextImpl ctx;
+
+ /**
+ * @param ctx Context.
+ */
+ TransactionsMXBeanImpl(GridKernalContextImpl ctx) {
+ this.ctx = ctx;
+ }
+
+ /** {@inheritDoc} */
+ @Override public String getActiveTransactions(Long minDuration, Integer minSize, String prj, String consistentIds,
+ String xid, String lbRegex, Integer limit, String order, boolean detailed, boolean kill) {
+ try {
+ IgniteCompute compute = ctx.cluster().get().compute();
+
+ VisorTxProjection proj = null;
+
+ if (prj != null) {
+ if ("clients".equals(prj))
+ proj = VisorTxProjection.CLIENT;
+ else if ("servers".equals(prj))
+ proj = VisorTxProjection.SERVER;
+ }
+
+ List<String> consIds = null;
+
+ if (consistentIds != null)
+ consIds = Arrays.stream(consistentIds.split(",")).collect(Collectors.toList());
+
+ VisorTxSortOrder sortOrder = null;
+
+ if (order != null) {
+ if ("DURATION".equals(order))
+ sortOrder = VisorTxSortOrder.DURATION;
+ else if ("SIZE".equals(order))
+ sortOrder = VisorTxSortOrder.SIZE;
+ }
+
+ VisorTxTaskArg arg = new VisorTxTaskArg(kill ? VisorTxOperation.KILL : VisorTxOperation.LIST,
+ limit, minDuration == null ? null : minDuration * 1000, minSize, null, proj, consIds, xid, lbRegex, sortOrder);
+
+ Map<ClusterNode, VisorTxTaskResult> res = compute.execute(new VisorTxTask(),
+ new VisorTaskArgument<>(ctx.cluster().get().localNode().id(), arg, false));
+
+ if (detailed) {
+ StringWriter sw = new StringWriter();
+
+ PrintWriter w = new PrintWriter(sw);
+
+ for (Map.Entry<ClusterNode, VisorTxTaskResult> entry : res.entrySet()) {
+ if (entry.getValue().getInfos().isEmpty())
+ continue;
+
+ ClusterNode key = entry.getKey();
+
+ w.println(key.toString());
+
+ for (VisorTxInfo info : entry.getValue().getInfos())
+ w.println(" Tx: [xid=" + info.getXid() +
+ ", label=" + info.getLabel() +
+ ", state=" + info.getState() +
+ ", duration=" + info.getDuration() / 1000 +
+ ", isolation=" + info.getIsolation() +
+ ", concurrency=" + info.getConcurrency() +
+ ", timeout=" + info.getTimeout() +
+ ", size=" + info.getSize() +
+ ", dhtNodes=" + F.transform(info.getPrimaryNodes(), new IgniteClosure<UUID, String>() {
+ @Override public String apply(UUID id) {
+ return U.id8(id);
+ }
+ }) +
+ ']');
+ }
+
+ w.flush();
+
+ return sw.toString();
+ }
+ else {
+ int cnt = 0;
+
+ for (VisorTxTaskResult result : res.values())
+ cnt += result.getInfos().size();
+
+ return Integer.toString(cnt);
+ }
+ }
+ catch (Exception e) {
+ throw new RuntimeException(e.getMessage());
+ }
+ }
+
+ /** {@inheritDoc} */
+ @Override public long getTxTimeoutOnPartitionMapExchange() {
+ return ctx.config().getTransactionConfiguration().getTxTimeoutOnPartitionMapExchange();
+ }
+
+ /** {@inheritDoc} */
+ @Override public void setTxTimeoutOnPartitionMapExchange(long timeout) {
+ try {
+ ctx.grid().context().cache().setTxTimeoutOnPartitionMapExchange(timeout);
+ }
+ catch (Exception e) {
+ throw new RuntimeException(e.getMessage());
+ }
+ }
+
+ /** {@inheritDoc} */
+ @Override public String toString() {
+ return S.toString(TransactionsMXBeanImpl.class, this);
+ }
+}
+
+
http://git-wip-us.apache.org/repos/asf/ignite/blob/2b5d2fc5/modules/core/src/main/java/org/apache/ignite/internal/cluster/IgniteClusterAsyncImpl.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/cluster/IgniteClusterAsyncImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/cluster/IgniteClusterAsyncImpl.java
index 43e97b5..98fb8ce 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/cluster/IgniteClusterAsyncImpl.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/cluster/IgniteClusterAsyncImpl.java
@@ -172,6 +172,11 @@ public class IgniteClusterAsyncImpl extends AsyncSupportAdapter<IgniteCluster>
}
/** {@inheritDoc} */
+ @Override public void setTxTimeoutOnPartitionMapExchange(long timeout) {
+ cluster.setTxTimeoutOnPartitionMapExchange(timeout);
+ }
+
+ /** {@inheritDoc} */
@Override public Ignite ignite() {
return cluster.ignite();
}
http://git-wip-us.apache.org/repos/asf/ignite/blob/2b5d2fc5/modules/core/src/main/java/org/apache/ignite/internal/cluster/IgniteClusterImpl.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/cluster/IgniteClusterImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/cluster/IgniteClusterImpl.java
index b69923b..e28342c 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/cluster/IgniteClusterImpl.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/cluster/IgniteClusterImpl.java
@@ -502,6 +502,21 @@ public class IgniteClusterImpl extends ClusterGroupAdapter implements IgniteClus
}
/** {@inheritDoc} */
+ @Override public void setTxTimeoutOnPartitionMapExchange(long timeout) {
+ guard();
+
+ try {
+ ctx.cache().setTxTimeoutOnPartitionMapExchange(timeout);
+ }
+ catch (IgniteCheckedException e) {
+ throw U.convertException(e);
+ }
+ finally {
+ unguard();
+ }
+ }
+
+ /** {@inheritDoc} */
@Override public IgniteCluster withAsync() {
return new IgniteClusterAsyncImpl(this);
}
http://git-wip-us.apache.org/repos/asf/ignite/blob/2b5d2fc5/modules/core/src/main/java/org/apache/ignite/internal/commandline/Arguments.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/commandline/Arguments.java b/modules/core/src/main/java/org/apache/ignite/internal/commandline/Arguments.java
index 23c8eec..660edf4 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/commandline/Arguments.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/commandline/Arguments.java
@@ -17,6 +17,8 @@
package org.apache.ignite.internal.commandline;
+import org.apache.ignite.internal.visor.tx.VisorTxTaskArg;
+
/**
* Bean with all parsed and validated arguments.
*/
@@ -49,6 +51,9 @@ public class Arguments {
*/
private String baselineArgs;
+ /** Transaction arguments. */
+ private final VisorTxTaskArg txArg;
+
/**
* @param cmd Command.
* @param host Host.
@@ -57,11 +62,12 @@ public class Arguments {
* @param pwd Password.
* @param baselineAct Baseline action.
* @param baselineArgs Baseline args.
+ * @param txArg TX arg.
* @param force Force flag.
*/
public Arguments(Command cmd, String host, String port, String user, String pwd,
String baselineAct, String baselineArgs,
- boolean force
+ VisorTxTaskArg txArg, boolean force
) {
this.cmd = cmd;
this.host = host;
@@ -71,6 +77,7 @@ public class Arguments {
this.baselineAct = baselineAct;
this.baselineArgs = baselineArgs;
this.force = force;
+ this.txArg = txArg;
}
/**
@@ -123,6 +130,13 @@ public class Arguments {
}
/**
+ * @return Transaction arguments.
+ */
+ public VisorTxTaskArg transactionArguments() {
+ return txArg;
+ }
+
+ /**
* @return Force option.
*/
public boolean force() {
http://git-wip-us.apache.org/repos/asf/ignite/blob/2b5d2fc5/modules/core/src/main/java/org/apache/ignite/internal/commandline/Command.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/commandline/Command.java b/modules/core/src/main/java/org/apache/ignite/internal/commandline/Command.java
index e73a24f..c8c7db5 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/commandline/Command.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/commandline/Command.java
@@ -31,7 +31,10 @@ public enum Command {
STATE("--state"),
/** */
- BASELINE("--baseline");
+ BASELINE("--baseline"),
+
+ /** */
+ TX("--tx");
/** */
private final String text;
http://git-wip-us.apache.org/repos/asf/ignite/blob/2b5d2fc5/modules/core/src/main/java/org/apache/ignite/internal/commandline/CommandHandler.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/commandline/CommandHandler.java b/modules/core/src/main/java/org/apache/ignite/internal/commandline/CommandHandler.java
index 5993f59..3bc5c1a 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/commandline/CommandHandler.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/commandline/CommandHandler.java
@@ -24,6 +24,11 @@ import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Scanner;
+import java.util.UUID;
+import java.util.logging.Logger;
+import java.util.regex.Pattern;
+import java.util.regex.PatternSyntaxException;
+import org.apache.ignite.cluster.ClusterNode;
import org.apache.ignite.internal.client.GridClient;
import org.apache.ignite.internal.client.GridClientAuthenticationException;
import org.apache.ignite.internal.client.GridClientClosedException;
@@ -39,15 +44,23 @@ import org.apache.ignite.internal.client.GridServerUnreachableException;
import org.apache.ignite.internal.client.impl.connection.GridClientConnectionResetException;
import org.apache.ignite.internal.util.typedef.F;
import org.apache.ignite.internal.util.typedef.X;
+import org.apache.ignite.internal.util.typedef.internal.U;
import org.apache.ignite.internal.visor.VisorTaskArgument;
import org.apache.ignite.internal.visor.baseline.VisorBaselineNode;
import org.apache.ignite.internal.visor.baseline.VisorBaselineOperation;
import org.apache.ignite.internal.visor.baseline.VisorBaselineTask;
import org.apache.ignite.internal.visor.baseline.VisorBaselineTaskArg;
import org.apache.ignite.internal.visor.baseline.VisorBaselineTaskResult;
+import org.apache.ignite.internal.visor.tx.VisorTxInfo;
+import org.apache.ignite.internal.visor.tx.VisorTxOperation;
+import org.apache.ignite.internal.visor.tx.VisorTxProjection;
+import org.apache.ignite.internal.visor.tx.VisorTxSortOrder;
+import org.apache.ignite.internal.visor.tx.VisorTxTask;
+import org.apache.ignite.internal.visor.tx.VisorTxTaskArg;
+import org.apache.ignite.internal.visor.tx.VisorTxTaskResult;
+import org.apache.ignite.lang.IgniteClosure;
import org.apache.ignite.plugin.security.SecurityCredentials;
import org.apache.ignite.plugin.security.SecurityCredentialsBasicProvider;
-import org.jetbrains.annotations.NotNull;
import static org.apache.ignite.internal.IgniteVersionUtils.ACK_VER_STR;
import static org.apache.ignite.internal.IgniteVersionUtils.COPYRIGHT;
@@ -55,6 +68,7 @@ import static org.apache.ignite.internal.commandline.Command.ACTIVATE;
import static org.apache.ignite.internal.commandline.Command.BASELINE;
import static org.apache.ignite.internal.commandline.Command.DEACTIVATE;
import static org.apache.ignite.internal.commandline.Command.STATE;
+import static org.apache.ignite.internal.commandline.Command.TX;
import static org.apache.ignite.internal.visor.baseline.VisorBaselineOperation.ADD;
import static org.apache.ignite.internal.visor.baseline.VisorBaselineOperation.COLLECT;
import static org.apache.ignite.internal.visor.baseline.VisorBaselineOperation.REMOVE;
@@ -65,6 +79,9 @@ import static org.apache.ignite.internal.visor.baseline.VisorBaselineOperation.V
* Class that execute several commands passed via command line.
*/
public class CommandHandler {
+ /** Logger. */
+ private static final Logger log = Logger.getLogger(CommandHandler.class.getName());
+
/** */
static final String DFLT_HOST = "127.0.0.1";
@@ -87,6 +104,9 @@ public class CommandHandler {
private static final String CMD_USER = "--user";
/** */
+ public static final String CONFIRM_MSG = "y";
+
+ /** */
private static final String BASELINE_ADD = "add";
/** */
@@ -126,11 +146,44 @@ public class CommandHandler {
private static final Scanner IN = new Scanner(System.in);
/** */
+ private static final String TX_LIMIT = "limit";
+
+ /** */
+ private static final String TX_ORDER = "order";
+
+ /** */
+ private static final String TX_SERVERS = "servers";
+
+ /** */
+ private static final String TX_CLIENTS = "clients";
+
+ /** */
+ private static final String TX_DURATION = "minDuration";
+
+ /** */
+ private static final String TX_SIZE = "minSize";
+
+ /** */
+ private static final String TX_LABEL = "label";
+
+ /** */
+ private static final String TX_NODES = "nodes";
+
+ /** */
+ private static final String TX_XID = "xid";
+
+ /** */
+ private static final String TX_KILL = "kill";
+
+ /** */
private Iterator<String> argsIt;
/** */
private String peekedArg;
+ /** */
+ private Object lastOperationResult;
+
/**
* Output specified string to console.
*
@@ -198,7 +251,7 @@ public class CommandHandler {
if (prompt == null)
return true;
- return "y".equalsIgnoreCase(readLine(prompt));
+ return CONFIRM_MSG.equalsIgnoreCase(readLine(prompt));
}
/**
@@ -219,9 +272,15 @@ public class CommandHandler {
case BASELINE:
if (!BASELINE_COLLECT.equals(args.baselineAction()))
str = "Warning: the command will perform changes in baseline.";
+ break;
+
+ case TX:
+ if (args.transactionArguments().getOperation() == VisorTxOperation.KILL)
+ str = "Warning: the command will kill some transactions.";
+ break;
}
- return str == null ? null : str + "\nPress 'y' to continue...";
+ return str == null ? null : str + "\nPress '" + CONFIRM_MSG + "' to continue . . . ";
}
/**
@@ -301,14 +360,39 @@ public class CommandHandler {
}
/**
+ * @param client Client.
+ * @param arg Task argument.
+ * @return Task result.
+ * @throws GridClientException If failed to execute task.
+ */
+ private Map<UUID, VisorTxTaskResult> executeTransactionsTask(GridClient client,
+ VisorTxTaskArg arg) throws GridClientException {
+
+ return executeTask(client, VisorTxTask.class, arg);
+ }
+
+ /**
*
- * @param client Client
+ * @param client Client.
+ * @param taskCls Task class.
+ * @param taskArgs Task arguments.
* @return Task result.
* @throws GridClientException If failed to execute task.
*/
private <R> R executeTask(GridClient client, Class<?> taskCls, Object taskArgs) throws GridClientException {
GridClientCompute compute = client.compute();
+ GridClientNode node = getBalancedNode(compute);
+
+ return compute.execute(taskCls.getName(),
+ new VisorTaskArgument<>(node.nodeId(), taskArgs, false));
+ }
+
+ /**
+ * @param compute instance
+ * @return balanced node
+ */
+ private GridClientNode getBalancedNode(GridClientCompute compute) throws GridClientException {
List<GridClientNode> nodes = new ArrayList<>();
for (GridClientNode node : compute.nodes())
@@ -318,10 +402,7 @@ public class CommandHandler {
if (F.isEmpty(nodes))
throw new GridClientDisconnectedException("Connectable node not found", null);
- GridClientNode node = compute.balancer().balancedNode(nodes);
-
- return compute.projection(node).execute(taskCls.getName(),
- new VisorTaskArgument<>(node.nodeId(), taskArgs, false));
+ return compute.balancer().balancedNode(nodes);
}
/**
@@ -368,13 +449,7 @@ public class CommandHandler {
case ADD:
case REMOVE:
case SET:
- if(F.isEmpty(s))
- throw new IllegalArgumentException("Empty list of consistent IDs");
-
- List<String> consistentIds = new ArrayList<>();
-
- for (String consistentId : s.split(","))
- consistentIds.add(consistentId.trim());
+ List<String> consistentIds = getConsistentIds(s);
return new VisorBaselineTaskArg(op, -1, consistentIds);
@@ -394,6 +469,22 @@ public class CommandHandler {
}
/**
+ * @param s String of consisted ids delimited by comma.
+ * @return List of consistent ids.
+ */
+ private List<String> getConsistentIds(String s) {
+ if (F.isEmpty(s))
+ throw new IllegalArgumentException("Empty list of consistent IDs");
+
+ List<String> consistentIds = new ArrayList<>();
+
+ for (String consistentId : s.split(","))
+ consistentIds.add(consistentId.trim());
+
+ return consistentIds;
+ }
+
+ /**
* Print baseline topology.
*
* @param res Task result with baseline topology.
@@ -404,6 +495,7 @@ public class CommandHandler {
nl();
Map<String, VisorBaselineNode> baseline = res.getBaseline();
+
Map<String, VisorBaselineNode> servers = res.getServers();
if (F.isEmpty(baseline))
@@ -532,6 +624,57 @@ public class CommandHandler {
}
/**
+ * Dump transactions information.
+ *
+ * @param client Client.
+ * @param arg Transaction search arguments
+ */
+ private void transactions(GridClient client, VisorTxTaskArg arg) throws GridClientException {
+ try {
+ Map<ClusterNode, VisorTxTaskResult> res = executeTask(client, VisorTxTask.class, arg);
+
+ lastOperationResult = res;
+
+ if (res.isEmpty())
+ log("Nothing found.");
+ else if (arg.getOperation() == VisorTxOperation.KILL)
+ log("Killed transactions:");
+ else
+ log("Matching transactions:");
+
+ for (Map.Entry<ClusterNode, VisorTxTaskResult> entry : res.entrySet()) {
+ if (entry.getValue().getInfos().isEmpty())
+ continue;
+
+ ClusterNode key = entry.getKey();
+
+ log(key.toString());
+
+ for (VisorTxInfo info : entry.getValue().getInfos())
+ log(" Tx: [xid=" + info.getXid() +
+ ", label=" + info.getLabel() +
+ ", state=" + info.getState() +
+ ", duration=" + info.getDuration() / 1000 +
+ ", isolation=" + info.getIsolation() +
+ ", concurrency=" + info.getConcurrency() +
+ ", timeout=" + info.getTimeout() +
+ ", size=" + info.getSize() +
+ ", dhtNodes=" + F.transform(info.getPrimaryNodes(), new IgniteClosure<UUID, String>() {
+ @Override public String apply(UUID id) {
+ return U.id8(id);
+ }
+ }) +
+ ']');
+ }
+ }
+ catch (Throwable e) {
+ log("Failed to perform operation.");
+
+ throw e;
+ }
+ }
+
+ /**
* @param e Exception to check.
* @return {@code true} if specified exception is {@link GridClientAuthenticationException}.
*/
@@ -603,7 +746,7 @@ public class CommandHandler {
* @return Arguments bean.
* @throws IllegalArgumentException In case arguments aren't valid.
*/
- @NotNull Arguments parseAndValidate(List<String> rawArgs) {
+ Arguments parseAndValidate(List<String> rawArgs) {
String host = DFLT_HOST;
String port = DFLT_PORT;
@@ -622,6 +765,8 @@ public class CommandHandler {
initArgIterator(rawArgs);
+ VisorTxTaskArg txArgs = null;
+
while (hasNextArg()) {
String str = nextArg("").toLowerCase();
@@ -632,7 +777,14 @@ public class CommandHandler {
case ACTIVATE:
case DEACTIVATE:
case STATE:
- commands.add(Command.of(str));
+ commands.add(cmd);
+ break;
+
+ case TX:
+ commands.add(TX);
+
+ txArgs = parseTransactionArguments();
+
break;
case BASELINE:
@@ -652,6 +804,11 @@ public class CommandHandler {
baselineArgs = nextArg("Expected baseline arguments");
}
}
+
+ break;
+
+ default:
+ throw new IllegalArgumentException("Unexpected command: " + str);
}
}
else {
@@ -685,6 +842,7 @@ public class CommandHandler {
case CMD_FORCE:
force = true;
break;
+
default:
throw new IllegalArgumentException("Unexpected argument: " + str);
}
@@ -707,7 +865,138 @@ public class CommandHandler {
if (hasUsr != hasPwd)
throw new IllegalArgumentException("Both user and password should be specified");
- return new Arguments(cmd, host, port, user, pwd, baselineAct, baselineArgs, force);
+ return new Arguments(cmd, host, port, user, pwd, baselineAct, baselineArgs, txArgs, force);
+ }
+
+ /**
+ * @return Transaction arguments.
+ */
+ private VisorTxTaskArg parseTransactionArguments() {
+ VisorTxProjection proj = null;
+
+ Integer limit = null;
+
+ VisorTxSortOrder sortOrder = null;
+
+ Long duration = null;
+
+ Integer size = null;
+
+ String lbRegex = null;
+
+ List<String> consistentIds = null;
+
+ VisorTxOperation op = VisorTxOperation.LIST;
+
+ String xid = null;
+
+ boolean end = false;
+
+ do {
+ String str = peekNextArg();
+
+ if (str == null)
+ break;
+
+ switch (str) {
+ case TX_LIMIT:
+ nextArg("");
+
+ limit = (int) nextLongArg(TX_LIMIT);
+ break;
+
+ case TX_ORDER:
+ nextArg("");
+
+ sortOrder = VisorTxSortOrder.fromString(nextArg(TX_ORDER));
+
+ break;
+
+ case TX_SERVERS:
+ nextArg("");
+
+ proj = VisorTxProjection.SERVER;
+ break;
+
+ case TX_CLIENTS:
+ nextArg("");
+
+ proj = VisorTxProjection.CLIENT;
+ break;
+
+ case TX_NODES:
+ nextArg("");
+
+ consistentIds = getConsistentIds(nextArg(TX_NODES));
+ break;
+
+ case TX_DURATION:
+ nextArg("");
+
+ duration = nextLongArg(TX_DURATION) * 1000L;
+ break;
+
+ case TX_SIZE:
+ nextArg("");
+
+ size = (int) nextLongArg(TX_SIZE);
+ break;
+
+ case TX_LABEL:
+ nextArg("");
+
+ lbRegex = nextArg(TX_LABEL);
+
+ try {
+ Pattern.compile(lbRegex);
+ }
+ catch (PatternSyntaxException e) {
+ throw new IllegalArgumentException("Illegal regex syntax");
+ }
+
+ break;
+
+ case TX_XID:
+ nextArg("");
+
+ xid = nextArg(TX_XID);
+ break;
+
+ case TX_KILL:
+ nextArg("");
+
+ op = VisorTxOperation.KILL;
+ break;
+
+ default:
+ end = true;
+ }
+ }
+ while (!end);
+
+ if (proj != null && consistentIds != null)
+ throw new IllegalArgumentException("Projection can't be used together with list of consistent ids.");
+
+ return new VisorTxTaskArg(op, limit, duration, size, null, proj, consistentIds, xid, lbRegex, sortOrder);
+ }
+
+ /**
+ * @return Numeric value.
+ */
+ private long nextLongArg(String lb) {
+ String str = nextArg("Expecting " + lb);
+
+ try {
+ long val = Long.parseLong(str);
+
+ if (val < 0)
+ throw new IllegalArgumentException("Invalid value for " + lb + ": " + val);
+
+ return val;
+ }
+ catch (NumberFormatException e) {
+ throw new IllegalArgumentException("Invalid value for " + lb + ": " + str);
+ }
}
/**
@@ -734,8 +1023,11 @@ public class CommandHandler {
usage(" Remove nodes from baseline topology:", BASELINE, " remove consistentId1[,consistentId2,....,consistentIdN] [--force]");
usage(" Set baseline topology:", BASELINE, " set consistentId1[,consistentId2,....,consistentIdN] [--force]");
usage(" Set baseline topology based on version:", BASELINE, " version topologyVersion [--force]");
+ usage(" List or kill transactions:", TX, " [xid XID] [minDuration SECONDS] " +
+ "[minSize SIZE] [label PATTERN_REGEX] [servers|clients] " +
+ "[nodes consistentId1[,consistentId2,....,consistentIdN] [limit NUMBER] [order DURATION|SIZE] [kill] [--force]");
- log("By default cluster deactivation and changes in baseline topology commands request interactive confirmation. ");
+ log("By default commands affecting the cluster require interactive confirmation. ");
log(" --force option can be used to execute commands without prompting for confirmation.");
nl();
@@ -757,7 +1049,7 @@ public class CommandHandler {
Arguments args = parseAndValidate(rawArgs);
if (!confirm(args)) {
- log("Operation canceled.");
+ log("Operation cancelled.");
return EXIT_CODE_OK;
}
@@ -789,6 +1081,10 @@ public class CommandHandler {
case BASELINE:
baseline(client, args.baselineAction(), args.baselineArguments());
break;
+
+ case TX:
+ transactions(client, args.transactionArguments());
+ break;
}
}
@@ -816,5 +1112,14 @@ public class CommandHandler {
System.exit(hnd.execute(Arrays.asList(args)));
}
+
+ /**
+ * Used for tests.
+ * @return Last operation result;
+ */
+ @SuppressWarnings("unchecked")
+ public <T> T getLastOperationResult() {
+ return (T)lastOperationResult;
+ }
}
http://git-wip-us.apache.org/repos/asf/ignite/blob/2b5d2fc5/modules/core/src/main/java/org/apache/ignite/internal/marshaller/optimized/OptimizedMarshallerUtils.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/marshaller/optimized/OptimizedMarshallerUtils.java b/modules/core/src/main/java/org/apache/ignite/internal/marshaller/optimized/OptimizedMarshallerUtils.java
index aa4bfd6..4626df7 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/marshaller/optimized/OptimizedMarshallerUtils.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/marshaller/optimized/OptimizedMarshallerUtils.java
@@ -203,7 +203,7 @@ class OptimizedMarshallerUtils {
try {
registered = ctx.registerClassName(JAVA_ID, typeId, cls.getName());
}
- catch (IgniteCheckedException e) {
+ catch (Exception e) {
throw new IOException("Failed to register class: " + cls.getName(), e);
}
http://git-wip-us.apache.org/repos/asf/ignite/blob/2b5d2fc5/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheAdapter.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheAdapter.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheAdapter.java
index bd613a1..567cc6e 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheAdapter.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheAdapter.java
@@ -89,6 +89,7 @@ import org.apache.ignite.internal.processors.cache.distributed.IgniteExternaliza
import org.apache.ignite.internal.processors.cache.distributed.dht.GridDhtCacheAdapter;
import org.apache.ignite.internal.processors.cache.distributed.dht.GridDhtInvalidPartitionException;
import org.apache.ignite.internal.processors.cache.distributed.dht.GridDhtTopologyFuture;
+import org.apache.ignite.internal.processors.cache.distributed.dht.GridDhtTxLocalAdapter;
import org.apache.ignite.internal.processors.cache.distributed.near.GridNearTxLocal;
import org.apache.ignite.internal.processors.cache.dr.GridCacheDrInfo;
import org.apache.ignite.internal.processors.cache.persistence.CacheDataRow;
@@ -4081,7 +4082,8 @@ public abstract class GridCacheAdapter<K, V> implements IgniteInternalCache<K, V
READ_COMMITTED,
tCfg.getDefaultTxTimeout(),
!ctx.skipStore(),
- 0
+ 0,
+ null
);
assert tx != null;
@@ -4105,7 +4107,8 @@ public abstract class GridCacheAdapter<K, V> implements IgniteInternalCache<K, V
tx.xid(), e);
}
catch (IgniteCheckedException | AssertionError | RuntimeException e1) {
- U.error(log, "Failed to rollback transaction (cache may contain stale locks): " + tx, e1);
+ U.error(log, "Failed to rollback transaction (cache may contain stale locks): " +
+ CU.txString(tx), e1);
if (e != e1)
e.addSuppressed(e1);
@@ -4180,7 +4183,8 @@ public abstract class GridCacheAdapter<K, V> implements IgniteInternalCache<K, V
READ_COMMITTED,
txCfg.getDefaultTxTimeout(),
!skipStore,
- 0);
+ 0,
+ null);
return asyncOp(tx, op, opCtx, /*retry*/false);
}
@@ -4224,6 +4228,31 @@ public abstract class GridCacheAdapter<K, V> implements IgniteInternalCache<K, V
final GridNearTxLocal tx0 = tx;
+ final CX1 clo = new CX1<IgniteInternalFuture<T>, T>() {
+ @Override public T applyx(IgniteInternalFuture<T> tFut) throws IgniteCheckedException {
+ try {
+ return tFut.get();
+ }
+ catch (IgniteTxTimeoutCheckedException | IgniteTxRollbackCheckedException | NodeStoppingException e) {
+ throw e;
+ }
+ catch (IgniteCheckedException e1) {
+ try {
+ tx0.rollbackNearTxLocalAsync();
+ }
+ catch (Throwable e2) {
+ if (e1 != e2)
+ e1.addSuppressed(e2);
+ }
+
+ throw e1;
+ }
+ finally {
+ ctx.shared().txContextReset();
+ }
+ }
+ };
+
if (fut != null && !fut.isDone()) {
IgniteInternalFuture<T> f = new GridEmbeddedFuture(fut,
new IgniteOutClosure<IgniteInternalFuture>() {
@@ -4233,31 +4262,7 @@ public abstract class GridCacheAdapter<K, V> implements IgniteInternalCache<K, V
new IgniteCheckedException("Operation has been cancelled (node is stopping)."));
try {
- return op.op(tx0, opCtx).chain(new CX1<IgniteInternalFuture<T>, T>() {
- @Override
- public T applyx(IgniteInternalFuture<T> tFut) throws IgniteCheckedException {
- try {
- return tFut.get();
- }
- catch (IgniteTxRollbackCheckedException | NodeStoppingException e) {
- throw e;
- }
- catch (IgniteCheckedException e1) {
- try {
- tx0.rollbackNearTxLocalAsync();
- }
- catch (Throwable e2) {
- if (e1 != e2)
- e1.addSuppressed(e2);
- }
-
- throw e1;
- }
- finally {
- ctx.shared().txContextReset();
- }
- }
- });
+ return op.op(tx0, opCtx).chain(clo);
}
finally {
// It is necessary to clear tx context in this thread as well.
@@ -4271,33 +4276,17 @@ public abstract class GridCacheAdapter<K, V> implements IgniteInternalCache<K, V
return f;
}
+ /**
+ * Wait for concurrent tx operation to finish.
+ * See {@link GridDhtTxLocalAdapter#updateLockFuture(IgniteInternalFuture, IgniteInternalFuture)}
+ */
+ if (!tx0.txState().implicitSingle())
+ tx0.txState().awaitLastFuture(ctx.shared());
+
IgniteInternalFuture<T> f;
try {
- f = op.op(tx, opCtx).chain(new CX1<IgniteInternalFuture<T>, T>() {
- @Override public T applyx(IgniteInternalFuture<T> tFut) throws IgniteCheckedException {
- try {
- return tFut.get();
- }
- catch (IgniteTxRollbackCheckedException | NodeStoppingException e) {
- throw e;
- }
- catch (IgniteCheckedException e1) {
- try {
- tx0.rollbackNearTxLocalAsync(e1 instanceof IgniteTxTimeoutCheckedException);
- }
- catch (Throwable e2) {
- if (e2 != e1)
- e1.addSuppressed(e2);
- }
-
- throw e1;
- }
- finally {
- ctx.shared().txContextReset();
- }
- }
- });
+ f = op.op(tx, opCtx).chain(clo);
}
finally {
// It is necessary to clear tx context in this thread as well.
@@ -4858,7 +4847,8 @@ public abstract class GridCacheAdapter<K, V> implements IgniteInternalCache<K, V
READ_COMMITTED,
CU.transactionConfiguration(ctx, ctx.kernalContext().config()).getDefaultTxTimeout(),
opCtx == null || !opCtx.skipStore(),
- 0);
+ 0,
+ null);
IgniteInternalFuture<T> fut = asyncOp(tx, op, opCtx, retry);
http://git-wip-us.apache.org/repos/asf/ignite/blob/2b5d2fc5/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCachePartitionExchangeManager.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCachePartitionExchangeManager.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCachePartitionExchangeManager.java
index 35f14da..28d5d20 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCachePartitionExchangeManager.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCachePartitionExchangeManager.java
@@ -36,7 +36,6 @@ import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ConcurrentSkipListMap;
import java.util.concurrent.LinkedBlockingDeque;
-import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicReference;
@@ -47,6 +46,7 @@ import org.apache.ignite.IgniteSystemProperties;
import org.apache.ignite.cache.affinity.AffinityFunction;
import org.apache.ignite.cluster.ClusterNode;
import org.apache.ignite.configuration.CacheConfiguration;
+import org.apache.ignite.configuration.IgniteConfiguration;
import org.apache.ignite.events.DiscoveryEvent;
import org.apache.ignite.failure.FailureContext;
import org.apache.ignite.internal.IgniteClientDisconnectedCheckedException;
@@ -2420,23 +2420,28 @@ public class GridCachePartitionExchangeManager<K, V> extends GridCacheSharedMana
int dumpCnt = 0;
- final long futTimeout = 2 * cctx.gridConfig().getNetworkTimeout();
+ IgniteConfiguration cfg = cctx.gridConfig();
+
+ long rollbackTimeout = cfg.getTransactionConfiguration().getTxTimeoutOnPartitionMapExchange();
+
+ final long dumpTimeout = 2 * cctx.gridConfig().getNetworkTimeout();
long nextDumpTime = 0;
while (true) {
try {
- resVer = exchFut.get(futTimeout, TimeUnit.MILLISECONDS);
+ resVer = exchFut.get(rollbackTimeout > 0 ? rollbackTimeout : dumpTimeout);
break;
}
catch (IgniteFutureTimeoutCheckedException ignored) {
- U.warn(diagnosticLog, "Failed to wait for partition map exchange [" +
- "topVer=" + exchFut.initialVersion() +
- ", node=" + cctx.localNodeId() + "]. " +
- "Dumping pending objects that might be the cause: ");
-
if (nextDumpTime <= U.currentTimeMillis()) {
+ U.warn(diagnosticLog, "Failed to wait for partition map exchange [" +
+ "topVer=" + exchFut.initialVersion() +
+ ", node=" + cctx.localNodeId() + "]. " +
+ (rollbackTimeout == 0 ? "Consider changing TransactionConfiguration.txTimeoutOnPartitionMapSynchronization to non default value to avoid this message. " : "") +
+ "Dumping pending objects that might be the cause: ");
+
try {
dumpDebugInfo(exchFut);
}
@@ -2444,7 +2449,13 @@ public class GridCachePartitionExchangeManager<K, V> extends GridCacheSharedMana
U.error(diagnosticLog, "Failed to dump debug information: " + e, e);
}
- nextDumpTime = U.currentTimeMillis() + nextDumpTimeout(dumpCnt++, futTimeout);
+ nextDumpTime = U.currentTimeMillis() + nextDumpTimeout(dumpCnt++, dumpTimeout);
+ }
+
+ if (rollbackTimeout > 0) {
+ rollbackTimeout = 0; // Try automatic rollback only once.
+
+ cctx.tm().rollbackOnTopologyChange(exchFut.initialVersion());
}
}
catch (Exception e) {
http://git-wip-us.apache.org/repos/asf/ignite/blob/2b5d2fc5/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheProcessor.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheProcessor.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheProcessor.java
index bceb8c7..39c7e71 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheProcessor.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheProcessor.java
@@ -229,6 +229,10 @@ public class GridCacheProcessor extends GridProcessorAdapter {
/** Enable/disable cache statistics futures. */
private ConcurrentMap<UUID, EnableStatisticsFuture> enableStatisticsFuts = new ConcurrentHashMap<>();
+ /** The futures for changing transaction timeout on partition map exchange. */
+ private ConcurrentMap<UUID, TxTimeoutOnPartitionMapExchangeChangeFuture> txTimeoutOnPartitionMapExchangeFuts =
+ new ConcurrentHashMap<>();
+
/** */
private ClusterCachesInfo cachesInfo;
@@ -380,6 +384,11 @@ public class GridCacheProcessor extends GridProcessorAdapter {
processStatisticsModeChange(task0.message());
}
+ else if (task instanceof TxTimeoutOnPartitionMapExchangeChangeTask) {
+ TxTimeoutOnPartitionMapExchangeChangeTask task0 = (TxTimeoutOnPartitionMapExchangeChangeTask)task;
+
+ processTxTimeoutOnPartitionMapExchangeChange(task0.message());
+ }
else if (task instanceof StopCachesOnClientReconnectExchangeTask) {
StopCachesOnClientReconnectExchangeTask task0 = (StopCachesOnClientReconnectExchangeTask)task;
@@ -683,7 +692,7 @@ public class GridCacheProcessor extends GridProcessorAdapter {
sharedCtx = createSharedContext(ctx, sessionListeners);
- transactions = new IgniteTransactionsImpl(sharedCtx);
+ transactions = new IgniteTransactionsImpl(sharedCtx, null);
// Start shared managers.
for (GridCacheSharedManager mgr : sharedCtx.managers())
@@ -1057,6 +1066,9 @@ public class GridCacheProcessor extends GridProcessorAdapter {
for (EnableStatisticsFuture fut : enableStatisticsFuts.values())
fut.onDone(err);
+ for (TxTimeoutOnPartitionMapExchangeChangeFuture fut : txTimeoutOnPartitionMapExchangeFuts.values())
+ fut.onDone(err);
+
for (CacheGroupContext grp : cacheGrps.values())
grp.onDisconnected(reconnectFut);
@@ -2618,6 +2630,43 @@ public class GridCacheProcessor extends GridProcessorAdapter {
}
/**
+ * Callback invoked from discovery thread when discovery custom message is received.
+ *
+ * @param msg Discovery message for changing transaction timeout on partition map exchange.
+ */
+ public void onTxTimeoutOnPartitionMapExchangeChange(TxTimeoutOnPartitionMapExchangeChangeMessage msg) {
+ assert msg != null;
+
+ if (msg.isInit()) {
+ TransactionConfiguration cfg = ctx.config().getTransactionConfiguration();
+
+ if (cfg.getTxTimeoutOnPartitionMapExchange() != msg.getTimeout())
+ cfg.setTxTimeoutOnPartitionMapExchange(msg.getTimeout());
+ }
+ else {
+ TxTimeoutOnPartitionMapExchangeChangeFuture fut = txTimeoutOnPartitionMapExchangeFuts.get(
+ msg.getRequestId());
+
+ if (fut != null)
+ fut.onDone();
+ }
+ }
+
+ /**
+ * The task for changing transaction timeout on partition map exchange processed by exchange worker.
+ *
+ * @param msg Message.
+ */
+ public void processTxTimeoutOnPartitionMapExchangeChange(TxTimeoutOnPartitionMapExchangeChangeMessage msg) {
+ assert msg != null;
+
+ long timeout = ctx.config().getTransactionConfiguration().getTxTimeoutOnPartitionMapExchange();
+
+ if (timeout != msg.getTimeout())
+ ctx.config().getTransactionConfiguration().setTxTimeoutOnPartitionMapExchange(msg.getTimeout());
+ }
+
+ /**
* @param stoppedCaches Stopped caches.
*/
private void stopCachesOnClientReconnect(Collection<GridCacheAdapter> stoppedCaches) {
@@ -3413,6 +3462,9 @@ public class GridCacheProcessor extends GridProcessorAdapter {
if (msg instanceof CacheStatisticsModeChangeMessage)
onCacheStatisticsModeChange((CacheStatisticsModeChangeMessage)msg);
+ if (msg instanceof TxTimeoutOnPartitionMapExchangeChangeMessage)
+ onTxTimeoutOnPartitionMapExchangeChange((TxTimeoutOnPartitionMapExchangeChangeMessage)msg);
+
return false;
}
@@ -3963,6 +4015,9 @@ public class GridCacheProcessor extends GridProcessorAdapter {
for (EnableStatisticsFuture fut : enableStatisticsFuts.values())
fut.onDone(err);
+
+ for (TxTimeoutOnPartitionMapExchangeChangeFuture fut : txTimeoutOnPartitionMapExchangeFuts.values())
+ fut.onDone(err);
}
/**
@@ -4392,6 +4447,26 @@ public class GridCacheProcessor extends GridProcessorAdapter {
}
/**
+ * Sets transaction timeout on partition map exchange.
+ *
+ * @param timeout Transaction timeout on partition map exchange in milliseconds.
+ */
+ public void setTxTimeoutOnPartitionMapExchange(long timeout) throws IgniteCheckedException {
+ UUID requestId = UUID.randomUUID();
+
+ TxTimeoutOnPartitionMapExchangeChangeFuture fut = new TxTimeoutOnPartitionMapExchangeChangeFuture(requestId);
+
+ txTimeoutOnPartitionMapExchangeFuts.put(requestId, fut);
+
+ TxTimeoutOnPartitionMapExchangeChangeMessage msg = new TxTimeoutOnPartitionMapExchangeChangeMessage(
+ requestId, timeout);
+
+ ctx.grid().context().discovery().sendCustomEvent(msg);
+
+ fut.get();
+ }
+
+ /**
* @param obj Object to clone.
* @return Object copy.
* @throws IgniteCheckedException If failed.
@@ -4624,4 +4699,30 @@ public class GridCacheProcessor extends GridProcessorAdapter {
return S.toString(EnableStatisticsFuture.class, this);
}
}
+
+ /**
+ * The future for changing transaction timeout on partition map exchange.
+ */
+ private class TxTimeoutOnPartitionMapExchangeChangeFuture extends GridFutureAdapter<Void> {
+ /** */
+ private UUID id;
+
+ /**
+ * @param id Future ID.
+ */
+ private TxTimeoutOnPartitionMapExchangeChangeFuture(UUID id) {
+ this.id = id;
+ }
+
+ /** {@inheritDoc} */
+ @Override public boolean onDone(@Nullable Void res, @Nullable Throwable err) {
+ txTimeoutOnPartitionMapExchangeFuts.remove(id, this);
+ return super.onDone(res, err);
+ }
+
+ /** {@inheritDoc} */
+ @Override public String toString() {
+ return S.toString(TxTimeoutOnPartitionMapExchangeChangeFuture.class, this);
+ }
+ }
}
http://git-wip-us.apache.org/repos/asf/ignite/blob/2b5d2fc5/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheSharedContext.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheSharedContext.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheSharedContext.java
index b5c4096..b195508 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheSharedContext.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheSharedContext.java
@@ -71,6 +71,7 @@ import org.apache.ignite.plugin.PluginProvider;
import org.jetbrains.annotations.Nullable;
import static org.apache.ignite.IgniteSystemProperties.IGNITE_LOCAL_STORE_KEEPS_PRIMARY_ONLY;
+import static org.apache.ignite.transactions.TransactionState.MARKED_ROLLBACK;
/**
* Shared context.
@@ -955,9 +956,14 @@ public class GridCacheSharedContext<K, V> {
* @throws IgniteCheckedException If failed.
*/
public void endTx(GridNearTxLocal tx) throws IgniteCheckedException {
- tx.txState().awaitLastFuture(this);
+ boolean clearThreadMap = txMgr.threadLocalTx(null) == tx;
+
+ if (clearThreadMap)
+ tx.txState().awaitLastFuture(this);
+ else
+ tx.state(MARKED_ROLLBACK);
- tx.close();
+ tx.close(clearThreadMap);
}
/**
@@ -983,9 +989,14 @@ public class GridCacheSharedContext<K, V> {
* @return Rollback future.
*/
public IgniteInternalFuture rollbackTxAsync(GridNearTxLocal tx) throws IgniteCheckedException {
- tx.txState().awaitLastFuture(this);
+ boolean clearThreadMap = txMgr.threadLocalTx(null) == tx;
+
+ if (clearThreadMap)
+ tx.txState().awaitLastFuture(this);
+ else
+ tx.state(MARKED_ROLLBACK);
- return tx.rollbackNearTxLocalAsync();
+ return tx.rollbackNearTxLocalAsync(clearThreadMap, false);
}
/**
http://git-wip-us.apache.org/repos/asf/ignite/blob/2b5d2fc5/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheUtils.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheUtils.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheUtils.java
index e244c75..bb64cc6 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheUtils.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheUtils.java
@@ -817,13 +817,15 @@ public class GridCacheUtils {
if (tx == null)
return "null";
- return tx.getClass().getSimpleName() + "[id=" + tx.xid() +
+ return tx.getClass().getSimpleName() + "[xid=" + tx.xid() +
+ ", xidVersion=" + tx.xidVersion() +
", concurrency=" + tx.concurrency() +
", isolation=" + tx.isolation() +
", state=" + tx.state() +
", invalidate=" + tx.isInvalidate() +
", rollbackOnly=" + tx.isRollbackOnly() +
", nodeId=" + tx.nodeId() +
+ ", timeout=" + tx.timeout() +
", duration=" + (U.currentTimeMillis() - tx.startTime()) + ']';
}
http://git-wip-us.apache.org/repos/asf/ignite/blob/2b5d2fc5/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/TxTimeoutOnPartitionMapExchangeChangeMessage.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/TxTimeoutOnPartitionMapExchangeChangeMessage.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/TxTimeoutOnPartitionMapExchangeChangeMessage.java
new file mode 100644
index 0000000..5589c94
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/TxTimeoutOnPartitionMapExchangeChangeMessage.java
@@ -0,0 +1,128 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.processors.cache;
+
+import java.util.UUID;
+import org.apache.ignite.internal.managers.discovery.DiscoCache;
+import org.apache.ignite.internal.managers.discovery.DiscoveryCustomMessage;
+import org.apache.ignite.internal.managers.discovery.GridDiscoveryManager;
+import org.apache.ignite.internal.processors.affinity.AffinityTopologyVersion;
+import org.apache.ignite.internal.util.typedef.internal.S;
+import org.apache.ignite.lang.IgniteUuid;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * Discovery message for changing transaction timeout on partition map exchange.
+ */
+public class TxTimeoutOnPartitionMapExchangeChangeMessage implements DiscoveryCustomMessage {
+ /** */
+ private static final long serialVersionUID = 0L;
+
+ /** */
+ private final IgniteUuid id = IgniteUuid.randomUuid();
+
+ /** Request ID. */
+ private final UUID reqId;
+
+ /** Transaction timeout on partition map exchange in milliseconds. */
+ private final long timeout;
+
+ /** Init flag. */
+ private final boolean isInit;
+
+ /**
+ * Constructor for response.
+ *
+ * @param req Request message.
+ */
+ public TxTimeoutOnPartitionMapExchangeChangeMessage(TxTimeoutOnPartitionMapExchangeChangeMessage req) {
+ this.reqId = req.reqId;
+ this.timeout = req.timeout;
+ this.isInit = false;
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param reqId Request ID.
+ * @param timeout Transaction timeout on partition map exchange in milliseconds.
+ */
+ public TxTimeoutOnPartitionMapExchangeChangeMessage(UUID reqId, long timeout) {
+ this.reqId = reqId;
+ this.timeout = timeout;
+ this.isInit = true;
+ }
+
+ /** {@inheritDoc} */
+ @Override public IgniteUuid id() {
+ return id;
+ }
+
+ /** {@inheritDoc} */
+ @Nullable @Override public DiscoveryCustomMessage ackMessage() {
+ return isInit() ? new TxTimeoutOnPartitionMapExchangeChangeMessage(this) : null;
+ }
+
+ /** {@inheritDoc} */
+ @Override public boolean isMutable() {
+ return false;
+ }
+
+ /** {@inheritDoc} */
+ @Override public boolean stopProcess() {
+ return false;
+ }
+
+ /** {@inheritDoc} */
+ @Override public DiscoCache createDiscoCache(GridDiscoveryManager mgr, AffinityTopologyVersion topVer,
+ DiscoCache discoCache) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Gets request ID.
+ *
+ * @return Request ID.
+ */
+ public UUID getRequestId() {
+ return reqId;
+ }
+
+ /**
+ * Gets transaction timeout on partition map exchange in milliseconds.
+ *
+ * @return Transaction timeout on partition map exchange in milliseconds.
+ */
+ public long getTimeout() {
+ return timeout;
+ }
+
+ /**
+ * Gets init flag.
+ *
+ * @return Init flag.
+ */
+ public boolean isInit() {
+ return isInit;
+ }
+
+ /** {@inheritDoc} */
+ @Override public String toString() {
+ return S.toString(TxTimeoutOnPartitionMapExchangeChangeMessage.class, this);
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/2b5d2fc5/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/TxTimeoutOnPartitionMapExchangeChangeTask.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/TxTimeoutOnPartitionMapExchangeChangeTask.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/TxTimeoutOnPartitionMapExchangeChangeTask.java
new file mode 100644
index 0000000..6edfa58
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/TxTimeoutOnPartitionMapExchangeChangeTask.java
@@ -0,0 +1,57 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.processors.cache;
+
+import org.apache.ignite.internal.util.typedef.internal.S;
+
+/**
+ * The task for changing transaction timeout on partition map exchange.
+ */
+public class TxTimeoutOnPartitionMapExchangeChangeTask implements CachePartitionExchangeWorkerTask {
+ /** Discovery message. */
+ private final TxTimeoutOnPartitionMapExchangeChangeMessage msg;
+
+ /**
+ * Constructor.
+ *
+ * @param msg Discovery message.
+ */
+ public TxTimeoutOnPartitionMapExchangeChangeTask(TxTimeoutOnPartitionMapExchangeChangeMessage msg) {
+ assert msg != null;
+ this.msg = msg;
+ }
+
+ /**
+ * Gets discovery message.
+ *
+ * @return Discovery message.
+ */
+ public TxTimeoutOnPartitionMapExchangeChangeMessage message() {
+ return msg;
+ }
+
+ /** {@inheritDoc} */
+ @Override public boolean skipForExchangeMerge() {
+ return false;
+ }
+
+ /** {@inheritDoc} */
+ @Override public String toString() {
+ return S.toString(TxTimeoutOnPartitionMapExchangeChangeTask.class, this);
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/2b5d2fc5/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/GridCacheTxFinishSync.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/GridCacheTxFinishSync.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/GridCacheTxFinishSync.java
index 02d1e8e..7cc368a 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/GridCacheTxFinishSync.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/GridCacheTxFinishSync.java
@@ -26,6 +26,7 @@ import org.apache.ignite.IgniteLogger;
import org.apache.ignite.internal.IgniteClientDisconnectedCheckedException;
import org.apache.ignite.internal.IgniteInternalFuture;
import org.apache.ignite.internal.processors.cache.GridCacheSharedContext;
+import org.apache.ignite.internal.processors.cache.version.GridCacheVersion;
import org.apache.ignite.internal.util.future.GridFinishedFuture;
import org.apache.ignite.internal.util.future.GridFutureAdapter;
import org.apache.ignite.internal.util.typedef.F;
@@ -338,4 +339,4 @@ public class GridCacheTxFinishSync<K, V> {
}
}
}
-}
\ No newline at end of file
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/2b5d2fc5/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/GridDistributedTxMapping.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/GridDistributedTxMapping.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/GridDistributedTxMapping.java
index 45903aa..481c954 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/GridDistributedTxMapping.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/GridDistributedTxMapping.java
@@ -41,7 +41,7 @@ public class GridDistributedTxMapping {
/** Entries. */
@GridToStringInclude
- private Collection<IgniteTxEntry> entries;
+ private final Collection<IgniteTxEntry> entries;
/** Explicit lock flag. */
private boolean explicitLock;
http://git-wip-us.apache.org/repos/asf/ignite/blob/2b5d2fc5/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/GridDistributedTxRemoteAdapter.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/GridDistributedTxRemoteAdapter.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/GridDistributedTxRemoteAdapter.java
index 27044eb..a692b2e 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/GridDistributedTxRemoteAdapter.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/GridDistributedTxRemoteAdapter.java
@@ -117,6 +117,9 @@ public abstract class GridDistributedTxRemoteAdapter extends IgniteTxAdapter
@GridToStringInclude
protected IgniteTxRemoteState txState;
+ /** {@code True} if tx should skip adding itself to completed version map on finish. */
+ private boolean skipCompletedVers;
+
/**
* Empty constructor required for {@link Externalizable}.
*/
@@ -228,8 +231,7 @@ public abstract class GridDistributedTxRemoteAdapter extends IgniteTxAdapter
@Override public GridTuple<CacheObject> peek(GridCacheContext cacheCtx,
boolean failFast,
KeyCacheObject key)
- throws GridCacheFilterFailedException
- {
+ throws GridCacheFilterFailedException {
assert false : "Method peek can only be called on user transaction: " + this;
throw new IllegalStateException("Method peek can only be called on user transaction: " + this);
@@ -869,7 +871,7 @@ public abstract class GridDistributedTxRemoteAdapter extends IgniteTxAdapter
// Note that we don't evict near entries here -
// they will be deleted by their corresponding transactions.
if (state(ROLLING_BACK) || state() == UNKNOWN) {
- cctx.tm().rollbackTx(this, false);
+ cctx.tm().rollbackTx(this, false, skipCompletedVers);
state(ROLLED_BACK);
}
@@ -899,6 +901,20 @@ public abstract class GridDistributedTxRemoteAdapter extends IgniteTxAdapter
}
/**
+ * @return {@code True} if tx should skip adding itself to completed version map on finish.
+ */
+ public boolean skipCompletedVersions() {
+ return skipCompletedVers;
+ }
+
+ /**
+ * @param skipCompletedVers {@code True} if tx should skip adding itself to completed version map on finish.
+ */
+ public void skipCompletedVersions(boolean skipCompletedVers) {
+ this.skipCompletedVers = skipCompletedVers;
+ }
+
+ /**
* Adds explicit version if there is one.
*
* @param e Transaction entry.
@@ -925,4 +941,5 @@ public abstract class GridDistributedTxRemoteAdapter extends IgniteTxAdapter
@Override public String toString() {
return GridToStringBuilder.toString(GridDistributedTxRemoteAdapter.class, this, "super", super.toString());
}
+
}
[3/6] ignite git commit: IGNITE-6827 Configurable rollback for long
running transactions before partition exchange IGNITE-7910 Improved
transaction debugging support
Posted by ag...@apache.org.
http://git-wip-us.apache.org/repos/asf/ignite/blob/2b5d2fc5/modules/core/src/main/java/org/apache/ignite/internal/visor/tx/VisorTxInfo.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/visor/tx/VisorTxInfo.java b/modules/core/src/main/java/org/apache/ignite/internal/visor/tx/VisorTxInfo.java
new file mode 100644
index 0000000..89bf274
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/internal/visor/tx/VisorTxInfo.java
@@ -0,0 +1,174 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.visor.tx;
+
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+import java.io.Serializable;
+import java.util.Collection;
+import java.util.UUID;
+import org.apache.ignite.internal.util.typedef.internal.S;
+import org.apache.ignite.internal.util.typedef.internal.U;
+import org.apache.ignite.internal.visor.VisorDataTransferObject;
+import org.apache.ignite.lang.IgniteUuid;
+import org.apache.ignite.transactions.TransactionConcurrency;
+import org.apache.ignite.transactions.TransactionIsolation;
+import org.apache.ignite.transactions.TransactionState;
+
+/**
+ */
+public class VisorTxInfo extends VisorDataTransferObject {
+ /** */
+ private static final long serialVersionUID = 0L;
+
+ /** */
+ private IgniteUuid xid;
+
+ /** */
+ private long duration;
+
+ /** */
+ private TransactionIsolation isolation;
+
+ /** */
+ private TransactionConcurrency concurrency;
+
+ /** */
+ private long timeout;
+
+ /** */
+ private String lb;
+
+ /** */
+ private Collection<UUID> primaryNodes;
+
+ /** */
+ private TransactionState state;
+
+ /** */
+ private int size;
+
+ /**
+ * Default constructor.
+ */
+ public VisorTxInfo() {
+ // No-op.
+ }
+
+ /**
+ * @param xid Xid.
+ * @param duration Duration.
+ * @param isolation Isolation.
+ * @param concurrency Concurrency.
+ * @param timeout Timeout.
+ * @param lb Label.
+ * @param primaryNodes Primary nodes.
+ * @param state State.
+ * @param size Size.
+ */
+ public VisorTxInfo(IgniteUuid xid, long duration, TransactionIsolation isolation,
+ TransactionConcurrency concurrency, long timeout, String lb, Collection<UUID> primaryNodes,
+ TransactionState state, int size) {
+ this.xid = xid;
+ this.duration = duration;
+ this.isolation = isolation;
+ this.concurrency = concurrency;
+ this.timeout = timeout;
+ this.lb = lb;
+ this.primaryNodes = primaryNodes;
+ this.state = state;
+ this.size = size;
+ }
+
+ /** */
+ public IgniteUuid getXid() {
+ return xid;
+ }
+
+ /** */
+ public long getDuration() {
+ return duration;
+ }
+
+ /** */
+ public TransactionIsolation getIsolation() {
+ return isolation;
+ }
+
+ /** */
+ public TransactionConcurrency getConcurrency() {
+ return concurrency;
+ }
+
+ /** */
+ public long getTimeout() {
+ return timeout;
+ }
+
+ /** */
+ public String getLabel() {
+ return lb;
+ }
+
+ /** */
+ public Collection<UUID> getPrimaryNodes() {
+ return primaryNodes;
+ }
+
+ /** */
+ public TransactionState getState() {
+ return state;
+ }
+
+ /** */
+ public int getSize() {
+ return size;
+ }
+
+ /** {@inheritDoc} */
+ @Override protected void writeExternalData(ObjectOutput out) throws IOException {
+ U.writeGridUuid(out, xid);
+ out.writeLong(duration);
+ U.writeEnum(out, isolation);
+ U.writeEnum(out, concurrency);
+ out.writeLong(timeout);
+ U.writeString(out, lb);
+ U.writeCollection(out, primaryNodes);
+ U.writeEnum(out, state);
+ out.writeInt(size);
+ }
+
+ /** {@inheritDoc} */
+ @Override protected void readExternalData(byte protoVer, ObjectInput in) throws IOException, ClassNotFoundException {
+ xid = U.readGridUuid(in);
+ duration = in.readLong();
+ isolation = TransactionIsolation.fromOrdinal(in.readByte());
+ concurrency = TransactionConcurrency.fromOrdinal(in.readByte());
+ timeout = in.readLong();
+ lb = U.readString(in);
+ primaryNodes = U.readCollection(in);
+ state = TransactionState.fromOrdinal(in.readByte());
+ size = in.readInt();
+ }
+
+ /** {@inheritDoc} */
+ @Override public String toString() {
+ return S.toString(VisorTxInfo.class, this);
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/2b5d2fc5/modules/core/src/main/java/org/apache/ignite/internal/visor/tx/VisorTxOperation.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/visor/tx/VisorTxOperation.java b/modules/core/src/main/java/org/apache/ignite/internal/visor/tx/VisorTxOperation.java
new file mode 100644
index 0000000..4aaab8e
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/internal/visor/tx/VisorTxOperation.java
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.visor.tx;
+
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * Defines possible Visor operation on transactions.
+ */
+public enum VisorTxOperation {
+ /** List matching transactions. */
+ LIST,
+ /** Kill matching transactions. */
+ KILL;
+
+ /** Enumerated values. */
+ private static final VisorTxOperation[] VALS = values();
+
+ /**
+ * Efficiently gets enumerated value from its ordinal.
+ *
+ * @param ord Ordinal value.
+ * @return Enumerated value or {@code null} if ordinal out of range.
+ */
+ @Nullable public static VisorTxOperation fromOrdinal(int ord) {
+ return ord >= 0 && ord < VALS.length ? VALS[ord] : null;
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/2b5d2fc5/modules/core/src/main/java/org/apache/ignite/internal/visor/tx/VisorTxProjection.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/visor/tx/VisorTxProjection.java b/modules/core/src/main/java/org/apache/ignite/internal/visor/tx/VisorTxProjection.java
new file mode 100644
index 0000000..4c81cc6
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/internal/visor/tx/VisorTxProjection.java
@@ -0,0 +1,42 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.visor.tx;
+
+import org.jetbrains.annotations.Nullable;
+
+/**
+ */
+public enum VisorTxProjection {
+ /** Server nodes. */
+ SERVER,
+ /** Client nodes. */
+ CLIENT;
+
+ /** Enumerated values. */
+ private static final VisorTxProjection[] VALS = values();
+
+ /**
+ * Efficiently gets enumerated value from its ordinal.
+ *
+ * @param ord Ordinal value.
+ * @return Enumerated value or {@code null} if ordinal out of range.
+ */
+ @Nullable public static VisorTxProjection fromOrdinal(int ord) {
+ return ord >= 0 && ord < VALS.length ? VALS[ord] : null;
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/2b5d2fc5/modules/core/src/main/java/org/apache/ignite/internal/visor/tx/VisorTxSortOrder.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/visor/tx/VisorTxSortOrder.java b/modules/core/src/main/java/org/apache/ignite/internal/visor/tx/VisorTxSortOrder.java
new file mode 100644
index 0000000..382cf91
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/internal/visor/tx/VisorTxSortOrder.java
@@ -0,0 +1,55 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.visor.tx;
+
+import org.jetbrains.annotations.Nullable;
+
+/**
+ */
+public enum VisorTxSortOrder {
+ /** Sort by duration. */
+ DURATION,
+ /** Sort by size. */
+ SIZE;
+
+ /** Enumerated values. */
+ private static final VisorTxSortOrder[] VALS = values();
+
+ /**
+ * Efficiently gets enumerated value from its ordinal.
+ *
+ * @param ord Ordinal value.
+ * @return Enumerated value or {@code null} if ordinal out of range.
+ */
+ @Nullable public static VisorTxSortOrder fromOrdinal(int ord) {
+ return ord >= 0 && ord < VALS.length ? VALS[ord] : null;
+ }
+
+ /**
+ * @param name Name.
+ */
+ public static VisorTxSortOrder fromString(String name) {
+ if (DURATION.toString().equals(name))
+ return DURATION;
+
+ if (SIZE.toString().equals(name))
+ return SIZE;
+
+ throw new IllegalArgumentException("Sort order is unknown: " + name);
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/2b5d2fc5/modules/core/src/main/java/org/apache/ignite/internal/visor/tx/VisorTxTask.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/visor/tx/VisorTxTask.java b/modules/core/src/main/java/org/apache/ignite/internal/visor/tx/VisorTxTask.java
new file mode 100644
index 0000000..72b1740
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/internal/visor/tx/VisorTxTask.java
@@ -0,0 +1,248 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.visor.tx;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+import java.util.UUID;
+import java.util.regex.Pattern;
+import java.util.regex.PatternSyntaxException;
+import org.apache.ignite.IgniteException;
+import org.apache.ignite.cluster.ClusterNode;
+import org.apache.ignite.compute.ComputeJobResult;
+import org.apache.ignite.internal.processors.cache.distributed.GridDistributedTxMapping;
+import org.apache.ignite.internal.processors.cache.distributed.near.GridNearTxLocal;
+import org.apache.ignite.internal.processors.cache.transactions.TransactionProxyImpl;
+import org.apache.ignite.internal.processors.task.GridInternal;
+import org.apache.ignite.internal.util.typedef.F;
+import org.apache.ignite.internal.util.typedef.internal.U;
+import org.apache.ignite.internal.visor.VisorJob;
+import org.apache.ignite.internal.visor.VisorMultiNodeTask;
+import org.apache.ignite.internal.visor.VisorTaskArgument;
+import org.apache.ignite.lang.IgniteClosure;
+import org.apache.ignite.lang.IgnitePredicate;
+import org.apache.ignite.lang.IgniteUuid;
+import org.apache.ignite.transactions.Transaction;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ *
+ */
+@GridInternal
+public class VisorTxTask extends VisorMultiNodeTask<VisorTxTaskArg, Map<ClusterNode, VisorTxTaskResult>, VisorTxTaskResult> {
+ /** */
+ private static final long serialVersionUID = 0L;
+
+ /** {@inheritDoc} */
+ @Override protected VisorJob<VisorTxTaskArg, VisorTxTaskResult> job(VisorTxTaskArg arg) {
+ return new VisorTxJob(arg, debug);
+ }
+
+ /** {@inheritDoc} */
+ @Override protected Collection<UUID> jobNodes(VisorTaskArgument<VisorTxTaskArg> arg) {
+ final VisorTxTaskArg taskArg = arg.getArgument();
+
+ if (taskArg.getConsistentIds() != null) {
+ return F.transform(ignite.cluster().forPredicate(new IgnitePredicate<ClusterNode>() {
+ @Override public boolean apply(ClusterNode node) {
+ return taskArg.getConsistentIds().contains((String)node.consistentId().toString());
+ }
+ }).nodes(), new IgniteClosure<ClusterNode, UUID>() {
+ @Override public UUID apply(ClusterNode node) {
+ return node.id();
+ }
+ });
+ }
+
+ if (taskArg.getProjection() == VisorTxProjection.SERVER) {
+ return F.transform(ignite.cluster().forServers().nodes(), new IgniteClosure<ClusterNode, UUID>() {
+ @Override public UUID apply(ClusterNode node) {
+ return node.id();
+ }
+ });
+ }
+
+ if (taskArg.getProjection() == VisorTxProjection.CLIENT) {
+ return F.transform(ignite.cluster().forClients().nodes(), new IgniteClosure<ClusterNode, UUID>() {
+ @Override public UUID apply(ClusterNode node) {
+ return node.id();
+ }
+ });
+ }
+
+ return F.transform(ignite.cluster().nodes(), new IgniteClosure<ClusterNode, UUID>() {
+ @Override public UUID apply(ClusterNode node) {
+ return node.id();
+ }
+ });
+ }
+
+ /** {@inheritDoc} */
+ @Nullable @Override protected Map<ClusterNode, VisorTxTaskResult> reduce0(List<ComputeJobResult> results) throws IgniteException {
+ Map<ClusterNode, VisorTxTaskResult> mapRes = new TreeMap<>();
+
+ for (ComputeJobResult result : results) {
+ VisorTxTaskResult data = result.getData();
+
+ if (data == null || data.getInfos().isEmpty())
+ continue;
+
+ mapRes.put(result.getNode(), data);
+ }
+
+ return mapRes;
+ }
+
+ /**
+ *
+ */
+ private static class VisorTxJob extends VisorJob<VisorTxTaskArg, VisorTxTaskResult> {
+ /** */
+ private static final long serialVersionUID = 0L;
+
+ /** */
+ public static final int DEFAULT_LIMIT = 50;
+
+ /**
+ * @param arg Formal job argument.
+ * @param debug Debug flag.
+ */
+ private VisorTxJob(VisorTxTaskArg arg, boolean debug) {
+ super(arg, debug);
+ }
+
+ /** {@inheritDoc} */
+ @Override protected VisorTxTaskResult run(@Nullable VisorTxTaskArg arg) throws IgniteException {
+ if (arg == null)
+ return new VisorTxTaskResult(Collections.emptyList());
+
+ Collection<Transaction> transactions = ignite.transactions().localActiveTransactions();
+
+ List<VisorTxInfo> infos = new ArrayList<>();
+
+ int limit = arg.getLimit() == null ? DEFAULT_LIMIT : arg.getLimit();
+
+ Pattern lbMatch = null;
+
+ if (arg.getLabelRegex() != null) {
+ try {
+ lbMatch = Pattern.compile(arg.getLabelRegex());
+ }
+ catch (PatternSyntaxException ignored) {
+ // No-op.
+ }
+ }
+
+ for (Transaction transaction : transactions) {
+ GridNearTxLocal locTx = ((TransactionProxyImpl)transaction).tx();
+
+ if (arg.getXid() != null && !locTx.xid().toString().equals(arg.getXid()))
+ continue;
+
+ if (arg.getState() != null && locTx.state() != arg.getState())
+ continue;
+
+ long duration = U.currentTimeMillis() - transaction.startTime();
+
+ if (arg.getMinDuration() != null &&
+ duration < arg.getMinDuration())
+ continue;
+
+ if (arg.getMinSize() != null && locTx.size() < arg.getMinSize())
+ continue;
+
+ if (lbMatch != null && (locTx.label() == null || !lbMatch.matcher(locTx.label()).matches()))
+ continue;
+
+ Collection<UUID> mappings = new ArrayList<>();
+
+ int size = 0;
+
+ if (locTx.mappings() != null) {
+ for (GridDistributedTxMapping mapping : locTx.mappings().mappings()) {
+ mappings.add(mapping.primary().id());
+
+ size += mapping.entries().size(); // Entries are not synchronized so no visibility guaranties.
+ }
+ }
+
+ infos.add(new VisorTxInfo(locTx.xid(), duration, locTx.isolation(), locTx.concurrency(),
+ locTx.timeout(), locTx.label(), mappings, locTx.state(), size));
+
+ if (arg.getOperation() == VisorTxOperation.KILL)
+ locTx.rollbackAsync();
+
+ if (infos.size() == limit)
+ break;
+ }
+
+ Comparator<VisorTxInfo> comp = TxDurationComparator.INSTANCE;
+
+ if (arg.getSortOrder() != null) {
+ switch (arg.getSortOrder()) {
+ case DURATION:
+ comp = TxDurationComparator.INSTANCE;
+
+ break;
+
+ case SIZE:
+ comp = TxSizeComparator.INSTANCE;
+
+ break;
+
+ default:
+ }
+ }
+
+ Collections.sort(infos, comp);
+
+ return new VisorTxTaskResult(infos);
+ }
+ }
+
+ /**
+ *
+ */
+ private static class TxDurationComparator implements Comparator<VisorTxInfo> {
+ /** Instance. */
+ public static final TxDurationComparator INSTANCE = new TxDurationComparator();
+
+ /** {@inheritDoc} */
+ @Override public int compare(VisorTxInfo o1, VisorTxInfo o2) {
+ return Long.compare(o2.getDuration(), o1.getDuration());
+ }
+ }
+
+ /**
+ *
+ */
+ private static class TxSizeComparator implements Comparator<VisorTxInfo> {
+ /** Instance. */
+ public static final TxSizeComparator INSTANCE = new TxSizeComparator();
+
+ /** {@inheritDoc} */
+ @Override public int compare(VisorTxInfo o1, VisorTxInfo o2) {
+ return Long.compare(o2.getSize(), o1.getSize());
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/2b5d2fc5/modules/core/src/main/java/org/apache/ignite/internal/visor/tx/VisorTxTaskArg.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/visor/tx/VisorTxTaskArg.java b/modules/core/src/main/java/org/apache/ignite/internal/visor/tx/VisorTxTaskArg.java
new file mode 100644
index 0000000..80bf8b5
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/internal/visor/tx/VisorTxTaskArg.java
@@ -0,0 +1,205 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.visor.tx;
+
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+import java.util.List;
+import org.apache.ignite.internal.util.typedef.internal.S;
+import org.apache.ignite.internal.util.typedef.internal.U;
+import org.apache.ignite.internal.visor.VisorDataTransferObject;
+import org.apache.ignite.internal.visor.baseline.VisorBaselineTask;
+import org.apache.ignite.transactions.TransactionState;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * Argument for {@link VisorTxTask}.
+ */
+public class VisorTxTaskArg extends VisorDataTransferObject {
+ /** */
+ private static final long serialVersionUID = 0L;
+
+ /** */
+ private VisorTxOperation op;
+
+ /** */
+ private @Nullable Integer limit;
+
+ /** */
+ private @Nullable Long minDuration;
+
+ /** */
+ private @Nullable Integer minSize;
+
+ /** */
+ private @Nullable TransactionState state;
+
+ /** */
+ private @Nullable VisorTxProjection proj;
+
+ /** */
+ private @Nullable List<String> consistentIds;
+
+ /** */
+ private @Nullable String xid;
+
+ /** */
+ private @Nullable String lbRegex;
+
+ /** */
+ private @Nullable VisorTxSortOrder sortOrder;
+
+ /**
+ * Default constructor.
+ */
+ public VisorTxTaskArg() {
+ // No-op.
+ }
+
+ /**
+ * @param limit Limit to collect.
+ * @param minDuration Min duration.
+ * @param minSize Min size.
+ * @param state State.
+ * @param proj Projection.
+ * @param consistentIds Consistent ids for NODES projection.
+ * @param xid Xid.
+ * @param lbRegex Label regex.
+ * @param sortOrder Sort order.
+ */
+ public VisorTxTaskArg(VisorTxOperation op, @Nullable Integer limit, @Nullable Long minDuration, @Nullable Integer minSize,
+ @Nullable TransactionState state, @Nullable VisorTxProjection proj, @Nullable List<String> consistentIds,
+ @Nullable String xid, @Nullable String lbRegex, @Nullable VisorTxSortOrder sortOrder) {
+ this.op = op;
+ this.limit = limit;
+ this.minDuration = minDuration;
+ this.minSize = minSize;
+ this.state = state;
+ this.proj = proj;
+ this.consistentIds = consistentIds;
+ this.lbRegex = lbRegex;
+ this.xid = xid;
+ this.sortOrder = sortOrder;
+ }
+
+ /** */
+ public VisorTxOperation getOperation() {
+ return op;
+ }
+
+ /** */
+ @Nullable public Integer getLimit() {
+ return limit;
+ }
+
+ /** */
+ @Nullable public Long getMinDuration() {
+ return minDuration;
+ }
+
+ /** */
+ @Nullable public Integer getMinSize() {
+ return minSize;
+ }
+
+ /** */
+ @Nullable public TransactionState getState() {
+ return state;
+ }
+
+ /** */
+ public VisorTxProjection getProjection() {
+ return proj;
+ }
+
+ /** */
+ @Nullable public List<String> getConsistentIds() {
+ return consistentIds;
+ }
+
+ /** */
+ @Nullable public String getLabelRegex() {
+ return lbRegex;
+ }
+
+ /** */
+ @Nullable public String getXid() {
+ return xid;
+ }
+
+ /** */
+ @Nullable public VisorTxSortOrder getSortOrder() {
+ return sortOrder;
+ }
+
+ /** {@inheritDoc} */
+ @Override protected void writeExternalData(ObjectOutput out) throws IOException {
+ U.writeEnum(out, op);
+ out.writeInt(limit == null ? -1 : limit);
+ out.writeLong(minDuration == null ? -1 : minDuration);
+ out.writeInt(minSize == null ? -1 : minSize);
+ U.writeEnum(out, state);
+ U.writeEnum(out, proj);
+ U.writeCollection(out, consistentIds);
+ out.writeUTF(lbRegex == null ? "" : lbRegex);
+ out.writeUTF(xid == null ? "" : xid);
+ U.writeEnum(out, sortOrder);
+ }
+
+ /** {@inheritDoc} */
+ @Override protected void readExternalData(byte protoVer, ObjectInput in) throws IOException, ClassNotFoundException {
+ op = VisorTxOperation.fromOrdinal(in.readByte());
+ limit = fixNull(in.readInt());
+ minDuration = fixNull(in.readLong());
+ minSize = fixNull(in.readInt());
+ state = TransactionState.fromOrdinal(in.readByte());
+ proj = VisorTxProjection.fromOrdinal(in.readByte());
+ consistentIds = U.readList(in);
+ lbRegex = fixNull(in.readUTF());
+ xid = fixNull(in.readUTF());
+ sortOrder = VisorTxSortOrder.fromOrdinal(in.readByte());
+ }
+
+ /**
+ * @param val Value.
+ */
+ private Integer fixNull(int val) {
+ return val == -1 ? null : val;
+ }
+
+ /**
+ * @param val Value.
+ */
+ private Long fixNull(long val) {
+ return val == -1 ? null : val;
+ }
+
+ /**
+ * @param val Value.
+ */
+ private String fixNull(String val) {
+ return "".equals(val) ? null : val;
+ }
+
+
+ /** {@inheritDoc} */
+ @Override public String toString() {
+ return S.toString(VisorTxTaskArg.class, this);
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/2b5d2fc5/modules/core/src/main/java/org/apache/ignite/internal/visor/tx/VisorTxTaskResult.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/visor/tx/VisorTxTaskResult.java b/modules/core/src/main/java/org/apache/ignite/internal/visor/tx/VisorTxTaskResult.java
new file mode 100644
index 0000000..4864a77
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/internal/visor/tx/VisorTxTaskResult.java
@@ -0,0 +1,80 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.visor.tx;
+
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+import org.apache.ignite.cluster.BaselineNode;
+import org.apache.ignite.internal.util.typedef.F;
+import org.apache.ignite.internal.util.typedef.internal.S;
+import org.apache.ignite.internal.util.typedef.internal.U;
+import org.apache.ignite.internal.visor.VisorDataTransferObject;
+import org.apache.ignite.internal.visor.baseline.VisorBaselineNode;
+import org.apache.ignite.internal.visor.baseline.VisorBaselineTask;
+
+/**
+ * Result for {@link VisorTxTask}.
+ */
+public class VisorTxTaskResult extends VisorDataTransferObject {
+ /** */
+ private static final long serialVersionUID = 0L;
+
+ /** */
+ private List<VisorTxInfo> infos;
+
+ /**
+ * Default constructor.
+ */
+ public VisorTxTaskResult() {
+ // No-op.
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param infos Infos.
+ */
+ public VisorTxTaskResult(List<VisorTxInfo> infos) {
+ this.infos = infos;
+ }
+
+ /** */
+ public List<VisorTxInfo> getInfos() {
+ return infos;
+ }
+
+ /** {@inheritDoc} */
+ @Override protected void writeExternalData(ObjectOutput out) throws IOException {
+ U.writeCollection(out, infos);
+ }
+
+ /** {@inheritDoc} */
+ @Override protected void readExternalData(byte protoVer, ObjectInput in) throws IOException, ClassNotFoundException {
+ infos = U.readList(in);
+ }
+
+ /** {@inheritDoc} */
+ @Override public String toString() {
+ return S.toString(VisorTxTaskResult.class, this);
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/2b5d2fc5/modules/core/src/main/java/org/apache/ignite/mxbean/TransactionsMXBean.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/mxbean/TransactionsMXBean.java b/modules/core/src/main/java/org/apache/ignite/mxbean/TransactionsMXBean.java
new file mode 100644
index 0000000..2a125fa
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/mxbean/TransactionsMXBean.java
@@ -0,0 +1,99 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.mxbean;
+
+import org.apache.ignite.configuration.TransactionConfiguration;
+
+/**
+ * Transactions MXBean interface.
+ */
+@MXBeanDescription("MBean that provides access to Ignite transactions.")
+public interface TransactionsMXBean {
+ /**
+ * @param minDuration Minimum duration.
+ * @param minSize Minimum size.
+ * @param prj Projection.
+ * @param consistentIds Consistent ids.
+ * @param xid Xid.
+ * @param lbRegex Label regex.
+ * @param limit Limit.
+ * @param order Order.
+ * @param detailed Detailed.
+ * @param kill Kill.
+ */
+ @MXBeanDescription("Returns or kills transactions matching the filter conditions.")
+ @MXBeanParametersNames(
+ {
+ "minDuration",
+ "minSize",
+ "prj",
+ "consistentIds",
+ "xid",
+ "lbRegex",
+ "limit",
+ "order",
+ "detailed",
+ "kill"
+ }
+ )
+ @MXBeanParametersDescriptions(
+ {
+ "Minimum duration (seconds).",
+ "Minimum size.",
+ "Projection (servers|clients).",
+ "Consistent ids (separated by comma).",
+ "Transaction XID.",
+ "Label regexp.",
+ "Limit a number of transactions collected on each node.",
+ "Order by DURATION|SIZE.",
+ "Show detailed description, otherwise only count.",
+ "Kill matching transactions (be careful)."
+ }
+ )
+ public String getActiveTransactions(Long minDuration, Integer minSize, String prj,
+ String consistentIds, String xid, String lbRegex, Integer limit, String order, boolean detailed, boolean kill);
+
+ /**
+ * Gets transaction timeout on partition map exchange.
+ * <p>
+ * @see TransactionConfiguration#getTxTimeoutOnPartitionMapExchange
+ *
+ * @return Transaction timeout on partition map exchange in milliseconds.
+ */
+ @MXBeanDescription("Returns transaction timeout on partition map exchange in milliseconds.")
+ public long getTxTimeoutOnPartitionMapExchange();
+
+ /**
+ * Sets transaction timeout on partition map exchange.
+ * <p>
+ * If not set, default value is {@link TransactionConfiguration#TX_TIMEOUT_ON_PARTITION_MAP_EXCHANGE} which means
+ * transactions will never be rolled back on partition map exchange.
+ * <p>
+ * @see TransactionConfiguration#setTxTimeoutOnPartitionMapExchange
+ *
+ * @param timeout Transaction timeout on partition map exchange in milliseconds.
+ */
+ @MXBeanDescription("Sets transaction timeout on partition map exchange in milliseconds.")
+ @MXBeanParametersNames(
+ "timeout"
+ )
+ @MXBeanParametersDescriptions(
+ "Transaction timeout on partition map exchange in milliseconds."
+ )
+ public void setTxTimeoutOnPartitionMapExchange(long timeout);
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/2b5d2fc5/modules/core/src/main/java/org/apache/ignite/transactions/Transaction.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/transactions/Transaction.java b/modules/core/src/main/java/org/apache/ignite/transactions/Transaction.java
index a1b4d78..b0f90c1 100644
--- a/modules/core/src/main/java/org/apache/ignite/transactions/Transaction.java
+++ b/modules/core/src/main/java/org/apache/ignite/transactions/Transaction.java
@@ -24,6 +24,7 @@ import org.apache.ignite.lang.IgniteAsyncSupport;
import org.apache.ignite.lang.IgniteAsyncSupported;
import org.apache.ignite.lang.IgniteFuture;
import org.apache.ignite.lang.IgniteUuid;
+import org.jetbrains.annotations.Nullable;
/**
* Ignite cache transaction. Cache transactions have a default 2PC (two-phase-commit) behavior and
@@ -259,6 +260,7 @@ public interface Transaction extends AutoCloseable, IgniteAsyncSupport {
/**
* Rolls back this transaction.
+ * Note, that it's allowed to roll back transaction from any thread at any time.
*
* @throws IgniteException If rollback failed.
*/
@@ -267,6 +269,7 @@ public interface Transaction extends AutoCloseable, IgniteAsyncSupport {
/**
* Asynchronously rolls back this transaction.
+ * Note, that it's allowed to roll back transaction from any thread at any time.
*
* @return a Future representing pending completion of the rollback.
* @throws IgniteException If rollback failed.
@@ -274,16 +277,25 @@ public interface Transaction extends AutoCloseable, IgniteAsyncSupport {
public IgniteFuture<Void> rollbackAsync() throws IgniteException;
/**
- * Resume transaction if it was previously suspended. <strong>Supported only for optimistic transactions.</strong>
+ * Resume a transaction if it was previously suspended. <strong>Supported only for optimistic transactions.</strong>
*
* @throws IgniteException If resume failed.
*/
public void resume() throws IgniteException;
/**
- * Suspends transaction. It could be resumed later. <strong>Supported only for optimistic transactions.</strong>
+ * Suspends a transaction. It could be resumed later. <strong>Supported only for optimistic transactions.</strong>
*
* @throws IgniteException If suspension failed.
*/
public void suspend() throws IgniteException;
-}
\ No newline at end of file
+
+ /**
+ * Returns transaction's label.
+ * <p>
+ * Use {@link IgniteTransactions#withLabel(java.lang.String)} to assign a label to a newly created transaction.
+ *
+ * @return Label.
+ */
+ public @Nullable String label();
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/2b5d2fc5/modules/core/src/main/resources/META-INF/classnames.properties
----------------------------------------------------------------------
diff --git a/modules/core/src/main/resources/META-INF/classnames.properties b/modules/core/src/main/resources/META-INF/classnames.properties
index 6dc3d85..d939b02 100644
--- a/modules/core/src/main/resources/META-INF/classnames.properties
+++ b/modules/core/src/main/resources/META-INF/classnames.properties
@@ -2069,6 +2069,13 @@ org.apache.ignite.internal.visor.util.VisorClusterGroupEmptyException
org.apache.ignite.internal.visor.util.VisorEventMapper
org.apache.ignite.internal.visor.util.VisorExceptionWrapper
org.apache.ignite.internal.visor.util.VisorTaskUtils$4
+org.apache.ignite.internal.visor.tx.VisorTxInfo
+org.apache.ignite.internal.visor.tx.VisorTxOperation
+org.apache.ignite.internal.visor.tx.VisorTxProjection
+org.apache.ignite.internal.visor.tx.VisorTxSortOrder
+org.apache.ignite.internal.visor.tx.VisorTxTask
+org.apache.ignite.internal.visor.tx.VisorTxTaskArg
+org.apache.ignite.internal.visor.tx.VisorTxTaskResult
org.apache.ignite.internal.websession.WebSessionAttributeProcessor
org.apache.ignite.internal.websession.WebSessionEntity
org.apache.ignite.lang.IgniteBiClosure
http://git-wip-us.apache.org/repos/asf/ignite/blob/2b5d2fc5/modules/core/src/test/java/org/apache/ignite/internal/TestRecordingCommunicationSpi.java
----------------------------------------------------------------------
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/TestRecordingCommunicationSpi.java b/modules/core/src/test/java/org/apache/ignite/internal/TestRecordingCommunicationSpi.java
index cf4f059..5d12d9a 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/TestRecordingCommunicationSpi.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/TestRecordingCommunicationSpi.java
@@ -105,7 +105,7 @@ public class TestRecordingCommunicationSpi extends TcpCommunicationSpi {
}
if (block) {
- ignite.log().info("Block message [node=" + node.id() +
+ ignite.log().info("Block message [node=" + node.id() + ", order=" + node.order() +
", msg=" + ioMsg.message() + ']');
blockedMsgs.add(new T2<>(node, ioMsg));
@@ -273,6 +273,7 @@ public class TestRecordingCommunicationSpi extends TcpCommunicationSpi {
for (T2<ClusterNode, GridIoMessage> msg : blockedMsgs) {
try {
ignite.log().info("Send blocked message [node=" + msg.get1().id() +
+ ", order=" + msg.get1().order() +
", msg=" + msg.get2().message() + ']');
super.sendMessage(msg.get1(), msg.get2());
http://git-wip-us.apache.org/repos/asf/ignite/blob/2b5d2fc5/modules/core/src/test/java/org/apache/ignite/internal/TransactionMetricsMxBeanImplTest.java
----------------------------------------------------------------------
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/TransactionMetricsMxBeanImplTest.java b/modules/core/src/test/java/org/apache/ignite/internal/TransactionMetricsMxBeanImplTest.java
index 80b0dc0..91bd9bc 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/TransactionMetricsMxBeanImplTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/TransactionMetricsMxBeanImplTest.java
@@ -100,7 +100,7 @@ public class TransactionMetricsMxBeanImplTest extends GridCommonAbstractTest {
awaitPartitionMapExchange();
- TransactionMetricsMxBean txMXBean = txMXBean(0);
+ TransactionMetricsMxBean txMXBean = txMetricsMXBean(0);
final IgniteCache<Integer, String> cache = ignite.cache(DEFAULT_CACHE_NAME);
@@ -176,7 +176,7 @@ public class TransactionMetricsMxBeanImplTest extends GridCommonAbstractTest {
IgniteEx primaryNode2 = startGrid(1);
IgniteEx nearNode = startGrid(2);
- TransactionMetricsMxBean txMXBeanBackup = txMXBean(2);
+ TransactionMetricsMxBean txMXBeanBackup = txMetricsMXBean(2);
awaitPartitionMapExchange();
@@ -285,10 +285,10 @@ public class TransactionMetricsMxBeanImplTest extends GridCommonAbstractTest {
/**
*
*/
- private TransactionMetricsMxBean txMXBean(int igniteInt) throws Exception {
+ private TransactionMetricsMxBean txMetricsMXBean(int igniteInt) throws Exception {
ObjectName mbeanName = U.makeMBeanName(
getTestIgniteInstanceName(igniteInt),
- "Transactions",
+ "TransactionMetrics",
TransactionMetricsMxBeanImpl.class.getSimpleName()
);
http://git-wip-us.apache.org/repos/asf/ignite/blob/2b5d2fc5/modules/core/src/test/java/org/apache/ignite/internal/TransactionsMXBeanImplTest.java
----------------------------------------------------------------------
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/TransactionsMXBeanImplTest.java b/modules/core/src/test/java/org/apache/ignite/internal/TransactionsMXBeanImplTest.java
new file mode 100644
index 0000000..d358c72
--- /dev/null
+++ b/modules/core/src/test/java/org/apache/ignite/internal/TransactionsMXBeanImplTest.java
@@ -0,0 +1,118 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal;
+
+import java.lang.management.ManagementFactory;
+import javax.management.MBeanServer;
+import javax.management.MBeanServerInvocationHandler;
+import javax.management.ObjectName;
+import org.apache.ignite.cache.CacheRebalanceMode;
+import org.apache.ignite.cache.affinity.rendezvous.RendezvousAffinityFunction;
+import org.apache.ignite.configuration.CacheConfiguration;
+import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.internal.util.typedef.internal.U;
+import org.apache.ignite.mxbean.TransactionsMXBean;
+import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi;
+import org.apache.ignite.spi.discovery.tcp.ipfinder.TcpDiscoveryIpFinder;
+import org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder;
+import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
+
+import static org.apache.ignite.cache.CacheAtomicityMode.TRANSACTIONAL;
+import static org.apache.ignite.cache.CacheWriteSynchronizationMode.FULL_SYNC;
+
+/**
+ *
+ */
+public class TransactionsMXBeanImplTest extends GridCommonAbstractTest {
+ /** */
+ private static final TcpDiscoveryIpFinder IP_FINDER = new TcpDiscoveryVmIpFinder(true);
+
+ /** {@inheritDoc} */
+ @Override protected void afterTest() throws Exception {
+ stopAllGrids();
+
+ super.afterTest();
+ }
+
+ /** {@inheritDoc} */
+ @Override protected IgniteConfiguration getConfiguration(String name) throws Exception {
+ final IgniteConfiguration cfg = super.getConfiguration(name);
+
+ ((TcpDiscoverySpi)cfg.getDiscoverySpi()).setIpFinder(IP_FINDER);
+
+ cfg.setCommunicationSpi(new TestRecordingCommunicationSpi());
+
+ final CacheConfiguration cCfg = new CacheConfiguration()
+ .setName(DEFAULT_CACHE_NAME)
+ .setAffinity(new RendezvousAffinityFunction(false, 32))
+ .setBackups(1)
+ .setAtomicityMode(TRANSACTIONAL)
+ .setRebalanceMode(CacheRebalanceMode.ASYNC)
+ .setWriteSynchronizationMode(FULL_SYNC);
+
+ cfg.setCacheConfiguration(cCfg);
+
+ return cfg;
+ }
+
+ /**
+ *
+ */
+ public void testBasic() throws Exception {
+ IgniteEx ignite = startGrid(0);
+
+ TransactionsMXBean bean = txMXBean(0);
+
+ ignite.transactions().txStart();
+
+ ignite.cache(DEFAULT_CACHE_NAME).put(0, 0);
+
+ String res = bean.getActiveTransactions(null, null, null, null, null, null, null, null, false, false);
+
+ assertEquals("1", res);
+
+ res = bean.getActiveTransactions(null, null, null, null, null, null, null, null, true, false);
+
+ assertTrue(res.indexOf("Tx:") > 0);
+
+ res = bean.getActiveTransactions(null, null, null, null, null, null, null, null, false, true);
+
+ assertEquals("1", res);
+
+ doSleep(500);
+
+ res = bean.getActiveTransactions(null, null, null, null, null, null, null, null, false, false);
+
+ assertEquals("0", res);
+ }
+
+ /**
+ *
+ */
+ private TransactionsMXBean txMXBean(int igniteInt) throws Exception {
+ ObjectName mbeanName = U.makeMBeanName(getTestIgniteInstanceName(igniteInt), "Transactions",
+ TransactionsMXBeanImpl.class.getSimpleName());
+
+ MBeanServer mbeanSrv = ManagementFactory.getPlatformMBeanServer();
+
+ if (!mbeanSrv.isRegistered(mbeanName))
+ fail("MBean is not registered: " + mbeanName.getCanonicalName());
+
+ return MBeanServerInvocationHandler.newProxyInstance(mbeanSrv, mbeanName, TransactionsMXBean.class, true);
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/2b5d2fc5/modules/core/src/test/java/org/apache/ignite/internal/commandline/CommandHandlerParsingTest.java
----------------------------------------------------------------------
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/commandline/CommandHandlerParsingTest.java b/modules/core/src/test/java/org/apache/ignite/internal/commandline/CommandHandlerParsingTest.java
index cfbf1a6..049500a 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/commandline/CommandHandlerParsingTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/commandline/CommandHandlerParsingTest.java
@@ -19,7 +19,11 @@
package org.apache.ignite.internal.commandline;
+import java.util.Arrays;
import junit.framework.TestCase;
+import org.apache.ignite.internal.visor.tx.VisorTxProjection;
+import org.apache.ignite.internal.visor.tx.VisorTxSortOrder;
+import org.apache.ignite.internal.visor.tx.VisorTxTaskArg;
import static java.util.Arrays.asList;
import static org.apache.ignite.internal.commandline.CommandHandler.DFLT_HOST;
@@ -109,4 +113,100 @@ public class CommandHandlerParsingTest extends TestCase {
}
}
}
+
+ /**
+ * test parsing dump transaction arguments
+ */
+ @SuppressWarnings("Null")
+ public void testTransactionArguments() {
+ CommandHandler hnd = new CommandHandler();
+ Arguments args;
+
+ args = hnd.parseAndValidate(asList("--tx"));
+
+ try {
+ hnd.parseAndValidate(asList("--tx", "minDuration"));
+
+ fail("Expected exception");
+ }
+ catch (IllegalArgumentException ignored) {
+ }
+
+ try {
+ hnd.parseAndValidate(asList("--tx", "minDuration", "-1"));
+
+ fail("Expected exception");
+ }
+ catch (IllegalArgumentException ignored) {
+ }
+
+ try {
+ hnd.parseAndValidate(asList("--tx", "minSize"));
+
+ fail("Expected exception");
+ }
+ catch (IllegalArgumentException ignored) {
+ }
+
+ try {
+ hnd.parseAndValidate(asList("--tx", "minSize", "-1"));
+
+ fail("Expected exception");
+ }
+ catch (IllegalArgumentException ignored) {
+ }
+
+ try {
+ hnd.parseAndValidate(asList("--tx", "label"));
+
+ fail("Expected exception");
+ }
+ catch (IllegalArgumentException ignored) {
+ }
+
+ try {
+ hnd.parseAndValidate(asList("--tx", "label", "tx123["));
+
+ fail("Expected exception");
+ }
+ catch (IllegalArgumentException ignored) {
+ }
+
+ try {
+ hnd.parseAndValidate(asList("--tx", "servers", "nodes", "1,2,3"));
+
+ fail("Expected exception");
+ }
+ catch (IllegalArgumentException ignored) {
+ }
+
+ args = hnd.parseAndValidate(asList("--tx", "minDuration", "120", "minSize", "10", "limit", "100", "order", "SIZE",
+ "servers"));
+
+ VisorTxTaskArg arg = args.transactionArguments();
+
+ assertEquals(Long.valueOf(120 * 1000L), arg.getMinDuration());
+ assertEquals(Integer.valueOf(10), arg.getMinSize());
+ assertEquals(Integer.valueOf(100), arg.getLimit());
+ assertEquals(VisorTxSortOrder.SIZE, arg.getSortOrder());
+ assertEquals(VisorTxProjection.SERVER, arg.getProjection());
+
+ args = hnd.parseAndValidate(asList("--tx", "minDuration", "130", "minSize", "1", "limit", "60", "order", "DURATION",
+ "clients"));
+
+ arg = args.transactionArguments();
+
+ assertEquals(Long.valueOf(130 * 1000L), arg.getMinDuration());
+ assertEquals(Integer.valueOf(1), arg.getMinSize());
+ assertEquals(Integer.valueOf(60), arg.getLimit());
+ assertEquals(VisorTxSortOrder.DURATION, arg.getSortOrder());
+ assertEquals(VisorTxProjection.CLIENT, arg.getProjection());
+
+ args = hnd.parseAndValidate(asList("--tx", "nodes", "1,2,3"));
+
+ arg = args.transactionArguments();
+
+ assertNull(arg.getProjection());
+ assertEquals(Arrays.asList("1", "2", "3"), arg.getConsistentIds());
+ }
}
http://git-wip-us.apache.org/repos/asf/ignite/blob/2b5d2fc5/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheGetEntryPessimisticRepeatableReadSeltTest.java
----------------------------------------------------------------------
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheGetEntryPessimisticRepeatableReadSeltTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheGetEntryPessimisticRepeatableReadSeltTest.java
index dac64d9..4aa693c 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheGetEntryPessimisticRepeatableReadSeltTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheGetEntryPessimisticRepeatableReadSeltTest.java
@@ -33,4 +33,8 @@ public class CacheGetEntryPessimisticRepeatableReadSeltTest extends CacheGetEntr
@Override protected TransactionIsolation isolation() {
return TransactionIsolation.REPEATABLE_READ;
}
-}
\ No newline at end of file
+
+ @Override public void testReplicatedTransactional() throws Exception {
+ super.testReplicatedTransactional();
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/2b5d2fc5/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/SetTxTimeoutOnPartitionMapExchangeTest.java
----------------------------------------------------------------------
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/SetTxTimeoutOnPartitionMapExchangeTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/SetTxTimeoutOnPartitionMapExchangeTest.java
new file mode 100644
index 0000000..3152349
--- /dev/null
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/SetTxTimeoutOnPartitionMapExchangeTest.java
@@ -0,0 +1,166 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.processors.cache;
+
+import java.lang.management.ManagementFactory;
+import javax.management.MBeanServer;
+import javax.management.MBeanServerInvocationHandler;
+import javax.management.ObjectName;
+import org.apache.ignite.Ignite;
+import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.configuration.TransactionConfiguration;
+import org.apache.ignite.internal.IgniteEx;
+import org.apache.ignite.internal.IgniteInterruptedCheckedException;
+import org.apache.ignite.internal.TransactionsMXBeanImpl;
+import org.apache.ignite.internal.util.lang.GridAbsPredicate;
+import org.apache.ignite.internal.util.typedef.G;
+import org.apache.ignite.internal.util.typedef.internal.U;
+import org.apache.ignite.mxbean.TransactionsMXBean;
+import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi;
+import org.apache.ignite.spi.discovery.tcp.ipfinder.TcpDiscoveryIpFinder;
+import org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder;
+import org.apache.ignite.testframework.GridTestUtils;
+import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
+
+/**
+ *
+ */
+public class SetTxTimeoutOnPartitionMapExchangeTest extends GridCommonAbstractTest {
+ /** */
+ private static final TcpDiscoveryIpFinder ipFinder = new TcpDiscoveryVmIpFinder(true);
+
+ /** Wait condition timeout. */
+ private static final long WAIT_CONDITION_TIMEOUT = 10_000L;
+
+ /** {@inheritDoc} */
+ @Override protected void afterTest() throws Exception {
+ super.afterTest();
+
+ stopAllGrids();
+ }
+
+ /** {@inheritDoc} */
+ @SuppressWarnings("unchecked")
+ @Override protected IgniteConfiguration getConfiguration(String igniteInstanceName) throws Exception {
+ IgniteConfiguration cfg = super.getConfiguration(igniteInstanceName);
+
+ ((TcpDiscoverySpi)cfg.getDiscoverySpi()).setIpFinder(ipFinder);
+
+ return cfg;
+ }
+
+ /**
+ *
+ */
+ public void testDefaultTxTimeoutOnPartitionMapExchange() throws Exception {
+ IgniteEx ig1 = startGrid(1);
+ IgniteEx ig2 = startGrid(2);
+
+ TransactionConfiguration txCfg1 = ig1.configuration().getTransactionConfiguration();
+ TransactionConfiguration txCfg2 = ig2.configuration().getTransactionConfiguration();
+
+ final long expDfltTimeout = TransactionConfiguration.TX_TIMEOUT_ON_PARTITION_MAP_EXCHANGE;
+
+ assertEquals(expDfltTimeout, txCfg1.getTxTimeoutOnPartitionMapExchange());
+ assertEquals(expDfltTimeout, txCfg2.getTxTimeoutOnPartitionMapExchange());
+ }
+
+ /**
+ *
+ */
+ public void testJmxSetTxTimeoutOnPartitionMapExchange() throws Exception {
+ startGrid(1);
+ startGrid(2);
+
+ TransactionsMXBean mxBean1 = txMXBean(1);
+ TransactionsMXBean mxBean2 = txMXBean(2);
+
+ final long expTimeout1 = 20_000L;
+ final long expTimeout2 = 30_000L;
+
+ mxBean1.setTxTimeoutOnPartitionMapExchange(expTimeout1);
+ assertTxTimeoutOnPartitionMapExchange(expTimeout1);
+ assertEquals(expTimeout1, mxBean1.getTxTimeoutOnPartitionMapExchange());
+
+ mxBean2.setTxTimeoutOnPartitionMapExchange(expTimeout2);
+ assertTxTimeoutOnPartitionMapExchange(expTimeout2);
+ assertEquals(expTimeout2, mxBean2.getTxTimeoutOnPartitionMapExchange());
+ }
+
+ /**
+ *
+ */
+ public void testClusterSetTxTimeoutOnPartitionMapExchange() throws Exception {
+ Ignite ig1 = startGrid(1);
+ Ignite ig2 = startGrid(2);
+
+ final long expTimeout1 = 20_000L;
+ final long expTimeout2 = 30_000L;
+
+ ig1.cluster().setTxTimeoutOnPartitionMapExchange(expTimeout1);
+ assertTxTimeoutOnPartitionMapExchange(expTimeout1);
+
+ ig2.cluster().setTxTimeoutOnPartitionMapExchange(expTimeout2);
+ assertTxTimeoutOnPartitionMapExchange(expTimeout2);
+ }
+
+ /**
+ *
+ */
+ private TransactionsMXBean txMXBean(int igniteInt) throws Exception {
+ ObjectName mbeanName = U.makeMBeanName(getTestIgniteInstanceName(igniteInt), "Transactions",
+ TransactionsMXBeanImpl.class.getSimpleName());
+
+ MBeanServer mbeanSrv = ManagementFactory.getPlatformMBeanServer();
+
+ if (!mbeanSrv.isRegistered(mbeanName))
+ fail("MBean is not registered: " + mbeanName.getCanonicalName());
+
+ return MBeanServerInvocationHandler.newProxyInstance(mbeanSrv, mbeanName, TransactionsMXBean.class, true);
+ }
+
+ /**
+ * Checking the transaction timeout on all grids.
+ *
+ * @param expTimeout Expected timeout.
+ * @throws IgniteInterruptedCheckedException If failed.
+ */
+ private void assertTxTimeoutOnPartitionMapExchange(final long expTimeout)
+ throws IgniteInterruptedCheckedException {
+
+ assertTrue(GridTestUtils.waitForCondition(new GridAbsPredicate() {
+ @Override public boolean apply() {
+ for (Ignite ignite : G.allGrids()) {
+ long actualTimeout = ignite.configuration()
+ .getTransactionConfiguration().getTxTimeoutOnPartitionMapExchange();
+
+ if (actualTimeout != expTimeout) {
+ log.warning(String.format(
+ "Wrong transaction timeout on partition map exchange [grid=%s, timeout=%d, expected=%d]",
+ ignite.name(), actualTimeout, expTimeout));
+
+ return false;
+ }
+ }
+
+ return true;
+
+ }
+ }, WAIT_CONDITION_TIMEOUT));
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/2b5d2fc5/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/CacheLateAffinityAssignmentTest.java
----------------------------------------------------------------------
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/CacheLateAffinityAssignmentTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/CacheLateAffinityAssignmentTest.java
index e456047..787095e 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/CacheLateAffinityAssignmentTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/CacheLateAffinityAssignmentTest.java
@@ -219,11 +219,6 @@ public class CacheLateAffinityAssignmentTest extends GridCommonAbstractTest {
parts == null ? RendezvousAffinityFunction.DFLT_PARTITION_COUNT : parts);
}
- @Override
- protected void beforeTest() throws Exception {
- super.beforeTest();
- }
-
/** {@inheritDoc} */
@Override protected void afterTest() throws Exception {
try {
http://git-wip-us.apache.org/repos/asf/ignite/blob/2b5d2fc5/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/IgniteTxRemoveTimeoutObjectsNearTest.java
----------------------------------------------------------------------
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/IgniteTxRemoveTimeoutObjectsNearTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/IgniteTxRemoveTimeoutObjectsNearTest.java
new file mode 100644
index 0000000..fe8b1fb
--- /dev/null
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/IgniteTxRemoveTimeoutObjectsNearTest.java
@@ -0,0 +1,30 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.processors.cache.distributed;
+
+import org.apache.ignite.configuration.NearCacheConfiguration;
+
+/**
+ * Test correctness of rollback a transaction with timeout during the grid stop.
+ */
+public class IgniteTxRemoveTimeoutObjectsNearTest extends IgniteTxRemoveTimeoutObjectsTest {
+ /** {@inheritDoc} */
+ @Override protected NearCacheConfiguration nearConfiguration() {
+ return new NearCacheConfiguration();
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/2b5d2fc5/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/IgniteTxRemoveTimeoutObjectsTest.java
----------------------------------------------------------------------
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/IgniteTxRemoveTimeoutObjectsTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/IgniteTxRemoveTimeoutObjectsTest.java
index 752d854..5713621 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/IgniteTxRemoveTimeoutObjectsTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/IgniteTxRemoveTimeoutObjectsTest.java
@@ -22,6 +22,7 @@ import java.util.Map;
import java.util.Set;
import org.apache.ignite.Ignite;
import org.apache.ignite.IgniteCache;
+import org.apache.ignite.configuration.NearCacheConfiguration;
import org.apache.ignite.internal.IgniteEx;
import org.apache.ignite.internal.IgniteInterruptedCheckedException;
import org.apache.ignite.internal.processors.cache.GridCacheAbstractSelfTest;
@@ -205,4 +206,9 @@ public class IgniteTxRemoveTimeoutObjectsTest extends GridCacheAbstractSelfTest
return GridTestUtils.getFieldValue(timeout, timeout.getClass(), "timeoutObjs");
}
+
+ /** {@inheritDoc} */
+ @Override protected NearCacheConfiguration nearConfiguration() {
+ return null;
+ }
}
http://git-wip-us.apache.org/repos/asf/ignite/blob/2b5d2fc5/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/dht/IgniteCachePrimaryNodeFailureRecoveryAbstractTest.java
----------------------------------------------------------------------
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/dht/IgniteCachePrimaryNodeFailureRecoveryAbstractTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/dht/IgniteCachePrimaryNodeFailureRecoveryAbstractTest.java
index d147d31..00f9729 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/dht/IgniteCachePrimaryNodeFailureRecoveryAbstractTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/dht/IgniteCachePrimaryNodeFailureRecoveryAbstractTest.java
@@ -481,7 +481,7 @@ public abstract class IgniteCachePrimaryNodeFailureRecoveryAbstractTest extends
@Override public boolean apply() {
GridDhtTxLocal locTx = null;
- for (IgniteInternalTx tx : tm.txs()) {
+ for (IgniteInternalTx tx : tm.activeTransactions()) {
if (tx instanceof GridDhtTxLocal) {
assertNull("Only one tx is expected.", locTx);
http://git-wip-us.apache.org/repos/asf/ignite/blob/2b5d2fc5/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/dht/IgniteCacheTxRecoveryRollbackTest.java
----------------------------------------------------------------------
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/dht/IgniteCacheTxRecoveryRollbackTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/dht/IgniteCacheTxRecoveryRollbackTest.java
index b644cda..11c4c67 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/dht/IgniteCacheTxRecoveryRollbackTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/dht/IgniteCacheTxRecoveryRollbackTest.java
@@ -98,7 +98,7 @@ public class IgniteCacheTxRecoveryRollbackTest extends GridCommonAbstractTest {
@Override protected void afterTest() throws Exception {
try {
for (Ignite node : G.allGrids()) {
- Collection<IgniteInternalTx> txs = ((IgniteKernal)node).context().cache().context().tm().txs();
+ Collection<IgniteInternalTx> txs = ((IgniteKernal)node).context().cache().context().tm().activeTransactions();
assertTrue("Unfinished txs [node=" + node.name() + ", txs=" + txs + ']', txs.isEmpty());
}
http://git-wip-us.apache.org/repos/asf/ignite/blob/2b5d2fc5/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/near/GridCacheNearTxMultiNodeSelfTest.java
----------------------------------------------------------------------
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/near/GridCacheNearTxMultiNodeSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/near/GridCacheNearTxMultiNodeSelfTest.java
index 0ca10f8..07ee991 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/near/GridCacheNearTxMultiNodeSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/near/GridCacheNearTxMultiNodeSelfTest.java
@@ -242,7 +242,7 @@ public class GridCacheNearTxMultiNodeSelfTest extends GridCommonAbstractTest {
*/
@SuppressWarnings( {"unchecked"})
private void checkTm(Ignite g, IgniteTxManager tm) {
- Collection<IgniteInternalTx> txs = tm.txs();
+ Collection<IgniteInternalTx> txs = tm.activeTransactions();
info(">>> Number of transactions in the set [size=" + txs.size() +
", nodeId=" + g.cluster().localNode().id() + ']');
http://git-wip-us.apache.org/repos/asf/ignite/blob/2b5d2fc5/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/near/GridCachePartitionedTxSalvageSelfTest.java
----------------------------------------------------------------------
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/near/GridCachePartitionedTxSalvageSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/near/GridCachePartitionedTxSalvageSelfTest.java
index 256e8da..2e4ad92 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/near/GridCachePartitionedTxSalvageSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/near/GridCachePartitionedTxSalvageSelfTest.java
@@ -181,8 +181,8 @@ public class GridCachePartitionedTxSalvageSelfTest extends GridCommonAbstractTes
List<Integer> dhtSizes = new ArrayList<>(GRID_CNT - 1);
for (int i = 1; i < GRID_CNT; i++) {
- nearSizes.add(near(i).context().tm().txs().size());
- dhtSizes.add(dht(i).context().tm().txs().size());
+ nearSizes.add(near(i).context().tm().activeTransactions().size());
+ dhtSizes.add(dht(i).context().tm().activeTransactions().size());
}
stopNodeAndSleep(SALVAGE_TIMEOUT - DELTA_BEFORE);
@@ -247,7 +247,7 @@ public class GridCachePartitionedTxSalvageSelfTest extends GridCommonAbstractTes
* @param ctx Cache context.
*/
private void checkTxsEmpty(GridCacheContext ctx) {
- Collection txs = ctx.tm().txs();
+ Collection txs = ctx.tm().activeTransactions();
assert txs.isEmpty() : "Not all transactions were salvaged: " + txs;
}
@@ -259,7 +259,7 @@ public class GridCachePartitionedTxSalvageSelfTest extends GridCommonAbstractTes
* @param exp Expected amount of transactions.
*/
private void checkTxsNotEmpty(GridCacheContext ctx, int exp) {
- int size = ctx.tm().txs().size();
+ int size = ctx.tm().activeTransactions().size();
assertEquals("Some transactions were salvaged unexpectedly", exp, size);
}
http://git-wip-us.apache.org/repos/asf/ignite/blob/2b5d2fc5/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/local/GridCacheLocalTxMultiThreadedSelfTest.java
----------------------------------------------------------------------
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/local/GridCacheLocalTxMultiThreadedSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/local/GridCacheLocalTxMultiThreadedSelfTest.java
index 9e46b40..388a7bf 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/local/GridCacheLocalTxMultiThreadedSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/local/GridCacheLocalTxMultiThreadedSelfTest.java
@@ -73,7 +73,7 @@ public class GridCacheLocalTxMultiThreadedSelfTest extends IgniteTxMultiThreaded
/** {@inheritDoc} */
@Override protected int threadCount() {
- return 8;
+ return 2;
}
/** {@inheritDoc} */
http://git-wip-us.apache.org/repos/asf/ignite/blob/2b5d2fc5/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/transactions/TxLabelTest.java
----------------------------------------------------------------------
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/transactions/TxLabelTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/transactions/TxLabelTest.java
new file mode 100644
index 0000000..d89ba0b
--- /dev/null
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/transactions/TxLabelTest.java
@@ -0,0 +1,63 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.processors.cache.transactions;
+
+import org.apache.ignite.Ignite;
+import org.apache.ignite.internal.processors.cache.GridCacheAbstractSelfTest;
+import org.apache.ignite.transactions.Transaction;
+
+/**
+ * Tests transaction labels.
+ */
+public class TxLabelTest extends GridCacheAbstractSelfTest {
+ /**
+ * Tests transaction labels.
+ */
+ public void testLabel() {
+ testLabel0(grid(0), "lbl0");
+ testLabel0(grid(0), "lbl1");
+
+ try {
+ testLabel0(grid(0), null);
+
+ fail();
+ }
+ catch (Exception e) {
+ // Expected.
+ }
+ }
+
+ /**
+ * @param ignite Ignite.
+ * @param lbl Label.
+ */
+ private void testLabel0(Ignite ignite, String lbl) {
+ try(Transaction tx = ignite.transactions().withLabel(lbl).txStart()) {
+ assertEquals(lbl, tx.label());
+
+ ignite.cache(DEFAULT_CACHE_NAME).put(0, 0);
+
+ tx.commit();
+ }
+ }
+
+ /** {@inheritDoc} */
+ @Override protected int gridCount() {
+ return 1;
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/2b5d2fc5/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/transactions/TxMultiCacheAsyncOpsTest.java
----------------------------------------------------------------------
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/transactions/TxMultiCacheAsyncOpsTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/transactions/TxMultiCacheAsyncOpsTest.java
new file mode 100644
index 0000000..261af70
--- /dev/null
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/transactions/TxMultiCacheAsyncOpsTest.java
@@ -0,0 +1,140 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.processors.cache.transactions;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+import org.apache.ignite.configuration.CacheConfiguration;
+import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.lang.IgniteFuture;
+import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
+import org.apache.ignite.transactions.Transaction;
+
+import static org.apache.ignite.cache.CacheAtomicityMode.TRANSACTIONAL;
+import static org.apache.ignite.cache.CacheWriteSynchronizationMode.FULL_SYNC;
+
+/**
+ *
+ */
+public class TxMultiCacheAsyncOpsTest extends GridCommonAbstractTest {
+ /** Grid count. */
+ public static final int GRID_COUNT = 3;
+
+ /** Caches count. */
+ public static final int CACHES_CNT = 3;
+
+ /** {@inheritDoc} */
+ @Override protected IgniteConfiguration getConfiguration(String igniteInstanceName) throws Exception {
+ IgniteConfiguration cfg = super.getConfiguration(igniteInstanceName);
+
+ cfg.setCacheConfiguration(cacheConfigurations());
+
+ return cfg;
+ }
+
+ /** */
+ private CacheConfiguration[] cacheConfigurations() {
+ return IntStream.range(0, CACHES_CNT).mapToObj(
+ this::cacheConfiguration).collect(Collectors.toList()).toArray(new CacheConfiguration[CACHES_CNT]);
+ }
+
+ /**
+ * @param idx Index.
+ */
+ private CacheConfiguration cacheConfiguration(int idx) {
+ CacheConfiguration ccfg = new CacheConfiguration(DEFAULT_CACHE_NAME + idx);
+
+ ccfg.setAtomicityMode(TRANSACTIONAL);
+ ccfg.setBackups(2);
+ ccfg.setWriteSynchronizationMode(FULL_SYNC);
+ ccfg.setOnheapCacheEnabled(false);
+
+ return ccfg;
+ }
+
+ /** {@inheritDoc} */
+ @Override protected void beforeTestsStarted() throws Exception {
+ startGridsMultiThreaded(GRID_COUNT);
+ }
+
+ /** {@inheritDoc} */
+ @Override protected void afterTestsStopped() throws Exception {
+ super.afterTestsStopped();
+
+ stopAllGrids();
+ }
+
+ /**
+ *
+ */
+ public void testCommitAfterAsyncPut() {
+ CacheConfiguration[] caches = cacheConfigurations();
+
+ try {
+ for (int i = 0; i < caches.length; i++)
+ grid(0).cache(caches[i].getName()).put(1, i + 1);
+
+ try (Transaction tx = grid(0).transactions().txStart()) {
+ for (int i = 0; i < caches.length; i++)
+ grid(0).cache(caches[i].getName()).putAsync(1, (i + 1) * 10);
+
+ tx.commit();
+ }
+ catch (Exception e) {
+ System.out.println();
+ }
+
+ for (int i = 0; i < caches.length; i++)
+ assertEquals((i + 1) * 10, grid(0).cache(caches[i].getName()).get(1));
+ }
+ finally {
+ for (int i = 0; i < caches.length; i++)
+ grid(0).cache(caches[i].getName()).removeAll();
+ }
+ }
+
+ /**
+ *
+ */
+ public void testCommitAfterAsyncGet() {
+ CacheConfiguration[] caches = cacheConfigurations();
+
+ try {
+ for (int i = 0; i < caches.length; i++)
+ grid(0).cache(caches[i].getName()).put(1, i + 1);
+
+ List<IgniteFuture> futs = new ArrayList<>();
+
+ try (Transaction tx = grid(0).transactions().txStart()) {
+ for (int i = 0; i < caches.length; i++)
+ futs.add(grid(0).cache(caches[i].getName()).getAsync(1));
+
+ tx.commit();
+ }
+
+ for (int i = 0; i < futs.size(); i++)
+ assertEquals(i + 1, futs.get(i).get());
+ }
+ finally {
+ for (int i = 0; i < caches.length; i++)
+ grid(0).cache(caches[i].getName()).removeAll();
+ }
+ }
+}
[2/6] ignite git commit: IGNITE-6827 Configurable rollback for long
running transactions before partition exchange IGNITE-7910 Improved
transaction debugging support
Posted by ag...@apache.org.
http://git-wip-us.apache.org/repos/asf/ignite/blob/2b5d2fc5/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/transactions/TxOptimisticPrepareOnUnstableTopologyTest.java
----------------------------------------------------------------------
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/transactions/TxOptimisticPrepareOnUnstableTopologyTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/transactions/TxOptimisticPrepareOnUnstableTopologyTest.java
new file mode 100644
index 0000000..cb371cf
--- /dev/null
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/transactions/TxOptimisticPrepareOnUnstableTopologyTest.java
@@ -0,0 +1,250 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.processors.cache.transactions;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.TreeMap;
+import java.util.concurrent.ThreadLocalRandom;
+import java.util.concurrent.TimeUnit;
+import org.apache.ignite.Ignite;
+import org.apache.ignite.IgniteCache;
+import org.apache.ignite.configuration.CacheConfiguration;
+import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.internal.IgniteEx;
+import org.apache.ignite.internal.IgniteKernal;
+import org.apache.ignite.internal.util.typedef.G;
+import org.apache.ignite.internal.util.typedef.internal.U;
+import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi;
+import org.apache.ignite.spi.discovery.tcp.ipfinder.TcpDiscoveryIpFinder;
+import org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder;
+import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
+import org.apache.ignite.transactions.Transaction;
+import org.apache.ignite.transactions.TransactionConcurrency;
+import org.apache.ignite.transactions.TransactionIsolation;
+
+import static org.apache.ignite.cache.CacheAtomicityMode.TRANSACTIONAL;
+import static org.apache.ignite.cache.CacheMode.PARTITIONED;
+import static org.apache.ignite.cache.CacheWriteSynchronizationMode.PRIMARY_SYNC;
+
+/**
+ * Tests optimistic prepare on unstable topology.
+ */
+public class TxOptimisticPrepareOnUnstableTopologyTest extends GridCommonAbstractTest {
+ /** */
+ public static final String CACHE_NAME = "part_cache";
+
+ /** IP finder. */
+ private static final TcpDiscoveryIpFinder ipFinder = new TcpDiscoveryVmIpFinder(true);
+
+ /** */
+ private volatile boolean run = true;
+
+ /** */
+ private boolean client;
+
+ /** {@inheritDoc} */
+ @Override protected void afterTestsStopped() throws Exception {
+ stopAllGrids();
+
+ assertEquals(0, G.allGrids().size());
+ }
+
+ /** {@inheritDoc} */
+ @Override protected IgniteConfiguration getConfiguration(String igniteInstanceName) throws Exception {
+ IgniteConfiguration c = super.getConfiguration(igniteInstanceName);
+
+ TcpDiscoverySpi disco = new TcpDiscoverySpi();
+
+ disco.setIpFinder(ipFinder);
+
+ c.setDiscoverySpi(disco);
+
+ CacheConfiguration ccfg = new CacheConfiguration(DEFAULT_CACHE_NAME);
+
+ ccfg.setName(CACHE_NAME);
+ ccfg.setAtomicityMode(TRANSACTIONAL);
+ ccfg.setWriteSynchronizationMode(PRIMARY_SYNC);
+ ccfg.setBackups(2);
+ ccfg.setCacheMode(PARTITIONED);
+
+ c.setCacheConfiguration(ccfg);
+
+ c.setClientMode(client);
+
+ return c;
+ }
+
+ /**
+ *
+ */
+ public void testPrepareOnUnstableTopology() throws Exception {
+ for (TransactionIsolation isolation : TransactionIsolation.values()) {
+ doPrepareOnUnstableTopology(4, false, isolation, 0);
+ doPrepareOnUnstableTopology(4, true, isolation, 0);
+ doPrepareOnUnstableTopology(4, false, isolation, TimeUnit.DAYS.toMillis(1));
+ doPrepareOnUnstableTopology(4, true, isolation, TimeUnit.DAYS.toMillis(1));
+ }
+ }
+
+ /**
+ * @param keys Keys.
+ * @param testClient Test client.
+ * @param isolation Isolation.
+ * @param timeout Timeout.
+ */
+ private void doPrepareOnUnstableTopology(int keys, boolean testClient, TransactionIsolation isolation,
+ long timeout) throws Exception {
+ Collection<Thread> threads = new ArrayList<>();
+
+ try {
+ // Start grid 1.
+ IgniteEx grid1 = startGrid(0);
+
+ assertFalse(grid1.configuration().isClientMode());
+
+ threads.add(runCacheOperations(grid1, isolation, timeout, keys));
+
+ TimeUnit.SECONDS.sleep(3L);
+
+ client = testClient; // If test client start on node in client mode.
+
+ // Start grid 2.
+ IgniteEx grid2 = startGrid(1);
+
+ assertEquals((Object)testClient, grid2.configuration().isClientMode());
+
+ client = false;
+
+ threads.add(runCacheOperations(grid2, isolation, timeout, keys));
+
+ TimeUnit.SECONDS.sleep(3L);
+
+ // Start grid 3.
+ IgniteEx grid3 = startGrid(2);
+
+ assertFalse(grid3.configuration().isClientMode());
+
+ if (testClient)
+ log.info("Started client node: " + grid3.name());
+
+ threads.add(runCacheOperations(grid3, isolation, timeout, keys));
+
+ TimeUnit.SECONDS.sleep(3L);
+
+ // Start grid 4.
+ IgniteEx grid4 = startGrid(3);
+
+ assertFalse(grid4.configuration().isClientMode());
+
+ threads.add(runCacheOperations(grid4, isolation, timeout, keys));
+
+ TimeUnit.SECONDS.sleep(3L);
+
+ stopThreads(threads);
+
+ for (int i = 0; i < 4; i++) {
+ IgniteTxManager tm = ((IgniteKernal)grid(i)).internalCache(CACHE_NAME).context().tm();
+
+ assertEquals("txMap is not empty:" + i, 0, tm.idMapSize());
+ }
+ }
+ finally {
+ stopAllGrids();
+ }
+ }
+
+ /**
+ * @param threads Thread which will be stopped.
+ */
+ private void stopThreads(Iterable<Thread> threads) {
+ try {
+ run = false;
+
+ for (Thread thread : threads)
+ thread.join();
+ }
+ catch (Exception e) {
+ U.error(log(), "Couldn't stop threads.", e);
+ }
+ }
+
+ /**
+ * @param node Node.
+ * @param isolation Isolation.
+ * @param timeout Timeout.
+ * @param keys Number of keys.
+ * @return Running thread.
+ */
+ @SuppressWarnings("TypeMayBeWeakened")
+ private Thread runCacheOperations(Ignite node, TransactionIsolation isolation, long timeout, final int keys) {
+ Thread t = new Thread() {
+ @Override public void run() {
+ while (run) {
+ TreeMap<Integer, String> vals = generateValues(keys);
+
+ try {
+ try (Transaction tx = node.transactions().txStart(TransactionConcurrency.OPTIMISTIC, isolation,
+ timeout, keys)){
+
+ IgniteCache<Object, Object> cache = node.cache(CACHE_NAME);
+
+ // Put or remove.
+ if (ThreadLocalRandom.current().nextDouble(1) < 0.65)
+ cache.putAll(vals);
+ else
+ cache.removeAll(vals.keySet());
+
+ tx.commit();
+ }
+ catch (Exception e) {
+ U.error(log(), "Failed cache operation.", e);
+ }
+
+ U.sleep(100);
+ }
+ catch (Exception e){
+ U.error(log(), "Failed unlock.", e);
+ }
+ }
+ }
+ };
+
+ t.start();
+
+ return t;
+ }
+
+ /**
+ * @param cnt Number of keys to generate.
+ * @return Map.
+ */
+ private TreeMap<Integer, String> generateValues(int cnt) {
+ TreeMap<Integer, String> res = new TreeMap<>();
+
+ ThreadLocalRandom rnd = ThreadLocalRandom.current();
+
+ while (res.size() < cnt) {
+ int key = rnd.nextInt(0, 100);
+
+ res.put(key, String.valueOf(key));
+ }
+
+ return res;
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/2b5d2fc5/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/transactions/TxPessimisticDeadlockDetectionTest.java
----------------------------------------------------------------------
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/transactions/TxPessimisticDeadlockDetectionTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/transactions/TxPessimisticDeadlockDetectionTest.java
index 60f1c96..aab0b8e 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/transactions/TxPessimisticDeadlockDetectionTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/transactions/TxPessimisticDeadlockDetectionTest.java
@@ -107,7 +107,7 @@ public class TxPessimisticDeadlockDetectionTest extends AbstractDeadlockDetectio
client = false;
- startGrids(NODES_CNT);
+ startGridsMultiThreaded(NODES_CNT);
client = true;
http://git-wip-us.apache.org/repos/asf/ignite/blob/2b5d2fc5/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/transactions/TxRollbackAsyncNearCacheTest.java
----------------------------------------------------------------------
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/transactions/TxRollbackAsyncNearCacheTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/transactions/TxRollbackAsyncNearCacheTest.java
new file mode 100644
index 0000000..5caa1a0
--- /dev/null
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/transactions/TxRollbackAsyncNearCacheTest.java
@@ -0,0 +1,28 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.processors.cache.transactions;
+
+/**
+ * Tests an ability to async rollback near transactions.
+ */
+public class TxRollbackAsyncNearCacheTest extends TxRollbackAsyncTest {
+ /** {@inheritDoc} */
+ @Override protected boolean nearCacheEnabled() {
+ return true;
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/2b5d2fc5/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/transactions/TxRollbackAsyncTest.java
----------------------------------------------------------------------
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/transactions/TxRollbackAsyncTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/transactions/TxRollbackAsyncTest.java
new file mode 100644
index 0000000..3a8be49
--- /dev/null
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/transactions/TxRollbackAsyncTest.java
@@ -0,0 +1,938 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.processors.cache.transactions;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Random;
+import java.util.Set;
+import java.util.concurrent.Callable;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicIntegerArray;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.concurrent.atomic.LongAdder;
+import javax.cache.CacheException;
+import org.apache.ignite.Ignite;
+import org.apache.ignite.IgniteCheckedException;
+import org.apache.ignite.IgniteException;
+import org.apache.ignite.IgniteTransactions;
+import org.apache.ignite.cluster.ClusterNode;
+import org.apache.ignite.configuration.CacheConfiguration;
+import org.apache.ignite.configuration.DataRegionConfiguration;
+import org.apache.ignite.configuration.DataStorageConfiguration;
+import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.configuration.NearCacheConfiguration;
+import org.apache.ignite.internal.IgniteEx;
+import org.apache.ignite.internal.IgniteInternalFuture;
+import org.apache.ignite.internal.IgniteInterruptedCheckedException;
+import org.apache.ignite.internal.IgniteKernal;
+import org.apache.ignite.internal.TestRecordingCommunicationSpi;
+import org.apache.ignite.internal.processors.cache.GridCacheContext;
+import org.apache.ignite.internal.processors.cache.GridCacheFuture;
+import org.apache.ignite.internal.processors.cache.GridCacheSharedContext;
+import org.apache.ignite.internal.processors.cache.distributed.near.GridNearLockRequest;
+import org.apache.ignite.internal.processors.cache.distributed.near.GridNearTxFinishRequest;
+import org.apache.ignite.internal.processors.cache.distributed.near.GridNearTxLocal;
+import org.apache.ignite.internal.util.typedef.G;
+import org.apache.ignite.internal.util.typedef.X;
+import org.apache.ignite.internal.util.typedef.internal.CU;
+import org.apache.ignite.internal.util.typedef.internal.U;
+import org.apache.ignite.lang.IgniteBiPredicate;
+import org.apache.ignite.lang.IgniteFuture;
+import org.apache.ignite.lang.IgniteInClosure;
+import org.apache.ignite.lang.IgniteUuid;
+import org.apache.ignite.plugin.extensions.communication.Message;
+import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi;
+import org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder;
+import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
+import org.apache.ignite.transactions.Transaction;
+import org.apache.ignite.transactions.TransactionConcurrency;
+import org.apache.ignite.transactions.TransactionIsolation;
+import org.apache.ignite.transactions.TransactionRollbackException;
+
+import static java.lang.Thread.yield;
+import static org.apache.ignite.cache.CacheAtomicityMode.TRANSACTIONAL;
+import static org.apache.ignite.cache.CacheWriteSynchronizationMode.FULL_SYNC;
+import static org.apache.ignite.configuration.WALMode.LOG_ONLY;
+import static org.apache.ignite.testframework.GridTestUtils.runAsync;
+import static org.apache.ignite.transactions.TransactionConcurrency.OPTIMISTIC;
+import static org.apache.ignite.transactions.TransactionConcurrency.PESSIMISTIC;
+import static org.apache.ignite.transactions.TransactionIsolation.READ_COMMITTED;
+import static org.apache.ignite.transactions.TransactionIsolation.REPEATABLE_READ;
+import static org.apache.ignite.transactions.TransactionIsolation.SERIALIZABLE;
+import static org.apache.ignite.transactions.TransactionState.ROLLED_BACK;
+
+/**
+ * Tests an ability to async rollback near transactions.
+ */
+public class TxRollbackAsyncTest extends GridCommonAbstractTest {
+ /** */
+ public static final int DURATION = 60_000;
+
+ /** */
+ private static final String CACHE_NAME = "test";
+
+ /** IP finder. */
+ private static final TcpDiscoveryVmIpFinder IP_FINDER = new TcpDiscoveryVmIpFinder(true);
+
+ /** */
+ private static final int GRID_CNT = 3;
+
+ /** */
+ public static final long MB = 1024 * 1024;
+
+ /** */
+ public static final String LABEL = "wLockTx";
+
+ /** {@inheritDoc} */
+ @Override protected IgniteConfiguration getConfiguration(String igniteInstanceName) throws Exception {
+ IgniteConfiguration cfg = super.getConfiguration(igniteInstanceName);
+
+ ((TcpDiscoverySpi)cfg.getDiscoverySpi()).setIpFinder(IP_FINDER);
+
+ cfg.setCommunicationSpi(new TestRecordingCommunicationSpi());
+
+ boolean client = igniteInstanceName.startsWith("client");
+
+ cfg.setClientMode(client);
+
+ if (persistenceEnabled())
+ cfg.setDataStorageConfiguration(new DataStorageConfiguration().setWalMode(LOG_ONLY).setPageSize(1024).
+ setDefaultDataRegionConfiguration(new DataRegionConfiguration().setPersistenceEnabled(true).
+ setInitialSize(100 * MB).setMaxSize(100 * MB)));
+
+ if (!client) {
+ CacheConfiguration ccfg = new CacheConfiguration(CACHE_NAME);
+
+ if (nearCacheEnabled())
+ ccfg.setNearConfiguration(new NearCacheConfiguration());
+
+ ccfg.setAtomicityMode(TRANSACTIONAL);
+ ccfg.setBackups(2);
+ ccfg.setWriteSynchronizationMode(FULL_SYNC);
+ ccfg.setOnheapCacheEnabled(false);
+
+ cfg.setCacheConfiguration(ccfg);
+ }
+
+ return cfg;
+ }
+
+ /**
+ * @return Near cache flag.
+ */
+ protected boolean nearCacheEnabled() {
+ return false;
+ }
+
+ /**
+ *
+ * @return {@code True} if persistence must be enabled for test.
+ */
+ protected boolean persistenceEnabled() { return false; }
+
+ /** {@inheritDoc} */
+ @Override protected void beforeTest() throws Exception {
+ super.beforeTest();
+
+ final IgniteEx crd = startGrid(0);
+
+ startGridsMultiThreaded(1, GRID_CNT - 1);
+
+ crd.cluster().active(true);
+
+ awaitPartitionMapExchange();
+ }
+
+ /** {@inheritDoc} */
+ @Override protected void afterTest() throws Exception {
+ super.afterTest();
+
+ stopAllGrids();
+ }
+
+ /**
+ * @return Started client.
+ * @throws Exception If f nodeailed.
+ */
+ private Ignite startClient() throws Exception {
+ Ignite client = startGrid("client");
+
+ assertTrue(client.configuration().isClientMode());
+
+ if (nearCacheEnabled())
+ client.createNearCache(CACHE_NAME, new NearCacheConfiguration<>());
+ else
+ assertNotNull(client.cache(CACHE_NAME));
+
+ return client;
+ }
+
+ /**
+ *
+ */
+ public void testRollbackSimple() throws Exception {
+ startClient();
+
+ for (Ignite ignite : G.allGrids()) {
+ testRollbackSimple0(ignite);
+
+ ignite.cache(CACHE_NAME).clear();
+ }
+ }
+
+ /**
+ *
+ */
+ private void testRollbackSimple0(Ignite near) throws Exception {
+ // Normal rollback after put.
+ Transaction tx = near.transactions().txStart(PESSIMISTIC, READ_COMMITTED);
+
+ near.cache(CACHE_NAME).put(0, 0);
+
+ tx.rollback();
+
+ assertNull(near.cache(CACHE_NAME).get(0));
+
+ // Normal rollback before put.
+ tx = near.transactions().txStart();
+
+ tx.rollback();
+
+ near.cache(CACHE_NAME).put(0, 1);
+
+ assertEquals(1, near.cache(CACHE_NAME).get(0));
+
+ // Normal rollback async after put.
+ tx = near.transactions().txStart();
+
+ near.cache(CACHE_NAME).put(1, 0);
+
+ rollbackAsync(tx).get();
+
+ try {
+ assertNull(near.cache(CACHE_NAME).get(0));
+
+ fail();
+ }
+ catch (Exception e) {
+ // Expected.
+ }
+
+ try {
+ near.cache(CACHE_NAME).put(1, 1);
+
+ fail();
+ }
+ catch (Exception e) {
+ // Expected.
+ }
+
+ try {
+ near.cache(CACHE_NAME).remove(0);
+
+ fail();
+ }
+ catch (Exception e) {
+ // Expected.
+ }
+
+ // Normal rollback async before put.
+ tx = near.transactions().txStart();
+
+ rollbackAsync(tx).get();
+
+ try {
+ assertNull(near.cache(CACHE_NAME).get(0));
+
+ fail();
+ }
+ catch (Exception e) {
+ // Expected.
+ }
+
+ try {
+ near.cache(CACHE_NAME).put(1, 1);
+
+ fail();
+ }
+ catch (Exception e) {
+ // Expected.
+ }
+
+ try {
+ near.cache(CACHE_NAME).remove(0);
+
+ fail();
+ }
+ catch (Exception e) {
+ // Expected.
+ }
+
+ checkFutures();
+ }
+
+ /**
+ *
+ */
+ public void testSynchronousRollback() throws Exception {
+ Ignite client = startClient();
+
+ for (int i = 0; i < GRID_CNT; i++)
+ testSynchronousRollback0(grid(0), grid(i), false);
+
+ testSynchronousRollback0(grid(0), client, false);
+
+ for (int i = 0; i < GRID_CNT; i++)
+ testSynchronousRollback0(grid(0), grid(i), true);
+
+ testSynchronousRollback0(grid(0), client, true);
+
+ for (int i = 0; i < GRID_CNT; i++)
+ testSynchronousRollback0(grid(1), grid(i), false);
+
+ testSynchronousRollback0(grid(1), client, false);
+
+ for (int i = 0; i < GRID_CNT; i++)
+ testSynchronousRollback0(grid(1), grid(i), true);
+
+ testSynchronousRollback0(grid(1), client, true);
+ }
+
+ /**
+ *
+ * @param holdLockNode Node holding the write lock.
+ * @param tryLockNode Node trying to acquire lock.
+ * @param useTimeout {@code True} if need to start tx with timeout.
+ *
+ * @throws Exception If failed.
+ */
+ private void testSynchronousRollback0(Ignite holdLockNode, final Ignite tryLockNode, final boolean useTimeout) throws Exception {
+ final CountDownLatch keyLocked = new CountDownLatch(1);
+
+ CountDownLatch waitCommit = new CountDownLatch(1);
+
+ IgniteInternalFuture<?> lockFut = lockInTx(holdLockNode, keyLocked, waitCommit, 0);
+
+ U.awaitQuiet(keyLocked);
+
+ final CountDownLatch rollbackLatch = new CountDownLatch(1);
+
+ final int txCnt = 10000;
+
+ final IgniteKernal k = (IgniteKernal)tryLockNode;
+
+ final GridCacheSharedContext<Object, Object> ctx = k.context().cache().context();
+
+ final GridCacheContext<Object, Object> cctx = ctx.cacheContext(CU.cacheId(CACHE_NAME));
+
+ final AtomicBoolean stop = new AtomicBoolean();
+
+ IgniteInternalFuture<?> txFut = multithreadedAsync(new Runnable() {
+ @Override public void run() {
+ U.awaitQuiet(keyLocked);
+
+ for (int i = 0; i < txCnt; i++) {
+ GridNearTxLocal tx0 = ctx.tm().threadLocalTx(cctx);
+
+ assertTrue(tx0 == null || tx0.state() == ROLLED_BACK);
+
+ rollbackLatch.countDown();
+
+ try (Transaction tx = tryLockNode.transactions().txStart(PESSIMISTIC, REPEATABLE_READ,
+ useTimeout ? 500 : 0, 1)) {
+
+ // Will block on lock request until rolled back asynchronously.
+ Object o = tryLockNode.cache(CACHE_NAME).get(0);
+
+ assertNull(o); // If rolled back by close, previous get will return null.
+ }
+ catch (Exception e) {
+ // If rolled back by rollback, previous get will throw an exception.
+ }
+ }
+
+ stop.set(true);
+ }
+ }, 1, "tx-get-thread");
+
+ IgniteInternalFuture<?> rollbackFut = multithreadedAsync(new Runnable() {
+ @Override public void run() {
+ U.awaitQuiet(rollbackLatch);
+
+ doSleep(50);
+
+ Set<IgniteUuid> rolledBackVers = new HashSet<>();
+
+ int proc = 1;
+
+ while(!stop.get()) {
+ for (Transaction tx : tryLockNode.transactions().localActiveTransactions()) {
+ if (rolledBackVers.contains(tx.xid()))
+ fail("Rollback version is expected");
+
+ // Skip write transaction.
+ if (LABEL.equals(tx.label()))
+ continue;
+
+ try {
+ if (proc % 2 == 0)
+ tx.rollback();
+ else
+ tx.close();
+ }
+ catch (IgniteException e) {
+ log.warning("Got exception while rolling back a transaction", e);
+ }
+
+ rolledBackVers.add(tx.xid());
+
+ if (proc % 1000 == 0)
+ log.info("Rolled back: " + proc);
+
+ proc++;
+ }
+ }
+
+ assertEquals("Unexpected size", txCnt, rolledBackVers.size());
+ }
+ }, 1, "tx-rollback-thread");
+
+ rollbackFut.get();
+
+ txFut.get();
+
+ log.info("All transactions are rolled back: holdLockNode=" + holdLockNode + ", tryLockNode=" + tryLockNode);
+
+ waitCommit.countDown();
+
+ lockFut.get();
+
+ assertEquals(0, holdLockNode.cache(CACHE_NAME).get(0));
+
+ checkFutures();
+ }
+
+ /**
+ *
+ */
+ public void testEnlistManyRead() throws Exception {
+ testEnlistMany(false, REPEATABLE_READ, PESSIMISTIC);
+ }
+
+ /**
+ *
+ */
+ public void testEnlistManyWrite() throws Exception {
+ testEnlistMany(true, REPEATABLE_READ, PESSIMISTIC);
+ }
+
+ /**
+ *
+ */
+ public void testEnlistManyReadOptimistic() throws Exception {
+ testEnlistMany(false, SERIALIZABLE, OPTIMISTIC);
+ }
+
+ /**
+ *
+ */
+ public void testEnlistManyWriteOptimistic() throws Exception {
+ testEnlistMany(true, SERIALIZABLE, OPTIMISTIC);
+ }
+
+
+ /**
+ *
+ */
+ private void testEnlistMany(boolean write, TransactionIsolation isolation, TransactionConcurrency conc) throws Exception {
+ final Ignite client = startClient();
+
+ Map<Integer, Integer> entries = new HashMap<>();
+
+ for (int i = 0; i < 1000000; i++)
+ entries.put(i, i);
+
+ IgniteInternalFuture<?> fut = null;
+
+ try(Transaction tx = client.transactions().txStart(conc, isolation, 0, 0)) {
+ fut = rollbackAsync(tx, 200);
+
+ if (write)
+ client.cache(CACHE_NAME).putAll(entries);
+ else
+ client.cache(CACHE_NAME).getAll(entries.keySet());
+
+ tx.commit();
+
+ fail("Commit must fail");
+ }
+ catch (Throwable t) {
+ assertTrue(X.hasCause(t, TransactionRollbackException.class));
+ }
+
+ fut.get();
+
+ assertEquals(0, client.cache(CACHE_NAME).size());
+
+ checkFutures();
+ }
+
+ /**
+ * Rollback tx while near lock request is delayed.
+ */
+ public void testRollbackDelayNearLockRequest() throws Exception {
+ final Ignite client = startClient();
+
+ final Ignite prim = primaryNode(0, CACHE_NAME);
+
+ final TestRecordingCommunicationSpi spi = (TestRecordingCommunicationSpi)client.configuration().getCommunicationSpi();
+
+ spi.blockMessages(GridNearLockRequest.class, prim.name());
+
+ final IgniteInternalFuture<Void> rollbackFut = runAsync(new Callable<Void>() {
+ @Override public Void call() throws Exception {
+ spi.waitForBlocked();
+
+ client.transactions().localActiveTransactions().iterator().next().rollback();
+
+ return null;
+ }
+ }, "tx-rollback-thread");
+
+ try(final Transaction tx = client.transactions().txStart()) {
+ client.cache(CACHE_NAME).put(0, 0);
+
+ fail();
+ }
+ catch (CacheException e) {
+ assertTrue(X.hasCause(e, TransactionRollbackException.class));
+ }
+
+ rollbackFut.get();
+
+ spi.stopBlock(true);
+
+ doSleep(500);
+
+ checkFutures();
+ }
+
+ /**
+ * Tests rollback with concurrent commit.
+ */
+ public void testRollbackDelayFinishRequest() throws Exception {
+ final Ignite client = startClient();
+
+ final Ignite prim = primaryNode(0, CACHE_NAME);
+
+ final TestRecordingCommunicationSpi spi = (TestRecordingCommunicationSpi)client.configuration().getCommunicationSpi();
+
+ final AtomicReference<Transaction> txRef = new AtomicReference<>();
+
+ // Block commit request to primary node.
+ spi.blockMessages(new IgniteBiPredicate<ClusterNode, Message>() {
+ @Override public boolean apply(ClusterNode node, Message msg) {
+ if (msg instanceof GridNearTxFinishRequest) {
+ GridNearTxFinishRequest r = (GridNearTxFinishRequest)msg;
+
+ return r.commit() && node.equals(prim.cluster().localNode());
+ }
+
+ return false;
+ }
+ });
+
+ final IgniteInternalFuture<Void> rollbackFut = runAsync(new Callable<Void>() {
+ @Override public Void call() throws Exception {
+ spi.waitForBlocked();
+
+ final IgniteFuture<?> fut = txRef.get().rollbackAsync();
+
+ doSleep(500);
+
+ spi.stopBlock(true);
+
+ fut.get();
+
+ return null;
+ }
+ }, "tx-rollback-thread");
+
+ try(final Transaction tx = client.transactions().txStart()) {
+ txRef.set(tx);
+
+ client.cache(CACHE_NAME).put(0, 0);
+
+ tx.commit();
+ }
+ catch (CacheException e) {
+ assertTrue(X.hasCause(e, TransactionRollbackException.class));
+ }
+
+ rollbackFut.get();
+
+ doSleep(500);
+
+ checkFutures();
+ }
+
+ /**
+ *
+ */
+ public void testMixedAsyncRollbackTypes() throws Exception {
+ final Ignite client = startClient();
+
+ final AtomicBoolean stop = new AtomicBoolean();
+
+ final int threadCnt = Runtime.getRuntime().availableProcessors() * 2;
+
+ final int txSize = 200;
+
+ for (int k = 0; k < txSize; k++)
+ grid(0).cache(CACHE_NAME).put(k, (long)0);
+
+ final long seed = System.currentTimeMillis();
+
+ final Random r = new Random(seed);
+
+ log.info("Using seed: " + seed);
+
+ final TransactionConcurrency[] TC_VALS = TransactionConcurrency.values();
+ final TransactionIsolation[] TI_VALS = TransactionIsolation.values();
+
+ final LongAdder total = new LongAdder();
+ final LongAdder completed = new LongAdder();
+ final LongAdder failed = new LongAdder();
+ final LongAdder rolledBack = new LongAdder();
+
+ IgniteInternalFuture<?> txFut = multithreadedAsync(new Runnable() {
+ @Override public void run() {
+ while (!stop.get()) {
+ int nodeId = r.nextInt(GRID_CNT + 1);
+
+ // Choose random node to start tx on.
+ Ignite node = nodeId == GRID_CNT || nearCacheEnabled() ? client : grid(nodeId);
+
+ TransactionConcurrency conc = TC_VALS[r.nextInt(TC_VALS.length)];
+ TransactionIsolation isolation = TI_VALS[r.nextInt(TI_VALS.length)];
+
+ long timeout = r.nextInt(50) + 50; // Timeout is necessary to prevent deadlocks.
+
+ try (Transaction tx = node.transactions().txStart(conc, isolation, timeout, txSize)) {
+ int setSize = r.nextInt(txSize / 2) + 1;
+
+ for (int i = 0; i < setSize; i++) {
+ switch (r.nextInt(4)) {
+ case 0:
+ node.cache(CACHE_NAME).remove(r.nextInt(txSize));
+
+ break;
+
+ case 1:
+ node.cache(CACHE_NAME).get(r.nextInt(txSize));
+
+ break;
+
+ case 2:
+ final Integer v = (Integer)node.cache(CACHE_NAME).get(r.nextInt(txSize));
+
+ node.cache(CACHE_NAME).put(r.nextInt(txSize), (v == null ? 0 : v) + 1);
+
+ break;
+
+ case 3:
+ node.cache(CACHE_NAME).put(r.nextInt(txSize), 0);
+
+ break;
+
+ default:
+ fail("Unexpected opcode");
+ }
+ }
+
+ tx.commit();
+
+ completed.add(1);
+ }
+ catch (Throwable e) {
+ failed.add(1);
+ }
+
+ total.add(1);
+ }
+ }
+ }, threadCnt, "tx-thread");
+
+ final AtomicIntegerArray idx = new AtomicIntegerArray(GRID_CNT + 1);
+
+ IgniteInternalFuture<?> rollbackFut = multithreadedAsync(new Runnable() {
+ @Override public void run() {
+ int concurrentRollbackCnt = 5;
+
+ List<IgniteFuture<?>> futs = new ArrayList<>(concurrentRollbackCnt);
+
+ while (!stop.get()) {
+ // Choose node randomly.
+ final int nodeId = r.nextInt(GRID_CNT + 1);
+
+ // Reserve node.
+ if (!idx.compareAndSet(nodeId, 0, 1)) {
+ yield();
+
+ continue;
+ }
+
+ Ignite node = nodeId == GRID_CNT || nearCacheEnabled() ? client : grid(nodeId);
+
+ Collection<Transaction> transactions = node.transactions().localActiveTransactions();
+
+ for (Transaction tx : transactions) {
+ rolledBack.add(1);
+
+ if (rolledBack.sum() % 1000 == 0)
+ info("Processed: " + rolledBack.sum());
+
+ try {
+ IgniteFuture<Void> rollbackFut = tx.rollbackAsync();
+
+ rollbackFut.listen(new IgniteInClosure<IgniteFuture<Void>>() {
+ @Override public void apply(IgniteFuture<Void> fut) {
+ tx.close();
+ }
+ });
+
+ futs.add(rollbackFut);
+ }
+ catch (Throwable t) {
+ log.error("Exception on async rollback", t);
+
+ fail("Exception is not expected");
+ }
+
+ if (futs.size() == concurrentRollbackCnt) {
+ for (IgniteFuture<?> fut : futs)
+ try {
+ fut.get();
+ }
+ catch (IgniteException e) {
+ log.warning("Future was rolled back with error", e);
+ }
+
+ futs.clear();
+ }
+ }
+
+ idx.set(nodeId, 0);
+ }
+
+ for (IgniteFuture<?> fut : futs)
+ try {
+ fut.get();
+ }
+ catch (Throwable t) {
+ // No-op.
+ }
+
+ }
+ }, 3, "rollback-thread"); // Rollback by multiple threads.
+
+ doSleep(DURATION);
+
+ stop.set(true);
+
+ txFut.get();
+
+ rollbackFut.get();
+
+ log.info("total=" + total.sum() + ", completed=" + completed.sum() + ", failed=" + failed.sum() +
+ ", rolledBack=" + rolledBack.sum());
+
+ assertEquals("total != completed + failed", total.sum(), completed.sum() + failed.sum());
+
+ checkFutures();
+ }
+
+ /**
+ * Tests proxy object returned by {@link IgniteTransactions#localActiveTransactions()}
+ */
+ public void testRollbackProxy() throws Exception {
+ final CountDownLatch keyLocked = new CountDownLatch(1);
+
+ CountDownLatch waitCommit = new CountDownLatch(1);
+
+ Ignite ig = ignite(0);
+
+ IgniteInternalFuture<?> lockFut = lockInTx(ig, keyLocked, waitCommit, 0);
+
+ U.awaitQuiet(keyLocked);
+
+ Collection<Transaction> txs = ig.transactions().localActiveTransactions();
+
+ for (Transaction tx : txs) {
+ try {
+ tx.timeout(1);
+
+ fail("timeout");
+ }
+ catch (Exception e) {
+ // No-op.
+ }
+
+ try {
+ tx.setRollbackOnly();
+
+ fail("setRollbackOnly");
+ }
+ catch (Exception e) {
+ // No-op.
+ }
+
+ try {
+ tx.commit();
+
+ fail("commit");
+ }
+ catch (Exception e) {
+ // No-op.
+ }
+
+ try {
+ tx.commitAsync();
+
+ fail("commitAsync");
+ }
+ catch (Exception e) {
+ // No-op.
+ }
+
+ try {
+ tx.suspend();
+
+ fail("suspend");
+ }
+ catch (Exception e) {
+ // No-op.
+ }
+
+ try {
+ tx.resume();
+
+ fail("resume");
+ }
+ catch (Exception e) {
+ // No-op.
+ }
+
+ tx.rollback();
+
+ tx.rollbackAsync().get();
+ }
+
+ waitCommit.countDown();
+
+ try {
+ lockFut.get();
+
+ fail();
+ }
+ catch (IgniteCheckedException e) {
+ // No-op.
+ }
+ }
+
+ /**
+ * Locks entry in tx and delays commit until signalled.
+ *
+ * @param node Near node.
+ * @param keyLocked Latch for notifying until key is locked.
+ * @param waitCommit Latch for waiting until commit is allowed.
+ * @param timeout Timeout.
+ *
+ * @return tx completion future.
+ */
+ private IgniteInternalFuture<?> lockInTx(final Ignite node, final CountDownLatch keyLocked,
+ final CountDownLatch waitCommit, final int timeout) throws Exception {
+ return multithreadedAsync(new Runnable() {
+ @Override public void run() {
+ Transaction tx = node.transactions().withLabel(LABEL).txStart(PESSIMISTIC, REPEATABLE_READ, timeout, 1);
+
+ node.cache(CACHE_NAME).put(0, 0);
+
+ keyLocked.countDown();
+
+ try {
+ U.await(waitCommit);
+ }
+ catch (IgniteInterruptedCheckedException e) {
+ fail("Lock thread was interrupted while waiting");
+ }
+
+ tx.commit();
+ }
+ }, 1, "tx-lock-thread");
+ }
+
+ /**
+ * Checks if all tx futures are finished.
+ */
+ private void checkFutures() {
+ for (Ignite ignite : G.allGrids()) {
+ IgniteEx ig = (IgniteEx)ignite;
+
+ final Collection<GridCacheFuture<?>> futs = ig.context().cache().context().mvcc().activeFutures();
+
+ for (GridCacheFuture<?> fut : futs)
+ log.info("Waiting for future: " + fut);
+
+ assertTrue("Expecting no active futures: node=" + ig.localNode().id(), futs.isEmpty());
+ }
+ }
+
+ /**
+ * @param tx Tx to rollback.
+ */
+ private IgniteInternalFuture<?> rollbackAsync(final Transaction tx) throws Exception {
+ return multithreadedAsync(new Runnable() {
+ @Override public void run() {
+ tx.rollback();
+ }
+ }, 1, "tx-rollback-thread");
+ }
+
+ /**
+ * @param tx Tx to rollback.
+ * @param delay Delay in millis.
+ */
+ private IgniteInternalFuture<?> rollbackAsync(final Transaction tx, long delay) throws Exception {
+ return multithreadedAsync(new Runnable() {
+ @Override public void run() {
+ doSleep(delay);
+
+ tx.rollback();
+ }
+ }, 1, "tx-rollback-thread");
+ }
+
+}
+
http://git-wip-us.apache.org/repos/asf/ignite/blob/2b5d2fc5/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/transactions/TxRollbackAsyncWithPersistenceTest.java
----------------------------------------------------------------------
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/transactions/TxRollbackAsyncWithPersistenceTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/transactions/TxRollbackAsyncWithPersistenceTest.java
new file mode 100644
index 0000000..f1f8d10
--- /dev/null
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/transactions/TxRollbackAsyncWithPersistenceTest.java
@@ -0,0 +1,59 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.processors.cache.transactions;
+
+import static org.apache.ignite.IgniteSystemProperties.IGNITE_WAL_LOG_TX_RECORDS;
+
+/**
+ * Tests an ability to rollback near transactions.
+ */
+public class TxRollbackAsyncWithPersistenceTest extends TxRollbackAsyncTest {
+ /** {@inheritDoc} */
+ @Override protected boolean persistenceEnabled() {
+ return true;
+ }
+
+ /** {@inheritDoc} */
+ @Override protected void beforeTestsStarted() throws Exception {
+ System.setProperty(IGNITE_WAL_LOG_TX_RECORDS, "true");
+
+ super.beforeTestsStarted();
+ }
+
+ /** {@inheritDoc} */
+ @Override protected void afterTestsStopped() throws Exception {
+ super.afterTestsStopped();
+
+ System.clearProperty(IGNITE_WAL_LOG_TX_RECORDS);
+ }
+
+ /** {@inheritDoc} */
+ @Override protected void beforeTest() throws Exception {
+ cleanPersistenceDir();
+
+ super.beforeTest();
+ }
+
+ /** {@inheritDoc} */
+ @Override protected void afterTest() throws Exception {
+ super.afterTest();
+
+ cleanPersistenceDir();
+ }
+}
+
http://git-wip-us.apache.org/repos/asf/ignite/blob/2b5d2fc5/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/transactions/TxRollbackOnTimeoutNoDeadlockDetectionTest.java
----------------------------------------------------------------------
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/transactions/TxRollbackOnTimeoutNoDeadlockDetectionTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/transactions/TxRollbackOnTimeoutNoDeadlockDetectionTest.java
index 5123329..d888970 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/transactions/TxRollbackOnTimeoutNoDeadlockDetectionTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/transactions/TxRollbackOnTimeoutNoDeadlockDetectionTest.java
@@ -44,4 +44,8 @@ public class TxRollbackOnTimeoutNoDeadlockDetectionTest extends TxRollbackOnTime
assertEquals("TimeoutException is expected",
TransactionTimeoutException.class, e.getCause().getClass());
}
-}
\ No newline at end of file
+
+ @Override public void testRandomMixedTxConfigurations() throws Exception {
+ super.testRandomMixedTxConfigurations();
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/2b5d2fc5/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/transactions/TxRollbackOnTimeoutTest.java
----------------------------------------------------------------------
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/transactions/TxRollbackOnTimeoutTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/transactions/TxRollbackOnTimeoutTest.java
index 97de81e..d1cbfa7 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/transactions/TxRollbackOnTimeoutTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/transactions/TxRollbackOnTimeoutTest.java
@@ -18,10 +18,13 @@
package org.apache.ignite.internal.processors.cache.transactions;
import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
import java.util.Random;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.LongAdder;
import javax.cache.CacheException;
import org.apache.ignite.Ignite;
@@ -434,23 +437,19 @@ public class TxRollbackOnTimeoutTest extends GridCommonAbstractTest {
final Long v = (Long)node.cache(CACHE_NAME).get(k);
+ assertNotNull("Expecting not null value: " + tx, v);
+
final int delay = r.nextInt(400);
if (delay > 0)
sleep(delay);
- assert v != null;
-
node.cache(CACHE_NAME).put(k, v + 1);
tx.commit();
cntr1.add(1);
}
- catch (TransactionOptimisticException | InterruptedException e) {
- // Expected.
- cntr3.add(1);
- }
catch (TransactionTimeoutException e) {
cntr2.add(1);
}
@@ -459,6 +458,9 @@ public class TxRollbackOnTimeoutTest extends GridCommonAbstractTest {
cntr2.add(1);
}
+ catch (Exception e) {
+ cntr3.add(1);
+ }
}
}
}, threadsCnt, "tx-async-thread");
@@ -474,7 +476,8 @@ public class TxRollbackOnTimeoutTest extends GridCommonAbstractTest {
", failed=" + cntr3.sum() +
", timedOut=" + cntr2.sum());
- assertEquals("Expected finished count same as started count", cntr0.sum(), cntr1.sum() + cntr2.sum() + cntr3.sum());
+ assertEquals("Expected finished count same as started count", cntr0.sum(), cntr1.sum() + cntr2.sum() +
+ cntr3.sum());
}
/**
@@ -495,6 +498,107 @@ public class TxRollbackOnTimeoutTest extends GridCommonAbstractTest {
/**
*
+ */
+ public void testLockRelease() throws Exception {
+ final Ignite client = startClient();
+
+ final AtomicInteger idx = new AtomicInteger();
+
+ final int threadCnt = Runtime.getRuntime().availableProcessors() * 2;
+
+ final CountDownLatch readStartLatch = new CountDownLatch(1);
+
+ final CountDownLatch commitLatch = new CountDownLatch(threadCnt - 1);
+
+ final IgniteInternalFuture<?> fut = multithreadedAsync(new Runnable() {
+ @Override public void run() {
+ final int idx0 = idx.getAndIncrement();
+
+ if (idx0 == 0) {
+ try(final Transaction tx = client.transactions().txStart(PESSIMISTIC, REPEATABLE_READ, 0, 1)) {
+ client.cache(CACHE_NAME).put(0, 0); // Lock is owned.
+
+ readStartLatch.countDown();
+
+ U.awaitQuiet(commitLatch);
+
+ tx.commit();
+ }
+ }
+ else {
+ try (Transaction tx = client.transactions().txStart(PESSIMISTIC, REPEATABLE_READ, 300, 1)) {
+ U.awaitQuiet(readStartLatch);
+
+ client.cache(CACHE_NAME).get(0); // Lock acquisition is queued.
+ }
+ catch (CacheException e) {
+ assertTrue(e.getMessage(), X.hasCause(e, TransactionTimeoutException.class));
+ }
+
+ commitLatch.countDown();
+ }
+ }
+ }, threadCnt, "tx-async");
+
+ fut.get();
+
+ Thread.sleep(500);
+
+ assertEquals(0, client.cache(CACHE_NAME).get(0));
+
+ for (Ignite ignite : G.allGrids()) {
+ IgniteEx ig = (IgniteEx)ignite;
+
+ final IgniteInternalFuture<?> f = ig.context().cache().context().
+ partitionReleaseFuture(new AffinityTopologyVersion(G.allGrids().size() + 1, 0));
+
+ assertTrue("Unexpected incomplete future", f.isDone());
+ }
+
+ }
+
+ /**
+ *
+ */
+ public void testEnlistManyRead() throws Exception {
+ testEnlistMany(false);
+ }
+
+ /**
+ *
+ */
+ public void testEnlistManyWrite() throws Exception {
+ testEnlistMany(true);
+ }
+
+ /**
+ *
+ */
+ private void testEnlistMany(boolean write) throws Exception {
+ final Ignite client = startClient();
+
+ Map<Integer, Integer> entries = new HashMap<>();
+
+ for (int i = 0; i < 1000000; i++)
+ entries.put(i, i);
+
+ try(Transaction tx = client.transactions().txStart(PESSIMISTIC, REPEATABLE_READ, 200, 0)) {
+ if (write)
+ client.cache(CACHE_NAME).putAll(entries);
+ else
+ client.cache(CACHE_NAME).getAll(entries.keySet());
+
+ tx.commit();
+ }
+ catch (Throwable t) {
+ assertTrue(X.hasCause(t, TransactionTimeoutException.class));
+ }
+
+ assertEquals(0, client.cache(CACHE_NAME).size());
+ }
+
+ /**
+ *
* @param prim Primary node.
* @param conc Concurrency.
* @param isolation Isolation.
http://git-wip-us.apache.org/repos/asf/ignite/blob/2b5d2fc5/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/transactions/TxRollbackOnTopologyChangeTest.java
----------------------------------------------------------------------
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/transactions/TxRollbackOnTopologyChangeTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/transactions/TxRollbackOnTopologyChangeTest.java
new file mode 100644
index 0000000..2542cdb
--- /dev/null
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/transactions/TxRollbackOnTopologyChangeTest.java
@@ -0,0 +1,228 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.processors.cache.transactions;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Random;
+import java.util.concurrent.Callable;
+import java.util.concurrent.CyclicBarrier;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicIntegerArray;
+import org.apache.ignite.Ignite;
+import org.apache.ignite.configuration.CacheConfiguration;
+import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.configuration.TransactionConfiguration;
+import org.apache.ignite.internal.IgniteEx;
+import org.apache.ignite.internal.IgniteInternalFuture;
+import org.apache.ignite.internal.TestRecordingCommunicationSpi;
+import org.apache.ignite.internal.processors.cache.GridCacheFuture;
+import org.apache.ignite.internal.util.typedef.G;
+import org.apache.ignite.internal.util.typedef.internal.U;
+import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi;
+import org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder;
+import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
+import org.apache.ignite.transactions.Transaction;
+
+import static java.lang.Thread.yield;
+import static org.apache.ignite.cache.CacheAtomicityMode.TRANSACTIONAL;
+import static org.apache.ignite.cache.CacheWriteSynchronizationMode.FULL_SYNC;
+import static org.apache.ignite.transactions.TransactionConcurrency.PESSIMISTIC;
+import static org.apache.ignite.transactions.TransactionIsolation.REPEATABLE_READ;
+
+/**
+ * Tests an ability to rollback transactions on topology change.
+ */
+public class TxRollbackOnTopologyChangeTest extends GridCommonAbstractTest {
+ /** */
+ public static final int ROLLBACK_TIMEOUT = 500;
+
+ /** */
+ private static final String CACHE_NAME = "test";
+
+ /** IP finder. */
+ private static final TcpDiscoveryVmIpFinder IP_FINDER = new TcpDiscoveryVmIpFinder(true);
+
+ /** */
+ private static final int SRV_CNT = 6;
+
+ /** */
+ private static final int CLNT_CNT = 2;
+
+ /** */
+ private static final int TOTAL_CNT = SRV_CNT + CLNT_CNT;
+
+ /** */
+ public static final int ITERATIONS = 100;
+
+ /** {@inheritDoc} */
+ @Override protected IgniteConfiguration getConfiguration(String igniteInstanceName) throws Exception {
+ IgniteConfiguration cfg = super.getConfiguration(igniteInstanceName);
+
+ cfg.setTransactionConfiguration(new TransactionConfiguration().
+ setTxTimeoutOnPartitionMapExchange(ROLLBACK_TIMEOUT));
+
+ ((TcpDiscoverySpi)cfg.getDiscoverySpi()).setIpFinder(IP_FINDER);
+
+ cfg.setCommunicationSpi(new TestRecordingCommunicationSpi());
+
+ cfg.setClientMode(getTestIgniteInstanceIndex(igniteInstanceName) >= SRV_CNT);
+
+ CacheConfiguration ccfg = new CacheConfiguration(CACHE_NAME);
+
+ ccfg.setAtomicityMode(TRANSACTIONAL);
+ ccfg.setBackups(2);
+ ccfg.setWriteSynchronizationMode(FULL_SYNC);
+
+ cfg.setCacheConfiguration(ccfg);
+
+ return cfg;
+ }
+
+ /** {@inheritDoc} */
+ @Override protected void beforeTest() throws Exception {
+ super.beforeTest();
+
+ startGridsMultiThreaded(TOTAL_CNT);
+ }
+
+ /** {@inheritDoc} */
+ @Override protected void afterTest() throws Exception {
+ super.afterTest();
+
+ stopAllGrids();
+ }
+
+ /**
+ * Tests rollbacks on topology change.
+ */
+ public void testRollbackOnTopologyChange() throws Exception {
+ final AtomicBoolean stop = new AtomicBoolean();
+
+ final long seed = System.currentTimeMillis();
+
+ final Random r = new Random(seed);
+
+ log.info("Using seed: " + seed);
+
+ AtomicIntegerArray reservedIdx = new AtomicIntegerArray(TOTAL_CNT);
+
+ final int keysCnt = SRV_CNT - 1;
+
+ for (int k = 0; k < keysCnt; k++)
+ grid(0).cache(CACHE_NAME).put(k, (long)0);
+
+ final CyclicBarrier b = new CyclicBarrier(keysCnt);
+
+ AtomicInteger idGen = new AtomicInteger();
+
+ final IgniteInternalFuture<?> txFut = multithreadedAsync(new Runnable() {
+ @Override public void run() {
+ int key = idGen.getAndIncrement();
+
+ List<Integer> keys = new ArrayList<>();
+
+ for (int k = 0; k < keysCnt; k++)
+ keys.add(k);
+
+ int cntr = 0;
+
+ for (int i = 0; i < ITERATIONS; i++) {
+ cntr++;
+
+ int nodeId;
+
+ while(!reservedIdx.compareAndSet((nodeId = r.nextInt(TOTAL_CNT)), 0, 1))
+ doSleep(10);
+
+ U.awaitQuiet(b);
+
+ final IgniteEx grid = grid(nodeId);
+
+ try (final Transaction tx = grid.transactions().txStart(PESSIMISTIC, REPEATABLE_READ, 0, 0)) {
+ reservedIdx.set(nodeId, 0);
+
+ // Construct deadlock
+ grid.cache(CACHE_NAME).get(keys.get(key));
+
+ // Should block.
+ grid.cache(CACHE_NAME).get(keys.get((key + 1) % keysCnt));
+
+ fail("Deadlock expected");
+ }
+ catch (Throwable t) {
+ // Expected.
+ }
+
+ if (key == 0)
+ log.info("Rolled back: " + cntr);
+ }
+ }
+ }, keysCnt, "tx-lock-thread");
+
+ final IgniteInternalFuture<?> restartFut = multithreadedAsync(new Callable<Void>() {
+ @Override public Void call() throws Exception {
+ while(!stop.get()) {
+ final int nodeId = r.nextInt(TOTAL_CNT);
+
+ if (!reservedIdx.compareAndSet(nodeId, 0, 1)) {
+ yield();
+
+ continue;
+ }
+
+ stopGrid(nodeId);
+
+ doSleep(500 + r.nextInt(1000));
+
+ startGrid(nodeId);
+
+ reservedIdx.set(nodeId, 0);
+ }
+
+ return null;
+ }
+ }, 1, "tx-restart-thread");
+
+ txFut.get(); // Wait for iterations to complete.
+
+ stop.set(true);
+
+ restartFut.get();
+
+ checkFutures();
+ }
+
+ /**
+ * Checks if all tx futures are finished.
+ */
+ private void checkFutures() {
+ for (Ignite ignite : G.allGrids()) {
+ IgniteEx ig = (IgniteEx)ignite;
+
+ final Collection<GridCacheFuture<?>> futs = ig.context().cache().context().mvcc().activeFutures();
+
+ for (GridCacheFuture<?> fut : futs)
+ log.info("Waiting for future: " + fut);
+
+ assertTrue("Expecting no active futures: node=" + ig.localNode().id(), futs.isEmpty());
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/2b5d2fc5/modules/core/src/test/java/org/apache/ignite/internal/processors/igfs/IgfsDataManagerSelfTest.java
----------------------------------------------------------------------
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/igfs/IgfsDataManagerSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/igfs/IgfsDataManagerSelfTest.java
index 774af03..18abc1c 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/igfs/IgfsDataManagerSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/igfs/IgfsDataManagerSelfTest.java
@@ -196,7 +196,7 @@ public class IgfsDataManagerSelfTest extends IgfsCommonAbstractTest {
GridCacheContext<Object, Object> ctx = GridTestUtils.getFieldValue(
grid(j).cachex(grid(j).igfsx("igfs").configuration().getDataCacheConfiguration().getName()),
"ctx");
- Collection<IgniteInternalTx> txs = ctx.tm().txs();
+ Collection<IgniteInternalTx> txs = ctx.tm().activeTransactions();
assert txs.isEmpty() : "Incomplete transactions: " + txs;
}
@@ -289,7 +289,7 @@ public class IgfsDataManagerSelfTest extends IgfsCommonAbstractTest {
GridCacheContext<Object, Object> ctx = GridTestUtils.getFieldValue(grid(j).cachex(
grid(j).igfsx("igfs").configuration().getDataCacheConfiguration().getName()),
"ctx");
- Collection<IgniteInternalTx> txs = ctx.tm().txs();
+ Collection<IgniteInternalTx> txs = ctx.tm().activeTransactions();
assert txs.isEmpty() : "Incomplete transactions: " + txs;
}
@@ -374,7 +374,7 @@ public class IgfsDataManagerSelfTest extends IgfsCommonAbstractTest {
GridCacheContext<Object, Object> ctx = GridTestUtils.getFieldValue(
grid(j).cachex(grid(j).igfsx("igfs").configuration().getDataCacheConfiguration().getName()),
"ctx");
- Collection<IgniteInternalTx> txs = ctx.tm().txs();
+ Collection<IgniteInternalTx> txs = ctx.tm().activeTransactions();
assert txs.isEmpty() : "Incomplete transactions: " + txs;
}
http://git-wip-us.apache.org/repos/asf/ignite/blob/2b5d2fc5/modules/core/src/test/java/org/apache/ignite/testframework/junits/cache/GridAbstractCacheStoreSelfTest.java
----------------------------------------------------------------------
diff --git a/modules/core/src/test/java/org/apache/ignite/testframework/junits/cache/GridAbstractCacheStoreSelfTest.java b/modules/core/src/test/java/org/apache/ignite/testframework/junits/cache/GridAbstractCacheStoreSelfTest.java
index f764212..22d9376 100644
--- a/modules/core/src/test/java/org/apache/ignite/testframework/junits/cache/GridAbstractCacheStoreSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/testframework/junits/cache/GridAbstractCacheStoreSelfTest.java
@@ -584,6 +584,11 @@ public abstract class GridAbstractCacheStoreSelfTest<T extends CacheStore<Object
}
/** {@inheritDoc} */
+ @Nullable @Override public String label() {
+ return null;
+ }
+
+ /** {@inheritDoc} */
@Override public void resume() {
// No-op.
}
@@ -593,4 +598,4 @@ public abstract class GridAbstractCacheStoreSelfTest<T extends CacheStore<Object
return null;
}
}
-}
\ No newline at end of file
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/2b5d2fc5/modules/core/src/test/java/org/apache/ignite/testframework/junits/multijvm/IgniteClusterProcessProxy.java
----------------------------------------------------------------------
diff --git a/modules/core/src/test/java/org/apache/ignite/testframework/junits/multijvm/IgniteClusterProcessProxy.java b/modules/core/src/test/java/org/apache/ignite/testframework/junits/multijvm/IgniteClusterProcessProxy.java
index 266c1f1..e06af68 100644
--- a/modules/core/src/test/java/org/apache/ignite/testframework/junits/multijvm/IgniteClusterProcessProxy.java
+++ b/modules/core/src/test/java/org/apache/ignite/testframework/junits/multijvm/IgniteClusterProcessProxy.java
@@ -161,6 +161,11 @@ public class IgniteClusterProcessProxy implements IgniteClusterEx {
}
/** {@inheritDoc} */
+ @Override public void setTxTimeoutOnPartitionMapExchange(long timeout) {
+ throw new UnsupportedOperationException("Operation is not supported yet.");
+ }
+
+ /** {@inheritDoc} */
@Override public IgniteCluster withAsync() {
throw new UnsupportedOperationException("Operation is not supported yet.");
}
http://git-wip-us.apache.org/repos/asf/ignite/blob/2b5d2fc5/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteBasicTestSuite.java
----------------------------------------------------------------------
diff --git a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteBasicTestSuite.java b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteBasicTestSuite.java
index c388f1d..e71a569 100644
--- a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteBasicTestSuite.java
+++ b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteBasicTestSuite.java
@@ -42,6 +42,7 @@ import org.apache.ignite.internal.GridStopWithCancelSelfTest;
import org.apache.ignite.internal.IgniteLocalNodeMapBeforeStartTest;
import org.apache.ignite.internal.IgniteSlowClientDetectionSelfTest;
import org.apache.ignite.internal.MarshallerContextLockingSelfTest;
+import org.apache.ignite.internal.TransactionsMXBeanImplTest;
import org.apache.ignite.internal.managers.IgniteDiagnosticMessagesTest;
import org.apache.ignite.internal.processors.affinity.GridAffinityProcessorRendezvousSelfTest;
import org.apache.ignite.internal.processors.cache.GridLocalIgniteSerializationTest;
@@ -51,6 +52,7 @@ import org.apache.ignite.internal.processors.cache.IgniteMarshallerCacheClassNam
import org.apache.ignite.internal.processors.cache.IgniteMarshallerCacheClientRequestsMappingOnMissTest;
import org.apache.ignite.internal.processors.cache.IgniteMarshallerCacheConcurrentReadWriteTest;
import org.apache.ignite.internal.processors.cache.IgniteMarshallerCacheFSRestoreTest;
+import org.apache.ignite.internal.processors.cache.SetTxTimeoutOnPartitionMapExchangeTest;
import org.apache.ignite.internal.processors.cache.distributed.IgniteRejectConnectOnNodeStopTest;
import org.apache.ignite.internal.processors.closure.GridClosureProcessorRemoteTest;
import org.apache.ignite.internal.processors.closure.GridClosureProcessorSelfTest;
@@ -153,6 +155,8 @@ public class IgniteBasicTestSuite extends TestSuite {
suite.addTestSuite(GridNodeMetricsLogSelfTest.class);
suite.addTestSuite(GridLocalIgniteSerializationTest.class);
suite.addTestSuite(GridMBeansTest.class);
+ suite.addTestSuite(TransactionsMXBeanImplTest.class);
+ suite.addTestSuite(SetTxTimeoutOnPartitionMapExchangeTest.class);
suite.addTestSuite(IgniteExceptionInNioWorkerSelfTest.class);
suite.addTestSuite(IgniteLocalNodeMapBeforeStartTest.class);
http://git-wip-us.apache.org/repos/asf/ignite/blob/2b5d2fc5/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheTestSuite3.java
----------------------------------------------------------------------
diff --git a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheTestSuite3.java b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheTestSuite3.java
index bfdf2fd..b66bf5b 100644
--- a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheTestSuite3.java
+++ b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheTestSuite3.java
@@ -38,6 +38,7 @@ import org.apache.ignite.internal.processors.cache.IgniteCacheScanPredicateDeplo
import org.apache.ignite.internal.processors.cache.distributed.CacheAsyncOperationsTest;
import org.apache.ignite.internal.processors.cache.distributed.GridCacheMixedModeSelfTest;
import org.apache.ignite.internal.processors.cache.distributed.IgniteTxGetAfterStopTest;
+import org.apache.ignite.internal.processors.cache.distributed.IgniteTxRemoveTimeoutObjectsNearTest;
import org.apache.ignite.internal.processors.cache.distributed.IgniteTxRemoveTimeoutObjectsTest;
import org.apache.ignite.internal.processors.cache.distributed.dht.GridCacheDaemonNodePartitionedSelfTest;
import org.apache.ignite.internal.processors.cache.distributed.dht.GridCachePartitionedOnlyP2PDisabledByteArrayValuesSelfTest;
@@ -206,6 +207,7 @@ public class IgniteCacheTestSuite3 extends TestSuite {
suite.addTestSuite(CacheAsyncOperationsTest.class);
suite.addTestSuite(IgniteTxRemoveTimeoutObjectsTest.class);
+ suite.addTestSuite(IgniteTxRemoveTimeoutObjectsNearTest.class);
return suite;
}
http://git-wip-us.apache.org/repos/asf/ignite/blob/2b5d2fc5/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheTestSuite6.java
----------------------------------------------------------------------
diff --git a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheTestSuite6.java b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheTestSuite6.java
index a31bd75..fb0daa9 100644
--- a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheTestSuite6.java
+++ b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheTestSuite6.java
@@ -42,11 +42,17 @@ import org.apache.ignite.internal.processors.cache.distributed.IgniteOptimisticT
import org.apache.ignite.internal.processors.cache.distributed.IgniteOptimisticTxSuspendResumeTest;
import org.apache.ignite.internal.processors.cache.distributed.IgnitePessimisticTxSuspendResumeTest;
import org.apache.ignite.internal.processors.cache.persistence.IgnitePdsCacheAssignmentNodeRestartsTest;
-import org.apache.ignite.internal.processors.cache.persistence.file.FileDownloaderTest;
+import org.apache.ignite.internal.processors.cache.transactions.TxLabelTest;
+import org.apache.ignite.internal.processors.cache.transactions.TxMultiCacheAsyncOpsTest;
+import org.apache.ignite.internal.processors.cache.transactions.TxOptimisticPrepareOnUnstableTopologyTest;
+import org.apache.ignite.internal.processors.cache.transactions.TxRollbackAsyncWithPersistenceTest;
import org.apache.ignite.internal.processors.cache.transactions.TxOptimisticOnPartitionExchangeTest;
import org.apache.ignite.internal.processors.cache.transactions.TxRollbackOnTimeoutNearCacheTest;
import org.apache.ignite.internal.processors.cache.transactions.TxRollbackOnTimeoutNoDeadlockDetectionTest;
import org.apache.ignite.internal.processors.cache.transactions.TxRollbackOnTimeoutTest;
+import org.apache.ignite.internal.processors.cache.transactions.TxRollbackAsyncNearCacheTest;
+import org.apache.ignite.internal.processors.cache.transactions.TxRollbackAsyncTest;
+import org.apache.ignite.internal.processors.cache.transactions.TxRollbackOnTopologyChangeTest;
/**
* Test suite.
@@ -72,6 +78,16 @@ public class IgniteCacheTestSuite6 extends TestSuite {
suite.addTestSuite(TxRollbackOnTimeoutNoDeadlockDetectionTest.class);
suite.addTestSuite(TxRollbackOnTimeoutNearCacheTest.class);
suite.addTestSuite(IgniteCacheThreadLocalTxTest.class);
+ suite.addTestSuite(TxRollbackAsyncTest.class);
+ suite.addTestSuite(TxRollbackAsyncNearCacheTest.class);
+ suite.addTestSuite(TxRollbackAsyncWithPersistenceTest.class);
+ suite.addTestSuite(TxRollbackOnTopologyChangeTest.class);
+
+ suite.addTestSuite(TxOptimisticPrepareOnUnstableTopologyTest.class);
+
+ suite.addTestSuite(TxLabelTest.class);
+
+ suite.addTestSuite(TxMultiCacheAsyncOpsTest.class);
suite.addTestSuite(IgnitePdsCacheAssignmentNodeRestartsTest.class);
http://git-wip-us.apache.org/repos/asf/ignite/blob/2b5d2fc5/modules/core/src/test/java/org/apache/ignite/util/GridCommandHandlerTest.java
----------------------------------------------------------------------
diff --git a/modules/core/src/test/java/org/apache/ignite/util/GridCommandHandlerTest.java b/modules/core/src/test/java/org/apache/ignite/util/GridCommandHandlerTest.java
index eb18e29..c2d9eec 100644
--- a/modules/core/src/test/java/org/apache/ignite/util/GridCommandHandlerTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/util/GridCommandHandlerTest.java
@@ -22,20 +22,40 @@ import java.io.File;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Map;
+import java.util.TreeMap;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.atomic.AtomicInteger;
import org.apache.ignite.Ignite;
+import org.apache.ignite.IgniteCache;
import org.apache.ignite.IgniteCheckedException;
+import org.apache.ignite.cluster.ClusterNode;
+import org.apache.ignite.configuration.CacheConfiguration;
import org.apache.ignite.configuration.ConnectorConfiguration;
import org.apache.ignite.configuration.DataRegionConfiguration;
import org.apache.ignite.configuration.DataStorageConfiguration;
import org.apache.ignite.configuration.IgniteConfiguration;
import org.apache.ignite.configuration.WALMode;
+import org.apache.ignite.internal.IgniteInternalFuture;
import org.apache.ignite.internal.commandline.CommandHandler;
import org.apache.ignite.internal.util.typedef.F;
+import org.apache.ignite.internal.util.typedef.G;
+import org.apache.ignite.internal.util.typedef.X;
import org.apache.ignite.internal.util.typedef.internal.U;
+import org.apache.ignite.internal.visor.tx.VisorTxInfo;
+import org.apache.ignite.internal.visor.tx.VisorTxTaskResult;
+import org.apache.ignite.lang.IgniteInClosure;
import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
+import org.apache.ignite.transactions.Transaction;
+import org.apache.ignite.transactions.TransactionRollbackException;
+import static org.apache.ignite.cache.CacheAtomicityMode.*;
+import static org.apache.ignite.cache.CacheWriteSynchronizationMode.*;
import static org.apache.ignite.internal.commandline.CommandHandler.EXIT_CODE_OK;
import static org.apache.ignite.internal.commandline.CommandHandler.EXIT_CODE_UNEXPECTED_ERROR;
+import static org.apache.ignite.transactions.TransactionConcurrency.OPTIMISTIC;
+import static org.apache.ignite.transactions.TransactionConcurrency.PESSIMISTIC;
+import static org.apache.ignite.transactions.TransactionIsolation.READ_COMMITTED;
/**
* Command line handler test.
@@ -85,6 +105,8 @@ public class GridCommandHandlerTest extends GridCommonAbstractTest {
cfg.setConsistentId(igniteInstanceName);
+ cfg.setClientMode("client".equals(igniteInstanceName));
+
return cfg;
}
@@ -123,6 +145,32 @@ public class GridCommandHandlerTest extends GridCommonAbstractTest {
}
/**
+ * @param hnd Handler.
+ * @param args Arguments.
+ * @return Result of execution
+ */
+ protected int execute(CommandHandler hnd, ArrayList<String> args) {
+ // Add force to avoid interactive confirmation
+ args.add("--force");
+
+ return hnd.execute(args);
+ }
+
+ /**
+ * @param hnd Handler.
+ * @param args Arguments.
+ * @return Result of execution
+ */
+ protected int execute(CommandHandler hnd, String... args) {
+ ArrayList<String> args0 = new ArrayList<>(Arrays.asList(args));
+
+ // Add force to avoid interactive confirmation
+ args0.add("--force");
+
+ return hnd.execute(args0);
+ }
+
+ /**
* Test deactivation works via control.sh
*
* @throws Exception If failed.
@@ -312,4 +360,203 @@ public class GridCommandHandlerTest extends GridCommonAbstractTest {
assertEquals(2, ignite.cluster().currentBaselineTopology().size());
}
+
+ /**
+ * Test active transactions.
+ *
+ * @throws Exception If failed.
+ */
+ public void testActiveTransactions() throws Exception {
+ Ignite ignite = startGridsMultiThreaded(2);
+
+ ignite.cluster().active(true);
+
+ Ignite client = startGrid("client");
+
+ IgniteCache<Object, Object> cache = client.getOrCreateCache(new CacheConfiguration<>(DEFAULT_CACHE_NAME)
+ .setAtomicityMode(TRANSACTIONAL).setWriteSynchronizationMode(FULL_SYNC));
+
+ for (Ignite ig : G.allGrids())
+ assertNotNull(ig.cache(DEFAULT_CACHE_NAME));
+
+ AtomicInteger idx = new AtomicInteger();
+
+ CountDownLatch lockLatch = new CountDownLatch(1);
+ CountDownLatch unlockLatch = new CountDownLatch(1);
+
+ IgniteInternalFuture<?> fut = multithreadedAsync(new Runnable() {
+ @Override public void run() {
+ int id = idx.getAndIncrement();
+
+ switch (id) {
+ case 0:
+ try (Transaction tx = grid(0).transactions().txStart()) {
+ grid(0).cache(DEFAULT_CACHE_NAME).putAll(generate(0, 100));
+
+ lockLatch.countDown();
+
+ U.awaitQuiet(unlockLatch);
+
+ tx.commit();
+
+ fail("Commit must fail");
+ }
+ catch (Exception ignored) {
+ // No-op.
+ assertTrue(X.hasCause(ignored, TransactionRollbackException.class));
+ }
+
+ break;
+ case 1:
+ U.awaitQuiet(lockLatch);
+
+ doSleep(3000);
+
+ try (Transaction tx = grid(0).transactions().withLabel("label1").txStart(PESSIMISTIC, READ_COMMITTED, Integer.MAX_VALUE, 0)) {
+ grid(0).cache(DEFAULT_CACHE_NAME).putAll(generate(200, 110));
+
+ grid(0).cache(DEFAULT_CACHE_NAME).put(0, 0);
+ }
+
+ break;
+ case 2:
+ try (Transaction tx = grid(1).transactions().txStart()) {
+ U.awaitQuiet(lockLatch);
+
+ grid(1).cache(DEFAULT_CACHE_NAME).put(0, 0);
+ }
+
+ break;
+ case 3:
+ try (Transaction tx = client.transactions().withLabel("label2").txStart(OPTIMISTIC, READ_COMMITTED, 0, 0)) {
+ U.awaitQuiet(lockLatch);
+
+ client.cache(DEFAULT_CACHE_NAME).putAll(generate(100, 10));
+
+ client.cache(DEFAULT_CACHE_NAME).put(0, 0);
+
+ tx.commit();
+ }
+
+ break;
+ }
+ }
+ }, 4, "tx-thread");
+
+ U.awaitQuiet(lockLatch);
+
+ doSleep(5000);
+
+ CommandHandler h = new CommandHandler();
+
+ final VisorTxInfo[] toKill = {null};
+
+ // Basic test.
+ validate(h, map -> {
+ ClusterNode node = grid(0).cluster().localNode();
+
+ VisorTxTaskResult res = map.get(node);
+
+ for (VisorTxInfo info : res.getInfos()) {
+ if (info.getSize() == 100) {
+ toKill[0] = info;
+
+ break;
+ }
+ }
+
+ assertEquals(3, map.size());
+ }, "--tx");
+
+ assertNotNull(toKill);
+
+ // Test filter by label.
+ validate(h, map -> {
+ ClusterNode node = grid(0).cluster().localNode();
+
+ for (Map.Entry<ClusterNode, VisorTxTaskResult> entry : map.entrySet())
+ assertEquals(entry.getKey().equals(node) ? 1 : 0, entry.getValue().getInfos().size());
+ }, "--tx", "label", "label1");
+
+ // Test filter by label regex.
+ validate(h, map -> {
+ ClusterNode node1 = grid(0).cluster().localNode();
+ ClusterNode node2 = grid("client").cluster().localNode();
+
+ for (Map.Entry<ClusterNode, VisorTxTaskResult> entry : map.entrySet()) {
+ if (entry.getKey().equals(node1)) {
+ assertEquals(1, entry.getValue().getInfos().size());
+
+ assertEquals("label1", entry.getValue().getInfos().get(0).getLabel());
+ }
+ else if (entry.getKey().equals(node2)) {
+ assertEquals(1, entry.getValue().getInfos().size());
+
+ assertEquals("label2", entry.getValue().getInfos().get(0).getLabel());
+ }
+ else
+ assertTrue(entry.getValue().getInfos().isEmpty());
+
+ }
+ }, "--tx", "label", "^label[0-9]");
+
+ // test order by size.
+ validate(h, map -> {
+ VisorTxTaskResult res = map.get(grid(0).localNode());
+
+ assertTrue(res.getInfos().get(0).getSize() >= res.getInfos().get(1).getSize());
+
+ }, "--tx", "order", "SIZE");
+
+ // test order by duration.
+ validate(h, map -> {
+ VisorTxTaskResult res = map.get(grid(0).localNode());
+
+ assertTrue(res.getInfos().get(0).getDuration() >= res.getInfos().get(1).getDuration());
+
+ }, "--tx", "order", "DURATION");
+
+ // Test kill by xid.
+ validate(h, map -> {
+ assertEquals(1, map.size());
+
+ Map.Entry<ClusterNode, VisorTxTaskResult> killedEntry = map.entrySet().iterator().next();
+
+ VisorTxInfo info = killedEntry.getValue().getInfos().get(0);
+
+ assertEquals(toKill[0].getXid(), info.getXid());
+ }, "--tx", "kill",
+ "xid", toKill[0].getXid().toString(),
+ "nodes", grid(0).localNode().consistentId().toString());
+
+ unlockLatch.countDown();
+
+ fut.get();
+ }
+
+ /**
+ * @param h Handler.
+ * @param validateClo Validate clo.
+ * @param args Args.
+ */
+ private void validate(
+ CommandHandler h, IgniteInClosure<Map<ClusterNode, VisorTxTaskResult>> validateClo, String... args)
+ throws IgniteCheckedException {
+ assertEquals(EXIT_CODE_OK, execute(h, args));
+
+ validateClo.apply(h.getLastOperationResult());
+ }
+
+ /**
+ * @param from From.
+ * @param cnt Count.
+ */
+ private Map<Object, Object> generate(int from, int cnt) {
+ Map<Object, Object> map = new TreeMap<>();
+
+ for (int i = 0; i < cnt; i++ )
+ map.put(i + from, i + from);
+
+ return map;
+ }
}
http://git-wip-us.apache.org/repos/asf/ignite/blob/2b5d2fc5/modules/jta/src/main/java/org/apache/ignite/internal/processors/cache/jta/CacheJtaManager.java
----------------------------------------------------------------------
diff --git a/modules/jta/src/main/java/org/apache/ignite/internal/processors/cache/jta/CacheJtaManager.java b/modules/jta/src/main/java/org/apache/ignite/internal/processors/cache/jta/CacheJtaManager.java
index dd5f6b7..8dcdd57 100644
--- a/modules/jta/src/main/java/org/apache/ignite/internal/processors/cache/jta/CacheJtaManager.java
+++ b/modules/jta/src/main/java/org/apache/ignite/internal/processors/cache/jta/CacheJtaManager.java
@@ -167,7 +167,8 @@ public class CacheJtaManager extends CacheJtaManagerAdapter {
tCfg.getDefaultTxIsolation(),
tCfg.getDefaultTxTimeout(),
/*store enabled*/true,
- /*tx size*/0
+ /*tx size*/0,
+ null
);
}
http://git-wip-us.apache.org/repos/asf/ignite/blob/2b5d2fc5/modules/platforms/dotnet/Apache.Ignite.Core.Tests/ApiParity/ClusterParityTest.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/ApiParity/ClusterParityTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/ApiParity/ClusterParityTest.cs
index b940d09..2267540 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/ApiParity/ClusterParityTest.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/ApiParity/ClusterParityTest.cs
@@ -38,7 +38,8 @@
/** Members that are missing on .NET side and should be added in future. */
private static readonly string[] MissingMembers =
{
- "enableStatistics" // IGNITE-7276
+ "enableStatistics", // IGNITE-7276
+ "setTxTimeoutOnPartitionMapExchange" // IGNITE-8075
};
/// <summary>
http://git-wip-us.apache.org/repos/asf/ignite/blob/2b5d2fc5/modules/platforms/dotnet/Apache.Ignite.Core.Tests/ApiParity/TransactionsParityTest.cs
----------------------------------------------------------------------
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/ApiParity/TransactionsParityTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/ApiParity/TransactionsParityTest.cs
index 7c19569..e519ab3 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/ApiParity/TransactionsParityTest.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/ApiParity/TransactionsParityTest.cs
@@ -25,6 +25,13 @@ namespace Apache.Ignite.Core.Tests.ApiParity
/// </summary>
public class TransactionsParityTest
{
+ /** Members that are missing on .NET side and should be added in future. */
+ private static readonly string[] MissingMembers =
+ {
+ "localActiveTransactions", // IGNITE-8075
+ "withLabel" // IGNITE-8075
+ };
+
/// <summary>
/// Tests the API parity.
/// </summary>
@@ -33,7 +40,9 @@ namespace Apache.Ignite.Core.Tests.ApiParity
{
ParityTest.CheckInterfaceParity(
@"modules\core\src\main\java\org\apache\ignite\IgniteTransactions.java",
- typeof(ITransactions));
+ typeof(ITransactions),
+ null,
+ MissingMembers);
}
}
-}
\ No newline at end of file
+}
[5/6] ignite git commit: IGNITE-6827 Configurable rollback for long
running transactions before partition exchange IGNITE-7910 Improved
transaction debugging support
Posted by ag...@apache.org.
http://git-wip-us.apache.org/repos/asf/ignite/blob/2b5d2fc5/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtLockFuture.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtLockFuture.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtLockFuture.java
index b4447b7..2869bb6 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtLockFuture.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtLockFuture.java
@@ -52,6 +52,7 @@ import org.apache.ignite.internal.processors.cache.KeyCacheObject;
import org.apache.ignite.internal.processors.cache.distributed.GridCacheMappedVersion;
import org.apache.ignite.internal.processors.cache.distributed.GridDistributedCacheEntry;
import org.apache.ignite.internal.processors.cache.distributed.GridDistributedLockCancelledException;
+import org.apache.ignite.internal.processors.cache.distributed.dht.colocated.GridDhtColocatedLockFuture;
import org.apache.ignite.internal.processors.cache.distributed.near.GridNearCacheAdapter;
import org.apache.ignite.internal.processors.cache.transactions.IgniteTxEntry;
import org.apache.ignite.internal.processors.cache.transactions.IgniteTxKey;
@@ -67,6 +68,7 @@ import org.apache.ignite.internal.util.typedef.F;
import org.apache.ignite.internal.util.typedef.internal.CU;
import org.apache.ignite.internal.util.typedef.internal.S;
import org.apache.ignite.internal.util.typedef.internal.U;
+import org.apache.ignite.lang.IgniteInClosure;
import org.apache.ignite.lang.IgniteUuid;
import org.apache.ignite.transactions.TransactionIsolation;
import org.jetbrains.annotations.NotNull;
@@ -259,6 +261,38 @@ public final class GridDhtLockFuture extends GridCacheCompoundIdentityFuture<Boo
msgLog = cctx.shared().txLockMessageLogger();
log = U.logger(cctx.kernalContext(), logRef, GridDhtLockFuture.class);
}
+
+ if (tx != null) {
+ while(true) {
+ IgniteInternalFuture<Boolean> fut = tx.lockFut;
+
+ if (fut != null) {
+ if (fut == GridDhtTxLocalAdapter.ROLLBACK_FUT)
+ onError(tx.timedOut() ? tx.timeoutException() : tx.rollbackException());
+ else {
+ // Wait for collocated lock future.
+ assert fut instanceof GridDhtColocatedLockFuture : fut;
+
+ // Terminate this future if parent(collocated) future is terminated by rollback.
+ fut.listen(new IgniteInClosure<IgniteInternalFuture<Boolean>>() {
+ @Override public void apply(IgniteInternalFuture<Boolean> fut) {
+ try {
+ fut.get();
+ }
+ catch (IgniteCheckedException e) {
+ onError(e);
+ }
+ }
+ });
+ }
+
+ return;
+ }
+
+ if (tx.updateLockFuture(null, this))
+ return;
+ }
+ }
}
/** {@inheritDoc} */
@@ -650,19 +684,23 @@ public final class GridDhtLockFuture extends GridCacheCompoundIdentityFuture<Boo
* @param entry Entry whose lock ownership changed.
*/
@Override public boolean onOwnerChanged(GridCacheEntryEx entry, GridCacheMvccCandidate owner) {
- if (isDone() || (inTx() && tx.remainingTime() == -1))
+ if (isDone() || (inTx() && (tx.remainingTime() == -1 || tx.isRollbackOnly())))
return false; // Check other futures.
if (log.isDebugEnabled())
log.debug("Received onOwnerChanged() callback [entry=" + entry + ", owner=" + owner + "]");
if (owner != null && owner.version().equals(lockVer)) {
+ boolean isEmpty;
+
synchronized (this) {
if (!pendingLocks.remove(entry.key()))
return false;
+
+ isEmpty = pendingLocks.isEmpty();
}
- if (checkLocks())
+ if (isEmpty)
map(entries());
return true;
@@ -722,7 +760,7 @@ public final class GridDhtLockFuture extends GridCacheCompoundIdentityFuture<Boo
* @param unlock {@code True} if locks should be released.
* @return {@code True} if complete by this operation.
*/
- private boolean onComplete(boolean success, boolean stopping, boolean unlock) {
+ private synchronized boolean onComplete(boolean success, boolean stopping, boolean unlock) {
if (log.isDebugEnabled())
log.debug("Received onComplete(..) callback [success=" + success + ", fut=" + this + ']');
@@ -735,6 +773,9 @@ public final class GridDhtLockFuture extends GridCacheCompoundIdentityFuture<Boo
cctx.tm().txContext(tx);
set = cctx.tm().setTxTopologyHint(tx.topologyVersionSnapshot());
+
+ if (success)
+ tx.clearLockFuture(this);
}
try {
@@ -774,7 +815,7 @@ public final class GridDhtLockFuture extends GridCacheCompoundIdentityFuture<Boo
readyLocks();
- if (timeout > 0) {
+ if (timeout > 0 && !isDone()) { // Prevent memory leak if future is completed by call to readyLocks.
timeoutObj = new LockTimeoutObject();
cctx.time().addTimeoutObject(timeoutObj);
@@ -782,6 +823,21 @@ public final class GridDhtLockFuture extends GridCacheCompoundIdentityFuture<Boo
}
/**
+ *
+ * @return {@code True} if future is done.
+ */
+ private boolean checkDone() {
+ if (isDone()) {
+ if (log.isDebugEnabled())
+ log.debug("Mapping won't proceed because future is done: " + this);
+
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
* @param entries Entries.
*/
private void map(Iterable<GridDhtCacheEntry> entries) {
@@ -835,139 +891,146 @@ public final class GridDhtLockFuture extends GridCacheCompoundIdentityFuture<Boo
}
}
- if (isDone()) {
- if (log.isDebugEnabled())
- log.debug("Mapping won't proceed because future is done: " + this);
-
+ if (checkDone())
return;
- }
if (log.isDebugEnabled())
log.debug("Mapped DHT lock future [dhtMap=" + F.nodeIds(dhtMap.keySet()) + ", dhtLockFut=" + this + ']');
long timeout = inTx() ? tx.remainingTime() : this.timeout;
- // Create mini futures.
- for (Map.Entry<ClusterNode, List<GridDhtCacheEntry>> mapped : dhtMap.entrySet()) {
- ClusterNode n = mapped.getKey();
+ synchronized (this) { // Prevents entry removal on concurrent rollback.
+ if (checkDone())
+ return;
+
+ // Create mini futures.
+ for (Map.Entry<ClusterNode, List<GridDhtCacheEntry>> mapped : dhtMap.entrySet()) {
+ ClusterNode n = mapped.getKey();
- List<GridDhtCacheEntry> dhtMapping = mapped.getValue();
+ List<GridDhtCacheEntry> dhtMapping = mapped.getValue();
- int cnt = F.size(dhtMapping);
+ int cnt = F.size(dhtMapping);
- if (cnt > 0) {
- assert !n.id().equals(cctx.localNodeId());
+ if (cnt > 0) {
+ assert !n.id().equals(cctx.localNodeId());
- if (inTx() && tx.remainingTime() == -1)
- return;
+ if (inTx() && tx.remainingTime() == -1)
+ return;
- MiniFuture fut = new MiniFuture(n, dhtMapping);
-
- GridDhtLockRequest req = new GridDhtLockRequest(
- cctx.cacheId(),
- nearNodeId,
- inTx() ? tx.nearXidVersion() : null,
- threadId,
- futId,
- fut.futureId(),
- lockVer,
- topVer,
- inTx(),
- read,
- isolation(),
- isInvalidate(),
- timeout,
- cnt,
- 0,
- inTx() ? tx.size() : cnt,
- inTx() ? tx.subjectId() : null,
- inTx() ? tx.taskNameHash() : 0,
- read ? accessTtl : -1L,
- skipStore,
- cctx.store().configured(),
- keepBinary,
- cctx.deploymentEnabled());
-
- try {
- for (ListIterator<GridDhtCacheEntry> it = dhtMapping.listIterator(); it.hasNext();) {
- GridDhtCacheEntry e = it.next();
-
- boolean needVal = false;
+ MiniFuture fut = new MiniFuture(n, dhtMapping);
+
+ GridDhtLockRequest req = new GridDhtLockRequest(
+ cctx.cacheId(),
+ nearNodeId,
+ inTx() ? tx.nearXidVersion() : null,
+ threadId,
+ futId,
+ fut.futureId(),
+ lockVer,
+ topVer,
+ inTx(),
+ read,
+ isolation(),
+ isInvalidate(),
+ timeout,
+ cnt,
+ 0,
+ inTx() ? tx.size() : cnt,
+ inTx() ? tx.subjectId() : null,
+ inTx() ? tx.taskNameHash() : 0,
+ read ? accessTtl : -1L,
+ skipStore,
+ cctx.store().configured(),
+ keepBinary,
+ cctx.deploymentEnabled());
- try {
- // Must unswap entry so that isNewLocked returns correct value.
- e.unswap(false);
+ try {
+ for (ListIterator<GridDhtCacheEntry> it = dhtMapping.listIterator(); it.hasNext(); ) {
+ GridDhtCacheEntry e = it.next();
- needVal = e.isNewLocked();
+ boolean needVal = false;
- if (needVal) {
- List<ClusterNode> owners = cctx.topology().owners(e.partition(),
- tx != null ? tx.topologyVersion() : cctx.affinity().affinityTopologyVersion());
+ try {
+ // Must unswap entry so that isNewLocked returns correct value.
+ e.unswap(false);
- // Do not preload if local node is partition owner.
- if (owners.contains(cctx.localNode()))
- needVal = false;
- }
- }
- catch (GridCacheEntryRemovedException ex) {
- assert false : "Entry cannot become obsolete when DHT local candidate is added " +
- "[e=" + e + ", ex=" + ex + ']';
- }
+ needVal = e.isNewLocked();
+
+ if (needVal) {
+ List<ClusterNode> owners = cctx.topology().owners(e.partition(),
+ tx != null ? tx.topologyVersion() : cctx.affinity().affinityTopologyVersion());
+
+ // Do not preload if local node is partition owner.
+ if (owners.contains(cctx.localNode()))
+ needVal = false;
+ }
- // Skip entry if it is not new and is not present in updated mapping.
- if (tx != null && !needVal)
- continue;
+ // Skip entry if it is not new and is not present in updated mapping.
+ if (tx != null && !needVal)
+ continue;
- boolean invalidateRdr = e.readerId(n.id()) != null;
+ boolean invalidateRdr = e.readerId(n.id()) != null;
- req.addDhtKey(e.key(), invalidateRdr, cctx);
+ req.addDhtKey(e.key(), invalidateRdr, cctx);
- if (needVal) {
- // Mark last added key as needed to be preloaded.
- req.markLastKeyForPreload();
+ if (needVal) {
+ // Mark last added key as needed to be preloaded.
+ req.markLastKeyForPreload();
- if (tx != null) {
- IgniteTxEntry txEntry = tx.entry(e.txKey());
+ if (tx != null) {
+ IgniteTxEntry txEntry = tx.entry(e.txKey());
- // NOOP entries will be sent to backups on prepare step.
- if (txEntry.op() == GridCacheOperation.READ)
- txEntry.op(GridCacheOperation.NOOP);
+ // NOOP entries will be sent to backups on prepare step.
+ if (txEntry.op() == GridCacheOperation.READ)
+ txEntry.op(GridCacheOperation.NOOP);
+ }
+ }
+
+ GridCacheMvccCandidate added = e.candidate(lockVer);
+
+ assert added != null;
+ assert added.dhtLocal();
+
+ if (added.ownerVersion() != null)
+ req.owned(e.key(), added.ownerVersion());
+ }
+ catch (GridCacheEntryRemovedException ex) {
+ assert false : "Entry cannot become obsolete when DHT local candidate is added " +
+ "[e=" + e + ", ex=" + ex + ']';
}
}
- it.set(addOwned(req, e));
- }
-
- if (!F.isEmpty(req.keys())) {
- if (tx != null)
- tx.addLockTransactionNode(n);
+ if (!F.isEmpty(req.keys())) {
+ if (tx != null)
+ tx.addLockTransactionNode(n);
- add(fut); // Append new future.
+ add(fut); // Append new future.
- cctx.io().send(n, req, cctx.ioPolicy());
+ cctx.io().send(n, req, cctx.ioPolicy());
- if (msgLog.isDebugEnabled()) {
- msgLog.debug("DHT lock fut, sent request [txId=" + nearLockVer +
- ", dhtTxId=" + lockVer +
- ", inTx=" + inTx() +
- ", nodeId=" + n.id() + ']');
+ if (msgLog.isDebugEnabled()) {
+ msgLog.debug("DHT lock fut, sent request [txId=" + nearLockVer +
+ ", dhtTxId=" + lockVer +
+ ", inTx=" + inTx() +
+ ", nodeId=" + n.id() + ']');
+ }
}
}
- }
- catch (IgniteCheckedException e) {
- // Fail the whole thing.
- if (e instanceof ClusterTopologyCheckedException)
- fut.onResult();
- else {
- if (msgLog.isDebugEnabled()) {
- msgLog.debug("DHT lock fut, failed to send request [txId=" + nearLockVer +
- ", dhtTxId=" + lockVer +
- ", inTx=" + inTx() +
- ", node=" + n.id() +
- ", err=" + e + ']');
- }
+ catch (IgniteCheckedException e) {
+ // Fail the whole thing.
+ if (e instanceof ClusterTopologyCheckedException)
+ fut.onResult();
+ else {
+ if (msgLog.isDebugEnabled()) {
+ msgLog.debug("DHT lock fut, failed to send request [txId=" + nearLockVer +
+ ", dhtTxId=" + lockVer +
+ ", inTx=" + inTx() +
+ ", node=" + n.id() +
+ ", err=" + e + ']');
+ }
- fut.onResult(e);
+ fut.onResult(e);
+ }
}
}
}
@@ -978,35 +1041,6 @@ public final class GridDhtLockFuture extends GridCacheCompoundIdentityFuture<Boo
}
}
- /**
- * @param req Request.
- * @param e Entry.
- * @return Entry.
- */
- private GridDhtCacheEntry addOwned(GridDhtLockRequest req, GridDhtCacheEntry e) {
- while (true) {
- try {
- GridCacheMvccCandidate added = e.candidate(lockVer);
-
- assert added != null;
- assert added.dhtLocal();
-
- if (added.ownerVersion() != null)
- req.owned(e.key(), added.ownerVersion());
-
- break;
- }
- catch (GridCacheEntryRemovedException ignore) {
- if (log.isDebugEnabled())
- log.debug("Got removed entry when creating DHT lock request (will retry): " + e);
-
- e = cctx.dht().entryExx(e.key(), topVer);
- }
- }
-
- return e;
- }
-
/** {@inheritDoc} */
@Override public int hashCode() {
return futId.hashCode();
@@ -1260,38 +1294,43 @@ public final class GridDhtLockFuture extends GridCacheCompoundIdentityFuture<Boo
if (cache0.isNear())
cache0 = ((GridNearCacheAdapter)cache0).dht();
- for (GridCacheEntryInfo info : res.preloadEntries()) {
- try {
- GridCacheEntryEx entry = cache0.entryEx(info.key(), topVer);
-
- cctx.shared().database().checkpointReadLock();
+ synchronized (GridDhtLockFuture.this) { // Prevents entry re-creation on concurrent rollback.
+ if (GridDhtLockFuture.this.checkDone())
+ return;
+ for (GridCacheEntryInfo info : res.preloadEntries()) {
try {
- if (entry.initialValue(info.value(),
- info.version(),
- info.ttl(),
- info.expireTime(),
- true, topVer,
- replicate ? DR_PRELOAD : DR_NONE,
- false)) {
- if (rec && !entry.isInternal())
- cctx.events().addEvent(entry.partition(), entry.key(), cctx.localNodeId(),
- (IgniteUuid)null, null, EVT_CACHE_REBALANCE_OBJECT_LOADED, info.value(), true, null,
- false, null, null, null, false);
+ GridCacheEntryEx entry = cache0.entryEx(info.key(), topVer);
+
+ cctx.shared().database().checkpointReadLock();
+
+ try {
+ if (entry.initialValue(info.value(),
+ info.version(),
+ info.ttl(),
+ info.expireTime(),
+ true, topVer,
+ replicate ? DR_PRELOAD : DR_NONE,
+ false)) {
+ if (rec && !entry.isInternal())
+ cctx.events().addEvent(entry.partition(), entry.key(), cctx.localNodeId(),
+ (IgniteUuid)null, null, EVT_CACHE_REBALANCE_OBJECT_LOADED, info.value(), true, null,
+ false, null, null, null, false);
+ }
+ }
+ finally {
+ cctx.shared().database().checkpointReadUnlock();
}
}
- finally {
- cctx.shared().database().checkpointReadUnlock();
- }
- }
- catch (IgniteCheckedException e) {
- onDone(e);
+ catch (IgniteCheckedException e) {
+ onDone(e);
- return;
- }
- catch (GridCacheEntryRemovedException e) {
- assert false : "Entry cannot become obsolete when DHT local candidate is added " +
- "[e=" + e + ", ex=" + e + ']';
+ return;
+ }
+ catch (GridCacheEntryRemovedException e) {
+ assert false : "Entry cannot become obsolete when DHT local candidate is added " +
+ "[e=" + e + ", ex=" + e + ']';
+ }
}
}
http://git-wip-us.apache.org/repos/asf/ignite/blob/2b5d2fc5/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtTransactionalCacheAdapter.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtTransactionalCacheAdapter.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtTransactionalCacheAdapter.java
index 27e5d6f..e3e29b0 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtTransactionalCacheAdapter.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtTransactionalCacheAdapter.java
@@ -43,6 +43,7 @@ import org.apache.ignite.internal.processors.cache.GridCacheEntryRemovedExceptio
import org.apache.ignite.internal.processors.cache.GridCacheLockTimeoutException;
import org.apache.ignite.internal.processors.cache.GridCacheMvccCandidate;
import org.apache.ignite.internal.processors.cache.GridCacheReturn;
+import org.apache.ignite.internal.processors.cache.GridCacheVersionedFuture;
import org.apache.ignite.internal.processors.cache.KeyCacheObject;
import org.apache.ignite.internal.processors.cache.distributed.GridDistributedCacheEntry;
import org.apache.ignite.internal.processors.cache.distributed.GridDistributedLockCancelledException;
@@ -61,6 +62,7 @@ import org.apache.ignite.internal.processors.cache.transactions.IgniteTxKey;
import org.apache.ignite.internal.processors.cache.transactions.IgniteTxLocalEx;
import org.apache.ignite.internal.processors.cache.version.GridCacheVersion;
import org.apache.ignite.internal.transactions.IgniteTxRollbackCheckedException;
+import org.apache.ignite.internal.transactions.IgniteTxTimeoutCheckedException;
import org.apache.ignite.internal.util.F0;
import org.apache.ignite.internal.util.GridLeanSet;
import org.apache.ignite.internal.util.future.GridFinishedFuture;
@@ -74,6 +76,7 @@ import org.apache.ignite.internal.util.typedef.F;
import org.apache.ignite.internal.util.typedef.X;
import org.apache.ignite.internal.util.typedef.internal.CU;
import org.apache.ignite.internal.util.typedef.internal.U;
+import org.apache.ignite.lang.IgniteInClosure;
import org.apache.ignite.thread.IgniteThread;
import org.apache.ignite.transactions.TransactionIsolation;
import org.jetbrains.annotations.Nullable;
@@ -671,11 +674,16 @@ public abstract class GridDhtTransactionalCacheAdapter<K, V> extends GridDhtCach
f = lockAllAsync(ctx, nearNode, req, null);
// Register listener just so we print out errors.
- // Exclude lock timeout exception since it's not a fatal exception.
+ // Exclude lock timeout and rollback exceptions since it's not a fatal exception.
f.listen(CU.errorLogger(log, GridCacheLockTimeoutException.class,
- GridDistributedLockCancelledException.class));
+ GridDistributedLockCancelledException.class, IgniteTxTimeoutCheckedException.class,
+ IgniteTxRollbackCheckedException.class));
}
+ /**
+ * @param node Node.
+ * @param req Request.
+ */
private boolean waitForExchangeFuture(final ClusterNode node, final GridNearLockRequest req) {
assert req.firstClientRequest() : req;
@@ -824,6 +832,9 @@ public abstract class GridDhtTransactionalCacheAdapter<K, V> extends GridDhtCach
skipStore,
keepBinary);
+ if (fut.isDone()) // Possible in case of cancellation or timeout or rollback.
+ return fut;
+
for (KeyCacheObject key : keys) {
try {
while (true) {
@@ -832,7 +843,7 @@ public abstract class GridDhtTransactionalCacheAdapter<K, V> extends GridDhtCach
try {
fut.addEntry(entry);
- // Possible in case of cancellation or time out.
+ // Possible in case of cancellation or time out or rollback.
if (fut.isDone())
return fut;
@@ -859,9 +870,11 @@ public abstract class GridDhtTransactionalCacheAdapter<K, V> extends GridDhtCach
}
}
- ctx.mvcc().addFuture(fut);
+ if (!fut.isDone()) {
+ ctx.mvcc().addFuture(fut);
- fut.map();
+ fut.map();
+ }
return fut;
}
@@ -962,10 +975,10 @@ public abstract class GridDhtTransactionalCacheAdapter<K, V> extends GridDhtCach
}
}
- boolean timedout = false;
+ boolean timedOut = false;
for (KeyCacheObject key : keys) {
- if (timedout)
+ if (timedOut)
break;
while (true) {
@@ -980,7 +993,7 @@ public abstract class GridDhtTransactionalCacheAdapter<K, V> extends GridDhtCach
fut.addEntry(key == null ? null : entry);
if (fut.isDone()) {
- timedout = true;
+ timedOut = true;
break;
}
@@ -1079,7 +1092,7 @@ public abstract class GridDhtTransactionalCacheAdapter<K, V> extends GridDhtCach
if (tx != null)
tx.rollbackDhtLocal();
- return new GridDhtFinishedFuture<>(new IgniteCheckedException(msg));
+ return new GridDhtFinishedFuture<>(new IgniteTxRollbackCheckedException(msg));
}
tx.topologyVersion(req.topologyVersion());
@@ -1117,7 +1130,8 @@ public abstract class GridDhtTransactionalCacheAdapter<K, V> extends GridDhtCach
if (e != null)
e = U.unwrap(e);
- assert !t.empty();
+ // Transaction can be emptied by asynchronous rollback.
+ assert e != null || !t.empty();
// Create response while holding locks.
final GridNearLockResponse resp = createLockReply(nearNode,
@@ -1296,13 +1310,11 @@ public abstract class GridDhtTransactionalCacheAdapter<K, V> extends GridDhtCach
null,
req.keepBinary());
- assert e.lockedBy(mappedVer) ||
- (ctx.mvcc().isRemoved(e.context(), mappedVer) && req.timeout() > 0) :
+ assert e.lockedBy(mappedVer) || ctx.mvcc().isRemoved(e.context(), mappedVer) :
"Entry does not own lock for tx [locNodeId=" + ctx.localNodeId() +
", entry=" + e +
", mappedVer=" + mappedVer + ", ver=" + ver +
- ", tx=" + tx + ", req=" + req +
- ", err=" + err + ']';
+ ", tx=" + tx + ", req=" + req + ']';
boolean filterPassed = false;
@@ -1384,12 +1396,14 @@ public abstract class GridDhtTransactionalCacheAdapter<K, V> extends GridDhtCach
Throwable err = res.error();
// Log error before sending reply.
- if (err != null && !(err instanceof GridCacheLockTimeoutException) && !ctx.kernalContext().isStopping())
+ if (err != null && !(err instanceof GridCacheLockTimeoutException) &&
+ !(err instanceof IgniteTxRollbackCheckedException) && !ctx.kernalContext().isStopping())
U.error(log, "Failed to acquire lock for request: " + req, err);
try {
- // Don't send reply message to this node or if lock was cancelled.
- if (!nearNode.id().equals(ctx.nodeId()) && !X.hasCause(err, GridDistributedLockCancelledException.class)) {
+ // Don't send reply message to this node or if lock was cancelled or tx was rolled back asynchronously.
+ if (!nearNode.id().equals(ctx.nodeId()) && !X.hasCause(err, GridDistributedLockCancelledException.class) &&
+ !X.hasCause(err, IgniteTxRollbackCheckedException.class)) {
ctx.io().send(nearNode, res, ctx.ioPolicy());
if (txLockMsgLog.isDebugEnabled()) {
http://git-wip-us.apache.org/repos/asf/ignite/blob/2b5d2fc5/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtTxLocal.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtTxLocal.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtTxLocal.java
index 0609f04..2e19df2 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtTxLocal.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtTxLocal.java
@@ -48,6 +48,7 @@ import org.apache.ignite.internal.util.typedef.CI1;
import org.apache.ignite.internal.util.typedef.F;
import org.apache.ignite.internal.util.typedef.internal.CU;
import org.apache.ignite.internal.util.typedef.internal.U;
+import org.apache.ignite.lang.IgniteInClosure;
import org.apache.ignite.lang.IgniteUuid;
import org.apache.ignite.transactions.TransactionConcurrency;
import org.apache.ignite.transactions.TransactionIsolation;
@@ -395,13 +396,13 @@ public class GridDhtTxLocal extends GridDhtTxLocalAdapter implements GridCacheMa
else
fut.prepare(req);
}
- catch (IgniteTxTimeoutCheckedException | IgniteTxOptimisticCheckedException e) {
+ catch (IgniteTxTimeoutCheckedException | IgniteTxRollbackCheckedException | IgniteTxOptimisticCheckedException e) {
fut.onError(e);
}
catch (IgniteCheckedException e) {
setRollbackOnly();
- fut.onError(new IgniteTxRollbackCheckedException("Failed to prepare transaction: " + this, e));
+ fut.onError(new IgniteTxRollbackCheckedException("Failed to prepare transaction: " + CU.txString(this), e));
}
return chainOnePhasePrepare(fut);
@@ -419,6 +420,30 @@ public class GridDhtTxLocal extends GridDhtTxLocalAdapter implements GridCacheMa
IgniteCheckedException err = null;
+ if (!commit) {
+ final IgniteInternalFuture<?> lockFut = tryRollbackAsync();
+
+ if (lockFut != null) {
+ if (lockFut instanceof GridDhtLockFuture)
+ ((GridDhtLockFuture)lockFut).onError(rollbackException());
+ else {
+ /**
+ * Prevents race with {@link GridDhtTransactionalCacheAdapter#lockAllAsync
+ * (GridCacheContext, ClusterNode, GridNearLockRequest, CacheEntryPredicate[])}
+ */
+ final IgniteInternalFuture finalPrepFut = prepFut;
+
+ lockFut.listen(new IgniteInClosure<IgniteInternalFuture<?>>() {
+ @Override public void apply(IgniteInternalFuture<?> ignored) {
+ finishTx(false, finalPrepFut, fut);
+ }
+ });
+
+ return;
+ }
+ }
+ }
+
if (!commit && prepFut != null) {
try {
prepFut.get();
http://git-wip-us.apache.org/repos/asf/ignite/blob/2b5d2fc5/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtTxLocalAdapter.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtTxLocalAdapter.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtTxLocalAdapter.java
index bed9243..604fe06 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtTxLocalAdapter.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtTxLocalAdapter.java
@@ -25,6 +25,7 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
+import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
import org.apache.ignite.IgniteCheckedException;
import org.apache.ignite.cluster.ClusterNode;
import org.apache.ignite.internal.IgniteInternalFuture;
@@ -46,7 +47,9 @@ import org.apache.ignite.internal.util.GridLeanMap;
import org.apache.ignite.internal.util.GridLeanSet;
import org.apache.ignite.internal.util.future.GridEmbeddedFuture;
import org.apache.ignite.internal.util.future.GridFinishedFuture;
+import org.apache.ignite.internal.util.future.GridFutureAdapter;
import org.apache.ignite.internal.util.tostring.GridToStringBuilder;
+import org.apache.ignite.internal.util.tostring.GridToStringExclude;
import org.apache.ignite.internal.util.typedef.CX1;
import org.apache.ignite.internal.util.typedef.F;
import org.apache.ignite.internal.util.typedef.internal.CU;
@@ -59,7 +62,6 @@ import org.jetbrains.annotations.Nullable;
import java.util.concurrent.ConcurrentHashMap;
import static org.apache.ignite.internal.processors.cache.GridCacheOperation.NOOP;
-import static org.apache.ignite.internal.processors.cache.GridCacheOperation.READ;
import static org.apache.ignite.transactions.TransactionState.COMMITTED;
import static org.apache.ignite.transactions.TransactionState.COMMITTING;
import static org.apache.ignite.transactions.TransactionState.PREPARED;
@@ -75,6 +77,13 @@ public abstract class GridDhtTxLocalAdapter extends IgniteTxLocalAdapter {
/** */
private static final long serialVersionUID = 0L;
+ /** Asynchronous rollback marker for lock futures. */
+ protected static final IgniteInternalFuture<Boolean> ROLLBACK_FUT = new GridFutureAdapter<>();
+
+ /** Lock future updater. */
+ private static final AtomicReferenceFieldUpdater<GridDhtTxLocalAdapter, IgniteInternalFuture> LOCK_FUT_UPD =
+ AtomicReferenceFieldUpdater.newUpdater(GridDhtTxLocalAdapter.class, IgniteInternalFuture.class, "lockFut");
+
/** Near mappings. */
protected Map<UUID, GridDistributedTxMapping> nearMap = new ConcurrentHashMap<>();
@@ -96,6 +105,11 @@ public abstract class GridDhtTxLocalAdapter extends IgniteTxLocalAdapter {
/** Nodes where transactions were started on lock step. */
private Set<ClusterNode> lockTxNodes;
+ /** Enlist or lock future what is currently in progress. */
+ @SuppressWarnings("UnusedDeclaration")
+ @GridToStringExclude
+ protected volatile IgniteInternalFuture<Boolean> lockFut;
+
/**
* Empty constructor required for {@link Externalizable}.
*/
@@ -561,69 +575,79 @@ public abstract class GridDhtTxLocalAdapter extends IgniteTxLocalAdapter {
onePhaseCommit(onePhaseCommit);
try {
- Set<KeyCacheObject> skipped = null;
+ GridFutureAdapter<GridCacheReturn> enlistFut = new GridFutureAdapter<>();
- AffinityTopologyVersion topVer = topologyVersion();
+ if (!updateLockFuture(null, enlistFut))
+ return finishFuture(enlistFut, timedOut() ? timeoutException() : rollbackException(), false);
- GridDhtCacheAdapter dhtCache = cacheCtx.isNear() ? cacheCtx.near().dht() : cacheCtx.dht();
+ Set<KeyCacheObject> skipped = null;
- // Enlist locks into transaction.
- for (int i = 0; i < entries.size(); i++) {
- GridCacheEntryEx entry = entries.get(i);
+ try {
+ AffinityTopologyVersion topVer = topologyVersion();
- KeyCacheObject key = entry.key();
+ GridDhtCacheAdapter dhtCache = cacheCtx.isNear() ? cacheCtx.near().dht() : cacheCtx.dht();
- IgniteTxEntry txEntry = entry(entry.txKey());
+ // Enlist locks into transaction.
+ for (int i = 0; i < entries.size(); i++) {
+ GridCacheEntryEx entry = entries.get(i);
- // First time access.
- if (txEntry == null) {
- GridDhtCacheEntry cached;
+ KeyCacheObject key = entry.key();
- while (true) {
- try {
- cached = dhtCache.entryExx(key, topVer);
+ IgniteTxEntry txEntry = entry(entry.txKey());
- cached.unswap(read);
+ // First time access.
+ if (txEntry == null) {
+ GridDhtCacheEntry cached;
- break;
- }
- catch (GridCacheEntryRemovedException ignore) {
- if (log.isDebugEnabled())
- log.debug("Get removed entry: " + key);
- }
- }
-
- addActiveCache(dhtCache.context(), false);
+ while (true) {
+ try {
+ cached = dhtCache.entryExx(key, topVer);
- txEntry = addEntry(NOOP,
- null,
- null,
- null,
- cached,
- null,
- CU.empty0(),
- false,
- -1L,
- -1L,
- null,
- skipStore,
- keepBinary,
- nearCache);
-
- if (read)
- txEntry.ttl(accessTtl);
+ cached.unswap(read);
- txEntry.cached(cached);
+ break;
+ }
+ catch (GridCacheEntryRemovedException ignore) {
+ if (log.isDebugEnabled())
+ log.debug("Get removed entry: " + key);
+ }
+ }
- addReader(msgId, cached, txEntry, topVer);
- }
- else {
- if (skipped == null)
- skipped = new GridLeanSet<>();
+ addActiveCache(dhtCache.context(), false);
+
+ txEntry = addEntry(NOOP,
+ null,
+ null,
+ null,
+ cached,
+ null,
+ CU.empty0(),
+ false,
+ -1L,
+ -1L,
+ null,
+ skipStore,
+ keepBinary,
+ nearCache);
+
+ if (read)
+ txEntry.ttl(accessTtl);
+
+ txEntry.cached(cached);
+
+ addReader(msgId, cached, txEntry, topVer);
+ }
+ else {
+ if (skipped == null)
+ skipped = new GridLeanSet<>();
- skipped.add(key);
+ skipped.add(key);
+ }
}
}
+ finally {
+ finishFuture(enlistFut, null, true);
+ }
assert pessimistic();
@@ -690,6 +714,9 @@ public abstract class GridDhtTxLocalAdapter extends IgniteTxLocalAdapter {
if (timeout == -1)
return new GridFinishedFuture<>(timeoutException());
+ if (isRollbackOnly())
+ return new GridFinishedFuture<>(rollbackException());
+
IgniteInternalFuture<Boolean> fut = dhtCache.lockAllAsyncInternal(passedKeys,
timeout,
this,
@@ -826,6 +853,68 @@ public abstract class GridDhtTxLocalAdapter extends IgniteTxLocalAdapter {
}
/**
+ * Atomically updates lock future.
+ *
+ * @param oldFut Old future.
+ * @param newFut New future.
+ *
+ * @return {@code true} If future was changed.
+ */
+ public boolean updateLockFuture(IgniteInternalFuture<?> oldFut, IgniteInternalFuture<?> newFut) {
+ return LOCK_FUT_UPD.compareAndSet(this, oldFut, newFut);
+ }
+
+ /**
+ * Clears lock future.
+ *
+ * @param cond Clear lock condition.
+ */
+ public void clearLockFuture(@Nullable IgniteInternalFuture cond) {
+ IgniteInternalFuture f = lockFut;
+
+ if (cond != null && f != cond)
+ return;
+
+ lockFut = null;
+ }
+
+ /**
+ *
+ * @param f Future to finish.
+ * @param err Error.
+ * @param clearLockFut {@code True} if need to clear lock future.
+ *
+ * @return Finished future.
+ */
+ public <T> GridFutureAdapter<T> finishFuture(GridFutureAdapter<T> f, Throwable err, boolean clearLockFut) {
+ if (clearLockFut)
+ clearLockFuture(null);
+
+ f.onDone(err);
+
+ return f;
+ }
+
+ /**
+ * Prepare async rollback.
+ *
+ * @return Current lock future or null if it's safe to roll back.
+ */
+ public @Nullable IgniteInternalFuture<?> tryRollbackAsync() {
+ IgniteInternalFuture<Boolean> fut;
+
+ while(true) {
+ fut = lockFut;
+
+ if (fut != null)
+ return fut == ROLLBACK_FUT ? null : fut;
+
+ if (updateLockFuture(null, ROLLBACK_FUT))
+ return null;
+ }
+ }
+
+ /**
* @param prepFut Prepare future.
* @return If transaction if finished on prepare step returns future which is completed after transaction finish.
*/
http://git-wip-us.apache.org/repos/asf/ignite/blob/2b5d2fc5/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtTxPrepareFuture.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtTxPrepareFuture.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtTxPrepareFuture.java
index bde15c2..622774d 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtTxPrepareFuture.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtTxPrepareFuture.java
@@ -1040,7 +1040,7 @@ public final class GridDhtTxPrepareFuture extends GridCacheCompoundFuture<Ignite
readyLocks();
- if (timeoutObj != null) {
+ if (timeoutObj != null && !isDone()) {
// Start timeout tracking after 'readyLocks' to avoid race with timeout processing.
cctx.time().addTimeoutObject(timeoutObj);
}
http://git-wip-us.apache.org/repos/asf/ignite/blob/2b5d2fc5/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtTxPrepareRequest.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtTxPrepareRequest.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtTxPrepareRequest.java
index d334850..12819bf 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtTxPrepareRequest.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtTxPrepareRequest.java
@@ -103,6 +103,9 @@ public class GridDhtTxPrepareRequest extends GridDistributedTxPrepareRequest {
@GridDirectTransient
private List<IgniteTxKey> nearWritesCacheMissed;
+ /** {@code True} if remote tx should skip adding itself to completed versions map on finish. */
+ private boolean skipCompletedVers;
+
/**
* Empty constructor required for {@link Externalizable}.
*/
@@ -169,6 +172,8 @@ public class GridDhtTxPrepareRequest extends GridDistributedTxPrepareRequest {
invalidateNearEntries = new BitSet(dhtWrites == null ? 0 : dhtWrites.size());
nearNodeId = tx.nearNodeId();
+
+ skipCompletedVers = tx.xidVersion() == tx.nearXidVersion();
}
/**
@@ -293,6 +298,13 @@ public class GridDhtTxPrepareRequest extends GridDistributedTxPrepareRequest {
}
/**
+ * @return {@code True} if remote tx should skip adding itself to completed versions map on finish.
+ */
+ public boolean skipCompletedVersion() {
+ return skipCompletedVers;
+ }
+
+ /**
* {@inheritDoc}
*
* @param ctx
@@ -443,18 +455,24 @@ public class GridDhtTxPrepareRequest extends GridDistributedTxPrepareRequest {
writer.incrementState();
case 29:
- if (!writer.writeUuid("subjId", subjId))
+ if (!writer.writeBoolean("skipCompletedVers", skipCompletedVers))
return false;
writer.incrementState();
case 30:
- if (!writer.writeInt("taskNameHash", taskNameHash))
+ if (!writer.writeUuid("subjId", subjId))
return false;
writer.incrementState();
case 31:
+ if (!writer.writeInt("taskNameHash", taskNameHash))
+ return false;
+
+ writer.incrementState();
+
+ case 32:
if (!writer.writeMessage("topVer", topVer))
return false;
@@ -549,7 +567,7 @@ public class GridDhtTxPrepareRequest extends GridDistributedTxPrepareRequest {
reader.incrementState();
case 29:
- subjId = reader.readUuid("subjId");
+ skipCompletedVers = reader.readBoolean("skipCompletedVers");
if (!reader.isLastRead())
return false;
@@ -557,7 +575,7 @@ public class GridDhtTxPrepareRequest extends GridDistributedTxPrepareRequest {
reader.incrementState();
case 30:
- taskNameHash = reader.readInt("taskNameHash");
+ subjId = reader.readUuid("subjId");
if (!reader.isLastRead())
return false;
@@ -565,6 +583,14 @@ public class GridDhtTxPrepareRequest extends GridDistributedTxPrepareRequest {
reader.incrementState();
case 31:
+ taskNameHash = reader.readInt("taskNameHash");
+
+ if (!reader.isLastRead())
+ return false;
+
+ reader.incrementState();
+
+ case 32:
topVer = reader.readMessage("topVer");
if (!reader.isLastRead())
@@ -584,6 +610,6 @@ public class GridDhtTxPrepareRequest extends GridDistributedTxPrepareRequest {
/** {@inheritDoc} */
@Override public byte fieldsCount() {
- return 32;
+ return 33;
}
}
http://git-wip-us.apache.org/repos/asf/ignite/blob/2b5d2fc5/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/colocated/GridDhtColocatedCache.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/colocated/GridDhtColocatedCache.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/colocated/GridDhtColocatedCache.java
index 607f363..14d3866 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/colocated/GridDhtColocatedCache.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/colocated/GridDhtColocatedCache.java
@@ -194,7 +194,7 @@ public class GridDhtColocatedCache<K, V> extends GridDhtTransactionalCacheAdapte
if (tx != null && !tx.implicit() && !skipTx) {
return asyncOp(tx, new AsyncOp<V>() {
@Override public IgniteInternalFuture<V> op(GridNearTxLocal tx, AffinityTopologyVersion readyTopVer) {
- IgniteInternalFuture<Map<Object, Object>> fut = tx.getAllAsync(ctx,
+ IgniteInternalFuture<Map<Object, Object>> fut = tx.getAllAsync(ctx,
readyTopVer,
Collections.singleton(ctx.toCacheKeyObject(key)),
deserializeBinary,
@@ -425,7 +425,7 @@ public class GridDhtColocatedCache<K, V> extends GridDhtTransactionalCacheAdapte
if (expiryPlc == null)
expiryPlc = expiryPolicy(null);
- // Optimisation: try to resolve value locally and escape 'get future' creation.
+ // Optimization: try to resolve value locally and escape 'get future' creation.
if (!forcePrimary && ctx.affinityNode()) {
try {
Map<K, V> locVals = null;
http://git-wip-us.apache.org/repos/asf/ignite/blob/2b5d2fc5/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/colocated/GridDhtColocatedLockFuture.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/colocated/GridDhtColocatedLockFuture.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/colocated/GridDhtColocatedLockFuture.java
index c10f2ca..da0858f 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/colocated/GridDhtColocatedLockFuture.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/colocated/GridDhtColocatedLockFuture.java
@@ -23,6 +23,7 @@ import java.util.Collection;
import java.util.Deque;
import java.util.HashSet;
import java.util.Iterator;
+import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
@@ -56,7 +57,6 @@ import org.apache.ignite.internal.processors.cache.distributed.near.GridNearLock
import org.apache.ignite.internal.processors.cache.distributed.near.GridNearLockRequest;
import org.apache.ignite.internal.processors.cache.distributed.near.GridNearLockResponse;
import org.apache.ignite.internal.processors.cache.distributed.near.GridNearTxLocal;
-import org.apache.ignite.internal.processors.cache.transactions.IgniteInternalTx;
import org.apache.ignite.internal.processors.cache.transactions.IgniteTxEntry;
import org.apache.ignite.internal.processors.cache.transactions.IgniteTxKey;
import org.apache.ignite.internal.processors.cache.transactions.TxDeadlock;
@@ -237,6 +237,12 @@ public final class GridDhtColocatedLockFuture extends GridCacheCompoundIdentityF
}
valMap = new ConcurrentHashMap<>();
+
+ if (tx != null && !tx.updateLockFuture(null, this)) {
+ onError(tx.timedOut() ? tx.timeoutException() : tx.rollbackException());
+
+ onComplete(false, false);
+ }
}
/** {@inheritDoc} */
@@ -405,7 +411,7 @@ public final class GridDhtColocatedLockFuture extends GridCacheCompoundIdentityF
* @param success Success flag.
*/
public void complete(boolean success) {
- onComplete(success, true, true);
+ onComplete(success, true);
}
/**
@@ -450,8 +456,9 @@ public final class GridDhtColocatedLockFuture extends GridCacheCompoundIdentityF
return;
}
+ // This warning can be triggered by deadlock detection code which clears pending futures.
U.warn(msgLog, "Collocated lock fut, failed to find mini future [txId=" + lockVer +
- ", inTx=" + inTx() +
+ ", tx=" + (inTx() ? CU.txString(tx) : "N/A") +
", node=" + nodeId +
", res=" + res +
", fut=" + this + ']');
@@ -536,12 +543,14 @@ public final class GridDhtColocatedLockFuture extends GridCacheCompoundIdentityF
err = t;
}
- /** {@inheritDoc} */
+ /**
+ * Cancellation has special meaning for lock futures. It's called then lock must be released on rollback.
+ */
@Override public boolean cancel() {
- if (onCancelled())
- onComplete(false, true, true);
+ if (inTx())
+ onError(tx.rollbackException());
- return isCancelled();
+ return onComplete(false, true);
}
/** {@inheritDoc} */
@@ -562,7 +571,7 @@ public final class GridDhtColocatedLockFuture extends GridCacheCompoundIdentityF
if (err != null)
success = false;
- return onComplete(success, true, true);
+ return onComplete(success, true);
}
/**
@@ -570,10 +579,9 @@ public final class GridDhtColocatedLockFuture extends GridCacheCompoundIdentityF
*
* @param success {@code True} if lock was acquired.
* @param distribute {@code True} if need to distribute lock removal in case of failure.
- * @param restoreTimeout {@code True} if need restore tx timeout callback.
* @return {@code True} if complete by this operation.
*/
- private boolean onComplete(boolean success, boolean distribute, boolean restoreTimeout) {
+ private boolean onComplete(boolean success, boolean distribute) {
if (log.isDebugEnabled()) {
log.debug("Received onComplete(..) callback [success=" + success + ", distribute=" + distribute +
", fut=" + this + ']');
@@ -588,12 +596,8 @@ public final class GridDhtColocatedLockFuture extends GridCacheCompoundIdentityF
if (tx != null) {
cctx.tm().txContext(tx);
- if (restoreTimeout && tx.trackTimeout()) {
- // Need restore timeout before onDone is called and next tx operation can proceed.
- boolean add = tx.addTimeoutHandler();
-
- assert add;
- }
+ if (success)
+ tx.clearLockFuture(this);
}
if (super.onDone(success, err)) {
@@ -694,23 +698,8 @@ public final class GridDhtColocatedLockFuture extends GridCacheCompoundIdentityF
* part. Note that if primary node leaves grid, the future will fail and transaction will be rolled back.
*/
void map() {
- if (tx != null && tx.trackTimeout()) {
- if (!tx.removeTimeoutHandler()) {
- tx.finishFuture().listen(new IgniteInClosure<IgniteInternalFuture<IgniteInternalTx>>() {
- @Override public void apply(IgniteInternalFuture<IgniteInternalTx> fut) {
- IgniteTxTimeoutCheckedException err = new IgniteTxTimeoutCheckedException("Failed to " +
- "acquire lock, transaction was rolled back on timeout [timeout=" + tx.timeout() +
- ", tx=" + tx + ']');
-
- onError(err);
-
- onComplete(false, false, false);
- }
- });
-
- return;
- }
- }
+ if (isDone()) // Possible due to async rollback.
+ return;
if (timeout > 0) {
timeoutObj = new LockTimeoutObject();
@@ -973,7 +962,7 @@ public final class GridDhtColocatedLockFuture extends GridCacheCompoundIdentityF
if (log.isDebugEnabled())
log.debug("Entry being locked did not pass filter (will not lock): " + entry);
- onComplete(false, false, true);
+ onComplete(false, false);
return;
}
@@ -1350,7 +1339,7 @@ public final class GridDhtColocatedLockFuture extends GridCacheCompoundIdentityF
if (log.isDebugEnabled())
log.debug("Entry being locked did not pass filter (will not lock): " + entry);
- onComplete(false, false, true);
+ onComplete(false, false);
return false;
}
@@ -1430,44 +1419,48 @@ public final class GridDhtColocatedLockFuture extends GridCacheCompoundIdentityF
if (log.isDebugEnabled())
log.debug("Timed out waiting for lock response: " + this);
- if (inTx() && cctx.tm().deadlockDetectionEnabled()) {
- synchronized (GridDhtColocatedLockFuture.this) {
- requestedKeys = requestedKeys0();
+ if (inTx()) {
+ if (cctx.tm().deadlockDetectionEnabled()) {
+ synchronized (GridDhtColocatedLockFuture.this) {
+ requestedKeys = requestedKeys0();
- clear(); // Stop response processing.
- }
+ clear(); // Stop response processing.
+ }
- Set<IgniteTxKey> keys = new HashSet<>();
+ Set<IgniteTxKey> keys = new HashSet<>();
- for (IgniteTxEntry txEntry : tx.allEntries()) {
- if (!txEntry.locked())
- keys.add(txEntry.txKey());
- }
+ for (IgniteTxEntry txEntry : tx.allEntries()) {
+ if (!txEntry.locked())
+ keys.add(txEntry.txKey());
+ }
- IgniteInternalFuture<TxDeadlock> fut = cctx.tm().detectDeadlock(tx, keys);
+ IgniteInternalFuture<TxDeadlock> fut = cctx.tm().detectDeadlock(tx, keys);
- fut.listen(new IgniteInClosure<IgniteInternalFuture<TxDeadlock>>() {
- @Override public void apply(IgniteInternalFuture<TxDeadlock> fut) {
- try {
- TxDeadlock deadlock = fut.get();
+ fut.listen(new IgniteInClosure<IgniteInternalFuture<TxDeadlock>>() {
+ @Override public void apply(IgniteInternalFuture<TxDeadlock> fut) {
+ try {
+ TxDeadlock deadlock = fut.get();
- if (deadlock != null)
- err = new IgniteTxTimeoutCheckedException("Failed to acquire lock within provided timeout for " +
- "transaction [timeout=" + tx.timeout() + ", tx=" + tx + ']',
- new TransactionDeadlockException(deadlock.toString(cctx.shared())));
- }
- catch (IgniteCheckedException e) {
- err = e;
+ err = new IgniteTxTimeoutCheckedException("Failed to acquire lock within provided " +
+ "timeout for transaction [timeout=" + tx.timeout() + ", tx=" + CU.txString(tx) + ']',
+ deadlock != null ? new TransactionDeadlockException(deadlock.toString(cctx.shared())) :
+ null);
+ }
+ catch (IgniteCheckedException e) {
+ err = e;
- U.warn(log, "Failed to detect deadlock.", e);
- }
+ U.warn(log, "Failed to detect deadlock.", e);
+ }
- onComplete(false, true, true);
- }
- });
+ onComplete(false, true);
+ }
+ });
+ }
+ else
+ err = tx.timeoutException();
}
else
- onComplete(false, true, true);
+ onComplete(false, true);
}
/** {@inheritDoc} */
@@ -1716,4 +1709,4 @@ public final class GridDhtColocatedLockFuture extends GridCacheCompoundIdentityF
return S.toString(MiniFuture.class, this, "node", node.id(), "super", super.toString());
}
}
-}
\ No newline at end of file
+}
http://git-wip-us.apache.org/repos/asf/ignite/blob/2b5d2fc5/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionsExchangeFuture.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionsExchangeFuture.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionsExchangeFuture.java
index a21d98e..c8e0034 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionsExchangeFuture.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionsExchangeFuture.java
@@ -43,6 +43,7 @@ import org.apache.ignite.IgniteSystemProperties;
import org.apache.ignite.cache.CacheMode;
import org.apache.ignite.cache.CacheRebalanceMode;
import org.apache.ignite.cluster.ClusterNode;
+import org.apache.ignite.configuration.IgniteConfiguration;
import org.apache.ignite.configuration.NearCacheConfiguration;
import org.apache.ignite.events.DiscoveryEvent;
import org.apache.ignite.internal.IgniteClientDisconnectedCheckedException;
@@ -1243,11 +1244,17 @@ public class GridDhtPartitionsExchangeFuture extends GridDhtTopologyFutureAdapte
long nextDumpTime = 0;
- long futTimeout = 2 * cctx.gridConfig().getNetworkTimeout();
+ IgniteConfiguration cfg = cctx.gridConfig();
+
+ boolean rollbackEnabled = cfg.getTransactionConfiguration().getTxTimeoutOnPartitionMapExchange() > 0;
+
+ long waitTimeout = 2 * cfg.getNetworkTimeout();
while (true) {
try {
- partReleaseFut.get(futTimeout, TimeUnit.MILLISECONDS);
+ partReleaseFut.get(rollbackEnabled ?
+ cfg.getTransactionConfiguration().getTxTimeoutOnPartitionMapExchange() :
+ waitTimeout, TimeUnit.MILLISECONDS);
break;
}
@@ -1256,7 +1263,13 @@ public class GridDhtPartitionsExchangeFuture extends GridDhtTopologyFutureAdapte
if (nextDumpTime <= U.currentTimeMillis()) {
dumpPendingObjects(partReleaseFut);
- nextDumpTime = U.currentTimeMillis() + nextDumpTimeout(dumpCnt++, futTimeout);
+ nextDumpTime = U.currentTimeMillis() + nextDumpTimeout(dumpCnt++, waitTimeout);
+ }
+
+ if (rollbackEnabled) {
+ rollbackEnabled = false;
+
+ cctx.tm().rollbackOnTopologyChange(initialVersion());
}
}
catch (IgniteCheckedException e) {
@@ -1286,7 +1299,7 @@ public class GridDhtPartitionsExchangeFuture extends GridDhtTopologyFutureAdapte
while (true) {
try {
- locksFut.get(futTimeout, TimeUnit.MILLISECONDS);
+ locksFut.get(waitTimeout, TimeUnit.MILLISECONDS);
break;
}
@@ -1309,7 +1322,7 @@ public class GridDhtPartitionsExchangeFuture extends GridDhtTopologyFutureAdapte
for (Map.Entry<IgniteTxKey, Collection<GridCacheMvccCandidate>> e : locks.entrySet())
U.warn(log, "Awaited locked entry [key=" + e.getKey() + ", mvcc=" + e.getValue() + ']');
- nextDumpTime = U.currentTimeMillis() + nextDumpTimeout(dumpCnt++, futTimeout);
+ nextDumpTime = U.currentTimeMillis() + nextDumpTimeout(dumpCnt++, waitTimeout);
if (getBoolean(IGNITE_THREAD_DUMP_ON_EXCHANGE_TIMEOUT, false))
U.dumpThreads(log);
@@ -1326,7 +1339,7 @@ public class GridDhtPartitionsExchangeFuture extends GridDhtTopologyFutureAdapte
try {
while (true) {
try {
- releaseLatch.await(futTimeout, TimeUnit.MILLISECONDS);
+ releaseLatch.await(waitTimeout, TimeUnit.MILLISECONDS);
if (log.isInfoEnabled())
log.info("Finished waiting for partitions release latch: " + releaseLatch);
http://git-wip-us.apache.org/repos/asf/ignite/blob/2b5d2fc5/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearLockFuture.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearLockFuture.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearLockFuture.java
index 6ff5e65..4b46bda 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearLockFuture.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearLockFuture.java
@@ -52,7 +52,6 @@ import org.apache.ignite.internal.processors.cache.distributed.GridDistributedCa
import org.apache.ignite.internal.processors.cache.distributed.dht.GridDhtCacheEntry;
import org.apache.ignite.internal.processors.cache.distributed.dht.GridDhtTopologyFuture;
import org.apache.ignite.internal.processors.cache.distributed.dht.GridDhtTransactionalCacheAdapter;
-import org.apache.ignite.internal.processors.cache.transactions.IgniteInternalTx;
import org.apache.ignite.internal.processors.cache.transactions.IgniteTxEntry;
import org.apache.ignite.internal.processors.cache.transactions.IgniteTxKey;
import org.apache.ignite.internal.processors.cache.transactions.TxDeadlock;
@@ -239,6 +238,12 @@ public final class GridNearLockFuture extends GridCacheCompoundIdentityFuture<Bo
log = U.logger(cctx.kernalContext(), logRef, GridNearLockFuture.class);
valMap = new ConcurrentHashMap<>();
+
+ if (tx != null && !tx.updateLockFuture(null, this)) {
+ err = tx.timedOut() ? tx.timeoutException() : tx.rollbackException();
+
+ onComplete(false, false);
+ }
}
/** {@inheritDoc} */
@@ -436,7 +441,7 @@ public final class GridNearLockFuture extends GridCacheCompoundIdentityFuture<Bo
* @param success Success flag.
*/
public void complete(boolean success) {
- onComplete(success, true, true);
+ onComplete(success, true);
}
/**
@@ -657,7 +662,7 @@ public final class GridNearLockFuture extends GridCacheCompoundIdentityFuture<Bo
log.debug("Local lock acquired for entries [fut=" + this + ", entries=" + entries + "]");
}
- onComplete(true, true, true);
+ onComplete(true, true);
return true;
}
@@ -665,12 +670,14 @@ public final class GridNearLockFuture extends GridCacheCompoundIdentityFuture<Bo
return false;
}
- /** {@inheritDoc} */
+ /**
+ * Cancellation has special meaning for lock futures. It's called then lock must be released on rollback.
+ */
@Override public boolean cancel() {
- if (onCancelled())
- onComplete(false, true, true);
+ if (inTx())
+ onError(tx.rollbackException());
- return isCancelled();
+ return onComplete(false, true);
}
/** {@inheritDoc} */
@@ -692,7 +699,7 @@ public final class GridNearLockFuture extends GridCacheCompoundIdentityFuture<Bo
if (err != null)
success = false;
- return onComplete(success, true, true);
+ return onComplete(success, true);
}
/**
@@ -700,10 +707,9 @@ public final class GridNearLockFuture extends GridCacheCompoundIdentityFuture<Bo
*
* @param success {@code True} if lock was acquired.
* @param distribute {@code True} if need to distribute lock removal in case of failure.
- * @param restoreTimeout {@code True} if need restore tx timeout callback.
* @return {@code True} if complete by this operation.
*/
- private boolean onComplete(boolean success, boolean distribute, boolean restoreTimeout) {
+ private boolean onComplete(boolean success, boolean distribute) {
if (log.isDebugEnabled()) {
log.debug("Received onComplete(..) callback [success=" + success + ", distribute=" + distribute +
", fut=" + this + ']');
@@ -718,12 +724,8 @@ public final class GridNearLockFuture extends GridCacheCompoundIdentityFuture<Bo
if (tx != null) {
cctx.tm().txContext(tx);
- if (restoreTimeout && tx.trackTimeout()) {
- // Need restore timeout before onDone is called and next tx operation can proceed.
- boolean add = tx.addTimeoutHandler();
-
- assert add;
- }
+ if (success)
+ tx.clearLockFuture(this);
}
if (super.onDone(success, err)) {
@@ -785,23 +787,8 @@ public final class GridNearLockFuture extends GridCacheCompoundIdentityFuture<Bo
* part. Note that if primary node leaves grid, the future will fail and transaction will be rolled back.
*/
void map() {
- if (tx != null && tx.trackTimeout()) {
- if (!tx.removeTimeoutHandler()) {
- tx.finishFuture().listen(new IgniteInClosure<IgniteInternalFuture<IgniteInternalTx>>() {
- @Override public void apply(IgniteInternalFuture<IgniteInternalTx> fut) {
- IgniteTxTimeoutCheckedException err = new IgniteTxTimeoutCheckedException("Failed to " +
- "acquire lock, transaction was rolled back on timeout [timeout=" + tx.timeout() +
- ", tx=" + tx + ']');
-
- onError(err);
-
- onComplete(false, false, false);
- }
- });
-
- return;
- }
- }
+ if (isDone()) // Possible due to async rollback.
+ return;
if (timeout > 0) {
timeoutObj = new LockTimeoutObject();
@@ -1020,7 +1007,7 @@ public final class GridNearLockFuture extends GridCacheCompoundIdentityFuture<Bo
if (log.isDebugEnabled())
log.debug("Entry being locked did not pass filter (will not lock): " + entry);
- onComplete(false, false, true);
+ onComplete(false, false);
return;
}
@@ -1476,44 +1463,48 @@ public final class GridNearLockFuture extends GridCacheCompoundIdentityFuture<Bo
timedOut = true;
- if (inTx() && cctx.tm().deadlockDetectionEnabled()) {
- synchronized (GridNearLockFuture.this) {
- requestedKeys = requestedKeys0();
+ if (inTx()) {
+ if (cctx.tm().deadlockDetectionEnabled()) {
+ synchronized (GridNearLockFuture.this) {
+ requestedKeys = requestedKeys0();
- clear(); // Stop response processing.
- }
+ clear(); // Stop response processing.
+ }
- Set<IgniteTxKey> keys = new HashSet<>();
+ Set<IgniteTxKey> keys = new HashSet<>();
- for (IgniteTxEntry txEntry : tx.allEntries()) {
- if (!txEntry.locked())
- keys.add(txEntry.txKey());
- }
+ for (IgniteTxEntry txEntry : tx.allEntries()) {
+ if (!txEntry.locked())
+ keys.add(txEntry.txKey());
+ }
- IgniteInternalFuture<TxDeadlock> fut = cctx.tm().detectDeadlock(tx, keys);
+ IgniteInternalFuture<TxDeadlock> fut = cctx.tm().detectDeadlock(tx, keys);
- fut.listen(new IgniteInClosure<IgniteInternalFuture<TxDeadlock>>() {
- @Override public void apply(IgniteInternalFuture<TxDeadlock> fut) {
- try {
- TxDeadlock deadlock = fut.get();
+ fut.listen(new IgniteInClosure<IgniteInternalFuture<TxDeadlock>>() {
+ @Override public void apply(IgniteInternalFuture<TxDeadlock> fut) {
+ try {
+ TxDeadlock deadlock = fut.get();
- if (deadlock != null)
- err = new IgniteTxTimeoutCheckedException("Failed to acquire lock within provided timeout for " +
- "transaction [timeout=" + tx.timeout() + ", tx=" + tx + ']',
- new TransactionDeadlockException(deadlock.toString(cctx.shared())));
- }
- catch (IgniteCheckedException e) {
- err = e;
+ err = new IgniteTxTimeoutCheckedException("Failed to acquire lock within provided " +
+ "timeout for transaction [timeout=" + tx.timeout() + ", tx=" + CU.txString(tx) + ']',
+ deadlock != null ? new TransactionDeadlockException(deadlock.toString(cctx.shared())) :
+ null);
+ }
+ catch (IgniteCheckedException e) {
+ err = e;
- U.warn(log, "Failed to detect deadlock.", e);
- }
+ U.warn(log, "Failed to detect deadlock.", e);
+ }
- onComplete(false, true, true);
- }
- });
+ onComplete(false, true);
+ }
+ });
+ }
+ else
+ err = tx.timeoutException();
}
else
- onComplete(false, true, true);
+ onComplete(false, true);
}
/** {@inheritDoc} */
http://git-wip-us.apache.org/repos/asf/ignite/blob/2b5d2fc5/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearOptimisticSerializableTxPrepareFuture.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearOptimisticSerializableTxPrepareFuture.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearOptimisticSerializableTxPrepareFuture.java
index 3e2c84a..974de6b 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearOptimisticSerializableTxPrepareFuture.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearOptimisticSerializableTxPrepareFuture.java
@@ -296,14 +296,12 @@ public class GridNearOptimisticSerializableTxPrepareFuture extends GridNearOptim
if (!txStateCheck) {
if (tx.isRollbackOnly() || tx.setRollbackOnly()) {
if (tx.timedOut())
- onError(null, new IgniteTxTimeoutCheckedException("Transaction timed out and " +
- "was rolled back: " + this));
+ onDone(null, tx.timeoutException());
else
- onError(null, new IgniteCheckedException("Invalid transaction state for prepare " +
- "[state=" + tx.state() + ", tx=" + this + ']'));
+ onDone(null, tx.rollbackException());
}
else
- onError(null, new IgniteTxRollbackCheckedException("Invalid transaction state for " +
+ onDone(null, new IgniteCheckedException("Invalid transaction state for " +
"prepare [state=" + tx.state() + ", tx=" + this + ']'));
return;
http://git-wip-us.apache.org/repos/asf/ignite/blob/2b5d2fc5/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearOptimisticTxPrepareFuture.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearOptimisticTxPrepareFuture.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearOptimisticTxPrepareFuture.java
index 2afb096..247af84 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearOptimisticTxPrepareFuture.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearOptimisticTxPrepareFuture.java
@@ -59,6 +59,7 @@ import org.apache.ignite.internal.util.typedef.CI1;
import org.apache.ignite.internal.util.typedef.F;
import org.apache.ignite.internal.util.typedef.P1;
import org.apache.ignite.internal.util.typedef.X;
+import org.apache.ignite.internal.util.typedef.internal.CU;
import org.apache.ignite.internal.util.typedef.internal.S;
import org.apache.ignite.internal.util.typedef.internal.U;
import org.apache.ignite.lang.IgniteBiClosure;
@@ -329,15 +330,13 @@ public class GridNearOptimisticTxPrepareFuture extends GridNearOptimisticTxPrepa
if (!txStateCheck) {
if (tx.isRollbackOnly() || tx.setRollbackOnly()) {
if (tx.remainingTime() == -1)
- onError(new IgniteTxTimeoutCheckedException("Transaction timed out and " +
- "was rolled back: " + this), false);
+ onDone(tx.timeoutException());
else
- onError(new IgniteCheckedException("Invalid transaction state for prepare " +
- "[state=" + tx.state() + ", tx=" + this + ']'), false);
+ onDone(tx.rollbackException());
}
else
- onError(new IgniteTxRollbackCheckedException("Invalid transaction state for " +
- "prepare [state=" + tx.state() + ", tx=" + this + ']'), false);
+ onDone(new IgniteCheckedException("Invalid transaction state for " +
+ "prepare [state=" + tx.state() + ", tx=" + this + ']'));
return;
}
@@ -768,7 +767,7 @@ public class GridNearOptimisticTxPrepareFuture extends GridNearOptimisticTxPrepa
U.warn(log, "Failed to detect deadlock.", e);
else {
e = new IgniteTxTimeoutCheckedException("Failed to acquire lock within provided timeout for " +
- "transaction [timeout=" + tx.timeout() + ", tx=" + tx + ']',
+ "transaction [timeout=" + tx.timeout() + ", tx=" + CU.txString(tx) + ']',
deadlock != null ? new TransactionDeadlockException(deadlock.toString(cctx)) : null);
}
http://git-wip-us.apache.org/repos/asf/ignite/blob/2b5d2fc5/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearPessimisticTxPrepareFuture.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearPessimisticTxPrepareFuture.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearPessimisticTxPrepareFuture.java
index 54ae85c..da9bdac 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearPessimisticTxPrepareFuture.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearPessimisticTxPrepareFuture.java
@@ -157,13 +157,12 @@ public class GridNearPessimisticTxPrepareFuture extends GridNearTxPrepareFutureA
if (!tx.state(PREPARING)) {
if (tx.isRollbackOnly() || tx.setRollbackOnly()) {
if (tx.remainingTime() == -1)
- onDone(new IgniteTxTimeoutCheckedException("Transaction timed out and was rolled back: " + tx));
+ onDone(tx.timeoutException());
else
- onDone(new IgniteCheckedException("Invalid transaction state for prepare " +
- "[state=" + tx.state() + ", tx=" + this + ']'));
+ onDone(tx.rollbackException());
}
else
- onDone(new IgniteTxRollbackCheckedException("Invalid transaction state for prepare " +
+ onDone(new IgniteCheckedException("Invalid transaction state for prepare " +
"[state=" + tx.state() + ", tx=" + this + ']'));
return;
http://git-wip-us.apache.org/repos/asf/ignite/blob/2b5d2fc5/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearTxFastFinishFuture.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearTxFastFinishFuture.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearTxFastFinishFuture.java
index 95e4ded..53d901a 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearTxFastFinishFuture.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearTxFastFinishFuture.java
@@ -37,17 +37,13 @@ public class GridNearTxFastFinishFuture extends GridFutureAdapter<IgniteInternal
/** */
private final boolean commit;
- /** */
- private final boolean onTimeout;
-
/**
* @param tx Transaction.
* @param commit Commit flag.
*/
- GridNearTxFastFinishFuture(GridNearTxLocal tx, boolean commit, boolean onTimeout) {
+ GridNearTxFastFinishFuture(GridNearTxLocal tx, boolean commit) {
this.tx = tx;
this.commit = commit;
- this.onTimeout = onTimeout;
}
/** {@inheritDoc} */
@@ -56,9 +52,9 @@ public class GridNearTxFastFinishFuture extends GridFutureAdapter<IgniteInternal
}
/**
- *
+ * @param clearThreadMap {@code True} if need remove tx from thread map.
*/
- public void finish() {
+ public void finish(boolean clearThreadMap) {
try {
if (commit) {
tx.state(PREPARING);
@@ -74,7 +70,7 @@ public class GridNearTxFastFinishFuture extends GridFutureAdapter<IgniteInternal
tx.state(PREPARED);
tx.state(ROLLING_BACK);
- tx.context().tm().fastFinishTx(tx, false, !onTimeout);
+ tx.context().tm().fastFinishTx(tx, false, clearThreadMap);
tx.state(ROLLED_BACK);
}