You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by sd...@apache.org on 2022/10/05 16:37:32 UTC

[ignite] branch master updated: IGNITE-17436 Fix CacheGroupReencryptionTest#testReencryptionOnUnstableTopology fails if checkpoint is skipped on node stop (#10289)

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

sdanilov 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 72aa5848bb8 IGNITE-17436 Fix CacheGroupReencryptionTest#testReencryptionOnUnstableTopology fails if checkpoint is skipped on node stop (#10289)
72aa5848bb8 is described below

commit 72aa5848bb8462bf3118ad548e584461688af818
Author: Semyon Danilov <sa...@yandex.ru>
AuthorDate: Wed Oct 5 19:37:23 2022 +0300

    IGNITE-17436 Fix CacheGroupReencryptionTest#testReencryptionOnUnstableTopology fails if checkpoint is skipped on node stop (#10289)
---
 .../encryption/CacheGroupReencryptionTest.java     | 89 +++++++++++++++++++++-
 1 file changed, 88 insertions(+), 1 deletion(-)

diff --git a/modules/core/src/test/java/org/apache/ignite/internal/encryption/CacheGroupReencryptionTest.java b/modules/core/src/test/java/org/apache/ignite/internal/encryption/CacheGroupReencryptionTest.java
index e97ed90ef35..f809a1c317b 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/encryption/CacheGroupReencryptionTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/encryption/CacheGroupReencryptionTest.java
@@ -45,6 +45,8 @@ import org.apache.ignite.internal.IgniteEx;
 import org.apache.ignite.internal.IgniteFutureCancelledCheckedException;
 import org.apache.ignite.internal.IgniteInternalFuture;
 import org.apache.ignite.internal.IgniteInterruptedCheckedException;
+import org.apache.ignite.internal.managers.encryption.ReencryptStateUtils;
+import org.apache.ignite.internal.processors.cache.CacheGroupContext;
 import org.apache.ignite.internal.processors.cache.CacheGroupMetricsImpl;
 import org.apache.ignite.internal.processors.cache.persistence.file.FileIO;
 import org.apache.ignite.internal.processors.cache.persistence.file.FileIODecorator;
@@ -57,11 +59,15 @@ import org.apache.ignite.internal.util.typedef.internal.CU;
 import org.apache.ignite.spi.metric.BooleanMetric;
 import org.apache.ignite.spi.metric.LongMetric;
 import org.apache.ignite.testframework.GridTestUtils;
+import org.apache.ignite.testframework.junits.WithSystemProperty;
+import org.jetbrains.annotations.Nullable;
 import org.junit.Test;
 
 import static org.apache.ignite.configuration.EncryptionConfiguration.DFLT_REENCRYPTION_RATE_MBPS;
 import static org.apache.ignite.configuration.WALMode.LOG_ONLY;
 import static org.apache.ignite.internal.managers.encryption.GridEncryptionManager.INITIAL_KEY_ID;
+import static org.apache.ignite.internal.pagemem.PageIdAllocator.INDEX_PARTITION;
+import static org.apache.ignite.internal.processors.cache.persistence.GridCacheDatabaseSharedManager.IGNITE_PDS_SKIP_CHECKPOINT_ON_NODE_STOP;
 import static org.apache.ignite.internal.processors.metric.impl.MetricUtils.metricName;
 import static org.apache.ignite.testframework.GridTestUtils.assertThrowsAnyCause;
 import static org.apache.ignite.testframework.GridTestUtils.waitForCondition;
@@ -581,6 +587,7 @@ public class CacheGroupReencryptionTest extends AbstractEncryptionTest {
      * @throws Exception If failed.
      */
     @Test
+    @WithSystemProperty(key = IGNITE_PDS_SKIP_CHECKPOINT_ON_NODE_STOP, value = "true")
     public void testReencryptionOnUnstableTopology() throws Exception {
         backups = 1;
         pageScanRate = 2;
@@ -615,7 +622,24 @@ public class CacheGroupReencryptionTest extends AbstractEncryptionTest {
 
             stopGrid(gridName);
 
-            startGrid(gridName);
+            IgniteEx restarted = startGrid(gridName);
+
+            // Find last reencrypted page's index of currently reencrypted partition.
+            ReencryptionStatus firstNotReencrypted = findFirstNotReencrypted(restarted, cacheGroups);
+
+            if (firstNotReencrypted != null) {
+                int grpId = firstNotReencrypted.grpId;
+                int partId = firstNotReencrypted.partId;
+                int idx = firstNotReencrypted.pageIdx;
+
+                // Wait until reencryption status changes.
+                boolean updated = waitForCondition(() ->
+                        reencryptionPageIndex(restarted, grpId, partId) > idx, TimeUnit.SECONDS.toMillis(10));
+
+                // If reencryption page index changed, make a checkpoint, so that status of reencryption is saved.
+                if (updated)
+                    forceCheckpoint(restarted);
+            }
         }
 
         stopAllGrids();
@@ -921,4 +945,67 @@ public class CacheGroupReencryptionTest extends AbstractEncryptionTest {
             return Objects.hash(name, id);
         }
     }
+
+    /** Reencryption status of the partition. */
+    private static class ReencryptionStatus {
+        /** Cache group id. */
+        final int grpId;
+
+        /** Partition id. */
+        final int partId;
+
+        /** Reencrypted page index. */
+        final int pageIdx;
+
+        /** Constructor. */
+        private ReencryptionStatus(int grpId, int partId, int pageIdx) {
+            this.grpId = grpId;
+            this.partId = partId;
+            this.pageIdx = pageIdx;
+        }
+    }
+
+    /**
+     * Finds first not reencrypted partition and returns tuple with cache group id, partition id and reencrypted page index.
+     */
+    @Nullable private static ReencryptionStatus findFirstNotReencrypted(IgniteEx node, Iterable<String> cacheGrps) {
+        for (String cacheGrp : cacheGrps) {
+            int grpId = CU.cacheId(cacheGrp);
+
+            CacheGroupContext grp = node.context().cache().cacheGroup(grpId);
+
+            if (grp == null || !grp.affinityNode())
+                continue;
+
+            for (int p = 0; p < grp.affinity().partitions(); p++) {
+                int pageIdx = reencryptionPageIndex(node, grpId, p);
+
+                if (pageIdx != Integer.MAX_VALUE)
+                    return new ReencryptionStatus(grpId, p, pageIdx);
+            }
+
+            int pageIdx = reencryptionPageIndex(node, grpId, INDEX_PARTITION);
+
+            if (pageIdx != Integer.MAX_VALUE)
+                return new ReencryptionStatus(grpId, INDEX_PARTITION, pageIdx);
+        }
+
+        return null;
+    }
+
+    /** Gets reencryption page index of partition. */
+    private static int reencryptionPageIndex(IgniteEx node, int grpId, int partId) {
+        long state = node.context().encryption().getEncryptionState(grpId, partId);
+
+        int pageIdx = ReencryptStateUtils.pageIndex(state);
+
+        if (ReencryptStateUtils.pageCount(state) == pageIdx) {
+            // In case if reencryption finished, page count will be zero along with page index,
+            // making pageIndex lesser than previously obtained. Return MAX_VALUE so that it will always be higher than
+            // previously obtained value.
+            return Integer.MAX_VALUE;
+        }
+
+        return pageIdx;
+    }
 }