This is an automated email from the ASF dual-hosted git repository.

gvvinblade pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ignite.git


The following commit(s) were added to refs/heads/master by this push:
     new b5b9ffa  IGNITE-10604: MVCC: mvcc history can be missed during remove 
operation. This closes #5979.
b5b9ffa is described below

commit b5b9ffa6183f7f77b595e1232839fa4d3c5c5d59
Author: Andrey V. Mashenkov <andrey.mashen...@gmail.com>
AuthorDate: Thu Feb 7 16:30:40 2019 +0300

    IGNITE-10604: MVCC: mvcc history can be missed during remove operation. 
This closes #5979.
---
 .../processors/cache/GridCacheMapEntry.java        |  2 +
 .../processors/cache/GridCacheMvccEntryInfo.java   |  4 +-
 .../cache/IgniteCacheOffheapManagerImpl.java       | 47 ++++++++++---------
 .../dht/GridDhtTxAbstractEnlistFuture.java         |  2 +-
 .../cache/distributed/near/GridNearTxLocal.java    |  2 +-
 .../internal/processors/cache/mvcc/MvccUtils.java  | 50 +++++++++++---------
 .../cache/persistence/tree/io/DataPageIO.java      | 54 ++++++++++++----------
 .../cache/tree/mvcc/data/MvccDataRow.java          | 48 +++++++++++--------
 .../cache/tree/mvcc/data/MvccUpdateDataRow.java    |  8 ++--
 .../cache/tree/mvcc/search/MvccMaxSearchRow.java   |  3 +-
 .../CacheLateAffinityAssignmentTest.java           |  2 -
 .../cache/mvcc/CacheMvccTransactionsTest.java      |  2 +-
 .../cache/mvcc/CacheMvccSqlUpdateCountersTest.java | 12 ++++-
 13 files changed, 133 insertions(+), 103 deletions(-)

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 4753e9f..e044a2d 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
@@ -5606,6 +5606,8 @@ public abstract class GridCacheMapEntry extends 
GridMetadataAwareAdapter impleme
                 updRes.invokeResult(res.invokeResult());
             }
 
+            updRes.newValue(res.newValue());
+
             if (needOldVal && compareIgnoreOpCounter(res.resultVersion(), 
mvccVer) != 0 &&
                 (res.resultType() == ResultType.PREV_NOT_NULL || 
res.resultType() == ResultType.REMOVED_NOT_NULL))
                 updRes.oldValue(res.oldValue());
diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheMvccEntryInfo.java
 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheMvccEntryInfo.java
index 027305d..b9589de 100644
--- 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheMvccEntryInfo.java
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheMvccEntryInfo.java
@@ -65,7 +65,7 @@ public class GridCacheMvccEntryInfo extends 
GridCacheEntryInfo implements MvccVe
 
     /** {@inheritDoc} */
     @Override public int newMvccOperationCounter() {
-        return newMvccOpCntr & ~MVCC_OP_COUNTER_MASK;
+        return newMvccOpCntr & MVCC_OP_COUNTER_MASK;
     }
 
     /** {@inheritDoc} */
@@ -85,7 +85,7 @@ public class GridCacheMvccEntryInfo extends 
GridCacheEntryInfo implements MvccVe
 
     /** {@inheritDoc} */
     @Override public int mvccOperationCounter() {
-        return mvccOpCntr & ~MVCC_OP_COUNTER_MASK;
+        return mvccOpCntr & MVCC_OP_COUNTER_MASK;
     }
 
     /** {@inheritDoc} */
diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteCacheOffheapManagerImpl.java
 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteCacheOffheapManagerImpl.java
index 48d4682..209c9cf 100644
--- 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteCacheOffheapManagerImpl.java
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteCacheOffheapManagerImpl.java
@@ -121,6 +121,7 @@ import static 
org.apache.ignite.internal.processors.cache.mvcc.MvccUtils.INITIAL
 import static 
org.apache.ignite.internal.processors.cache.mvcc.MvccUtils.MVCC_COUNTER_NA;
 import static 
org.apache.ignite.internal.processors.cache.mvcc.MvccUtils.MVCC_CRD_COUNTER_NA;
 import static 
org.apache.ignite.internal.processors.cache.mvcc.MvccUtils.MVCC_HINTS_BIT_OFF;
+import static 
org.apache.ignite.internal.processors.cache.mvcc.MvccUtils.MVCC_KEY_ABSENT_BEFORE_OFF;
 import static 
org.apache.ignite.internal.processors.cache.mvcc.MvccUtils.MVCC_OP_COUNTER_MASK;
 import static 
org.apache.ignite.internal.processors.cache.mvcc.MvccUtils.MVCC_OP_COUNTER_NA;
 import static 
org.apache.ignite.internal.processors.cache.mvcc.MvccUtils.compare;
@@ -1443,7 +1444,7 @@ public class IgniteCacheOffheapManagerImpl implements 
IgniteCacheOffheapManager
         private final ConcurrentMap<Integer, AtomicLong> cacheSizes = new 
ConcurrentHashMap<>();
 
         /** Mvcc remove handler. */
-        private final PageHandler<MvccVersion, Boolean> mvccUpdateMarker = new 
MvccMarkUpdatedHandler();
+        private final PageHandler<MvccUpdateDataRow, Boolean> mvccUpdateMarker 
= new MvccMarkUpdatedHandler();
 
         /** Mvcc update tx state hint handler. */
         private final PageHandler<Void, Boolean> mvccUpdateTxStateHint = new 
MvccUpdateTxStateHintHandler();
@@ -1998,7 +1999,7 @@ public class IgniteCacheOffheapManagerImpl implements 
IgniteCacheOffheapManager
 
                     // Mark old version as removed.
                     if (res == ResultType.PREV_NOT_NULL) {
-                        rowStore.updateDataRow(oldRow.link(), 
mvccUpdateMarker, mvccSnapshot, grp.statisticsHolderData());
+                        rowStore.updateDataRow(oldRow.link(), 
mvccUpdateMarker, updateRow, grp.statisticsHolderData());
 
                         if (op == CacheInvokeEntry.Operation.REMOVE) {
                             updateRow.resultType(ResultType.REMOVED_NOT_NULL);
@@ -2014,7 +2015,7 @@ public class IgniteCacheOffheapManagerImpl implements 
IgniteCacheOffheapManager
                         assert op != CacheInvokeEntry.Operation.REMOVE;
                 }
                 else if (oldRow != null)
-                    rowStore.updateDataRow(oldRow.link(), mvccUpdateMarker, 
mvccSnapshot, grp.statisticsHolderData());
+                    rowStore.updateDataRow(oldRow.link(), mvccUpdateMarker, 
updateRow, grp.statisticsHolderData());
 
                 if (!grp.storeCacheIdInDataPage() && updateRow.cacheId() != 
CU.UNDEFINED_CACHE_ID) {
                     updateRow.cacheId(CU.UNDEFINED_CACHE_ID);
@@ -2174,7 +2175,7 @@ public class IgniteCacheOffheapManagerImpl implements 
IgniteCacheOffheapManager
 
                     assert oldRow != null && oldRow.link() != 0 : oldRow;
 
-                    rowStore.updateDataRow(oldRow.link(), mvccUpdateMarker, 
mvccSnapshot, grp.statisticsHolderData());
+                    rowStore.updateDataRow(oldRow.link(), mvccUpdateMarker, 
updateRow, grp.statisticsHolderData());
 
                     clearPendingEntries(cctx, oldRow);
                 }
@@ -2451,7 +2452,7 @@ public class IgniteCacheOffheapManagerImpl implements 
IgniteCacheOffheapManager
 
                     assert oldRow != null && oldRow.link() != 0 : oldRow;
 
-                    rowStore.updateDataRow(oldRow.link(), mvccUpdateMarker, 
mvccSnapshot, grp.statisticsHolderData());
+                    rowStore.updateDataRow(oldRow.link(), mvccUpdateMarker, 
updateRow, grp.statisticsHolderData());
                 }
 
                 if (val != null) {
@@ -3154,10 +3155,10 @@ public class IgniteCacheOffheapManagerImpl implements 
IgniteCacheOffheapManager
     /**
      * Mvcc remove handler.
      */
-    private final class MvccMarkUpdatedHandler extends 
PageHandler<MvccVersion, Boolean> {
+    private final class MvccMarkUpdatedHandler extends 
PageHandler<MvccUpdateDataRow, Boolean> {
         /** {@inheritDoc} */
         @Override public Boolean run(int cacheId, long pageId, long page, long 
pageAddr, PageIO io, Boolean walPlc,
-            MvccVersion newVer, int itemId, IoStatisticsHolder statHolder) 
throws IgniteCheckedException {
+            MvccUpdateDataRow updateDataRow, int itemId, IoStatisticsHolder 
statHolder) throws IgniteCheckedException {
             assert grp.mvccEnabled();
 
             DataPageIO iox = (DataPageIO)io;
@@ -3167,15 +3168,18 @@ public class IgniteCacheOffheapManagerImpl implements 
IgniteCacheOffheapManager
 
             long newCrd = iox.newMvccCoordinator(pageAddr, off);
             long newCntr = iox.newMvccCounter(pageAddr, off);
-            int newOpCntr = iox.newMvccOperationCounter(pageAddr, off);
+            int newOpCntr = iox.rawNewMvccOperationCounter(pageAddr, off);
 
             assert newCrd == MVCC_CRD_COUNTER_NA || state(grp, newCrd, 
newCntr, newOpCntr) == TxState.ABORTED;
 
-            iox.updateNewVersion(pageAddr, off, newVer, TxState.NA);
+            int keyAbsentBeforeFlag = updateDataRow.isKeyAbsentBefore() ? (1 
<< MVCC_KEY_ABSENT_BEFORE_OFF) : 0;
+
+            iox.updateNewVersion(pageAddr, off, 
updateDataRow.mvccCoordinatorVersion(), updateDataRow.mvccCounter(),
+                updateDataRow.mvccOperationCounter() | keyAbsentBeforeFlag, 
TxState.NA);
 
             if (isWalDeltaRecordNeeded(grp.dataRegion().pageMemory(), cacheId, 
pageId, page, ctx.wal(), walPlc))
                 ctx.wal().log(new DataPageMvccMarkUpdatedRecord(cacheId, 
pageId, itemId,
-                    newVer.coordinatorVersion(), newVer.counter(), 
newVer.operationCounter()));
+                    updateDataRow.mvccCoordinatorVersion(), 
updateDataRow.mvccCounter(), updateDataRow.mvccOperationCounter()));
 
             return TRUE;
         }
@@ -3196,14 +3200,14 @@ public class IgniteCacheOffheapManagerImpl implements 
IgniteCacheOffheapManager
 
             long crd = iox.mvccCoordinator(pageAddr, off);
             long cntr = iox.mvccCounter(pageAddr, off);
-            int opCntr = iox.mvccOperationCounter(pageAddr, off);
+            int opCntr = iox.rawMvccOperationCounter(pageAddr, off);
             byte txState = (byte)(opCntr >>> MVCC_HINTS_BIT_OFF);
 
             if (txState == TxState.NA) {
                 byte state = state(grp, crd, cntr, opCntr);
 
                 if (state == TxState.COMMITTED || state == TxState.ABORTED) {
-                    iox.mvccOperationCounter(pageAddr, off, opCntr | (state << 
MVCC_HINTS_BIT_OFF));
+                    iox.rawMvccOperationCounter(pageAddr, off, opCntr | (state 
<< MVCC_HINTS_BIT_OFF));
 
                     if (isWalDeltaRecordNeeded(grp.dataRegion().pageMemory(), 
cacheId, pageId, page, ctx.wal(), walPlc))
                         ctx.wal().log(new 
DataPageMvccUpdateTxStateHintRecord(cacheId, pageId, itemId, state));
@@ -3214,14 +3218,14 @@ public class IgniteCacheOffheapManagerImpl implements 
IgniteCacheOffheapManager
 
             long newCrd = iox.newMvccCoordinator(pageAddr, off);
             long newCntr = iox.newMvccCounter(pageAddr, off);
-            int newOpCntr = iox.newMvccOperationCounter(pageAddr, off);
+            int newOpCntr = iox.rawNewMvccOperationCounter(pageAddr, off);
             byte newTxState = (byte)(newOpCntr >>> MVCC_HINTS_BIT_OFF);
 
             if (newCrd != MVCC_CRD_COUNTER_NA && newTxState == TxState.NA) {
                 byte state = state(grp, newCrd, newCntr, newOpCntr);
 
                 if (state == TxState.COMMITTED || state == TxState.ABORTED) {
-                    iox.newMvccOperationCounter(pageAddr, off, newOpCntr | 
(state << MVCC_HINTS_BIT_OFF));
+                    iox.rawNewMvccOperationCounter(pageAddr, off, newOpCntr | 
(state << MVCC_HINTS_BIT_OFF));
 
                     if (isWalDeltaRecordNeeded(grp.dataRegion().pageMemory(), 
cacheId, pageId, page, ctx.wal(), walPlc))
                         ctx.wal().log(new 
DataPageMvccUpdateNewTxStateHintRecord(cacheId, pageId, itemId, state));
@@ -3250,14 +3254,14 @@ public class IgniteCacheOffheapManagerImpl implements 
IgniteCacheOffheapManager
 
             long crd = iox.mvccCoordinator(pageAddr, off);
             long cntr = iox.mvccCounter(pageAddr, off);
-            int opCntrAndHint = iox.mvccOperationCounter(pageAddr, off);
-            int opCntr = opCntrAndHint & ~MVCC_OP_COUNTER_MASK;
+            int opCntrAndHint = iox.rawMvccOperationCounter(pageAddr, off);
+            int opCntr = opCntrAndHint & MVCC_OP_COUNTER_MASK;
             byte txState = (byte)(opCntrAndHint >>> MVCC_HINTS_BIT_OFF);
 
             long newCrd = iox.newMvccCoordinator(pageAddr, off);
             long newCntr = iox.newMvccCounter(pageAddr, off);
-            int newOpCntrAndHint = iox.newMvccOperationCounter(pageAddr, off);
-            int newOpCntr = newOpCntrAndHint & ~MVCC_OP_COUNTER_MASK;
+            int newOpCntrAndHint = iox.rawNewMvccOperationCounter(pageAddr, 
off);
+            int newOpCntr = newOpCntrAndHint & MVCC_OP_COUNTER_MASK;
             byte newTxState = (byte)(newOpCntrAndHint >>> MVCC_HINTS_BIT_OFF);
 
             assert crd == newRow.mvccCoordinatorVersion();
@@ -3267,7 +3271,7 @@ public class IgniteCacheOffheapManagerImpl implements 
IgniteCacheOffheapManager
             if (txState != newRow.mvccTxState() && newRow.mvccTxState() != 
TxState.NA) {
                 assert txState == TxState.NA;
 
-                iox.mvccOperationCounter(pageAddr, off, opCntr | 
(newRow.mvccTxState() << MVCC_HINTS_BIT_OFF));
+                iox.rawMvccOperationCounter(pageAddr, off, opCntr | 
(newRow.mvccTxState() << MVCC_HINTS_BIT_OFF));
 
                 if (isWalDeltaRecordNeeded(grp.dataRegion().pageMemory(), 
cacheId, pageId, page, ctx.wal(), walPlc))
                     ctx.wal().log(new 
DataPageMvccUpdateTxStateHintRecord(cacheId, pageId, itemId, 
newRow.mvccTxState()));
@@ -3280,7 +3284,8 @@ public class IgniteCacheOffheapManagerImpl implements 
IgniteCacheOffheapManager
                 newRow.newMvccCounter(),
                 newRow.newMvccOperationCounter()) != 0) {
 
-                iox.updateNewVersion(pageAddr, off, newRow.newMvccVersion(), 
newRow.newMvccTxState());
+                iox.updateNewVersion(pageAddr, off, 
newRow.newMvccCoordinatorVersion(), newRow.newMvccCounter(),
+                    newRow.newMvccOperationCounter(), newRow.newMvccTxState());
 
                 if (isWalDeltaRecordNeeded(grp.dataRegion().pageMemory(), 
cacheId, pageId, page, ctx.wal(), walPlc))
                     ctx.wal().log(new DataPageMvccMarkUpdatedRecord(cacheId, 
pageId, itemId,
@@ -3289,7 +3294,7 @@ public class IgniteCacheOffheapManagerImpl implements 
IgniteCacheOffheapManager
             else if (newTxState != newRow.newMvccTxState() && 
newRow.newMvccTxState() != TxState.NA) {
                 assert newTxState == TxState.NA;
 
-                iox.newMvccOperationCounter(pageAddr, off, newOpCntr | 
(newRow.newMvccTxState() << MVCC_HINTS_BIT_OFF));
+                iox.rawNewMvccOperationCounter(pageAddr, off, newOpCntr | 
(newRow.newMvccTxState() << MVCC_HINTS_BIT_OFF));
 
                 if (isWalDeltaRecordNeeded(grp.dataRegion().pageMemory(), 
cacheId, pageId, page, ctx.wal(), walPlc))
                     ctx.wal().log(new 
DataPageMvccUpdateNewTxStateHintRecord(cacheId, pageId, itemId, 
newRow.newMvccTxState()));
diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtTxAbstractEnlistFuture.java
 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtTxAbstractEnlistFuture.java
index bc310ec..6f3153c 100644
--- 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtTxAbstractEnlistFuture.java
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtTxAbstractEnlistFuture.java
@@ -701,7 +701,7 @@ public abstract class GridDhtTxAbstractEnlistFuture<T> 
extends GridCacheFutureAd
                 batches.put(node.id(), batch = new Batch(node));
 
             if (moving && hist0 == null) {
-                assert !F.isEmpty(hist);
+                assert !F.isEmpty(hist) || val == null;
 
                 hist0 = fetchHistoryInfo(key, hist);
             }
diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearTxLocal.java
 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearTxLocal.java
index 8ff0960..d6fcf50 100644
--- 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearTxLocal.java
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearTxLocal.java
@@ -2113,7 +2113,7 @@ public class GridNearTxLocal extends 
GridDhtTxLocalAdapter implements GridTimeou
                     assert res != null;
 
                     if (res > 0) {
-                        if (mvccSnapshot.operationCounter() == 
~MvccUtils.MVCC_OP_COUNTER_MASK) {
+                        if (mvccSnapshot.operationCounter() == 
MvccUtils.MVCC_READ_OP_CNTR) {
                             throw new IgniteCheckedException("The maximum 
limit of the number of statements allowed in" +
                                 " one transaction is reached. [max=" + 
mvccSnapshot.operationCounter() + ']');
                         }
diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/mvcc/MvccUtils.java
 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/mvcc/MvccUtils.java
index f34416f..9d688c5 100644
--- 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/mvcc/MvccUtils.java
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/mvcc/MvccUtils.java
@@ -55,16 +55,16 @@ public class MvccUtils {
     public static final int MVCC_KEY_ABSENT_BEFORE_OFF = 29;
 
     /** */
-    public static final int MVCC_KEY_ABSENT_BEFORE_MASK = 0b0001 << 
MVCC_KEY_ABSENT_BEFORE_OFF;
-
-    /** */
     public static final int MVCC_HINTS_BIT_OFF = MVCC_KEY_ABSENT_BEFORE_OFF + 
1;
 
-    /** */
-    public static final int MVCC_HINTS_MASK = 0b0011 << MVCC_HINTS_BIT_OFF;
+    /** Mask for KeyAbsent flag. */
+    public static final int MVCC_KEY_ABSENT_BEFORE_MASK = 1 << 
MVCC_KEY_ABSENT_BEFORE_OFF;
+
+    /** Mask for tx hints. (2 highest bits)  */
+    public static final int MVCC_HINTS_MASK = Integer.MIN_VALUE >> 1;
 
-    /** Mask for all masked high bits in operation counter field. */
-    public static final int MVCC_OP_COUNTER_MASK = 0b0111 << 
MVCC_KEY_ABSENT_BEFORE_OFF;
+    /** Mask for operation counter bits. (Excludes hints and flags) */
+    public static final int MVCC_OP_COUNTER_MASK = ~(Integer.MIN_VALUE >> 2);
 
     /** */
     public static final long MVCC_CRD_COUNTER_NA = 0L;
@@ -87,8 +87,8 @@ public class MvccUtils {
     /** */
     public static final int MVCC_START_OP_CNTR = 1;
 
-    /** */
-    public static final int MVCC_READ_OP_CNTR = ~MVCC_HINTS_MASK;
+    /** Used as 'read' snapshot op counter. */
+    public static final int MVCC_READ_OP_CNTR = MVCC_OP_COUNTER_MASK;
 
     /** */
     public static final int MVCC_INVISIBLE = 0;
@@ -215,16 +215,18 @@ public class MvccUtils {
      * @param snapshot Snapshot.
      * @param mvccCrd Mvcc coordinator.
      * @param mvccCntr Mvcc counter.
-     * @param opCntr Operation counter.
+     * @param opCntrWithHints Operation counter.
      * @param useTxLog {@code True} if TxLog should be used.
      * @return {@code True} if visible.
      * @throws IgniteCheckedException If failed.
      */
     public static boolean isVisible(GridCacheContext cctx, MvccSnapshot 
snapshot, long mvccCrd, long mvccCntr,
-        int opCntr, boolean useTxLog) throws IgniteCheckedException {
+        int opCntrWithHints, boolean useTxLog) throws IgniteCheckedException {
+        int opCntr = opCntrWithHints & MVCC_OP_COUNTER_MASK;
+
         if (mvccCrd == MVCC_CRD_COUNTER_NA) {
-            assert mvccCntr == MVCC_COUNTER_NA && opCntr == MVCC_OP_COUNTER_NA
-                : "rowVer=" + mvccVersion(mvccCrd, mvccCntr, opCntr) + ", 
snapshot=" + snapshot;
+            assert mvccCntr == MVCC_COUNTER_NA && opCntrWithHints == 
MVCC_OP_COUNTER_NA
+                : "rowVer=" + mvccVersion(mvccCrd, mvccCntr, opCntrWithHints) 
+ ", snapshot=" + snapshot;
 
             return false; // Unassigned version is always invisible
         }
@@ -237,6 +239,8 @@ public class MvccUtils {
         long snapshotCntr = snapshot.counter();
         int snapshotOpCntr = snapshot.operationCounter();
 
+        assert (snapshotOpCntr & ~MVCC_OP_COUNTER_MASK) == 0 : snapshot;
+
         if (mvccCrd > snapshotCrd)
             return false; // Rows in the future are never visible.
 
@@ -244,11 +248,11 @@ public class MvccUtils {
             if (!useTxLog)
                 return true; // The checking row is expected to be committed.
 
-            byte state = state(cctx, mvccCrd, mvccCntr, opCntr);
+            byte state = state(cctx, mvccCrd, mvccCntr, opCntrWithHints);
 
             if (MVCC_MAX_SNAPSHOT.compareTo(snapshot) != 0 // Special version 
which sees all committed entries.
                 && state != TxState.COMMITTED && state != TxState.ABORTED)
-                throw unexpectedStateException(cctx, state, mvccCrd, mvccCntr, 
opCntr, snapshot);
+                throw unexpectedStateException(cctx, state, mvccCrd, mvccCntr, 
opCntrWithHints, snapshot);
 
             return state == TxState.COMMITTED;
         }
@@ -261,7 +265,7 @@ public class MvccUtils {
         // because read-only queries use last committed version in it's 
snapshot which could be actually aborted
         // (during transaction recovery we do not know whether recovered 
transaction was committed or aborted).
         if (mvccCntr == snapshotCntr && snapshotOpCntr != MVCC_READ_OP_CNTR) {
-            assert opCntr <= snapshotOpCntr : "rowVer=" + mvccVersion(mvccCrd, 
mvccCntr, opCntr) + ", snapshot=" + snapshot;
+            assert opCntr <= snapshotOpCntr : "rowVer=" + mvccVersion(mvccCrd, 
mvccCntr, opCntrWithHints) + ", snapshot=" + snapshot;
 
             return opCntr < snapshotOpCntr; // we don't see own pending updates
         }
@@ -272,10 +276,10 @@ public class MvccUtils {
         if (!useTxLog)
             return true; // The checking row is expected to be committed.
 
-        byte state = state(cctx, mvccCrd, mvccCntr, opCntr);
+        byte state = state(cctx, mvccCrd, mvccCntr, opCntrWithHints);
 
         if (state != TxState.COMMITTED && state != TxState.ABORTED)
-            throw unexpectedStateException(cctx, state, mvccCrd, mvccCntr, 
opCntr, snapshot);
+            throw unexpectedStateException(cctx, state, mvccCrd, mvccCntr, 
opCntrWithHints, snapshot);
 
         return state == TxState.COMMITTED;
     }
@@ -476,7 +480,7 @@ public class MvccUtils {
 
         if ((cmp = Long.compare(mvccCrdLeft, mvccCrdRight)) != 0
             || (cmp = Long.compare(mvccCntrLeft, mvccCntrRight)) != 0
-            || (cmp = Integer.compare(mvccOpCntrLeft & ~MVCC_HINTS_MASK, 
mvccOpCntrRight & ~MVCC_HINTS_MASK)) != 0)
+            || (cmp = Integer.compare(mvccOpCntrLeft & MVCC_OP_COUNTER_MASK, 
mvccOpCntrRight & MVCC_OP_COUNTER_MASK)) != 0)
             return cmp;
 
         return 0;
@@ -537,7 +541,7 @@ public class MvccUtils {
      * @return Always {@code true}.
      */
     public static boolean mvccVersionIsValid(long crdVer, long cntr, int 
opCntr) {
-        return mvccVersionIsValid(crdVer, cntr) && opCntr != 
MVCC_OP_COUNTER_NA;
+        return mvccVersionIsValid(crdVer, cntr) && (opCntr & 
MVCC_OP_COUNTER_MASK) != MVCC_OP_COUNTER_NA;
     }
 
     /**
@@ -628,13 +632,13 @@ public class MvccUtils {
 
         long mvccCrd = dataIo.mvccCoordinator(pageAddr, offset);
         long mvccCntr = dataIo.mvccCounter(pageAddr, offset);
-        int mvccOpCntr = dataIo.mvccOperationCounter(pageAddr, offset) & 
~MVCC_KEY_ABSENT_BEFORE_MASK;
+        int mvccOpCntr = dataIo.rawMvccOperationCounter(pageAddr, offset);
 
-        assert mvccVersionIsValid(mvccCrd, mvccCntr, mvccOpCntr) : 
mvccVersion(mvccCrd, mvccCntr, mvccOpCntr);
+        assert mvccVersionIsValid(mvccCrd, mvccCntr, mvccOpCntr ) : 
mvccVersion(mvccCrd, mvccCntr, mvccOpCntr);
 
         long newMvccCrd = dataIo.newMvccCoordinator(pageAddr, offset);
         long newMvccCntr = dataIo.newMvccCounter(pageAddr, offset);
-        int newMvccOpCntr = dataIo.newMvccOperationCounter(pageAddr, offset) & 
~MVCC_KEY_ABSENT_BEFORE_MASK;
+        int newMvccOpCntr = dataIo.rawNewMvccOperationCounter(pageAddr, 
offset);
 
         assert newMvccCrd == MVCC_CRD_COUNTER_NA || 
mvccVersionIsValid(newMvccCrd, newMvccCntr, newMvccOpCntr)
             : mvccVersion(newMvccCrd, newMvccCntr, newMvccOpCntr);
diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/tree/io/DataPageIO.java
 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/tree/io/DataPageIO.java
index f9e6bcc..9ed7b72 100644
--- 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/tree/io/DataPageIO.java
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/tree/io/DataPageIO.java
@@ -28,6 +28,7 @@ import 
org.apache.ignite.internal.processors.cache.tree.mvcc.data.MvccUpdateResu
 import org.apache.ignite.internal.processors.cache.version.GridCacheVersion;
 import org.apache.ignite.internal.util.GridStringBuilder;
 
+import static 
org.apache.ignite.internal.processors.cache.mvcc.MvccUtils.MVCC_CRD_COUNTER_NA;
 import static 
org.apache.ignite.internal.processors.cache.mvcc.MvccUtils.MVCC_HINTS_BIT_OFF;
 import static 
org.apache.ignite.internal.processors.cache.mvcc.MvccUtils.MVCC_HINTS_MASK;
 import static 
org.apache.ignite.internal.processors.cache.mvcc.MvccUtils.MVCC_KEY_ABSENT_BEFORE_OFF;
@@ -72,23 +73,23 @@ public class DataPageIO extends 
AbstractDataPageIO<CacheDataRow> {
             if (mvccInfoSize > 0) {
                 assert 
MvccUtils.mvccVersionIsValid(row.mvccCoordinatorVersion(), row.mvccCounter(), 
row.mvccOperationCounter());
 
-                byte keyAbsentBeforeFlag = (byte)((row instanceof 
MvccUpdateResult) &&
-                    ((MvccUpdateResult)row).isKeyAbsentBefore() ? 1 : 0);
+                final int keyAbsentBeforeFlag = (row instanceof 
MvccUpdateResult) &&
+                    ((MvccUpdateResult)row).isKeyAbsentBefore() ? (1 << 
MVCC_KEY_ABSENT_BEFORE_OFF) : 0;
 
                 // xid_min.
                 PageUtils.putLong(addr, 0, row.mvccCoordinatorVersion());
                 PageUtils.putLong(addr, 8, row.mvccCounter());
                 PageUtils.putInt(addr, 16, row.mvccOperationCounter() | 
(row.mvccTxState() << MVCC_HINTS_BIT_OFF) |
-                    (keyAbsentBeforeFlag << MVCC_KEY_ABSENT_BEFORE_OFF));
+                    ((row.newMvccCoordinatorVersion() == MVCC_CRD_COUNTER_NA) 
? keyAbsentBeforeFlag : 0));
 
-                assert row.newMvccCoordinatorVersion() == 0
+                assert row.newMvccCoordinatorVersion() == MVCC_CRD_COUNTER_NA
                     || 
MvccUtils.mvccVersionIsValid(row.newMvccCoordinatorVersion(), 
row.newMvccCounter(), row.newMvccOperationCounter());
 
                 // xid_max.
                 PageUtils.putLong(addr, 20, row.newMvccCoordinatorVersion());
                 PageUtils.putLong(addr, 28, row.newMvccCounter());
                 PageUtils.putInt(addr, 36, row.newMvccOperationCounter() | 
(row.newMvccTxState() << MVCC_HINTS_BIT_OFF) |
-                    (keyAbsentBeforeFlag << MVCC_KEY_ABSENT_BEFORE_OFF));
+                    ((row.newMvccCoordinatorVersion() == MVCC_CRD_COUNTER_NA) 
? 0 : keyAbsentBeforeFlag));
 
                 addr += mvccInfoSize;
             }
@@ -212,8 +213,8 @@ public class DataPageIO extends 
AbstractDataPageIO<CacheDataRow> {
 
         final int len = Math.min(curLen - rowOff, payloadSize);
 
-        byte keyAbsentBeforeFlag = (byte)((row instanceof MvccUpdateResult) &&
-            ((MvccUpdateResult)row).isKeyAbsentBefore() ? 1 : 0);
+        final int keyAbsentBeforeFlag = (row instanceof MvccUpdateResult) &&
+            ((MvccUpdateResult)row).isKeyAbsentBefore() ? (1 << 
MVCC_KEY_ABSENT_BEFORE_OFF) : 0;
 
         if (type == EXPIRE_TIME)
             writeExpireTimeFragment(buf, row.expireTime(), rowOff, len, 
prevLen);
@@ -224,11 +225,11 @@ public class DataPageIO extends 
AbstractDataPageIO<CacheDataRow> {
                 row.mvccCoordinatorVersion(),
                 row.mvccCounter(),
                 row.mvccOperationCounter() | (row.mvccTxState() << 
MVCC_HINTS_BIT_OFF) |
-                    (keyAbsentBeforeFlag << MVCC_KEY_ABSENT_BEFORE_OFF),
+                    ((row.newMvccCoordinatorVersion() == MVCC_CRD_COUNTER_NA) 
? keyAbsentBeforeFlag : 0),
                 row.newMvccCoordinatorVersion(),
                 row.newMvccCounter(),
                 row.newMvccOperationCounter() | (row.newMvccTxState() << 
MVCC_HINTS_BIT_OFF) |
-                    (keyAbsentBeforeFlag << MVCC_KEY_ABSENT_BEFORE_OFF),
+                    ((row.newMvccCoordinatorVersion() == MVCC_CRD_COUNTER_NA) 
? 0 : keyAbsentBeforeFlag),
                 len);
         else if (type != VERSION) {
             // Write key or value.
@@ -283,13 +284,16 @@ public class DataPageIO extends 
AbstractDataPageIO<CacheDataRow> {
     /**
      * @param pageAddr Page address.
      * @param dataOff Data offset.
-     * @param newVer New version.
+     * @param mvccCrd Mvcc coordinator.
+     * @param mvccCntr Mvcc counter.
+     * @param mvccOpCntr Operation counter.
+     * @param txState Tx state hint.
      */
-    public void updateNewVersion(long pageAddr, int dataOff, MvccVersion 
newVer, byte newTxState) {
+    public void updateNewVersion(long pageAddr, int dataOff, long mvccCrd, 
long mvccCntr, int mvccOpCntr, byte txState) {
         long addr = pageAddr + dataOff;
 
-        updateNewVersion(addr, newVer.coordinatorVersion(), newVer.counter(),
-            (newVer.operationCounter() & ~MVCC_HINTS_MASK) | ((int)newTxState 
<< MVCC_HINTS_BIT_OFF));
+        updateNewVersion(addr, mvccCrd, mvccCntr,
+            (mvccOpCntr & ~MVCC_HINTS_MASK) | ((int)txState << 
MVCC_HINTS_BIT_OFF));
     }
 
     /**
@@ -319,9 +323,9 @@ public class DataPageIO extends 
AbstractDataPageIO<CacheDataRow> {
 
         long addr = pageAddr + dataOff + (isFragmented(pageAddr, dataOff) ? 10 
: 2);
 
-        int opCntr = mvccOperationCounter(addr, 0);
+        int opCntr = rawMvccOperationCounter(addr, 0);
 
-        mvccOperationCounter(addr, 0, ((int)txState << MVCC_HINTS_BIT_OFF) | 
(opCntr & ~MVCC_HINTS_MASK));
+        rawMvccOperationCounter(addr, 0, ((int)txState << MVCC_HINTS_BIT_OFF) 
| (opCntr & ~MVCC_HINTS_MASK));
     }
 
     /**
@@ -335,9 +339,9 @@ public class DataPageIO extends 
AbstractDataPageIO<CacheDataRow> {
 
         long addr = pageAddr + dataOff + (isFragmented(pageAddr, dataOff) ? 10 
: 2);
 
-        int opCntr = newMvccOperationCounter(addr, 0);
+        int opCntr = rawNewMvccOperationCounter(addr, 0);
 
-        newMvccOperationCounter(addr, 0, ((int)txState << MVCC_HINTS_BIT_OFF) 
| (opCntr & ~MVCC_HINTS_MASK));
+        rawNewMvccOperationCounter(addr, 0, ((int)txState << 
MVCC_HINTS_BIT_OFF) | (opCntr & ~MVCC_HINTS_MASK));
     }
 
     /**
@@ -383,26 +387,26 @@ public class DataPageIO extends 
AbstractDataPageIO<CacheDataRow> {
     }
 
     /**
-     * Returns MVCC operation counter value.
+     * Returns MVCC operation counter raw value (with hints and flags).
      *
      * @param pageAddr Page address.
      * @param dataOff Data offset.
      * @return MVCC counter value.
      */
-    public int mvccOperationCounter(long pageAddr, int dataOff) {
+    public int rawMvccOperationCounter(long pageAddr, int dataOff) {
         long addr = pageAddr + dataOff;
 
         return PageUtils.getInt(addr, 16);
     }
 
     /**
-     * Sets MVCC operation counter value.
+     * Sets MVCC operation counter raw value (with hints and flags).
      *
      * @param pageAddr Page address.
      * @param dataOff Data offset.
      * @param opCntr MVCC counter value.
      */
-    public void mvccOperationCounter(long pageAddr, int dataOff, int opCntr) {
+    public void rawMvccOperationCounter(long pageAddr, int dataOff, int 
opCntr) {
         long addr = pageAddr + dataOff;
 
         PageUtils.putInt(addr, 16, opCntr);
@@ -441,13 +445,13 @@ public class DataPageIO extends 
AbstractDataPageIO<CacheDataRow> {
     }
 
     /**
-     * Returns MVCC operation counter value.
+     * Returns MVCC operation counter raw value (with hints and flags).
      *
      * @param pageAddr Page address.
      * @param dataOff Data offset.
      * @return MVCC counter value.
      */
-    public int newMvccOperationCounter(long pageAddr, int dataOff) {
+    public int rawNewMvccOperationCounter(long pageAddr, int dataOff) {
         long addr = pageAddr + dataOff;
 
         // Skip xid_min.
@@ -457,13 +461,13 @@ public class DataPageIO extends 
AbstractDataPageIO<CacheDataRow> {
     }
 
     /**
-     * Sets MVCC new operation counter value.
+     * Sets MVCC new operation counter raw value (with hints and flags).
      *
      * @param pageAddr Page address.
      * @param dataOff Data offset.
      * @param opCntr MVCC operation counter value.
      */
-    public void newMvccOperationCounter(long pageAddr, int dataOff, int 
opCntr) {
+    public void rawNewMvccOperationCounter(long pageAddr, int dataOff, int 
opCntr) {
         long addr = pageAddr + dataOff;
 
         // Skip xid_min.
diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/tree/mvcc/data/MvccDataRow.java
 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/tree/mvcc/data/MvccDataRow.java
index a3ee923..92f5aed 100644
--- 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/tree/mvcc/data/MvccDataRow.java
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/tree/mvcc/data/MvccDataRow.java
@@ -34,9 +34,8 @@ import org.apache.ignite.internal.util.typedef.internal.S;
 import static 
org.apache.ignite.internal.processors.cache.mvcc.MvccUtils.MVCC_COUNTER_NA;
 import static 
org.apache.ignite.internal.processors.cache.mvcc.MvccUtils.MVCC_CRD_COUNTER_NA;
 import static 
org.apache.ignite.internal.processors.cache.mvcc.MvccUtils.MVCC_HINTS_BIT_OFF;
-import static 
org.apache.ignite.internal.processors.cache.mvcc.MvccUtils.MVCC_HINTS_MASK;
 import static 
org.apache.ignite.internal.processors.cache.mvcc.MvccUtils.MVCC_KEY_ABSENT_BEFORE_MASK;
-import static 
org.apache.ignite.internal.processors.cache.mvcc.MvccUtils.MVCC_KEY_ABSENT_BEFORE_OFF;
+import static 
org.apache.ignite.internal.processors.cache.mvcc.MvccUtils.MVCC_OP_COUNTER_MASK;
 import static 
org.apache.ignite.internal.processors.cache.mvcc.MvccUtils.MVCC_OP_COUNTER_NA;
 import static 
org.apache.ignite.internal.processors.cache.persistence.tree.io.DataPageIO.MVCC_INFO_SIZE;
 
@@ -76,6 +75,10 @@ public class MvccDataRow extends DataRow {
     @GridToStringInclude
     private byte newMvccTxState;
 
+    /** Key absent before tx flag. */
+    @GridToStringInclude
+    private boolean keyAbsentFlag;
+
     /**
      * @param link Link.
      */
@@ -119,6 +122,8 @@ public class MvccDataRow extends DataRow {
             this.mvccCntr = mvccCntr;
             this.mvccOpCntr = mvccOpCntr;
         }
+
+        assert (mvccOpCntr & ~MVCC_OP_COUNTER_MASK) == 0: mvccOpCntr;
     }
 
     /**
@@ -146,6 +151,8 @@ public class MvccDataRow extends DataRow {
         this.mvccCntr = mvccVer.counter();
         this.mvccOpCntr = mvccVer.operationCounter();
 
+        assert (mvccOpCntr & ~MVCC_OP_COUNTER_MASK) == 0 : mvccOpCntr;
+
         if (newMvccVer == null) {
             newMvccCrd = MVCC_CRD_COUNTER_NA;
             newMvccCntr = MVCC_COUNTER_NA;
@@ -155,6 +162,8 @@ public class MvccDataRow extends DataRow {
             newMvccCrd = newMvccVer.coordinatorVersion();
             newMvccCntr = newMvccVer.counter();
             newMvccOpCntr = newMvccVer.operationCounter();
+
+            assert (newMvccOpCntr & ~MVCC_OP_COUNTER_MASK) == 0 : 
newMvccOpCntr;
         }
     }
 
@@ -166,22 +175,27 @@ public class MvccDataRow extends DataRow {
 
         int withHint = PageUtils.getInt(addr, off + 16);
 
-        mvccOpCntr = withHint & ~MVCC_HINTS_MASK;
+        mvccOpCntr = withHint & MVCC_OP_COUNTER_MASK;
         mvccTxState = (byte)(withHint >>> MVCC_HINTS_BIT_OFF);
 
         assert MvccUtils.mvccVersionIsValid(mvccCrd, mvccCntr, mvccOpCntr);
 
+        keyAbsentFlag = (withHint & MVCC_KEY_ABSENT_BEFORE_MASK) != 0;
+
         // xid_max.
         newMvccCrd = PageUtils.getLong(addr, off + 20);
         newMvccCntr = PageUtils.getLong(addr, off + 28);
 
         withHint = PageUtils.getInt(addr, off + 36);
 
-        newMvccOpCntr = withHint & ~MVCC_HINTS_MASK;
+        newMvccOpCntr = withHint & MVCC_OP_COUNTER_MASK;
         newMvccTxState = (byte)(withHint >>> MVCC_HINTS_BIT_OFF);
 
         assert newMvccCrd == MVCC_CRD_COUNTER_NA || 
MvccUtils.mvccVersionIsValid(newMvccCrd, newMvccCntr, newMvccOpCntr);
 
+        if (newMvccCrd != MVCC_CRD_COUNTER_NA)
+            keyAbsentFlag = (withHint & MVCC_KEY_ABSENT_BEFORE_MASK) != 0;
+
         return MVCC_INFO_SIZE;
     }
 
@@ -197,7 +211,9 @@ public class MvccDataRow extends DataRow {
 
     /** {@inheritDoc} */
     @Override public int mvccOperationCounter() {
-        return mvccOpCntr & ~MVCC_KEY_ABSENT_BEFORE_MASK;
+        assert (mvccCntr & ~MVCC_OP_COUNTER_MASK) == 0;
+
+        return mvccOpCntr;
     }
 
     /** {@inheritDoc} */
@@ -217,7 +233,7 @@ public class MvccDataRow extends DataRow {
 
     /** {@inheritDoc} */
     @Override public int newMvccOperationCounter() {
-        return newMvccOpCntr & ~MVCC_KEY_ABSENT_BEFORE_MASK;
+        return newMvccOpCntr;
     }
 
     /** {@inheritDoc} */
@@ -227,6 +243,8 @@ public class MvccDataRow extends DataRow {
 
     /** {@inheritDoc} */
     @Override public void newMvccVersion(long crd, long cntr, int opCntr) {
+        assert (opCntr & ~MVCC_OP_COUNTER_MASK) == 0 : opCntr;
+
         newMvccCrd = crd;
         newMvccCntr = cntr;
         newMvccOpCntr = opCntr;
@@ -237,6 +255,8 @@ public class MvccDataRow extends DataRow {
 
     /** {@inheritDoc} */
     @Override public void mvccVersion(long crd, long cntr, int opCntr) {
+        assert (opCntr & ~MVCC_OP_COUNTER_MASK) == 0 : opCntr;
+
         mvccCrd = crd;
         mvccCntr = cntr;
         mvccOpCntr = opCntr;
@@ -263,26 +283,14 @@ public class MvccDataRow extends DataRow {
      * @return {@code True} if key absent before.
      */
     protected boolean keyAbsentBeforeFlag() {
-        long withHint = newMvccCrd == MVCC_CRD_COUNTER_NA ? mvccOpCntr : 
newMvccOpCntr;
-
-        return ((withHint & MVCC_KEY_ABSENT_BEFORE_MASK) >>> 
MVCC_KEY_ABSENT_BEFORE_OFF) == 1;
+        return keyAbsentFlag;
     }
 
     /**
      * @param flag {@code True} if key is absent before.
      */
     protected void keyAbsentBeforeFlag(boolean flag) {
-        if (flag) {
-            if (mvccCrd != MVCC_CRD_COUNTER_NA)
-                mvccOpCntr |= MVCC_KEY_ABSENT_BEFORE_MASK;
-
-            if (newMvccCrd != MVCC_CRD_COUNTER_NA)
-                newMvccOpCntr |= MVCC_KEY_ABSENT_BEFORE_MASK;
-        }
-        else {
-            mvccOpCntr &= ~MVCC_KEY_ABSENT_BEFORE_MASK;
-            newMvccOpCntr &= ~MVCC_KEY_ABSENT_BEFORE_MASK;
-        }
+        keyAbsentFlag = flag;
     }
 
     /** {@inheritDoc} */
diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/tree/mvcc/data/MvccUpdateDataRow.java
 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/tree/mvcc/data/MvccUpdateDataRow.java
index 75c510b..d240cd0 100644
--- 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/tree/mvcc/data/MvccUpdateDataRow.java
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/tree/mvcc/data/MvccUpdateDataRow.java
@@ -300,13 +300,13 @@ public class MvccUpdateDataRow extends MvccDataRow 
implements MvccUpdateResult,
         long rowCntr = row.mvccCounter();
 
         // with hint bits
-        int rowOpCntr = (row.mvccTxState() << MVCC_HINTS_BIT_OFF) | 
(row.mvccOperationCounter() & ~MVCC_OP_COUNTER_MASK);
+        int rowOpCntr = row.mvccOperationCounter() | (row.mvccTxState() << 
MVCC_HINTS_BIT_OFF);
 
         long rowNewCrd = row.newMvccCoordinatorVersion();
         long rowNewCntr = row.newMvccCounter();
 
         // with hint bits
-        int rowNewOpCntr = (row.newMvccTxState() << MVCC_HINTS_BIT_OFF) | 
(row.newMvccOperationCounter() & ~MVCC_OP_COUNTER_MASK);
+        int rowNewOpCntr = row.newMvccOperationCounter() | 
(row.newMvccTxState() << MVCC_HINTS_BIT_OFF);
 
         // Search for youngest committed by another transaction row.
         if (!isFlagsSet(LAST_COMMITTED_FOUND)) {
@@ -456,7 +456,7 @@ public class MvccUpdateDataRow extends MvccDataRow 
implements MvccUpdateResult,
             if (cleanupRows == null)
                 cleanupRows = new ArrayList<>();
 
-            cleanupRows.add(new MvccLinkAwareSearchRow(cacheId, key, rowCrd, 
rowCntr, rowOpCntr & ~MVCC_OP_COUNTER_MASK, rowLink));
+            cleanupRows.add(new MvccLinkAwareSearchRow(cacheId, key, rowCrd, 
rowCntr, rowOpCntr & MVCC_OP_COUNTER_MASK, rowLink));
         }
         else {
             // Row obsoleted by current operation, all rows created or updated 
with current tx.
@@ -467,7 +467,7 @@ public class MvccUpdateDataRow extends MvccDataRow 
implements MvccUpdateResult,
                 if (histRows == null)
                     histRows = new ArrayList<>();
 
-                histRows.add(new MvccLinkAwareSearchRow(cacheId, key, rowCrd, 
rowCntr, rowOpCntr & ~MVCC_OP_COUNTER_MASK, rowLink));
+                histRows.add(new MvccLinkAwareSearchRow(cacheId, key, rowCrd, 
rowCntr, rowOpCntr & MVCC_OP_COUNTER_MASK, rowLink));
             }
 
             if (cleanupVer > MVCC_OP_COUNTER_NA // Do not clean if cleanup 
version is not assigned.
diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/tree/mvcc/search/MvccMaxSearchRow.java
 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/tree/mvcc/search/MvccMaxSearchRow.java
index f5f3b67..4bac120 100644
--- 
a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/tree/mvcc/search/MvccMaxSearchRow.java
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/tree/mvcc/search/MvccMaxSearchRow.java
@@ -18,6 +18,7 @@
 package org.apache.ignite.internal.processors.cache.tree.mvcc.search;
 
 import org.apache.ignite.internal.processors.cache.KeyCacheObject;
+import org.apache.ignite.internal.processors.cache.mvcc.MvccUtils;
 import org.apache.ignite.internal.processors.cache.tree.SearchRow;
 import org.apache.ignite.internal.util.typedef.internal.S;
 
@@ -45,7 +46,7 @@ public class MvccMaxSearchRow extends SearchRow {
 
     /** {@inheritDoc} */
     @Override public int mvccOperationCounter() {
-        return Integer.MAX_VALUE;
+        return MvccUtils.MVCC_READ_OP_CNTR;
     }
 
     /** {@inheritDoc} */
diff --git 
a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/CacheLateAffinityAssignmentTest.java
 
b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/CacheLateAffinityAssignmentTest.java
index 22d4831..294e8c8 100644
--- 
a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/CacheLateAffinityAssignmentTest.java
+++ 
b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/CacheLateAffinityAssignmentTest.java
@@ -2096,8 +2096,6 @@ public class CacheLateAffinityAssignmentTest extends 
GridCommonAbstractTest {
      */
     @Test
     public void testNoForceKeysRequests() throws Exception {
-        
Assume.assumeFalse("https://issues.apache.org/jira/browse/IGNITE-10604";, 
MvccFeatureChecker.forcedMvcc());
-
         cacheC = new IgniteClosure<String, CacheConfiguration[]>() {
             @Override public CacheConfiguration[] apply(String s) {
                 return null;
diff --git 
a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/mvcc/CacheMvccTransactionsTest.java
 
b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/mvcc/CacheMvccTransactionsTest.java
index a336097f..2542c50 100644
--- 
a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/mvcc/CacheMvccTransactionsTest.java
+++ 
b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/mvcc/CacheMvccTransactionsTest.java
@@ -3357,7 +3357,7 @@ public class CacheMvccTransactionsTest extends 
CacheMvccAbstractTest {
                 MvccVersion cntr = ver.get2();
 
                 MvccSnapshot readVer =
-                    new MvccSnapshotWithoutTxs(cntr.coordinatorVersion(), 
cntr.counter(), Integer.MAX_VALUE, 0);
+                    new MvccSnapshotWithoutTxs(cntr.coordinatorVersion(), 
cntr.counter(), MvccUtils.MVCC_READ_OP_CNTR, 0);
 
                 row = cctx.offheap().mvccRead(cctx, key0, readVer);
 
diff --git 
a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/mvcc/CacheMvccSqlUpdateCountersTest.java
 
b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/mvcc/CacheMvccSqlUpdateCountersTest.java
index 9ecd745..f6588c4 100644
--- 
a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/mvcc/CacheMvccSqlUpdateCountersTest.java
+++ 
b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/mvcc/CacheMvccSqlUpdateCountersTest.java
@@ -270,7 +270,15 @@ public class CacheMvccSqlUpdateCountersTest extends 
CacheMvccAbstractTest {
         checkUpdateCounters(DEFAULT_CACHE_NAME, part1, 2);
 
         try (Transaction tx = node.transactions().txStart(PESSIMISTIC, 
REPEATABLE_READ)) {
-            SqlFieldsQuery qry  = new SqlFieldsQuery("MERGE INTO Integer 
(_key, _val) values (" + key1 + ",5)");
+            SqlFieldsQuery qry  = new SqlFieldsQuery("INSERT INTO Integer 
(_key, _val) values (" + key1 + ", 2)");
+
+            cache.query(qry).getAll();
+
+            qry = new SqlFieldsQuery("DELETE FROM Integer WHERE _key=" + key1);
+
+            cache.query(qry).getAll();
+
+            qry  = new SqlFieldsQuery("MERGE INTO Integer (_key, _val) values 
(" + key1 + ", 3)");
 
             cache.query(qry).getAll();
 
@@ -312,7 +320,7 @@ public class CacheMvccSqlUpdateCountersTest extends 
CacheMvccAbstractTest {
 
             cache.query(qry).getAll();
 
-            qry  = new SqlFieldsQuery("MERGE INTO Integer (_key, _val) values 
(" + key1 + ",5)");
+            qry  = new SqlFieldsQuery("MERGE INTO Integer (_key, _val) values 
(" + key1 + ",7)");
 
             cache.query(qry).getAll();
 

Reply via email to