/*
 * 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.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.UUID;
import org.apache.ignite.configuration.CacheConfiguration;
import org.apache.ignite.configuration.IgniteConfiguration;
import org.apache.ignite.internal.IgniteKernal;
import org.apache.ignite.internal.processors.cache.version.GridCacheVersion;
import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
import org.jetbrains.annotations.Nullable;
import org.junit.Test;

import static org.apache.ignite.cache.CacheAtomicityMode.TRANSACTIONAL;
import static org.apache.ignite.cache.CacheMode.PARTITIONED;

/**
 * Test cases for multi-threaded tests in partitioned cache.
 */
public class GridCacheMvccPartitionedSelfTest extends GridCommonAbstractTest {
    /** */
    private static final UUID nodeId = UUID.randomUUID();

    /** Grid. */
    private IgniteKernal grid;

    /**
     *
     */
    public GridCacheMvccPartitionedSelfTest() {
        super(true /*start grid. */);
    }

    /** {@inheritDoc} */
    @Override protected void beforeTest() throws Exception {
        grid = (IgniteKernal)grid();
    }

    /** {@inheritDoc} */
    @Override protected void afterTest() throws Exception {
        grid = null;
    }

    /** {@inheritDoc} */
    @Override protected IgniteConfiguration getConfiguration() throws Exception {
        IgniteConfiguration cfg = super.getConfiguration();

        CacheConfiguration cacheCfg = defaultCacheConfiguration();

        cacheCfg.setCacheMode(PARTITIONED);
        cacheCfg.setBackups(1);
        cacheCfg.setAtomicityMode(TRANSACTIONAL);

        cfg.setCacheConfiguration(cacheCfg);

        return cfg;
    }

    /**
     * Tests remote candidates.
     */
    @Test
    public void testNearLocalsWithPending() {
        GridCacheAdapter<String, String> cache = grid.internalCache(DEFAULT_CACHE_NAME);

        GridCacheTestEntryEx entry = new GridCacheTestEntryEx(cache.context(), "1");

        UUID node1 = UUID.randomUUID();

        GridCacheVersion ver1 = version(1);
        GridCacheVersion ver2 = version(2);

        GridCacheMvccCandidate c1 = entry.addRemote(node1, 1, ver1, true);
        GridCacheMvccCandidate c2 = entry.addNearLocal(node1, 1, ver2, true);

        Collection<GridCacheMvccCandidate> rmtCands = entry.remoteMvccSnapshot();
        Collection<GridCacheMvccCandidate> nearLocCands = entry.localCandidates();

        assertEquals(1, nearLocCands.size());
        assertEquals(ver2, nearLocCands.iterator().next().version());

        assertEquals(1, rmtCands.size());
        assertEquals(ver1, rmtCands.iterator().next().version());

        entry.readyNearLocal(ver2, ver2, empty(), empty(), Arrays.asList(ver1));

        checkLocalOwner(c2, ver2, false);
        checkRemote(c1, ver1, false, false);

        assertNotNull(entry.anyOwner());
        assertEquals(ver2, entry.anyOwner().version());
    }

    /**
     * Tests remote candidates.
     */
    @Test
    public void testNearLocalsWithCommitted() {
        GridCacheAdapter<String, String> cache = grid.internalCache(DEFAULT_CACHE_NAME);

        GridCacheTestEntryEx entry = new GridCacheTestEntryEx(cache.context(), "1");

        UUID node1 = UUID.randomUUID();

        GridCacheVersion ver1 = version(1);
        GridCacheVersion ver2 = version(2);

        GridCacheMvccCandidate c1 = entry.addNearLocal(node1, 1, ver1, true);
        GridCacheMvccCandidate c2 = entry.addRemote(node1, 1, ver2, true);

        Collection<GridCacheMvccCandidate> rmtCands = entry.remoteMvccSnapshot();
        Collection<GridCacheMvccCandidate> nearLocCands = entry.localCandidates();

        assertEquals(1, nearLocCands.size());
        assertEquals(ver1, nearLocCands.iterator().next().version());

        assertEquals(1, rmtCands.size());
        assertEquals(ver2, rmtCands.iterator().next().version());

        entry.readyNearLocal(ver1, ver1, Arrays.asList(ver2), empty(), empty());

        checkLocal(c1, ver1, true, false, false);
        checkRemote(c2, ver2, true, false);

        assertNull(entry.anyOwner());
    }

    /**
     * Tests remote candidates.
     */
    @Test
    public void testNearLocalsWithRolledback() {
        GridCacheAdapter<String, String> cache = grid.internalCache(DEFAULT_CACHE_NAME);

        GridCacheTestEntryEx entry = new GridCacheTestEntryEx(cache.context(), "1");

        UUID node1 = UUID.randomUUID();

        GridCacheVersion ver1 = version(1);
        GridCacheVersion ver2 = version(2);

        GridCacheMvccCandidate c1 = entry.addNearLocal(node1, 1, ver1, true);
        GridCacheMvccCandidate c2 = entry.addRemote(node1, 1, ver2, true);

        Collection<GridCacheMvccCandidate> rmtCands = entry.remoteMvccSnapshot();
        Collection<GridCacheMvccCandidate> nearLocCands = entry.localCandidates();

        assertEquals(1, nearLocCands.size());
        assertEquals(ver1, nearLocCands.iterator().next().version());

        assertEquals(1, rmtCands.size());
        assertEquals(ver2, rmtCands.iterator().next().version());

        entry.readyNearLocal(ver1, ver1, empty(), Arrays.asList(ver2), empty());

        checkLocal(c1, ver1, true, false, false);
        checkRemote(c2, ver2, true, false);

        assertNull(entry.anyOwner());
    }

    /**
     * Tests remote candidates.
     */
    @Test
    public void testNearLocals() {
        GridCacheAdapter<String, String> cache = grid.internalCache(DEFAULT_CACHE_NAME);

        GridCacheTestEntryEx entry = new GridCacheTestEntryEx(cache.context(), "1");

        UUID node1 = UUID.randomUUID();

        GridCacheVersion ver1 = version(1);
        GridCacheVersion ver2 = version(2);

        GridCacheMvccCandidate c1 = entry.addNearLocal(node1, 1, ver1, true);
        GridCacheMvccCandidate c2 = entry.addNearLocal(node1, 1, ver2, true);

        entry.readyNearLocal(ver2, ver2, empty(), empty(), empty());

        checkLocalOwner(c2, ver2, false);
        checkLocal(c1, ver1, false, false, false);

        Collection<GridCacheMvccCandidate> cands = entry.localCandidates();

        assert cands.size() == 2;
        assert cands.iterator().next().version().equals(ver2);

        checkLocalOwner(c2, ver2, false);
        checkLocal(c1, ver1, false, false, false);
    }

    /**
     * Tests remote candidates.
     */
    @Test
    public void testNearLocalsWithOwned() {
        GridCacheAdapter<String, String> cache = grid.internalCache(DEFAULT_CACHE_NAME);

        GridCacheTestEntryEx entry = new GridCacheTestEntryEx(cache.context(), "1");

        UUID node1 = UUID.randomUUID();

        GridCacheVersion ver1 = version(1);
        GridCacheVersion ver2 = version(2);

        GridCacheMvccCandidate c1 = entry.addRemote(node1, 1, ver1, true);
        GridCacheMvccCandidate c2 = entry.addNearLocal(node1, 1, ver2, true);

        Collection<GridCacheMvccCandidate> rmtCands = entry.remoteMvccSnapshot();
        Collection<GridCacheMvccCandidate> nearLocCands = entry.localCandidates();

        assertEquals(1, nearLocCands.size());
        assertEquals(ver2, nearLocCands.iterator().next().version());

        assertEquals(1, rmtCands.size());
        assertEquals(ver1, rmtCands.iterator().next().version());

        entry.orderOwned(ver1, ver2);

        entry.readyNearLocal(ver2, ver2, empty(), empty(), empty());

        checkRemote(c1, ver1, false, false);

        assertFalse(c1.owner());

        checkLocalOwner(c2, ver2, false);

        assertNotNull(entry.anyOwner());
        assertEquals(ver2, entry.anyOwner().version());
    }

    /**
     * @throws Exception If failed.
     */
    @Test
    public void testAddPendingRemote0() throws Exception {
        GridCacheAdapter<String, String> cache = grid.internalCache(DEFAULT_CACHE_NAME);

        GridCacheTestEntryEx entry = new GridCacheTestEntryEx(cache.context(), "1");

        UUID node1 = UUID.randomUUID();

        GridCacheVersion ver0 = version(0);
        GridCacheVersion ver1 = version(1);

        entry.addNearLocal(node1, 1, ver1, true);

        entry.readyNearLocal(ver1, ver1, empty(), empty(), Collections.singletonList(ver0));

        entry.addRemote(node1, 1, ver0, true);

        Collection<GridCacheMvccCandidate> rmtCands = entry.remoteMvccSnapshot();
        Collection<GridCacheMvccCandidate> nearLocCands = entry.localCandidates();

        assertEquals(1, nearLocCands.size());
        assertEquals(ver1, nearLocCands.iterator().next().version());

        assertEquals(1, rmtCands.size());
        assertEquals(ver0, rmtCands.iterator().next().version());

        assertNotNull(entry.anyOwner());
        assertEquals(ver1, entry.anyOwner().version());
    }

    /**
     * @throws Exception If failed.
     */
    @Test
    public void testAddPendingRemote1() throws Exception {
        GridCacheAdapter<String, String> cache = grid.internalCache(DEFAULT_CACHE_NAME);

        GridCacheTestEntryEx entry = new GridCacheTestEntryEx(cache.context(), "1");

        UUID node1 = UUID.randomUUID();

        GridCacheVersion ver0 = version(0);
        GridCacheVersion ver1 = version(1);
        GridCacheVersion ver2 = version(2);
        GridCacheVersion ver3 = version(3);

        GridCacheMvccCandidate c3 = entry.addNearLocal(node1, 1, ver3, true);

        entry.readyNearLocal(ver3, ver3, empty(), empty(), Arrays.asList(ver0, ver1, ver2));

        GridCacheMvccCandidate c2 = entry.addRemote(node1, 1, ver2, true);
        GridCacheMvccCandidate c1 = entry.addRemote(node1, 1, ver1, true);
        GridCacheMvccCandidate c0 = entry.addRemote(node1, 1, ver0, true);

        Collection<GridCacheMvccCandidate> rmtCands = entry.remoteMvccSnapshot();

        assert rmtCands.size() == 3;

        // DHT remote candidates are not reordered and sorted.
        GridCacheMvccCandidate[] candArr = new GridCacheMvccCandidate[] {c2, c1, c0};

        rmtCands = entry.remoteMvccSnapshot();

        int i = 0;

        for (GridCacheMvccCandidate cand : rmtCands) {
            assert cand == candArr[i] : "Invalid candidate in position " + i;

            i++;
        }

        assertEquals(c3, entry.anyOwner());
    }

    /**
     * @throws Exception If failed.
     */
    @Test
    public void testAddPendingRemote2() throws Exception {
        GridCacheAdapter<String, String> cache = grid.internalCache(DEFAULT_CACHE_NAME);

        GridCacheTestEntryEx entry = new GridCacheTestEntryEx(cache.context(), "1");

        UUID node1 = UUID.randomUUID();

        GridCacheVersion ver0 = version(0);
        GridCacheVersion ver1 = version(1);
        GridCacheVersion ver2 = version(2);
        GridCacheVersion ver3 = version(3);

        GridCacheMvccCandidate c3 = entry.addNearLocal(node1, 1, ver3, true);
        entry.addNearLocal(node1, 1, ver2, true);

        entry.readyNearLocal(ver3, ver3, empty(), empty(), Arrays.asList(ver0, ver1, ver2));

        GridCacheMvccCandidate c1 = entry.addRemote(node1, 1, ver1, true);
        GridCacheMvccCandidate c0 = entry.addRemote(node1, 1, ver0, true);

        Collection<GridCacheMvccCandidate> rmtCands = entry.remoteMvccSnapshot();

        assertEquals(2, rmtCands.size());

        Collection<GridCacheMvccCandidate> nearLocCands = entry.localCandidates();

        assertEquals(2, nearLocCands.size());

        GridCacheMvccCandidate[] candArr = new GridCacheMvccCandidate[] {c1, c0};

        int i = 0;

        for (GridCacheMvccCandidate cand : rmtCands) {
            assert cand == candArr[i] : "Invalid candidate in position " + i;

            i++;
        }

        assertEquals(c3, entry.anyOwner());
    }

    /**
     * Tests salvageRemote method
     */
    @Test
    public void testSalvageRemote() {
        GridCacheAdapter<String, String> cache = grid.internalCache(DEFAULT_CACHE_NAME);

        GridCacheTestEntryEx entry = new GridCacheTestEntryEx(cache.context(), "1");

        UUID node1 = UUID.randomUUID();

        GridCacheVersion ver1 = version(1);
        GridCacheVersion ver2 = version(2);
        GridCacheVersion ver3 = version(3);
        GridCacheVersion ver4 = version(4);
        GridCacheVersion ver5 = version(5);
        GridCacheVersion ver6 = version(6);

        entry.addRemote(node1, 1, ver1, true);
        entry.addRemote(node1, 1, ver2, true);
        GridCacheMvccCandidate c3 = entry.addNearLocal(node1, 1, ver3, true);
        GridCacheMvccCandidate c4 = entry.addRemote(node1, 1, ver4, true);
        entry.addRemote(node1, 1, ver5, true);
        entry.addRemote(node1, 1, ver6, true);

        Collection<GridCacheMvccCandidate> rmtCands = entry.remoteMvccSnapshot();

        assertEquals(5, rmtCands.size());
        assertEquals(ver1, rmtCands.iterator().next().version());

        Collection<GridCacheMvccCandidate> nearLocCands = entry.localCandidates();

        assertEquals(1, nearLocCands.size());
        assertEquals(ver3, nearLocCands.iterator().next().version());

        entry.salvageRemote(ver4);

        rmtCands = entry.remoteMvccSnapshot();

        boolean before = true;

        for (GridCacheMvccCandidate cand : rmtCands) {
            if (cand == c4) {
                before = false;

                continue;
            }

            if (before && cand != c3) {
                assertTrue(cand.owner());
                assertTrue(cand.used());
            }
            else {
                assertFalse(cand.owner());
                assertFalse(cand.used());
            }
        }
    }

    /**
     * @throws Exception If failed.
     */
    @Test
    public void testNearRemoteConsistentOrdering0() throws Exception {
        GridCacheAdapter<String, String> cache = grid.internalCache(DEFAULT_CACHE_NAME);

        GridCacheTestEntryEx entry = new GridCacheTestEntryEx(cache.context(), "1");

        UUID node1 = UUID.randomUUID();

        GridCacheVersion ver1 = version(10);
        GridCacheVersion nearVer2 = version(5);
        GridCacheVersion ver2 = version(20);
        GridCacheVersion ver3 = version(30);

        entry.addRemote(node1, 1, ver1, true);
        entry.addNearLocal(node1, 1, nearVer2, true);
        entry.addRemote(node1, 1, ver3, true);

        Collection<GridCacheMvccCandidate> rmtCands = entry.remoteMvccSnapshot();
        Collection<GridCacheMvccCandidate> nearLocCands = entry.localCandidates();

        assertEquals(1, nearLocCands.size());
        assertEquals(nearVer2, nearLocCands.iterator().next().version());

        assertEquals(2, rmtCands.size());
        assertEquals(ver1, rmtCands.iterator().next().version());

        entry.readyNearLocal(nearVer2, ver2, empty(), empty(), empty());

        assertNull(entry.anyOwner());

        rmtCands = entry.remoteMvccSnapshot();

        assertEquals(ver1, rmtCands.iterator().next().version());
        assertTrue(rmtCands.iterator().next().owner());
    }

    /**
     * @throws Exception If failed.
     */
    @Test
    public void testNearRemoteConsistentOrdering1() throws Exception {
        GridCacheAdapter<String, String> cache = grid.internalCache(DEFAULT_CACHE_NAME);

        GridCacheTestEntryEx entry = new GridCacheTestEntryEx(cache.context(), "1");

        UUID node1 = UUID.randomUUID();

        GridCacheVersion ver1 = version(10);
        GridCacheVersion nearVer2 = version(5);
        GridCacheVersion ver2 = version(20);
        GridCacheVersion ver3 = version(30);

        entry.addRemote(node1, 1, ver1, true);
        entry.addNearLocal(node1, 1, nearVer2, true);
        entry.addRemote(node1, 1, ver3, true);

        Collection<GridCacheMvccCandidate> rmtCands = entry.remoteMvccSnapshot();
        Collection<GridCacheMvccCandidate> nearLocCands = entry.localCandidates();

        assertEquals(1, nearLocCands.size());
        assertEquals(nearVer2, nearLocCands.iterator().next().version());

        assertEquals(2, rmtCands.size());
        assertEquals(ver1, rmtCands.iterator().next().version());

        entry.orderCompleted(nearVer2, Arrays.asList(ver3), empty());
        entry.readyNearLocal(nearVer2, ver2, empty(), empty(), Arrays.asList(ver1));

        nearLocCands = entry.localCandidates();
        rmtCands = entry.remoteMvccSnapshot();

        assertNull(entry.anyOwner());
        assertEquals(ver3, rmtCands.iterator().next().version());
        assertTrue(rmtCands.iterator().next().owner());

        GridCacheMvccCandidate cand = nearLocCands.iterator().next();

        assertTrue(cand.ready());
        assertFalse(cand.owner());
        assertFalse(cand.used());
    }

    /**
     * @throws Exception If failed.
     */
    @Test
    public void testNearRemoteConsistentOrdering2() throws Exception {
        GridCacheAdapter<String, String> cache = grid.internalCache(DEFAULT_CACHE_NAME);

        GridCacheTestEntryEx entry = new GridCacheTestEntryEx(cache.context(), "1");

        UUID node1 = UUID.randomUUID();

        GridCacheVersion ver1 = version(10);
        GridCacheVersion nearVer2 = version(5);
        GridCacheVersion ver2 = version(20);
        GridCacheVersion ver3 = version(30);

        entry.addRemote(node1, 1, ver1, true);
        entry.addNearLocal(node1, 1, nearVer2, true);
        entry.addRemote(node1, 1, ver3, true);

        Collection<GridCacheMvccCandidate> rmtCands = entry.remoteMvccSnapshot();
        Collection<GridCacheMvccCandidate> nearLocCands = entry.localCandidates();

        assertEquals(1, nearLocCands.size());
        assertEquals(nearVer2, nearLocCands.iterator().next().version());

        assertEquals(2, rmtCands.size());
        assertEquals(ver1, rmtCands.iterator().next().version());

        entry.orderCompleted(nearVer2, empty(), empty());
        entry.readyNearLocal(nearVer2, ver2, empty(), empty(), empty());

        nearLocCands = entry.localCandidates();
        rmtCands = entry.remoteMvccSnapshot();

        assertNull(entry.anyOwner());
        assertEquals(ver1, rmtCands.iterator().next().version());
        assertTrue(rmtCands.iterator().next().owner());

        GridCacheMvccCandidate cand = nearLocCands.iterator().next();

        assertTrue(cand.ready());
        assertFalse(cand.used());
        assertFalse(cand.owner());
    }

    /**
     * @throws Exception If failed.
     */
    @Test
    public void testNearRemoteConsistentOrdering3() throws Exception {
        GridCacheAdapter<String, String> cache = grid.internalCache(DEFAULT_CACHE_NAME);

        GridCacheTestEntryEx entry = new GridCacheTestEntryEx(cache.context(), "1");

        UUID node1 = UUID.randomUUID();

        GridCacheVersion ver1 = version(10);
        GridCacheVersion nearVer2 = version(5);
        GridCacheVersion ver2 = version(20);
        GridCacheVersion ver3 = version(30);

        entry.addRemote(node1, 1, ver1, true);
        entry.addNearLocal(node1, 1, nearVer2, true);
        entry.addRemote(node1, 1, ver3, true);

        Collection<GridCacheMvccCandidate> rmtCands = entry.remoteMvccSnapshot();
        Collection<GridCacheMvccCandidate> nearLocCands = entry.localCandidates();

        assertEquals(1, nearLocCands.size());
        assertEquals(nearVer2, nearLocCands.iterator().next().version());

        assertEquals(2, rmtCands.size());
        assertEquals(ver1, rmtCands.iterator().next().version());

        entry.orderCompleted(nearVer2, empty(), empty());
        entry.readyNearLocal(nearVer2, ver2, empty(), empty(), Arrays.asList(ver1));

        rmtCands = entry.remoteMvccSnapshot();

        assertNotNull(entry.anyOwner());
        checkLocalOwner(entry.anyOwner(), nearVer2, false);

        assertEquals(ver1, rmtCands.iterator().next().version());
    }

    /**
     * @throws Exception If failed.
     */
    @Test
    public void testSerializableReadLocksAdd() throws Exception {
        GridCacheAdapter<String, String> cache = grid.internalCache(DEFAULT_CACHE_NAME);

        GridCacheVersion serOrder1 = new GridCacheVersion(0, 10, 1);
        GridCacheVersion serOrder2 = new GridCacheVersion(0, 20, 1);
        GridCacheVersion serOrder3 = new GridCacheVersion(0, 15, 1);

        {
            GridCacheMvcc mvcc = new GridCacheMvcc(cache.context());

            GridCacheTestEntryEx e = new GridCacheTestEntryEx(cache.context(), "1");

            GridCacheMvccCandidate cand1 = addLocal(mvcc, e, version(1), serOrder1, true);

            assertNotNull(cand1);

            GridCacheMvccCandidate cand2 = addLocal(mvcc, e, version(2), serOrder2, true);

            assertNotNull(cand2);

            GridCacheMvccCandidate cand3 = addLocal(mvcc, e, version(3), serOrder3, false);

            assertNull(cand3);

            cand3 = addLocal(mvcc, e, version(3), serOrder3, true);

            assertNotNull(cand3);
        }

        {
            GridCacheMvcc mvcc = new GridCacheMvcc(cache.context());

            GridCacheTestEntryEx e = new GridCacheTestEntryEx(cache.context(), "1");

            GridCacheMvccCandidate cand1 = addLocal(mvcc, e, version(1), serOrder2, true);

            assertNotNull(cand1);

            GridCacheMvccCandidate cand2 = addLocal(mvcc, e, version(2), serOrder1, true);

            assertNotNull(cand2);

            GridCacheMvccCandidate cand3 = addLocal(mvcc, e, version(3), serOrder3, false);

            assertNull(cand3);

            cand3 = addLocal(mvcc, e, version(3), serOrder3, true);

            assertNotNull(cand3);
        }

        {
            GridCacheMvcc mvcc = new GridCacheMvcc(cache.context());

            GridCacheTestEntryEx e = new GridCacheTestEntryEx(cache.context(), "1");

            GridCacheMvccCandidate cand1 = addLocal(mvcc, e, version(1), serOrder3, false);

            assertNotNull(cand1);

            GridCacheMvccCandidate cand2 = addLocal(mvcc, e, version(2), serOrder2, true);

            assertNotNull(cand2);

            GridCacheMvccCandidate cand3 = addLocal(mvcc, e, version(3), serOrder1, true);

            assertNull(cand3);

            cand3 = addLocal(mvcc, e, version(3), serOrder1, false);

            assertNull(cand3);
        }
    }

    /**
     * @throws Exception If failed.
     */
    @Test
    public void testSerializableReadLocksAssign() throws Exception {
        GridCacheAdapter<String, String> cache = grid.internalCache(DEFAULT_CACHE_NAME);

        GridCacheVersion serOrder1 = new GridCacheVersion(0, 10, 1);
        GridCacheVersion serOrder2 = new GridCacheVersion(0, 20, 1);
        GridCacheVersion serOrder3 = new GridCacheVersion(0, 15, 1);

        {
            GridCacheMvcc mvcc = new GridCacheMvcc(cache.context());

            GridCacheTestEntryEx e = new GridCacheTestEntryEx(cache.context(), "1");

            GridCacheMvccCandidate cand1 = addLocal(mvcc, e, version(1), serOrder1, true);

            assertNotNull(cand1);

            GridCacheMvccCandidate cand2 = addLocal(mvcc, e, version(2), serOrder2, true);

            assertNotNull(cand2);

            GridCacheMvccCandidate cand3 = addLocal(mvcc, e, version(3), serOrder3, false);

            assertNull(cand3);

            cand3 = addLocal(mvcc, e, version(3), serOrder3, true);

            assertNotNull(cand3);

            CacheLockCandidates owners = mvcc.recheck();

            assertNull(owners);

            cand1.setReady();

            owners = mvcc.recheck();

            assertSame(cand1, owners);
            checkCandidates(owners, cand1.version());

            cand2.setReady();

            owners = mvcc.recheck();
            checkCandidates(owners, cand1.version(), cand2.version());

            mvcc.remove(cand1.version());

            owners = mvcc.recheck();
            assertSame(cand2, owners);
            checkCandidates(owners, cand2.version());
        }

        {
            GridCacheMvcc mvcc = new GridCacheMvcc(cache.context());

            GridCacheTestEntryEx e = new GridCacheTestEntryEx(cache.context(), "1");

            GridCacheMvccCandidate cand1 = addLocal(mvcc, e, version(1), serOrder1, true);

            assertNotNull(cand1);

            GridCacheMvccCandidate cand2 = addLocal(mvcc, e, version(2), serOrder2, true);

            assertNotNull(cand2);

            GridCacheMvccCandidate cand3 = addLocal(mvcc, e, version(3), serOrder3, false);

            assertNull(cand3);

            cand3 = addLocal(mvcc, e, version(3), serOrder3, true);

            assertNotNull(cand3);

            CacheLockCandidates owners = mvcc.recheck();

            assertNull(owners);

            cand2.setReady();

            owners = mvcc.recheck();

            assertSame(cand2, owners);
            checkCandidates(owners, cand2.version());

            cand1.setReady();

            owners = mvcc.recheck();
            checkCandidates(owners, cand1.version(), cand2.version());

            mvcc.remove(cand2.version());

            owners = mvcc.recheck();
            assertSame(cand1, owners);
            checkCandidates(owners, cand1.version());
        }
    }

    /**
     * @param all Candidates list.
     * @param vers Expected candidates.
     */
    private void checkCandidates(CacheLockCandidates all, GridCacheVersion...vers) {
        assertNotNull(all);
        assertEquals(vers.length, all.size());

        for (GridCacheVersion ver : vers)
            assertTrue(all.hasCandidate(ver));
    }

    /**
     * @param mvcc Mvcc.
     * @param e Entry.
     * @param ver Version.
     * @param serOrder Serializable tx version.
     * @param read Read lock flag.
     * @return Candidate.
     */
    @Nullable private GridCacheMvccCandidate addLocal(GridCacheMvcc mvcc,
        GridCacheEntryEx e,
        GridCacheVersion ver,
        GridCacheVersion serOrder,
        boolean read) {
        return mvcc.addLocal(e,
            nodeId,
            null,
            1,
            ver,
            0,
            serOrder,
            false,
            true,
            false,
            true,
            read
        );
    }

    /**
     * @throws Exception If failed.
     */
    @Test
    public void testSerializableLocks() throws Exception {
        checkSerializableAdd(false);

        checkSerializableAdd(true);

        checkNonSerializableConflict();
    }

    /**
     * @throws Exception If failed.
     */
    private void checkNonSerializableConflict() throws Exception {
        GridCacheAdapter<String, String> cache = grid.internalCache(DEFAULT_CACHE_NAME);

        UUID nodeId = UUID.randomUUID();

        GridCacheMvcc mvcc = new GridCacheMvcc(cache.context());

        GridCacheTestEntryEx e = new GridCacheTestEntryEx(cache.context(), "1");

        GridCacheMvccCandidate cand1 = mvcc.addLocal(e,
            nodeId,
            null,
            1,
            version(1),
            0,
            null,
            false,
            true,
            false,
            true,
            false
        );

        assertNotNull(cand1);

        GridCacheMvccCandidate cand2 = mvcc.addLocal(e,
            nodeId,
            null,
            1,
            version(2),
            0,
            new GridCacheVersion(0, 0, 1),
            false,
            true,
            false,
            true,
            false
        );

        assertNull(cand2);
    }

    /**
     * @param incVer If {@code true} lock version is incremented.
     * @throws Exception If failed.
     */
    private void checkSerializableAdd(boolean incVer) throws Exception {
        GridCacheAdapter<String, String> cache = grid.internalCache(DEFAULT_CACHE_NAME);

        UUID nodeId = UUID.randomUUID();

        GridCacheMvcc mvcc = new GridCacheMvcc(cache.context());

        GridCacheTestEntryEx e = new GridCacheTestEntryEx(cache.context(), "1");

        GridCacheVersion serOrder1 = new GridCacheVersion(0, 10, 1);
        GridCacheVersion serOrder2 = new GridCacheVersion(0, 20, 1);
        GridCacheVersion serOrder3 = new GridCacheVersion(0, 15, 1);
        GridCacheVersion serOrder4 = new GridCacheVersion(0, 30, 1);

        GridCacheVersion ver1 = incVer ? version(1) : version(4);
        GridCacheVersion ver2 = incVer ? version(2) : version(3);
        GridCacheVersion ver3 = incVer ? version(3) : version(2);
        GridCacheVersion ver4 = incVer ? version(4) : version(1);

        GridCacheMvccCandidate cand1 = mvcc.addLocal(e,
            nodeId,
            null,
            1,
            ver1,
            0,
            serOrder1,
            false,
            true,
            false,
            true,
            false
            );

        assertNotNull(cand1);

        GridCacheMvccCandidate cand2 = mvcc.addLocal(e,
            nodeId,
            null,
            2,
            ver2,
            0,
            serOrder2,
            false,
            true,
            false,
            true,
            false
        );

        assertNotNull(cand2);

        GridCacheMvccCandidate cand3 = mvcc.addLocal(e,
            nodeId,
            null,
            3,
            ver3,
            0,
            serOrder3,
            false,
            true,
            false,
            true,
            false
        );

        assertNull(cand3);

        GridCacheMvccCandidate cand4 = mvcc.addLocal(e,
            nodeId,
            null,
            4,
            ver4,
            0,
            serOrder4,
            false,
            true,
            false,
            true,
            false
        );

        assertNotNull(cand4);

        CacheLockCandidates owners = mvcc.recheck();

        assertNull(owners);

        cand2.setReady();

        owners = mvcc.recheck();

        assertNull(owners);

        cand1.setReady();

        owners = mvcc.recheck();

        assertSame(cand1, owners);

        owners = mvcc.recheck();

        assertSame(cand1, owners);

        mvcc.remove(cand1.version());

        owners = mvcc.recheck();

        assertSame(cand2, owners);
    }

    /**
     * Gets version based on order.
     *
     * @param order Order.
     * @return Version.
     */
    private GridCacheVersion version(int order) {
        return new GridCacheVersion(1, order, order, 0);
    }

    /**
     * Creates an empty list of {@code GridCacheVersion}.
     *
     * @return Empty list.
     */
    private Collection<GridCacheVersion> empty() {
        return Collections.emptyList();
    }

    /**
     * Checks flags on local owner candidate.
     *
     * @param cand Candidate to check.
     * @param ver Cache version.
     * @param reentry Reentry flag.
     */
    private void checkLocalOwner(GridCacheMvccCandidate cand, GridCacheVersion ver, boolean reentry) {
        assert cand != null;

        info("Done candidate: " + cand);

        assert cand.version().equals(ver);

        // Check flags.
        assert cand.reentry() == reentry;

        assert !cand.used();

        assert cand.ready();
        assert cand.owner();
        assert cand.local();
    }

    /**
     * @param cand Candidate to check.
     * @param ver Version.
     * @param owner Owner flag.
     * @param used Done flag.
     */
    private void checkRemote(GridCacheMvccCandidate cand, GridCacheVersion ver, boolean owner, boolean used) {
        assert cand != null;

        info("Done candidate: " + cand);

        assert cand.version().equals(ver);

        // Check flags.
        assert cand.used() == used;
        assert cand.owner() == owner;

        assert !cand.ready();
        assert !cand.reentry();
        assert !cand.local();
    }

    /**
     * Checks flags on local candidate.
     *
     * @param cand Candidate to check.
     * @param ver Cache version.
     * @param ready Ready flag.
     * @param owner Lock owner.
     * @param reentry Reentry flag.
     */
    private void checkLocal(GridCacheMvccCandidate cand, GridCacheVersion ver, boolean ready,
        boolean owner, boolean reentry) {
        assert cand != null;

        info("Done candidate: " + cand);

        assert cand.version().equals(ver);

        // Check flags.
        assert cand.ready() == ready;
        assert cand.owner() == owner;
        assert cand.reentry() == reentry;

        assert !cand.used();

        assert cand.local();
    }
}
