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]

Reply via email to