Search in sources :

Example 1 with PartitionUpdateCounter

use of org.apache.ignite.internal.processors.cache.PartitionUpdateCounter in project ignite by apache.

the class TxPartitionCounterStateConsistencyTest method testPartitionConsistencyDuringRebalanceAndConcurrentUpdates_LateAffinitySwitch.

/**
 * Tests tx load concurrently with PME for switching late affinity.
 * <p>
 * Scenario: two keys tx mapped locally on late affinity topology and when mapped and prepared remotely on ideal
 * topology, first key is mapped to non-moving partition, second is mapped on moving partition.
 * <p>
 * Success: key over moving partition is prepared on new owner (choosed after late affinity switch),
 * otherwise it's possible txs are prepared on different primaries after late affinity switch.
 */
@Test
public void testPartitionConsistencyDuringRebalanceAndConcurrentUpdates_LateAffinitySwitch() throws Exception {
    backups = 1;
    customDiscoSpi = new BlockTcpDiscoverySpi().setIpFinder(IP_FINDER);
    Field rndAddrsField = U.findField(BlockTcpDiscoverySpi.class, "skipAddrsRandomization");
    assertNotNull(rndAddrsField);
    rndAddrsField.set(customDiscoSpi, true);
    // Start coordinator with custom discovery SPI.
    IgniteEx crd = startGrid(0);
    IgniteEx g1 = startGrid(1);
    startGrid(2);
    crd.cluster().baselineAutoAdjustEnabled(false);
    crd.cluster().active(true);
    // Same name pattern as in test configuration.
    String consistentId = "node" + getTestIgniteInstanceName(3);
    List<Integer> g1Keys = primaryKeys(g1.cache(DEFAULT_CACHE_NAME), 10);
    List<Integer> movingFromG1 = movingKeysAfterJoin(g1, DEFAULT_CACHE_NAME, 10, null, consistentId);
    // Retain only stable keys;
    g1Keys.removeAll(movingFromG1);
    // The key will move from grid0 to grid3.
    Integer key = movingKeysAfterJoin(crd, DEFAULT_CACHE_NAME, 1, null, consistentId).get(0);
    IgniteEx g3 = startGrid(3);
    assertEquals(consistentId, g3.localNode().consistentId());
    resetBaselineTopology();
    awaitPartitionMapExchange();
    assertTrue(crd.affinity(DEFAULT_CACHE_NAME).isPrimary(g1.localNode(), g1Keys.get(0)));
    stopGrid(3);
    Ignite client = startClientGrid(CLIENT_GRID_NAME);
    IgniteCache<Object, Object> cache = client.cache(DEFAULT_CACHE_NAME);
    IgniteCache<Object, Object> cache2 = client.getOrCreateCache(cacheConfiguration(DEFAULT_CACHE_NAME + "2"));
    // Put one key per partition.
    for (int k = 0; k < partitions(); k++) {
        cache.put(k, 0);
        cache2.put(k, 0);
    }
    CountDownLatch resumeDiscoSndLatch = new CountDownLatch(1);
    BlockTcpDiscoverySpi crdDiscoSpi = (BlockTcpDiscoverySpi) grid(0).configuration().getDiscoverySpi();
    CyclicBarrier sync = new CyclicBarrier(2);
    crdDiscoSpi.setClosure((node, msg) -> {
        if (msg instanceof CacheAffinityChangeMessage) {
            U.awaitQuiet(sync);
            U.awaitQuiet(resumeDiscoSndLatch);
        }
        return null;
    });
    // Locks mapped wait.
    IgniteInternalFuture fut = GridTestUtils.runAsync(() -> {
        try {
            startGrid(SERVER_NODES);
            awaitPartitionMapExchange();
        } catch (Exception e) {
            fail(X.getFullStackTrace(e));
        }
    });
    sync.await();
    TestRecordingCommunicationSpi clientSpi = TestRecordingCommunicationSpi.spi(client);
    clientSpi.blockMessages((node, msg) -> msg instanceof GridNearLockRequest);
    IgniteInternalFuture txFut = GridTestUtils.runAsync(() -> {
        try (Transaction tx = client.transactions().txStart()) {
            Map<Integer, Integer> map = new LinkedHashMap<>();
            // clientFirst=true in lockAll mapped to stable part.
            map.put(g1Keys.get(0), g1Keys.get(0));
            // clientFirst=false in lockAll mapped to moving part.
            map.put(key, key);
            cache.putAll(map);
            cache2.putAll(new LinkedHashMap<>(map));
            // Will start preparing in the middle of PME.
            tx.commit();
        }
    });
    IgniteInternalFuture lockFut = GridTestUtils.runAsync(() -> {
        try {
            // Wait for first lock request sent on local (late) topology.
            clientSpi.waitForBlocked();
            // Continue late switch PME.
            resumeDiscoSndLatch.countDown();
            crdDiscoSpi.setClosure(null);
            // Wait late affinity switch.
            awaitPartitionMapExchange();
            // Continue tx mapping and preparing.
            clientSpi.stopBlock();
        } catch (InterruptedException e) {
            fail(X.getFullStackTrace(e));
        }
    });
    fut.get();
    txFut.get();
    lockFut.get();
    assertPartitionsSame(idleVerify(crd, DEFAULT_CACHE_NAME));
    // TX must be prepared over new owner.
    PartitionUpdateCounter cntr = counter(key, grid(3).name());
    assertNotNull(cntr);
    assertEquals(cntr.toString(), 2, cntr.reserved());
    PartitionUpdateCounter cntr2 = counter(key, DEFAULT_CACHE_NAME + "2", grid(3).name());
    assertNotNull(cntr2);
    assertEquals(cntr2.toString(), 2, cntr2.reserved());
}
Also used : GridNearLockRequest(org.apache.ignite.internal.processors.cache.distributed.near.GridNearLockRequest) PartitionUpdateCounter(org.apache.ignite.internal.processors.cache.PartitionUpdateCounter) CountDownLatch(java.util.concurrent.CountDownLatch) IgniteInternalFuture(org.apache.ignite.internal.IgniteInternalFuture) IgniteCheckedException(org.apache.ignite.IgniteCheckedException) IgniteFutureTimeoutCheckedException(org.apache.ignite.internal.IgniteFutureTimeoutCheckedException) ClusterTopologyException(org.apache.ignite.cluster.ClusterTopologyException) CacheInvalidStateException(org.apache.ignite.internal.processors.cache.CacheInvalidStateException) ClusterTopologyCheckedException(org.apache.ignite.internal.cluster.ClusterTopologyCheckedException) TransactionRollbackException(org.apache.ignite.transactions.TransactionRollbackException) CyclicBarrier(java.util.concurrent.CyclicBarrier) LinkedHashMap(java.util.LinkedHashMap) Field(java.lang.reflect.Field) CacheAffinityChangeMessage(org.apache.ignite.internal.processors.cache.CacheAffinityChangeMessage) TestRecordingCommunicationSpi(org.apache.ignite.internal.TestRecordingCommunicationSpi) Transaction(org.apache.ignite.transactions.Transaction) BlockTcpDiscoverySpi(org.apache.ignite.spi.discovery.tcp.BlockTcpDiscoverySpi) IgniteEx(org.apache.ignite.internal.IgniteEx) Ignite(org.apache.ignite.Ignite) Test(org.junit.Test)

Example 2 with PartitionUpdateCounter

use of org.apache.ignite.internal.processors.cache.PartitionUpdateCounter in project ignite by apache.

the class TxPartitionCounterStateOnePrimaryTwoBackupsFailAllTest method doTestRestartAllOwnersAfterPartialCommit.

/**
 * Test scenario:
 * <p>
 * 1. All txs is prepared.
 * <p>
 * 2. All txs are committed on primary, all txs until waitCommitIdx are committed.
 * <p>
 * 3. Tx processing is paused, all nodes are stopped.
 * <p>
 * 4. Start backup1 and backup2 in specified order, detect unrecoverable partition and trigger failure handler.
 * <p>
 * Pass condition: nodes are stopped by failure handler if applicable.
 *
 * @param skipCheckpoint Skip checkpoint on node stop.
 * @param prepareOrder Prepare order.
 * @param primCommitOrder Prim commit order.
 * @param backup1CommitOrder Backup 1 commit order.
 * @param backup2CommitOrder Backup 2 commit order.
 * @param sizes Sizes.
 * @param waitCommitIdx Wait commit index.
 * @param backupsStartOrder Start order of backups (should work same for any order).
 * @param expectAliveNodes Expected alive nodes.
 * @param failNodesOnBadCntr {@code True} to trigger FH if consistency can't be recovered.
 */
private void doTestRestartAllOwnersAfterPartialCommit(boolean skipCheckpoint, int[] prepareOrder, int[] primCommitOrder, int[] backup1CommitOrder, int[] backup2CommitOrder, int[] sizes, int[] waitCommitIdx, int[] backupsStartOrder, int expectAliveNodes, boolean failNodesOnBadCntr) throws Exception {
    Map<IgniteEx, int[]> commits = new HashMap<IgniteEx, int[]>();
    Map<Integer, T2<Ignite, List<Ignite>>> txTop = runOnPartition(PARTITION_ID, null, BACKUPS, NODES_CNT, new IgniteClosure<Map<Integer, T2<Ignite, List<Ignite>>>, TxCallback>() {

        @Override
        public TxCallback apply(Map<Integer, T2<Ignite, List<Ignite>>> map) {
            T2<Ignite, List<Ignite>> txTop = map.get(PARTITION_ID);
            Map<IgniteEx, int[]> prepares = new HashMap<IgniteEx, int[]>();
            prepares.put((IgniteEx) txTop.get1(), prepareOrder);
            final Ignite backup1 = txTop.get2().get(0);
            final Ignite backup2 = txTop.get2().get(1);
            commits.put((IgniteEx) txTop.get1(), primCommitOrder);
            commits.put((IgniteEx) backup1, backup1CommitOrder);
            commits.put((IgniteEx) backup2, backup2CommitOrder);
            CountDownLatch l = new CountDownLatch(2);
            return new TwoPhaseCommitTxCallbackAdapter(prepares, commits, sizes.length) {

                @Override
                protected boolean onBackupCommitted(IgniteEx backup, int idx) {
                    super.onBackupCommitted(backup, idx);
                    if (idx == commits.get(backup)[waitCommitIdx[backup == backup1 ? 0 : 1]]) {
                        l.countDown();
                        // Wait until both backups are committed required transactions.
                        try {
                            assertTrue(U.await(l, 30_000, TimeUnit.MILLISECONDS));
                        } catch (IgniteInterruptedCheckedException e) {
                            fail(e.getMessage());
                        }
                        if (backup == backup1) {
                            blockRecovery();
                            stopGrid(skipCheckpoint, txTop.get2().get(0).name());
                            stopGrid(skipCheckpoint, txTop.get2().get(1).name());
                            // Stop all remaining nodes.
                            stopAllGrids();
                        }
                        return true;
                    }
                    return false;
                }
            };
        }
    }, sizes);
    // All owners should be stopped.
    waitForTopology(0);
    if (failNodesOnBadCntr)
        System.setProperty(IGNITE_FAIL_NODE_ON_UNRECOVERABLE_PARTITION_INCONSISTENCY, "true");
    try {
        // Start only backups in given order.
        startGrid(txTop.get(PARTITION_ID).get2().get(backupsStartOrder[0]).name());
        startGrid(txTop.get(PARTITION_ID).get2().get(backupsStartOrder[1]).name());
        try {
            grid(0).cluster().active(true);
        } catch (Throwable t) {
            // Nodes are expected to stop during activation due to irrecoverable partition consistency.
            assertTrue(X.hasCause(t, NodeStoppingException.class));
        }
        waitForTopology(expectAliveNodes);
        awaitPartitionMapExchange();
    } finally {
        System.clearProperty(IGNITE_FAIL_NODE_ON_UNRECOVERABLE_PARTITION_INCONSISTENCY);
    }
    // Alive node should not have missed updates.
    if (expectAliveNodes == 1) {
        IgniteEx node = (IgniteEx) G.allGrids().iterator().next();
        PartitionUpdateCounter cntr = counter(PARTITION_ID, node.name());
        assertTrue(cntr.sequential());
    }
}
Also used : HashMap(java.util.HashMap) PartitionUpdateCounter(org.apache.ignite.internal.processors.cache.PartitionUpdateCounter) CountDownLatch(java.util.concurrent.CountDownLatch) IgniteInterruptedCheckedException(org.apache.ignite.internal.IgniteInterruptedCheckedException) IgniteEx(org.apache.ignite.internal.IgniteEx) Ignite(org.apache.ignite.Ignite) List(java.util.List) HashMap(java.util.HashMap) Map(java.util.Map) T2(org.apache.ignite.internal.util.typedef.T2)

Example 3 with PartitionUpdateCounter

use of org.apache.ignite.internal.processors.cache.PartitionUpdateCounter in project ignite by apache.

the class TxPartitionCounterStateOnePrimaryTwoBackupsTest method testMissingUpdateBetweenMultipleCheckpoints.

/**
 * Test scenario:
 * <p>
 * 1. Assign counters in order tx0, tx1
 * <p>
 * 2. Commit tx1.
 * <p>
 * 3. Delay tx0 commit on backup1.
 * <p>
 * 4. Put more keys in partition, trigger checkpoint, put more keys.
 * <p>
 * 5. Commit delayed tx closing gap.
 * <p>
 * 5. Restart backup1 without triggering checkpoint on stop.
 * <p>
 *
 * Pass condition: backup1 after restart has sequential update counter. No rebalance is expected.
 * The test states necessity of storing gaps between checkpoints.
 *
 * @throws Exception If failed.
 */
@Test
public void testMissingUpdateBetweenMultipleCheckpoints() throws Exception {
    int[] sizes = new int[] { 3, 7 };
    int[] assignOrder = new int[] { 0, 1 };
    int delayBackupIdx = 0;
    GridFutureAdapter<T2<Ignite, GridFutureAdapter>> fut = new GridFutureAdapter<>();
    GridTestUtils.runAsync(new Runnable() {

        @Override
        public void run() {
            try {
                T2<Ignite, GridFutureAdapter> pair = fut.get(30, TimeUnit.SECONDS);
                IgniteEx client = grid(CLIENT_GRID_NAME);
                // Allow txs to work as usual.
                for (Ignite node : G.allGrids()) TestRecordingCommunicationSpi.spi(node).stopBlock(false, null, true, false);
                List<Integer> keys = partitionKeys(client.cache(DEFAULT_CACHE_NAME), PARTITION_ID, 10, sizes[0] + sizes[1] + PRELOAD_KEYS_CNT);
                for (Integer key : keys) client.cache(DEFAULT_CACHE_NAME).put(key, key);
                Ignite backup1 = pair.get1();
                forceCheckpoint(backup1);
                // Commit delayed tx.
                pair.get2().onDone();
            } catch (IgniteCheckedException e) {
                fail(X.getFullStackTrace(e));
            }
        }
    });
    Map<Integer, T2<Ignite, List<Ignite>>> txTops = runOnPartition(PARTITION_ID, null, BACKUPS, SERVERS_CNT, map -> {
        Ignite primary = map.get(PARTITION_ID).get1();
        Ignite backup1 = map.get(PARTITION_ID).get2().get(delayBackupIdx);
        return new TwoPhaseCommitTxCallbackAdapter(U.map((IgniteEx) primary, assignOrder), new HashMap<>(), new HashMap<>(), sizes.length) {

            @Override
            public boolean beforeBackupFinish(IgniteEx primary, IgniteEx backup, @Nullable IgniteInternalTx primaryTx, IgniteInternalTx backupTx, IgniteUuid nearXidVer, GridFutureAdapter<?> proceedFut) {
                if (order(nearXidVer) == assignOrder[0] && backup == backup1) {
                    fut.onDone(new T2<>(backup1, proceedFut));
                    // Delay commit on backup.
                    return true;
                }
                return super.beforeBackupFinish(primary, backup, primaryTx, backupTx, nearXidVer, proceedFut);
            }
        };
    }, sizes);
    // At this point all txs are committed and no gaps are expected.
    Ignite backup1 = txTops.get(PARTITION_ID).get2().get(delayBackupIdx);
    PartitionUpdateCounter cntr;
    assertNotNull(cntr = counter(PARTITION_ID, backup1.name()));
    assertTrue(cntr.sequential());
    stopGrid(true, backup1.name());
    startGrid(backup1.name());
    awaitPartitionMapExchange();
    assertNotNull(cntr = counter(PARTITION_ID, backup1.name()));
    assertTrue(cntr.sequential());
    assertPartitionsSame(idleVerify(grid(CLIENT_GRID_NAME), DEFAULT_CACHE_NAME));
    assertCountersSame(PARTITION_ID, true, DEFAULT_CACHE_NAME);
}
Also used : PartitionUpdateCounter(org.apache.ignite.internal.processors.cache.PartitionUpdateCounter) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) IgniteCheckedException(org.apache.ignite.IgniteCheckedException) IgniteUuid(org.apache.ignite.lang.IgniteUuid) IgniteEx(org.apache.ignite.internal.IgniteEx) GridFutureAdapter(org.apache.ignite.internal.util.future.GridFutureAdapter) Ignite(org.apache.ignite.Ignite) List(java.util.List) T2(org.apache.ignite.internal.util.typedef.T2) Nullable(org.jetbrains.annotations.Nullable) Test(org.junit.Test)

Example 4 with PartitionUpdateCounter

use of org.apache.ignite.internal.processors.cache.PartitionUpdateCounter in project ignite by apache.

the class PartitionUpdateCounterTest method testMixedModeMultithreaded.

/**
 * Test multithreaded updates of pc in various modes.
 *
 * @throws Exception If failed.
 */
@Test
public void testMixedModeMultithreaded() throws Exception {
    PartitionUpdateCounter pc = new PartitionUpdateCounterTrackingImpl(null);
    AtomicBoolean stop = new AtomicBoolean();
    Queue<long[]> reservations = new ConcurrentLinkedQueue<>();
    LongAdder reserveCntr = new LongAdder();
    IgniteInternalFuture<?> fut = multithreadedAsync(() -> {
        while (!stop.get() || !reservations.isEmpty()) {
            if (!stop.get() && ThreadLocalRandom.current().nextBoolean()) {
                int size = ThreadLocalRandom.current().nextInt(9) + 1;
                // Only update if stop flag is set.
                reservations.add(new long[] { pc.reserve(size), size });
                reserveCntr.add(size);
            } else {
                long[] reserved = reservations.poll();
                if (reserved == null)
                    continue;
                pc.update(reserved[0], reserved[1]);
            }
        }
    }, Runtime.getRuntime().availableProcessors() * 2, "updater-thread");
    doSleep(10_000);
    stop.set(true);
    fut.get();
    assertTrue(reservations.isEmpty());
    log.info("counter=" + pc.toString() + ", reserveCntrLocal=" + reserveCntr.sum());
    assertTrue(pc.sequential());
    assertTrue(pc.get() == pc.reserved());
    assertEquals(reserveCntr.sum(), pc.get());
}
Also used : AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) PartitionUpdateCounterTrackingImpl(org.apache.ignite.internal.processors.cache.PartitionUpdateCounterTrackingImpl) LongAdder(java.util.concurrent.atomic.LongAdder) PartitionUpdateCounter(org.apache.ignite.internal.processors.cache.PartitionUpdateCounter) ConcurrentLinkedQueue(java.util.concurrent.ConcurrentLinkedQueue) GridCommonAbstractTest(org.apache.ignite.testframework.junits.common.GridCommonAbstractTest) Test(org.junit.Test)

Example 5 with PartitionUpdateCounter

use of org.apache.ignite.internal.processors.cache.PartitionUpdateCounter in project ignite by apache.

the class PartitionUpdateCounterTest method testStaleUpdate.

/**
 * Test if pc correctly reports stale (before current counter) updates.
 * This information is used for logging rollback records only once.
 */
@Test
public void testStaleUpdate() {
    PartitionUpdateCounter pc = new PartitionUpdateCounterTrackingImpl(null);
    assertTrue(pc.update(0, 1));
    assertFalse(pc.update(0, 1));
    assertTrue(pc.update(2, 1));
    assertFalse(pc.update(2, 1));
    assertTrue(pc.update(1, 1));
    assertFalse(pc.update(1, 1));
}
Also used : PartitionUpdateCounterTrackingImpl(org.apache.ignite.internal.processors.cache.PartitionUpdateCounterTrackingImpl) PartitionUpdateCounter(org.apache.ignite.internal.processors.cache.PartitionUpdateCounter) GridCommonAbstractTest(org.apache.ignite.testframework.junits.common.GridCommonAbstractTest) Test(org.junit.Test)

Aggregations

PartitionUpdateCounter (org.apache.ignite.internal.processors.cache.PartitionUpdateCounter)29 Test (org.junit.Test)17 IgniteEx (org.apache.ignite.internal.IgniteEx)15 Ignite (org.apache.ignite.Ignite)12 IgniteCheckedException (org.apache.ignite.IgniteCheckedException)12 GridCommonAbstractTest (org.apache.ignite.testframework.junits.common.GridCommonAbstractTest)12 PartitionUpdateCounterTrackingImpl (org.apache.ignite.internal.processors.cache.PartitionUpdateCounterTrackingImpl)10 List (java.util.List)9 AtomicInteger (java.util.concurrent.atomic.AtomicInteger)8 T2 (org.apache.ignite.internal.util.typedef.T2)7 Map (java.util.Map)6 GridDhtLocalPartition (org.apache.ignite.internal.processors.cache.distributed.dht.topology.GridDhtLocalPartition)6 Nullable (org.jetbrains.annotations.Nullable)6 ArrayList (java.util.ArrayList)5 HashMap (java.util.HashMap)5 IgniteInternalFuture (org.apache.ignite.internal.IgniteInternalFuture)5 TestRecordingCommunicationSpi (org.apache.ignite.internal.TestRecordingCommunicationSpi)5 Collections (java.util.Collections)4 IgniteException (org.apache.ignite.IgniteException)4 Collection (java.util.Collection)3