You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@flink.apache.org by lz...@apache.org on 2022/11/23 02:42:48 UTC
[flink-table-store] branch master updated: [FLINK-30139] CodeGenLoader fails when temporary directory is a symlink
This is an automated email from the ASF dual-hosted git repository.
lzljs3620320 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/flink-table-store.git
The following commit(s) were added to refs/heads/master by this push:
new ae96b335 [FLINK-30139] CodeGenLoader fails when temporary directory is a symlink
ae96b335 is described below
commit ae96b335e470a068a7e87f3d1a22c58bf2d82256
Author: Jingsong Lee <ji...@gmail.com>
AuthorDate: Wed Nov 23 10:42:42 2022 +0800
[FLINK-30139] CodeGenLoader fails when temporary directory is a symlink
This closes #397
---
flink-table-store-codegen-loader/pom.xml | 7 ++
.../flink/table/store/codegen/CodeGenLoader.java | 16 ++--
.../flink/table/store/utils/LocalFileUtils.java | 50 +++++++++++
.../table/store/utils/LocalFileUtilsTest.java | 80 +++++++++++++++++
.../flink/table/store/utils/TempDirUtils.java | 100 +++++++++++++++++++++
5 files changed, 247 insertions(+), 6 deletions(-)
diff --git a/flink-table-store-codegen-loader/pom.xml b/flink-table-store-codegen-loader/pom.xml
index b968b507..1cbe9bd7 100644
--- a/flink-table-store-codegen-loader/pom.xml
+++ b/flink-table-store-codegen-loader/pom.xml
@@ -39,6 +39,13 @@ under the License.
<scope>provided</scope>
</dependency>
+ <dependency>
+ <groupId>org.apache.flink</groupId>
+ <artifactId>flink-table-store-common</artifactId>
+ <version>${project.version}</version>
+ <scope>provided</scope>
+ </dependency>
+
<dependency>
<!-- Ensures that flink-table-store-codegen is built beforehand, in order to bundle the jar -->
<groupId>org.apache.flink</groupId>
diff --git a/flink-table-store-codegen-loader/src/main/java/org/apache/flink/table/store/codegen/CodeGenLoader.java b/flink-table-store-codegen-loader/src/main/java/org/apache/flink/table/store/codegen/CodeGenLoader.java
index 938e4cec..6bba6a4c 100644
--- a/flink-table-store-codegen-loader/src/main/java/org/apache/flink/table/store/codegen/CodeGenLoader.java
+++ b/flink-table-store-codegen-loader/src/main/java/org/apache/flink/table/store/codegen/CodeGenLoader.java
@@ -20,6 +20,7 @@ package org.apache.flink.table.store.codegen;
import org.apache.flink.configuration.Configuration;
import org.apache.flink.configuration.ConfigurationUtils;
+import org.apache.flink.table.store.utils.LocalFileUtils;
import org.apache.flink.util.IOUtils;
import java.io.IOException;
@@ -70,7 +71,8 @@ public class CodeGenLoader {
final ClassLoader flinkClassLoader = CodeGenLoader.class.getClassLoader();
final Path tmpDirectory =
Paths.get(ConfigurationUtils.parseTempDirectories(new Configuration())[0]);
- Files.createDirectories(tmpDirectory);
+ Files.createDirectories(
+ LocalFileUtils.getTargetPathIfContainsSymbolicPath(tmpDirectory));
Path delegateJar =
extractResource(
FLINK_TABLE_STORE_CODEGEN_FAT_JAR,
@@ -110,12 +112,14 @@ public class CodeGenLoader {
// Singleton lazy initialization
- private static class CodegenLoaderHolder {
- private static final CodeGenLoader INSTANCE = new CodeGenLoader();
- }
+ private static CodeGenLoader instance;
- public static CodeGenLoader getInstance() {
- return CodeGenLoader.CodegenLoaderHolder.INSTANCE;
+ public static synchronized CodeGenLoader getInstance() {
+ if (instance == null) {
+ // Avoid NoClassDefFoundError without cause by exception
+ instance = new CodeGenLoader();
+ }
+ return instance;
}
public <T> T discover(Class<T> clazz) {
diff --git a/flink-table-store-common/src/main/java/org/apache/flink/table/store/utils/LocalFileUtils.java b/flink-table-store-common/src/main/java/org/apache/flink/table/store/utils/LocalFileUtils.java
new file mode 100644
index 00000000..a3930ea7
--- /dev/null
+++ b/flink-table-store-common/src/main/java/org/apache/flink/table/store/utils/LocalFileUtils.java
@@ -0,0 +1,50 @@
+/*
+ * 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.flink.table.store.utils;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+/** Utils for local file. */
+public class LocalFileUtils {
+
+ /**
+ * Get a target path(the path that replaced symbolic links with linked path) if the original
+ * path contains symbolic path, return the original path otherwise.
+ *
+ * @param path the original path.
+ * @return the path that replaced symbolic links with real path.
+ */
+ public static Path getTargetPathIfContainsSymbolicPath(Path path) throws IOException {
+ Path targetPath = path;
+ Path suffixPath = Paths.get("");
+ while (path != null && path.getFileName() != null) {
+ if (Files.isSymbolicLink(path)) {
+ Path linkedPath = path.toRealPath();
+ targetPath = Paths.get(linkedPath.toString(), suffixPath.toString());
+ break;
+ }
+ suffixPath = Paths.get(path.getFileName().toString(), suffixPath.toString());
+ path = path.getParent();
+ }
+ return targetPath;
+ }
+}
diff --git a/flink-table-store-common/src/test/java/org/apache/flink/table/store/utils/LocalFileUtilsTest.java b/flink-table-store-common/src/test/java/org/apache/flink/table/store/utils/LocalFileUtilsTest.java
new file mode 100644
index 00000000..b4bbed32
--- /dev/null
+++ b/flink-table-store-common/src/test/java/org/apache/flink/table/store/utils/LocalFileUtilsTest.java
@@ -0,0 +1,80 @@
+/*
+ * 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.flink.table.store.utils;
+
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.io.TempDir;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+/** Test for {@link LocalFileUtils}. */
+public class LocalFileUtilsTest {
+
+ @TempDir private java.nio.file.Path temporaryFolder;
+
+ @Test
+ void testGetTargetPathNotContainsSymbolicPath() throws IOException {
+ java.nio.file.Path testPath = Paths.get("parent", "child");
+ java.nio.file.Path targetPath =
+ LocalFileUtils.getTargetPathIfContainsSymbolicPath(testPath);
+ assertThat(targetPath).isEqualTo(testPath);
+ }
+
+ @Test
+ void testGetTargetPathContainsSymbolicPath() throws IOException {
+ File linkedDir = TempDirUtils.newFolder(temporaryFolder, "linked");
+ java.nio.file.Path symlink = Paths.get(temporaryFolder.toString(), "symlink");
+ java.nio.file.Path dirInLinked =
+ TempDirUtils.newFolder(linkedDir.toPath(), "one", "two").toPath().toRealPath();
+ Files.createSymbolicLink(symlink, linkedDir.toPath());
+
+ java.nio.file.Path targetPath =
+ LocalFileUtils.getTargetPathIfContainsSymbolicPath(
+ symlink.resolve("one").resolve("two"));
+ assertThat(targetPath).isEqualTo(dirInLinked);
+ }
+
+ @Test
+ void testGetTargetPathContainsMultipleSymbolicPath() throws IOException {
+ File linked1Dir = TempDirUtils.newFolder(temporaryFolder, "linked1");
+ java.nio.file.Path symlink1 = Paths.get(temporaryFolder.toString(), "symlink1");
+ Files.createSymbolicLink(symlink1, linked1Dir.toPath());
+
+ java.nio.file.Path symlink2 = Paths.get(symlink1.toString(), "symlink2");
+ File linked2Dir = TempDirUtils.newFolder(temporaryFolder, "linked2");
+ Files.createSymbolicLink(symlink2, linked2Dir.toPath());
+ java.nio.file.Path dirInLinked2 =
+ TempDirUtils.newFolder(linked2Dir.toPath(), "one").toPath().toRealPath();
+
+ // symlink3 point to another symbolic link: symlink2
+ java.nio.file.Path symlink3 = Paths.get(symlink1.toString(), "symlink3");
+ Files.createSymbolicLink(symlink3, symlink2);
+
+ java.nio.file.Path targetPath =
+ LocalFileUtils.getTargetPathIfContainsSymbolicPath(
+ // path contains multiple symlink : xxx/symlink1/symlink3/one
+ symlink3.resolve("one"));
+ assertThat(targetPath).isEqualTo(dirInLinked2);
+ }
+}
diff --git a/flink-table-store-common/src/test/java/org/apache/flink/table/store/utils/TempDirUtils.java b/flink-table-store-common/src/test/java/org/apache/flink/table/store/utils/TempDirUtils.java
new file mode 100644
index 00000000..fecb457b
--- /dev/null
+++ b/flink-table-store-common/src/test/java/org/apache/flink/table/store/utils/TempDirUtils.java
@@ -0,0 +1,100 @@
+/*
+ * 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.flink.table.store.utils;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+
+/** The utils contains some methods same as org.junit.rules.TemporaryFolder in Junit4. */
+public class TempDirUtils {
+ private static final String TMP_PREFIX = "junit";
+
+ public static File newFolder(Path path) throws IOException {
+ Path tempPath;
+ if (path != null) {
+ tempPath = Files.createTempDirectory(path, TMP_PREFIX);
+ } else {
+ tempPath = Files.createTempDirectory(TMP_PREFIX);
+ }
+ return tempPath.toFile();
+ }
+
+ public static File newFile(Path path) throws IOException {
+ return File.createTempFile(TMP_PREFIX, null, path.toFile());
+ }
+
+ public static File newFolder(Path base, String... paths) throws IOException {
+ if (paths.length == 0) {
+ throw new IllegalArgumentException("must pass at least one path");
+ }
+
+ /*
+ * Before checking if the paths are absolute paths, check if create() was ever called,
+ * and if it wasn't, throw IllegalStateException.
+ */
+ File root = base.toFile();
+ for (String path : paths) {
+ if (new File(path).isAbsolute()) {
+ throw new IOException(
+ String.format("folder path '%s' is not a relative path", path));
+ }
+ }
+
+ File relativePath = null;
+ File file = root;
+ boolean lastMkdirsCallSuccessful = true;
+ for (String path : paths) {
+ relativePath = new File(relativePath, path);
+ file = new File(root, relativePath.getPath());
+
+ lastMkdirsCallSuccessful = file.mkdirs();
+ if (!lastMkdirsCallSuccessful && !file.isDirectory()) {
+ if (file.exists()) {
+ throw new IOException(
+ String.format(
+ "a file with the path '%s' exists", relativePath.getPath()));
+ } else {
+ throw new IOException(
+ String.format(
+ "could not create a folder with the path: '%s'",
+ relativePath.getPath()));
+ }
+ }
+ }
+ if (!lastMkdirsCallSuccessful) {
+ throw new IOException(
+ String.format(
+ "a folder with the path '%s' already exists", relativePath.getPath()));
+ }
+ return file;
+ }
+
+ public static File newFile(Path folder, String fileName) throws IOException {
+ File file = new File(folder.toFile(), fileName);
+ if (!file.createNewFile()) {
+ throw new IOException(
+ String.format(
+ "a file with the name '%s' already exists in the test folder",
+ fileName));
+ }
+ return file;
+ }
+}