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 2015/09/03 03:03:39 UTC

[30/50] [abbrv] ignite git commit: Reverted committed versions for txs.

http://git-wip-us.apache.org/repos/asf/ignite/blob/a6dd5ee2/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 e2046de..067366a 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
@@ -214,7 +214,8 @@ public class IgniteTxManager extends GridCacheSharedManagerAdapter {
                 if (tx instanceof IgniteTxRemoteEx) {
                     IgniteTxRemoteEx rmtTx = (IgniteTxRemoteEx)tx;
 
-                    rmtTx.doneRemote(tx.xidVersion());
+                    rmtTx.doneRemote(tx.xidVersion(), Collections.<GridCacheVersion>emptyList(),
+                        Collections.<GridCacheVersion>emptyList(), Collections.<GridCacheVersion>emptyList());
                 }
 
                 tx.commit();
@@ -347,7 +348,7 @@ public class IgniteTxManager extends GridCacheSharedManagerAdapter {
      *      {@code false} otherwise.
      */
     public boolean isCompleted(IgniteInternalTx tx) {
-        return completedVers.containsKey(tx.writeVersion());
+        return completedVers.containsKey(tx.xidVersion());
     }
 
     /**
@@ -983,10 +984,36 @@ public class IgniteTxManager extends GridCacheSharedManagerAdapter {
     }
 
     /**
+     * Gets committed transactions starting from the given version (inclusive). // TODO: GG-4011: why inclusive?
+     *
+     * @param min Start (or minimum) version.
+     * @return Committed transactions starting from the given version (non-inclusive).
+     */
+    public Collection<GridCacheVersion> committedVersions(GridCacheVersion min) {
+        ConcurrentNavigableMap<GridCacheVersion, Boolean> tail
+            = completedVers.tailMap(min, true);
+
+        return F.isEmpty(tail) ? Collections.<GridCacheVersion>emptyList() : copyOf(tail, true);
+    }
+
+    /**
+     * Gets rolledback transactions starting from the given version (inclusive). // TODO: GG-4011: why inclusive?
+     *
+     * @param min Start (or minimum) version.
+     * @return Committed transactions starting from the given version (non-inclusive).
+     */
+    public Collection<GridCacheVersion> rolledbackVersions(GridCacheVersion min) {
+        ConcurrentNavigableMap<GridCacheVersion, Boolean> tail
+            = completedVers.tailMap(min, true);
+
+        return F.isEmpty(tail) ? Collections.<GridCacheVersion>emptyList() : copyOf(tail, false);
+    }
+
+    /**
      * @param tx Tx to remove.
      */
     public void removeCommittedTx(IgniteInternalTx tx) {
-        completedVers.remove(tx.writeVersion(), true);
+        completedVers.remove(tx.xidVersion(), true);
     }
 
     /**
@@ -994,7 +1021,7 @@ public class IgniteTxManager extends GridCacheSharedManagerAdapter {
      * @return If transaction was not already present in committed set.
      */
     public boolean addCommittedTx(IgniteInternalTx tx) {
-        return addCommittedTx(tx.writeVersion(), tx.nearXidVersion());
+        return addCommittedTx(tx.xidVersion(), tx.nearXidVersion());
     }
 
     /**
@@ -1059,6 +1086,76 @@ public class IgniteTxManager extends GridCacheSharedManagerAdapter {
     }
 
     /**
+     * @param tx Transaction.
+     */
+    private void processCompletedEntries(IgniteInternalTx tx) {
+        if (tx.needsCompletedVersions()) {
+            GridCacheVersion min = minVersion(tx.readEntries(), tx.xidVersion(), tx);
+
+            min = minVersion(tx.writeEntries(), min, tx);
+
+            assert min != null;
+
+            tx.completedVersions(min, committedVersions(min), rolledbackVersions(min));
+        }
+    }
+
+    /**
+     * Collects versions for all pending locks for all entries within transaction
+     *
+     * @param dhtTxLoc Transaction being committed.
+     */
+    private void collectPendingVersions(GridDhtTxLocal dhtTxLoc) {
+        if (dhtTxLoc.needsCompletedVersions()) {
+            if (log.isDebugEnabled())
+                log.debug("Checking for pending locks with version less then tx version: " + dhtTxLoc);
+
+            Set<GridCacheVersion> vers = new LinkedHashSet<>();
+
+            collectPendingVersions(dhtTxLoc.readEntries(), dhtTxLoc.xidVersion(), vers);
+            collectPendingVersions(dhtTxLoc.writeEntries(), dhtTxLoc.xidVersion(), vers);
+
+            if (!vers.isEmpty())
+                dhtTxLoc.pendingVersions(vers);
+        }
+    }
+
+    /**
+     * Gets versions of all not acquired locks for collection of tx entries that are less then base version.
+     *
+     * @param entries Tx entries to process.
+     * @param baseVer Base version to compare with.
+     * @param vers Collection of versions that will be populated.
+     */
+    @SuppressWarnings("TypeMayBeWeakened")
+    private void collectPendingVersions(Iterable<IgniteTxEntry> entries,
+        GridCacheVersion baseVer, Set<GridCacheVersion> vers) {
+
+        // The locks are not released yet, so we can safely list pending candidates versions.
+        for (IgniteTxEntry txEntry : entries) {
+            GridCacheEntryEx cached = txEntry.cached();
+
+            try {
+                // If check should be faster then exception handling.
+                if (!cached.obsolete()) {
+                    for (GridCacheMvccCandidate cand : cached.localCandidates()) {
+                        if (!cand.owner() && cand.version().compareTo(baseVer) < 0) {
+                            if (log.isDebugEnabled())
+                                log.debug("Adding candidate version to pending set: " + cand);
+
+                            vers.add(cand.version());
+                        }
+                    }
+                }
+            }
+            catch (GridCacheEntryRemovedException ignored) {
+                if (log.isDebugEnabled())
+                    log.debug("There are no pending locks for entry (entry was deleted in transaction): " + txEntry);
+            }
+        }
+    }
+
+    /**
      * Go through all candidates for entries involved in transaction and find their min
      * version. We know that these candidates will commit after this transaction, and
      * therefore we can grab the min version so we can send all committed and rolled
@@ -1112,7 +1209,7 @@ public class IgniteTxManager extends GridCacheSharedManagerAdapter {
          * so we don't do it here.
          */
 
-        Boolean committed = completedVers.get(tx.writeVersion());
+        Boolean committed = completedVers.get(tx.xidVersion());
 
         // 1. Make sure that committed version has been recorded.
         if (!((committed != null && committed) || tx.writeSet().isEmpty() || tx.isSystemInvalidate())) {
@@ -1129,6 +1226,15 @@ public class IgniteTxManager extends GridCacheSharedManagerAdapter {
         ConcurrentMap<GridCacheVersion, IgniteInternalTx> txIdMap = transactionMap(tx);
 
         if (txIdMap.remove(tx.xidVersion(), tx)) {
+            // 2. Must process completed entries before unlocking!
+            processCompletedEntries(tx);
+
+            if (tx instanceof GridDhtTxLocal) {
+                GridDhtTxLocal dhtTxLoc = (GridDhtTxLocal)tx;
+
+                collectPendingVersions(dhtTxLoc);
+            }
+
             // 4. Unlock write resources.
             unlockMultiple(tx, tx.writeEntries());
 
@@ -1868,7 +1974,8 @@ public class IgniteTxManager extends GridCacheSharedManagerAdapter {
         if (tx instanceof GridDistributedTxRemoteAdapter) {
             IgniteTxRemoteEx rmtTx = (IgniteTxRemoteEx)tx;
 
-            rmtTx.doneRemote(tx.xidVersion());
+            rmtTx.doneRemote(tx.xidVersion(), Collections.<GridCacheVersion>emptyList(), Collections.<GridCacheVersion>emptyList(),
+                Collections.<GridCacheVersion>emptyList());
         }
 
         if (commit)

http://git-wip-us.apache.org/repos/asf/ignite/blob/a6dd5ee2/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTxRemoteEx.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTxRemoteEx.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTxRemoteEx.java
index 77dc330..9e9e5bf 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTxRemoteEx.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTxRemoteEx.java
@@ -32,8 +32,12 @@ public interface IgniteTxRemoteEx extends IgniteInternalTx {
 
     /**
      * @param baseVer Base version.
+     * @param committedVers Committed version.
+     * @param rolledbackVers Rolled back version.
+     * @param pendingVers Pending versions.
      */
-    public void doneRemote(GridCacheVersion baseVer);
+    public void doneRemote(GridCacheVersion baseVer, Collection<GridCacheVersion> committedVers,
+        Collection<GridCacheVersion> rolledbackVers, Collection<GridCacheVersion> pendingVers);
 
     /**
      * @param e Sets write value for pessimistic transactions.

http://git-wip-us.apache.org/repos/asf/ignite/blob/a6dd5ee2/modules/core/src/main/java/org/apache/ignite/internal/processors/query/h2/twostep/messages/GridQueryNextPageResponse.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/h2/twostep/messages/GridQueryNextPageResponse.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/h2/twostep/messages/GridQueryNextPageResponse.java
index d93937b..d06e118 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/h2/twostep/messages/GridQueryNextPageResponse.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/h2/twostep/messages/GridQueryNextPageResponse.java
@@ -187,13 +187,13 @@ public class GridQueryNextPageResponse implements Message {
                 writer.incrementState();
 
             case 5:
-                if (!writer.writeMessage("retry", retry))
+                if (!writer.writeCollection("vals", vals, MessageCollectionItemType.MSG))
                     return false;
 
                 writer.incrementState();
 
             case 6:
-                if (!writer.writeCollection("vals", vals, MessageCollectionItemType.MSG))
+                if (!writer.writeMessage("retry", retry))
                     return false;
 
                 writer.incrementState();
@@ -252,7 +252,7 @@ public class GridQueryNextPageResponse implements Message {
                 reader.incrementState();
 
             case 5:
-                retry = reader.readMessage("retry");
+                vals = reader.readCollection("vals", MessageCollectionItemType.MSG);
 
                 if (!reader.isLastRead())
                     return false;
@@ -260,7 +260,7 @@ public class GridQueryNextPageResponse implements Message {
                 reader.incrementState();
 
             case 6:
-                vals = reader.readCollection("vals", MessageCollectionItemType.MSG);
+                retry = reader.readMessage("retry");
 
                 if (!reader.isLastRead())
                     return false;

http://git-wip-us.apache.org/repos/asf/ignite/blob/a6dd5ee2/modules/core/src/main/java/org/apache/ignite/internal/processors/query/h2/twostep/messages/GridQueryRequest.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/h2/twostep/messages/GridQueryRequest.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/h2/twostep/messages/GridQueryRequest.java
index f97b6d0..2b04c52 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/h2/twostep/messages/GridQueryRequest.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/h2/twostep/messages/GridQueryRequest.java
@@ -183,43 +183,43 @@ public class GridQueryRequest implements Message {
 
         switch (writer.state()) {
             case 0:
-                if (!writer.writeCollection("extraSpaces", extraSpaces, MessageCollectionItemType.STRING))
+                if (!writer.writeInt("pageSize", pageSize))
                     return false;
 
                 writer.incrementState();
 
             case 1:
-                if (!writer.writeInt("pageSize", pageSize))
+                if (!writer.writeCollection("qrys", qrys, MessageCollectionItemType.MSG))
                     return false;
 
                 writer.incrementState();
 
             case 2:
-                if (!writer.writeIntArray("parts", parts))
+                if (!writer.writeLong("reqId", reqId))
                     return false;
 
                 writer.incrementState();
 
             case 3:
-                if (!writer.writeCollection("qrys", qrys, MessageCollectionItemType.MSG))
+                if (!writer.writeString("space", space))
                     return false;
 
                 writer.incrementState();
 
             case 4:
-                if (!writer.writeLong("reqId", reqId))
+                if (!writer.writeMessage("topVer", topVer))
                     return false;
 
                 writer.incrementState();
 
             case 5:
-                if (!writer.writeString("space", space))
+                if (!writer.writeCollection("extraSpaces", extraSpaces, MessageCollectionItemType.STRING))
                     return false;
 
                 writer.incrementState();
 
             case 6:
-                if (!writer.writeMessage("topVer", topVer))
+                if (!writer.writeIntArray("parts", parts))
                     return false;
 
                 writer.incrementState();
@@ -238,7 +238,7 @@ public class GridQueryRequest implements Message {
 
         switch (reader.state()) {
             case 0:
-                extraSpaces = reader.readCollection("extraSpaces", MessageCollectionItemType.STRING);
+                pageSize = reader.readInt("pageSize");
 
                 if (!reader.isLastRead())
                     return false;
@@ -246,7 +246,7 @@ public class GridQueryRequest implements Message {
                 reader.incrementState();
 
             case 1:
-                pageSize = reader.readInt("pageSize");
+                qrys = reader.readCollection("qrys", MessageCollectionItemType.MSG);
 
                 if (!reader.isLastRead())
                     return false;
@@ -254,7 +254,7 @@ public class GridQueryRequest implements Message {
                 reader.incrementState();
 
             case 2:
-                parts = reader.readIntArray("parts");
+                reqId = reader.readLong("reqId");
 
                 if (!reader.isLastRead())
                     return false;
@@ -262,7 +262,7 @@ public class GridQueryRequest implements Message {
                 reader.incrementState();
 
             case 3:
-                qrys = reader.readCollection("qrys", MessageCollectionItemType.MSG);
+                space = reader.readString("space");
 
                 if (!reader.isLastRead())
                     return false;
@@ -270,7 +270,7 @@ public class GridQueryRequest implements Message {
                 reader.incrementState();
 
             case 4:
-                reqId = reader.readLong("reqId");
+                topVer = reader.readMessage("topVer");
 
                 if (!reader.isLastRead())
                     return false;
@@ -278,7 +278,7 @@ public class GridQueryRequest implements Message {
                 reader.incrementState();
 
             case 5:
-                space = reader.readString("space");
+                extraSpaces = reader.readCollection("extraSpaces", MessageCollectionItemType.STRING);
 
                 if (!reader.isLastRead())
                     return false;
@@ -286,7 +286,7 @@ public class GridQueryRequest implements Message {
                 reader.incrementState();
 
             case 6:
-                topVer = reader.readMessage("topVer");
+                parts = reader.readIntArray("parts");
 
                 if (!reader.isLastRead())
                     return false;

http://git-wip-us.apache.org/repos/asf/ignite/blob/a6dd5ee2/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheMvccPartitionedSelfTest.java
----------------------------------------------------------------------
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheMvccPartitionedSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheMvccPartitionedSelfTest.java
index 5b7ebef..c0054ac 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheMvccPartitionedSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheMvccPartitionedSelfTest.java
@@ -103,24 +103,79 @@ public class GridCacheMvccPartitionedSelfTest extends GridCommonAbstractTest {
         assertEquals(1, rmtCands.size());
         assertEquals(ver1, rmtCands.iterator().next().version());
 
-        entry.readyNearLocal(ver2, ver2);
+        entry.readyNearLocal(ver2, ver2, empty(), empty(), Arrays.asList(ver1));
 
-        checkLocal(c2, ver2, true, false, false);
+        checkLocalOwner(c2, ver2, false);
         checkRemote(c1, ver1, false, false);
 
-        entry.doneRemote(ver1);
+        assertNotNull(entry.anyOwner());
+        assertEquals(ver2, entry.anyOwner().version());
+    }
 
-        checkLocal(c2, ver2, true, false, false);
-        checkRemote(c1, ver1, true, true);
+    /**
+     * Tests remote candidates.
+     */
+    public void testNearLocalsWithCommitted() {
+        GridCacheAdapter<String, String> cache = grid.internalCache();
 
-        entry.removeLock(ver1);
+        GridCacheTestEntryEx entry = new GridCacheTestEntryEx(cache.context(), "1");
 
-        assertTrue(entry.remoteMvccSnapshot().isEmpty());
+        UUID node1 = UUID.randomUUID();
 
-        checkLocal(c2, ver2, true, true, false);
+        GridCacheVersion ver1 = version(1);
+        GridCacheVersion ver2 = version(2);
 
-        assertNotNull(entry.anyOwner());
-        assertEquals(ver2, entry.anyOwner().version());
+        GridCacheMvccCandidate c1 = entry.addNearLocal(node1, 1, ver1, 0, true);
+        GridCacheMvccCandidate c2 = entry.addRemote(node1, 1, ver2, 0, false, true);
+
+        Collection<GridCacheMvccCandidate> rmtCands = entry.remoteMvccSnapshot();
+        Collection<GridCacheMvccCandidate> nearLocCands = entry.localCandidates();
+
+        assertEquals(1, nearLocCands.size());
+        assertEquals(ver1, nearLocCands.iterator().next().version());
+
+        assertEquals(1, rmtCands.size());
+        assertEquals(ver2, rmtCands.iterator().next().version());
+
+        entry.readyNearLocal(ver1, ver1, Arrays.asList(ver2), empty(), empty());
+
+        checkLocal(c1, ver1, true, false, false);
+        checkRemote(c2, ver2, true, false);
+
+        assertNull(entry.anyOwner());
+    }
+
+    /**
+     * Tests remote candidates.
+     */
+    public void testNearLocalsWithRolledback() {
+        GridCacheAdapter<String, String> cache = grid.internalCache();
+
+        GridCacheTestEntryEx entry = new GridCacheTestEntryEx(cache.context(), "1");
+
+        UUID node1 = UUID.randomUUID();
+
+        GridCacheVersion ver1 = version(1);
+        GridCacheVersion ver2 = version(2);
+
+        GridCacheMvccCandidate c1 = entry.addNearLocal(node1, 1, ver1, 0, true);
+        GridCacheMvccCandidate c2 = entry.addRemote(node1, 1, ver2, 0, false, true);
+
+        Collection<GridCacheMvccCandidate> rmtCands = entry.remoteMvccSnapshot();
+        Collection<GridCacheMvccCandidate> nearLocCands = entry.localCandidates();
+
+        assertEquals(1, nearLocCands.size());
+        assertEquals(ver1, nearLocCands.iterator().next().version());
+
+        assertEquals(1, rmtCands.size());
+        assertEquals(ver2, rmtCands.iterator().next().version());
+
+        entry.readyNearLocal(ver1, ver1, empty(), Arrays.asList(ver2), empty());
+
+        checkLocal(c1, ver1, true, false, false);
+        checkRemote(c2, ver2, true, false);
+
+        assertNull(entry.anyOwner());
     }
 
     /**
@@ -139,7 +194,7 @@ public class GridCacheMvccPartitionedSelfTest extends GridCommonAbstractTest {
         GridCacheMvccCandidate c1 = entry.addNearLocal(node1, 1, ver1, 0, true);
         GridCacheMvccCandidate c2 = entry.addNearLocal(node1, 1, ver2, 0, true);
 
-        entry.readyNearLocal(ver2, ver2);
+        entry.readyNearLocal(ver2, ver2,  empty(), empty(), empty());
 
         checkLocalOwner(c2, ver2, false);
         checkLocal(c1, ver1, false, false, false);
@@ -154,6 +209,164 @@ public class GridCacheMvccPartitionedSelfTest extends GridCommonAbstractTest {
     }
 
     /**
+     * Tests remote candidates.
+     */
+    public void testNearLocalsWithOwned() {
+        GridCacheAdapter<String, String> cache = grid.internalCache();
+
+        GridCacheTestEntryEx entry = new GridCacheTestEntryEx(cache.context(), "1");
+
+        UUID node1 = UUID.randomUUID();
+
+        GridCacheVersion ver1 = version(1);
+        GridCacheVersion ver2 = version(2);
+
+        GridCacheMvccCandidate c1 = entry.addRemote(node1, 1, ver1, 0, false, true);
+        GridCacheMvccCandidate c2 = entry.addNearLocal(node1, 1, ver2, 0, true);
+
+        Collection<GridCacheMvccCandidate> rmtCands = entry.remoteMvccSnapshot();
+        Collection<GridCacheMvccCandidate> nearLocCands = entry.localCandidates();
+
+        assertEquals(1, nearLocCands.size());
+        assertEquals(ver2, nearLocCands.iterator().next().version());
+
+        assertEquals(1, rmtCands.size());
+        assertEquals(ver1, rmtCands.iterator().next().version());
+
+        entry.orderOwned(ver1, ver2);
+
+        entry.readyNearLocal(ver2, ver2,  empty(), empty(), empty());
+
+        checkRemote(c1, ver1, false, false);
+
+        assertFalse(c1.owner());
+
+        checkLocalOwner(c2, ver2, false);
+
+        assertNotNull(entry.anyOwner());
+        assertEquals(ver2, entry.anyOwner().version());
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testAddPendingRemote0() throws Exception {
+        GridCacheAdapter<String, String> cache = grid.internalCache();
+
+        GridCacheTestEntryEx entry = new GridCacheTestEntryEx(cache.context(), "1");
+
+        UUID node1 = UUID.randomUUID();
+
+        GridCacheVersion ver0 = version(0);
+        GridCacheVersion ver1 = version(1);
+
+        entry.addNearLocal(node1, 1, ver1, 0, true);
+
+        entry.readyNearLocal(ver1, ver1, empty(), empty(), Collections.singletonList(ver0));
+
+        entry.addRemote(node1, 1, ver0, 0, false, true);
+
+        Collection<GridCacheMvccCandidate> rmtCands = entry.remoteMvccSnapshot();
+        Collection<GridCacheMvccCandidate> nearLocCands = entry.localCandidates();
+
+        assertEquals(1, nearLocCands.size());
+        assertEquals(ver1, nearLocCands.iterator().next().version());
+
+        assertEquals(1, rmtCands.size());
+        assertEquals(ver0, rmtCands.iterator().next().version());
+
+        assertNotNull(entry.anyOwner());
+        assertEquals(ver1, entry.anyOwner().version());
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testAddPendingRemote1() throws Exception {
+        GridCacheAdapter<String, String> cache = grid.internalCache();
+
+        GridCacheTestEntryEx entry = new GridCacheTestEntryEx(cache.context(), "1");
+
+        UUID node1 = UUID.randomUUID();
+
+        GridCacheVersion ver0 = version(0);
+        GridCacheVersion ver1 = version(1);
+        GridCacheVersion ver2 = version(2);
+        GridCacheVersion ver3 = version(3);
+
+        GridCacheMvccCandidate c3 = entry.addNearLocal(node1, 1, ver3, 0, true);
+
+        entry.readyNearLocal(ver3, ver3, empty(), empty(), Arrays.asList(ver0, ver1, ver2));
+
+        GridCacheMvccCandidate c2 = entry.addRemote(node1, 1, ver2, 0, false, true);
+        GridCacheMvccCandidate c1 = entry.addRemote(node1, 1, ver1, 0, false, true);
+        GridCacheMvccCandidate c0 = entry.addRemote(node1, 1, ver0, 0, false, true);
+
+        Collection<GridCacheMvccCandidate> rmtCands = entry.remoteMvccSnapshot();
+
+        assert rmtCands.size() == 3;
+
+        // DHT remote candidates are not reordered and sorted.
+        GridCacheMvccCandidate[] candArr = new GridCacheMvccCandidate[] {c2, c1, c0};
+
+        rmtCands = entry.remoteMvccSnapshot();
+
+        int i = 0;
+
+        for (GridCacheMvccCandidate cand : rmtCands) {
+            assert cand == candArr[i] : "Invalid candidate in position " + i;
+
+            i++;
+        }
+
+        assertEquals(c3, entry.anyOwner());
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testAddPendingRemote2() throws Exception {
+        GridCacheAdapter<String, String> cache = grid.internalCache();
+
+        GridCacheTestEntryEx entry = new GridCacheTestEntryEx(cache.context(), "1");
+
+        UUID node1 = UUID.randomUUID();
+
+        GridCacheVersion ver0 = version(0);
+        GridCacheVersion ver1 = version(1);
+        GridCacheVersion ver2 = version(2);
+        GridCacheVersion ver3 = version(3);
+
+        GridCacheMvccCandidate c3 = entry.addNearLocal(node1, 1, ver3, 0, true);
+        entry.addNearLocal(node1, 1, ver2, 0, true);
+
+        entry.readyNearLocal(ver3, ver3, empty(), empty(), Arrays.asList(ver0, ver1, ver2));
+
+        GridCacheMvccCandidate c1 = entry.addRemote(node1, 1, ver1, 0, false, true);
+        GridCacheMvccCandidate c0 = entry.addRemote(node1, 1, ver0, 0, false, true);
+
+        Collection<GridCacheMvccCandidate> rmtCands = entry.remoteMvccSnapshot();
+
+        assertEquals(2, rmtCands.size());
+
+        Collection<GridCacheMvccCandidate> nearLocCands = entry.localCandidates();
+
+        assertEquals(2, nearLocCands.size());
+
+        GridCacheMvccCandidate[] candArr = new GridCacheMvccCandidate[] {c1, c0};
+
+        int i = 0;
+
+        for (GridCacheMvccCandidate cand : rmtCands) {
+            assert cand == candArr[i] : "Invalid candidate in position " + i;
+
+            i++;
+        }
+
+        assertEquals(c3, entry.anyOwner());
+    }
+
+    /**
      * Tests salvageRemote method
      */
     public void testSalvageRemote() {
@@ -239,12 +452,10 @@ public class GridCacheMvccPartitionedSelfTest extends GridCommonAbstractTest {
         assertEquals(2, rmtCands.size());
         assertEquals(ver1, rmtCands.iterator().next().version());
 
-        entry.readyNearLocal(nearVer2, ver2);
+        entry.readyNearLocal(nearVer2, ver2, empty(), empty(), empty());
 
         assertNull(entry.anyOwner());
 
-        entry.doneRemote(ver1);
-
         rmtCands = entry.remoteMvccSnapshot();
 
         assertEquals(ver1, rmtCands.iterator().next().version());
@@ -279,16 +490,14 @@ public class GridCacheMvccPartitionedSelfTest extends GridCommonAbstractTest {
         assertEquals(2, rmtCands.size());
         assertEquals(ver1, rmtCands.iterator().next().version());
 
-        entry.readyNearLocal(nearVer2, ver2);
+        entry.orderCompleted(nearVer2, Arrays.asList(ver3), empty());
+        entry.readyNearLocal(nearVer2, ver2, empty(), empty(), Arrays.asList(ver1));
 
         nearLocCands = entry.localCandidates();
         rmtCands = entry.remoteMvccSnapshot();
 
         assertNull(entry.anyOwner());
-
-        entry.doneRemote(ver1);
-
-        assertEquals(ver1, rmtCands.iterator().next().version());
+        assertEquals(ver3, rmtCands.iterator().next().version());
         assertTrue(rmtCands.iterator().next().owner());
 
         GridCacheMvccCandidate cand = nearLocCands.iterator().next();
@@ -326,14 +535,15 @@ public class GridCacheMvccPartitionedSelfTest extends GridCommonAbstractTest {
         assertEquals(2, rmtCands.size());
         assertEquals(ver1, rmtCands.iterator().next().version());
 
-        entry.readyNearLocal(nearVer2, ver2);
+        entry.orderCompleted(nearVer2, empty(), empty());
+        entry.readyNearLocal(nearVer2, ver2, empty(), empty(), empty());
 
         nearLocCands = entry.localCandidates();
         rmtCands = entry.remoteMvccSnapshot();
 
         assertNull(entry.anyOwner());
         assertEquals(ver1, rmtCands.iterator().next().version());
-        assertFalse(rmtCands.iterator().next().owner());
+        assertTrue(rmtCands.iterator().next().owner());
 
         GridCacheMvccCandidate cand = nearLocCands.iterator().next();
 
@@ -370,12 +580,13 @@ public class GridCacheMvccPartitionedSelfTest extends GridCommonAbstractTest {
         assertEquals(2, rmtCands.size());
         assertEquals(ver1, rmtCands.iterator().next().version());
 
-        entry.readyNearLocal(nearVer2, ver2);
+        entry.orderCompleted(nearVer2, empty(), empty());
+        entry.readyNearLocal(nearVer2, ver2, empty(), empty(), Arrays.asList(ver1));
 
         rmtCands = entry.remoteMvccSnapshot();
 
-        assertNull(entry.anyOwner());
-        checkLocal(entry.candidate(nearVer2), nearVer2, true, false, false);
+        assertNotNull(entry.anyOwner());
+        checkLocalOwner(entry.anyOwner(), nearVer2, false);
 
         assertEquals(ver1, rmtCands.iterator().next().version());
     }

http://git-wip-us.apache.org/repos/asf/ignite/blob/a6dd5ee2/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheMvccSelfTest.java
----------------------------------------------------------------------
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheMvccSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheMvccSelfTest.java
index 0e855ed..8038604 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheMvccSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheMvccSelfTest.java
@@ -168,6 +168,12 @@ public class GridCacheMvccSelfTest extends GridCommonAbstractTest {
         // Check order.
         checkOrder(cands, ver1, ver5, ver3, ver2);
 
+        entry.orderCompleted(
+            new GridCacheVersion(1, 0, 2, 0, 0),
+            Arrays.asList(new GridCacheVersion(1, 0, 3, 4, 0), ver2, new GridCacheVersion(1, 0, 5, 6, 0)),
+            Collections.<GridCacheVersion>emptyList()
+        );
+
         cands = entry.remoteMvccSnapshot();
 
         info(cands);
@@ -175,16 +181,16 @@ public class GridCacheMvccSelfTest extends GridCommonAbstractTest {
         assert cands.size() == 4;
 
         // Done ver 2.
-        checkOrder(cands, ver1, ver5, ver3, ver2);
+        checkOrder(cands, ver1, ver2, ver5, ver3);
 
         checkRemote(entry.candidate(ver1), ver1, false, false);
-        checkRemote(entry.candidate(ver2), ver2, false, false);
+        checkRemote(entry.candidate(ver2), ver2, true, false);
         checkRemote(entry.candidate(ver3), ver3, true, true);
         checkRemote(entry.candidate(ver5), ver5, false, false);
 
-        entry.doneRemote(ver2);
+        entry.doneRemote(ver5);
 
-        checkDone(entry.candidate(ver2));
+        checkDone(entry.candidate(ver5));
 
         entry.addRemote(node1, 4, ver4, 0, false, true);
 
@@ -195,7 +201,9 @@ public class GridCacheMvccSelfTest extends GridCommonAbstractTest {
         assert cands.size() == 5;
 
         // Check order.
-        checkOrder(cands, ver1, ver5, ver3, ver2, ver4);
+        checkOrder(cands, ver1, ver2, ver5, ver3, ver4);
+
+        entry.orderCompleted(ver3, Arrays.asList(ver2, ver5), Collections.<GridCacheVersion>emptyList());
 
         cands = entry.remoteMvccSnapshot();
 
@@ -203,7 +211,7 @@ public class GridCacheMvccSelfTest extends GridCommonAbstractTest {
 
         assert cands.size() == 5;
 
-        checkOrder(cands, ver1, ver5, ver3, ver2, ver4);
+        checkOrder(cands, ver1, ver2, ver5, ver3, ver4);
 
         assert entry.anyOwner() == null;
 
@@ -215,29 +223,25 @@ public class GridCacheMvccSelfTest extends GridCommonAbstractTest {
 
         assert entry.remoteMvccSnapshot().size() == 4;
 
-        cands = entry.remoteMvccSnapshot();
-
-        checkOrder(cands, ver5, ver3, ver2, ver4);
-
-        assertNull(entry.anyOwner());
+        assert entry.anyOwner() == null;
 
-        entry.doneRemote(ver5);
+        entry.doneRemote(ver2);
 
-        checkRemoteOwner(entry.anyOwner(), ver5);
+        checkRemoteOwner(entry.anyOwner(), ver2);
 
-        entry.removeLock(ver5);
+        entry.removeLock(ver2);
 
         assert entry.remoteMvccSnapshot().size() == 3;
 
-        checkRemoteOwner(entry.anyOwner(), ver3);
+        checkRemoteOwner(entry.anyOwner(), ver5);
 
         entry.removeLock(ver3);
 
         assert entry.remoteMvccSnapshot().size() == 2;
 
-        checkRemoteOwner(entry.anyOwner(), ver2);
+        checkRemoteOwner(entry.anyOwner(), ver5);
 
-        entry.removeLock(ver2);
+        entry.removeLock(ver5);
 
         assert entry.remoteMvccSnapshot().size() == 1;
 
@@ -255,6 +259,142 @@ public class GridCacheMvccSelfTest extends GridCommonAbstractTest {
     }
 
     /**
+     * Tests that orderOwned does not reorder owned locks.
+     */
+    public void testNearRemoteWithOwned() {
+        GridCacheAdapter<String, String> cache = grid.internalCache();
+
+        GridCacheTestEntryEx entry = new GridCacheTestEntryEx(cache.context(), "1");
+
+        UUID node1 = UUID.randomUUID();
+
+        GridCacheVersion ver1 = version(1);
+        GridCacheVersion ver2 = version(2);
+        GridCacheVersion ver3 = version(3);
+        GridCacheVersion ver4 = version(4);
+
+        GridCacheMvccCandidate c1 = entry.addRemote(node1, 1, ver1, 0, false, true);
+        GridCacheMvccCandidate c2 = entry.addRemote(node1, 1, ver2, 0, false, true);
+        GridCacheMvccCandidate c3 = entry.addRemote(node1, 1, ver3, 0, false, true);
+        GridCacheMvccCandidate c4 = entry.addRemote(node1, 1, ver4, 0, false, true);
+
+        GridCacheMvccCandidate[] candArr = new GridCacheMvccCandidate[] {c1, c2, c3, c4};
+
+        Collection<GridCacheMvccCandidate> rmtCands = entry.remoteMvccSnapshot();
+
+        assert rmtCands.size() == 4;
+        assert rmtCands.iterator().next().version().equals(ver1);
+
+        entry.orderOwned(ver1, ver2);
+
+        rmtCands = entry.remoteMvccSnapshot();
+
+        int i = 0;
+
+        for (GridCacheMvccCandidate cand : rmtCands) {
+            assertTrue(cand == candArr[i]);
+
+            assertTrue(ver2.equals(cand.ownerVersion()) || cand != c1);
+
+            i++;
+        }
+    }
+
+    /**
+     * Tests that orderOwned does not reorder owned locks.
+     */
+    public void testNearRemoteWithOwned1() {
+        GridCacheAdapter<String, String> cache = grid.internalCache();
+
+        GridCacheTestEntryEx entry = new GridCacheTestEntryEx(cache.context(), "1");
+
+        UUID node1 = UUID.randomUUID();
+
+        GridCacheVersion ver1 = version(1);
+        GridCacheVersion ver2 = version(2);
+        GridCacheVersion ver3 = version(3);
+        GridCacheVersion ver4 = version(4);
+        GridCacheVersion ver5 = version(5);
+        GridCacheVersion ver6 = version(6);
+
+        GridCacheMvccCandidate c1 = entry.addRemote(node1, 1, ver1, 0, false, true);
+        GridCacheMvccCandidate c2 = entry.addRemote(node1, 1, ver2, 0, false, true);
+        GridCacheMvccCandidate c3 = entry.addRemote(node1, 1, ver3, 0, false, true);
+        GridCacheMvccCandidate c4 = entry.addRemote(node1, 1, ver4, 0, false, true);
+        GridCacheMvccCandidate c5 = entry.addRemote(node1, 1, ver5, 0, false, true);
+        GridCacheMvccCandidate c6 = entry.addRemote(node1, 1, ver6, 0, false, true);
+
+        GridCacheMvccCandidate[] candArr = new GridCacheMvccCandidate[] {c1, c2, c3, c4, c5, c6};
+
+        Collection<GridCacheMvccCandidate> cands = entry.remoteMvccSnapshot();
+
+        assert cands.size() == 6;
+        assert cands.iterator().next().version().equals(ver1);
+
+        entry.orderOwned(ver1, ver3);
+
+        cands = entry.remoteMvccSnapshot();
+
+        int i = 0;
+
+        for (GridCacheMvccCandidate cand : cands) {
+            assert cand == candArr[i];
+
+            assertTrue(ver3.equals(cand.ownerVersion()) || cand != c1);
+
+            i++;
+        }
+    }
+
+    /**
+     * Tests that orderOwned does not reorder owned locks.
+     */
+    public void testNearRemoteWithOwned2() {
+        GridCacheAdapter<String, String> cache = grid.internalCache();
+
+        GridCacheTestEntryEx entry = new GridCacheTestEntryEx(cache.context(), "1");
+
+        UUID node1 = UUID.randomUUID();
+
+        GridCacheVersion ver0 = version(0);
+        GridCacheVersion ver1 = version(1);
+        GridCacheVersion ver2 = version(2);
+        GridCacheVersion ver3 = version(3);
+        GridCacheVersion ver4 = version(4);
+        GridCacheVersion ver5 = version(5);
+        GridCacheVersion ver6 = version(6);
+
+        GridCacheMvccCandidate c0 = entry.addRemote(node1, 1, ver0, 0, false, true);
+        GridCacheMvccCandidate c1 = entry.addRemote(node1, 1, ver1, 0, false, true);
+        GridCacheMvccCandidate c2 = entry.addRemote(node1, 1, ver2, 0, false, true);
+        GridCacheMvccCandidate c3 = entry.addRemote(node1, 1, ver3, 0, false, true);
+        GridCacheMvccCandidate c4 = entry.addRemote(node1, 1, ver4, 0, false, true);
+        GridCacheMvccCandidate c5 = entry.addRemote(node1, 1, ver5, 0, false, true);
+        GridCacheMvccCandidate c6 = entry.addRemote(node1, 1, ver6, 0, false, true);
+
+        GridCacheMvccCandidate[] candArr = new GridCacheMvccCandidate[] {c0, c1, c2, c3, c4, c5, c6};
+
+        Collection<GridCacheMvccCandidate> cands = entry.remoteMvccSnapshot();
+
+        assert cands.size() == 7;
+        assert cands.iterator().next().version().equals(ver0);
+
+        entry.orderOwned(ver1, ver2);
+
+        cands = entry.remoteMvccSnapshot();
+
+        int i = 0;
+
+        for (GridCacheMvccCandidate cand : cands) {
+            assert cand == candArr[i];
+
+            assertTrue(ver2.equals(cand.ownerVersion()) || cand != c1);
+
+            i++;
+        }
+    }
+
+    /**
      * Tests remote candidates.
      */
     public void testLocal() {
@@ -394,24 +534,27 @@ public class GridCacheMvccSelfTest extends GridCommonAbstractTest {
 
         GridCacheMvccCandidate doomed = entry.addRemote(node2, 6, ver6, 0, false, true);
 
-        entry.doneRemote(ver6);
-
         // No reordering happens.
         checkOrder(entry.remoteMvccSnapshot(), ver1, ver2, ver3, ver4, ver5, ver7, ver8, ver6);
 
+        List<GridCacheVersion> committed = Arrays.asList(ver4, ver7);
+        List<GridCacheVersion> rolledback = Arrays.asList(ver6);
+
+        entry.orderCompleted(ver2, committed, rolledback);
+
         assert !entry.lockedBy(ver6);
 
-        checkOrder(entry.remoteMvccSnapshot(), ver1, ver2, ver3, ver4, ver5, ver7, ver8, ver6);
+        checkOrder(entry.remoteMvccSnapshot(), ver1, ver4, ver7, ver2, ver3, ver5, ver8);
 
         checkRemote(entry.candidate(ver1), ver1, false, false);
         checkRemote(entry.candidate(ver2), ver2, false, false);
         checkRemote(entry.candidate(ver3), ver3, false, false);
-        checkRemote(entry.candidate(ver4), ver4, false, false);
+        checkRemote(entry.candidate(ver4), ver4, true, false);
         checkRemote(entry.candidate(ver5), ver5, false, false);
-        checkRemote(entry.candidate(ver7), ver7, false, false);
+        checkRemote(entry.candidate(ver7), ver7, true, false);
         checkRemote(entry.candidate(ver8), ver8, false, false);
 
-        checkRemote(doomed, ver6, true, true);
+        checkRemote(doomed, ver6, false, true);
     }
 
     /**
@@ -441,43 +584,65 @@ public class GridCacheMvccSelfTest extends GridCommonAbstractTest {
         entry.addRemote(node2, 6, ver6, 0, false, true);
         entry.addRemote(node2, 7, ver7, 0, false, true);
 
-        checkOrder(entry.remoteMvccSnapshot(), ver1, ver2, ver3, ver4, ver5, ver6, ver7);
+        List<GridCacheVersion> committed = Arrays.asList(ver4, ver6, ver2);
+
+        entry.orderCompleted(ver2, committed, Collections.<GridCacheVersion>emptyList());
+
+        checkOrder(entry.remoteMvccSnapshot(), ver1, ver4, ver6, ver2, ver3, ver5, ver7);
 
         checkRemote(entry.candidate(ver1), ver1, false, false);
-        checkRemote(entry.candidate(ver2), ver2, false, false);
+        checkRemote(entry.candidate(ver2), ver2, true, false);
         checkRemote(entry.candidate(ver3), ver3, false, false);
-        checkRemote(entry.candidate(ver4), ver4, false, false);
+        checkRemote(entry.candidate(ver4), ver4, true, false);
         checkRemote(entry.candidate(ver5), ver5, false, false);
-        checkRemote(entry.candidate(ver6), ver6, false, false);
+        checkRemote(entry.candidate(ver6), ver6, true, false);
         checkRemote(entry.candidate(ver7), ver7, false, false);
+    }
 
-        entry.doneRemote(ver2);
+    /**
+     *
+     */
+    public void testCompletedTwiceWithBaseInTheMiddle() {
+        GridCacheAdapter<String, String> cache = grid.internalCache();
 
-        checkOrder(entry.remoteMvccSnapshot(), ver1, ver2, ver3, ver4, ver5, ver6, ver7);
+        GridCacheTestEntryEx entry = new GridCacheTestEntryEx(cache.context(), "1");
 
-        checkRemote(entry.candidate(ver1), ver1, false, false);
-        checkRemote(entry.candidate(ver2), ver2, true, true);
-        checkRemote(entry.candidate(ver3), ver3, false, false);
-        checkRemote(entry.candidate(ver4), ver4, false, false);
-        checkRemote(entry.candidate(ver5), ver5, false, false);
-        checkRemote(entry.candidate(ver6), ver6, false, false);
-        checkRemote(entry.candidate(ver7), ver7, false, false);
+        UUID node1 = UUID.randomUUID();
+        UUID node2 = UUID.randomUUID();
 
-        assertNull(entry.anyOwner());
+        GridCacheVersion ver1 = version(1);
+        GridCacheVersion ver2 = version(2);
+        GridCacheVersion ver3 = version(3);
+        GridCacheVersion ver4 = version(4);
+        GridCacheVersion ver5 = version(5);
+        GridCacheVersion ver6 = version(6);
+        GridCacheVersion ver7 = version(7);
 
-        entry.doneRemote(ver1);
+        entry.addRemote(node1, 1, ver1, 0, false, true);
+        entry.addRemote(node2, 2, ver2, 0, false, true);
+        entry.addRemote(node1, 3, ver3, 0, false, true);
+        entry.addRemote(node2, 4, ver4, 0, false, true);
+        entry.addRemote(node1, 5, ver5, 0, false, true);
+        entry.addRemote(node2, 6, ver6, 0, false, true);
+        entry.addRemote(node2, 7, ver7, 0, false, true);
 
-        checkOrder(entry.remoteMvccSnapshot(), ver1, ver2, ver3, ver4, ver5, ver6, ver7);
+        List<GridCacheVersion> completed = Arrays.asList(ver4, ver6);
 
-        checkRemote(entry.candidate(ver1), ver1, true, true);
-        checkRemote(entry.candidate(ver2), ver2, true, true);
+        entry.orderCompleted(ver2, completed, Collections.<GridCacheVersion>emptyList());
+
+        checkOrder(entry.remoteMvccSnapshot(), ver1, ver4, ver6, ver2, ver3, ver5, ver7);
+
+        entry.orderCompleted(ver4, completed, Collections.<GridCacheVersion>emptyList());
+
+        checkOrder(entry.remoteMvccSnapshot(), ver1, ver6, ver4, ver2, ver3, ver5, ver7);
+
+        checkRemote(entry.candidate(ver1), ver1, false, false);
+        checkRemote(entry.candidate(ver2), ver2, false, false);
         checkRemote(entry.candidate(ver3), ver3, false, false);
-        checkRemote(entry.candidate(ver4), ver4, false, false);
+        checkRemote(entry.candidate(ver4), ver4, true, false);
         checkRemote(entry.candidate(ver5), ver5, false, false);
-        checkRemote(entry.candidate(ver6), ver6, false, false);
+        checkRemote(entry.candidate(ver6), ver6, true, false);
         checkRemote(entry.candidate(ver7), ver7, false, false);
-
-        assertEquals(ver1, entry.anyOwner().version());
     }
 
     /**
@@ -496,6 +661,8 @@ public class GridCacheMvccSelfTest extends GridCommonAbstractTest {
         GridCacheVersion ver3 = version(3);
         GridCacheVersion ver4 = version(4);
         GridCacheVersion ver5 = version(5);
+        GridCacheVersion ver6 = version(6);
+        GridCacheVersion ver7 = version(7);
 
         entry.addRemote(node1, 1, ver1, 0, false, false);
         entry.addRemote(node2, 2, ver2, 0, false, false);
@@ -503,6 +670,10 @@ public class GridCacheMvccSelfTest extends GridCommonAbstractTest {
         entry.addRemote(node2, 4, ver4, 0, false, false);
         entry.addRemote(node1, 5, ver5, 0, false, false);
 
+        List<GridCacheVersion> committed = Arrays.asList(ver6, ver7);
+
+        entry.orderCompleted(ver4, committed, Collections.<GridCacheVersion>emptyList());
+
         checkOrder(entry.remoteMvccSnapshot(), ver1, ver2, ver3, ver4, ver5);
 
         // Nothing set to owner since there is no change.
@@ -514,6 +685,48 @@ public class GridCacheMvccSelfTest extends GridCommonAbstractTest {
     }
 
     /**
+     *
+     */
+    public void testCompletedWithBaseInTheBeginning() {
+        GridCacheAdapter<String, String> cache = grid.internalCache();
+
+        GridCacheTestEntryEx entry = new GridCacheTestEntryEx(cache.context(), "1");
+
+        UUID node1 = UUID.randomUUID();
+        UUID node2 = UUID.randomUUID();
+
+        GridCacheVersion ver1 = version(1);
+        GridCacheVersion ver2 = version(2);
+        GridCacheVersion ver3 = version(3);
+        GridCacheVersion ver4 = version(4);
+        GridCacheVersion ver5 = version(5);
+        GridCacheVersion ver6 = version(6);
+        GridCacheVersion ver7 = version(7);
+
+        entry.addRemote(node1, 1, ver1, 0, false, false);
+        entry.addRemote(node2, 2, ver2, 0, false, false);
+        entry.addRemote(node1, 3, ver3, 0, false, false);
+        entry.addRemote(node2, 4, ver4, 0, false, false);
+        entry.addRemote(node1, 5, ver5, 0, false, false);
+        entry.addRemote(node2, 6, ver6, 0, false, false);
+        entry.addRemote(node2, 7, ver7, 0, false, false);
+
+        List<GridCacheVersion> committed = Arrays.asList(ver4, ver6, ver3);
+
+        entry.orderCompleted(ver1, committed, Collections.<GridCacheVersion>emptyList());
+
+        checkOrder(entry.remoteMvccSnapshot(), ver3, ver4, ver6, ver1, ver2, ver5, ver7);
+
+        checkRemote(entry.candidate(ver1), ver1, false, false);
+        checkRemote(entry.candidate(ver2), ver2, false, false);
+        checkRemote(entry.candidate(ver3), ver3, true, false);
+        checkRemote(entry.candidate(ver4), ver4, true, false);
+        checkRemote(entry.candidate(ver5), ver5, false, false);
+        checkRemote(entry.candidate(ver6), ver6, true, false);
+        checkRemote(entry.candidate(ver7), ver7, false, false);
+    }
+
+    /**
      * This case should never happen, nevertheless we need to test for it.
      */
     public void testCompletedWithBaseInTheBeginningNoChange() {
@@ -529,6 +742,8 @@ public class GridCacheMvccSelfTest extends GridCommonAbstractTest {
         GridCacheVersion ver3 = version(3);
         GridCacheVersion ver4 = version(4);
         GridCacheVersion ver5 = version(5);
+        GridCacheVersion ver6 = version(6);
+        GridCacheVersion ver7 = version(7);
 
         entry.addRemote(node1, 1, ver1, 0, false, false);
         entry.addRemote(node2, 2, ver2, 0, false, false);
@@ -536,6 +751,10 @@ public class GridCacheMvccSelfTest extends GridCommonAbstractTest {
         entry.addRemote(node2, 4, ver4, 0, false, false);
         entry.addRemote(node1, 5, ver5, 0, false, false);
 
+        List<GridCacheVersion> committed = Arrays.asList(ver6, ver7);
+
+        entry.orderCompleted(ver1, committed, Collections.<GridCacheVersion>emptyList());
+
         checkOrder(entry.remoteMvccSnapshot(), ver1, ver2, ver3, ver4, ver5);
 
         // Nothing set to owner since there is no change.
@@ -562,6 +781,8 @@ public class GridCacheMvccSelfTest extends GridCommonAbstractTest {
         GridCacheVersion ver3 = version(3);
         GridCacheVersion ver4 = version(4);
         GridCacheVersion ver5 = version(5);
+        GridCacheVersion ver6 = version(6);
+        GridCacheVersion ver7 = version(7);
 
         entry.addRemote(node1, 1, ver1, 0, false, false);
         entry.addRemote(node2, 2, ver2, 0, false, false);
@@ -569,6 +790,10 @@ public class GridCacheMvccSelfTest extends GridCommonAbstractTest {
         entry.addRemote(node2, 4, ver4, 0, false, false);
         entry.addRemote(node1, 5, ver5, 0, false, false);
 
+        List<GridCacheVersion> committed = Arrays.asList(ver6, ver7);
+
+        entry.orderCompleted(ver5, committed, Collections.<GridCacheVersion>emptyList());
+
         checkOrder(entry.remoteMvccSnapshot(), ver1, ver2, ver3, ver4, ver5);
 
         // Nothing set to owner since there is no change.
@@ -582,7 +807,7 @@ public class GridCacheMvccSelfTest extends GridCommonAbstractTest {
     /**
      *
      */
-    public void testNoReordering() {
+    public void testCompletedWithBaseNotPresentInTheMiddle() {
         GridCacheAdapter<String, String> cache = grid.internalCache();
 
         GridCacheTestEntryEx entry = new GridCacheTestEntryEx(cache.context(), "1");
@@ -598,49 +823,141 @@ public class GridCacheMvccSelfTest extends GridCommonAbstractTest {
         GridCacheVersion ver6 = version(6);
         GridCacheVersion ver7 = version(7);
 
-        entry.addRemote(node1, 2, ver2, 0, false, true);
-        entry.addRemote(node1, 3, ver3, 0, false, true);
+        // Don't add version 2.
         entry.addRemote(node1, 1, ver1, 0, false, true);
-        entry.addRemote(node1, 5, ver5, 0, false, true);
+        entry.addRemote(node1, 3, ver3, 0, false, true);
         entry.addRemote(node2, 4, ver4, 0, false, true);
+        entry.addRemote(node1, 5, ver5, 0, false, true);
         entry.addRemote(node2, 6, ver6, 0, false, true);
         entry.addRemote(node2, 7, ver7, 0, false, true);
 
-        checkOrder(entry.remoteMvccSnapshot(), ver2, ver3, ver1, ver5, ver4, ver6, ver7);
+        List<GridCacheVersion> committed = Arrays.asList(ver6, ver4);
+
+        entry.orderCompleted(ver2, committed, Collections.<GridCacheVersion>emptyList());
+
+        checkOrder(entry.remoteMvccSnapshot(), ver1, ver4, ver6, ver3, ver5, ver7);
 
-        checkRemote(entry.candidate(ver2), ver2, false, false);
-        checkRemote(entry.candidate(ver3), ver3, false, false);
         checkRemote(entry.candidate(ver1), ver1, false, false);
+        checkRemote(entry.candidate(ver3), ver3, false, false);
+        checkRemote(entry.candidate(ver4), ver4, true, false);
         checkRemote(entry.candidate(ver5), ver5, false, false);
-        checkRemote(entry.candidate(ver4), ver4, false, false);
-        checkRemote(entry.candidate(ver6), ver6, false, false);
+        checkRemote(entry.candidate(ver6), ver6, true, false);
         checkRemote(entry.candidate(ver7), ver7, false, false);
+    }
 
-        entry.doneRemote(ver3);
+    /**
+     *
+     */
+    public void testCompletedWithBaseNotPresentInTheMiddleNoChange() {
+        GridCacheAdapter<String, String> cache = grid.internalCache();
 
-        checkOrder(entry.remoteMvccSnapshot(), ver2, ver3, ver1, ver5, ver4, ver6, ver7);
+        GridCacheTestEntryEx entry = new GridCacheTestEntryEx(cache.context(), "1");
 
-        assertNull(entry.anyOwner());
+        UUID node1 = UUID.randomUUID();
+        UUID node2 = UUID.randomUUID();
+
+        GridCacheVersion ver1 = version(1);
+        GridCacheVersion ver2 = version(2);
+        GridCacheVersion ver3 = version(3);
+        GridCacheVersion ver4 = version(4);
+        GridCacheVersion ver5 = version(5);
+        GridCacheVersion ver6 = version(6);
+        GridCacheVersion ver7 = version(7);
+
+        // Don't add versions 2, 5, 6, 7.
+        entry.addRemote(node1, 1, ver1, 0, false, true);
+        entry.addRemote(node1, 3, ver3, 0, false, true);
+        entry.addRemote(node2, 4, ver4, 0, false, true);
+
+        List<GridCacheVersion> committed = Arrays.asList(ver6, ver5, ver7);
+
+        entry.orderCompleted(ver2, committed, Collections.<GridCacheVersion>emptyList());
+
+        checkOrder(entry.remoteMvccSnapshot(), ver1, ver3, ver4);
 
-        checkRemote(entry.candidate(ver2), ver2, false, false);
-        checkRemote(entry.candidate(ver3), ver3, true, true);
         checkRemote(entry.candidate(ver1), ver1, false, false);
-        checkRemote(entry.candidate(ver5), ver5, false, false);
+        checkRemote(entry.candidate(ver3), ver3, false, false);
         checkRemote(entry.candidate(ver4), ver4, false, false);
-        checkRemote(entry.candidate(ver6), ver6, false, false);
-        checkRemote(entry.candidate(ver7), ver7, false, false);
+    }
 
-        entry.doneRemote(ver2);
+    /**
+     *
+     */
+    public void testCompletedWithBaseNotPresentInTheBeginning() {
+        GridCacheAdapter<String, String> cache = grid.internalCache();
 
-        checkOrder(entry.remoteMvccSnapshot(), ver2, ver3, ver1, ver5, ver4, ver6, ver7);
+        GridCacheTestEntryEx entry = new GridCacheTestEntryEx(cache.context(), "1");
 
-        assertEquals(ver2, entry.anyOwner().version());
+        UUID node1 = UUID.randomUUID();
+        UUID node2 = UUID.randomUUID();
 
-        checkRemote(entry.candidate(ver2), ver2, true, true);
-        checkRemote(entry.candidate(ver3), ver3, true, true);
-        checkRemote(entry.candidate(ver1), ver1, false, false);
+        GridCacheVersion ver1 = version(1);
+        GridCacheVersion ver2 = version(2);
+        GridCacheVersion ver3 = version(3);
+        GridCacheVersion ver4 = version(4);
+        GridCacheVersion ver5 = version(5);
+        GridCacheVersion ver6 = version(6);
+        GridCacheVersion ver7 = version(7);
+
+        // Don't add version 1.
+        entry.addRemote(node1, 2, ver2, 0, false, true);
+        entry.addRemote(node1, 3, ver3, 0, false, true);
+        entry.addRemote(node2, 4, ver4, 0, false, true);
+        entry.addRemote(node1, 5, ver5, 0, false, true);
+        entry.addRemote(node2, 6, ver6, 0, false, true);
+        entry.addRemote(node2, 7, ver7, 0, false, true);
+
+        List<GridCacheVersion> committed = Arrays.asList(ver4, ver6, ver3);
+
+        entry.orderCompleted(ver1, committed, Collections.<GridCacheVersion>emptyList());
+
+        checkOrder(entry.remoteMvccSnapshot(), ver3, ver4, ver6, ver2, ver5, ver7);
+
+        checkRemote(entry.candidate(ver2), ver2, false, false);
+        checkRemote(entry.candidate(ver3), ver3, true, false);
+        checkRemote(entry.candidate(ver4), ver4, true, false);
         checkRemote(entry.candidate(ver5), ver5, false, false);
+        checkRemote(entry.candidate(ver6), ver6, true, false);
+        checkRemote(entry.candidate(ver7), ver7, false, false);
+    }
+
+    /**
+     *
+     */
+    public void testCompletedWithBaseNotPresentInTheBeginningNoChange() {
+        GridCacheAdapter<String, String> cache = grid.internalCache();
+
+        GridCacheTestEntryEx entry = new GridCacheTestEntryEx(cache.context(), "1");
+
+        UUID node1 = UUID.randomUUID();
+        UUID node2 = UUID.randomUUID();
+
+        GridCacheVersion ver1 = version(1);
+        GridCacheVersion ver2 = version(2);
+        GridCacheVersion ver3 = version(3);
+        GridCacheVersion ver4 = version(4);
+        GridCacheVersion ver5 = version(5);
+        GridCacheVersion ver6 = version(6);
+        GridCacheVersion ver7 = version(7);
+
+        // Don't add version 6, 7
+        entry.addRemote(node1, 2, ver2, 0, false, true);
+        entry.addRemote(node1, 3, ver3, 0, false, true);
+        entry.addRemote(node2, 4, ver4, 0, false, true);
+        entry.addRemote(node1, 5, ver5, 0, false, true);
+        entry.addRemote(node1, 6, ver6, 0, false, true);
+        entry.addRemote(node1, 7, ver7, 0, false, true);
+
+        List<GridCacheVersion> committed = Arrays.asList(ver2, ver3);
+
+        entry.orderCompleted(ver1, committed, Collections.<GridCacheVersion>emptyList());
+
+        checkOrder(entry.remoteMvccSnapshot(), ver2, ver3, ver4, ver5, ver6, ver7);
+
+        checkRemote(entry.candidate(ver2), ver2, true, false);
+        checkRemote(entry.candidate(ver3), ver3, true, false);
         checkRemote(entry.candidate(ver4), ver4, false, false);
+        checkRemote(entry.candidate(ver5), ver5, false, false);
         checkRemote(entry.candidate(ver6), ver6, false, false);
         checkRemote(entry.candidate(ver7), ver7, false, false);
     }
@@ -660,6 +977,9 @@ public class GridCacheMvccSelfTest extends GridCommonAbstractTest {
         GridCacheVersion ver2 = version(2);
         GridCacheVersion ver3 = version(3);
         GridCacheVersion ver4 = version(4);
+        GridCacheVersion ver5 = version(5);
+        GridCacheVersion ver6 = version(6);
+        GridCacheVersion ver7 = version(7);
 
         // Don't add version 5, 6, 7
         entry.addRemote(node1, 1, ver1, 0, false, true);
@@ -667,6 +987,10 @@ public class GridCacheMvccSelfTest extends GridCommonAbstractTest {
         entry.addRemote(node1, 3, ver3, 0, false, true);
         entry.addRemote(node2, 4, ver4, 0, false, true);
 
+        List<GridCacheVersion> committed = Arrays.asList(ver6, ver7);
+
+        entry.orderCompleted(ver5, committed, Collections.<GridCacheVersion>emptyList());
+
         checkOrder(entry.remoteMvccSnapshot(), ver1, ver2, ver3, ver4);
 
         checkRemote(entry.candidate(ver1), ver1, false, false);
@@ -676,6 +1000,132 @@ public class GridCacheMvccSelfTest extends GridCommonAbstractTest {
     }
 
     /**
+     * Test local and remote candidates together.
+     */
+    public void testLocalAndRemote() {
+        GridCacheAdapter<String, String> cache = grid.internalCache();
+
+        GridCacheTestEntryEx entry = new GridCacheTestEntryEx(cache.context(), "1");
+
+        UUID node1 = UUID.randomUUID();
+        UUID node2 = UUID.randomUUID();
+
+        GridCacheVersion ver1 = version(1);
+        GridCacheVersion ver2 = version(2);
+        GridCacheVersion ver3 = version(3);
+        GridCacheVersion ver4 = version(4);
+        GridCacheVersion ver5 = version(5);
+
+        entry.addRemote(node1, 1, ver1, 0, false, false);
+        entry.addLocal(2, ver2, 0, true, true);
+
+        Collection<GridCacheMvccCandidate> cands = entry.remoteMvccSnapshot();
+
+        assert cands.size() == 1;
+        assert cands.iterator().next().version().equals(ver1);
+
+        entry.addRemote(node2, 5, ver5, 0, false, false);
+
+        cands = entry.remoteMvccSnapshot();
+
+        assert cands.size() == 2;
+
+        info(cands);
+
+        checkOrder(cands, ver1, ver5);
+        checkOrder(entry.localCandidates(true), ver2);
+
+        entry.addRemote(node1, 3, ver3, 0, false, true);
+        entry.addLocal(4, ver4, 0, /*reenter*/true, false);
+
+        cands = entry.remoteMvccSnapshot();
+
+        assert cands.size() == 3;
+
+        // Check order.
+        checkOrder(entry.remoteMvccSnapshot(), ver1, ver5, ver3);
+        checkOrder(entry.localCandidates(), ver2, ver4);
+
+        entry.orderCompleted(
+            ver2 /*local version.*/,
+            Arrays.asList(new GridCacheVersion(1, 0, 1, 2, 0), ver3, new GridCacheVersion(1, 0, 5, 6, 0)),
+            Collections.<GridCacheVersion>emptyList()
+        );
+
+        // Done ver3.
+        checkOrder(entry.remoteMvccSnapshot(), ver1, ver3, ver5);
+        checkOrder(entry.localCandidates(), ver2, ver4);
+
+        checkRemote(entry.candidate(ver1), ver1, false, false);
+        checkRemote(entry.candidate(ver3), ver3, true, false);
+        checkRemote(entry.candidate(ver5), ver5, false, false);
+
+        checkLocal(entry.candidate(ver2), ver2, false, false, false);
+        checkLocal(entry.candidate(ver4), ver4, false, false, false);
+
+        entry.readyLocal(ver2);
+
+        checkLocal(entry.candidate(ver2), ver2, true, false, false);
+        checkLocal(entry.candidate(ver4), ver4, false, false, false);
+
+        assert entry.anyOwner() == null;
+
+        entry.doneRemote(ver1);
+
+        checkRemoteOwner(entry.anyOwner(), ver1);
+
+        entry.removeLock(ver1);
+
+        checkOrder(entry.remoteMvccSnapshot(), ver3, ver5);
+
+        assert entry.anyOwner() == null;
+
+        entry.doneRemote(ver3);
+
+        checkRemoteOwner(entry.anyOwner(), ver3);
+
+        entry.removeLock(ver3);
+
+        checkLocalOwner(entry.anyOwner(), ver2, false);
+
+        entry.removeLock(ver2);
+
+        assert !entry.lockedByAny(ver4, ver5);
+
+        checkOrder(entry.remoteMvccSnapshot(), ver5);
+        checkOrder(entry.localCandidates(), ver4);
+
+        assert entry.anyOwner() == null;
+
+        entry.readyLocal(ver4);
+
+        checkLocalOwner(entry.anyOwner(), ver4, false);
+
+        entry.removeLock(ver4);
+
+        assert entry.anyOwner() == null;
+
+        GridCacheMvccCandidate c5 = entry.candidate(ver5);
+
+        assert c5 != null;
+
+        c5.setOwner();
+
+        assert entry.anyOwner() == null;
+
+        entry.doneRemote(ver5);
+
+        checkRemoteOwner(entry.anyOwner(), ver5);
+
+        assert !entry.lockedByAny(ver5);
+
+        entry.removeLock(ver5);
+
+        assert !entry.lockedByAny();
+        assert entry.anyOwner() == null;
+    }
+
+    /**
      * @throws Exception If test failed.
      */
     public void testMultipleLocalAndRemoteLocks1() throws Exception {

http://git-wip-us.apache.org/repos/asf/ignite/blob/a6dd5ee2/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheTestEntryEx.java
----------------------------------------------------------------------
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheTestEntryEx.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheTestEntryEx.java
index 68e0ea5..0055557 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheTestEntryEx.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheTestEntryEx.java
@@ -197,10 +197,34 @@ public class GridCacheTestEntryEx extends GridMetadataAwareAdapter implements Gr
     }
 
     /**
+     * Moves completed candidates right before the base one. Note that
+     * if base is not found, then nothing happens and {@code false} is
+     * returned.
+     *
+     * @param baseVer Base version.
+     * @param committedVers Committed versions relative to base.
+     * @param rolledbackVers Rolled back versions relative to base.
+     * @return Lock owner.
+     */
+    @Nullable public GridCacheMvccCandidate orderCompleted(GridCacheVersion baseVer,
+        Collection<GridCacheVersion> committedVers, Collection<GridCacheVersion> rolledbackVers) {
+        return mvcc.orderCompleted(baseVer, committedVers, rolledbackVers);
+    }
+
+    /**
      * @param ver Version.
      */
     public void doneRemote(GridCacheVersion ver) {
-        mvcc.doneRemote(ver);
+        mvcc.doneRemote(ver, Collections.<GridCacheVersion>emptyList(),
+            Collections.<GridCacheVersion>emptyList(), Collections.<GridCacheVersion>emptyList());
+    }
+
+    /**
+     * @param baseVer Base version.
+     * @param owned Owned.
+     */
+    public void orderOwned(GridCacheVersion baseVer, GridCacheVersion owned) {
+        mvcc.markOwned(baseVer, owned);
     }
 
     /**
@@ -214,10 +238,15 @@ public class GridCacheTestEntryEx extends GridMetadataAwareAdapter implements Gr
     /**
      * @param ver Ready near lock version.
      * @param mapped Mapped version.
+     * @param committedVers Committed versions.
+     * @param rolledbackVers Rolled back versions.
+     * @param pending Pending versions.
      * @return Lock owner.
      */
-    @Nullable public GridCacheMvccCandidate readyNearLocal(GridCacheVersion ver, GridCacheVersion mapped) {
-        return mvcc.readyNearLocal(ver, mapped);
+    @Nullable public GridCacheMvccCandidate readyNearLocal(GridCacheVersion ver, GridCacheVersion mapped,
+        Collection<GridCacheVersion> committedVers, Collection<GridCacheVersion> rolledbackVers,
+        Collection<GridCacheVersion> pending) {
+        return mvcc.readyNearLocal(ver, mapped, committedVers, rolledbackVers, pending);
     }
 
     /**