ignite-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From sboi...@apache.org
Subject ignite git commit: ignite-4285
Date Mon, 28 Nov 2016 14:38:54 GMT
Repository: ignite
Updated Branches:
  refs/heads/ignite-4285 4e7c8d02e -> 36e98d6a2


ignite-4285


Project: http://git-wip-us.apache.org/repos/asf/ignite/repo
Commit: http://git-wip-us.apache.org/repos/asf/ignite/commit/36e98d6a
Tree: http://git-wip-us.apache.org/repos/asf/ignite/tree/36e98d6a
Diff: http://git-wip-us.apache.org/repos/asf/ignite/diff/36e98d6a

Branch: refs/heads/ignite-4285
Commit: 36e98d6a21cc5ee938a8793fa6355a37a61fedf6
Parents: 4e7c8d0
Author: sboikov <sboikov@gridgain.com>
Authored: Mon Nov 28 11:06:38 2016 +0300
Committer: sboikov <sboikov@gridgain.com>
Committed: Mon Nov 28 17:37:52 2016 +0300

----------------------------------------------------------------------
 .../processors/cache/CacheLockCandidates.java   |  31 +++
 .../cache/CacheLockCandidatesList.java          |  69 ++++++
 .../processors/cache/GridCacheMapEntry.java     |  14 +-
 .../processors/cache/GridCacheMvcc.java         | 227 ++++++++++--------
 .../processors/cache/GridCacheMvccCallback.java |   4 +-
 .../cache/GridCacheMvccCandidate.java           |  28 ++-
 .../processors/cache/GridCacheMvccManager.java  |  19 +-
 .../distributed/GridDistributedCacheEntry.java  | 229 ++++++++++++-------
 .../distributed/dht/GridDhtCacheEntry.java      |  11 +-
 .../distributed/dht/GridDhtLockFuture.java      |  30 +--
 .../distributed/dht/GridDhtTxPrepareFuture.java |   5 +-
 .../distributed/near/GridNearCacheEntry.java    |  37 +--
 .../distributed/near/GridNearLockFuture.java    |   3 +-
 .../cache/local/GridLocalCacheEntry.java        | 111 ++++-----
 .../cache/transactions/IgniteTxManager.java     |   4 +-
 .../cache/GridCacheMvccPartitionedSelfTest.java | 133 ++++++++++-
 .../processors/cache/GridCacheTestEntryEx.java  |  68 ++----
 17 files changed, 641 insertions(+), 382 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ignite/blob/36e98d6a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheLockCandidates.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheLockCandidates.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheLockCandidates.java
new file mode 100644
index 0000000..d139262
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheLockCandidates.java
@@ -0,0 +1,31 @@
+/*
+ * 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.processors.cache.version.GridCacheVersion;
+
+/**
+ *
+ */
+public interface CacheLockCandidates {
+    public GridCacheMvccCandidate candidate(int idx);
+
+    public int size();
+
+    public boolean hasCandidate(GridCacheVersion ver);
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/36e98d6a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheLockCandidatesList.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheLockCandidatesList.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheLockCandidatesList.java
new file mode 100644
index 0000000..f127d43
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheLockCandidatesList.java
@@ -0,0 +1,69 @@
+/*
+ * 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.ArrayList;
+import java.util.List;
+import org.apache.ignite.internal.processors.cache.version.GridCacheVersion;
+import org.apache.ignite.internal.util.tostring.GridToStringInclude;
+import org.apache.ignite.internal.util.typedef.internal.S;
+
+/**
+ *
+ */
+class CacheLockCandidatesList implements CacheLockCandidates {
+    /** */
+    @GridToStringInclude
+    private List<GridCacheMvccCandidate> list = new ArrayList<>();
+
+    /**
+     * @param cand Candidate to add.
+     */
+    void add(GridCacheMvccCandidate cand) {
+        assert !hasCandidate(cand.version());
+
+        list.add(cand);
+    }
+
+    /** {@inheritDoc} */
+    @Override public GridCacheMvccCandidate candidate(int idx) {
+        return list.get(idx);
+    }
+
+    /** {@inheritDoc} */
+    @Override public int size() {
+        return list.size();
+    }
+
+    /** {@inheritDoc} */
+    @Override public boolean hasCandidate(GridCacheVersion ver) {
+        for (int i = 0; i < list.size(); i++) {
+            GridCacheMvccCandidate cand = list.get(i);
+
+            if (cand.version().equals(ver))
+                return true;
+        }
+
+        return false;
+    }
+
+    /** {@inheritDoc} */
+    @Override public String toString() {
+        return S.toString(CacheLockCandidatesList.class, this);
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/36e98d6a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheMapEntry.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheMapEntry.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheMapEntry.java
index aec28bb..eef4bfc 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheMapEntry.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheMapEntry.java
@@ -827,8 +827,6 @@ public abstract class GridCacheMapEntry extends GridMetadataAwareAdapter impleme
         if (readThrough && !cctx.readThrough())
             readThrough = false;
 
-        GridCacheMvccCandidate owner;
-
         CacheObject ret;
 
         GridCacheVersion startVer;
@@ -841,10 +839,6 @@ public abstract class GridCacheMapEntry extends GridMetadataAwareAdapter impleme
         synchronized (this) {
             checkObsolete();
 
-            GridCacheMvcc mvcc = mvccExtras();
-
-            owner = mvcc == null ? null : mvcc.anyOwner();
-
             boolean valid = valid(tx != null ? tx.topologyVersion() : cctx.affinity().affinityTopologyVersion());
 
             CacheObject val;
@@ -899,11 +893,13 @@ public abstract class GridCacheMapEntry extends GridMetadataAwareAdapter impleme
             if (evt && cctx.events().isRecordable(EVT_CACHE_OBJECT_READ)) {
                 transformClo = EntryProcessorResourceInjectorProxy.unwrap(transformClo);
 
+                GridCacheMvcc mvcc = mvccExtras();
+
                 cctx.events().addEvent(
                     partition(),
                     key,
                     tx,
-                    owner,
+                    mvcc != null ? mvcc.anyOwner() : null,
                     EVT_CACHE_OBJECT_READ,
                     ret,
                     ret != null,
@@ -1010,11 +1006,13 @@ public abstract class GridCacheMapEntry extends GridMetadataAwareAdapter impleme
                 if (evt && cctx.events().isRecordable(EVT_CACHE_OBJECT_READ)) {
                     transformClo = EntryProcessorResourceInjectorProxy.unwrap(transformClo);
 
+                    GridCacheMvcc mvcc = mvccExtras();
+
                     cctx.events().addEvent(
                         partition(),
                         key,
                         tx,
-                        owner,
+                        mvcc != null ? mvcc.anyOwner() : null,
                         EVT_CACHE_OBJECT_READ,
                         ret,
                         ret != null,

http://git-wip-us.apache.org/repos/asf/ignite/blob/36e98d6a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheMvcc.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheMvcc.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheMvcc.java
index f54aefd..87c3be2 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheMvcc.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheMvcc.java
@@ -107,7 +107,7 @@ public final class GridCacheMvcc {
     /**
      * @return Any owner.
      */
-    @Nullable public GridCacheMvccCandidate anyOwner() {
+    @Nullable GridCacheMvccCandidate anyOwner() {
         GridCacheMvccCandidate owner = localOwner();
 
         if (owner == null)
@@ -117,10 +117,22 @@ public final class GridCacheMvcc {
     }
 
     /**
+     * @return All owners.
+     */
+    @Nullable public CacheLockCandidates allOwners() {
+        CacheLockCandidates owners = localOwners();
+
+        if (owners == null)
+            owners = remoteOwner();
+
+        return owners;
+    }
+
+    /**
      * @return Remote candidate only if it's first in the list and is marked
      *      as <tt>'used'</tt>.
      */
-    @Nullable public GridCacheMvccCandidate remoteOwner() {
+    @Nullable private GridCacheMvccCandidate remoteOwner() {
         if (rmts != null) {
             assert !rmts.isEmpty();
 
@@ -133,6 +145,50 @@ public final class GridCacheMvcc {
     }
 
     /**
+     * @return All local owners.
+     */
+    @Nullable public CacheLockCandidates localOwners() {
+        if (locs != null) {
+            assert !locs.isEmpty();
+
+            CacheLockCandidates locks = null;
+
+            GridCacheMvccCandidate first = locs.getFirst();
+
+            if (first.serializable() && first.read()) {
+                for (GridCacheMvccCandidate cand : locs) {
+                    if (cand.owner()) {
+                        assert cand.serializable() && cand.read() : cand;
+
+                        if (locks != null) {
+                            if (locks.size() == 1) {
+                                GridCacheMvccCandidate owner = locks.candidate(0);
+
+                                locks = new CacheLockCandidatesList();
+
+                                ((CacheLockCandidatesList)locks).add(owner);
+                            }
+
+                            ((CacheLockCandidatesList)locks).add(cand);
+                        }
+                        else
+                            locks = cand;
+                    }
+
+                    if (!cand.serializable() || !cand.read())
+                        break;
+                }
+            }
+            else if (first.owner())
+                locks = first;
+
+            return locks;
+        }
+
+        return null;
+    }
+
+    /**
      * @return Local candidate only if it's first in the list and is marked
      *      as <tt>'owner'</tt>.
      */
@@ -432,7 +488,7 @@ public final class GridCacheMvcc {
      * @param rolledbackVers Rolled back versions relative to base.
      * @return Lock owner.
      */
-    @Nullable public GridCacheMvccCandidate orderCompleted(GridCacheVersion baseVer,
+    public void orderCompleted(GridCacheVersion baseVer,
         Collection<GridCacheVersion> committedVers, Collection<GridCacheVersion> rolledbackVers) {
         assert baseVer != null;
 
@@ -494,8 +550,6 @@ public final class GridCacheMvcc {
                     rmts = null;
             }
         }
-
-        return anyOwner();
     }
 
     /**
@@ -503,11 +557,10 @@ public final class GridCacheMvcc {
      *
      * @param baseVer Base version.
      * @param owned Owned list.
-     * @return Current owner.
      */
-    @Nullable public GridCacheMvccCandidate markOwned(GridCacheVersion baseVer, GridCacheVersion owned) {
+    public void markOwned(GridCacheVersion baseVer, GridCacheVersion owned) {
         if (owned == null)
-            return anyOwner();
+            return;
 
         if (rmts != null) {
             GridCacheMvccCandidate baseCand = candidate(rmts, baseVer);
@@ -515,8 +568,6 @@ public final class GridCacheMvcc {
             if (baseCand != null)
                 baseCand.ownerVersion(owned);
         }
-
-        return anyOwner();
     }
 
     /**
@@ -527,6 +578,7 @@ public final class GridCacheMvcc {
      * @param reenter Reentry flag ({@code true} if reentry is allowed).
      * @param tx Transaction flag.
      * @param implicitSingle Implicit transaction flag.
+     * @param read Read lock flag.
      * @return New lock candidate if lock was added, or current owner if lock was reentered,
      *      or <tt>null</tt> if lock was owned by another thread and timeout is negative.
      */
@@ -537,7 +589,8 @@ public final class GridCacheMvcc {
         long timeout,
         boolean reenter,
         boolean tx,
-        boolean implicitSingle) {
+        boolean implicitSingle,
+        boolean read) {
         return addLocal(
             parent,
             /*nearNodeId*/null,
@@ -550,7 +603,7 @@ public final class GridCacheMvcc {
             tx,
             implicitSingle,
             /*dht-local*/false,
-            /*read*/false
+            /*read*/read
         );
     }
 
@@ -694,6 +747,7 @@ public final class GridCacheMvcc {
      * @param ver Lock version.
      * @param tx Transaction flag.
      * @param implicitSingle Implicit flag.
+     * @param read Read lock flag.
      * @return Add remote candidate.
      */
     public GridCacheMvccCandidate addNearLocal(GridCacheEntryEx parent,
@@ -702,7 +756,8 @@ public final class GridCacheMvcc {
         long threadId,
         GridCacheVersion ver,
         boolean tx,
-        boolean implicitSingle) {
+        boolean implicitSingle,
+        boolean read) {
         GridCacheMvccCandidate cand = new GridCacheMvccCandidate(parent,
             nodeId,
             otherNodeId,
@@ -716,7 +771,7 @@ public final class GridCacheMvcc {
             /*near loc*/true,
             /*dht loc*/false,
             null,
-            /*read*/false);
+            /*read*/read);
 
         add0(cand);
 
@@ -726,7 +781,7 @@ public final class GridCacheMvcc {
     /**
      * @param cand Remote candidate.
      */
-    public void addRemote(GridCacheMvccCandidate cand) {
+    private void addRemote(GridCacheMvccCandidate cand) {
         assert !cand.local();
 
         if (log.isDebugEnabled())
@@ -741,11 +796,11 @@ public final class GridCacheMvcc {
      * @param ver Lock version to acquire or set to ready.
      * @return Current owner.
      */
-    @Nullable public GridCacheMvccCandidate readyLocal(GridCacheVersion ver) {
+    @Nullable public CacheLockCandidates readyLocal(GridCacheVersion ver) {
         GridCacheMvccCandidate cand = candidate(ver);
 
         if (cand == null)
-            return anyOwner();
+            return allOwners();
 
         assert cand.local();
 
@@ -756,14 +811,14 @@ public final class GridCacheMvcc {
      * @param cand Local candidate added in any of the {@code addLocal(..)} methods.
      * @return Current lock owner.
      */
-    @Nullable public GridCacheMvccCandidate readyLocal(GridCacheMvccCandidate cand) {
+    @Nullable public CacheLockCandidates readyLocal(GridCacheMvccCandidate cand) {
         assert cand.local();
 
         cand.setReady();
 
         reassign();
 
-        return anyOwner();
+        return allOwners();
     }
 
     /**
@@ -782,9 +837,12 @@ public final class GridCacheMvcc {
      * @param pending Pending dht versions that are not owned and which version is less then mapped.
      * @return Lock owner after reassignment.
      */
-    @Nullable public GridCacheMvccCandidate readyNearLocal(GridCacheVersion ver, GridCacheVersion mappedVer,
-        Collection<GridCacheVersion> committedVers, Collection<GridCacheVersion> rolledBackVers,
-        Collection<GridCacheVersion> pending) {
+    @Nullable public CacheLockCandidates readyNearLocal(GridCacheVersion ver,
+        GridCacheVersion mappedVer,
+        Collection<GridCacheVersion> committedVers,
+        Collection<GridCacheVersion> rolledBackVers,
+        Collection<GridCacheVersion> pending)
+    {
         GridCacheMvccCandidate cand = candidate(locs, ver);
 
         if (cand != null) {
@@ -816,16 +874,18 @@ public final class GridCacheMvcc {
                     if (c.owner())
                         continue;
 
-                    assert !c.ready() :
+                    assert !c.ready() || (cand.read() && c.read()):
                         "Cannot have more then one ready near-local candidate [c=" + c + ", cand=" + cand +
                             ", mvcc=" + this + ']';
 
-                    it.remove();
+                    if (!c.ready()) {
+                        it.remove();
 
-                    if (mvAfter == null)
-                        mvAfter = new LinkedList<>();
+                        if (mvAfter == null)
+                            mvAfter = new LinkedList<>();
 
-                    mvAfter.add(c);
+                        mvAfter.add(c);
+                    }
                 }
             }
 
@@ -850,7 +910,7 @@ public final class GridCacheMvcc {
             reassign();
         }
 
-        return anyOwner();
+        return allOwners();
     }
 
     /**
@@ -862,7 +922,7 @@ public final class GridCacheMvcc {
      * @param rolledback Rolledback versions.
      * @return Lock owner.
      */
-    @Nullable public GridCacheMvccCandidate doneRemote(
+    @Nullable public CacheLockCandidates doneRemote(
         GridCacheVersion ver,
         Collection<GridCacheVersion> pending,
         Collection<GridCacheVersion> committed,
@@ -910,7 +970,7 @@ public final class GridCacheMvcc {
             }
         }
 
-        return anyOwner();
+        return allOwners();
     }
 
     /**
@@ -1119,15 +1179,16 @@ public final class GridCacheMvcc {
      *
      * @return Owner.
      */
-    @Nullable public GridCacheMvccCandidate recheck() {
+    @Nullable public CacheLockCandidates recheck() {
         reassign();
 
-        return anyOwner();
+        return allOwners();
     }
 
     /**
      * Local local release.
-     * @return Removed lock candidate or <tt>null</tt> if candidate was not removed.
+     *
+     * @return Removed candidate.
      */
     @Nullable public GridCacheMvccCandidate releaseLocal() {
         return releaseLocal(Thread.currentThread().getId());
@@ -1137,32 +1198,45 @@ public final class GridCacheMvcc {
      * Local release.
      *
      * @param threadId ID of the thread.
-     * @return Current owner.
+     * @return Removed candidate.
      */
     @Nullable public GridCacheMvccCandidate releaseLocal(long threadId) {
-        GridCacheMvccCandidate owner = localOwner();
+        CacheLockCandidates owners = localOwners();
 
-        if (owner == null || owner.threadId() != threadId)
-            // Release had no effect.
-            return owner;
+        // Release had no effect.
+        if (owners == null)
+            return null;
 
-        owner.setUsed();
+        GridCacheMvccCandidate owner = null;
 
-        remove0(owner.version(), true);
+        for (int i = 0; i < owners.size(); i++) {
+            GridCacheMvccCandidate owner0 = owners.candidate(i);
 
-        return anyOwner();
+            if (owner0.threadId() == threadId) {
+                owner = owner0;
+
+                break;
+            }
+        }
+
+        if (owner != null) {
+            owner.setUsed();
+
+            remove0(owner.version(), true);
+
+            return owner;
+        }
+        else
+            return null;
     }
 
     /**
      * Removes lock even if it is not owner.
      *
      * @param ver Lock version.
-     * @return Current owner.
      */
-    @Nullable public GridCacheMvccCandidate remove(GridCacheVersion ver) {
+    public void remove(GridCacheVersion ver) {
         remove0(ver, false);
-
-        return anyOwner();
     }
 
     /**
@@ -1171,7 +1245,7 @@ public final class GridCacheMvcc {
      * @param nodeId Node ID.
      * @return Current owner.
      */
-    @Nullable public GridCacheMvccCandidate removeExplicitNodeCandidates(UUID nodeId) {
+    @Nullable public CacheLockCandidates removeExplicitNodeCandidates(UUID nodeId) {
         if (rmts != null) {
             for (Iterator<GridCacheMvccCandidate> it = rmts.iterator(); it.hasNext(); ) {
                 GridCacheMvccCandidate cand = it.next();
@@ -1206,7 +1280,7 @@ public final class GridCacheMvcc {
 
         reassign();
 
-        return anyOwner();
+        return allOwners();
     }
 
     /**
@@ -1230,7 +1304,7 @@ public final class GridCacheMvcc {
      * @param threadId Thread ID.
      * @return Candidate or <tt>null</tt> if there is no candidate for given ID.
      */
-    @Nullable public GridCacheMvccCandidate localCandidate(long threadId) {
+    @Nullable GridCacheMvccCandidate localCandidate(long threadId) {
         // Don't return reentries.
         return localCandidate(threadId, false);
     }
@@ -1240,7 +1314,7 @@ public final class GridCacheMvcc {
      * @param threadId Thread ID.
      * @return Remote candidate.
      */
-    @Nullable public GridCacheMvccCandidate remoteCandidate(UUID nodeId, long threadId) {
+    @Nullable GridCacheMvccCandidate remoteCandidate(UUID nodeId, long threadId) {
         if (rmts != null)
             for (GridCacheMvccCandidate c : rmts)
                 if (c.nodeId().equals(nodeId) && c.threadId() == threadId)
@@ -1270,7 +1344,7 @@ public final class GridCacheMvcc {
      * @param ver Version.
      * @return {@code True} if candidate with given version exists.
      */
-    public boolean hasCandidate(GridCacheVersion ver) {
+    boolean hasCandidate(GridCacheVersion ver) {
         return candidate(ver) != null;
     }
 
@@ -1337,18 +1411,11 @@ public final class GridCacheMvcc {
     }
 
     /**
-     * @return {@code True} if lock is owner by current thread.
-     */
-    public boolean isLocallyOwnedByCurrentThread() {
-        return isLocallyOwnedByThread(Thread.currentThread().getId(), true);
-    }
-
-    /**
      * @param threadId Thread ID to check.
      * @param exclude Versions to ignore.
      * @return {@code True} if lock is owned by the thread with given ID.
      */
-    public boolean isLocallyOwnedByThread(long threadId, boolean allowDhtLoc, GridCacheVersion... exclude) {
+    boolean isLocallyOwnedByThread(long threadId, boolean allowDhtLoc, GridCacheVersion... exclude) {
         GridCacheMvccCandidate owner = localOwner();
 
         return owner != null && owner.threadId() == threadId && owner.nodeId().equals(cctx.nodeId()) &&
@@ -1356,29 +1423,11 @@ public final class GridCacheMvcc {
     }
 
     /**
-     * @param threadId Thread ID.
-     * @param nodeId Node ID.
-     * @return {@code True} if lock is held by given thread and node IDs.
-     */
-    public boolean isLockedByThread(long threadId, UUID nodeId) {
-        GridCacheMvccCandidate owner = anyOwner();
-
-        return owner != null && owner.threadId() == threadId && owner.nodeId().equals(nodeId);
-    }
-
-    /**
-     * @return {@code True} if lock is owned by any thread or node.
-     */
-    public boolean isOwnedByAny() {
-        return anyOwner() != null;
-    }
-
-    /**
      *
      * @param lockVer ID of lock candidate.
      * @return {@code True} if candidate is owner.
      */
-    public boolean isLocallyOwned(GridCacheVersion lockVer) {
+    boolean isLocallyOwned(GridCacheVersion lockVer) {
         GridCacheMvccCandidate owner = localOwner();
 
         return owner != null && owner.version().equals(lockVer);
@@ -1389,30 +1438,16 @@ public final class GridCacheMvcc {
      * @param threadId Thread ID.
      * @return {@code True} if locked by lock ID or thread ID.
      */
-    public boolean isLocallyOwnedByIdOrThread(GridCacheVersion lockVer, long threadId) {
+    boolean isLocallyOwnedByIdOrThread(GridCacheVersion lockVer, long threadId) {
         GridCacheMvccCandidate owner = localOwner();
 
         return owner != null && (owner.version().equals(lockVer) || owner.threadId() == threadId);
     }
 
     /**
-     * @return First remote entry or <tt>null</tt>.
-     */
-    @Nullable public GridCacheMvccCandidate firstRemote() {
-        return rmts == null ? null : rmts.getFirst();
-    }
-
-    /**
-     * @return First local entry or <tt>null</tt>.
-     */
-    @Nullable public GridCacheMvccCandidate firstLocal() {
-        return locs == null ? null : locs.getFirst();
-    }
-
-    /**
      * @return Local MVCC candidates.
      */
-    @Nullable public List<GridCacheMvccCandidate> allLocal() {
+    @Nullable List<GridCacheMvccCandidate> allLocal() {
         return locs;
     }
 
@@ -1420,10 +1455,10 @@ public final class GridCacheMvcc {
      * @param ver Version to check for ownership.
      * @return {@code True} if lock is owned by the specified version.
      */
-    public boolean isOwnedBy(GridCacheVersion ver) {
-        GridCacheMvccCandidate cand = anyOwner();
+    boolean isOwnedBy(GridCacheVersion ver) {
+        CacheLockCandidates owners = allOwners();
 
-        return cand != null && cand.version().equals(ver);
+        return owners != null && owners.hasCandidate(ver);
     }
 
     /** {@inheritDoc} */

http://git-wip-us.apache.org/repos/asf/ignite/blob/36e98d6a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheMvccCallback.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheMvccCallback.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheMvccCallback.java
index fc1faf7..2ba41f7 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheMvccCallback.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheMvccCallback.java
@@ -37,11 +37,9 @@ public interface GridCacheMvccCallback {
      * can be made from this call.
      *
      * @param entry Entry.
-     * @param prev Previous candidate.
      * @param owner Current owner.
      */
-    public void onOwnerChanged(GridCacheEntryEx entry, GridCacheMvccCandidate prev,
-        GridCacheMvccCandidate owner);
+    public void onOwnerChanged(GridCacheEntryEx entry, GridCacheMvccCandidate owner);
 
     /**
      * Called when entry has no more candidates. This call happens

http://git-wip-us.apache.org/repos/asf/ignite/blob/36e98d6a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheMvccCandidate.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheMvccCandidate.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheMvccCandidate.java
index a08a21f..e9dd455 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheMvccCandidate.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheMvccCandidate.java
@@ -55,7 +55,7 @@ import static org.apache.ignite.internal.processors.cache.GridCacheMvccCandidate
  * Lock candidate.
  */
 public class GridCacheMvccCandidate implements Externalizable,
-    Comparable<GridCacheMvccCandidate> {
+    Comparable<GridCacheMvccCandidate>, CacheLockCandidates {
     /** */
     private static final long serialVersionUID = 0L;
 
@@ -164,7 +164,6 @@ public class GridCacheMvccCandidate implements Externalizable,
         assert nodeId != null;
         assert ver != null;
         assert parent != null;
-        assert !read || serOrder != null;
 
         this.parent = parent;
         this.nodeId = nodeId;
@@ -571,16 +570,21 @@ public class GridCacheMvccCandidate implements Externalizable,
         return parent0.txKey();
     }
 
-    /**
-     * Checks if this candidate matches version or thread-nodeId combination.
-     *
-     * @param nodeId Node ID to check.
-     * @param ver Version to check.
-     * @param threadId Thread ID to check.
-     * @return {@code True} if matched.
-     */
-    public boolean matches(GridCacheVersion ver, UUID nodeId, long threadId) {
-        return ver.equals(this.ver) || (nodeId.equals(this.nodeId) && threadId == this.threadId);
+    /** {@inheritDoc} */
+    @Override public GridCacheMvccCandidate candidate(int idx) {
+        assert idx == 0 : idx;
+
+        return this;
+    }
+
+    /** {@inheritDoc} */
+    @Override public int size() {
+        return 1;
+    }
+
+    /** {@inheritDoc} */
+    @Override public boolean hasCandidate(GridCacheVersion ver) {
+        return this.ver.equals(ver);
     }
 
     /** {@inheritDoc} */

http://git-wip-us.apache.org/repos/asf/ignite/blob/36e98d6a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheMvccManager.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheMvccManager.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheMvccManager.java
index c57e17c..0d0e9ee 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheMvccManager.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheMvccManager.java
@@ -140,15 +140,14 @@ public class GridCacheMvccManager extends GridCacheSharedManagerAdapter {
     private final GridCacheMvccCallback cb = new GridCacheMvccCallback() {
         /** {@inheritDoc} */
         @SuppressWarnings({"unchecked"})
-        @Override public void onOwnerChanged(final GridCacheEntryEx entry, final GridCacheMvccCandidate prev,
-            final GridCacheMvccCandidate owner) {
+        @Override public void onOwnerChanged(final GridCacheEntryEx entry, final GridCacheMvccCandidate owner) {
             int nested = nestedLsnrCalls.get();
 
             if (nested < MAX_NESTED_LSNR_CALLS) {
                 nestedLsnrCalls.set(nested + 1);
 
                 try {
-                    notifyOwnerChanged(entry, prev, owner);
+                    notifyOwnerChanged(entry, owner);
                 }
                 finally {
                     nestedLsnrCalls.set(nested);
@@ -157,7 +156,7 @@ public class GridCacheMvccManager extends GridCacheSharedManagerAdapter {
             else {
                 cctx.kernalContext().closure().runLocalSafe(new GridPlainRunnable() {
                     @Override public void run() {
-                        notifyOwnerChanged(entry, prev, owner);
+                        notifyOwnerChanged(entry, owner);
                     }
                 }, true);
             }
@@ -182,19 +181,13 @@ public class GridCacheMvccManager extends GridCacheSharedManagerAdapter {
 
     /**
      * @param entry Entry to notify callback for.
-     * @param prev Previous lock owner.
      * @param owner Current lock owner.
      */
-    private void notifyOwnerChanged(final GridCacheEntryEx entry, final GridCacheMvccCandidate prev,
-        final GridCacheMvccCandidate owner) {
+    private void notifyOwnerChanged(final GridCacheEntryEx entry, final GridCacheMvccCandidate owner) {
         assert entry != null;
-        assert owner != prev : "New and previous owner are identical instances: " + owner;
-        assert owner == null || prev == null || !owner.version().equals(prev.version()) :
-            "New and previous owners have identical versions [owner=" + owner + ", prev=" + prev + ']';
 
         if (log.isDebugEnabled())
-            log.debug("Received owner changed callback [" + entry.key() + ", owner=" + owner + ", prev=" +
-                prev + ']');
+            log.debug("Received owner changed callback [" + entry.key() + ", owner=" + owner + ']');
 
         if (owner != null && (owner.local() || owner.nearLocal())) {
             Collection<GridCacheMvccFuture<?>> futCol = mvccFuts.get(owner.version());
@@ -226,7 +219,7 @@ public class GridCacheMvccManager extends GridCacheSharedManagerAdapter {
 
         if (log.isDebugEnabled())
             log.debug("Lock future not found for owner change callback (will try transaction futures) [owner=" +
-                owner + ", prev=" + prev + ", entry=" + entry + ']');
+                owner + ", entry=" + entry + ']');
 
         // If no future was found, delegate to transaction manager.
         if (cctx.tm().onOwnerChanged(entry, owner)) {

http://git-wip-us.apache.org/repos/asf/ignite/blob/36e98d6a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/GridDistributedCacheEntry.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/GridDistributedCacheEntry.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/GridDistributedCacheEntry.java
index 68031c6..3a94e8b 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/GridDistributedCacheEntry.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/GridDistributedCacheEntry.java
@@ -23,6 +23,7 @@ import java.util.Collections;
 import java.util.List;
 import java.util.UUID;
 import org.apache.ignite.internal.processors.affinity.AffinityTopologyVersion;
+import org.apache.ignite.internal.processors.cache.CacheLockCandidates;
 import org.apache.ignite.internal.processors.cache.CacheObject;
 import org.apache.ignite.internal.processors.cache.GridCacheContext;
 import org.apache.ignite.internal.processors.cache.GridCacheEntryRemovedException;
@@ -82,6 +83,7 @@ public class GridDistributedCacheEntry extends GridCacheMapEntry {
      * @param reenter Reentry flag.
      * @param tx Transaction flag.
      * @param implicitSingle Implicit flag.
+     * @param read Read lock flag.
      * @return New candidate.
      * @throws GridCacheEntryRemovedException If entry has been removed.
      */
@@ -92,10 +94,11 @@ public class GridDistributedCacheEntry extends GridCacheMapEntry {
         long timeout,
         boolean reenter,
         boolean tx,
-        boolean implicitSingle) throws GridCacheEntryRemovedException {
+        boolean implicitSingle,
+        boolean read) throws GridCacheEntryRemovedException {
         GridCacheMvccCandidate cand;
-        GridCacheMvccCandidate prev;
-        GridCacheMvccCandidate owner;
+        CacheLockCandidates prev;
+        CacheLockCandidates owner;
 
         CacheObject val;
 
@@ -110,16 +113,23 @@ public class GridDistributedCacheEntry extends GridCacheMapEntry {
                 mvccExtras(mvcc);
             }
 
-            prev = mvcc.anyOwner();
+            prev = mvcc.allOwners();
 
             boolean emptyBefore = mvcc.isEmpty();
 
-            cand = mvcc.addLocal(this, threadId, ver, timeout, reenter, tx, implicitSingle);
+            cand = mvcc.addLocal(this,
+                threadId,
+                ver,
+                timeout,
+                reenter,
+                tx,
+                implicitSingle,
+                read);
 
             if (cand != null)
                 cand.topologyVersion(topVer);
 
-            owner = mvcc.anyOwner();
+            owner = mvcc.allOwners();
 
             boolean emptyAfter = mvcc.isEmpty();
 
@@ -183,8 +193,8 @@ public class GridDistributedCacheEntry extends GridCacheMapEntry {
         boolean implicitSingle,
         @Nullable GridCacheVersion owned
     ) throws GridDistributedLockCancelledException, GridCacheEntryRemovedException {
-        GridCacheMvccCandidate prev;
-        GridCacheMvccCandidate owner;
+        CacheLockCandidates prev;
+        CacheLockCandidates owner;
 
         CacheObject val;
 
@@ -202,7 +212,7 @@ public class GridDistributedCacheEntry extends GridCacheMapEntry {
                 mvccExtras(mvcc);
             }
 
-            prev = mvcc.anyOwner();
+            prev = mvcc.allOwners();
 
             boolean emptyBefore = mvcc.isEmpty();
 
@@ -220,7 +230,7 @@ public class GridDistributedCacheEntry extends GridCacheMapEntry {
             if (owned != null)
                 mvcc.markOwned(ver, owned);
 
-            owner = mvcc.anyOwner();
+            owner = mvcc.allOwners();
 
             boolean emptyAfter = mvcc.isEmpty();
 
@@ -245,8 +255,8 @@ public class GridDistributedCacheEntry extends GridCacheMapEntry {
      * @throws GridCacheEntryRemovedException If entry was removed.
      */
     public void removeExplicitNodeLocks(UUID nodeId) throws GridCacheEntryRemovedException {
-        GridCacheMvccCandidate prev = null;
-        GridCacheMvccCandidate owner = null;
+        CacheLockCandidates prev = null;
+        CacheLockCandidates owner = null;
 
         CacheObject val = null;
 
@@ -256,7 +266,7 @@ public class GridDistributedCacheEntry extends GridCacheMapEntry {
             GridCacheMvcc mvcc = mvccExtras();
 
             if (mvcc != null) {
-                prev = mvcc.anyOwner();
+                prev = mvcc.allOwners();
 
                 boolean emptyBefore = mvcc.isEmpty();
 
@@ -288,8 +298,9 @@ public class GridDistributedCacheEntry extends GridCacheMapEntry {
      * @return Removed candidate, or <tt>null</tt> if thread still holds the lock.
      */
     @Nullable public GridCacheMvccCandidate removeLock() {
-        GridCacheMvccCandidate prev = null;
-        GridCacheMvccCandidate owner = null;
+        GridCacheMvccCandidate rmvd = null;
+        CacheLockCandidates prev = null;
+        CacheLockCandidates owner = null;
 
         CacheObject val;
 
@@ -297,11 +308,11 @@ public class GridDistributedCacheEntry extends GridCacheMapEntry {
             GridCacheMvcc mvcc = mvccExtras();
 
             if (mvcc != null) {
-                prev = mvcc.anyOwner();
+                prev = mvcc.allOwners();
 
                 boolean emptyBefore = mvcc.isEmpty();
 
-                owner = mvcc.releaseLocal();
+                rmvd = mvcc.releaseLocal();
 
                 boolean emptyAfter = mvcc.isEmpty();
 
@@ -309,28 +320,38 @@ public class GridDistributedCacheEntry extends GridCacheMapEntry {
 
                 if (emptyAfter)
                     mvccExtras(null);
+                else
+                    owner = mvcc.allOwners();
             }
 
             val = this.val;
         }
 
-        if (log.isDebugEnabled())
-            log.debug("Released local candidate from entry [owner=" + owner + ", prev=" + prev +
+        if (log.isDebugEnabled()) {
+            log.debug("Released local candidate from entry [owner=" + owner +
+                ", prev=" + prev +
+                ", rmvd=" + rmvd +
                 ", entry=" + this + ']');
+        }
+
+        if (prev != null) {
+            for (int i = 0; i < prev.size(); i++) {
+                GridCacheMvccCandidate cand = prev.candidate(i);
 
-        if (prev != null && owner != prev)
-            checkThreadChain(prev);
+                checkThreadChain(cand);
+            }
+        }
 
         // This call must be outside of synchronization.
         checkOwnerChanged(prev, owner, val);
 
-        return owner != prev ? prev : null;
+        return rmvd;
     }
 
     /** {@inheritDoc} */
     @Override public boolean removeLock(GridCacheVersion ver) throws GridCacheEntryRemovedException {
-        GridCacheMvccCandidate prev = null;
-        GridCacheMvccCandidate owner = null;
+        CacheLockCandidates prev = null;
+        CacheLockCandidates owner = null;
 
         GridCacheMvccCandidate doomed;
 
@@ -350,13 +371,13 @@ public class GridDistributedCacheEntry extends GridCacheMapEntry {
                 checkObsolete();
 
             if (doomed != null) {
-                assert mvcc != null;
-
-                prev = mvcc.anyOwner();
+                prev = mvcc.allOwners();
 
                 boolean emptyBefore = mvcc.isEmpty();
 
-                owner = mvcc.remove(doomed.version());
+                mvcc.remove(doomed.version());
+
+                owner = mvcc.allOwners();
 
                 boolean emptyAfter = mvcc.isEmpty();
 
@@ -419,10 +440,10 @@ public class GridDistributedCacheEntry extends GridCacheMapEntry {
      * @return Owner.
      * @throws GridCacheEntryRemovedException If entry is removed.
      */
-    @Nullable public GridCacheMvccCandidate readyLock(GridCacheVersion ver)
+    @Nullable public CacheLockCandidates readyLock(GridCacheVersion ver)
         throws GridCacheEntryRemovedException {
-        GridCacheMvccCandidate prev = null;
-        GridCacheMvccCandidate owner = null;
+        CacheLockCandidates prev = null;
+        CacheLockCandidates owner = null;
 
         CacheObject val;
 
@@ -432,13 +453,13 @@ public class GridDistributedCacheEntry extends GridCacheMapEntry {
             GridCacheMvcc mvcc = mvccExtras();
 
             if (mvcc != null) {
-                prev = mvcc.anyOwner();
+                prev = mvcc.allOwners();
 
                 boolean emptyBefore = mvcc.isEmpty();
 
                 owner = mvcc.readyLocal(ver);
 
-                assert owner == null || owner.owner() : "Owner flag not set for owner: " + owner;
+                assert owner == null || owner.candidate(0).owner() : "Owner flag not set for owner: " + owner;
 
                 boolean emptyAfter = mvcc.isEmpty();
 
@@ -465,16 +486,16 @@ public class GridDistributedCacheEntry extends GridCacheMapEntry {
      * @param committed Committed versions.
      * @param rolledBack Rolled back versions.
      * @param pending Pending locks on dht node with version less then mapped.
-     * @return Current lock owner.
      *
      * @throws GridCacheEntryRemovedException If entry is removed.
      */
-    @Nullable public GridCacheMvccCandidate readyNearLock(GridCacheVersion ver, GridCacheVersion mapped,
+    public void readyNearLock(GridCacheVersion ver, GridCacheVersion mapped,
         Collection<GridCacheVersion> committed,
         Collection<GridCacheVersion> rolledBack,
-        Collection<GridCacheVersion> pending) throws GridCacheEntryRemovedException {
-        GridCacheMvccCandidate prev = null;
-        GridCacheMvccCandidate owner = null;
+        Collection<GridCacheVersion> pending) throws GridCacheEntryRemovedException
+    {
+        CacheLockCandidates prev = null;
+        CacheLockCandidates owner = null;
 
         CacheObject val;
 
@@ -484,13 +505,13 @@ public class GridDistributedCacheEntry extends GridCacheMapEntry {
             GridCacheMvcc mvcc = mvccExtras();
 
             if (mvcc != null) {
-                prev = mvcc.anyOwner();
+                prev = mvcc.allOwners();
 
                 boolean emptyBefore = mvcc.isEmpty();
 
                 owner = mvcc.readyNearLocal(ver, mapped, committed, rolledBack, pending);
 
-                assert owner == null || owner.owner() : "Owner flag is not set for owner: " + owner;
+                assert owner == null || owner.candidate(0).owner() : "Owner flag is not set for owner: " + owner;
 
                 boolean emptyAfter = mvcc.isEmpty();
 
@@ -505,30 +526,6 @@ public class GridDistributedCacheEntry extends GridCacheMapEntry {
 
         // This call must be made outside of synchronization.
         checkOwnerChanged(prev, owner, val);
-
-        return owner;
-    }
-
-    /**
-     *
-     * @param lockVer Done version.
-     * @param baseVer Base version.
-     * @param committedVers Completed versions for reordering.
-     * @param rolledbackVers Rolled back versions for reordering.
-     * @param sysInvalidate Flag indicating if this entry is done from invalidated transaction (in case of tx
-     *      salvage). In this case all locks before salvaged lock will marked as used and corresponding
-     *      transactions will be invalidated.
-     * @throws GridCacheEntryRemovedException If entry has been removed.
-     * @return Owner.
-     */
-    @Nullable public GridCacheMvccCandidate doneRemote(
-        GridCacheVersion lockVer,
-        GridCacheVersion baseVer,
-        Collection<GridCacheVersion> committedVers,
-        Collection<GridCacheVersion> rolledbackVers,
-        boolean sysInvalidate) throws GridCacheEntryRemovedException {
-        return doneRemote(lockVer, baseVer, Collections.<GridCacheVersion>emptySet(), committedVers,
-            rolledbackVers, sysInvalidate);
     }
 
     /**
@@ -542,17 +539,16 @@ public class GridDistributedCacheEntry extends GridCacheMapEntry {
      *      salvage). In this case all locks before salvaged lock will marked as used and corresponding
      *      transactions will be invalidated.
      * @throws GridCacheEntryRemovedException If entry has been removed.
-     * @return Owner.
      */
-    @Nullable public GridCacheMvccCandidate doneRemote(
+    public void doneRemote(
         GridCacheVersion lockVer,
         GridCacheVersion baseVer,
         @Nullable Collection<GridCacheVersion> pendingVers,
         Collection<GridCacheVersion> committedVers,
         Collection<GridCacheVersion> rolledbackVers,
         boolean sysInvalidate) throws GridCacheEntryRemovedException {
-        GridCacheMvccCandidate prev = null;
-        GridCacheMvccCandidate owner = null;
+        CacheLockCandidates prev = null;
+        CacheLockCandidates owner = null;
 
         CacheObject val;
 
@@ -562,7 +558,7 @@ public class GridDistributedCacheEntry extends GridCacheMapEntry {
             GridCacheMvcc mvcc = mvccExtras();
 
             if (mvcc != null) {
-                prev = mvcc.anyOwner();
+                prev = mvcc.allOwners();
 
                 boolean emptyBefore = mvcc.isEmpty();
 
@@ -577,7 +573,9 @@ public class GridDistributedCacheEntry extends GridCacheMapEntry {
                 if (sysInvalidate && baseVer != null)
                     mvcc.salvageRemote(baseVer);
 
-                owner = mvcc.doneRemote(lockVer, maskNull(pendingVers), maskNull(committedVers),
+                owner = mvcc.doneRemote(lockVer,
+                    maskNull(pendingVers),
+                    maskNull(committedVers),
                     maskNull(rolledbackVers));
 
                 boolean emptyAfter = mvcc.isEmpty();
@@ -593,18 +591,14 @@ public class GridDistributedCacheEntry extends GridCacheMapEntry {
 
         // This call must be made outside of synchronization.
         checkOwnerChanged(prev, owner, val);
-
-        return owner;
     }
 
     /**
      * Rechecks if lock should be reassigned.
-     *
-     * @return Current owner.
      */
-    @Nullable public GridCacheMvccCandidate recheck() {
-        GridCacheMvccCandidate prev = null;
-        GridCacheMvccCandidate owner = null;
+    public void recheck() {
+        CacheLockCandidates prev = null;
+        CacheLockCandidates owner = null;
 
         CacheObject val;
 
@@ -612,7 +606,7 @@ public class GridDistributedCacheEntry extends GridCacheMapEntry {
             GridCacheMvcc mvcc = mvccExtras();
 
             if (mvcc != null) {
-                prev = mvcc.anyOwner();
+                prev = mvcc.allOwners();
 
                 boolean emptyBefore = mvcc.isEmpty();
 
@@ -631,8 +625,6 @@ public class GridDistributedCacheEntry extends GridCacheMapEntry {
 
         // This call must be made outside of synchronization.
         checkOwnerChanged(prev, owner, val);
-
-        return owner;
     }
 
     /** {@inheritDoc} */
@@ -651,7 +643,8 @@ public class GridDistributedCacheEntry extends GridCacheMapEntry {
                 timeout,
                 /*reenter*/false,
                 /*tx*/true,
-                tx.implicitSingle()) != null;
+                tx.implicitSingle(),
+                read) != null;
 
         try {
             addRemote(
@@ -696,15 +689,85 @@ public class GridDistributedCacheEntry extends GridCacheMapEntry {
     }
 
     /**
+     * @param prev Previous owners.
+     * @param owner Corrent owners.
+     * @param val Entry value.
+     */
+    protected final void checkOwnerChanged(@Nullable CacheLockCandidates prev,
+        @Nullable CacheLockCandidates owner,
+        CacheObject val) {
+        assert !Thread.holdsLock(this);
+
+        if (prev != null && cctx.events().isRecordable(EVT_CACHE_OBJECT_UNLOCKED)) {
+            for (int i = 0; i < prev.size(); i++) {
+                GridCacheMvccCandidate cand = prev.candidate(i);
+
+                boolean unlocked = owner == null || !owner.hasCandidate(cand.version());
+
+                if (unlocked) {
+                    boolean hasVal = hasValue();
+
+                    cctx.events().addEvent(partition(),
+                        key,
+                        cand.nodeId(),
+                        cand,
+                        EVT_CACHE_OBJECT_UNLOCKED,
+                        val,
+                        hasVal,
+                        val, hasVal,
+                        null,
+                        null,
+                        null,
+                        true);
+                }
+            }
+        }
+
+        if (owner != null) {
+            for (int i = 0; i < owner.size(); i++) {
+                GridCacheMvccCandidate cand = owner.candidate(i);
+
+                boolean locked = prev == null || !prev.hasCandidate(cand.version());
+
+                if (locked) {
+                    cctx.mvcc().callback().onOwnerChanged(this, cand);
+
+                    if (cand.local())
+                        checkThreadChain(cand);
+
+                    if (cctx.events().isRecordable(EVT_CACHE_OBJECT_LOCKED)) {
+                        boolean hasVal = hasValue();
+
+                        // Event notification.
+                        cctx.events().addEvent(partition(),
+                            key,
+                            cand.nodeId(),
+                            cand,
+                            EVT_CACHE_OBJECT_LOCKED,
+                            val,
+                            hasVal,
+                            val,
+                            hasVal,
+                            null,
+                            null,
+                            null,
+                            true);
+                    }
+                }
+            }
+        }
+    }
+
+    /**
      * @param prev Previous owner.
      * @param owner Current owner.
      * @param val Entry value.
      */
-    protected void checkOwnerChanged(GridCacheMvccCandidate prev, GridCacheMvccCandidate owner, CacheObject val) {
+    protected final void checkOwnerChanged(GridCacheMvccCandidate prev, GridCacheMvccCandidate owner, CacheObject val) {
         assert !Thread.holdsLock(this);
 
         if (owner != prev) {
-            cctx.mvcc().callback().onOwnerChanged(this, prev, owner);
+            cctx.mvcc().callback().onOwnerChanged(this, owner);
 
             if (owner != null && owner.local())
                 checkThreadChain(owner);

http://git-wip-us.apache.org/repos/asf/ignite/blob/36e98d6a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtCacheEntry.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtCacheEntry.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtCacheEntry.java
index 581f636..dbbb235 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtCacheEntry.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtCacheEntry.java
@@ -27,6 +27,7 @@ import org.apache.ignite.IgniteCheckedException;
 import org.apache.ignite.cluster.ClusterNode;
 import org.apache.ignite.internal.IgniteInternalFuture;
 import org.apache.ignite.internal.processors.affinity.AffinityTopologyVersion;
+import org.apache.ignite.internal.processors.cache.CacheLockCandidates;
 import org.apache.ignite.internal.processors.cache.CacheObject;
 import org.apache.ignite.internal.processors.cache.GridCacheContext;
 import org.apache.ignite.internal.processors.cache.GridCacheEntryRemovedException;
@@ -192,8 +193,8 @@ public class GridDhtCacheEntry extends GridDistributedCacheEntry {
         assert !reenter || serOrder == null;
 
         GridCacheMvccCandidate cand;
-        GridCacheMvccCandidate prev;
-        GridCacheMvccCandidate owner;
+        CacheLockCandidates prev;
+        CacheLockCandidates owner;
 
         CacheObject val;
 
@@ -212,7 +213,7 @@ public class GridDhtCacheEntry extends GridDistributedCacheEntry {
                 mvccExtras(mvcc);
             }
 
-            prev = mvcc.anyOwner();
+            prev = mvcc.allOwners();
 
             boolean emptyBefore = mvcc.isEmpty();
 
@@ -236,10 +237,10 @@ public class GridDhtCacheEntry extends GridDistributedCacheEntry {
 
             cand.topologyVersion(topVer);
 
-            owner = mvcc.anyOwner();
+            owner = mvcc.allOwners();
 
             if (owner != null)
-                cand.ownerVersion(owner.version());
+                cand.ownerVersion(owner.candidate(0).version());
 
             boolean emptyAfter = mvcc.isEmpty();
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/36e98d6a/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 b3a1394..afc7615 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
@@ -36,6 +36,7 @@ import org.apache.ignite.internal.NodeStoppingException;
 import org.apache.ignite.internal.cluster.ClusterTopologyCheckedException;
 import org.apache.ignite.internal.processors.affinity.AffinityTopologyVersion;
 import org.apache.ignite.internal.processors.cache.CacheEntryPredicate;
+import org.apache.ignite.internal.processors.cache.CacheLockCandidates;
 import org.apache.ignite.internal.processors.cache.CacheObject;
 import org.apache.ignite.internal.processors.cache.GridCacheContext;
 import org.apache.ignite.internal.processors.cache.GridCacheEntryEx;
@@ -346,25 +347,6 @@ public final class GridDhtLockFuture extends GridCompoundIdentityFuture<Boolean>
     }
 
     /**
-     * @param cached Entry.
-     * @return {@code True} if locked.
-     * @throws GridCacheEntryRemovedException If removed.
-     */
-    private boolean locked(GridCacheEntryEx cached) throws GridCacheEntryRemovedException {
-        return (cached.lockedLocally(lockVer) && filter(cached)); // If filter failed, lock is failed.
-    }
-
-    /**
-     * @param cached Entry.
-     * @param owner Lock owner.
-     * @return {@code True} if locked.
-     */
-    private boolean locked(GridCacheEntryEx cached, GridCacheMvccCandidate owner) {
-        // Reentry-aware check (if filter failed, lock is failed).
-        return owner != null && owner.matches(lockVer, cctx.nodeId(), threadId) && filter(cached);
-    }
-
-    /**
      * Adds entry to future.
      *
      * @param entry Entry to add.
@@ -576,10 +558,10 @@ public final class GridDhtLockFuture extends GridCompoundIdentityFuture<Boolean>
                     break; // While.
 
                 try {
-                    GridCacheMvccCandidate owner = entry.readyLock(lockVer);
+                    CacheLockCandidates owners = entry.readyLock(lockVer);
 
                     if (timeout < 0) {
-                        if (owner == null || !owner.version().equals(lockVer)) {
+                        if (owners == null || !owners.hasCandidate(lockVer)) {
                             // We did not send any requests yet.
                             onFailed(false);
 
@@ -588,9 +570,9 @@ public final class GridDhtLockFuture extends GridCompoundIdentityFuture<Boolean>
                     }
 
                     if (log.isDebugEnabled()) {
-                        if (!locked(entry, owner))
-                            log.debug("Entry is not locked (will keep waiting) [entry=" + entry +
-                                ", fut=" + this + ']');
+                        log.debug("Current lock owners [entry=" + entry +
+                            ", owners=" + owners +
+                            ", fut=" + this + ']');
                     }
 
                     break; // Inner while loop.

http://git-wip-us.apache.org/repos/asf/ignite/blob/36e98d6a/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 1dbda69..a759194 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
@@ -40,6 +40,7 @@ import org.apache.ignite.internal.IgniteInternalFuture;
 import org.apache.ignite.internal.cluster.ClusterTopologyCheckedException;
 import org.apache.ignite.internal.processors.affinity.AffinityTopologyVersion;
 import org.apache.ignite.internal.processors.cache.CacheInvokeEntry;
+import org.apache.ignite.internal.processors.cache.CacheLockCandidates;
 import org.apache.ignite.internal.processors.cache.CacheObject;
 import org.apache.ignite.internal.processors.cache.GridCacheContext;
 import org.apache.ignite.internal.processors.cache.GridCacheEntryEx;
@@ -629,10 +630,10 @@ public final class GridDhtTxPrepareFuture extends GridCompoundFuture<IgniteInter
                 try {
                     assert txEntry.explicitVersion() == null || entry.lockedBy(txEntry.explicitVersion());
 
-                    GridCacheMvccCandidate c = entry.readyLock(tx.xidVersion());
+                    CacheLockCandidates owners = entry.readyLock(tx.xidVersion());
 
                     if (log.isDebugEnabled())
-                        log.debug("Current lock owner for entry [owner=" + c + ", entry=" + entry + ']');
+                        log.debug("Current lock owners for entry [owner=" + owners + ", entry=" + entry + ']');
 
                     break; // While.
                 }

http://git-wip-us.apache.org/repos/asf/ignite/blob/36e98d6a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearCacheEntry.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearCacheEntry.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearCacheEntry.java
index 7cd4196..cad6f90 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearCacheEntry.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearCacheEntry.java
@@ -21,6 +21,7 @@ import java.util.UUID;
 import org.apache.ignite.IgniteCheckedException;
 import org.apache.ignite.cluster.ClusterNode;
 import org.apache.ignite.internal.processors.affinity.AffinityTopologyVersion;
+import org.apache.ignite.internal.processors.cache.CacheLockCandidates;
 import org.apache.ignite.internal.processors.cache.CacheObject;
 import org.apache.ignite.internal.processors.cache.GridCacheContext;
 import org.apache.ignite.internal.processors.cache.GridCacheEntryInfo;
@@ -444,7 +445,8 @@ public class GridNearCacheEntry extends GridDistributedCacheEntry {
         long timeout,
         boolean reenter,
         boolean tx,
-        boolean implicitSingle) throws GridCacheEntryRemovedException {
+        boolean implicitSingle,
+        boolean read) throws GridCacheEntryRemovedException {
         return addNearLocal(
             null,
             threadId,
@@ -453,7 +455,8 @@ public class GridNearCacheEntry extends GridDistributedCacheEntry {
             timeout,
             reenter,
             tx,
-            implicitSingle
+            implicitSingle,
+            read
         );
     }
 
@@ -468,10 +471,11 @@ public class GridNearCacheEntry extends GridDistributedCacheEntry {
      * @param reenter Reentry flag.
      * @param tx Transaction flag.
      * @param implicitSingle Implicit flag.
+     * @param read Read lock flag.
      * @return New candidate.
      * @throws GridCacheEntryRemovedException If entry has been removed.
      */
-    @Nullable public GridCacheMvccCandidate addNearLocal(
+    @Nullable GridCacheMvccCandidate addNearLocal(
         @Nullable UUID dhtNodeId,
         long threadId,
         GridCacheVersion ver,
@@ -479,10 +483,11 @@ public class GridNearCacheEntry extends GridDistributedCacheEntry {
         long timeout,
         boolean reenter,
         boolean tx,
-        boolean implicitSingle)
+        boolean implicitSingle,
+        boolean read)
         throws GridCacheEntryRemovedException {
-        GridCacheMvccCandidate prev;
-        GridCacheMvccCandidate owner;
+        CacheLockCandidates prev;
+        CacheLockCandidates owner;
         GridCacheMvccCandidate cand;
 
         CacheObject val;
@@ -505,7 +510,7 @@ public class GridNearCacheEntry extends GridDistributedCacheEntry {
             if (c != null)
                 return reenter ? c.reenter() : null;
 
-            prev = mvcc.anyOwner();
+            prev = mvcc.allOwners();
 
             boolean emptyBefore = mvcc.isEmpty();
 
@@ -521,11 +526,12 @@ public class GridNearCacheEntry extends GridDistributedCacheEntry {
                 threadId,
                 ver,
                 tx,
-                implicitSingle);
+                implicitSingle,
+                read);
 
             cand.topologyVersion(topVer);
 
-            owner = mvcc.anyOwner();
+            owner = mvcc.allOwners();
 
             boolean emptyAfter = mvcc.isEmpty();
 
@@ -571,8 +577,8 @@ public class GridNearCacheEntry extends GridDistributedCacheEntry {
      * @return Removed candidate, or <tt>null</tt> if thread still holds the lock.
      */
     @Nullable @Override public GridCacheMvccCandidate removeLock() {
-        GridCacheMvccCandidate prev = null;
-        GridCacheMvccCandidate owner = null;
+        CacheLockCandidates prev = null;
+        CacheLockCandidates owner = null;
 
         CacheObject val;
 
@@ -584,7 +590,7 @@ public class GridNearCacheEntry extends GridDistributedCacheEntry {
             GridCacheMvcc mvcc = mvccExtras();
 
             if (mvcc != null) {
-                prev = mvcc.anyOwner();
+                prev = mvcc.allOwners();
 
                 boolean emptyBefore = mvcc.isEmpty();
 
@@ -604,7 +610,7 @@ public class GridNearCacheEntry extends GridDistributedCacheEntry {
 
                     mvcc.remove(cand.version());
 
-                    owner = mvcc.anyOwner();
+                    owner = mvcc.allOwners();
                 }
                 else
                     return null;
@@ -629,13 +635,12 @@ public class GridNearCacheEntry extends GridDistributedCacheEntry {
 
         cctx.mvcc().removeExplicitLock(cand);
 
-        if (prev != null && owner != prev)
-            checkThreadChain(prev);
+        checkThreadChain(cand);
 
         // This call must be outside of synchronization.
         checkOwnerChanged(prev, owner, val);
 
-        return owner != prev ? prev : null;
+        return cand;
     }
 
     /** {@inheritDoc} */

http://git-wip-us.apache.org/repos/asf/ignite/blob/36e98d6a/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 3d9b6ab..2431379 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
@@ -325,7 +325,8 @@ public final class GridNearLockFuture extends GridCompoundIdentityFuture<Boolean
             timeout,
             !inTx(),
             inTx(),
-            implicitSingleTx()
+            implicitSingleTx(),
+            false
         );
 
         if (inTx()) {

http://git-wip-us.apache.org/repos/asf/ignite/blob/36e98d6a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/local/GridLocalCacheEntry.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/local/GridLocalCacheEntry.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/local/GridLocalCacheEntry.java
index 1aa5017..d910363 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/local/GridLocalCacheEntry.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/local/GridLocalCacheEntry.java
@@ -17,6 +17,7 @@
 
 package org.apache.ignite.internal.processors.cache.local;
 
+import org.apache.ignite.internal.processors.cache.CacheLockCandidates;
 import org.apache.ignite.internal.processors.cache.CacheObject;
 import org.apache.ignite.internal.processors.cache.GridCacheContext;
 import org.apache.ignite.internal.processors.cache.GridCacheEntryRemovedException;
@@ -152,19 +153,17 @@ public class GridLocalCacheEntry extends GridCacheMapEntry {
     }
 
     /**
-     *
      * @param cand Candidate.
-     * @return Current owner.
      */
-    @Nullable public GridCacheMvccCandidate readyLocal(GridCacheMvccCandidate cand) {
-        GridCacheMvccCandidate prev = null;
-        GridCacheMvccCandidate owner = null;
+    void readyLocal(GridCacheMvccCandidate cand) {
+        CacheLockCandidates prev = null;
+        CacheLockCandidates owner = null;
 
         synchronized (this) {
             GridCacheMvcc mvcc = mvccExtras();
 
             if (mvcc != null) {
-                prev = mvcc.localOwner();
+                prev = mvcc.localOwners();
 
                 owner = mvcc.readyLocal(cand);
 
@@ -174,8 +173,6 @@ public class GridLocalCacheEntry extends GridCacheMapEntry {
         }
 
         checkOwnerChanged(prev, owner);
-
-        return owner;
     }
 
     /** {@inheritDoc} */
@@ -208,18 +205,16 @@ public class GridLocalCacheEntry extends GridCacheMapEntry {
 
     /**
      * Rechecks if lock should be reassigned.
-     *
-     * @return Current owner.
      */
-    @Nullable public GridCacheMvccCandidate recheck() {
-        GridCacheMvccCandidate prev = null;
-        GridCacheMvccCandidate owner = null;
+    public void recheck() {
+        CacheLockCandidates prev = null;
+        CacheLockCandidates owner = null;
 
         synchronized (this) {
             GridCacheMvcc mvcc = mvccExtras();
 
             if (mvcc != null) {
-                prev = mvcc.localOwner();
+                prev = mvcc.allOwners();
 
                 owner = mvcc.recheck();
 
@@ -229,8 +224,28 @@ public class GridLocalCacheEntry extends GridCacheMapEntry {
         }
 
         checkOwnerChanged(prev, owner);
+    }
+
+    /**
+     * @param prev Previous owners.
+     * @param owner Current owners.
+     */
+    private void checkOwnerChanged(@Nullable CacheLockCandidates prev, @Nullable CacheLockCandidates owner) {
+        assert !Thread.holdsLock(this);
+
+        if (owner != null) {
+            for (int i = 0; i < owner.size(); i++) {
+                GridCacheMvccCandidate cand = owner.candidate(i);
+
+                boolean locked = prev == null || !prev.hasCandidate(cand.version());
 
-        return owner;
+                if (locked) {
+                    cctx.mvcc().callback().onOwnerChanged(this, cand);
+
+                    checkThreadChain(cand);
+                }
+            }
+        }
     }
 
     /**
@@ -241,7 +256,7 @@ public class GridLocalCacheEntry extends GridCacheMapEntry {
         assert !Thread.holdsLock(this);
 
         if (owner != prev) {
-            cctx.mvcc().callback().onOwnerChanged(this, prev, owner);
+            cctx.mvcc().callback().onOwnerChanged(this, owner);
 
             if (owner != null)
                 checkThreadChain(owner);
@@ -300,62 +315,43 @@ public class GridLocalCacheEntry extends GridCacheMapEntry {
      *
      * @param threadId Thread ID.
      */
-    void releaseLocal(long threadId) {
-        GridCacheMvccCandidate prev = null;
-        GridCacheMvccCandidate owner = null;
-
-        CacheObject val;
-        boolean hasVal;
+    private void releaseLocal(long threadId) {
+        CacheLockCandidates prev = null;
+        CacheLockCandidates owner = null;
 
         synchronized (this) {
             GridCacheMvcc mvcc = mvccExtras();
 
             if (mvcc != null) {
-                prev = mvcc.localOwner();
+                prev = mvcc.localOwners();
 
-                owner = mvcc.releaseLocal(threadId);
+                mvcc.releaseLocal(threadId);
 
                 if (mvcc.isEmpty())
                     mvccExtras(null);
+                else
+                    owner = mvcc.allOwners();
             }
-
-            val = this.val;
-            hasVal = hasValueUnlocked();
         }
 
-        if (prev != null && owner != prev) {
-            checkThreadChain(prev);
+        if (prev != null) {
+            for (int i = 0; i < prev.size(); i++) {
+                GridCacheMvccCandidate cand = prev.candidate(i);
 
-            // Event notification.
-            if (cctx.events().isRecordable(EVT_CACHE_OBJECT_UNLOCKED))
-                cctx.events().addEvent(partition(), key, prev.nodeId(), prev, EVT_CACHE_OBJECT_UNLOCKED, val, hasVal,
-                    val, hasVal, null, null, null, true);
+                checkThreadChain(cand);
+            }
         }
 
         checkOwnerChanged(prev, owner);
     }
 
-    /**
-     * Removes candidate regardless if it is owner or not.
-     *
-     * @param cand Candidate to remove.
-     * @throws GridCacheEntryRemovedException If the entry was removed by version other
-     *      than one passed in.
-     */
-    void removeLock(GridCacheMvccCandidate cand) throws GridCacheEntryRemovedException {
-        removeLock(cand.version());
-    }
-
     /** {@inheritDoc} */
     @Override public boolean removeLock(GridCacheVersion ver) throws GridCacheEntryRemovedException {
-        GridCacheMvccCandidate prev = null;
-        GridCacheMvccCandidate owner = null;
+        CacheLockCandidates prev = null;
+        CacheLockCandidates owner = null;
 
         GridCacheMvccCandidate doomed;
 
-        CacheObject val;
-        boolean hasVal;
-
         synchronized (this) {
             GridCacheVersion obsoleteVer = obsoleteVersionExtras();
 
@@ -367,27 +363,20 @@ public class GridLocalCacheEntry extends GridCacheMapEntry {
             doomed = mvcc == null ? null : mvcc.candidate(ver);
 
             if (doomed != null) {
-                prev = mvcc.localOwner();
+                prev = mvcc.allOwners();
 
-                owner = mvcc.remove(ver);
+                mvcc.remove(ver);
 
                 if (mvcc.isEmpty())
                     mvccExtras(null);
+                else
+                    owner = mvcc.allOwners();
             }
-
-            val = this.val;
-            hasVal = hasValueUnlocked();
         }
 
-        if (doomed != null) {
+        if (doomed != null)
             checkThreadChain(doomed);
 
-            // Event notification.
-            if (cctx.events().isRecordable(EVT_CACHE_OBJECT_UNLOCKED))
-                cctx.events().addEvent(partition(), key, doomed.nodeId(), doomed, EVT_CACHE_OBJECT_UNLOCKED,
-                    val, hasVal, val, hasVal, null, null, null, true);
-        }
-
         checkOwnerChanged(prev, owner);
 
         return doomed != null;

http://git-wip-us.apache.org/repos/asf/ignite/blob/36e98d6a/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 faadf27..a4fb367 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
@@ -1615,7 +1615,9 @@ public class IgniteTxManager extends GridCacheSharedManagerAdapter {
 
                     assert serReadVer == null || (tx.optimistic() && tx.serializable()) : txEntry1;
 
-                    if (!entry1.tmLock(tx, timeout, serOrder, serReadVer, txEntry1.op() == READ)) {
+                    boolean read = serReadVer != null && txEntry1.op() == READ;
+
+                    if (!entry1.tmLock(tx, timeout, serOrder, serReadVer, read)) {
                         // Unlock locks locked so far.
                         for (IgniteTxEntry txEntry2 : entries) {
                             if (txEntry2 == txEntry1)

http://git-wip-us.apache.org/repos/asf/ignite/blob/36e98d6a/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 f00eae8..11a91b5 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
@@ -601,7 +601,7 @@ public class GridCacheMvccPartitionedSelfTest extends GridCommonAbstractTest {
     /**
      * @throws Exception If failed.
      */
-    public void testSerializableReadLocks() throws Exception {
+    public void testSerializableReadLocksAdd() throws Exception {
         GridCacheAdapter<String, String> cache = grid.internalCache();
 
         GridCacheVersion serOrder1 = new GridCacheVersion(0, 0, 10, 1);
@@ -676,6 +676,117 @@ public class GridCacheMvccPartitionedSelfTest extends GridCommonAbstractTest {
     }
 
     /**
+     * @throws Exception If failed.
+     */
+    public void testSerializableReadLocksAssign() throws Exception {
+        GridCacheAdapter<String, String> cache = grid.internalCache();
+
+        GridCacheVersion serOrder1 = new GridCacheVersion(0, 0, 10, 1);
+        GridCacheVersion serOrder2 = new GridCacheVersion(0, 0, 20, 1);
+        GridCacheVersion serOrder3 = new GridCacheVersion(0, 0, 15, 1);
+
+        {
+            GridCacheMvcc mvcc = new GridCacheMvcc(cache.context());
+
+            GridCacheTestEntryEx e = new GridCacheTestEntryEx(cache.context(), "1");
+
+            GridCacheMvccCandidate cand1 = addLocal(mvcc, e, version(1), serOrder1, true);
+
+            assertNotNull(cand1);
+
+            GridCacheMvccCandidate cand2 = addLocal(mvcc, e, version(2), serOrder2, true);
+
+            assertNotNull(cand2);
+
+            GridCacheMvccCandidate cand3 = addLocal(mvcc, e, version(3), serOrder3, false);
+
+            assertNull(cand3);
+
+            cand3 = addLocal(mvcc, e, version(3), serOrder3, true);
+
+            assertNotNull(cand3);
+
+            CacheLockCandidates owners = mvcc.recheck();
+
+            assertNull(owners);
+
+            cand1.setReady();
+
+            owners = mvcc.recheck();
+
+            assertSame(cand1, owners);
+            checkCandidates(owners, cand1.version());
+
+            cand2.setReady();
+
+            owners = mvcc.recheck();
+            checkCandidates(owners, cand1.version(), cand2.version());
+
+            mvcc.remove(cand1.version());
+
+            owners = mvcc.recheck();
+            assertSame(cand2, owners);
+            checkCandidates(owners, cand2.version());
+        }
+
+        {
+            GridCacheMvcc mvcc = new GridCacheMvcc(cache.context());
+
+            GridCacheTestEntryEx e = new GridCacheTestEntryEx(cache.context(), "1");
+
+            GridCacheMvccCandidate cand1 = addLocal(mvcc, e, version(1), serOrder1, true);
+
+            assertNotNull(cand1);
+
+            GridCacheMvccCandidate cand2 = addLocal(mvcc, e, version(2), serOrder2, true);
+
+            assertNotNull(cand2);
+
+            GridCacheMvccCandidate cand3 = addLocal(mvcc, e, version(3), serOrder3, false);
+
+            assertNull(cand3);
+
+            cand3 = addLocal(mvcc, e, version(3), serOrder3, true);
+
+            assertNotNull(cand3);
+
+            CacheLockCandidates owners = mvcc.recheck();
+
+            assertNull(owners);
+
+            cand2.setReady();
+
+            owners = mvcc.recheck();
+
+            assertSame(cand2, owners);
+            checkCandidates(owners, cand2.version());
+
+            cand1.setReady();
+
+            owners = mvcc.recheck();
+            checkCandidates(owners, cand1.version(), cand2.version());
+
+            mvcc.remove(cand2.version());
+
+            owners = mvcc.recheck();
+            assertSame(cand1, owners);
+            checkCandidates(owners, cand1.version());
+        }
+    }
+
+    /**
+     * @param all Candidates list.
+     * @param vers Expected candidates.
+     */
+    private void checkCandidates(CacheLockCandidates all, GridCacheVersion...vers) {
+        assertNotNull(all);
+        assertEquals(vers.length, all.size());
+
+        for (GridCacheVersion ver : vers)
+            assertTrue(all.hasCandidate(ver));
+    }
+
+    /**
      * @param mvcc Mvcc.
      * @param e Entry.
      * @param ver Version.
@@ -846,31 +957,31 @@ public class GridCacheMvccPartitionedSelfTest extends GridCommonAbstractTest {
 
         assertNotNull(cand4);
 
-        GridCacheMvccCandidate owner = mvcc.recheck();
+        CacheLockCandidates owners = mvcc.recheck();
 
-        assertNull(owner);
+        assertNull(owners);
 
         cand2.setReady();
 
-        owner = mvcc.recheck();
+        owners = mvcc.recheck();
 
-        assertNull(owner);
+        assertNull(owners);
 
         cand1.setReady();
 
-        owner = mvcc.recheck();
+        owners = mvcc.recheck();
 
-        assertSame(cand1, owner);
+        assertSame(cand1, owners);
 
-        owner = mvcc.recheck();
+        owners = mvcc.recheck();
 
-        assertSame(cand1, owner);
+        assertSame(cand1, owners);
 
         mvcc.remove(cand1.version());
 
-        owner = mvcc.recheck();
+        owners = mvcc.recheck();
 
-        assertSame(cand2, owner);
+        assertSame(cand2, owners);
     }
 
     /**

http://git-wip-us.apache.org/repos/asf/ignite/blob/36e98d6a/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 4a883d4..48621af 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
@@ -64,24 +64,12 @@ public class GridCacheTestEntryEx extends GridMetadataAwareAdapter implements Gr
      * @param ctx Context.
      * @param key Key.
      */
-    public GridCacheTestEntryEx(GridCacheContext ctx, Object key) {
+    GridCacheTestEntryEx(GridCacheContext ctx, Object key) {
         mvcc = new GridCacheMvcc(ctx);
 
         this.key = ctx.toCacheKeyObject(key);
     }
 
-    /**
-     * @param ctx Context.
-     * @param key Key.
-     * @param val Value.
-     */
-    public GridCacheTestEntryEx(GridCacheContext ctx, Object key, Object val) {
-        mvcc = new GridCacheMvcc(ctx);
-
-        this.key = ctx.toCacheKeyObject(key);
-        this.val = ctx.toCacheObject(val);
-    }
-
     /** {@inheritDoc} */
     @Override public int memorySize() throws IgniteCheckedException {
         return 1024;
@@ -146,7 +134,7 @@ public class GridCacheTestEntryEx extends GridMetadataAwareAdapter implements Gr
      * @return New lock candidate if lock was added, or current owner if lock was reentered,
      *      or <tt>null</tt> if lock was owned by another thread and timeout is negative.
      */
-    @Nullable public GridCacheMvccCandidate addLocal(
+    @Nullable GridCacheMvccCandidate addLocal(
         long threadId,
         GridCacheVersion ver,
         long timeout,
@@ -159,6 +147,7 @@ public class GridCacheTestEntryEx extends GridMetadataAwareAdapter implements Gr
             timeout,
             reenter,
             tx,
+            false,
             false
         );
     }
@@ -173,7 +162,7 @@ public class GridCacheTestEntryEx extends GridMetadataAwareAdapter implements Gr
      * @param tx Transaction flag.
      * @return Remote candidate.
      */
-    public GridCacheMvccCandidate addRemote(UUID nodeId, long threadId, GridCacheVersion ver,
+    GridCacheMvccCandidate addRemote(UUID nodeId, long threadId, GridCacheVersion ver,
         boolean ec, boolean tx) {
         return mvcc.addRemote(this, nodeId, null, threadId, ver, tx, true, false);
     }
@@ -187,16 +176,16 @@ public class GridCacheTestEntryEx extends GridMetadataAwareAdapter implements Gr
      * @param tx Transaction flag.
      * @return Remote candidate.
      */
-    public GridCacheMvccCandidate addNearLocal(UUID nodeId, long threadId, GridCacheVersion ver,
+    GridCacheMvccCandidate addNearLocal(UUID nodeId, long threadId, GridCacheVersion ver,
         boolean tx) {
-        return mvcc.addNearLocal(this, nodeId, null, threadId, ver, tx, true);
+        return mvcc.addNearLocal(this, nodeId, null, threadId, ver, tx, true, false);
     }
 
     /**
      *
      * @param baseVer Base version.
      */
-    public void salvageRemote(GridCacheVersion baseVer) {
+    void salvageRemote(GridCacheVersion baseVer) {
         mvcc.salvageRemote(baseVer);
     }
 
@@ -208,17 +197,16 @@ public class GridCacheTestEntryEx extends GridMetadataAwareAdapter implements Gr
      * @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,
+    void orderCompleted(GridCacheVersion baseVer,
         Collection<GridCacheVersion> committedVers, Collection<GridCacheVersion> rolledbackVers) {
-        return mvcc.orderCompleted(baseVer, committedVers, rolledbackVers);
+        mvcc.orderCompleted(baseVer, committedVers, rolledbackVers);
     }
 
     /**
      * @param ver Version.
      */
-    public void doneRemote(GridCacheVersion ver) {
+    void doneRemote(GridCacheVersion ver) {
         mvcc.doneRemote(ver, Collections.<GridCacheVersion>emptyList(),
             Collections.<GridCacheVersion>emptyList(), Collections.<GridCacheVersion>emptyList());
     }
@@ -227,16 +215,15 @@ public class GridCacheTestEntryEx extends GridMetadataAwareAdapter implements Gr
      * @param baseVer Base version.
      * @param owned Owned.
      */
-    public void orderOwned(GridCacheVersion baseVer, GridCacheVersion owned) {
+    void orderOwned(GridCacheVersion baseVer, GridCacheVersion owned) {
         mvcc.markOwned(baseVer, owned);
     }
 
     /**
      * @param ver Lock version to acquire or set to ready.
-     * @return Current owner.
      */
-    @Nullable public GridCacheMvccCandidate readyLocal(GridCacheVersion ver) {
-        return mvcc.readyLocal(ver);
+    void readyLocal(GridCacheVersion ver) {
+        mvcc.readyLocal(ver);
     }
 
     /**
@@ -245,44 +232,33 @@ public class GridCacheTestEntryEx extends GridMetadataAwareAdapter implements Gr
      * @param committedVers Committed versions.
      * @param rolledbackVers Rolled back versions.
      * @param pending Pending versions.
-     * @return Lock owner.
      */
-    @Nullable public GridCacheMvccCandidate readyNearLocal(GridCacheVersion ver, GridCacheVersion mapped,
+    void readyNearLocal(GridCacheVersion ver, GridCacheVersion mapped,
         Collection<GridCacheVersion> committedVers, Collection<GridCacheVersion> rolledbackVers,
         Collection<GridCacheVersion> pending) {
-        return mvcc.readyNearLocal(ver, mapped, committedVers, rolledbackVers, pending);
+        mvcc.readyNearLocal(ver, mapped, committedVers, rolledbackVers, pending);
     }
 
     /**
      * @param cand Candidate to set to ready.
-     * @return Current owner.
-     */
-    @Nullable public GridCacheMvccCandidate readyLocal(GridCacheMvccCandidate cand) {
-        return mvcc.readyLocal(cand);
-    }
-
-    /**
-     * Local local release.
-     * @return Removed lock candidate or <tt>null</tt> if candidate was not removed.
      */
-    @Nullable public GridCacheMvccCandidate releaseLocal() {
-        return releaseLocal(Thread.currentThread().getId());
+    void readyLocal(GridCacheMvccCandidate cand) {
+        mvcc.readyLocal(cand);
     }
 
     /**
      * Local release.
      *
      * @param threadId ID of the thread.
-     * @return Current owner.
      */
-    @Nullable public GridCacheMvccCandidate releaseLocal(long threadId) {
-        return mvcc.releaseLocal(threadId);
+    void releaseLocal(long threadId) {
+        mvcc.releaseLocal(threadId);
     }
 
     /**
      *
      */
-    public void recheckLock() {
+    void recheckLock() {
         mvcc.recheck();
     }
 
@@ -764,7 +740,7 @@ public class GridCacheTestEntryEx extends GridMetadataAwareAdapter implements Gr
     }
 
     /** @inheritDoc */
-    public Collection<GridCacheMvccCandidate> localCandidates(boolean reentries, GridCacheVersion... exclude) {
+    Collection<GridCacheMvccCandidate> localCandidates(boolean reentries, GridCacheVersion... exclude) {
         return mvcc.localCandidates(reentries, exclude);
     }
 
@@ -792,7 +768,7 @@ public class GridCacheTestEntryEx extends GridMetadataAwareAdapter implements Gr
     /**
      * @return Any MVCC owner.
      */
-    public GridCacheMvccCandidate anyOwner() {
+    GridCacheMvccCandidate anyOwner() {
         return mvcc.anyOwner();
     }
 


Mime
View raw message