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

tanxinyu pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/iotdb.git


The following commit(s) were added to refs/heads/master by this push:
     new 44f1d1813b [IOTDB-3589] Fix dataRegion cannot recover from snapshot 
(#6376)
44f1d1813b is described below

commit 44f1d1813be3c1b6be5c591c3073d6764dd94c9c
Author: Liu Xuxin <[email protected]>
AuthorDate: Wed Jun 22 14:05:55 2022 +0800

    [IOTDB-3589] Fix dataRegion cannot recover from snapshot (#6376)
    
    * take snapshot in form of directory
    
    * load snapshot with directory snapshot
    
    * fix error when loading snapshot
---
 .../iotdb/db/engine/snapshot/SnapshotLoader.java   | 137 +++++++++++++++------
 .../iotdb/db/engine/snapshot/SnapshotTaker.java    |  47 ++++---
 2 files changed, 127 insertions(+), 57 deletions(-)

diff --git 
a/server/src/main/java/org/apache/iotdb/db/engine/snapshot/SnapshotLoader.java 
b/server/src/main/java/org/apache/iotdb/db/engine/snapshot/SnapshotLoader.java
index 476a645533..7283e621ba 100644
--- 
a/server/src/main/java/org/apache/iotdb/db/engine/snapshot/SnapshotLoader.java
+++ 
b/server/src/main/java/org/apache/iotdb/db/engine/snapshot/SnapshotLoader.java
@@ -34,6 +34,7 @@ import java.io.IOException;
 import java.nio.file.Files;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Comparator;
 import java.util.List;
 
 public class SnapshotLoader {
@@ -78,22 +79,10 @@ public class SnapshotLoader {
     }
 
     // move the snapshot data to data dir
-    String seqBaseDir =
-        IoTDBConstant.SEQUENCE_FLODER_NAME
-            + File.separator
-            + storageGroupName
-            + File.separator
-            + dataRegionId;
-    String unseqBaseDir =
-        IoTDBConstant.UNSEQUENCE_FLODER_NAME
-            + File.separator
-            + storageGroupName
-            + File.separator
-            + dataRegionId;
     File sourceDataDir = new File(snapshotPath);
     if (sourceDataDir.exists()) {
       try {
-        createLinksFromSnapshotDirToDataDir(sourceDataDir, seqBaseDir, 
unseqBaseDir);
+        createLinksFromSnapshotDirToDataDir(sourceDataDir);
       } catch (IOException | DiskSpaceInsufficientException e) {
         LOGGER.error(
             "Exception occurs when creating links from snapshot directory to 
data directory", e);
@@ -158,38 +147,104 @@ public class SnapshotLoader {
     }
   }
 
-  private void createLinksFromSnapshotDirToDataDir(
-      File sourceDir, String seqBaseDir, String unseqBaseDir)
+  private void createLinksFromSnapshotDirToDataDir(File sourceDir)
       throws IOException, DiskSpaceInsufficientException {
-    File[] files = sourceDir.listFiles();
-    if (files == null) {
-      return;
+    File seqFileDir = new File(sourceDir, "sequence" + File.separator + 
storageGroupName);
+    File unseqFileDir = new File(sourceDir, "unsequence" + File.separator + 
storageGroupName);
+    if (!seqFileDir.exists() && !unseqFileDir.exists()) {
+      throw new IOException(
+          String.format(
+              "Cannot find %s or %s",
+              seqFileDir.getAbsolutePath(), unseqFileDir.getAbsolutePath()));
     }
-    for (File sourceFile : files) {
-      String[] fileInfo = 
sourceFile.getName().split(SnapshotTaker.SNAPSHOT_FILE_INFO_SEP_STR);
-      if (fileInfo.length != 5) {
-        continue;
-      }
-      boolean seq = fileInfo[0].equals("seq");
-      String timePartition = fileInfo[3];
-      String fileName = fileInfo[4];
-      String nextDataDir =
-          seq
-              ? DirectoryManager.getInstance().getNextFolderForSequenceFile()
-              : 
DirectoryManager.getInstance().getNextFolderForUnSequenceFile();
-      File baseDir = new File(nextDataDir, seq ? seqBaseDir : unseqBaseDir);
-      File targetDirForThisTimePartition = new File(baseDir, timePartition);
-      if (!targetDirForThisTimePartition.exists() && 
!targetDirForThisTimePartition.mkdirs()) {
-        throw new IOException(
-            String.format("Failed to make directory %s", 
targetDirForThisTimePartition));
+
+    File[] seqRegionDirs = seqFileDir.listFiles();
+    if (seqRegionDirs != null && seqRegionDirs.length > 0) {
+      for (File seqRegionDir : seqRegionDirs) {
+        if (!seqRegionDir.isDirectory()) {
+          LOGGER.info("Skip {}, because it is not a directory", seqRegionDir);
+          continue;
+        }
+        File[] seqPartitionDirs = seqRegionDir.listFiles();
+        if (seqPartitionDirs != null && seqPartitionDirs.length > 0) {
+          for (File seqPartitionDir : seqPartitionDirs) {
+            String[] splitPath =
+                seqPartitionDir
+                    .getAbsolutePath()
+                    .split(File.separator.equals("\\") ? "\\\\" : 
File.separator);
+            long timePartition = Long.parseLong(splitPath[splitPath.length - 
1]);
+            File[] files = seqPartitionDir.listFiles();
+            if (files != null && files.length > 0) {
+              Arrays.sort(files, Comparator.comparing(File::getName));
+              String currDir = 
DirectoryManager.getInstance().getNextFolderForSequenceFile();
+              for (File file : files) {
+                if (file.getName().endsWith(".tsfile")) {
+                  currDir = 
DirectoryManager.getInstance().getNextFolderForSequenceFile();
+                }
+                File targetFile =
+                    new File(
+                        currDir,
+                        storageGroupName
+                            + File.separator
+                            + dataRegionId
+                            + File.separator
+                            + timePartition
+                            + File.separator
+                            + file.getName());
+                if (!targetFile.getParentFile().exists() && 
!targetFile.getParentFile().mkdirs()) {
+                  throw new IOException(
+                      String.format("Failed to create dir %s", 
targetFile.getParent()));
+                }
+                Files.createLink(targetFile.toPath(), file.toPath());
+              }
+            }
+          }
+        }
       }
+    }
 
-      File targetFile = new File(targetDirForThisTimePartition, fileName);
-      try {
-        Files.createLink(targetFile.toPath(), sourceFile.toPath());
-      } catch (IOException e) {
-        throw new IOException(
-            String.format("Failed to create hard link from %s to %s", 
sourceFile, targetFile), e);
+    File[] unseqRegionDirs = unseqFileDir.listFiles();
+    if (unseqRegionDirs != null && unseqRegionDirs.length > 0) {
+      for (File unseqRegionDir : unseqRegionDirs) {
+        if (!unseqRegionDir.isDirectory()) {
+          LOGGER.info("Skip {}, because it is not a directory", 
unseqRegionDir);
+          continue;
+        }
+        File[] unseqPartitionDirs = unseqRegionDir.listFiles();
+        if (unseqPartitionDirs != null && unseqPartitionDirs.length > 0) {
+          for (File unseqPartitionDir : unseqPartitionDirs) {
+            String[] splitPath =
+                unseqPartitionDir
+                    .getAbsolutePath()
+                    .split(File.separator.equals("\\") ? "\\\\" : 
File.separator);
+            long timePartition = Long.parseLong(splitPath[splitPath.length - 
1]);
+            File[] files = unseqPartitionDir.listFiles();
+            if (files != null && files.length > 0) {
+              Arrays.sort(files, Comparator.comparing(File::getName));
+              String currDir = 
DirectoryManager.getInstance().getNextFolderForUnSequenceFile();
+              for (File file : files) {
+                if (file.getName().endsWith(".tsfile")) {
+                  currDir = 
DirectoryManager.getInstance().getNextFolderForUnSequenceFile();
+                }
+                File targetFile =
+                    new File(
+                        currDir,
+                        storageGroupName
+                            + File.separator
+                            + dataRegionId
+                            + File.separator
+                            + timePartition
+                            + File.separator
+                            + file.getName());
+                if (!targetFile.getParentFile().exists() && 
!targetFile.getParentFile().mkdirs()) {
+                  throw new IOException(
+                      String.format("Failed to create dir %s", 
targetFile.getParent()));
+                }
+                Files.createLink(targetFile.toPath(), file.toPath());
+              }
+            }
+          }
+        }
       }
     }
   }
diff --git 
a/server/src/main/java/org/apache/iotdb/db/engine/snapshot/SnapshotTaker.java 
b/server/src/main/java/org/apache/iotdb/db/engine/snapshot/SnapshotTaker.java
index a05f8f7182..02f69266c6 100644
--- 
a/server/src/main/java/org/apache/iotdb/db/engine/snapshot/SnapshotTaker.java
+++ 
b/server/src/main/java/org/apache/iotdb/db/engine/snapshot/SnapshotTaker.java
@@ -35,6 +35,7 @@ import java.io.IOException;
 import java.nio.file.Files;
 import java.util.LinkedList;
 import java.util.List;
+import java.util.Objects;
 
 /**
  * SnapshotTaker takes data snapshot for a DataRegion in one time. It does so 
by creating hard link
@@ -46,6 +47,8 @@ public class SnapshotTaker {
   private static final Logger LOGGER = 
LoggerFactory.getLogger(SnapshotTaker.class);
   private final DataRegion dataRegion;
   public static String SNAPSHOT_FILE_INFO_SEP_STR = "_";
+  private File seqBaseDir;
+  private File unseqBaseDir;
 
   public SnapshotTaker(DataRegion dataRegion) {
     this.dataRegion = dataRegion;
@@ -56,11 +59,27 @@ public class SnapshotTaker {
     File snapshotDir = new File(snapshotDirPath);
     if (snapshotDir.exists()
         && snapshotDir.listFiles() != null
-        && snapshotDir.listFiles().length > 0) {
+        && Objects.requireNonNull(snapshotDir.listFiles()).length > 0) {
       // the directory should be empty or not exists
       throw new DirectoryNotLegalException(
           String.format("%s already exists and is not empty", 
snapshotDirPath));
     }
+    seqBaseDir =
+        new File(
+            snapshotDir,
+            "sequence"
+                + File.separator
+                + dataRegion.getLogicalStorageGroupName()
+                + File.separator
+                + dataRegion.getDataRegionId());
+    unseqBaseDir =
+        new File(
+            snapshotDir,
+            "unsequence"
+                + File.separator
+                + dataRegion.getLogicalStorageGroupName()
+                + File.separator
+                + dataRegion.getDataRegionId());
 
     if (!snapshotDir.exists() && !snapshotDir.mkdirs()) {
       throw new IOException(String.format("Failed to create directory %s", 
snapshotDir));
@@ -78,7 +97,7 @@ public class SnapshotTaker {
         List<String> seqDataDirs = getAllDataDirOfOnePartition(true, 
timePartition);
 
         try {
-          createFileSnapshot(seqDataDirs, snapshotDir, true, timePartition);
+          createFileSnapshot(seqDataDirs, true, timePartition);
         } catch (IOException e) {
           LOGGER.error("Fail to create snapshot", e);
           cleanUpWhenFail(snapshotDir);
@@ -88,7 +107,7 @@ public class SnapshotTaker {
         List<String> unseqDataDirs = getAllDataDirOfOnePartition(false, 
timePartition);
 
         try {
-          createFileSnapshot(unseqDataDirs, snapshotDir, false, timePartition);
+          createFileSnapshot(unseqDataDirs, false, timePartition);
         } catch (IOException e) {
           LOGGER.error("Fail to create snapshot", e);
           cleanUpWhenFail(snapshotDir);
@@ -124,9 +143,15 @@ public class SnapshotTaker {
     return resultDirs;
   }
 
-  private void createFileSnapshot(
-      List<String> sourceDirPaths, File targetDir, boolean sequence, long 
timePartition)
+  private void createFileSnapshot(List<String> sourceDirPaths, boolean 
sequence, long timePartition)
       throws IOException {
+    File timePartitionDir =
+        new File(sequence ? seqBaseDir : unseqBaseDir, 
String.valueOf(timePartition));
+    if (!timePartitionDir.exists() && !timePartitionDir.mkdirs()) {
+      throw new IOException(
+          String.format("%s not exists and cannot create it", 
timePartitionDir.getAbsolutePath()));
+    }
+
     for (String sourceDirPath : sourceDirPaths) {
       File sourceDir = new File(sourceDirPath);
       if (!sourceDir.exists()) {
@@ -149,17 +174,7 @@ public class SnapshotTaker {
       }
 
       for (File file : files) {
-        String newFileName =
-            (sequence ? "seq" : "unseq")
-                + SNAPSHOT_FILE_INFO_SEP_STR
-                + dataRegion.getLogicalStorageGroupName()
-                + SNAPSHOT_FILE_INFO_SEP_STR
-                + dataRegion.getDataRegionId()
-                + SNAPSHOT_FILE_INFO_SEP_STR
-                + timePartition
-                + SNAPSHOT_FILE_INFO_SEP_STR
-                + file.getName();
-        File linkFile = new File(targetDir, newFileName);
+        File linkFile = new File(timePartitionDir, file.getName());
         Files.createLink(linkFile.toPath(), file.toPath());
       }
     }

Reply via email to