This is an automated email from the ASF dual-hosted git repository. kxiao pushed a commit to branch branch-2.0 in repository https://gitbox.apache.org/repos/asf/doris.git
commit 7b6d97071d2a33d415e4205fd592ae985a55ac03 Author: Calvin Kirs <[email protected]> AuthorDate: Tue Sep 19 23:11:20 2023 +0800 [Improve](Fe)Ensure that only one FE process uses the metedata file (#24442) --- .../src/main/java/org/apache/doris/DorisFE.java | 61 +++++++++++++++++++++- .../apache/doris/utframe/TestWithFeService.java | 6 +++ .../org/apache/doris/utframe/UtFrameUtils.java | 6 +++ 3 files changed, 72 insertions(+), 1 deletion(-) diff --git a/fe/fe-core/src/main/java/org/apache/doris/DorisFE.java b/fe/fe-core/src/main/java/org/apache/doris/DorisFE.java index e3cf89410d..2186ccbfa9 100755 --- a/fe/fe-core/src/main/java/org/apache/doris/DorisFE.java +++ b/fe/fe-core/src/main/java/org/apache/doris/DorisFE.java @@ -54,8 +54,10 @@ import java.io.File; import java.io.IOException; import java.io.RandomAccessFile; import java.lang.management.ManagementFactory; +import java.nio.channels.FileChannel; import java.nio.channels.FileLock; import java.nio.channels.OverlappingFileLockException; +import java.nio.file.StandardOpenOption; public class DorisFE { private static final Logger LOG = LogManager.getLogger(DorisFE.class); @@ -67,6 +69,13 @@ public class DorisFE { public static final String DORIS_HOME_DIR = System.getenv("DORIS_HOME"); public static final String PID_DIR = System.getenv("PID_DIR"); + + private static String LOCK_FILE_PATH; + + private static final String LOCK_FILE_NAME = "process.lock"; + private static FileChannel processLockFileChannel; + private static FileLock processFileLock; + public static void main(String[] args) { StartupOptions options = new StartupOptions(); options.enableHttpServer = true; @@ -103,7 +112,13 @@ public class DorisFE { // Must init custom config after init config, separately. // Because the path of custom config file is defined in fe.conf config.initCustom(Config.custom_config_dir + "/fe_custom.conf"); - + LOCK_FILE_PATH = Config.meta_dir + "/" + LOCK_FILE_NAME; + try { + tryLockProcess(); + } catch (Exception e) { + LOG.error("start doris failed.", e); + System.exit(-1); + } LdapConfig ldapConfig = new LdapConfig(); if (new File(dorisHomeDir + "/conf/ldap.conf").exists()) { ldapConfig.init(dorisHomeDir + "/conf/ldap.conf"); @@ -413,6 +428,50 @@ public class DorisFE { } } + /** + * When user starts multiple FE processes at the same time and uses one metadata directory, + * the metadata directory will be damaged. Therefore, we will bind the process by creating a file lock to ensure + * that only one FE process can occupy a metadata directory, and other processes will fail to start. + */ + private static void tryLockProcess() { + try { + processLockFileChannel = FileChannel.open(new File(LOCK_FILE_PATH).toPath(), StandardOpenOption.WRITE, + StandardOpenOption.CREATE); + processFileLock = processLockFileChannel.tryLock(); + if (processFileLock != null) { + // we need bind the lock file with the process + Runtime.getRuntime().addShutdownHook(new Thread(DorisFE::releaseFileLockAndCloseFileChannel)); + return; + } + releaseFileLockAndCloseFileChannel(); + } catch (IOException e) { + releaseFileLockAndCloseFileChannel(); + throw new RuntimeException("Try to lock process failed", e); + } + throw new RuntimeException("FE process has been started,please do not start multiple FE processes at the" + + "same time"); + } + + + private static void releaseFileLockAndCloseFileChannel() { + + if (processFileLock != null && processFileLock.isValid()) { + try { + processFileLock.release(); + } catch (IOException ioException) { + LOG.warn("release process lock file failed", ioException); + } + } + if (processLockFileChannel != null && processLockFileChannel.isOpen()) { + try { + processLockFileChannel.close(); + } catch (IOException ignored) { + LOG.warn("release process lock file failed", ignored); + } + } + + } + public static class StartupOptions { public boolean enableHttpServer = true; public boolean enableQeService = true; diff --git a/fe/fe-core/src/test/java/org/apache/doris/utframe/TestWithFeService.java b/fe/fe-core/src/test/java/org/apache/doris/utframe/TestWithFeService.java index dca7350d94..a17fcdf72b 100644 --- a/fe/fe-core/src/test/java/org/apache/doris/utframe/TestWithFeService.java +++ b/fe/fe-core/src/test/java/org/apache/doris/utframe/TestWithFeService.java @@ -355,6 +355,12 @@ public abstract class TestWithFeService { if (!file.exists()) { file.mkdir(); } + if (null != System.getenv("DORIS_HOME")) { + File metaDir = new File(Config.meta_dir); + if (!metaDir.exists()) { + metaDir.mkdir(); + } + } System.out.println("CREATE FE SERVER DIR: " + Config.custom_config_dir); int feHttpPort = findValidPort(); diff --git a/fe/fe-core/src/test/java/org/apache/doris/utframe/UtFrameUtils.java b/fe/fe-core/src/test/java/org/apache/doris/utframe/UtFrameUtils.java index 4213b7136f..2e2d53edb7 100644 --- a/fe/fe-core/src/test/java/org/apache/doris/utframe/UtFrameUtils.java +++ b/fe/fe-core/src/test/java/org/apache/doris/utframe/UtFrameUtils.java @@ -183,6 +183,12 @@ public class UtFrameUtils { if (!file.exists()) { file.mkdir(); } + if (null != System.getenv("DORIS_HOME")) { + File metaDir = new File(Config.meta_dir); + if (!metaDir.exists()) { + metaDir.mkdir(); + } + } int feHttpPort = findValidPort(); int feRpcPort = findValidPort(); --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
