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

nizhikov 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 f5bc7fe43ce IGNITE-18652 Fix segments not removed from CDC in case no 
DataEntry (#10510)
f5bc7fe43ce is described below

commit f5bc7fe43cea4c28a4b3502746d0f39098033595
Author: Nikolay <[email protected]>
AuthorDate: Wed Feb 1 17:46:10 2023 +0300

    IGNITE-18652 Fix segments not removed from CDC in case no DataEntry (#10510)
---
 .../org/apache/ignite/internal/cdc/CdcMain.java    |   9 +-
 .../ignite/internal/cdc/WalRecordsConsumer.java    |   4 +-
 .../java/org/apache/ignite/cdc/CdcSelfTest.java    |  17 +-
 .../ignite/internal/cdc/CdcIndexRebuildTest.java   | 204 +++++++++++++++++++++
 .../IgniteBinaryCacheQueryTestSuite3.java          |   5 +-
 5 files changed, 225 insertions(+), 14 deletions(-)

diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/cdc/CdcMain.java 
b/modules/core/src/main/java/org/apache/ignite/internal/cdc/CdcMain.java
index b7d449fa6a8..35d5a82023c 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/cdc/CdcMain.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/cdc/CdcMain.java
@@ -525,15 +525,16 @@ public class CdcMain implements Runnable {
                 walState = null;
             }
 
-            boolean interrupted = Thread.interrupted();
+            boolean interrupted = false;
 
-            while (iter.hasNext() && !interrupted) {
+            do {
                 boolean commit = consumer.onRecords(iter);
 
                 if (commit) {
                     T2<WALPointer, Integer> curState = iter.state();
 
-                    assert curState != null;
+                    if (curState == null)
+                        continue;
 
                     if (log.isDebugEnabled())
                         log.debug("Saving state [curState=" + curState + ']');
@@ -560,7 +561,7 @@ public class CdcMain implements Runnable {
                 }
 
                 interrupted = Thread.interrupted();
-            }
+            } while (iter.hasNext() && !interrupted);
 
             if (interrupted)
                 throw new IgniteException("Change Data Capture Application 
interrupted");
diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/cdc/WalRecordsConsumer.java
 
b/modules/core/src/main/java/org/apache/ignite/internal/cdc/WalRecordsConsumer.java
index 4fd7421afd1..3d450d6cd61 100644
--- 
a/modules/core/src/main/java/org/apache/ignite/internal/cdc/WalRecordsConsumer.java
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/cdc/WalRecordsConsumer.java
@@ -247,7 +247,9 @@ public class WalRecordsConsumer<K, V> {
         T2<WALPointer, Integer> state() {
             return hasNext() ?
                 new T2<>(curRec.get1(), entryIdx) :
-                new T2<>(curRec.get1().next(), 0);
+                curRec != null
+                    ? new T2<>(curRec.get1().next(), 0)
+                    : walIter.lastRead().map(ptr -> new T2<>(ptr.next(), 
0)).orElse(null);
         }
 
         /** Initialize state. */
diff --git a/modules/core/src/test/java/org/apache/ignite/cdc/CdcSelfTest.java 
b/modules/core/src/test/java/org/apache/ignite/cdc/CdcSelfTest.java
index 6e748c2eb93..a05d89fccc9 100644
--- a/modules/core/src/test/java/org/apache/ignite/cdc/CdcSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/cdc/CdcSelfTest.java
@@ -88,9 +88,6 @@ public class CdcSelfTest extends AbstractCdcTest {
     /** */
     public static final String TX_CACHE_NAME = "tx-cache";
 
-    /** */
-    public static final int WAL_ARCHIVE_TIMEOUT = 5_000;
-
     /** */
     @Parameterized.Parameter
     public boolean specificConsistentId;
@@ -157,7 +154,8 @@ public class CdcSelfTest extends AbstractCdcTest {
         // Read one record per call.
         readAll(new UserCdcConsumer() {
             @Override public boolean onEvents(Iterator<CdcEvent> evts) {
-                super.onEvents(Collections.singleton(evts.next()).iterator());
+                if (evts.hasNext())
+                    
super.onEvents(Collections.singleton(evts.next()).iterator());
 
                 return false;
             }
@@ -170,7 +168,8 @@ public class CdcSelfTest extends AbstractCdcTest {
         // Read one record per call and commit.
         readAll(new UserCdcConsumer() {
             @Override public boolean onEvents(Iterator<CdcEvent> evts) {
-                super.onEvents(Collections.singleton(evts.next()).iterator());
+                if (evts.hasNext())
+                    
super.onEvents(Collections.singleton(evts.next()).iterator());
 
                 return true;
             }
@@ -275,11 +274,12 @@ public class CdcSelfTest extends AbstractCdcTest {
 
             CdcConsumer cnsmr = new CdcConsumer() {
                 @Override public boolean onEvents(Iterator<CdcEvent> evts) {
+                    if (!evts.hasNext())
+                        return true;
+
                     if (!firstEvt.get())
                         throw new RuntimeException("Expected fail.");
 
-                    assertTrue(evts.hasNext());
-
                     data.add((Integer)evts.next().key());
 
                     firstEvt.set(false);
@@ -363,6 +363,9 @@ public class CdcSelfTest extends AbstractCdcTest {
                 boolean oneConsumed;
 
                 @Override public boolean onEvents(Iterator<CdcEvent> evts) {
+                    if (!evts.hasNext())
+                        return true;
+
                     // Fail application after one event read AND state 
committed.
                     if (oneConsumed)
                         throw new RuntimeException(errMsg);
diff --git 
a/modules/indexing/src/test/java/org/apache/ignite/internal/cdc/CdcIndexRebuildTest.java
 
b/modules/indexing/src/test/java/org/apache/ignite/internal/cdc/CdcIndexRebuildTest.java
new file mode 100644
index 00000000000..eab9766103a
--- /dev/null
+++ 
b/modules/indexing/src/test/java/org/apache/ignite/internal/cdc/CdcIndexRebuildTest.java
@@ -0,0 +1,204 @@
+/*
+ * 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.cdc;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.UUID;
+import org.apache.ignite.IgniteCache;
+import org.apache.ignite.binary.BinaryType;
+import org.apache.ignite.cache.query.annotations.QuerySqlField;
+import org.apache.ignite.cdc.AbstractCdcTest;
+import org.apache.ignite.cdc.CdcCacheEvent;
+import org.apache.ignite.cdc.CdcConsumer;
+import org.apache.ignite.cdc.CdcEvent;
+import org.apache.ignite.cdc.TypeMapping;
+import org.apache.ignite.configuration.CacheConfiguration;
+import org.apache.ignite.configuration.DataRegionConfiguration;
+import org.apache.ignite.configuration.DataStorageConfiguration;
+import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.internal.IgniteEx;
+import org.apache.ignite.internal.IgniteInternalFuture;
+import org.apache.ignite.internal.IgniteInterruptedCheckedException;
+import org.apache.ignite.internal.processors.metric.MetricRegistry;
+import org.apache.ignite.spi.metric.LongMetric;
+import org.junit.Test;
+
+import static org.apache.ignite.cluster.ClusterState.ACTIVE;
+import static org.apache.ignite.internal.cdc.CdcMain.COMMITTED_SEG_IDX;
+import static org.apache.ignite.internal.cdc.CdcMain.CUR_SEG_IDX;
+import static 
org.apache.ignite.internal.processors.cache.GridCacheUtils.cacheId;
+import static org.apache.ignite.internal.util.IgniteUtils.MB;
+import static org.apache.ignite.testframework.GridTestUtils.getFieldValue;
+import static org.apache.ignite.testframework.GridTestUtils.runAsync;
+import static org.apache.ignite.testframework.GridTestUtils.waitForCondition;
+
+/** */
+public class CdcIndexRebuildTest extends AbstractCdcTest {
+    /** */
+    public static final int VALS_CNT = 1024 * 30;
+
+    /** {@inheritDoc} */
+    @Override protected IgniteConfiguration getConfiguration(String 
igniteInstanceName) throws Exception {
+        return 
super.getConfiguration(igniteInstanceName).setDataStorageConfiguration(new 
DataStorageConfiguration()
+            .setWalForceArchiveTimeout(WAL_ARCHIVE_TIMEOUT)
+            .setDefaultDataRegionConfiguration(new DataRegionConfiguration()
+                .setPersistenceEnabled(true)
+                .setCdcEnabled(true))
+            .setWalSegmentSize((int)(16 * MB))
+        );
+    }
+
+    /** */
+    @Test
+    public void testIndexRebuild() throws Exception {
+        IgniteEx srv = startGrid(0);
+
+        srv.cluster().state(ACTIVE);
+
+        IgniteCache<Integer, TestVal> cache = srv.getOrCreateCache(
+            new CacheConfiguration<Integer, TestVal>(DEFAULT_CACHE_NAME)
+                .setIndexedTypes(Integer.class, TestVal.class)
+        );
+
+        Map<Integer, TestVal> vals = new HashMap<>(VALS_CNT);
+
+        for (int i = 0; i < VALS_CNT; i++)
+            vals.put(i, new TestVal());
+
+        cache.putAll(vals);
+
+        CountingCdcConsumer cnsmr = new CountingCdcConsumer();
+
+        CdcMain cdc = createCdc(cnsmr, getConfiguration(srv.name()));
+
+        IgniteInternalFuture<Object> fut = runAsync(cdc);
+
+        assertTrue(waitForCondition(() -> cnsmr.commited && cnsmr.evtsCnt == 
VALS_CNT, getTestTimeout()));
+
+        waitForWalSegmentsHandling(srv, cdc);
+
+        cnsmr.reset();
+
+        forceRebuildIndexes(srv, srv.cachex(DEFAULT_CACHE_NAME).context());
+
+        indexRebuildFuture(srv, 
cacheId(DEFAULT_CACHE_NAME)).get(getTestTimeout());
+
+        waitForWalSegmentsHandling(srv, cdc);
+
+        fut.cancel();
+    }
+
+    /** @param cdc Cdc. */
+    private void waitForWalSegmentsHandling(IgniteEx srv, CdcMain cdc) throws 
IgniteInterruptedCheckedException {
+        assertTrue("Wal segments was not committed by CdcConsumer", 
waitForCondition(() -> {
+            long lastArchivedSeg = 
srv.context().cache().context().wal().lastArchivedSegment();
+
+            MetricRegistry mreg = getFieldValue(cdc, "mreg");
+
+            long committedCdcSegIdx = 
mreg.<LongMetric>findMetric(COMMITTED_SEG_IDX).value();
+            long curCdcSegIdx = 
mreg.<LongMetric>findMetric(CUR_SEG_IDX).value();
+
+            log.warning(String.format(">>>>>> Information about CDC and WAL: " 
+
+                    "[lastArchivedSeg=%d, committedCdcSegIdx=%d, 
curCdcSegIdx=%d]",
+                lastArchivedSeg,
+                committedCdcSegIdx,
+                curCdcSegIdx));
+
+            return lastArchivedSeg == committedCdcSegIdx;
+        }, WAL_ARCHIVE_TIMEOUT * 4, WAL_ARCHIVE_TIMEOUT / 2));
+    }
+
+    /** */
+    public static class CountingCdcConsumer implements CdcConsumer {
+        /** Commited. */
+        volatile boolean commited;
+
+        /** Evts count. */
+        volatile int evtsCnt;
+
+        /** */
+        public void reset() {
+            commited = false;
+            evtsCnt = 0;
+        }
+
+        /** {@inheritDoc} */
+        @Override public void start(MetricRegistry mreg) {
+            // No-op.
+        }
+
+        /** {@inheritDoc} */
+        @Override public boolean onEvents(Iterator<CdcEvent> events) {
+            while (events.hasNext()) {
+                events.next();
+
+                evtsCnt++;
+            }
+
+            commited = true;
+
+            return true;
+        }
+
+        /** {@inheritDoc} */
+        @Override public void onTypes(Iterator<BinaryType> types) {
+            types.forEachRemaining(t -> { /* No-op */ });
+        }
+
+        /** {@inheritDoc} */
+        @Override public void onMappings(Iterator<TypeMapping> mappings) {
+            mappings.forEachRemaining(m -> { /* No-op */ });
+        }
+
+        /** {@inheritDoc} */
+        @Override public void onCacheChange(Iterator<CdcCacheEvent> 
cacheEvents) {
+            cacheEvents.forEachRemaining(e -> { /* No-op */ });
+        }
+
+        /** {@inheritDoc} */
+        @Override public void onCacheDestroy(Iterator<Integer> caches) {
+            caches.forEachRemaining(c -> { /* No-op */ });
+        }
+
+        /** {@inheritDoc} */
+        @Override public void stop() {
+            // No-op.
+        }
+    }
+
+    /** */
+    public static class TestVal {
+        /** Field 0. */
+        @QuerySqlField(index = true, inlineSize = 256)
+        private final String f0;
+
+        /** Field 1. */
+        @QuerySqlField(index = true, inlineSize = 256)
+        private final String f1;
+
+        /**
+         * Default constructor.
+         */
+        public TestVal() {
+            f0 = UUID.randomUUID().toString();
+            f1 = UUID.randomUUID().toString();
+        }
+    }
+}
diff --git 
a/modules/indexing/src/test/java/org/apache/ignite/testsuites/IgniteBinaryCacheQueryTestSuite3.java
 
b/modules/indexing/src/test/java/org/apache/ignite/testsuites/IgniteBinaryCacheQueryTestSuite3.java
index 93eefe1bf72..17dabe3b376 100644
--- 
a/modules/indexing/src/test/java/org/apache/ignite/testsuites/IgniteBinaryCacheQueryTestSuite3.java
+++ 
b/modules/indexing/src/test/java/org/apache/ignite/testsuites/IgniteBinaryCacheQueryTestSuite3.java
@@ -19,6 +19,7 @@ package org.apache.ignite.testsuites;
 
 import 
org.apache.ignite.internal.cache.query.index.sorted.inline.InlineIndexKeyTypeRegistryTest;
 import org.apache.ignite.internal.cdc.CacheEventsCdcTest;
+import org.apache.ignite.internal.cdc.CdcIndexRebuildTest;
 import org.apache.ignite.internal.cdc.SqlCdcTest;
 import org.apache.ignite.internal.metric.SystemViewSelfTest;
 import org.apache.ignite.internal.processors.cache.BigEntryQueryTest;
@@ -376,8 +377,8 @@ import org.junit.runners.Suite;
 
     // CDC tests.
     SqlCdcTest.class,
-    CacheEventsCdcTest.class
-
+    CacheEventsCdcTest.class,
+    CdcIndexRebuildTest.class
 })
 public class IgniteBinaryCacheQueryTestSuite3 {
 }

Reply via email to