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

marklau99 pushed a commit to branch IOTDB-4257
in repository https://gitbox.apache.org/repos/asf/iotdb.git


The following commit(s) were added to refs/heads/IOTDB-4257 by this push:
     new 65d859b4ca refactor snapshot
65d859b4ca is described below

commit 65d859b4caea6f9737e7f36a74f4733e873fa23b
Author: Liu Xuxin <[email protected]>
AuthorDate: Thu Oct 6 17:41:54 2022 +0800

    refactor snapshot
---
 .../apache/iotdb/commons/conf/IoTDBConstant.java   |   1 +
 .../iotdb/db/engine/snapshot/SnapshotLoader.java   | 343 +++++++++++++--------
 .../db/engine/snapshot/SnapshotLogAnalyzer.java    |  53 +++-
 .../iotdb/db/engine/snapshot/SnapshotLogger.java   |  55 +++-
 .../iotdb/db/engine/snapshot/SnapshotTaker.java    |  14 +-
 .../db/engine/snapshot/IoTDBSnapshotTest.java      |   2 +-
 6 files changed, 329 insertions(+), 139 deletions(-)

diff --git 
a/node-commons/src/main/java/org/apache/iotdb/commons/conf/IoTDBConstant.java 
b/node-commons/src/main/java/org/apache/iotdb/commons/conf/IoTDBConstant.java
index 66e8c157df..60900789e1 100644
--- 
a/node-commons/src/main/java/org/apache/iotdb/commons/conf/IoTDBConstant.java
+++ 
b/node-commons/src/main/java/org/apache/iotdb/commons/conf/IoTDBConstant.java
@@ -186,6 +186,7 @@ public class IoTDBConstant {
   public static final String FILE_NAME_SEPARATOR = "-";
   public static final String UPGRADE_FOLDER_NAME = "upgrade";
   public static final String CONSENSUS_FOLDER_NAME = "consensus";
+  public static final String SNAPSHOT_FOLDER_NAME = "snapshot";
 
   // system folder name
   public static final String SYSTEM_FOLDER_NAME = "system";
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 cff5886f38..d30edf80db 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
@@ -21,11 +21,11 @@ package org.apache.iotdb.db.engine.snapshot;
 
 import org.apache.iotdb.commons.conf.IoTDBConstant;
 import org.apache.iotdb.db.conf.IoTDBDescriptor;
-import org.apache.iotdb.db.conf.directories.DirectoryManager;
+import org.apache.iotdb.db.conf.directories.FolderManager;
+import org.apache.iotdb.db.conf.directories.strategy.DirectoryStrategyType;
 import org.apache.iotdb.db.engine.StorageEngineV2;
 import org.apache.iotdb.db.engine.storagegroup.DataRegion;
 import org.apache.iotdb.db.exception.DiskSpaceInsufficientException;
-import org.apache.iotdb.tsfile.utils.Pair;
 
 import org.apache.commons.io.FileUtils;
 import org.slf4j.Logger;
@@ -33,14 +33,12 @@ import org.slf4j.LoggerFactory;
 
 import java.io.File;
 import java.io.IOException;
-import java.nio.file.FileSystemException;
 import java.nio.file.Files;
 import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.Comparator;
 import java.util.LinkedList;
 import java.util.List;
-import java.util.Objects;
+import java.util.Queue;
 
 public class SnapshotLoader {
   private Logger LOGGER = LoggerFactory.getLogger(SnapshotLoader.class);
@@ -48,11 +46,13 @@ public class SnapshotLoader {
   private String snapshotPath;
   private String dataRegionId;
   private SnapshotLogAnalyzer logAnalyzer;
+  private FolderManager folderManager;
 
   public SnapshotLoader(String snapshotPath, String storageGroupName, String 
dataRegionId) {
     this.snapshotPath = snapshotPath;
     this.storageGroupName = storageGroupName;
     this.dataRegionId = dataRegionId;
+    this.folderManager = null;
   }
 
   private DataRegion loadSnapshot() {
@@ -125,23 +125,31 @@ public class SnapshotLoader {
   }
 
   private DataRegion loadSnapshotWithLog(File logFile) {
+    boolean snapshotComplete = false;
     try {
       logAnalyzer = new SnapshotLogAnalyzer(logFile);
+      snapshotComplete = logAnalyzer.isSnapshotComplete();
     } catch (Exception e) {
       LOGGER.error("Exception occurs when reading snapshot file", e);
       return null;
     }
 
+    if (!snapshotComplete) {
+      // Do not load this snapshot because it's not complete.
+      LOGGER.error("This snapshot is not complete, cannot load it");
+      return null;
+    }
+
     try {
       try {
         deleteAllFilesInDataDirs();
         LOGGER.info("Remove all data files in original data dir");
+        createLinksFromSnapshotDirToDataDirWithLog();
+        return loadSnapshot();
       } catch (IOException e) {
+        LOGGER.error("IOException occurs when creating links from snapshot dir 
to data dir", e);
         return null;
       }
-
-      createLinksFromSnapshotDirToDataDirWithLog();
-      return loadSnapshot();
     } finally {
       logAnalyzer.close();
     }
@@ -203,134 +211,195 @@ public class SnapshotLoader {
 
   private void createLinksFromSnapshotDirToDataDirWithoutLog(File sourceDir)
       throws IOException, DiskSpaceInsufficientException {
-    File seqFileDir = new File(sourceDir, "sequence" + File.separator + 
storageGroupName);
-    File unseqFileDir = new File(sourceDir, "unsequence" + File.separator + 
storageGroupName);
+    File seqFileDir =
+        new File(
+            sourceDir,
+            IoTDBConstant.SEQUENCE_FLODER_NAME
+                + File.separator
+                + storageGroupName
+                + File.separator
+                + dataRegionId);
+    File unseqFileDir =
+        new File(
+            sourceDir,
+            IoTDBConstant.UNSEQUENCE_FLODER_NAME
+                + File.separator
+                + storageGroupName
+                + File.separator
+                + dataRegionId);
     if (!seqFileDir.exists() && !unseqFileDir.exists()) {
       throw new IOException(
           String.format(
               "Cannot find %s or %s",
               seqFileDir.getAbsolutePath(), unseqFileDir.getAbsolutePath()));
     }
-
-    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);
+    folderManager =
+        new FolderManager(
+            
Arrays.asList(IoTDBDescriptor.getInstance().getConfig().getDataDirs()),
+            DirectoryStrategyType.SEQUENCE_STRATEGY);
+    File[] timePartitionFolders = seqFileDir.listFiles();
+    if (timePartitionFolders != null) {
+      for (File timePartitionFolder : timePartitionFolders) {
+        File[] files = timePartitionFolder.listFiles();
+        if (files == null || files.length == 0) {
           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()));
-                }
-                try {
-                  Files.createLink(targetFile.toPath(), file.toPath());
-                } catch (FileSystemException e) {
-                  // cannot create link between two directories in different fs
-                  // copy it
-                  Files.copy(file.toPath(), targetFile.toPath());
-                }
-              }
-            }
-          }
-        }
+        String targetSuffix =
+            IoTDBConstant.SEQUENCE_FLODER_NAME
+                + File.separator
+                + storageGroupName
+                + File.separator
+                + dataRegionId
+                + File.separator
+                + timePartitionFolder.getName();
+        createLinksFromSnapshotToSourceDir(targetSuffix, files);
       }
     }
 
-    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);
+    timePartitionFolders = unseqFileDir.listFiles();
+    if (timePartitionFolders != null) {
+      for (File timePartitionFolder : timePartitionFolders) {
+        File[] files = timePartitionFolder.listFiles();
+        if (files == null || files.length == 0) {
           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()));
-                }
-                try {
-                  Files.createLink(targetFile.toPath(), file.toPath());
-                } catch (FileSystemException e) {
-                  Files.copy(file.toPath(), targetFile.toPath());
-                }
-              }
-            }
-          }
-        }
+        String targetSuffix =
+            IoTDBConstant.UNSEQUENCE_FLODER_NAME
+                + File.separator
+                + storageGroupName
+                + File.separator
+                + dataRegionId
+                + File.separator
+                + timePartitionFolder.getName();
+        createLinksFromSnapshotToSourceDir(targetSuffix, files);
       }
     }
   }
 
-  private void createLinksFromSnapshotDirToDataDirWithLog() {
-    while (logAnalyzer.hasNext()) {
-      Pair<String, String> filesPath = logAnalyzer.getNextPairs();
-      File sourceFile = new File(filesPath.left);
-      File linkedFile = new File(filesPath.right);
-      if (!linkedFile.exists()) {
-        LOGGER.warn("Snapshot file {} does not exist, skip it", linkedFile);
-        continue;
-      }
-      if (!sourceFile.getParentFile().exists() && 
!sourceFile.getParentFile().mkdirs()) {
-        LOGGER.error("Failed to create folder {}", sourceFile.getParentFile());
-        continue;
+  private void createLinksFromSnapshotToSourceDir(String targetSuffix, File[] 
files)
+      throws DiskSpaceInsufficientException, IOException {
+    for (File file : files) {
+      String dataDir = folderManager.getNextFolder();
+      File targetFile =
+          new File(dataDir + File.separator + targetSuffix + File.separator + 
file.getName());
+      if (!targetFile.getParentFile().exists() && 
!targetFile.getParentFile().mkdirs()) {
+        throw new IOException(
+            String.format(
+                "Cannot create directory %s", 
targetFile.getParentFile().getAbsolutePath()));
       }
       try {
-        Files.createLink(sourceFile.toPath(), linkedFile.toPath());
+        Files.createLink(targetFile.toPath(), file.toPath());
+        continue;
       } catch (IOException e) {
-        LOGGER.error("Failed to create link from {} to {}", linkedFile, 
sourceFile, e);
+        LOGGER.info("Cannot create link from {} to {}, try to copy it", file, 
targetFile);
       }
+
+      Files.copy(file.toPath(), targetFile.toPath());
+    }
+  }
+
+  private void createLinksFromSnapshotDirToDataDirWithLog() throws IOException 
{
+    String snapshotId = logAnalyzer.getSnapshotId();
+    int fileNum = logAnalyzer.getTotalFileCountInSnapshot();
+    String[] dataDirs = 
IoTDBDescriptor.getInstance().getConfig().getDataDirs();
+    int fileCnt = 0;
+    for (String dataDir : dataDirs) {
+      String snapshotDir =
+          dataDir
+              + File.separator
+              + IoTDBConstant.SNAPSHOT_FOLDER_NAME
+              + File.separator
+              + snapshotId;
+      fileCnt += takeHardLinksFromSnapshotToDataDir(dataDir, new 
File(snapshotDir));
+    }
+    if (fileCnt != fileNum) {
+      throw new IOException(
+          String.format(
+              "The file num in log is %d, while file num in disk is %d", 
fileNum, fileCnt));
+    }
+  }
+
+  private int takeHardLinksFromSnapshotToDataDir(String dataDir, File 
snapshotFolder)
+      throws IOException {
+    int cnt = 0;
+    File sequenceTimePartitionFolders =
+        new File(
+            snapshotFolder.getAbsolutePath()
+                + File.separator
+                + IoTDBConstant.SEQUENCE_FLODER_NAME
+                + File.separator
+                + storageGroupName
+                + File.separator
+                + dataRegionId);
+    File[] timePartitionFolders = sequenceTimePartitionFolders.listFiles();
+    if (timePartitionFolders != null) {
+      for (File timePartitionFolder : timePartitionFolders) {
+        String timePartition = timePartitionFolder.getName();
+        File[] sourceFiles = timePartitionFolder.listFiles();
+        if (sourceFiles == null) {
+          continue;
+        }
+        File targetDir =
+            new File(
+                dataDir
+                    + File.separator
+                    + IoTDBConstant.SEQUENCE_FLODER_NAME
+                    + File.separator
+                    + storageGroupName
+                    + File.separator
+                    + dataRegionId
+                    + File.separator
+                    + timePartition);
+        createLinksFromSourceToTarget(targetDir, sourceFiles);
+        cnt += sourceFiles.length;
+      }
+    }
+
+    File unsequenceTimePartitionFolders =
+        new File(
+            snapshotFolder.getAbsolutePath()
+                + File.separator
+                + IoTDBConstant.UNSEQUENCE_FLODER_NAME
+                + File.separator
+                + storageGroupName
+                + File.separator
+                + dataRegionId);
+    timePartitionFolders = unsequenceTimePartitionFolders.listFiles();
+    if (timePartitionFolders != null) {
+      for (File timePartitionFolder : timePartitionFolders) {
+        String timePartition = timePartitionFolder.getName();
+        File[] sourceFiles = timePartitionFolder.listFiles();
+        if (sourceFiles == null) {
+          continue;
+        }
+        File targetDir =
+            new File(
+                dataDir
+                    + File.separator
+                    + IoTDBConstant.UNSEQUENCE_FLODER_NAME
+                    + File.separator
+                    + storageGroupName
+                    + File.separator
+                    + dataRegionId
+                    + File.separator
+                    + timePartition);
+        createLinksFromSourceToTarget(targetDir, sourceFiles);
+        cnt += sourceFiles.length;
+      }
+    }
+
+    return cnt;
+  }
+
+  private void createLinksFromSourceToTarget(File targetDir, File[] files) 
throws IOException {
+    for (File file : files) {
+      File targetFile = new File(targetDir, file.getName());
+      if (!targetFile.getParentFile().exists() && 
!targetFile.getParentFile().mkdirs()) {
+        throw new IOException(
+            String.format(
+                "Cannot create directory %s", 
targetFile.getParentFile().getAbsolutePath()));
+      }
+      Files.createLink(targetFile.toPath(), file.toPath());
     }
   }
 
@@ -338,7 +407,7 @@ public class SnapshotLoader {
     File snapshotLogFile = getSnapshotLogFile();
 
     if (snapshotLogFile == null) {
-      return getSnapshotFileWithoutLog();
+      return searchDataFilesRecursively(snapshotPath);
     } else {
       return getSnapshotFileWithLog(snapshotLogFile);
     }
@@ -347,24 +416,44 @@ public class SnapshotLoader {
   private List<File> getSnapshotFileWithLog(File logFile) throws IOException {
     SnapshotLogAnalyzer analyzer = new SnapshotLogAnalyzer(logFile);
     try {
-
+      String snapshotId = analyzer.getSnapshotId();
+      String[] dataDirs = 
IoTDBDescriptor.getInstance().getConfig().getDataDirs();
       List<File> fileList = new LinkedList<>();
-
-      while (analyzer.hasNext()) {
-        fileList.add(new File(analyzer.getNextPairs().right));
+      for (String dataDir : dataDirs) {
+        String snapshotDir =
+            dataDir
+                + File.separator
+                + IoTDBConstant.SNAPSHOT_FOLDER_NAME
+                + File.separator
+                + snapshotId;
+        fileList.addAll(searchDataFilesRecursively(snapshotDir));
       }
-
       return fileList;
     } finally {
       analyzer.close();
     }
   }
 
-  private List<File> getSnapshotFileWithoutLog() {
-    return new LinkedList<>(
-        Arrays.asList(
-            Objects.requireNonNull(
-                new File(snapshotPath)
-                    .listFiles((dir, name) -> SnapshotFileSet.isDataFile(new 
File(dir, name))))));
+  /**
+   * Search all data files in one directory recursively.
+   *
+   * @return
+   */
+  private List<File> searchDataFilesRecursively(String dir) {
+    LinkedList<File> fileList = new LinkedList<>();
+    Queue<File> queueToSearch = new LinkedList<>();
+    queueToSearch.add(new File(dir));
+    while (!queueToSearch.isEmpty()) {
+      File f = queueToSearch.poll();
+      if (f.isDirectory()) {
+        File[] files = f.listFiles();
+        if (files != null && files.length != 0) {
+          queueToSearch.addAll(Arrays.asList(files));
+        }
+      } else if (SnapshotFileSet.isDataFile(f)) {
+        fileList.add(f);
+      }
+    }
+    return fileList;
   }
 }
diff --git 
a/server/src/main/java/org/apache/iotdb/db/engine/snapshot/SnapshotLogAnalyzer.java
 
b/server/src/main/java/org/apache/iotdb/db/engine/snapshot/SnapshotLogAnalyzer.java
index 9291a99e3d..9fa935b969 100644
--- 
a/server/src/main/java/org/apache/iotdb/db/engine/snapshot/SnapshotLogAnalyzer.java
+++ 
b/server/src/main/java/org/apache/iotdb/db/engine/snapshot/SnapshotLogAnalyzer.java
@@ -25,18 +25,25 @@ import org.slf4j.LoggerFactory;
 
 import java.io.BufferedReader;
 import java.io.File;
-import java.io.FileNotFoundException;
+import java.io.FileInputStream;
 import java.io.FileReader;
 import java.io.IOException;
+import java.nio.charset.StandardCharsets;
 
 public class SnapshotLogAnalyzer {
   private static final Logger LOGGER = 
LoggerFactory.getLogger(SnapshotLogAnalyzer.class);
   private File snapshotLogFile;
   private BufferedReader reader;
+  private FileReader fileReader;
+  private FileInputStream fileInputStream;
+  String snapshotId;
 
-  public SnapshotLogAnalyzer(File snapshotLogFile) throws 
FileNotFoundException {
+  public SnapshotLogAnalyzer(File snapshotLogFile) throws IOException {
     this.snapshotLogFile = snapshotLogFile;
-    this.reader = new BufferedReader(new FileReader(snapshotLogFile));
+    this.fileReader = new FileReader(snapshotLogFile);
+    this.fileInputStream = new FileInputStream(snapshotLogFile);
+    this.reader = new BufferedReader(fileReader);
+    this.snapshotId = reader.readLine();
   }
 
   public void close() {
@@ -59,7 +66,7 @@ public class SnapshotLogAnalyzer {
    * @return The next pair of files recorded in the log. The left one is the 
path of source file,
    *     the right one is the path of target file
    */
-  public Pair<String, String> getNextPairs() {
+  public Pair<String, String> getTotalFileCount() {
     if (reader == null) {
       return null;
     }
@@ -76,4 +83,42 @@ public class SnapshotLogAnalyzer {
       return null;
     }
   }
+
+  public String getSnapshotId() {
+    return snapshotId;
+  }
+
+  /**
+   * Return the total num of file in this snapshot.
+   *
+   * @return
+   */
+  public int getTotalFileCountInSnapshot() throws IOException {
+    reader.reset();
+    String currLine;
+    int cnt = 0;
+    while ((currLine = reader.readLine()) != null) {
+      cnt++;
+    }
+    return cnt;
+  }
+
+  /**
+   * Read the tail of the log file to see if the snapshot is complete.
+   *
+   * @return
+   */
+  public boolean isSnapshotComplete() throws IOException {
+    char[] endFlagInChar = new char[SnapshotLogger.END_FLAG.length()];
+    long fileLength = snapshotLogFile.length();
+    int endFlagLength = 
SnapshotLogger.END_FLAG.getBytes(StandardCharsets.UTF_8).length;
+    if (fileLength < endFlagLength) {
+      // this snapshot cannot be complete
+      return false;
+    }
+    reader.mark((int) fileLength);
+    reader.read(endFlagInChar, (int) (fileLength - endFlagLength), 
endFlagLength);
+    String fileEndStr = new String(endFlagInChar);
+    return fileEndStr.equals(SnapshotLogger.END_FLAG);
+  }
 }
diff --git 
a/server/src/main/java/org/apache/iotdb/db/engine/snapshot/SnapshotLogger.java 
b/server/src/main/java/org/apache/iotdb/db/engine/snapshot/SnapshotLogger.java
index b2b8c06ba5..c067a0c3c3 100644
--- 
a/server/src/main/java/org/apache/iotdb/db/engine/snapshot/SnapshotLogger.java
+++ 
b/server/src/main/java/org/apache/iotdb/db/engine/snapshot/SnapshotLogger.java
@@ -27,7 +27,13 @@ import java.nio.file.Files;
 
 public class SnapshotLogger implements AutoCloseable {
   public static final String SNAPSHOT_LOG_NAME = "snapshot.log";
-  public static final String SPLIT_CHAR = "#";
+  public static final String SPLIT_CHAR = " ";
+  public static final String END_FLAG = "END";
+  public static final int FILE_NAME_OFFSET = 1;
+  public static final int TIME_PARTITION_OFFSET = 2;
+  public static final int DATA_REGION_OFFSET = 3;
+  public static final int STORAGE_GROUP_OFFSET = 4;
+  public static final int SEQUENCE_OFFSET = 5;
 
   private File logFile;
   private BufferedOutputStream os;
@@ -48,14 +54,55 @@ public class SnapshotLogger implements AutoCloseable {
     os.close();
   }
 
-  public void logFile(String sourceFile, String linkFile) throws IOException {
-    os.write(sourceFile.getBytes(StandardCharsets.UTF_8));
+  /**
+   * Log the logical info for the link file, including its file name, time 
partition, data region
+   * id, storage group name, sequence or not.
+   *
+   * @param sourceFile
+   * @throws IOException
+   */
+  public void logFile(File sourceFile) throws IOException {
+    String[] splitInfo =
+        sourceFile.getAbsolutePath().split(File.separator.equals("\\") ? 
"\\\\" : "/");
+    int length = splitInfo.length;
+    String fileName = splitInfo[length - FILE_NAME_OFFSET];
+    String timePartition = splitInfo[length - TIME_PARTITION_OFFSET];
+    String dataRegion = splitInfo[length - DATA_REGION_OFFSET];
+    String storageGroup = splitInfo[length - STORAGE_GROUP_OFFSET];
+    String sequence = splitInfo[length - SEQUENCE_OFFSET];
+    os.write(fileName.getBytes(StandardCharsets.UTF_8));
     os.write(SPLIT_CHAR.getBytes(StandardCharsets.UTF_8));
-    os.write(linkFile.getBytes(StandardCharsets.UTF_8));
+    os.write(timePartition.getBytes(StandardCharsets.UTF_8));
+    os.write(SPLIT_CHAR.getBytes(StandardCharsets.UTF_8));
+    os.write(dataRegion.getBytes(StandardCharsets.UTF_8));
+    os.write(SPLIT_CHAR.getBytes(StandardCharsets.UTF_8));
+    os.write(storageGroup.getBytes(StandardCharsets.UTF_8));
+    os.write(SPLIT_CHAR.getBytes(StandardCharsets.UTF_8));
+    os.write(sequence.getBytes(StandardCharsets.UTF_8));
     os.write("\n".getBytes(StandardCharsets.UTF_8));
     os.flush();
   }
 
+  /**
+   * Log the snapshot id to identify this snapshot.
+   *
+   * @param id
+   * @throws IOException
+   */
+  public void logSnapshotId(String id) throws IOException {
+    os.write(id.getBytes(StandardCharsets.UTF_8));
+    os.write("\n".getBytes(StandardCharsets.UTF_8));
+  }
+
+  /**
+   * Log the end of the snapshot.
+   *
+   * @throws IOException
+   */
+  public void logEnd() throws IOException {
+    os.write(END_FLAG.getBytes(StandardCharsets.UTF_8));
+  }
+
   public void cleanUpWhenFailed() throws IOException {
     os.close();
     Files.delete(logFile.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 004793bfa2..bde1e083d1 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
@@ -19,6 +19,7 @@
 
 package org.apache.iotdb.db.engine.snapshot;
 
+import org.apache.iotdb.commons.conf.IoTDBConstant;
 import org.apache.iotdb.commons.utils.FileUtils;
 import org.apache.iotdb.db.conf.IoTDBDescriptor;
 import org.apache.iotdb.db.engine.modification.ModificationFile;
@@ -76,6 +77,7 @@ public class SnapshotTaker {
     try {
       snapshotLogger = new SnapshotLogger(snapshotLog);
       boolean success = true;
+      snapshotLogger.logSnapshotId(snapshotDir.getName());
 
       readLockTheFile();
       try {
@@ -92,6 +94,7 @@ public class SnapshotTaker {
             dataRegion.getDataRegionId());
         cleanUpWhenFail(snapshotDir.getName());
       } else {
+        snapshotLogger.logEnd();
         LOGGER.info(
             "Successfully take snapshot for {}-{}, snapshot directory is {}",
             dataRegion.getStorageGroupName(),
@@ -167,7 +170,7 @@ public class SnapshotTaker {
 
   private void createHardLink(File target, File source) throws IOException {
     Files.createLink(target.toPath(), source.toPath());
-    snapshotLogger.logFile(source.getAbsolutePath(), target.getAbsolutePath());
+    snapshotLogger.logFile(source);
   }
 
   /**
@@ -193,7 +196,7 @@ public class SnapshotTaker {
       stringBuilder.append(splittedPath[i]);
       stringBuilder.append(File.separator);
     }
-    stringBuilder.append("snapshot");
+    stringBuilder.append(IoTDBConstant.SNAPSHOT_FOLDER_NAME);
     stringBuilder.append(File.separator);
     stringBuilder.append(snapshotId);
     stringBuilder.append(File.separator);
@@ -215,7 +218,12 @@ public class SnapshotTaker {
   private void cleanUpWhenFail(String snapshotId) {
     for (String dataDir : 
IoTDBDescriptor.getInstance().getConfig().getDataDirs()) {
       File dataDirForThisSnapshot =
-          new File(dataDir + File.separator + "snapshot" + File.separator + 
snapshotId);
+          new File(
+              dataDir
+                  + File.separator
+                  + IoTDBConstant.SNAPSHOT_FOLDER_NAME
+                  + File.separator
+                  + snapshotId);
       if (dataDirForThisSnapshot.exists()) {
         try {
           
FileUtils.recursiveDeleteFolder(dataDirForThisSnapshot.getAbsolutePath());
diff --git 
a/server/src/test/java/org/apache/iotdb/db/engine/snapshot/IoTDBSnapshotTest.java
 
b/server/src/test/java/org/apache/iotdb/db/engine/snapshot/IoTDBSnapshotTest.java
index 804ed6ef94..49c8560ef3 100644
--- 
a/server/src/test/java/org/apache/iotdb/db/engine/snapshot/IoTDBSnapshotTest.java
+++ 
b/server/src/test/java/org/apache/iotdb/db/engine/snapshot/IoTDBSnapshotTest.java
@@ -110,7 +110,7 @@ public class IoTDBSnapshotTest {
         SnapshotLogAnalyzer analyzer = new SnapshotLogAnalyzer(files[0]);
         int cnt = 0;
         while (analyzer.hasNext()) {
-          analyzer.getNextPairs();
+          analyzer.getTotalFileCount();
           cnt++;
         }
         analyzer.close();

Reply via email to