ignite-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From sboi...@apache.org
Subject [18/19] ignite git commit: ignite-4285 For serializable txs allow multiple threads to get read lock for the same key
Date Fri, 02 Dec 2016 09:25:24 GMT
ignite-4285 For serializable txs allow multiple threads to get read lock for the same key


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

Branch: refs/heads/master
Commit: 33dda46061aae73e5c138851cfdd5f49a1c254cb
Parents: 12bdd6a
Author: sboikov <sboikov@gridgain.com>
Authored: Fri Dec 2 12:13:38 2016 +0300
Committer: sboikov <sboikov@gridgain.com>
Committed: Fri Dec 2 12:15:14 2016 +0300

----------------------------------------------------------------------
 .../processors/cache/CacheLockCandidates.java   |  42 ++
 .../cache/CacheLockCandidatesList.java          |  71 +++
 .../processors/cache/GridCacheEntryEx.java      |   3 +-
 .../processors/cache/GridCacheMapEntry.java     | 117 +++-
 .../processors/cache/GridCacheMvcc.java         | 376 ++++++++----
 .../processors/cache/GridCacheMvccCallback.java |   4 +-
 .../cache/GridCacheMvccCandidate.java           |  80 ++-
 .../processors/cache/GridCacheMvccManager.java  |  19 +-
 .../distributed/GridDistributedCacheEntry.java  | 303 +++-------
 .../distributed/dht/GridDhtCacheEntry.java      |  32 +-
 .../distributed/dht/GridDhtLockFuture.java      |  34 +-
 .../dht/GridDhtTransactionalCacheAdapter.java   |   1 -
 .../distributed/dht/GridDhtTxPrepareFuture.java |   5 +-
 .../colocated/GridDhtColocatedLockFuture.java   |   8 +-
 .../distributed/near/GridNearCacheEntry.java    |  44 +-
 .../distributed/near/GridNearLockFuture.java    |   3 +-
 .../near/GridNearTransactionalCache.java        |   5 +-
 .../cache/local/GridLocalCacheEntry.java        | 173 ++----
 .../cache/local/GridLocalLockFuture.java        |   2 +-
 .../cache/transactions/IgniteTxManager.java     |   6 +-
 .../CacheSerializableTransactionsTest.java      | 604 ++++++++++++++++++-
 .../cache/GridCacheMvccFlagsTest.java           |   8 +-
 .../cache/GridCacheMvccPartitionedSelfTest.java | 334 ++++++++--
 .../processors/cache/GridCacheMvccSelfTest.java | 212 +++----
 .../processors/cache/GridCacheTestEntryEx.java  |  77 +--
 .../loadtests/hashmap/GridHashMapLoadTest.java  |   7 +-
 26 files changed, 1721 insertions(+), 849 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ignite/blob/33dda460/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..9cf16f4
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheLockCandidates.java
@@ -0,0 +1,42 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.processors.cache;
+
+import org.apache.ignite.internal.processors.cache.version.GridCacheVersion;
+
+/**
+ *
+ */
+public interface CacheLockCandidates {
+    /**
+     * @param idx Candidate index.
+     * @return Candidate.
+     */
+    public GridCacheMvccCandidate candidate(int idx);
+
+    /**
+     * @return Number of candidates.
+     */
+    public int size();
+
+    /**
+     * @param ver Candidate version.
+     * @return {@code True} if contains candidate with given version.
+     */
+    public boolean hasCandidate(GridCacheVersion ver);
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/33dda460/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..e026bce
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheLockCandidatesList.java
@@ -0,0 +1,71 @@
+/*
+ * 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()) : cand;
+
+        list.add(cand);
+    }
+
+    /** {@inheritDoc} */
+    @Override public GridCacheMvccCandidate candidate(int idx) {
+        assert idx < list.size() : 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/33dda460/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheEntryEx.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheEntryEx.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheEntryEx.java
index 176fe77..d8194fc 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheEntryEx.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheEntryEx.java
@@ -565,6 +565,7 @@ public interface GridCacheEntryEx {
      * @param timeout Timeout for lock acquisition.
      * @param serOrder Version for serializable transactions ordering.
      * @param serReadVer Optional read entry version for optimistic serializable transaction.
+     * @param read Read lock flag.
      * @return {@code True} if lock was acquired, {@code false} otherwise.
      * @throws GridCacheEntryRemovedException If this entry is obsolete.
      * @throws GridDistributedLockCancelledException If lock has been cancelled.
@@ -573,7 +574,7 @@ public interface GridCacheEntryEx {
         long timeout,
         @Nullable GridCacheVersion serOrder,
         @Nullable GridCacheVersion serReadVer,
-        boolean keepBinary
+        boolean read
     ) throws GridCacheEntryRemovedException, GridDistributedLockCancelledException;
 
     /**

http://git-wip-us.apache.org/repos/asf/ignite/blob/33dda460/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..31baeda 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
@@ -79,9 +79,11 @@ import org.apache.ignite.lang.IgniteUuid;
 import org.jetbrains.annotations.Nullable;
 
 import static org.apache.ignite.events.EventType.EVT_CACHE_OBJECT_EXPIRED;
+import static org.apache.ignite.events.EventType.EVT_CACHE_OBJECT_LOCKED;
 import static org.apache.ignite.events.EventType.EVT_CACHE_OBJECT_PUT;
 import static org.apache.ignite.events.EventType.EVT_CACHE_OBJECT_READ;
 import static org.apache.ignite.events.EventType.EVT_CACHE_OBJECT_REMOVED;
+import static org.apache.ignite.events.EventType.EVT_CACHE_OBJECT_UNLOCKED;
 import static org.apache.ignite.internal.processors.cache.GridCacheOperation.DELETE;
 import static org.apache.ignite.internal.processors.dr.GridDrType.DR_NONE;
 
@@ -827,8 +829,6 @@ public abstract class GridCacheMapEntry extends GridMetadataAwareAdapter impleme
         if (readThrough && !cctx.readThrough())
             readThrough = false;
 
-        GridCacheMvccCandidate owner;
-
         CacheObject ret;
 
         GridCacheVersion startVer;
@@ -841,10 +841,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 +895,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 +1008,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,
@@ -3391,14 +3391,14 @@ public abstract class GridCacheMapEntry extends GridMetadataAwareAdapter impleme
     }
 
     /** {@inheritDoc} */
-    @Override public synchronized boolean hasValue() {
+    @Override public final synchronized boolean hasValue() {
         return hasValueUnlocked();
     }
 
     /**
      * @return {@code True} if this entry has value.
      */
-    protected boolean hasValueUnlocked() {
+    protected final boolean hasValueUnlocked() {
         assert Thread.holdsLock(this);
 
         return val != null || hasOffHeapPointer();
@@ -4318,7 +4318,7 @@ public abstract class GridCacheMapEntry extends GridMetadataAwareAdapter impleme
     }
 
     /** {@inheritDoc} */
-    @Override public GridCacheBatchSwapEntry evictInBatchInternal(GridCacheVersion obsoleteVer)
+    @Override public final GridCacheBatchSwapEntry evictInBatchInternal(GridCacheVersion obsoleteVer)
         throws IgniteCheckedException {
         assert Thread.holdsLock(this);
         assert cctx.isSwapOrOffheapEnabled();
@@ -4385,7 +4385,7 @@ public abstract class GridCacheMapEntry extends GridMetadataAwareAdapter impleme
      * @param filter Entry filter.
      * @return {@code True} if entry is visitable.
      */
-    public boolean visitable(CacheEntryPredicate[] filter) {
+    public final boolean visitable(CacheEntryPredicate[] filter) {
         boolean rmv = false;
 
         try {
@@ -4440,7 +4440,7 @@ public abstract class GridCacheMapEntry extends GridMetadataAwareAdapter impleme
     }
 
     /** {@inheritDoc} */
-    @Override public boolean deleted() {
+    @Override public final boolean deleted() {
         if (!cctx.deferredDelete())
             return false;
 
@@ -4450,7 +4450,7 @@ public abstract class GridCacheMapEntry extends GridMetadataAwareAdapter impleme
     }
 
     /** {@inheritDoc} */
-    @Override public synchronized boolean obsoleteOrDeleted() {
+    @Override public final synchronized boolean obsoleteOrDeleted() {
         return obsoleteVersionExtras() != null ||
             (cctx.deferredDelete() && (deletedUnlocked() || !hasValueUnlocked()));
     }
@@ -4459,7 +4459,7 @@ public abstract class GridCacheMapEntry extends GridMetadataAwareAdapter impleme
      * @return {@code True} if deleted.
      */
     @SuppressWarnings("SimplifiableIfStatement")
-    protected boolean deletedUnlocked() {
+    protected final boolean deletedUnlocked() {
         assert Thread.holdsLock(this);
 
         if (!cctx.deferredDelete())
@@ -4471,7 +4471,7 @@ public abstract class GridCacheMapEntry extends GridMetadataAwareAdapter impleme
     /**
      * @param deleted {@code True} if deleted.
      */
-    protected void deletedUnlocked(boolean deleted) {
+    protected final void deletedUnlocked(boolean deleted) {
         assert Thread.holdsLock(this);
         assert cctx.deferredDelete();
 
@@ -4508,7 +4508,7 @@ public abstract class GridCacheMapEntry extends GridMetadataAwareAdapter impleme
     /**
      * @return MVCC.
      */
-    @Nullable protected GridCacheMvcc mvccExtras() {
+    @Nullable protected final GridCacheMvcc mvccExtras() {
         return extras != null ? extras.mvcc() : null;
     }
 
@@ -4516,7 +4516,7 @@ public abstract class GridCacheMapEntry extends GridMetadataAwareAdapter impleme
      * @return All MVCC local and non near candidates.
      */
     @SuppressWarnings("ForLoopReplaceableByForEach")
-    @Nullable public synchronized List<GridCacheMvccCandidate> mvccAllLocal() {
+    @Nullable public final synchronized List<GridCacheMvccCandidate> mvccAllLocal() {
         GridCacheMvcc mvcc = extras != null ? extras.mvcc() : null;
 
         if (mvcc == null)
@@ -4542,21 +4542,22 @@ public abstract class GridCacheMapEntry extends GridMetadataAwareAdapter impleme
     /**
      * @param mvcc MVCC.
      */
-    protected void mvccExtras(@Nullable GridCacheMvcc mvcc) {
+    protected final void mvccExtras(@Nullable GridCacheMvcc mvcc) {
         extras = (extras != null) ? extras.mvcc(mvcc) : mvcc != null ? new GridCacheMvccEntryExtras(mvcc) : null;
     }
 
     /**
      * @return Obsolete version.
      */
-    @Nullable protected GridCacheVersion obsoleteVersionExtras() {
+    @Nullable protected final GridCacheVersion obsoleteVersionExtras() {
         return extras != null ? extras.obsoleteVersion() : null;
     }
 
     /**
      * @param obsoleteVer Obsolete version.
+     * @param ext Extras.
      */
-    protected void obsoleteVersionExtras(@Nullable GridCacheVersion obsoleteVer, GridCacheObsoleteEntryExtras ext) {
+    private void obsoleteVersionExtras(@Nullable GridCacheVersion obsoleteVer, GridCacheObsoleteEntryExtras ext) {
         extras = (extras != null) ?
             extras.obsoleteVersion(obsoleteVer) :
             obsoleteVer != null ?
@@ -4565,6 +4566,80 @@ public abstract class GridCacheMapEntry extends GridMetadataAwareAdapter impleme
     }
 
     /**
+     * @param prevOwners Previous owners.
+     * @param owners Current owners.
+     * @param val Entry value.
+     */
+    protected final void checkOwnerChanged(@Nullable CacheLockCandidates prevOwners,
+        @Nullable CacheLockCandidates owners,
+        CacheObject val) {
+        assert !Thread.holdsLock(this);
+
+        if (prevOwners != null && owners == null) {
+            cctx.mvcc().callback().onOwnerChanged(this, null);
+
+            if (cctx.events().isRecordable(EVT_CACHE_OBJECT_UNLOCKED)) {
+                boolean hasVal = hasValue();
+
+                GridCacheMvccCandidate cand = prevOwners.candidate(0);
+
+                cctx.events().addEvent(partition(),
+                    key,
+                    cand.nodeId(),
+                    cand,
+                    EVT_CACHE_OBJECT_UNLOCKED,
+                    val,
+                    hasVal,
+                    val,
+                    hasVal,
+                    null,
+                    null,
+                    null,
+                    true);
+            }
+        }
+
+        if (owners != null) {
+            for (int i = 0; i < owners.size(); i++) {
+                GridCacheMvccCandidate owner = owners.candidate(i);
+
+                boolean locked = prevOwners == null || !prevOwners.hasCandidate(owner.version());
+
+                if (locked) {
+                    cctx.mvcc().callback().onOwnerChanged(this, owner);
+
+                    if (owner.local())
+                        checkThreadChain(owner);
+
+                    if (cctx.events().isRecordable(EVT_CACHE_OBJECT_LOCKED)) {
+                        boolean hasVal = hasValue();
+
+                        // Event notification.
+                        cctx.events().addEvent(partition(),
+                            key,
+                            owner.nodeId(),
+                            owner,
+                            EVT_CACHE_OBJECT_LOCKED,
+                            val,
+                            hasVal,
+                            val,
+                            hasVal,
+                            null,
+                            null,
+                            null,
+                            true);
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * @param owner Starting candidate in the chain.
+     */
+    protected abstract void checkThreadChain(GridCacheMvccCandidate owner);
+
+    /**
      * Updates metrics.
      *
      * @param op Operation.

http://git-wip-us.apache.org/repos/asf/ignite/blob/33dda460/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 507a2c9..498584c 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,10 +145,58 @@ public final class GridCacheMvcc {
     }
 
     /**
+     * @return All local owners.
+     */
+    @Nullable public CacheLockCandidates localOwners() {
+        if (locs != null) {
+            assert !locs.isEmpty();
+
+            CacheLockCandidates owners = null;
+
+            GridCacheMvccCandidate first = locs.getFirst();
+
+            if (first.read()) {
+                for (GridCacheMvccCandidate cand : locs) {
+                    if (cand.owner()) {
+                        assert cand.read() : this;
+
+                        if (owners != null) {
+                            CacheLockCandidatesList list;
+
+                            if (owners.size() == 1) {
+                                GridCacheMvccCandidate owner = owners.candidate(0);
+
+                                owners = list = new CacheLockCandidatesList();
+
+                                ((CacheLockCandidatesList)owners).add(owner);
+                            }
+                            else
+                                list = ((CacheLockCandidatesList)owners);
+
+                            list.add(cand);
+                        }
+                        else
+                            owners = cand;
+                    }
+
+                    if (!cand.read())
+                        break;
+                }
+            }
+            else if (first.owner())
+                owners = first;
+
+            return owners;
+        }
+
+        return null;
+    }
+
+    /**
      * @return Local candidate only if it's first in the list and is marked
      *      as <tt>'owner'</tt>.
      */
-    @Nullable public GridCacheMvccCandidate localOwner() {
+    @Nullable GridCacheMvccCandidate localOwner() {
         if (locs != null) {
             assert !locs.isEmpty();
 
@@ -186,6 +246,29 @@ public final class GridCacheMvcc {
     }
 
     /**
+     * @param cand Existing candidate.
+     * @param newCand New candidate.
+     * @return {@code False} if new candidate can not be added.
+     */
+    private boolean compareSerializableVersion(GridCacheMvccCandidate cand, GridCacheMvccCandidate newCand) {
+        assert cand.serializable() && newCand.serializable();
+
+        GridCacheVersion candOrder = cand.serializableOrder();
+
+        assert candOrder != null : cand;
+
+        GridCacheVersion newCandOrder = newCand.serializableOrder();
+
+        assert newCandOrder != null : newCand;
+
+        int cmp = SER_VER_COMPARATOR.compare(candOrder, newCandOrder);
+
+        assert cmp != 0;
+
+        return cmp < 0;
+    }
+
+    /**
      * @param cand Candidate to add.
      * @return {@code False} if failed to add candidate and transaction should be cancelled.
      */
@@ -200,25 +283,34 @@ public final class GridCacheMvcc {
             if (!cand.nearLocal()) {
                 if (!locs.isEmpty()) {
                     if (cand.serializable()) {
-                        GridCacheMvccCandidate last = locs.getLast();
-
-                        if (!last.serializable())
-                            return false;
-
-                        GridCacheVersion lastOrder = last.serializableOrder();
+                        Iterator<GridCacheMvccCandidate> it = locs.descendingIterator();
 
-                        assert lastOrder != null : last;
+                        if (cand.read()) {
+                            while (it.hasNext()) {
+                                GridCacheMvccCandidate c = it.next();
 
-                        GridCacheVersion candOrder = cand.serializableOrder();
+                                if (!c.serializable())
+                                    return false;
 
-                        assert candOrder != null : cand;
-
-                        int cmp = SER_VER_COMPARATOR.compare(lastOrder, candOrder);
+                                if (!c.read()) {
+                                    if (compareSerializableVersion(c, cand))
+                                        break;
+                                    else
+                                        return false;
+                                }
+                            }
+                        }
+                        else {
+                            while (it.hasNext()) {
+                                GridCacheMvccCandidate c = it.next();
 
-                        assert cmp != 0;
+                                if (!c.serializable() || !compareSerializableVersion(c, cand))
+                                    return false;
 
-                        if (cmp > 0)
-                            return false;
+                                if (!c.read())
+                                    break;
+                            }
+                        }
 
                         locs.addLast(cand);
 
@@ -284,12 +376,12 @@ public final class GridCacheMvcc {
         }
         // Remote.
         else {
-            assert !cand.serializable() : cand;
+            assert !cand.serializable() && !cand.read() : cand;
 
             if (rmts == null)
                 rmts = new LinkedList<>();
 
-            assert !cand.owner() || localOwner() == null : "Cannot have local and remote owners " +
+            assert !cand.owner() || localOwners() == null : "Cannot have local and remote owners " +
                 "at the same time [cand=" + cand + ", locs=" + locs + ", rmts=" + rmts + ']';
 
             GridCacheMvccCandidate cur = candidate(rmts, cand.version());
@@ -398,9 +490,8 @@ public final class GridCacheMvcc {
      * @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,
+    public void orderCompleted(GridCacheVersion baseVer,
         Collection<GridCacheVersion> committedVers, Collection<GridCacheVersion> rolledbackVers) {
         assert baseVer != null;
 
@@ -415,10 +506,13 @@ public final class GridCacheMvcc {
                 if (!cur.version().equals(baseVer) && committedVers.contains(cur.version())) {
                     cur.setOwner();
 
-                    assert localOwner() == null || localOwner().nearLocal(): "Cannot not have local owner and " +
+                    assert localOwners() == null || localOwner().nearLocal(): "Cannot not have local owner and " +
                         "remote completed transactions at the same time [baseVer=" + baseVer +
-                        ", committedVers=" + committedVers + ", rolledbackVers=" + rolledbackVers +
-                        ", localOwner=" + localOwner() + ", locs=" + locs + ", rmts=" + rmts + ']';
+                        ", committedVers=" + committedVers +
+                        ", rolledbackVers=" + rolledbackVers +
+                        ", localOwner=" + localOwner() +
+                        ", locs=" + locs +
+                        ", rmts=" + rmts + ']';
 
                     if (maxIdx < 0)
                         maxIdx = it.nextIndex();
@@ -462,8 +556,6 @@ public final class GridCacheMvcc {
                     rmts = null;
             }
         }
-
-        return anyOwner();
     }
 
     /**
@@ -471,11 +563,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);
@@ -483,8 +574,6 @@ public final class GridCacheMvcc {
             if (baseCand != null)
                 baseCand.ownerVersion(owned);
         }
-
-        return anyOwner();
     }
 
     /**
@@ -495,6 +584,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.
      */
@@ -505,7 +595,8 @@ public final class GridCacheMvcc {
         long timeout,
         boolean reenter,
         boolean tx,
-        boolean implicitSingle) {
+        boolean implicitSingle,
+        boolean read) {
         return addLocal(
             parent,
             /*nearNodeId*/null,
@@ -517,7 +608,8 @@ public final class GridCacheMvcc {
             reenter,
             tx,
             implicitSingle,
-            /*dht-local*/false
+            /*dht-local*/false,
+            /*read*/read
         );
     }
 
@@ -533,6 +625,7 @@ public final class GridCacheMvcc {
      * @param tx Transaction flag.
      * @param implicitSingle Implicit flag.
      * @param dhtLoc DHT local 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.
      */
@@ -547,7 +640,8 @@ public final class GridCacheMvcc {
         boolean reenter,
         boolean tx,
         boolean implicitSingle,
-        boolean dhtLoc) {
+        boolean dhtLoc,
+        boolean read) {
         if (log.isDebugEnabled())
             log.debug("Adding local candidate [mvcc=" + this + ", parent=" + parent + ", threadId=" + threadId +
                 ", ver=" + ver + ", timeout=" + timeout + ", reenter=" + reenter + ", tx=" + tx + "]");
@@ -582,14 +676,14 @@ public final class GridCacheMvcc {
             nearVer,
             threadId,
             ver,
-            timeout,
             /*local*/true,
             /*reenter*/false,
             tx,
             implicitSingle,
             /*near-local*/false,
             dhtLoc,
-            serOrder
+            serOrder,
+            read
         );
 
         if (serOrder == null) {
@@ -613,7 +707,6 @@ public final class GridCacheMvcc {
      * @param otherNodeId Other node ID.
      * @param threadId Thread ID.
      * @param ver Lock version.
-     * @param timeout Lock acquire timeout.
      * @param tx Transaction flag.
      * @param implicitSingle Implicit flag.
      * @param nearLoc Near local flag.
@@ -625,7 +718,6 @@ public final class GridCacheMvcc {
         @Nullable UUID otherNodeId,
         long threadId,
         GridCacheVersion ver,
-        long timeout,
         boolean tx,
         boolean implicitSingle,
         boolean nearLoc) {
@@ -636,14 +728,14 @@ public final class GridCacheMvcc {
             null,
             threadId,
             ver,
-            timeout,
             /*local*/false,
             /*reentry*/false,
             tx,
             implicitSingle,
             nearLoc,
             false,
-            null
+            null,
+            /*read*/false
         );
 
         addRemote(cand);
@@ -659,9 +751,9 @@ public final class GridCacheMvcc {
      * @param otherNodeId Other node ID.
      * @param threadId Thread ID.
      * @param ver Lock version.
-     * @param timeout Lock acquire timeout.
      * @param tx Transaction flag.
      * @param implicitSingle Implicit flag.
+     * @param read Read lock flag.
      * @return Add remote candidate.
      */
     public GridCacheMvccCandidate addNearLocal(GridCacheEntryEx parent,
@@ -669,23 +761,23 @@ public final class GridCacheMvcc {
         @Nullable UUID otherNodeId,
         long threadId,
         GridCacheVersion ver,
-        long timeout,
         boolean tx,
-        boolean implicitSingle) {
+        boolean implicitSingle,
+        boolean read) {
         GridCacheMvccCandidate cand = new GridCacheMvccCandidate(parent,
             nodeId,
             otherNodeId,
             null,
             threadId,
             ver,
-            timeout,
             /*local*/true,
             /*reentry*/false,
             tx,
             implicitSingle,
             /*near loc*/true,
             /*dht loc*/false,
-            null);
+            null,
+            /*read*/read);
 
         add0(cand);
 
@@ -695,7 +787,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())
@@ -710,11 +802,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();
 
@@ -725,14 +817,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();
     }
 
     /**
@@ -751,9 +843,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) {
@@ -785,7 +880,7 @@ public final class GridCacheMvcc {
                     if (c.owner())
                         continue;
 
-                    assert !c.ready() :
+                    assert !c.ready() || (c.read() && cand.read()):
                         "Cannot have more then one ready near-local candidate [c=" + c + ", cand=" + cand +
                             ", mvcc=" + this + ']';
 
@@ -819,7 +914,7 @@ public final class GridCacheMvcc {
             reassign();
         }
 
-        return anyOwner();
+        return allOwners();
     }
 
     /**
@@ -831,7 +926,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,
@@ -879,7 +974,7 @@ public final class GridCacheMvcc {
             }
         }
 
-        return anyOwner();
+        return allOwners();
     }
 
     /**
@@ -942,19 +1037,39 @@ public final class GridCacheMvcc {
         if (locs != null) {
             boolean first = true;
 
-            for (ListIterator<GridCacheMvccCandidate> it = locs.listIterator(); it.hasNext(); ) {
+            ListIterator<GridCacheMvccCandidate> it = locs.listIterator();
+
+            while (it.hasNext()) {
                 GridCacheMvccCandidate cand = it.next();
 
-                if (first && cand.serializable()) {
-                    if (cand.owner() || !cand.ready())
+                if (first) {
+                    if (cand.read()) {
+                        if (cand.ready() && !cand.owner())
+                            cand.setOwner();
+
+                        while (it.hasNext()) {
+                            cand = it.next();
+
+                            if (!cand.read())
+                                break;
+
+                            if (cand.ready() && !cand.owner())
+                                cand.setOwner();
+                        }
+
                         return;
+                    }
+                    else if (cand.serializable()) {
+                        if (cand.owner() || !cand.ready())
+                            return;
 
-                    cand.setOwner();
+                        cand.setOwner();
 
-                    return;
-                }
+                        return;
+                    }
 
-                first = false;
+                    first = false;
+                }
 
                 if (cand.owner())
                     return;
@@ -1036,6 +1151,8 @@ public final class GridCacheMvcc {
                     }
 
                     if (assigned) {
+                        assert !cand.serializable() : cand;
+
                         it.remove();
 
                         // Owner must be first in the list.
@@ -1066,15 +1183,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());
@@ -1084,32 +1202,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();
     }
 
     /**
@@ -1118,7 +1249,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();
@@ -1153,7 +1284,7 @@ public final class GridCacheMvcc {
 
         reassign();
 
-        return anyOwner();
+        return allOwners();
     }
 
     /**
@@ -1177,7 +1308,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);
     }
@@ -1187,7 +1318,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)
@@ -1217,7 +1348,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;
     }
 
@@ -1284,40 +1415,24 @@ 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) {
-        GridCacheMvccCandidate owner = localOwner();
-
-        return owner != null && owner.threadId() == threadId && owner.nodeId().equals(cctx.nodeId()) &&
-            (allowDhtLoc || !owner.dhtLocal()) && !U.containsObjectArray(exclude, owner.version());
-    }
+    boolean isLocallyOwnedByThread(long threadId, boolean allowDhtLoc, GridCacheVersion... exclude) {
+        CacheLockCandidates owners = localOwners();
 
-    /**
-     * @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();
+        if (owners != null) {
+            for (int i = 0; i < owners.size(); i++) {
+                GridCacheMvccCandidate owner = owners.candidate(i);
 
-        return owner != null && owner.threadId() == threadId && owner.nodeId().equals(nodeId);
-    }
+                if (owner.threadId() == threadId && owner.nodeId().equals(cctx.nodeId()) &&
+                    (allowDhtLoc || !owner.dhtLocal()) && !U.containsObjectArray(exclude, owner.version()))
+                    return true;
+            }
+        }
 
-    /**
-     * @return {@code True} if lock is owned by any thread or node.
-     */
-    public boolean isOwnedByAny() {
-        return anyOwner() != null;
+        return false;
     }
 
     /**
@@ -1325,10 +1440,10 @@ public final class GridCacheMvcc {
      * @param lockVer ID of lock candidate.
      * @return {@code True} if candidate is owner.
      */
-    public boolean isLocallyOwned(GridCacheVersion lockVer) {
-        GridCacheMvccCandidate owner = localOwner();
+    boolean isLocallyOwned(GridCacheVersion lockVer) {
+        CacheLockCandidates owners = localOwners();
 
-        return owner != null && owner.version().equals(lockVer);
+        return owners != null && owners.hasCandidate(lockVer);
     }
 
     /**
@@ -1336,30 +1451,25 @@ 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) {
-        GridCacheMvccCandidate owner = localOwner();
+    boolean isLocallyOwnedByIdOrThread(GridCacheVersion lockVer, long threadId) {
+        CacheLockCandidates owners = localOwners();
 
-        return owner != null && (owner.version().equals(lockVer) || owner.threadId() == threadId);
-    }
+        if (owners != null) {
+            for (int i = 0; i < owners.size(); i++) {
+                GridCacheMvccCandidate owner = owners.candidate(i);
 
-    /**
-     * @return First remote entry or <tt>null</tt>.
-     */
-    @Nullable public GridCacheMvccCandidate firstRemote() {
-        return rmts == null ? null : rmts.getFirst();
-    }
+                if ((owner.version().equals(lockVer) || owner.threadId() == threadId))
+                    return true;
+            }
+        }
 
-    /**
-     * @return First local entry or <tt>null</tt>.
-     */
-    @Nullable public GridCacheMvccCandidate firstLocal() {
-        return locs == null ? null : locs.getFirst();
+        return false;
     }
 
     /**
      * @return Local MVCC candidates.
      */
-    @Nullable public List<GridCacheMvccCandidate> allLocal() {
+    @Nullable List<GridCacheMvccCandidate> allLocal() {
         return locs;
     }
 
@@ -1367,10 +1477,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/33dda460/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/33dda460/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 f1c1b83..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
@@ -43,6 +43,7 @@ import static org.apache.ignite.internal.processors.cache.GridCacheMvccCandidate
 import static org.apache.ignite.internal.processors.cache.GridCacheMvccCandidate.Mask.LOCAL;
 import static org.apache.ignite.internal.processors.cache.GridCacheMvccCandidate.Mask.NEAR_LOCAL;
 import static org.apache.ignite.internal.processors.cache.GridCacheMvccCandidate.Mask.OWNER;
+import static org.apache.ignite.internal.processors.cache.GridCacheMvccCandidate.Mask.READ;
 import static org.apache.ignite.internal.processors.cache.GridCacheMvccCandidate.Mask.READY;
 import static org.apache.ignite.internal.processors.cache.GridCacheMvccCandidate.Mask.REENTRY;
 import static org.apache.ignite.internal.processors.cache.GridCacheMvccCandidate.Mask.REMOVED;
@@ -54,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;
 
@@ -69,14 +70,6 @@ public class GridCacheMvccCandidate implements Externalizable,
     @GridToStringInclude
     private GridCacheVersion ver;
 
-    /** Maximum wait time. */
-    @GridToStringInclude
-    private long timeout;
-
-    /** Candidate timestamp. */
-    @GridToStringInclude
-    private long ts;
-
     /** Thread ID. */
     @GridToStringInclude
     private long threadId;
@@ -143,7 +136,6 @@ public class GridCacheMvccCandidate implements Externalizable,
      * @param otherVer Other version.
      * @param threadId Requesting thread ID.
      * @param ver Cache version.
-     * @param timeout Maximum wait time.
      * @param loc {@code True} if the lock is local.
      * @param reentry {@code True} if candidate is for reentry.
      * @param tx Transaction flag.
@@ -151,6 +143,7 @@ public class GridCacheMvccCandidate implements Externalizable,
      * @param nearLoc Near-local flag.
      * @param dhtLoc DHT local flag.
      * @param serOrder Version for serializable transactions ordering.
+     * @param read Read lock flag.
      */
     public GridCacheMvccCandidate(
         GridCacheEntryEx parent,
@@ -159,14 +152,14 @@ public class GridCacheMvccCandidate implements Externalizable,
         @Nullable GridCacheVersion otherVer,
         long threadId,
         GridCacheVersion ver,
-        long timeout,
         boolean loc,
         boolean reentry,
         boolean tx,
         boolean singleImplicit,
         boolean nearLoc,
         boolean dhtLoc,
-        @Nullable GridCacheVersion serOrder
+        @Nullable GridCacheVersion serOrder,
+        boolean read
     ) {
         assert nodeId != null;
         assert ver != null;
@@ -178,7 +171,6 @@ public class GridCacheMvccCandidate implements Externalizable,
         this.otherVer = otherVer;
         this.threadId = threadId;
         this.ver = ver;
-        this.timeout = timeout;
         this.serOrder = serOrder;
 
         mask(LOCAL, loc);
@@ -187,8 +179,7 @@ public class GridCacheMvccCandidate implements Externalizable,
         mask(SINGLE_IMPLICIT, singleImplicit);
         mask(NEAR_LOCAL, nearLoc);
         mask(DHT_LOCAL, dhtLoc);
-
-        ts = U.currentTimeMillis();
+        mask(READ, read);
 
         id = IDGEN.incrementAndGet();
     }
@@ -245,14 +236,14 @@ public class GridCacheMvccCandidate implements Externalizable,
             otherVer,
             threadId,
             ver,
-            timeout,
             local(),
             /*reentry*/true,
             tx(),
             singleImplicit(),
             nearLocal(),
             dhtLocal(),
-            serializableOrder());
+            serializableOrder(),
+            read());
 
         reentry.topVer = topVer;
 
@@ -411,20 +402,6 @@ public class GridCacheMvccCandidate implements Externalizable,
     }
 
     /**
-     * @return Maximum wait time.
-     */
-    public long timeout() {
-        return timeout;
-    }
-
-    /**
-     * @return Timestamp at the time of entering pending set.
-     */
-    public long timestamp() {
-        return ts;
-    }
-
-    /**
      * @return {@code True} if lock is local.
      */
     public boolean local() {
@@ -474,6 +451,13 @@ public class GridCacheMvccCandidate implements Externalizable,
     }
 
     /**
+     * @return Read lock flag.
+     */
+    public boolean read() {
+        return READ.get(flags());
+    }
+
+    /**
      * @return {@code True} if this candidate is a reentry.
      */
     public boolean reentry() {
@@ -586,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} */
@@ -610,7 +599,6 @@ public class GridCacheMvccCandidate implements Externalizable,
             ver.writeExternal(out);
         }
 
-        out.writeLong(timeout);
         out.writeLong(threadId);
         out.writeLong(id);
         out.writeShort(flags());
@@ -626,7 +614,6 @@ public class GridCacheMvccCandidate implements Externalizable,
             ver.readExternal(in);
         }
 
-        timeout = in.readLong();
         threadId = in.readLong();
         id = in.readLong();
 
@@ -635,8 +622,6 @@ public class GridCacheMvccCandidate implements Externalizable,
         mask(OWNER, OWNER.get(flags));
         mask(USED, USED.get(flags));
         mask(TX, TX.get(flags));
-
-        ts = U.currentTimeMillis();
     }
 
     /** {@inheritDoc} */
@@ -719,7 +704,10 @@ public class GridCacheMvccCandidate implements Externalizable,
         NEAR_LOCAL(0x200),
 
         /** */
-        REMOVED(0x400);
+        REMOVED(0x400),
+
+        /** */
+        READ(0x800);
 
         /** All mask values. */
         private static final Mask[] MASKS = values();

http://git-wip-us.apache.org/repos/asf/ignite/blob/33dda460/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/33dda460/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 2d1b02e..3d55f31 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;
@@ -66,7 +67,7 @@ public class GridDistributedCacheEntry extends GridCacheMapEntry {
     /**
      *
      */
-    protected void refreshRemotes() {
+    private void refreshRemotes() {
         GridCacheMvcc mvcc = mvccExtras();
 
         rmts = mvcc == null ? Collections.<GridCacheMvccCandidate>emptyList() : mvcc.remoteCandidates();
@@ -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();
 
@@ -168,7 +178,6 @@ public class GridDistributedCacheEntry extends GridCacheMapEntry {
      * @param otherNodeId Other node ID.
      * @param threadId Thread ID.
      * @param ver Lock version.
-     * @param timeout Lock acquire timeout.
      * @param tx Transaction flag.
      * @param implicitSingle Implicit flag.
      * @param owned Owned candidate version.
@@ -180,13 +189,12 @@ public class GridDistributedCacheEntry extends GridCacheMapEntry {
         @Nullable UUID otherNodeId,
         long threadId,
         GridCacheVersion ver,
-        long timeout,
         boolean tx,
         boolean implicitSingle,
         @Nullable GridCacheVersion owned
     ) throws GridDistributedLockCancelledException, GridCacheEntryRemovedException {
-        GridCacheMvccCandidate prev;
-        GridCacheMvccCandidate owner;
+        CacheLockCandidates prev;
+        CacheLockCandidates owner;
 
         CacheObject val;
 
@@ -204,7 +212,7 @@ public class GridDistributedCacheEntry extends GridCacheMapEntry {
                 mvccExtras(mvcc);
             }
 
-            prev = mvcc.anyOwner();
+            prev = mvcc.allOwners();
 
             boolean emptyBefore = mvcc.isEmpty();
 
@@ -214,7 +222,6 @@ public class GridDistributedCacheEntry extends GridCacheMapEntry {
                 otherNodeId,
                 threadId,
                 ver,
-                timeout,
                 tx,
                 implicitSingle,
                 /*near-local*/false
@@ -223,62 +230,7 @@ public class GridDistributedCacheEntry extends GridCacheMapEntry {
             if (owned != null)
                 mvcc.markOwned(ver, owned);
 
-            owner = mvcc.anyOwner();
-
-            boolean emptyAfter = mvcc.isEmpty();
-
-            checkCallbacks(emptyBefore, emptyAfter);
-
-            val = this.val;
-
-            refreshRemotes();
-
-            if (emptyAfter)
-                mvccExtras(null);
-        }
-
-        // This call must be outside of synchronization.
-        checkOwnerChanged(prev, owner, val);
-    }
-
-    /**
-     * Adds new lock candidate.
-     *
-     * @param cand Remote lock candidate.
-     * @throws GridDistributedLockCancelledException If lock has been canceled.
-     * @throws GridCacheEntryRemovedException If this entry is obsolete.
-     */
-    public void addRemote(GridCacheMvccCandidate cand) throws GridDistributedLockCancelledException,
-        GridCacheEntryRemovedException {
-
-        CacheObject val;
-
-        GridCacheMvccCandidate prev;
-        GridCacheMvccCandidate owner;
-
-        synchronized (this) {
-            cand.parent(this);
-
-            // Check removed locks prior to obsolete flag.
-            checkRemoved(cand.version());
-
-            checkObsolete();
-
-            GridCacheMvcc mvcc = mvccExtras();
-
-            if (mvcc == null) {
-                mvcc = new GridCacheMvcc(cctx);
-
-                mvccExtras(mvcc);
-            }
-
-            boolean emptyBefore = mvcc.isEmpty();
-
-            prev = mvcc.anyOwner();
-
-            mvcc.addRemote(cand);
-
-            owner = mvcc.anyOwner();
+            owner = mvcc.allOwners();
 
             boolean emptyAfter = mvcc.isEmpty();
 
@@ -303,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;
 
@@ -314,7 +266,7 @@ public class GridDistributedCacheEntry extends GridCacheMapEntry {
             GridCacheMvcc mvcc = mvccExtras();
 
             if (mvcc != null) {
-                prev = mvcc.anyOwner();
+                prev = mvcc.allOwners();
 
                 boolean emptyBefore = mvcc.isEmpty();
 
@@ -346,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;
 
@@ -355,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();
 
@@ -367,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;
 
@@ -408,13 +371,11 @@ 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());
 
                 boolean emptyAfter = mvcc.isEmpty();
 
@@ -425,6 +386,8 @@ public class GridDistributedCacheEntry extends GridCacheMapEntry {
 
                 if (emptyAfter)
                     mvccExtras(null);
+                else
+                    owner = mvcc.allOwners();
             }
 
             val = this.val;
@@ -477,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;
 
@@ -490,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();
 
@@ -523,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;
 
@@ -542,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();
 
@@ -563,75 +526,6 @@ public class GridDistributedCacheEntry extends GridCacheMapEntry {
 
         // This call must be made outside of synchronization.
         checkOwnerChanged(prev, owner, val);
-
-        return owner;
-    }
-
-    /**
-     * Reorders completed versions.
-     *
-     * @param baseVer Base version for reordering.
-     * @param committedVers Completed versions.
-     * @param rolledbackVers Rolled back versions.
-     * @throws GridCacheEntryRemovedException If entry has been removed.
-     */
-    public void orderCompleted(GridCacheVersion baseVer, Collection<GridCacheVersion> committedVers,
-        Collection<GridCacheVersion> rolledbackVers)
-        throws GridCacheEntryRemovedException {
-        if (!F.isEmpty(committedVers) || !F.isEmpty(rolledbackVers)) {
-            GridCacheMvccCandidate prev = null;
-            GridCacheMvccCandidate owner = null;
-
-            CacheObject val;
-
-            synchronized (this) {
-                checkObsolete();
-
-                GridCacheMvcc mvcc = mvccExtras();
-
-                if (mvcc != null) {
-                    prev = mvcc.anyOwner();
-
-                    boolean emptyBefore = mvcc.isEmpty();
-
-                    owner = mvcc.orderCompleted(baseVer, committedVers, rolledbackVers);
-
-                    boolean emptyAfter = mvcc.isEmpty();
-
-                    checkCallbacks(emptyBefore, emptyAfter);
-
-                    if (emptyAfter)
-                        mvccExtras(null);
-                }
-
-                val = this.val;
-            }
-
-            // This call must be made outside of synchronization.
-            checkOwnerChanged(prev, owner, val);
-        }
-    }
-
-    /**
-     *
-     * @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);
     }
 
     /**
@@ -645,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;
 
@@ -665,7 +558,7 @@ public class GridDistributedCacheEntry extends GridCacheMapEntry {
             GridCacheMvcc mvcc = mvccExtras();
 
             if (mvcc != null) {
-                prev = mvcc.anyOwner();
+                prev = mvcc.allOwners();
 
                 boolean emptyBefore = mvcc.isEmpty();
 
@@ -680,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();
@@ -696,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;
 
@@ -715,7 +606,7 @@ public class GridDistributedCacheEntry extends GridCacheMapEntry {
             GridCacheMvcc mvcc = mvccExtras();
 
             if (mvcc != null) {
-                prev = mvcc.anyOwner();
+                prev = mvcc.allOwners();
 
                 boolean emptyBefore = mvcc.isEmpty();
 
@@ -734,8 +625,6 @@ public class GridDistributedCacheEntry extends GridCacheMapEntry {
 
         // This call must be made outside of synchronization.
         checkOwnerChanged(prev, owner, val);
-
-        return owner;
     }
 
     /** {@inheritDoc} */
@@ -743,7 +632,7 @@ public class GridDistributedCacheEntry extends GridCacheMapEntry {
         long timeout,
         @Nullable GridCacheVersion serOrder,
         GridCacheVersion serReadVer,
-        boolean keepBinary
+        boolean read
     ) throws GridCacheEntryRemovedException, GridDistributedLockCancelledException {
         if (tx.local())
             // Null is returned if timeout is negative and there is other lock owner.
@@ -754,7 +643,8 @@ public class GridDistributedCacheEntry extends GridCacheMapEntry {
                 timeout,
                 /*reenter*/false,
                 /*tx*/true,
-                tx.implicitSingle()) != null;
+                tx.implicitSingle(),
+                read) != null;
 
         try {
             addRemote(
@@ -762,7 +652,6 @@ public class GridDistributedCacheEntry extends GridCacheMapEntry {
                 tx.otherNodeId(),
                 tx.threadId(),
                 tx.xidVersion(),
-                tx.timeout(),
                 /*tx*/true,
                 tx.implicitSingle(),
                 tx.ownedVersion(txKey())
@@ -779,7 +668,7 @@ public class GridDistributedCacheEntry extends GridCacheMapEntry {
     }
 
     /** {@inheritDoc} */
-    @Override public void txUnlock(IgniteInternalTx tx) throws GridCacheEntryRemovedException {
+    @Override public final void txUnlock(IgniteInternalTx tx) throws GridCacheEntryRemovedException {
         removeLock(tx.xidVersion());
     }
 
@@ -799,42 +688,8 @@ public class GridDistributedCacheEntry extends GridCacheMapEntry {
         }
     }
 
-    /**
-     * @param prev Previous owner.
-     * @param owner Current owner.
-     * @param val Entry value.
-     */
-    protected void checkOwnerChanged(GridCacheMvccCandidate prev, GridCacheMvccCandidate owner, CacheObject val) {
-        assert !Thread.holdsLock(this);
-
-        if (owner != prev) {
-            cctx.mvcc().callback().onOwnerChanged(this, prev, owner);
-
-            if (owner != null && owner.local())
-                checkThreadChain(owner);
-
-            if (prev != null && cctx.events().isRecordable(EVT_CACHE_OBJECT_UNLOCKED)) {
-                boolean hasVal = hasValue();
-
-                // Event notification.
-                cctx.events().addEvent(partition(), key, prev.nodeId(), prev, EVT_CACHE_OBJECT_UNLOCKED, val, hasVal,
-                    val, hasVal, null, null, null, true);
-            }
-
-            if (owner != null && cctx.events().isRecordable(EVT_CACHE_OBJECT_LOCKED)) {
-                boolean hasVal = hasValue();
-
-                // Event notification.
-                cctx.events().addEvent(partition(), key, owner.nodeId(), owner, EVT_CACHE_OBJECT_LOCKED, val, hasVal,
-                    val, hasVal, null, null, null, true);
-            }
-        }
-    }
-
-    /**
-     * @param owner Starting candidate in the chain.
-     */
-    protected void checkThreadChain(GridCacheMvccCandidate owner) {
+    /** {@inheritDoc} */
+    @Override final protected void checkThreadChain(GridCacheMvccCandidate owner) {
         assert !Thread.holdsLock(this);
 
         assert owner != null;

http://git-wip-us.apache.org/repos/asf/ignite/blob/33dda460/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 b0b0a7e..cf4085b 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;
@@ -135,7 +136,7 @@ public class GridDhtCacheEntry extends GridDistributedCacheEntry {
      * @return Local candidate by near version.
      * @throws GridCacheEntryRemovedException If removed.
      */
-    @Nullable public synchronized GridCacheMvccCandidate localCandidateByNearVersion(GridCacheVersion nearVer,
+    @Nullable synchronized GridCacheMvccCandidate localCandidateByNearVersion(GridCacheVersion nearVer,
         boolean rmv) throws GridCacheEntryRemovedException {
         checkObsolete();
 
@@ -165,34 +166,33 @@ public class GridDhtCacheEntry extends GridDistributedCacheEntry {
      * @param threadId Owning thread ID.
      * @param ver Lock version.
      * @param serOrder Version for serializable transactions ordering.
-     * @param serReadVer Optional read entry version for optimistic serializable transaction.
      * @param timeout Timeout to acquire lock.
      * @param reenter Reentry flag.
      * @param tx Tx flag.
      * @param implicitSingle Implicit flag.
+     * @param read Read lock flag.
      * @return New candidate.
      * @throws GridCacheEntryRemovedException If entry has been removed.
      * @throws GridDistributedLockCancelledException If lock was cancelled.
      */
-    @Nullable public GridCacheMvccCandidate addDhtLocal(
+    @Nullable GridCacheMvccCandidate addDhtLocal(
         UUID nearNodeId,
         GridCacheVersion nearVer,
         AffinityTopologyVersion topVer,
         long threadId,
         GridCacheVersion ver,
         @Nullable GridCacheVersion serOrder,
-        @Nullable GridCacheVersion serReadVer,
         long timeout,
         boolean reenter,
         boolean tx,
-        boolean implicitSingle)
+        boolean implicitSingle,
+        boolean read)
         throws GridCacheEntryRemovedException, GridDistributedLockCancelledException {
-        assert serReadVer == null || serOrder != null;
         assert !reenter || serOrder == null;
 
         GridCacheMvccCandidate cand;
-        GridCacheMvccCandidate prev;
-        GridCacheMvccCandidate owner;
+        CacheLockCandidates prev;
+        CacheLockCandidates owner;
 
         CacheObject val;
 
@@ -211,7 +211,7 @@ public class GridDhtCacheEntry extends GridDistributedCacheEntry {
                 mvccExtras(mvcc);
             }
 
-            prev = mvcc.anyOwner();
+            prev = mvcc.allOwners();
 
             boolean emptyBefore = mvcc.isEmpty();
 
@@ -226,7 +226,8 @@ public class GridDhtCacheEntry extends GridDistributedCacheEntry {
                 reenter,
                 tx,
                 implicitSingle,
-                /*dht-local*/true
+                /*dht-local*/true,
+                read
             );
 
             if (cand == null)
@@ -234,10 +235,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();
 
@@ -264,7 +265,7 @@ public class GridDhtCacheEntry extends GridDistributedCacheEntry {
         long timeout,
         @Nullable GridCacheVersion serOrder,
         GridCacheVersion serReadVer,
-        boolean keepBinary
+        boolean read
     ) throws GridCacheEntryRemovedException, GridDistributedLockCancelledException {
         if (tx.local()) {
             GridDhtTxLocalAdapter dhtTx = (GridDhtTxLocalAdapter)tx;
@@ -277,11 +278,11 @@ public class GridDhtCacheEntry extends GridDistributedCacheEntry {
                 tx.threadId(),
                 tx.xidVersion(),
                 serOrder,
-                serReadVer,
                 timeout,
                 /*reenter*/false,
                 /*tx*/true,
-                tx.implicitSingle()) != null;
+                tx.implicitSingle(),
+                read) != null;
         }
 
         try {
@@ -290,7 +291,6 @@ public class GridDhtCacheEntry extends GridDistributedCacheEntry {
                 tx.otherNodeId(),
                 tx.threadId(),
                 tx.xidVersion(),
-                tx.timeout(),
                 /*tx*/true,
                 tx.implicit(),
                 null);


Mime
View raw message