From 67c28e9f6e24fac594046a685a7ec53ec130e8e0 Mon Sep 17 00:00:00 2001 From: Daniil Date: Wed, 10 Dec 2025 22:36:53 +0300 Subject: [PATCH 1/9] change wal mode for multiple caches from same group --- .../java/org/apache/ignite/IgniteCluster.java | 49 +++++++++++++ .../cluster/IgniteClusterAsyncImpl.java | 10 +++ .../internal/cluster/IgniteClusterImpl.java | 25 +++++-- .../cache/WalModeChangeAdvancedSelfTest.java | 69 +++++++++++++++++++ .../multijvm/IgniteClusterProcessProxy.java | 10 +++ 5 files changed, 157 insertions(+), 6 deletions(-) diff --git a/modules/core/src/main/java/org/apache/ignite/IgniteCluster.java b/modules/core/src/main/java/org/apache/ignite/IgniteCluster.java index 6e320ab516a49..e5c1b8f41ee83 100644 --- a/modules/core/src/main/java/org/apache/ignite/IgniteCluster.java +++ b/modules/core/src/main/java/org/apache/ignite/IgniteCluster.java @@ -544,6 +544,31 @@ public IgniteFuture> startNodesAsync(Collecti */ public boolean disableWal(String cacheName) throws IgniteException; + /** + * Disables write-ahead logging for specified caches. When WAL is disabled, changes are not logged to disk. + * This significantly improves cache update speed. The drawback is absence of local crash-recovery guarantees. + * If node is crashed, local content of WAL-disabled cache will be cleared on restart to avoid data corruption. + *

+ * Internally this method will wait for all current cache operations to finish and prevent new cache operations + * from being executed. Then checkpoint is initiated to flush all data to disk. Control is returned to the callee + * when all dirty pages are prepared for checkpoint, but not necessarily flushed to disk. + *

+ * WAL state can be changed only for persistent caches. + *

+ * NOTE: + * Currently, this method should only be called on a stable topology when no nodes are leaving or joining cluster, + * and all baseline nodes are present. + * Cache may be stuck in inconsistent state due to violation of these conditions. It is advised to destroy + * such cache. + * + * @param cacheNames Collection of cache names, all caches must be in the same cache group. + * @return Whether WAL disabled by this call. + * @throws IgniteException If error occurs. + * @see #enableWal(Collection) + * @see #isWalEnabled(String) + */ + public boolean disableWal(Collection cacheNames) throws IgniteException; + /** * Enables write-ahead logging for specified cache. Restoring crash-recovery guarantees of a previous call to * {@link #disableWal(String)}. @@ -568,6 +593,30 @@ public IgniteFuture> startNodesAsync(Collecti */ public boolean enableWal(String cacheName) throws IgniteException; + /** + * Enables write-ahead logging for specified caches. Restoring crash-recovery guarantees of a previous call to + * {@link #disableWal(Collection)}. + *

+ * Internally this method will wait for all current cache operations to finish and prevent new cache operations + * from being executed. Then checkpoint is initiated to flush all data to disk. Control is returned to the callee + * when all data is persisted to disk. + *

+ * WAL state can be changed only for persistent caches. + *

+ * NOTE: + * Currently, this method should only be called on a stable topology when no nodes are leaving or joining cluster, + * and all baseline nodes are present. + * Cache may be stuck in inconsistent state due to violation of these conditions. It is advised to destroy + * such cache. + * + * @param cacheNames Collection of cache names, all caches must be in the same cache group. + * @return Whether WAL state enabled by this call. + * @throws IgniteException If error occurs. + * @see #disableWal(Collection) + * @see #isWalEnabled(String) + */ + public boolean enableWal(Collection cacheNames) throws IgniteException; + /** * Checks if write-ahead logging is enabled for specified cache. * diff --git a/modules/core/src/main/java/org/apache/ignite/internal/cluster/IgniteClusterAsyncImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/cluster/IgniteClusterAsyncImpl.java index 6cf668de668c4..481b54d0ba2f7 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/cluster/IgniteClusterAsyncImpl.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/cluster/IgniteClusterAsyncImpl.java @@ -349,11 +349,21 @@ public IgniteClusterAsyncImpl(IgniteClusterImpl cluster) { return cluster.enableWal(cacheName); } + /** {@inheritDoc} */ + @Override public boolean enableWal(Collection cacheNames) throws IgniteException { + return cluster.enableWal(cacheNames); + } + /** {@inheritDoc} */ @Override public boolean disableWal(String cacheName) throws IgniteException { return cluster.disableWal(cacheName); } + /** {@inheritDoc} */ + @Override public boolean disableWal(Collection cacheNames) throws IgniteException { + return cluster.disableWal(cacheNames); + } + /** {@inheritDoc} */ @Override public boolean isWalEnabled(String cacheName) { return cluster.isWalEnabled(cacheName); diff --git a/modules/core/src/main/java/org/apache/ignite/internal/cluster/IgniteClusterImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/cluster/IgniteClusterImpl.java index c2b61700f11f3..f205bacbd8b20 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/cluster/IgniteClusterImpl.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/cluster/IgniteClusterImpl.java @@ -632,28 +632,41 @@ private void setBaselineTopology(long topVer, boolean isBaselineAutoAdjust) { /** {@inheritDoc} */ @Override public boolean enableWal(String cacheName) throws IgniteException { - return changeWalMode(cacheName, true); + return changeWalMode(Collections.singleton(cacheName), true); + } + + /** {@inheritDoc} */ + @Override public boolean enableWal(Collection cacheNames) throws IgniteException { + return changeWalMode(cacheNames, true); } /** {@inheritDoc} */ @Override public boolean disableWal(String cacheName) throws IgniteException { - return changeWalMode(cacheName, false); + return changeWalMode(Collections.singleton(cacheName), false); + } + + /** {@inheritDoc} */ + @Override public boolean disableWal(Collection cacheNames) throws IgniteException { + return changeWalMode(cacheNames, false); } /** * Change WAL mode. * - * @param cacheName Cache name. + * @param cacheNames Cache names. * @param enabled Enabled flag. * @return {@code True} if WAL mode was changed as a result of this call. */ - private boolean changeWalMode(String cacheName, boolean enabled) { - A.notNull(cacheName, "cacheName"); + private boolean changeWalMode(Collection cacheNames, boolean enabled) { + A.notNull(cacheNames, "cacheNames"); + + if (cacheNames.isEmpty()) + return false; guard(); try { - return ctx.cache().context().walState().changeWalMode(Collections.singleton(cacheName), enabled).get(); + return ctx.cache().context().walState().changeWalMode(cacheNames, enabled).get(); } catch (IgniteCheckedException e) { throw U.convertException(e); diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/WalModeChangeAdvancedSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/WalModeChangeAdvancedSelfTest.java index c4e4afd674ea9..f59594528d503 100644 --- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/WalModeChangeAdvancedSelfTest.java +++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/WalModeChangeAdvancedSelfTest.java @@ -19,6 +19,7 @@ import java.io.File; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ThreadLocalRandom; @@ -27,6 +28,7 @@ import org.apache.ignite.Ignite; import org.apache.ignite.IgniteCache; import org.apache.ignite.IgniteException; +import org.apache.ignite.configuration.CacheConfiguration; import org.apache.ignite.internal.IgniteClientReconnectAbstractTest; import org.apache.ignite.internal.IgniteEx; import org.apache.ignite.internal.IgniteInternalFuture; @@ -699,4 +701,71 @@ private static void checkConcurrentOperations(AtomicBoolean done, Ignite node) { throw new RuntimeException(e); } } + + /** + * Test that WAL mode change for caches from the same group requires all caches to be specified. + * + * @throws Exception If failed. + */ + @Test + public void testWalModeChangeRequiresAllGroupCaches() throws Exception { + IgniteEx srv = startGrid(config(SRV_1, false, false)); + + srv.cluster().state(ACTIVE); + + CacheConfiguration cacheCfg1 = cacheConfig(CACHE_NAME, PARTITIONED, TRANSACTIONAL); + CacheConfiguration cacheCfg2 = cacheConfig(CACHE_NAME_2, PARTITIONED, TRANSACTIONAL); + + cacheCfg1.setGroupName("testGroup"); + cacheCfg2.setGroupName("testGroup"); + + srv.getOrCreateCache(cacheCfg1); + srv.getOrCreateCache(cacheCfg2); + + assertForAllNodes(CACHE_NAME, true); + assertForAllNodes(CACHE_NAME_2, true); + + try { + srv.cluster().disableWal(CACHE_NAME); + fail("Should have thrown exception when trying to disable WAL for only one cache from a group"); + } + catch (IgniteException e) { + String expectedMsg = "Cannot change WAL mode because not all cache names belonging to the group are provided"; + assertTrue("Expected message about missing caches, but got: " + e.getMessage(), + e.getMessage().contains(expectedMsg)); + } + + assertForAllNodes(CACHE_NAME, true); + assertForAllNodes(CACHE_NAME_2, true); + + try { + srv.cluster().enableWal(CACHE_NAME); + fail("Should have thrown exception when trying to change WAL mode for only one cache from a group"); + } + catch (IgniteException e) { + String expectedMsg = "Cannot change WAL mode because not all cache names belonging to the group are provided"; + assertTrue("Expected message about missing caches, but got: " + e.getMessage(), + e.getMessage().contains(expectedMsg)); + } + + srv.cluster().disableWal(Arrays.asList(CACHE_NAME, CACHE_NAME_2)); + + assertForAllNodes(CACHE_NAME, false); + assertForAllNodes(CACHE_NAME_2, false); + + try { + srv.cluster().enableWal(CACHE_NAME); + fail("Should have thrown exception when trying to enable WAL for only one cache from a group"); + } + catch (IgniteException e) { + String expectedMsg = "Cannot change WAL mode because not all cache names belonging to the group are provided"; + assertTrue("Expected message about missing caches, but got: " + e.getMessage(), + e.getMessage().contains(expectedMsg)); + } + + srv.cluster().enableWal(Arrays.asList(CACHE_NAME, CACHE_NAME_2)); + + assertForAllNodes(CACHE_NAME, true); + assertForAllNodes(CACHE_NAME_2, true); + } } diff --git a/modules/core/src/test/java/org/apache/ignite/testframework/junits/multijvm/IgniteClusterProcessProxy.java b/modules/core/src/test/java/org/apache/ignite/testframework/junits/multijvm/IgniteClusterProcessProxy.java index 8ffa254abba53..8aed097f2f4da 100644 --- a/modules/core/src/test/java/org/apache/ignite/testframework/junits/multijvm/IgniteClusterProcessProxy.java +++ b/modules/core/src/test/java/org/apache/ignite/testframework/junits/multijvm/IgniteClusterProcessProxy.java @@ -172,11 +172,21 @@ public IgniteClusterProcessProxy(IgniteProcessProxy proxy) { throw new UnsupportedOperationException("Operation is not supported yet."); } + /** {@inheritDoc} */ + @Override public boolean enableWal(Collection cacheNames) throws IgniteException { + throw new UnsupportedOperationException("Operation is not supported yet."); + } + /** {@inheritDoc} */ @Override public boolean disableWal(String cacheName) throws IgniteException { throw new UnsupportedOperationException("Operation is not supported yet."); } + /** {@inheritDoc} */ + @Override public boolean disableWal(Collection cacheNames) throws IgniteException { + throw new UnsupportedOperationException("Operation is not supported yet."); + } + /** {@inheritDoc} */ @Override public boolean isWalEnabled(String cacheName) { throw new UnsupportedOperationException("Operation is not supported yet."); From e3082eb4e12c2dbee4f06c065b33f346862dd062 Mon Sep 17 00:00:00 2001 From: Daniil Date: Mon, 22 Dec 2025 03:32:27 +0300 Subject: [PATCH 2/9] replace try-catch with assertThrows --- .../cache/WalModeChangeAdvancedSelfTest.java | 51 +++++++++---------- 1 file changed, 24 insertions(+), 27 deletions(-) diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/WalModeChangeAdvancedSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/WalModeChangeAdvancedSelfTest.java index f59594528d503..8a1eaac640b0a 100644 --- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/WalModeChangeAdvancedSelfTest.java +++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/WalModeChangeAdvancedSelfTest.java @@ -725,43 +725,40 @@ public void testWalModeChangeRequiresAllGroupCaches() throws Exception { assertForAllNodes(CACHE_NAME, true); assertForAllNodes(CACHE_NAME_2, true); - try { - srv.cluster().disableWal(CACHE_NAME); - fail("Should have thrown exception when trying to disable WAL for only one cache from a group"); - } - catch (IgniteException e) { - String expectedMsg = "Cannot change WAL mode because not all cache names belonging to the group are provided"; - assertTrue("Expected message about missing caches, but got: " + e.getMessage(), - e.getMessage().contains(expectedMsg)); - } + assertThrows( + () -> { + srv.cluster().disableWal(CACHE_NAME); + return null; + }, + IgniteException.class, + "Cannot change WAL mode because not all cache names belonging to the group are provided" + ); assertForAllNodes(CACHE_NAME, true); assertForAllNodes(CACHE_NAME_2, true); - try { - srv.cluster().enableWal(CACHE_NAME); - fail("Should have thrown exception when trying to change WAL mode for only one cache from a group"); - } - catch (IgniteException e) { - String expectedMsg = "Cannot change WAL mode because not all cache names belonging to the group are provided"; - assertTrue("Expected message about missing caches, but got: " + e.getMessage(), - e.getMessage().contains(expectedMsg)); - } + assertThrows( + () -> { + srv.cluster().enableWal(CACHE_NAME); + return null; + }, + IgniteException.class, + "Cannot change WAL mode because not all cache names belonging to the group are provided" + ); srv.cluster().disableWal(Arrays.asList(CACHE_NAME, CACHE_NAME_2)); assertForAllNodes(CACHE_NAME, false); assertForAllNodes(CACHE_NAME_2, false); - try { - srv.cluster().enableWal(CACHE_NAME); - fail("Should have thrown exception when trying to enable WAL for only one cache from a group"); - } - catch (IgniteException e) { - String expectedMsg = "Cannot change WAL mode because not all cache names belonging to the group are provided"; - assertTrue("Expected message about missing caches, but got: " + e.getMessage(), - e.getMessage().contains(expectedMsg)); - } + assertThrows( + () -> { + srv.cluster().enableWal(CACHE_NAME); + return null; + }, + IgniteException.class, + "Cannot change WAL mode because not all cache names belonging to the group are provided" + ); srv.cluster().enableWal(Arrays.asList(CACHE_NAME, CACHE_NAME_2)); From bcd2fc6624e33794fa8e699e70c8a2ef6cea1901 Mon Sep 17 00:00:00 2001 From: Daniil Date: Mon, 22 Dec 2025 14:03:34 +0300 Subject: [PATCH 3/9] extend validation --- .../cache/WalModeChangeAdvancedSelfTest.java | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/WalModeChangeAdvancedSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/WalModeChangeAdvancedSelfTest.java index 8a1eaac640b0a..6016a4e69adb3 100644 --- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/WalModeChangeAdvancedSelfTest.java +++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/WalModeChangeAdvancedSelfTest.java @@ -21,6 +21,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; +import java.util.Collections; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.atomic.AtomicBoolean; @@ -734,12 +735,21 @@ public void testWalModeChangeRequiresAllGroupCaches() throws Exception { "Cannot change WAL mode because not all cache names belonging to the group are provided" ); + assertThrows( + () -> { + srv.cluster().disableWal(Collections.singleton(CACHE_NAME_2)); + return null; + }, + IgniteException.class, + "Cannot change WAL mode because not all cache names belonging to the group are provided" + ); + assertForAllNodes(CACHE_NAME, true); assertForAllNodes(CACHE_NAME_2, true); assertThrows( () -> { - srv.cluster().enableWal(CACHE_NAME); + srv.cluster().enableWal(Collections.singleton(CACHE_NAME)); return null; }, IgniteException.class, @@ -753,7 +763,7 @@ public void testWalModeChangeRequiresAllGroupCaches() throws Exception { assertThrows( () -> { - srv.cluster().enableWal(CACHE_NAME); + srv.cluster().enableWal(CACHE_NAME_2); return null; }, IgniteException.class, From dd502d4bf667e667b0b981da3a40c8cc6d6d2c3f Mon Sep 17 00:00:00 2001 From: Daniil Date: Mon, 22 Dec 2025 22:58:57 +0300 Subject: [PATCH 4/9] add test that reveals problem --- .../util/GridCommandHandlerWalTest.java | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/modules/control-utility/src/test/java/org/apache/ignite/util/GridCommandHandlerWalTest.java b/modules/control-utility/src/test/java/org/apache/ignite/util/GridCommandHandlerWalTest.java index 19ae93986dddb..5722a73a4feb2 100644 --- a/modules/control-utility/src/test/java/org/apache/ignite/util/GridCommandHandlerWalTest.java +++ b/modules/control-utility/src/test/java/org/apache/ignite/util/GridCommandHandlerWalTest.java @@ -17,9 +17,11 @@ package org.apache.ignite.util; +import java.util.Arrays; import java.util.Objects; import java.util.regex.Pattern; import org.apache.ignite.cluster.ClusterState; +import org.apache.ignite.configuration.CacheConfiguration; import org.apache.ignite.configuration.DataRegionConfiguration; import org.apache.ignite.configuration.DataStorageConfiguration; import org.apache.ignite.configuration.IgniteConfiguration; @@ -171,6 +173,45 @@ public void testWalStateInMemoryCdcCluster() throws Exception { assertFalse(testOut.toString().contains("cache3")); } + /** + * Test WAL mode change for a cache group contains multiple caches. + * @throws Exception If failed. + */ + @Test + public void testWalChangeForMultiCacheGroup() throws Exception { + clusterState = 0; // PDS cluster. + + IgniteEx srv = startGrids(2); + srv.cluster().state(ClusterState.ACTIVE); + + srv.createCache(new CacheConfiguration("cache1") + .setGroupName("testGroup")); + srv.createCache(new CacheConfiguration("cache2") + .setGroupName("testGroup")); + + assertEquals(EXIT_CODE_OK, execute("--wal", "state", "--groups", "testGroup")); + outputContains(".*testGroup.*true.*true.*true.*true.*false"); + + // disableWal fails, but EXIT_CODE_OK + assertEquals(EXIT_CODE_OK, execute("--wal", "disable", "--groups", "testGroup")); + + // WAL is still enabled + assertEquals(EXIT_CODE_OK, execute("--wal", "state", "--groups", "testGroup")); + outputContains(".*testGroup.*true.*true.*true.*true.*false"); + + srv.cluster().disableWal(Arrays.asList("cache1", "cache2")); + + assertEquals(EXIT_CODE_OK, execute("--wal", "state", "--groups", "testGroup")); + outputContains(".*testGroup.*true.*false.*true.*true.*false"); + + // enableWal fails + assertEquals(EXIT_CODE_OK, execute("--wal", "disable", "--groups", "testGroup")); + + // WAL is still disabled + assertEquals(EXIT_CODE_OK, execute("--wal", "state", "--groups", "testGroup")); + outputContains(".*testGroup.*true.*false.*true.*true.*false"); + } + /** */ private void outputContains(String regexp) { assertTrue(Pattern.compile(regexp).matcher(testOut.toString()).find()); From 9f73e774483859cd2846c9ebfa59b58fbd43058b Mon Sep 17 00:00:00 2001 From: Daniil Date: Wed, 24 Dec 2025 15:53:34 +0300 Subject: [PATCH 5/9] support cache groups in change WAL methods --- .../util/GridCommandHandlerWalTest.java | 14 +---- .../java/org/apache/ignite/IgniteCluster.java | 57 ++----------------- .../cluster/IgniteClusterAsyncImpl.java | 18 ++---- .../internal/cluster/IgniteClusterImpl.java | 42 +++++++------- .../management/wal/WalSetStateTask.java | 10 +--- .../cache/WalModeChangeAdvancedSelfTest.java | 13 ++--- .../multijvm/IgniteClusterProcessProxy.java | 14 +---- 7 files changed, 42 insertions(+), 126 deletions(-) diff --git a/modules/control-utility/src/test/java/org/apache/ignite/util/GridCommandHandlerWalTest.java b/modules/control-utility/src/test/java/org/apache/ignite/util/GridCommandHandlerWalTest.java index 5722a73a4feb2..aa8e362780cd6 100644 --- a/modules/control-utility/src/test/java/org/apache/ignite/util/GridCommandHandlerWalTest.java +++ b/modules/control-utility/src/test/java/org/apache/ignite/util/GridCommandHandlerWalTest.java @@ -17,7 +17,6 @@ package org.apache.ignite.util; -import java.util.Arrays; import java.util.Objects; import java.util.regex.Pattern; import org.apache.ignite.cluster.ClusterState; @@ -192,24 +191,15 @@ public void testWalChangeForMultiCacheGroup() throws Exception { assertEquals(EXIT_CODE_OK, execute("--wal", "state", "--groups", "testGroup")); outputContains(".*testGroup.*true.*true.*true.*true.*false"); - // disableWal fails, but EXIT_CODE_OK assertEquals(EXIT_CODE_OK, execute("--wal", "disable", "--groups", "testGroup")); - // WAL is still enabled - assertEquals(EXIT_CODE_OK, execute("--wal", "state", "--groups", "testGroup")); - outputContains(".*testGroup.*true.*true.*true.*true.*false"); - - srv.cluster().disableWal(Arrays.asList("cache1", "cache2")); - assertEquals(EXIT_CODE_OK, execute("--wal", "state", "--groups", "testGroup")); outputContains(".*testGroup.*true.*false.*true.*true.*false"); - // enableWal fails - assertEquals(EXIT_CODE_OK, execute("--wal", "disable", "--groups", "testGroup")); + assertEquals(EXIT_CODE_OK, execute("--wal", "enable", "--groups", "testGroup")); - // WAL is still disabled assertEquals(EXIT_CODE_OK, execute("--wal", "state", "--groups", "testGroup")); - outputContains(".*testGroup.*true.*false.*true.*true.*false"); + outputContains(".*testGroup.*true.*true.*true.*true.*false"); } /** */ diff --git a/modules/core/src/main/java/org/apache/ignite/IgniteCluster.java b/modules/core/src/main/java/org/apache/ignite/IgniteCluster.java index e5c1b8f41ee83..4e85172cdd993 100644 --- a/modules/core/src/main/java/org/apache/ignite/IgniteCluster.java +++ b/modules/core/src/main/java/org/apache/ignite/IgniteCluster.java @@ -536,38 +536,13 @@ public IgniteFuture> startNodesAsync(Collecti * Cache may be stuck in inconsistent state due to violation of these conditions. It is advised to destroy * such cache. * - * @param cacheName Cache name. + * @param cacheOrGrpName Cache or cache group name. * @return Whether WAL disabled by this call. * @throws IgniteException If error occurs. * @see #enableWal(String) * @see #isWalEnabled(String) */ - public boolean disableWal(String cacheName) throws IgniteException; - - /** - * Disables write-ahead logging for specified caches. When WAL is disabled, changes are not logged to disk. - * This significantly improves cache update speed. The drawback is absence of local crash-recovery guarantees. - * If node is crashed, local content of WAL-disabled cache will be cleared on restart to avoid data corruption. - *

- * Internally this method will wait for all current cache operations to finish and prevent new cache operations - * from being executed. Then checkpoint is initiated to flush all data to disk. Control is returned to the callee - * when all dirty pages are prepared for checkpoint, but not necessarily flushed to disk. - *

- * WAL state can be changed only for persistent caches. - *

- * NOTE: - * Currently, this method should only be called on a stable topology when no nodes are leaving or joining cluster, - * and all baseline nodes are present. - * Cache may be stuck in inconsistent state due to violation of these conditions. It is advised to destroy - * such cache. - * - * @param cacheNames Collection of cache names, all caches must be in the same cache group. - * @return Whether WAL disabled by this call. - * @throws IgniteException If error occurs. - * @see #enableWal(Collection) - * @see #isWalEnabled(String) - */ - public boolean disableWal(Collection cacheNames) throws IgniteException; + public boolean disableWal(String cacheOrGrpName) throws IgniteException; /** * Enables write-ahead logging for specified cache. Restoring crash-recovery guarantees of a previous call to @@ -585,37 +560,13 @@ public IgniteFuture> startNodesAsync(Collecti * Cache may be stuck in inconsistent state due to violation of these conditions. It is advised to destroy * such cache. * - * @param cacheName Cache name. + * @param cacheOrGrpName Cache or cache group name. * @return Whether WAL enabled by this call. * @throws IgniteException If error occurs. * @see #disableWal(String) * @see #isWalEnabled(String) */ - public boolean enableWal(String cacheName) throws IgniteException; - - /** - * Enables write-ahead logging for specified caches. Restoring crash-recovery guarantees of a previous call to - * {@link #disableWal(Collection)}. - *

- * Internally this method will wait for all current cache operations to finish and prevent new cache operations - * from being executed. Then checkpoint is initiated to flush all data to disk. Control is returned to the callee - * when all data is persisted to disk. - *

- * WAL state can be changed only for persistent caches. - *

- * NOTE: - * Currently, this method should only be called on a stable topology when no nodes are leaving or joining cluster, - * and all baseline nodes are present. - * Cache may be stuck in inconsistent state due to violation of these conditions. It is advised to destroy - * such cache. - * - * @param cacheNames Collection of cache names, all caches must be in the same cache group. - * @return Whether WAL state enabled by this call. - * @throws IgniteException If error occurs. - * @see #disableWal(Collection) - * @see #isWalEnabled(String) - */ - public boolean enableWal(Collection cacheNames) throws IgniteException; + public boolean enableWal(String cacheOrGrpName) throws IgniteException; /** * Checks if write-ahead logging is enabled for specified cache. diff --git a/modules/core/src/main/java/org/apache/ignite/internal/cluster/IgniteClusterAsyncImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/cluster/IgniteClusterAsyncImpl.java index 481b54d0ba2f7..08c8f2d2c7bb6 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/cluster/IgniteClusterAsyncImpl.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/cluster/IgniteClusterAsyncImpl.java @@ -345,23 +345,13 @@ public IgniteClusterAsyncImpl(IgniteClusterImpl cluster) { } /** {@inheritDoc} */ - @Override public boolean enableWal(String cacheName) throws IgniteException { - return cluster.enableWal(cacheName); + @Override public boolean enableWal(String cacheOrGrpName) throws IgniteException { + return cluster.enableWal(cacheOrGrpName); } /** {@inheritDoc} */ - @Override public boolean enableWal(Collection cacheNames) throws IgniteException { - return cluster.enableWal(cacheNames); - } - - /** {@inheritDoc} */ - @Override public boolean disableWal(String cacheName) throws IgniteException { - return cluster.disableWal(cacheName); - } - - /** {@inheritDoc} */ - @Override public boolean disableWal(Collection cacheNames) throws IgniteException { - return cluster.disableWal(cacheNames); + @Override public boolean disableWal(String cacheOrGrpName) throws IgniteException { + return cluster.disableWal(cacheOrGrpName); } /** {@inheritDoc} */ diff --git a/modules/core/src/main/java/org/apache/ignite/internal/cluster/IgniteClusterImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/cluster/IgniteClusterImpl.java index f205bacbd8b20..84552ac8b4fd8 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/cluster/IgniteClusterImpl.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/cluster/IgniteClusterImpl.java @@ -52,6 +52,7 @@ import org.apache.ignite.internal.GridKernalContext; import org.apache.ignite.internal.IgniteComponentType; import org.apache.ignite.internal.IgniteInternalFuture; +import org.apache.ignite.internal.processors.cache.CacheGroupDescriptor; import org.apache.ignite.internal.processors.cache.DynamicCacheDescriptor; import org.apache.ignite.internal.processors.cluster.BaselineTopology; import org.apache.ignite.internal.processors.cluster.baseline.autoadjust.BaselineAutoAdjustStatus; @@ -631,40 +632,41 @@ private void setBaselineTopology(long topVer, boolean isBaselineAutoAdjust) { } /** {@inheritDoc} */ - @Override public boolean enableWal(String cacheName) throws IgniteException { - return changeWalMode(Collections.singleton(cacheName), true); + @Override public boolean enableWal(String cacheOrGrpName) throws IgniteException { + return changeWalMode(cacheOrGrpName, true); } /** {@inheritDoc} */ - @Override public boolean enableWal(Collection cacheNames) throws IgniteException { - return changeWalMode(cacheNames, true); - } - - /** {@inheritDoc} */ - @Override public boolean disableWal(String cacheName) throws IgniteException { - return changeWalMode(Collections.singleton(cacheName), false); - } - - /** {@inheritDoc} */ - @Override public boolean disableWal(Collection cacheNames) throws IgniteException { - return changeWalMode(cacheNames, false); + @Override public boolean disableWal(String cacheOrGrpName) throws IgniteException { + return changeWalMode(cacheOrGrpName, false); } /** * Change WAL mode. * - * @param cacheNames Cache names. + * @param cacheOrGrpName Cache or cache group name. * @param enabled Enabled flag. * @return {@code True} if WAL mode was changed as a result of this call. */ - private boolean changeWalMode(Collection cacheNames, boolean enabled) { - A.notNull(cacheNames, "cacheNames"); - - if (cacheNames.isEmpty()) - return false; + private boolean changeWalMode(String cacheOrGrpName, boolean enabled) { + A.notNull(cacheOrGrpName, "cacheOrGrpName"); guard(); + List cacheNames = new ArrayList<>(); + + int cacheOrGrpId = CU.cacheId(cacheOrGrpName); + CacheGroupDescriptor grpDesc = ctx.cache().cacheGroupDescriptor(cacheOrGrpId); + + if (grpDesc != null) { + for (DynamicCacheDescriptor cacheDesc : ctx.cache().cacheDescriptors().values()) { + if (cacheDesc.groupId() == cacheOrGrpId) + cacheNames.add(cacheDesc.cacheName()); + } + } + else + cacheNames.add(cacheOrGrpName); + try { return ctx.cache().context().walState().changeWalMode(cacheNames, enabled).get(); } diff --git a/modules/core/src/main/java/org/apache/ignite/internal/management/wal/WalSetStateTask.java b/modules/core/src/main/java/org/apache/ignite/internal/management/wal/WalSetStateTask.java index 63dde2b8606a9..017dd729bb50c 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/management/wal/WalSetStateTask.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/management/wal/WalSetStateTask.java @@ -26,7 +26,6 @@ import org.apache.ignite.internal.management.wal.WalDisableCommand.WalDisableCommandArg; import org.apache.ignite.internal.management.wal.WalEnableCommand.WalEnableCommandArg; import org.apache.ignite.internal.processors.cache.CacheGroupContext; -import org.apache.ignite.internal.processors.cache.GridCacheContext; import org.apache.ignite.internal.util.typedef.F; import org.apache.ignite.internal.visor.VisorJob; import org.apache.ignite.internal.visor.VisorMultiNodeTask; @@ -67,15 +66,10 @@ protected WalDisableJob(@Nullable WalDisableCommandArg arg, boolean debug) { if (grps != null && !grps.contains(grpName)) continue; - GridCacheContext cctx = F.first(gctx.caches()); - - if (cctx == null) - continue; - if (arg instanceof WalEnableCommandArg) - ignite.cluster().enableWal(cctx.name()); + ignite.cluster().enableWal(grpName); else - ignite.cluster().disableWal(cctx.name()); + ignite.cluster().disableWal(grpName); } return null; diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/WalModeChangeAdvancedSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/WalModeChangeAdvancedSelfTest.java index 6016a4e69adb3..3a15b33678b89 100644 --- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/WalModeChangeAdvancedSelfTest.java +++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/WalModeChangeAdvancedSelfTest.java @@ -19,9 +19,7 @@ import java.io.File; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collection; -import java.util.Collections; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.atomic.AtomicBoolean; @@ -569,7 +567,8 @@ public void testCacheDestroy() throws Exception { String msg = e.getMessage(); assert msg.startsWith("Cache doesn't exist") || - msg.startsWith("Failed to change WAL mode because some caches no longer exist") : + msg.startsWith("Failed to change WAL mode because some caches no longer exist") || + msg.startsWith("Cache names cannot be empty.") : e.getMessage(); } finally { @@ -737,7 +736,7 @@ public void testWalModeChangeRequiresAllGroupCaches() throws Exception { assertThrows( () -> { - srv.cluster().disableWal(Collections.singleton(CACHE_NAME_2)); + srv.cluster().disableWal(CACHE_NAME_2); return null; }, IgniteException.class, @@ -749,14 +748,14 @@ public void testWalModeChangeRequiresAllGroupCaches() throws Exception { assertThrows( () -> { - srv.cluster().enableWal(Collections.singleton(CACHE_NAME)); + srv.cluster().enableWal(CACHE_NAME); return null; }, IgniteException.class, "Cannot change WAL mode because not all cache names belonging to the group are provided" ); - srv.cluster().disableWal(Arrays.asList(CACHE_NAME, CACHE_NAME_2)); + srv.cluster().disableWal("testGroup"); assertForAllNodes(CACHE_NAME, false); assertForAllNodes(CACHE_NAME_2, false); @@ -770,7 +769,7 @@ public void testWalModeChangeRequiresAllGroupCaches() throws Exception { "Cannot change WAL mode because not all cache names belonging to the group are provided" ); - srv.cluster().enableWal(Arrays.asList(CACHE_NAME, CACHE_NAME_2)); + srv.cluster().enableWal("testGroup"); assertForAllNodes(CACHE_NAME, true); assertForAllNodes(CACHE_NAME_2, true); diff --git a/modules/core/src/test/java/org/apache/ignite/testframework/junits/multijvm/IgniteClusterProcessProxy.java b/modules/core/src/test/java/org/apache/ignite/testframework/junits/multijvm/IgniteClusterProcessProxy.java index 8aed097f2f4da..2a60e28b4c8bd 100644 --- a/modules/core/src/test/java/org/apache/ignite/testframework/junits/multijvm/IgniteClusterProcessProxy.java +++ b/modules/core/src/test/java/org/apache/ignite/testframework/junits/multijvm/IgniteClusterProcessProxy.java @@ -168,22 +168,12 @@ public IgniteClusterProcessProxy(IgniteProcessProxy proxy) { } /** {@inheritDoc} */ - @Override public boolean enableWal(String cacheName) throws IgniteException { + @Override public boolean enableWal(String cacheOrGrpName) throws IgniteException { throw new UnsupportedOperationException("Operation is not supported yet."); } /** {@inheritDoc} */ - @Override public boolean enableWal(Collection cacheNames) throws IgniteException { - throw new UnsupportedOperationException("Operation is not supported yet."); - } - - /** {@inheritDoc} */ - @Override public boolean disableWal(String cacheName) throws IgniteException { - throw new UnsupportedOperationException("Operation is not supported yet."); - } - - /** {@inheritDoc} */ - @Override public boolean disableWal(Collection cacheNames) throws IgniteException { + @Override public boolean disableWal(String cacheOrGrpName) throws IgniteException { throw new UnsupportedOperationException("Operation is not supported yet."); } From 3b993fd0060b860d8a4b0ec8a612c824035e1e97 Mon Sep 17 00:00:00 2001 From: Daniil Date: Thu, 25 Dec 2025 16:28:23 +0300 Subject: [PATCH 6/9] add result reporting to WAL management commands --- .../management/wal/WalDisableCommand.java | 23 +++- .../management/wal/WalEnableCommand.java | 9 +- .../management/wal/WalSetStateTask.java | 84 +++++++++++--- .../management/wal/WalSetStateTaskResult.java | 106 ++++++++++++++++++ 4 files changed, 203 insertions(+), 19 deletions(-) create mode 100644 modules/core/src/main/java/org/apache/ignite/internal/management/wal/WalSetStateTaskResult.java diff --git a/modules/core/src/main/java/org/apache/ignite/internal/management/wal/WalDisableCommand.java b/modules/core/src/main/java/org/apache/ignite/internal/management/wal/WalDisableCommand.java index 9802dc318646c..bfc8ca00657ab 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/management/wal/WalDisableCommand.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/management/wal/WalDisableCommand.java @@ -17,10 +17,12 @@ package org.apache.ignite.internal.management.wal; +import java.util.List; +import java.util.function.Consumer; import org.apache.ignite.internal.management.api.ComputeCommand; /** */ -public class WalDisableCommand implements ComputeCommand { +public class WalDisableCommand implements ComputeCommand { /** {@inheritDoc} */ @Override public Class taskClass() { return WalSetStateTask.class; @@ -41,6 +43,25 @@ public class WalDisableCommand implements ComputeCommand printer) { + String operation = arg instanceof WalDisableCommandArg ? "disable" : "enable"; + List successGrps = res.successGroups(); + List errors = res.errorMessages(); + + if (!successGrps.isEmpty()) { + printer.accept("Successfully " + operation + "d WAL for groups:"); + for (String grp : successGrps) + printer.accept(" " + grp); + } + + if (errors != null && !errors.isEmpty()) { + printer.accept("Errors occurred:"); + for (String error : errors) + printer.accept(" " + error); + } + } + /** */ public static class WalDisableCommandArg extends WalStateCommandArg { /** */ diff --git a/modules/core/src/main/java/org/apache/ignite/internal/management/wal/WalEnableCommand.java b/modules/core/src/main/java/org/apache/ignite/internal/management/wal/WalEnableCommand.java index 950f416e54a9c..1ea9a7d527c52 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/management/wal/WalEnableCommand.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/management/wal/WalEnableCommand.java @@ -17,11 +17,12 @@ package org.apache.ignite.internal.management.wal; +import java.util.function.Consumer; import org.apache.ignite.internal.management.api.ComputeCommand; import org.apache.ignite.internal.management.wal.WalDisableCommand.WalDisableCommandArg; /** */ -public class WalEnableCommand implements ComputeCommand { +public class WalEnableCommand implements ComputeCommand { /** {@inheritDoc} */ @Override public Class taskClass() { return WalSetStateTask.class; @@ -37,6 +38,12 @@ public class WalEnableCommand implements ComputeCommand printer) { + WalDisableCommand cmd = new WalDisableCommand(); + cmd.printResult(arg, res, printer); + } + /** */ public static class WalEnableCommandArg extends WalDisableCommandArg { /** */ diff --git a/modules/core/src/main/java/org/apache/ignite/internal/management/wal/WalSetStateTask.java b/modules/core/src/main/java/org/apache/ignite/internal/management/wal/WalSetStateTask.java index 017dd729bb50c..672e93202573d 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/management/wal/WalSetStateTask.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/management/wal/WalSetStateTask.java @@ -17,6 +17,7 @@ package org.apache.ignite.internal.management.wal; +import java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; import java.util.List; @@ -32,22 +33,43 @@ import org.jetbrains.annotations.Nullable; /** */ -public class WalSetStateTask extends VisorMultiNodeTask { +public class WalSetStateTask extends VisorMultiNodeTask { /** */ private static final long serialVersionUID = 0; /** {@inheritDoc} */ - @Override protected VisorJob job(WalDisableCommandArg arg) { - return new WalDisableJob(arg, false); + @Override protected VisorJob job(WalDisableCommandArg arg) { + return new WalDisableJob(arg, debug); } /** {@inheritDoc} */ - @Override protected @Nullable Void reduce0(List res) throws IgniteException { - return null; + @Override protected @Nullable WalSetStateTaskResult reduce0(List res) throws IgniteException { + Set successGrps = new HashSet<>(); + List errors = new ArrayList<>(); + + for (ComputeJobResult jobRes : res) { + if (jobRes.getException() != null) { + Throwable e = jobRes.getException(); + errors.add("Node " + jobRes.getNode().consistentId() + + ": Task execution failed - " + e.getMessage()); + } + else { + WalSetStateTaskResult result = jobRes.getData(); + if (result.successGroups() != null) + successGrps.addAll(result.successGroups()); + if (!Boolean.TRUE.equals(result.success()) && result.errorMessages() != null) + errors.addAll(result.errorMessages()); + } + } + + if (errors.isEmpty()) + return new WalSetStateTaskResult(new ArrayList<>(successGrps)); + else + return new WalSetStateTaskResult(new ArrayList<>(successGrps), errors); } /** */ - private static class WalDisableJob extends VisorJob { + private static class WalDisableJob extends VisorJob { /** */ private static final long serialVersionUID = 0; @@ -57,22 +79,50 @@ protected WalDisableJob(@Nullable WalDisableCommandArg arg, boolean debug) { } /** {@inheritDoc} */ - @Override protected Void run(@Nullable WalDisableCommandArg arg) throws IgniteException { - Set grps = F.isEmpty(arg.groups()) ? null : new HashSet<>(Arrays.asList(arg.groups())); + @Override protected WalSetStateTaskResult run(@Nullable WalDisableCommandArg arg) throws IgniteException { + Set requestedGrps = F.isEmpty(arg.groups()) ? null : new HashSet<>(Arrays.asList(arg.groups())); + boolean isEnable = arg instanceof WalEnableCommandArg; + List successGrps = new ArrayList<>(); + List errors = new ArrayList<>(); + + try { + Set availableGrps = new HashSet<>(); - for (CacheGroupContext gctx : ignite.context().cache().cacheGroups()) { - String grpName = gctx.cacheOrGroupName(); + for (CacheGroupContext gctx : ignite.context().cache().cacheGroups()) { + String grpName = gctx.cacheOrGroupName(); + availableGrps.add(grpName); - if (grps != null && !grps.contains(grpName)) - continue; + if (requestedGrps != null && !requestedGrps.contains(grpName)) + continue; - if (arg instanceof WalEnableCommandArg) - ignite.cluster().enableWal(grpName); + try { + if (isEnable) + ignite.cluster().enableWal(grpName); + else + ignite.cluster().disableWal(grpName); + + successGrps.add(grpName); + } + catch (Exception e) { + errors.add("Failed to " + (isEnable ? "enable" : "disable") + + " WAL for cache group: " + grpName + " - " + e.getMessage()); + } + } + + for (String requestedGrp : requestedGrps) { + if (!availableGrps.contains(requestedGrp)) + errors.add("Cache group not found: " + requestedGrp); + } + + if (errors.isEmpty()) + return new WalSetStateTaskResult(successGrps); else - ignite.cluster().disableWal(grpName); + return new WalSetStateTaskResult(successGrps, errors); + } + catch (Exception e) { + errors.add("Failed to execute operation - " + e.getMessage()); + return new WalSetStateTaskResult(successGrps, errors); } - - return null; } } } diff --git a/modules/core/src/main/java/org/apache/ignite/internal/management/wal/WalSetStateTaskResult.java b/modules/core/src/main/java/org/apache/ignite/internal/management/wal/WalSetStateTaskResult.java new file mode 100644 index 0000000000000..6cf254c5e7a16 --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/internal/management/wal/WalSetStateTaskResult.java @@ -0,0 +1,106 @@ +/* + * 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.management.wal; + +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import java.util.ArrayList; +import java.util.List; +import org.apache.ignite.internal.dto.IgniteDataTransferObject; +import org.apache.ignite.internal.util.typedef.internal.U; + +/** + * Result of WAL enable/disable operation. + */ +public class WalSetStateTaskResult extends IgniteDataTransferObject { + /** */ + private static final long serialVersionUID = 0L; + + /** Success flag. */ + private Boolean success; + + /** Successfully processed groups. */ + private List successGrps; + + /** Error messages if operation failed. */ + private List errMsgs; + + /** Default constructor. */ + public WalSetStateTaskResult() { + // No-op. + } + + /** + * Constructor for success. + * + * @param successGrps Successfully processed groups. + */ + public WalSetStateTaskResult(List successGrps) { + this.success = true; + this.successGrps = new ArrayList<>(successGrps); + this.errMsgs = null; + } + + /** + * Constructor for failure. + * + * @param successGrps Successfully processed groups. + * @param errMsgs Error messages. + */ + public WalSetStateTaskResult(List successGrps, List errMsgs) { + this.success = false; + this.successGrps = new ArrayList<>(successGrps); + this.errMsgs = new ArrayList<>(errMsgs); + } + + /** {@inheritDoc} */ + @Override protected void writeExternalData(ObjectOutput out) throws IOException { + out.writeObject(success); + U.writeCollection(out, successGrps); + U.writeCollection(out, errMsgs); + } + + /** {@inheritDoc} */ + @Override protected void readExternalData(ObjectInput in) throws IOException, ClassNotFoundException { + success = (Boolean)in.readObject(); + successGrps = U.readList(in); + errMsgs = U.readList(in); + } + + /** + * @return Success flag. + */ + public Boolean success() { + return success; + } + + /** + * @return Successfully processed groups. + */ + public List successGroups() { + return successGrps; + } + + /** + * @return Error messages if operation failed. + */ + public List errorMessages() { + return errMsgs; + } +} From b6c94a8a5cd49b6c44f981f90b66905ba0fe7285 Mon Sep 17 00:00:00 2001 From: Daniil Date: Tue, 30 Dec 2025 00:03:20 +0300 Subject: [PATCH 7/9] remove extra newline --- .../apache/ignite/internal/management/wal/WalSetStateTask.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/modules/core/src/main/java/org/apache/ignite/internal/management/wal/WalSetStateTask.java b/modules/core/src/main/java/org/apache/ignite/internal/management/wal/WalSetStateTask.java index 672e93202573d..6075a043eaea2 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/management/wal/WalSetStateTask.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/management/wal/WalSetStateTask.java @@ -50,8 +50,7 @@ public class WalSetStateTask extends VisorMultiNodeTask Date: Tue, 30 Dec 2025 12:46:50 +0300 Subject: [PATCH 8/9] update tests to verify commands output --- .../util/GridCommandHandlerWalTest.java | 92 +++++++++++++++---- .../management/wal/WalDisableCommand.java | 2 +- 2 files changed, 77 insertions(+), 17 deletions(-) diff --git a/modules/control-utility/src/test/java/org/apache/ignite/util/GridCommandHandlerWalTest.java b/modules/control-utility/src/test/java/org/apache/ignite/util/GridCommandHandlerWalTest.java index 4417847b18d96..57cb9592290d1 100644 --- a/modules/control-utility/src/test/java/org/apache/ignite/util/GridCommandHandlerWalTest.java +++ b/modules/control-utility/src/test/java/org/apache/ignite/util/GridCommandHandlerWalTest.java @@ -159,13 +159,17 @@ public void testWalStateInMemoryCdcCluster() throws Exception { srv.createCache("cache3"); assertEquals(EXIT_CODE_OK, execute("--wal", "disable", "--groups", "cache2")); - assertEquals(EXIT_CODE_OK, execute("--wal", "state")); + outputContains("Errors occurred:"); + outputContains("Cannot change WAL mode because persistence is not enabled for cache\\(s\\)"); + assertEquals(EXIT_CODE_OK, execute("--wal", "state")); outputContains(".*cache2.*false.*true.*true.*true.*true"); assertEquals(EXIT_CODE_OK, execute("--wal", "enable", "--groups", "cache2")); - assertEquals(EXIT_CODE_OK, execute("--wal", "state", "--groups", "cache1,cache2")); + outputContains("Errors occurred:"); + outputContains("Cannot change WAL mode because persistence is not enabled for cache\\(s\\)"); + assertEquals(EXIT_CODE_OK, execute("--wal", "state", "--groups", "cache1,cache2")); outputContains(".*cache1.*false.*true.*true.*true.*true"); outputContains(".*cache2.*false.*true.*true.*true.*true"); @@ -173,33 +177,89 @@ public void testWalStateInMemoryCdcCluster() throws Exception { } /** - * Test WAL mode change for a cache group contains multiple caches. + * Test for WAL enable/disable commands. * @throws Exception If failed. */ @Test - public void testWalChangeForMultiCacheGroup() throws Exception { + public void testWalManagementOperations() throws Exception { clusterState = 0; // PDS cluster. IgniteEx srv = startGrids(2); srv.cluster().state(ClusterState.ACTIVE); srv.createCache(new CacheConfiguration<>("cache1") - .setGroupName("testGroup")); + .setGroupName("group1")); srv.createCache(new CacheConfiguration<>("cache2") - .setGroupName("testGroup")); + .setGroupName("group1")); + srv.createCache(new CacheConfiguration<>("cache3") + .setGroupName("group2")); + srv.createCache("cache4"); + + assertEquals(EXIT_CODE_OK, execute("--wal", "state", "--groups", "group1,group2,cache4")); + outputContains(".*group1.*true.*true.*true.*true.*false"); + outputContains(".*group2.*true.*true.*true.*true.*false"); + outputContains(".*cache4.*true.*true.*true.*true.*false"); + + assertEquals(EXIT_CODE_OK, execute("--wal", "disable", "--groups", "group1")); + outputContains("Successfully disabled WAL for groups:"); + outputContains("group1"); + + assertEquals(EXIT_CODE_OK, execute("--wal", "state", "--groups", "group1")); + outputContains(".*group1.*true.*false.*true.*true.*false"); + + assertEquals(EXIT_CODE_OK, execute("--wal", "disable", "--groups", "group1,group2")); + outputContains("Successfully disabled WAL for groups:"); + outputContains("group1"); + outputContains("group2"); + + assertEquals(EXIT_CODE_OK, execute("--wal", "state", "--groups", "group1,group2")); + outputContains(".*group1.*true.*false.*true.*true.*false"); + outputContains(".*group2.*true.*false.*true.*true.*false"); + + assertEquals(EXIT_CODE_OK, execute("--wal", "disable", "--groups", "cache4,nonExistentGroup")); + outputContains("Successfully disabled WAL for groups:"); + outputContains("cache4"); + outputContains("Errors occurred:"); + outputContains("Cache group not found: nonExistentGroup"); + + assertEquals(EXIT_CODE_OK, execute("--wal", "state", "--groups", "cache4")); + outputContains(".*cache4.*true.*false.*true.*true.*false"); + + //Error when using cache name instead of group name + assertEquals(EXIT_CODE_OK, execute("--wal", "enable", "--groups", "cache3")); + outputContains("Errors occurred:"); + outputContains("Cache group not found: cache3"); + + assertEquals(EXIT_CODE_OK, execute("--wal", "enable", "--groups", "group2,cache4")); + outputContains("Successfully enabled WAL for groups:"); + outputContains("group2"); + outputContains("cache4"); + + assertEquals(EXIT_CODE_OK, execute("--wal", "state", "--groups", "group2,cache4")); + outputContains(".*group2.*true.*true.*true.*true.*false"); + outputContains(".*cache4.*true.*true.*true.*true.*false"); + + assertEquals(EXIT_CODE_OK, execute("--wal", "disable")); + outputContains("Successfully disabled WAL for groups:"); + outputContains("group1"); + outputContains("group2"); + outputContains("cache4"); - assertEquals(EXIT_CODE_OK, execute("--wal", "state", "--groups", "testGroup")); - outputContains(".*testGroup.*true.*true.*true.*true.*false"); - - assertEquals(EXIT_CODE_OK, execute("--wal", "disable", "--groups", "testGroup")); - - assertEquals(EXIT_CODE_OK, execute("--wal", "state", "--groups", "testGroup")); - outputContains(".*testGroup.*true.*false.*true.*true.*false"); + assertEquals(EXIT_CODE_OK, execute("--wal", "state")); + outputContains(".*group1.*true.*false.*true.*true.*false"); + outputContains(".*group2.*true.*false.*true.*true.*false"); + outputContains(".*cache4.*true.*false.*true.*true.*false"); - assertEquals(EXIT_CODE_OK, execute("--wal", "enable", "--groups", "testGroup")); + assertEquals(EXIT_CODE_OK, execute("--wal", "enable")); + outputContains("Successfully enabled WAL for groups:"); + outputContains("group1"); + outputContains("group2"); + outputContains("cache4"); - assertEquals(EXIT_CODE_OK, execute("--wal", "state", "--groups", "testGroup")); - outputContains(".*testGroup.*true.*true.*true.*true.*false"); + assertEquals(EXIT_CODE_OK, execute("--wal", "state")); + outputContains(".*group1.*true.*true.*true.*true.*false"); + outputContains(".*group2.*true.*true.*true.*true.*false"); + outputContains(".*cache4.*true.*true.*true.*true.*false"); } /** */ diff --git a/modules/core/src/main/java/org/apache/ignite/internal/management/wal/WalDisableCommand.java b/modules/core/src/main/java/org/apache/ignite/internal/management/wal/WalDisableCommand.java index bfc8ca00657ab..be71045056b77 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/management/wal/WalDisableCommand.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/management/wal/WalDisableCommand.java @@ -45,7 +45,7 @@ public class WalDisableCommand implements ComputeCommand printer) { - String operation = arg instanceof WalDisableCommandArg ? "disable" : "enable"; + String operation = arg instanceof WalEnableCommand.WalEnableCommandArg ? "enable" : "disable"; List successGrps = res.successGroups(); List errors = res.errorMessages(); From d0778e778531f12b7c135be327c3890521d754e3 Mon Sep 17 00:00:00 2001 From: Daniil Date: Tue, 30 Dec 2025 15:26:19 +0300 Subject: [PATCH 9/9] add test for non persistent caches --- .../util/GridCommandHandlerWalTest.java | 36 +++++++++++++++---- 1 file changed, 30 insertions(+), 6 deletions(-) diff --git a/modules/control-utility/src/test/java/org/apache/ignite/util/GridCommandHandlerWalTest.java b/modules/control-utility/src/test/java/org/apache/ignite/util/GridCommandHandlerWalTest.java index 57cb9592290d1..b57e0176dda10 100644 --- a/modules/control-utility/src/test/java/org/apache/ignite/util/GridCommandHandlerWalTest.java +++ b/modules/control-utility/src/test/java/org/apache/ignite/util/GridCommandHandlerWalTest.java @@ -159,17 +159,13 @@ public void testWalStateInMemoryCdcCluster() throws Exception { srv.createCache("cache3"); assertEquals(EXIT_CODE_OK, execute("--wal", "disable", "--groups", "cache2")); - outputContains("Errors occurred:"); - outputContains("Cannot change WAL mode because persistence is not enabled for cache\\(s\\)"); - assertEquals(EXIT_CODE_OK, execute("--wal", "state")); + outputContains(".*cache2.*false.*true.*true.*true.*true"); assertEquals(EXIT_CODE_OK, execute("--wal", "enable", "--groups", "cache2")); - outputContains("Errors occurred:"); - outputContains("Cannot change WAL mode because persistence is not enabled for cache\\(s\\)"); - assertEquals(EXIT_CODE_OK, execute("--wal", "state", "--groups", "cache1,cache2")); + outputContains(".*cache1.*false.*true.*true.*true.*true"); outputContains(".*cache2.*false.*true.*true.*true.*true"); @@ -262,6 +258,34 @@ public void testWalManagementOperations() throws Exception { outputContains(".*cache4.*true.*true.*true.*true.*false"); } + /** + * Test WAL mode change attempts for non-persistent cache groups. + * @throws Exception If failed. + */ + @Test + public void testWalChangeForNonPersistentCaches() throws Exception { + IgniteConfiguration cfg = getConfiguration(getTestIgniteInstanceName(0)); + cfg.setDataStorageConfiguration(new DataStorageConfiguration() + .setDefaultDataRegionConfiguration(new DataRegionConfiguration() + .setPersistenceEnabled(false))); + + IgniteEx srv = startGrid(cfg); + srv.cluster().state(ClusterState.ACTIVE); + + srv.createCache("cache1"); + + assertEquals(EXIT_CODE_OK, execute("--wal", "enable", "--groups", "cache1")); + outputContains("Errors occurred:"); + outputContains("cache1.*Cannot change WAL mode because persistence is not enabled for cache\\(s\\)"); + + assertEquals(EXIT_CODE_OK, execute("--wal", "state", "--groups", "cache1")); + outputContains(".*cache1.*false.*false.*true.*true.*false"); + + assertEquals(EXIT_CODE_OK, execute("--wal", "disable", "--groups", "cache1")); + outputContains("Errors occurred:"); + outputContains("cache1.*Cannot change WAL mode because persistence is not enabled for cache\\(s\\)"); + } + /** */ private void outputContains(String regexp) { assertTrue(Pattern.compile(regexp).matcher(testOut.toString()).find());