You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by na...@apache.org on 2023/11/20 17:06:50 UTC

(ignite) 02/02: IGNITE-20867 Fixed server nodes crashing if the cache directory contains illegal chars (#11047)

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

namelchev pushed a commit to branch ignite-2.16
in repository https://gitbox.apache.org/repos/asf/ignite.git

commit 5a09c8660dea25549ab66f19f18fcf27ad29e404
Author: Anastasia Iakimova <94...@users.noreply.github.com>
AuthorDate: Mon Nov 20 20:05:13 2023 +0300

    IGNITE-20867 Fixed server nodes crashing if the cache directory contains illegal chars (#11047)
    
    (cherry picked from commit 8fbfe9c034d681b2754d8db1ea19340ed6fd010e)
---
 .../processors/cache/ClusterCachesInfo.java        |  24 +++++
 .../cache/distributed/CacheDirectoryNameTest.java  | 118 +++++++++++++++++++++
 .../ignite/testsuites/IgniteCacheTestSuite4.java   |   3 +
 3 files changed, 145 insertions(+)

diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/ClusterCachesInfo.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/ClusterCachesInfo.java
index 97202caedaf..fa9833e20b5 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/ClusterCachesInfo.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/ClusterCachesInfo.java
@@ -18,6 +18,8 @@
 package org.apache.ignite.internal.processors.cache;
 
 import java.io.Serializable;
+import java.nio.file.InvalidPathException;
+import java.nio.file.Paths;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
@@ -95,6 +97,7 @@ import static org.apache.ignite.events.EventType.EVT_NODE_JOINED;
 import static org.apache.ignite.internal.GridComponent.DiscoveryDataExchangeType.CACHE_PROC;
 import static org.apache.ignite.internal.processors.cache.GridCacheProcessor.CLUSTER_READ_ONLY_MODE_ERROR_MSG_FORMAT;
 import static org.apache.ignite.internal.processors.cache.GridLocalConfigManager.validateIncomingConfiguration;
+import static org.apache.ignite.internal.processors.cache.persistence.file.FilePageStoreManager.cacheDirName;
 import static org.apache.ignite.internal.processors.cache.persistence.snapshot.IgniteSnapshotManager.SNP_IN_PROGRESS_ERR_MSG;
 
 /**
@@ -1131,6 +1134,12 @@ public class ClusterCachesInfo {
             }
         }
 
+        if (containsInvalidFileNameChars(ccfg)) {
+            err = new IgniteCheckedException("Cache start failed. Cache or group name contains the characters " +
+                "that are not allowed in file names [cache= + cacheName " +
+                (ccfg.getGroupName() == null ? "" : ", group=" + ccfg.getGroupName()) + ']');
+        }
+
         if (err != null) {
             if (persistedCfgs)
                 res.errs.add(err);
@@ -1196,6 +1205,21 @@ public class ClusterCachesInfo {
         return true;
     }
 
+    /** @return {@code True} if cache directory contains the characters that are not allowed in file names. */
+    private boolean containsInvalidFileNameChars(CacheConfiguration<?, ?> ccfg) {
+        if (!CU.isPersistentCache(ccfg, ctx.config().getDataStorageConfiguration()))
+            return false;
+
+        String expDir = cacheDirName(ccfg);
+
+        try {
+            return !expDir.equals(Paths.get(expDir).toFile().getName());
+        }
+        catch (InvalidPathException ignored) {
+            return true;
+        }
+    }
+
     /**
      * Validate correcteness of new cache start request.
      *
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/CacheDirectoryNameTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/CacheDirectoryNameTest.java
new file mode 100644
index 00000000000..079786957e2
--- /dev/null
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/CacheDirectoryNameTest.java
@@ -0,0 +1,118 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.processors.cache.distributed;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import org.apache.ignite.IgniteCheckedException;
+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;
+import org.apache.ignite.internal.IgniteEx;
+import org.apache.ignite.internal.util.typedef.internal.U;
+import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import static org.apache.ignite.internal.util.lang.GridFunc.asList;
+import static org.apache.ignite.testframework.GridTestUtils.assertThrows;
+import static org.apache.ignite.testframework.GridTestUtils.cartesianProduct;
+
+/**
+ * Test cache directory name validation.
+ */
+@RunWith(Parameterized.class)
+public class CacheDirectoryNameTest extends GridCommonAbstractTest {
+    /** */
+    @Parameterized.Parameter
+    public boolean persistenceEnabled;
+
+    /** */
+    @Parameterized.Parameter(1)
+    public boolean checkGroup;
+
+    /** @return Test parameters. */
+    @Parameterized.Parameters(name = "persistenceEnabled={0}, isGroupName={1}")
+    public static Collection<?> parameters() {
+        return cartesianProduct(
+            asList(false, true), asList(false, true)
+        );
+    }
+
+    /** {@inheritDoc} */
+    @Override protected IgniteConfiguration getConfiguration(String igniteInstanceName) throws Exception {
+        return super.getConfiguration(igniteInstanceName)
+            .setDataStorageConfiguration(new DataStorageConfiguration()
+                .setDefaultDataRegionConfiguration(new DataRegionConfiguration()
+                    .setPersistenceEnabled(persistenceEnabled)));
+    }
+
+    /** {@inheritDoc} */
+    @Override protected void beforeTestsStarted() throws Exception {
+        super.beforeTestsStarted();
+
+        cleanPersistenceDir();
+    }
+
+    /** {@inheritDoc} */
+    @Override protected void afterTest() throws Exception {
+        stopAllGrids();
+
+        cleanPersistenceDir();
+    }
+
+    /** */
+    @Test
+    public void testCacheDirectoryContainsInvalidFileNameChars() throws Exception {
+        IgniteEx srv = startGrid();
+
+        srv.cluster().state(ClusterState.ACTIVE);
+
+        List<String> illegalNames = new ArrayList<>();
+
+        illegalNames.add("/");
+        illegalNames.add("a/b");
+
+        if (U.isWindows()) {
+            illegalNames.add("a>b");
+            illegalNames.add("a\\b");
+        }
+
+        for (String name : illegalNames) {
+            CacheConfiguration<Object, Object> cfg = new CacheConfiguration<>(DEFAULT_CACHE_NAME);
+
+            if (checkGroup)
+                cfg.setGroupName(name);
+            else
+                cfg.setName(name);
+
+            if (persistenceEnabled) {
+                assertThrows(log, () -> srv.createCache(cfg), IgniteCheckedException.class,
+                    "Cache start failed. Cache or group name contains the characters that are not allowed in file names");
+            }
+            else {
+                srv.createCache(cfg);
+                srv.destroyCache(cfg.getName());
+            }
+        }
+    }
+}
diff --git a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheTestSuite4.java b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheTestSuite4.java
index 3e7450275cb..7a225e4890c 100644
--- a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheTestSuite4.java
+++ b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheTestSuite4.java
@@ -96,6 +96,7 @@ import org.apache.ignite.internal.processors.cache.IgniteStartCacheInTransaction
 import org.apache.ignite.internal.processors.cache.IgniteSystemCacheOnClientTest;
 import org.apache.ignite.internal.processors.cache.MarshallerCacheJobRunNodeRestartTest;
 import org.apache.ignite.internal.processors.cache.distributed.CacheAffinityEarlyTest;
+import org.apache.ignite.internal.processors.cache.distributed.CacheDirectoryNameTest;
 import org.apache.ignite.internal.processors.cache.distributed.CacheDiscoveryDataConcurrentJoinTest;
 import org.apache.ignite.internal.processors.cache.distributed.CacheGetFutureHangsSelfTest;
 import org.apache.ignite.internal.processors.cache.distributed.CacheGroupsPreloadTest;
@@ -329,6 +330,8 @@ public class IgniteCacheTestSuite4 {
 
         GridTestUtils.addTestIfNeeded(suite, GridCacheProcessorActiveTxTest.class, ignoredTests);
 
+        GridTestUtils.addTestIfNeeded(suite, CacheDirectoryNameTest.class, ignoredTests);
+
         return suite;
     }
 }