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);
             }