You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@iotdb.apache.org by qi...@apache.org on 2022/08/18 08:53:00 UTC
[iotdb] branch master updated: [IOTDB-3771] Fix cannot take snapshot when the data dir and snapshot dir is on different disk (#6782)
This is an automated email from the ASF dual-hosted git repository.
qiaojialin 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 66e53e1338 [IOTDB-3771] Fix cannot take snapshot when the data dir and snapshot dir is on different disk (#6782)
66e53e1338 is described below
commit 66e53e1338205b1d1548405cebab7658dca14f19
Author: Liu Xuxin <37...@users.noreply.github.com>
AuthorDate: Thu Aug 18 16:52:53 2022 +0800
[IOTDB-3771] Fix cannot take snapshot when the data dir and snapshot dir is on different disk (#6782)
---
.../org/apache/iotdb/commons/utils/FileUtils.java | 17 ++
server/pom.xml | 6 +
.../java/org/apache/iotdb/db/conf/IoTDBConfig.java | 2 +-
.../db/conf/directories/DirectoryManager.java | 17 ++
.../statemachine/DataRegionStateMachine.java | 21 +-
.../org/apache/iotdb/db/engine/StorageEngine.java | 2 +-
.../apache/iotdb/db/engine/StorageEngineV2.java | 8 +-
.../iotdb/db/engine/snapshot/SnapshotFileSet.java | 44 ++++
.../iotdb/db/engine/snapshot/SnapshotLoader.java | 144 ++++++++++--
.../db/engine/snapshot/SnapshotLogAnalyzer.java | 79 +++++++
.../iotdb/db/engine/snapshot/SnapshotLogger.java | 58 +++++
.../iotdb/db/engine/snapshot/SnapshotTaker.java | 243 ++++++++++++---------
.../exception/DirectoryNotLegalException.java | 7 +-
.../iotdb/db/engine/storagegroup/DataRegion.java | 123 +++++------
.../engine/storagegroup/TsFileProcessorInfo.java | 6 +-
.../dataregion/StorageGroupManager.java | 4 +-
.../org/apache/iotdb/db/rescon/SystemInfo.java | 10 +-
.../db/engine/snapshot/IoTDBSnapshotTest.java | 199 +++++++++++++++++
.../apache/iotdb/db/utils/EnvironmentUtils.java | 17 ++
.../iotdb/tsfile/utils/TsFileGeneratorUtils.java | 100 +++++----
20 files changed, 847 insertions(+), 260 deletions(-)
diff --git a/node-commons/src/main/java/org/apache/iotdb/commons/utils/FileUtils.java b/node-commons/src/main/java/org/apache/iotdb/commons/utils/FileUtils.java
index a641e11381..b7a2b8b9be 100644
--- a/node-commons/src/main/java/org/apache/iotdb/commons/utils/FileUtils.java
+++ b/node-commons/src/main/java/org/apache/iotdb/commons/utils/FileUtils.java
@@ -136,4 +136,21 @@ public class FileUtils {
}
return sum;
}
+
+ public static void recursiveDeleteFolder(String path) throws IOException {
+ File file = new File(path);
+ if (file.isDirectory()) {
+ File[] files = file.listFiles();
+ if (files == null || files.length == 0) {
+ org.apache.commons.io.FileUtils.deleteDirectory(file);
+ } else {
+ for (File f : files) {
+ recursiveDeleteFolder(f.getAbsolutePath());
+ }
+ org.apache.commons.io.FileUtils.deleteDirectory(file);
+ }
+ } else {
+ org.apache.commons.io.FileUtils.delete(file);
+ }
+ }
}
diff --git a/server/pom.xml b/server/pom.xml
index fed4669024..347268084a 100644
--- a/server/pom.xml
+++ b/server/pom.xml
@@ -223,6 +223,12 @@
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
</dependency>
+ <dependency>
+ <groupId>org.apache.iotdb</groupId>
+ <artifactId>node-commons</artifactId>
+ <version>${project.version}</version>
+ <scope>compile</scope>
+ </dependency>
</dependencies>
<build>
<plugins>
diff --git a/server/src/main/java/org/apache/iotdb/db/conf/IoTDBConfig.java b/server/src/main/java/org/apache/iotdb/db/conf/IoTDBConfig.java
index 416a2a300e..3ee6e92b35 100644
--- a/server/src/main/java/org/apache/iotdb/db/conf/IoTDBConfig.java
+++ b/server/src/main/java/org/apache/iotdb/db/conf/IoTDBConfig.java
@@ -1156,7 +1156,7 @@ public class IoTDBConfig {
return dataDirs;
}
- void setDataDirs(String[] dataDirs) {
+ public void setDataDirs(String[] dataDirs) {
this.dataDirs = dataDirs;
}
diff --git a/server/src/main/java/org/apache/iotdb/db/conf/directories/DirectoryManager.java b/server/src/main/java/org/apache/iotdb/db/conf/directories/DirectoryManager.java
index 7b3a1478b9..5233337cf0 100644
--- a/server/src/main/java/org/apache/iotdb/db/conf/directories/DirectoryManager.java
+++ b/server/src/main/java/org/apache/iotdb/db/conf/directories/DirectoryManager.java
@@ -19,6 +19,7 @@
package org.apache.iotdb.db.conf.directories;
import org.apache.iotdb.commons.conf.IoTDBConstant;
+import org.apache.iotdb.commons.utils.TestOnly;
import org.apache.iotdb.db.conf.IoTDBDescriptor;
import org.apache.iotdb.db.conf.SystemStatus;
import org.apache.iotdb.db.conf.directories.strategy.DirectoryStrategy;
@@ -175,6 +176,22 @@ public class DirectoryManager {
return folders;
}
+ @TestOnly
+ public void resetFolders() {
+ sequenceFileFolders =
+ new ArrayList<>(Arrays.asList(IoTDBDescriptor.getInstance().getConfig().getDataDirs()));
+ for (int i = 0; i < sequenceFileFolders.size(); i++) {
+ sequenceFileFolders.set(
+ i, sequenceFileFolders.get(i) + File.separator + IoTDBConstant.SEQUENCE_FLODER_NAME);
+ }
+ unsequenceFileFolders =
+ new ArrayList<>(Arrays.asList(IoTDBDescriptor.getInstance().getConfig().getDataDirs()));
+ for (int i = 0; i < unsequenceFileFolders.size(); i++) {
+ unsequenceFileFolders.set(
+ i, unsequenceFileFolders.get(i) + File.separator + IoTDBConstant.UNSEQUENCE_FLODER_NAME);
+ }
+ }
+
private static class DirectoriesHolder {
private static final DirectoryManager INSTANCE = new DirectoryManager();
}
diff --git a/server/src/main/java/org/apache/iotdb/db/consensus/statemachine/DataRegionStateMachine.java b/server/src/main/java/org/apache/iotdb/db/consensus/statemachine/DataRegionStateMachine.java
index 721f3c33af..6c52fa73c3 100644
--- a/server/src/main/java/org/apache/iotdb/db/consensus/statemachine/DataRegionStateMachine.java
+++ b/server/src/main/java/org/apache/iotdb/db/consensus/statemachine/DataRegionStateMachine.java
@@ -48,6 +48,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
+import java.io.IOException;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
@@ -97,7 +98,7 @@ public class DataRegionStateMachine extends BaseStateMachine {
} catch (Exception e) {
logger.error(
"Exception occurs when taking snapshot for {}-{} in {}",
- region.getLogicalStorageGroupName(),
+ region.getStorageGroupName(),
region.getDataRegionId(),
snapshotDir,
e);
@@ -110,7 +111,7 @@ public class DataRegionStateMachine extends BaseStateMachine {
DataRegion newRegion =
new SnapshotLoader(
latestSnapshotRootDir.getAbsolutePath(),
- region.getLogicalStorageGroupName(),
+ region.getStorageGroupName(),
region.getDataRegionId())
.loadSnapshotForStateMachine();
if (newRegion == null) {
@@ -258,8 +259,20 @@ public class DataRegionStateMachine extends BaseStateMachine {
@Override
public List<File> getSnapshotFiles(File latestSnapshotRootDir) {
- // TODO: implement this method
- return super.getSnapshotFiles(latestSnapshotRootDir);
+ try {
+ return new SnapshotLoader(
+ latestSnapshotRootDir.getAbsolutePath(),
+ region.getStorageGroupName(),
+ region.getDataRegionId())
+ .getSnapshotFileInfo();
+ } catch (IOException e) {
+ logger.error(
+ "Meets error when getting snapshot files for {}-{}",
+ region.getStorageGroupName(),
+ region.getDataRegionId(),
+ e);
+ return null;
+ }
}
@Override
diff --git a/server/src/main/java/org/apache/iotdb/db/engine/StorageEngine.java b/server/src/main/java/org/apache/iotdb/db/engine/StorageEngine.java
index ab461f6b8c..60e0fecefa 100644
--- a/server/src/main/java/org/apache/iotdb/db/engine/StorageEngine.java
+++ b/server/src/main/java/org/apache/iotdb/db/engine/StorageEngine.java
@@ -1113,7 +1113,7 @@ public class StorageEngine implements IService {
public String getStorageGroupPath(PartialPath path) throws StorageEngineException {
PartialPath deviceId = path.getDevicePath();
DataRegion storageGroupProcessor = getProcessor(deviceId);
- return storageGroupProcessor.getLogicalStorageGroupName()
+ return storageGroupProcessor.getStorageGroupName()
+ File.separator
+ storageGroupProcessor.getDataRegionId();
}
diff --git a/server/src/main/java/org/apache/iotdb/db/engine/StorageEngineV2.java b/server/src/main/java/org/apache/iotdb/db/engine/StorageEngineV2.java
index 2cef4a19a0..f1a5f3ab21 100644
--- a/server/src/main/java/org/apache/iotdb/db/engine/StorageEngineV2.java
+++ b/server/src/main/java/org/apache/iotdb/db/engine/StorageEngineV2.java
@@ -540,7 +540,7 @@ public class StorageEngineV2 implements IService {
public void closeStorageGroupProcessor(String storageGroupPath, boolean isSeq) {
for (DataRegion dataRegion : dataRegionMap.values()) {
- if (dataRegion.getLogicalStorageGroupName().equals(storageGroupPath)) {
+ if (dataRegion.getStorageGroupName().equals(storageGroupPath)) {
if (isSeq) {
for (TsFileProcessor tsFileProcessor : dataRegion.getWorkSequenceTsFileProcessors()) {
dataRegion.syncCloseOneTsFileProcessor(isSeq, tsFileProcessor);
@@ -662,14 +662,12 @@ public class StorageEngineV2 implements IService {
.equals(ConsensusFactory.MultiLeaderConsensus)) {
WALManager.getInstance()
.deleteWALNode(
- region.getLogicalStorageGroupName()
- + FILE_NAME_SEPARATOR
- + region.getDataRegionId());
+ region.getStorageGroupName() + FILE_NAME_SEPARATOR + region.getDataRegionId());
}
} catch (Exception e) {
logger.error(
"Error occurs when deleting data region {}-{}",
- region.getLogicalStorageGroupName(),
+ region.getStorageGroupName(),
region.getDataRegionId(),
e);
} finally {
diff --git a/server/src/main/java/org/apache/iotdb/db/engine/snapshot/SnapshotFileSet.java b/server/src/main/java/org/apache/iotdb/db/engine/snapshot/SnapshotFileSet.java
new file mode 100644
index 0000000000..ee5aeb6db7
--- /dev/null
+++ b/server/src/main/java/org/apache/iotdb/db/engine/snapshot/SnapshotFileSet.java
@@ -0,0 +1,44 @@
+/*
+ * 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.iotdb.db.engine.snapshot;
+
+import org.apache.iotdb.db.engine.modification.ModificationFile;
+import org.apache.iotdb.db.engine.storagegroup.TsFileResource;
+import org.apache.iotdb.tsfile.common.constant.TsFileConstant;
+
+import java.io.File;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
+
+public class SnapshotFileSet {
+ public static final String[] DATA_FILE_SUFFIX =
+ new String[] {
+ TsFileConstant.TSFILE_SUFFIX, TsFileResource.RESOURCE_SUFFIX, ModificationFile.FILE_SUFFIX,
+ };
+
+ private static final Set<String> DATA_FILE_SUFFIX_SET =
+ new HashSet<>(Arrays.asList(DATA_FILE_SUFFIX));
+
+ public static boolean isDataFile(File file) {
+ String[] fileName = file.getName().split("\\.");
+ return DATA_FILE_SUFFIX_SET.contains(fileName[fileName.length - 1]);
+ }
+}
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 8067da84d4..cff5886f38 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
@@ -16,6 +16,7 @@
* specific language governing permissions and limitations
* under the License.
*/
+
package org.apache.iotdb.db.engine.snapshot;
import org.apache.iotdb.commons.conf.IoTDBConstant;
@@ -24,6 +25,7 @@ import org.apache.iotdb.db.conf.directories.DirectoryManager;
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;
@@ -31,17 +33,21 @@ 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;
public class SnapshotLoader {
private Logger LOGGER = LoggerFactory.getLogger(SnapshotLoader.class);
private String storageGroupName;
private String snapshotPath;
private String dataRegionId;
+ private SnapshotLogAnalyzer logAnalyzer;
public SnapshotLoader(String snapshotPath, String storageGroupName, String dataRegionId) {
this.snapshotPath = snapshotPath;
@@ -66,6 +72,25 @@ public class SnapshotLoader {
}
}
+ private File getSnapshotLogFile() {
+ File sourceDataDir = new File(snapshotPath);
+
+ if (sourceDataDir.exists()) {
+ File[] files =
+ sourceDataDir.listFiles((dir, name) -> name.equals(SnapshotLogger.SNAPSHOT_LOG_NAME));
+ if (files == null || files.length == 0) {
+ LOGGER.warn("Failed to find snapshot log file, cannot recover it");
+ } else if (files.length > 1) {
+ LOGGER.warn(
+ "Found more than one snapshot log file, cannot recover it. {}", Arrays.toString(files));
+ } else {
+ LOGGER.info("Reading snapshot log file {}", files[0]);
+ return files[0];
+ }
+ }
+ return null;
+ }
+
/**
* 1. Clear origin data 2. Move snapshot data to data dir 3. Load data region
*
@@ -77,27 +102,49 @@ public class SnapshotLoader {
storageGroupName,
dataRegionId,
snapshotPath);
+
+ File snapshotLogFile = getSnapshotLogFile();
+
+ if (snapshotLogFile == null) {
+ return loadSnapshotWithoutLog();
+ } else {
+ return loadSnapshotWithLog(snapshotLogFile);
+ }
+ }
+
+ private DataRegion loadSnapshotWithoutLog() {
try {
- deleteAllFilesInDataDirs();
- LOGGER.info("Remove all data files in original data dir");
- } catch (IOException e) {
+ LOGGER.info("Moving snapshot file to data dirs");
+ createLinksFromSnapshotDirToDataDirWithoutLog(new File(snapshotPath));
+ return loadSnapshot();
+ } catch (IOException | DiskSpaceInsufficientException e) {
+ LOGGER.error(
+ "Exception occurs when loading snapshot for {}-{}", storageGroupName, dataRegionId, e);
return null;
}
+ }
- // move the snapshot data to data dir
- File sourceDataDir = new File(snapshotPath);
- if (sourceDataDir.exists()) {
+ private DataRegion loadSnapshotWithLog(File logFile) {
+ try {
+ logAnalyzer = new SnapshotLogAnalyzer(logFile);
+ } catch (Exception e) {
+ LOGGER.error("Exception occurs when reading snapshot file", e);
+ return null;
+ }
+
+ try {
try {
- createLinksFromSnapshotDirToDataDir(sourceDataDir);
- LOGGER.info("Move data files from snapshot to data directory");
- } catch (IOException | DiskSpaceInsufficientException e) {
- LOGGER.error(
- "Exception occurs when creating links from snapshot directory to data directory", e);
+ deleteAllFilesInDataDirs();
+ LOGGER.info("Remove all data files in original data dir");
+ } catch (IOException e) {
return null;
}
- }
- return loadSnapshot();
+ createLinksFromSnapshotDirToDataDirWithLog();
+ return loadSnapshot();
+ } finally {
+ logAnalyzer.close();
+ }
}
private void deleteAllFilesInDataDirs() throws IOException {
@@ -154,7 +201,7 @@ public class SnapshotLoader {
}
}
- private void createLinksFromSnapshotDirToDataDir(File sourceDir)
+ 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);
@@ -202,7 +249,13 @@ public class SnapshotLoader {
throw new IOException(
String.format("Failed to create dir %s", targetFile.getParent()));
}
- Files.createLink(targetFile.toPath(), file.toPath());
+ 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());
+ }
}
}
}
@@ -247,7 +300,11 @@ public class SnapshotLoader {
throw new IOException(
String.format("Failed to create dir %s", targetFile.getParent()));
}
- Files.createLink(targetFile.toPath(), file.toPath());
+ try {
+ Files.createLink(targetFile.toPath(), file.toPath());
+ } catch (FileSystemException e) {
+ Files.copy(file.toPath(), targetFile.toPath());
+ }
}
}
}
@@ -255,4 +312,59 @@ public class SnapshotLoader {
}
}
}
+
+ 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;
+ }
+ try {
+ Files.createLink(sourceFile.toPath(), linkedFile.toPath());
+ } catch (IOException e) {
+ LOGGER.error("Failed to create link from {} to {}", linkedFile, sourceFile, e);
+ }
+ }
+ }
+
+ public List<File> getSnapshotFileInfo() throws IOException {
+ File snapshotLogFile = getSnapshotLogFile();
+
+ if (snapshotLogFile == null) {
+ return getSnapshotFileWithoutLog();
+ } else {
+ return getSnapshotFileWithLog(snapshotLogFile);
+ }
+ }
+
+ private List<File> getSnapshotFileWithLog(File logFile) throws IOException {
+ SnapshotLogAnalyzer analyzer = new SnapshotLogAnalyzer(logFile);
+ try {
+
+ List<File> fileList = new LinkedList<>();
+
+ while (analyzer.hasNext()) {
+ fileList.add(new File(analyzer.getNextPairs().right));
+ }
+
+ 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))))));
+ }
}
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
new file mode 100644
index 0000000000..9291a99e3d
--- /dev/null
+++ b/server/src/main/java/org/apache/iotdb/db/engine/snapshot/SnapshotLogAnalyzer.java
@@ -0,0 +1,79 @@
+/*
+ * 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.iotdb.db.engine.snapshot;
+
+import org.apache.iotdb.tsfile.utils.Pair;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.IOException;
+
+public class SnapshotLogAnalyzer {
+ private static final Logger LOGGER = LoggerFactory.getLogger(SnapshotLogAnalyzer.class);
+ private File snapshotLogFile;
+ private BufferedReader reader;
+
+ public SnapshotLogAnalyzer(File snapshotLogFile) throws FileNotFoundException {
+ this.snapshotLogFile = snapshotLogFile;
+ this.reader = new BufferedReader(new FileReader(snapshotLogFile));
+ }
+
+ public void close() {
+ try {
+ reader.close();
+ } catch (IOException e) {
+ LOGGER.error("Exception occurs when closing log analyzer", e);
+ }
+ }
+
+ public boolean hasNext() {
+ try {
+ return reader != null && reader.ready();
+ } catch (Exception e) {
+ return false;
+ }
+ }
+
+ /**
+ * @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() {
+ if (reader == null) {
+ return null;
+ }
+ try {
+ String fileInfo = reader.readLine();
+ String[] filesPath = fileInfo.split(SnapshotLogger.SPLIT_CHAR);
+ if (filesPath.length != 2) {
+ LOGGER.warn("Illegal file info: {} in snapshot log", fileInfo);
+ return null;
+ }
+ return new Pair<>(filesPath[0], filesPath[1]);
+ } catch (IOException e) {
+ LOGGER.error("Exception occurs when analyzing snapshot log", e);
+ return null;
+ }
+ }
+}
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
new file mode 100644
index 0000000000..fe1937fbcf
--- /dev/null
+++ b/server/src/main/java/org/apache/iotdb/db/engine/snapshot/SnapshotLogger.java
@@ -0,0 +1,58 @@
+/*
+ * 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.iotdb.db.engine.snapshot;
+
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+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 = "#";
+
+ private File logFile;
+ private BufferedOutputStream os;
+
+ public SnapshotLogger(File logFile) throws FileNotFoundException {
+ this.logFile = logFile;
+ os = new BufferedOutputStream(new FileOutputStream(logFile));
+ }
+
+ @Override
+ public void close() throws Exception {
+ os.close();
+ }
+
+ public void logFile(String sourceFile, String linkFile) throws IOException {
+ os.write(sourceFile.getBytes(StandardCharsets.UTF_8));
+ os.write(SPLIT_CHAR.getBytes(StandardCharsets.UTF_8));
+ os.write(linkFile.getBytes(StandardCharsets.UTF_8));
+ os.write("\n".getBytes(StandardCharsets.UTF_8));
+ os.flush();
+ }
+
+ 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 4796b66ac8..004793bfa2 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
@@ -16,11 +16,11 @@
* specific language governing permissions and limitations
* under the License.
*/
+
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.compaction.log.CompactionLogger;
import org.apache.iotdb.db.engine.modification.ModificationFile;
import org.apache.iotdb.db.engine.snapshot.exception.DirectoryNotLegalException;
import org.apache.iotdb.db.engine.storagegroup.DataRegion;
@@ -33,7 +33,6 @@ import org.slf4j.LoggerFactory;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
-import java.util.LinkedList;
import java.util.List;
import java.util.Objects;
@@ -46,9 +45,9 @@ import java.util.Objects;
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;
+ private SnapshotLogger snapshotLogger;
+ private List<TsFileResource> seqFiles;
+ private List<TsFileResource> unseqFiles;
public SnapshotTaker(DataRegion dataRegion) {
this.dataRegion = dataRegion;
@@ -64,22 +63,6 @@ public class SnapshotTaker {
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));
@@ -89,109 +72,157 @@ public class SnapshotTaker {
dataRegion.syncCloseAllWorkingTsFileProcessors();
}
- List<Long> timePartitions = dataRegion.getTimePartitions();
- TsFileManager manager = dataRegion.getTsFileManager();
- manager.readLock();
+ File snapshotLog = new File(snapshotDir, SnapshotLogger.SNAPSHOT_LOG_NAME);
try {
- for (Long timePartition : timePartitions) {
- List<String> seqDataDirs = getAllDataDirOfOnePartition(true, timePartition);
+ snapshotLogger = new SnapshotLogger(snapshotLog);
+ boolean success = true;
+
+ readLockTheFile();
+ try {
+ success = createSnapshot(seqFiles, snapshotDir.getName());
+ success = createSnapshot(unseqFiles, snapshotDir.getName()) && success;
+ } finally {
+ readUnlockTheFile();
+ }
- try {
- createFileSnapshot(seqDataDirs, true, timePartition);
- } catch (IOException e) {
- LOGGER.error("Fail to create snapshot", e);
- cleanUpWhenFail(snapshotDir);
- return false;
- }
+ if (!success) {
+ LOGGER.warn(
+ "Failed to take snapshot for {}-{}, clean up",
+ dataRegion.getStorageGroupName(),
+ dataRegion.getDataRegionId());
+ cleanUpWhenFail(snapshotDir.getName());
+ } else {
+ LOGGER.info(
+ "Successfully take snapshot for {}-{}, snapshot directory is {}",
+ dataRegion.getStorageGroupName(),
+ dataRegion.getDataRegionId(),
+ snapshotDirPath);
+ }
- List<String> unseqDataDirs = getAllDataDirOfOnePartition(false, timePartition);
+ return success;
+ } catch (Exception e) {
+ LOGGER.error(
+ "Exception occurs when taking snapshot for {}-{}",
+ dataRegion.getStorageGroupName(),
+ dataRegion.getDataRegionId(),
+ e);
+ return false;
+ } finally {
+ try {
+ snapshotLogger.close();
+ } catch (Exception e) {
+ LOGGER.error("Failed to close snapshot logger", e);
+ }
+ }
+ }
- try {
- createFileSnapshot(unseqDataDirs, false, timePartition);
- } catch (IOException e) {
- LOGGER.error("Fail to create snapshot", e);
- cleanUpWhenFail(snapshotDir);
- return false;
- }
+ private void readLockTheFile() {
+ TsFileManager manager = dataRegion.getTsFileManager();
+ manager.readLock();
+ try {
+ seqFiles = manager.getTsFileList(true);
+ unseqFiles = manager.getTsFileList(false);
+ for (TsFileResource resource : seqFiles) {
+ resource.readLock();
+ }
+ for (TsFileResource resource : unseqFiles) {
+ resource.readLock();
}
} finally {
manager.readUnlock();
}
-
- LOGGER.info(
- "Successfully take snapshot for {}-{}, snapshot directory is {}",
- dataRegion.getLogicalStorageGroupName(),
- dataRegion.getDataRegionId(),
- snapshotDirPath);
-
- return true;
}
- private List<String> getAllDataDirOfOnePartition(boolean sequence, long timePartition) {
- String[] dataDirs = IoTDBDescriptor.getInstance().getConfig().getDataDirs();
- List<String> resultDirs = new LinkedList<>();
-
- for (String dataDir : dataDirs) {
- resultDirs.add(
- dataDir
- + File.separator
- + (sequence
- ? IoTDBConstant.SEQUENCE_FLODER_NAME
- : IoTDBConstant.UNSEQUENCE_FLODER_NAME)
- + File.separator
- + dataRegion.getLogicalStorageGroupName()
- + File.separator
- + dataRegion.getDataRegionId()
- + File.separator
- + timePartition
- + File.separator);
+ private void readUnlockTheFile() {
+ for (TsFileResource resource : seqFiles) {
+ resource.readUnlock();
+ }
+ for (TsFileResource resource : unseqFiles) {
+ resource.readUnlock();
}
- return resultDirs;
}
- 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()));
+ private boolean createSnapshot(List<TsFileResource> resources, String snapshotId) {
+ try {
+ for (TsFileResource resource : resources) {
+ File tsFile = resource.getTsFile();
+ File snapshotTsFile = getSnapshotFilePathForTsFile(tsFile, snapshotId);
+ // create hard link for tsfile, resource, mods
+ createHardLink(snapshotTsFile, tsFile);
+ createHardLink(
+ new File(snapshotTsFile.getAbsolutePath() + TsFileResource.RESOURCE_SUFFIX),
+ new File(tsFile.getAbsolutePath() + TsFileResource.RESOURCE_SUFFIX));
+ if (resource.getModFile().exists()) {
+ createHardLink(
+ new File(snapshotTsFile.getAbsolutePath() + ModificationFile.FILE_SUFFIX),
+ new File(tsFile.getAbsolutePath() + ModificationFile.FILE_SUFFIX));
+ }
+ }
+ return true;
+ } catch (IOException e) {
+ LOGGER.error("Catch IOException when creating snapshot", e);
+ return false;
}
+ }
- for (String sourceDirPath : sourceDirPaths) {
- File sourceDir = new File(sourceDirPath);
- if (!sourceDir.exists()) {
- continue;
- }
- // Collect TsFile, TsFileResource, Mods, CompactionMods
- File[] files =
- sourceDir.listFiles(
- (dir, name) ->
- name.endsWith(".tsfile")
- || name.endsWith(TsFileResource.RESOURCE_SUFFIX)
- || name.endsWith(ModificationFile.FILE_SUFFIX)
- || name.endsWith(ModificationFile.COMPACTION_FILE_SUFFIX)
- || name.endsWith(CompactionLogger.INNER_COMPACTION_LOG_NAME_SUFFIX)
- || name.endsWith(CompactionLogger.CROSS_COMPACTION_LOG_NAME_SUFFIX)
- || name.endsWith(IoTDBConstant.INNER_COMPACTION_TMP_FILE_SUFFIX)
- || name.endsWith(IoTDBConstant.CROSS_COMPACTION_TMP_FILE_SUFFIX));
- if (files == null || files.length == 0) {
- continue;
- }
+ private void createHardLink(File target, File source) throws IOException {
+ Files.createLink(target.toPath(), source.toPath());
+ snapshotLogger.logFile(source.getAbsolutePath(), target.getAbsolutePath());
+ }
- for (File file : files) {
- File linkFile = new File(timePartitionDir, file.getName());
- Files.createLink(linkFile.toPath(), file.toPath());
- }
+ /**
+ * Construct the snapshot file path for a given tsfile, and will create the dir. Eg, given a
+ * tsfile in /data/iotdb/data/sequence/root.testsg/1/0/1-1-0-0.tsfile, with snapshotId "sm123",
+ * the snapshot location will be /data/iotdb/data/snapshot/sm123/root.testsg/1/0/1-1-0-0.tsfile
+ *
+ * @param tsFile tsfile to be taken a snapshot
+ * @param snapshotId the id for current snapshot
+ * @return the File object of the snapshot file, and its parent directory will be created
+ * @throws IOException
+ */
+ public File getSnapshotFilePathForTsFile(File tsFile, String snapshotId) throws IOException {
+ // ... data (un)sequence sgName dataRegionId timePartition tsFileName
+ String[] splittedPath =
+ tsFile.getAbsolutePath().split(File.separator.equals("\\") ? "\\\\" : File.separator);
+ // snapshot dir will be like
+ // ... data snapshot snapshotId (un)sequence sgName dataRegionId timePartition
+ StringBuilder stringBuilder = new StringBuilder();
+ int i = 0;
+ // build the prefix part of data dir
+ for (; i < splittedPath.length - 5; ++i) {
+ stringBuilder.append(splittedPath[i]);
+ stringBuilder.append(File.separator);
}
+ stringBuilder.append("snapshot");
+ stringBuilder.append(File.separator);
+ stringBuilder.append(snapshotId);
+ stringBuilder.append(File.separator);
+ // the content in here will be
+ // ... data snapshot snapshotId
+
+ // build the rest part for the dir
+ for (; i < splittedPath.length - 1; ++i) {
+ stringBuilder.append(splittedPath[i]);
+ stringBuilder.append(File.separator);
+ }
+ File dir = new File(stringBuilder.toString());
+ if (!dir.exists() && !dir.mkdirs()) {
+ throw new IOException("Cannot create directory " + dir.getAbsolutePath());
+ }
+ return new File(dir, tsFile.getName());
}
- private void cleanUpWhenFail(File snapshotDir) {
- File[] files = snapshotDir.listFiles();
- if (files != null) {
- for (File file : files) {
- if (!file.delete()) {
- LOGGER.error("Failed to delete link file {} after failing to create snapshot", file);
+ private void cleanUpWhenFail(String snapshotId) {
+ for (String dataDir : IoTDBDescriptor.getInstance().getConfig().getDataDirs()) {
+ File dataDirForThisSnapshot =
+ new File(dataDir + File.separator + "snapshot" + File.separator + snapshotId);
+ if (dataDirForThisSnapshot.exists()) {
+ try {
+ FileUtils.recursiveDeleteFolder(dataDirForThisSnapshot.getAbsolutePath());
+ } catch (IOException e) {
+ LOGGER.error(
+ "Failed to delete folder {} when cleaning up",
+ dataDirForThisSnapshot.getAbsolutePath());
}
}
}
diff --git a/server/src/main/java/org/apache/iotdb/db/engine/snapshot/exception/DirectoryNotLegalException.java b/server/src/main/java/org/apache/iotdb/db/engine/snapshot/exception/DirectoryNotLegalException.java
index bd4742d9e5..96eb9650dd 100644
--- a/server/src/main/java/org/apache/iotdb/db/engine/snapshot/exception/DirectoryNotLegalException.java
+++ b/server/src/main/java/org/apache/iotdb/db/engine/snapshot/exception/DirectoryNotLegalException.java
@@ -18,11 +18,8 @@
*/
package org.apache.iotdb.db.engine.snapshot.exception;
-import org.apache.iotdb.commons.exception.IoTDBException;
-import org.apache.iotdb.rpc.TSStatusCode;
-
-public class DirectoryNotLegalException extends IoTDBException {
+public class DirectoryNotLegalException extends Exception {
public DirectoryNotLegalException(String message) {
- super(message, TSStatusCode.SNAPSHOT_DIR_NOT_LEGAL.getStatusCode());
+ super(message);
}
}
diff --git a/server/src/main/java/org/apache/iotdb/db/engine/storagegroup/DataRegion.java b/server/src/main/java/org/apache/iotdb/db/engine/storagegroup/DataRegion.java
index e98ce60de4..6169901c29 100755
--- a/server/src/main/java/org/apache/iotdb/db/engine/storagegroup/DataRegion.java
+++ b/server/src/main/java/org/apache/iotdb/db/engine/storagegroup/DataRegion.java
@@ -218,7 +218,7 @@ public class DataRegion {
/** data region id */
private String dataRegionId;
/** logical storage group name */
- private String logicalStorageGroupName;
+ private String storageGroupName;
/** storage group system directory */
private File storageGroupSysDir;
/** manage seqFileList and unSeqFileList */
@@ -281,21 +281,21 @@ public class DataRegion {
* @param systemDir system dir path
* @param dataRegionId data region id e.g. 1
* @param fileFlushPolicy file flush policy
- * @param logicalStorageGroupName logical storage group name e.g. root.sg1
+ * @param storageGroupName logical storage group name e.g. root.sg1
*/
public DataRegion(
String systemDir,
String dataRegionId,
TsFileFlushPolicy fileFlushPolicy,
- String logicalStorageGroupName)
+ String storageGroupName)
throws DataRegionException {
this.dataRegionId = dataRegionId;
- this.logicalStorageGroupName = logicalStorageGroupName;
+ this.storageGroupName = storageGroupName;
this.fileFlushPolicy = fileFlushPolicy;
storageGroupSysDir = SystemFileFactory.INSTANCE.getFile(systemDir, dataRegionId);
this.tsFileManager =
- new TsFileManager(logicalStorageGroupName, dataRegionId, storageGroupSysDir.getPath());
+ new TsFileManager(storageGroupName, dataRegionId, storageGroupSysDir.getPath());
if (storageGroupSysDir.mkdirs()) {
logger.info(
"Storage Group system Directory {} doesn't exist, create it",
@@ -306,7 +306,7 @@ public class DataRegion {
// if use id table, we use id table flush time manager
if (config.isEnableIDTable()) {
- idTable = IDTableManager.getInstance().getIDTableDirectly(logicalStorageGroupName);
+ idTable = IDTableManager.getInstance().getIDTableDirectly(storageGroupName);
lastFlushTimeManager = new IDTableFlushTimeManager(idTable);
} else {
lastFlushTimeManager = new LastFlushTimeManager();
@@ -318,11 +318,11 @@ public class DataRegion {
&& !StorageEngineV2.getInstance().isAllSgReady()) {
logger.debug(
"Skip recovering data region {}[{}] when consensus protocol is ratis and storage engine is not ready.",
- logicalStorageGroupName,
+ storageGroupName,
dataRegionId);
for (String fileFolder : DirectoryManager.getInstance().getAllFilesFolders()) {
File dataRegionFolder =
- fsFactory.getFile(fileFolder, logicalStorageGroupName + File.separator + dataRegionId);
+ fsFactory.getFile(fileFolder, storageGroupName + File.separator + dataRegionId);
if (dataRegionFolder.exists()) {
File[] timePartitions = dataRegionFolder.listFiles();
if (timePartitions != null) {
@@ -333,7 +333,7 @@ public class DataRegion {
logger.error(
"Exception occurs when deleting time partition directory {} for {}-{}",
timePartitions,
- logicalStorageGroupName,
+ storageGroupName,
dataRegionId,
e);
}
@@ -352,11 +352,20 @@ public class DataRegion {
storageGroupInfo,
StorageGroupInfo::getMemCost,
Tag.NAME.toString(),
- "storageGroup_" + getLogicalStorageGroupName());
+ "storageGroup_" + getStorageGroupName());
}
- public String getLogicalStorageGroupName() {
- return logicalStorageGroupName;
+ @TestOnly
+ public DataRegion(String storageGroupName, String id) {
+ this.storageGroupName = storageGroupName;
+ this.dataRegionId = id;
+ this.tsFileManager = new TsFileManager(storageGroupName, id, "");
+ this.partitionMaxFileVersions = new HashMap<>();
+ partitionMaxFileVersions.put(0L, 0L);
+ }
+
+ public String getStorageGroupName() {
+ return storageGroupName;
}
public boolean isReady() {
@@ -414,7 +423,7 @@ public class DataRegion {
if (lastLogTime + config.getRecoveryLogIntervalInMs() < System.currentTimeMillis()) {
logger.info(
"The data region {}[{}] has recovered {}%, please wait a moment.",
- logicalStorageGroupName, dataRegionId, recoveredFilesNum * 1.0 / numOfFilesToRecover);
+ storageGroupName, dataRegionId, recoveredFilesNum * 1.0 / numOfFilesToRecover);
lastLogTime = System.currentTimeMillis();
}
}
@@ -547,13 +556,10 @@ public class DataRegion {
if (config.isMppMode()
? StorageEngineV2.getInstance().isAllSgReady()
: StorageEngine.getInstance().isAllSgReady()) {
- logger.info(
- "The data region {}[{}] is created successfully", logicalStorageGroupName, dataRegionId);
+ logger.info("The data region {}[{}] is created successfully", storageGroupName, dataRegionId);
} else {
logger.info(
- "The data region {}[{}] is recovered successfully",
- logicalStorageGroupName,
- dataRegionId);
+ "The data region {}[{}] is recovered successfully", storageGroupName, dataRegionId);
}
}
@@ -565,11 +571,7 @@ public class DataRegion {
}
timedCompactionScheduleTask =
IoTDBThreadPoolFactory.newSingleThreadScheduledExecutor(
- ThreadName.COMPACTION_SCHEDULE.getName()
- + "-"
- + logicalStorageGroupName
- + "-"
- + dataRegionId);
+ ThreadName.COMPACTION_SCHEDULE.getName() + "-" + storageGroupName + "-" + dataRegionId);
ScheduledExecutorUtil.safelyScheduleWithFixedDelay(
timedCompactionScheduleTask,
this::executeCompaction,
@@ -580,7 +582,7 @@ public class DataRegion {
private void recoverCompaction() {
CompactionRecoverManager compactionRecoverManager =
- new CompactionRecoverManager(tsFileManager, logicalStorageGroupName, dataRegionId);
+ new CompactionRecoverManager(tsFileManager, storageGroupName, dataRegionId);
compactionRecoverManager.recoverInnerSpaceCompaction(true);
compactionRecoverManager.recoverInnerSpaceCompaction(false);
compactionRecoverManager.recoverCrossSpaceCompaction();
@@ -643,7 +645,7 @@ public class DataRegion {
List<File> upgradeFiles = new ArrayList<>();
for (String baseDir : folders) {
File fileFolder =
- fsFactory.getFile(baseDir + File.separator + logicalStorageGroupName, dataRegionId);
+ fsFactory.getFile(baseDir + File.separator + storageGroupName, dataRegionId);
if (!fileFolder.exists()) {
continue;
}
@@ -723,11 +725,7 @@ public class DataRegion {
String.format(
"data region %s[%s] is down, because the time of tsfile %s is larger than system current time, "
+ "file time is %d while system current time is %d, please check it.",
- logicalStorageGroupName,
- dataRegionId,
- tsFile.getAbsolutePath(),
- fileTime,
- currentTime));
+ storageGroupName, dataRegionId, tsFile.getAbsolutePath(), fileTime, currentTime));
}
}
@@ -1525,7 +1523,7 @@ public class DataRegion {
String filePath =
TsFileNameGenerator.generateNewTsFilePathWithMkdir(
sequence,
- logicalStorageGroupName,
+ storageGroupName,
dataRegionId,
timePartitionId,
System.currentTimeMillis(),
@@ -1542,7 +1540,7 @@ public class DataRegion {
if (sequence) {
tsFileProcessor =
new TsFileProcessor(
- logicalStorageGroupName + FILE_NAME_SEPARATOR + dataRegionId,
+ storageGroupName + FILE_NAME_SEPARATOR + dataRegionId,
fsFactory.getFileWithParent(filePath),
storageGroupInfo,
this::closeUnsealedTsFileProcessorCallBack,
@@ -1551,7 +1549,7 @@ public class DataRegion {
} else {
tsFileProcessor =
new TsFileProcessor(
- logicalStorageGroupName + FILE_NAME_SEPARATOR + dataRegionId,
+ storageGroupName + FILE_NAME_SEPARATOR + dataRegionId,
fsFactory.getFileWithParent(filePath),
storageGroupInfo,
this::closeUnsealedTsFileProcessorCallBack,
@@ -1604,7 +1602,7 @@ public class DataRegion {
if (System.currentTimeMillis() - startTime > 60_000) {
logger.warn(
"{} has spent {}s to wait for closing one tsfile.",
- logicalStorageGroupName + "-" + this.dataRegionId,
+ storageGroupName + "-" + this.dataRegionId,
(System.currentTimeMillis() - startTime) / 1000);
}
}
@@ -1613,7 +1611,7 @@ public class DataRegion {
logger.error(
"syncCloseOneTsFileProcessor error occurs while waiting for closing the storage "
+ "group {}",
- logicalStorageGroupName + "-" + dataRegionId,
+ storageGroupName + "-" + dataRegionId,
e);
}
}
@@ -1647,8 +1645,7 @@ public class DataRegion {
if (!workUnsequenceTsFileProcessors.containsKey(tsFileProcessor.getTimeRangeId())) {
timePartitionIdVersionControllerMap.remove(tsFileProcessor.getTimeRangeId());
}
- logger.info(
- "close a sequence tsfile processor {}", logicalStorageGroupName + "-" + dataRegionId);
+ logger.info("close a sequence tsfile processor {}", storageGroupName + "-" + dataRegionId);
} else {
closingUnSequenceTsFileProcessor.add(tsFileProcessor);
tsFileProcessor.asyncClose();
@@ -1670,13 +1667,13 @@ public class DataRegion {
public void deleteFolder(String systemDir) {
logger.info(
"{} will close all files for deleting data folder {}",
- logicalStorageGroupName + "-" + dataRegionId,
+ storageGroupName + "-" + dataRegionId,
systemDir);
writeLock("deleteFolder");
try {
File dataRegionSystemFolder =
SystemFileFactory.INSTANCE.getFile(
- systemDir + File.separator + logicalStorageGroupName, dataRegionId);
+ systemDir + File.separator + storageGroupName, dataRegionId);
org.apache.iotdb.commons.utils.FileUtils.deleteDirectoryAndEmptyParent(
dataRegionSystemFolder);
} finally {
@@ -1705,8 +1702,7 @@ public class DataRegion {
/** delete tsfile */
public void syncDeleteDataFiles() {
logger.info(
- "{} will close all files for deleting data files",
- logicalStorageGroupName + "-" + dataRegionId);
+ "{} will close all files for deleting data files", storageGroupName + "-" + dataRegionId);
writeLock("syncDeleteDataFiles");
try {
@@ -1730,7 +1726,7 @@ public class DataRegion {
private void deleteAllSGFolders(List<String> folder) {
for (String tsfilePath : folder) {
File dataRegionDataFolder =
- fsFactory.getFile(tsfilePath, logicalStorageGroupName + File.separator + dataRegionId);
+ fsFactory.getFile(tsfilePath, storageGroupName + File.separator + dataRegionId);
if (dataRegionDataFolder.exists()) {
org.apache.iotdb.commons.utils.FileUtils.deleteDirectoryAndEmptyParent(
dataRegionDataFolder);
@@ -1741,14 +1737,13 @@ public class DataRegion {
/** Iterate each TsFile and try to lock and remove those out of TTL. */
public synchronized void checkFilesTTL() {
if (dataTTL == Long.MAX_VALUE) {
- logger.debug(
- "{}: TTL not set, ignore the check", logicalStorageGroupName + "-" + dataRegionId);
+ logger.debug("{}: TTL not set, ignore the check", storageGroupName + "-" + dataRegionId);
return;
}
long ttlLowerBound = System.currentTimeMillis() - dataTTL;
logger.debug(
"{}: TTL removing files before {}",
- logicalStorageGroupName + "-" + dataRegionId,
+ storageGroupName + "-" + dataRegionId,
new Date(ttlLowerBound));
// copy to avoid concurrent modification of deletion
@@ -1798,7 +1793,7 @@ public class DataRegion {
logger.info(
"Exceed sequence memtable flush interval, so flush working memtable of time partition {} in storage group {}[{}]",
tsFileProcessor.getTimeRangeId(),
- logicalStorageGroupName,
+ storageGroupName,
dataRegionId);
fileFlushPolicy.apply(this, tsFileProcessor, tsFileProcessor.isSequence());
}
@@ -1821,7 +1816,7 @@ public class DataRegion {
logger.info(
"Exceed unsequence memtable flush interval, so flush working memtable of time partition {} in storage group {}[{}]",
tsFileProcessor.getTimeRangeId(),
- logicalStorageGroupName,
+ storageGroupName,
dataRegionId);
fileFlushPolicy.apply(this, tsFileProcessor, tsFileProcessor.isSequence());
}
@@ -1843,7 +1838,7 @@ public class DataRegion {
if (System.currentTimeMillis() - startTime > 60_000) {
logger.warn(
"{} has spent {}s to wait for closing all TsFiles.",
- logicalStorageGroupName + "-" + this.dataRegionId,
+ storageGroupName + "-" + this.dataRegionId,
(System.currentTimeMillis() - startTime) / 1000);
}
}
@@ -1851,7 +1846,7 @@ public class DataRegion {
logger.error(
"CloseFileNodeCondition error occurs while waiting for closing the storage "
+ "group {}",
- logicalStorageGroupName + "-" + dataRegionId,
+ storageGroupName + "-" + dataRegionId,
e);
Thread.currentThread().interrupt();
}
@@ -1864,7 +1859,7 @@ public class DataRegion {
try {
logger.info(
"async force close all files in storage group: {}",
- logicalStorageGroupName + "-" + dataRegionId);
+ storageGroupName + "-" + dataRegionId);
// to avoid concurrent modification problem, we need a new array list
for (TsFileProcessor tsFileProcessor :
new ArrayList<>(workSequenceTsFileProcessors.values())) {
@@ -1885,8 +1880,7 @@ public class DataRegion {
writeLock("forceCloseAllWorkingTsFileProcessors");
try {
logger.info(
- "force close all processors in storage group: {}",
- logicalStorageGroupName + "-" + dataRegionId);
+ "force close all processors in storage group: {}", storageGroupName + "-" + dataRegionId);
// to avoid concurrent modification problem, we need a new array list
for (TsFileProcessor tsFileProcessor :
new ArrayList<>(workSequenceTsFileProcessors.values())) {
@@ -2277,7 +2271,7 @@ public class DataRegion {
if (timePartitionStartId <= entry.getKey()
&& entry.getKey() <= timePartitionEndId
&& (timePartitionFilter == null
- || timePartitionFilter.satisfy(logicalStorageGroupName, entry.getKey()))) {
+ || timePartitionFilter.satisfy(storageGroupName, entry.getKey()))) {
WALFlushListener walFlushListener = entry.getValue().logDeleteInWAL(deletionPlan);
walFlushListeners.add(walFlushListener);
}
@@ -2286,7 +2280,7 @@ public class DataRegion {
if (timePartitionStartId <= entry.getKey()
&& entry.getKey() <= timePartitionEndId
&& (timePartitionFilter == null
- || timePartitionFilter.satisfy(logicalStorageGroupName, entry.getKey()))) {
+ || timePartitionFilter.satisfy(storageGroupName, entry.getKey()))) {
WALFlushListener walFlushListener = entry.getValue().logDeleteInWAL(deletionPlan);
walFlushListeners.add(walFlushListener);
}
@@ -2301,8 +2295,7 @@ public class DataRegion {
long deleteEnd,
TimePartitionFilter timePartitionFilter) {
if (timePartitionFilter != null
- && !timePartitionFilter.satisfy(
- logicalStorageGroupName, tsFileResource.getTimePartition())) {
+ && !timePartitionFilter.satisfy(storageGroupName, tsFileResource.getTimePartition())) {
return true;
}
@@ -2479,8 +2472,7 @@ public class DataRegion {
closeStorageGroupCondition.notifyAll();
}
logger.info(
- "signal closing storage group condition in {}",
- logicalStorageGroupName + "-" + dataRegionId);
+ "signal closing storage group condition in {}", storageGroupName + "-" + dataRegionId);
}
private void executeCompaction() {
@@ -2992,7 +2984,7 @@ public class DataRegion {
targetFile =
fsFactory.getFile(
DirectoryManager.getInstance().getNextFolderForUnSequenceFile(),
- logicalStorageGroupName
+ storageGroupName
+ File.separatorChar
+ dataRegionId
+ File.separatorChar
@@ -3014,7 +3006,7 @@ public class DataRegion {
targetFile =
fsFactory.getFile(
DirectoryManager.getInstance().getNextFolderForSequenceFile(),
- logicalStorageGroupName
+ storageGroupName
+ File.separatorChar
+ dataRegionId
+ File.separatorChar
@@ -3270,7 +3262,7 @@ public class DataRegion {
* @return data region path, like root.sg1/0
*/
public String getStorageGroupPath() {
- return logicalStorageGroupName + File.separator + dataRegionId;
+ return storageGroupName + File.separator + dataRegionId;
}
public StorageGroupInfo getStorageGroupInfo() {
@@ -3366,8 +3358,7 @@ public class DataRegion {
public void abortCompaction() {
tsFileManager.setAllowCompaction(false);
List<AbstractCompactionTask> runningTasks =
- CompactionTaskManager.getInstance()
- .abortCompaction(logicalStorageGroupName + "-" + dataRegionId);
+ CompactionTaskManager.getInstance().abortCompaction(storageGroupName + "-" + dataRegionId);
while (CompactionTaskManager.getInstance().isAnyTaskInListStillRunning(runningTasks)) {
try {
TimeUnit.MILLISECONDS.sleep(10);
@@ -3388,7 +3379,7 @@ public class DataRegion {
Entry<Long, TsFileProcessor> longTsFileProcessorEntry = iterator.next();
long partitionId = longTsFileProcessorEntry.getKey();
TsFileProcessor processor = longTsFileProcessorEntry.getValue();
- if (filter.satisfy(logicalStorageGroupName, partitionId)) {
+ if (filter.satisfy(storageGroupName, partitionId)) {
processor.syncClose();
iterator.remove();
processor.getTsFileResource().remove();
@@ -3406,7 +3397,7 @@ public class DataRegion {
TimePartitionFilter filter, Iterator<TsFileResource> iterator, boolean sequence) {
while (iterator.hasNext()) {
TsFileResource tsFileResource = iterator.next();
- if (filter.satisfy(logicalStorageGroupName, tsFileResource.getTimePartition())) {
+ if (filter.satisfy(storageGroupName, tsFileResource.getTimePartition())) {
tsFileResource.remove();
tsFileManager.remove(tsFileResource, sequence);
updateLatestFlushTimeToPartition(tsFileResource.getTimePartition(), Long.MIN_VALUE);
@@ -3734,7 +3725,7 @@ public class DataRegion {
}
// identifier should be same with getTsFileProcessor method
return WALManager.getInstance()
- .applyForWALNode(logicalStorageGroupName + FILE_NAME_SEPARATOR + dataRegionId);
+ .applyForWALNode(storageGroupName + FILE_NAME_SEPARATOR + dataRegionId);
}
/** Wait for this data region successfully deleted */
diff --git a/server/src/main/java/org/apache/iotdb/db/engine/storagegroup/TsFileProcessorInfo.java b/server/src/main/java/org/apache/iotdb/db/engine/storagegroup/TsFileProcessorInfo.java
index 4eb8442697..4aafb030c8 100644
--- a/server/src/main/java/org/apache/iotdb/db/engine/storagegroup/TsFileProcessorInfo.java
+++ b/server/src/main/java/org/apache/iotdb/db/engine/storagegroup/TsFileProcessorInfo.java
@@ -47,7 +47,7 @@ public class TsFileProcessorInfo {
Metric.MEM.toString(),
MetricLevel.IMPORTANT,
Tag.NAME.toString(),
- "chunkMetaData_" + storageGroupInfo.getDataRegion().getLogicalStorageGroupName())
+ "chunkMetaData_" + storageGroupInfo.getDataRegion().getStorageGroupName())
.incr(cost);
}
}
@@ -61,7 +61,7 @@ public class TsFileProcessorInfo {
Metric.MEM.toString(),
MetricLevel.IMPORTANT,
Tag.NAME.toString(),
- "chunkMetaData_" + storageGroupInfo.getDataRegion().getLogicalStorageGroupName())
+ "chunkMetaData_" + storageGroupInfo.getDataRegion().getStorageGroupName())
.decr(cost);
}
@@ -73,7 +73,7 @@ public class TsFileProcessorInfo {
Metric.MEM.toString(),
MetricLevel.IMPORTANT,
Tag.NAME.toString(),
- "chunkMetaData_" + storageGroupInfo.getDataRegion().getLogicalStorageGroupName())
+ "chunkMetaData_" + storageGroupInfo.getDataRegion().getStorageGroupName())
.decr(memCost);
memCost = 0L;
}
diff --git a/server/src/main/java/org/apache/iotdb/db/engine/storagegroup/dataregion/StorageGroupManager.java b/server/src/main/java/org/apache/iotdb/db/engine/storagegroup/dataregion/StorageGroupManager.java
index 345c995332..375ae1f9a0 100644
--- a/server/src/main/java/org/apache/iotdb/db/engine/storagegroup/dataregion/StorageGroupManager.java
+++ b/server/src/main/java/org/apache/iotdb/db/engine/storagegroup/dataregion/StorageGroupManager.java
@@ -254,7 +254,7 @@ public class StorageGroupManager {
logger.info(
"{} closing sg processor is called for closing {}, seq = {}",
isSync ? "sync" : "async",
- processor.getDataRegionId() + "-" + processor.getLogicalStorageGroupName(),
+ processor.getDataRegionId() + "-" + processor.getStorageGroupName(),
isSeq);
}
@@ -293,7 +293,7 @@ public class StorageGroupManager {
if (processor != null) {
logger.info(
"async closing sg processor is called for closing {}, seq = {}, partitionId = {}",
- processor.getDataRegionId() + "-" + processor.getLogicalStorageGroupName(),
+ processor.getDataRegionId() + "-" + processor.getStorageGroupName(),
isSeq,
partitionId);
processor.writeLock("VirtualCloseStorageGroupProcessor-242");
diff --git a/server/src/main/java/org/apache/iotdb/db/rescon/SystemInfo.java b/server/src/main/java/org/apache/iotdb/db/rescon/SystemInfo.java
index 09e432bec2..88b639a82a 100644
--- a/server/src/main/java/org/apache/iotdb/db/rescon/SystemInfo.java
+++ b/server/src/main/java/org/apache/iotdb/db/rescon/SystemInfo.java
@@ -91,7 +91,7 @@ public class SystemInfo {
} else {
logger.info(
"Change system to reject status. Triggered by: logical SG ({}), mem cost delta ({}), totalSgMemCost ({}).",
- storageGroupInfo.getDataRegion().getLogicalStorageGroupName(),
+ storageGroupInfo.getDataRegion().getStorageGroupName(),
delta,
totalStorageGroupMemCost);
rejected = true;
@@ -131,13 +131,13 @@ public class SystemInfo {
&& totalStorageGroupMemCost < REJECT_THERSHOLD) {
logger.debug(
"SG ({}) released memory (delta: {}) but still exceeding flush proportion (totalSgMemCost: {}), call flush.",
- storageGroupInfo.getDataRegion().getLogicalStorageGroupName(),
+ storageGroupInfo.getDataRegion().getStorageGroupName(),
delta,
totalStorageGroupMemCost);
if (rejected) {
logger.info(
"SG ({}) released memory (delta: {}), set system to normal status (totalSgMemCost: {}).",
- storageGroupInfo.getDataRegion().getLogicalStorageGroupName(),
+ storageGroupInfo.getDataRegion().getStorageGroupName(),
delta,
totalStorageGroupMemCost);
}
@@ -146,7 +146,7 @@ public class SystemInfo {
} else if (totalStorageGroupMemCost >= REJECT_THERSHOLD) {
logger.warn(
"SG ({}) released memory (delta: {}), but system is still in reject status (totalSgMemCost: {}).",
- storageGroupInfo.getDataRegion().getLogicalStorageGroupName(),
+ storageGroupInfo.getDataRegion().getStorageGroupName(),
delta,
totalStorageGroupMemCost);
logCurrentTotalSGMemory();
@@ -154,7 +154,7 @@ public class SystemInfo {
} else {
logger.debug(
"SG ({}) released memory (delta: {}), system is in normal status (totalSgMemCost: {}).",
- storageGroupInfo.getDataRegion().getLogicalStorageGroupName(),
+ storageGroupInfo.getDataRegion().getStorageGroupName(),
delta,
totalStorageGroupMemCost);
logCurrentTotalSGMemory();
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
new file mode 100644
index 0000000000..804ed6ef94
--- /dev/null
+++ b/server/src/test/java/org/apache/iotdb/db/engine/snapshot/IoTDBSnapshotTest.java
@@ -0,0 +1,199 @@
+/*
+ * 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.iotdb.db.engine.snapshot;
+
+import org.apache.iotdb.commons.utils.FileUtils;
+import org.apache.iotdb.db.conf.IoTDBDescriptor;
+import org.apache.iotdb.db.conf.directories.DirectoryManager;
+import org.apache.iotdb.db.engine.snapshot.exception.DirectoryNotLegalException;
+import org.apache.iotdb.db.engine.storagegroup.DataRegion;
+import org.apache.iotdb.db.engine.storagegroup.TsFileResource;
+import org.apache.iotdb.db.engine.storagegroup.TsFileResourceStatus;
+import org.apache.iotdb.db.exception.DataRegionException;
+import org.apache.iotdb.db.exception.StorageEngineException;
+import org.apache.iotdb.db.utils.EnvironmentUtils;
+import org.apache.iotdb.tsfile.exception.write.WriteProcessException;
+import org.apache.iotdb.tsfile.utils.TsFileGeneratorUtils;
+
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import static org.apache.iotdb.tsfile.common.constant.TsFileConstant.PATH_SEPARATOR;
+
+public class IoTDBSnapshotTest {
+ private String[] testDataDirs =
+ new String[] {"target/data/data1", "target/data/data2", "target/data/data3"};
+ private String testSgName = "root.testsg";
+
+ @Before
+ public void setUp() throws Exception {
+ EnvironmentUtils.envSetUp();
+ }
+
+ @After
+ public void tearDown() throws IOException, StorageEngineException {
+ FileUtils.recursiveDeleteFolder("target" + File.separator + "data");
+ EnvironmentUtils.cleanEnv();
+ FileUtils.recursiveDeleteFolder("target" + File.separator + "tmp");
+ }
+
+ private List<TsFileResource> writeTsFiles() throws IOException, WriteProcessException {
+ List<TsFileResource> resources = new ArrayList<>();
+ for (int i = 0; i < 100; i++) {
+ String filePath =
+ testDataDirs[i % 3]
+ + File.separator
+ + "sequence"
+ + File.separator
+ + testSgName
+ + File.separator
+ + "0"
+ + File.separator
+ + "0"
+ + File.separator
+ + String.format("%d-%d-0-0.tsfile", i + 1, i + 1);
+ TsFileGeneratorUtils.generateMixTsFile(filePath, 5, 5, 10, i * 100, (i + 1) * 100, 10, 10);
+ TsFileResource resource = new TsFileResource(new File(filePath));
+ resources.add(resource);
+ for (int idx = 0; idx < 5; idx++) {
+ resource.updateStartTime(testSgName + PATH_SEPARATOR + "d" + i, i * 100);
+ resource.updateEndTime(testSgName + PATH_SEPARATOR + "d" + i, (i + 1) * 100);
+ }
+ resource.updatePlanIndexes(i);
+ resource.setStatus(TsFileResourceStatus.CLOSED);
+ resource.serialize();
+ }
+ return resources;
+ }
+
+ @Test
+ public void testCreateSnapshot()
+ throws IOException, WriteProcessException, DataRegionException, DirectoryNotLegalException {
+ String[] originDataDirs = IoTDBDescriptor.getInstance().getConfig().getDataDirs();
+ IoTDBDescriptor.getInstance().getConfig().setDataDirs(testDataDirs);
+ DirectoryManager.getInstance().resetFolders();
+ try {
+ List<TsFileResource> resources = writeTsFiles();
+ DataRegion region = new DataRegion(testSgName, "0");
+ region.getTsFileManager().addAll(resources, true);
+ File snapshotDir = new File("target" + File.separator + "snapshot");
+ Assert.assertTrue(snapshotDir.exists() || snapshotDir.mkdirs());
+ try {
+ new SnapshotTaker(region).takeFullSnapshot(snapshotDir.getAbsolutePath(), true);
+ File[] files =
+ snapshotDir.listFiles((dir, name) -> name.equals(SnapshotLogger.SNAPSHOT_LOG_NAME));
+ Assert.assertEquals(1, files.length);
+ SnapshotLogAnalyzer analyzer = new SnapshotLogAnalyzer(files[0]);
+ int cnt = 0;
+ while (analyzer.hasNext()) {
+ analyzer.getNextPairs();
+ cnt++;
+ }
+ analyzer.close();
+ Assert.assertEquals(200, cnt);
+ for (TsFileResource resource : resources) {
+ Assert.assertTrue(resource.tryWriteLock());
+ }
+ } finally {
+ FileUtils.recursiveDeleteFolder(snapshotDir.getAbsolutePath());
+ }
+ } finally {
+ IoTDBDescriptor.getInstance().getConfig().setDataDirs(originDataDirs);
+ DirectoryManager.getInstance().resetFolders();
+ }
+ }
+
+ @Test
+ public void testLoadSnapshot()
+ throws IOException, WriteProcessException, DataRegionException, DirectoryNotLegalException {
+ String[] originDataDirs = IoTDBDescriptor.getInstance().getConfig().getDataDirs();
+ IoTDBDescriptor.getInstance().getConfig().setDataDirs(testDataDirs);
+ DirectoryManager.getInstance().resetFolders();
+ try {
+ List<TsFileResource> resources = writeTsFiles();
+ DataRegion region = new DataRegion(testSgName, "0");
+ region.getTsFileManager().addAll(resources, true);
+ File snapshotDir = new File("target" + File.separator + "snapshot");
+ Assert.assertTrue(snapshotDir.exists() || snapshotDir.mkdirs());
+ try {
+ Assert.assertTrue(
+ new SnapshotTaker(region).takeFullSnapshot(snapshotDir.getAbsolutePath(), true));
+ DataRegion dataRegion =
+ new SnapshotLoader(snapshotDir.getAbsolutePath(), testSgName, "0")
+ .loadSnapshotForStateMachine();
+ Assert.assertNotNull(dataRegion);
+ List<TsFileResource> resource = dataRegion.getTsFileManager().getTsFileList(true);
+ Assert.assertEquals(100, resource.size());
+ } finally {
+ FileUtils.recursiveDeleteFolder(snapshotDir.getAbsolutePath());
+ }
+ } finally {
+ IoTDBDescriptor.getInstance().getConfig().setDataDirs(originDataDirs);
+ DirectoryManager.getInstance().resetFolders();
+ }
+ }
+
+ @Test
+ public void testGetSnapshotFile() throws IOException {
+ File tsFile =
+ new File(
+ IoTDBDescriptor.getInstance().getConfig().getDataDirs()[0]
+ + File.separator
+ + "sequence"
+ + File.separator
+ + "root.test"
+ + File.separator
+ + "0"
+ + File.separator
+ + "0"
+ + File.separator
+ + "1-1-0-0.tsfile");
+ File snapshotFile =
+ new SnapshotTaker(null).getSnapshotFilePathForTsFile(tsFile, "test-snapshotId");
+ Assert.assertEquals(
+ new File(
+ IoTDBDescriptor.getInstance().getConfig().getDataDirs()[0]
+ + File.separator
+ + "snapshot"
+ + File.separator
+ + "test-snapshotId"
+ + File.separator
+ + "sequence"
+ + File.separator
+ + "root.test"
+ + File.separator
+ + "0"
+ + File.separator
+ + "0"
+ + File.separator
+ + "1-1-0-0.tsfile")
+ .getAbsolutePath(),
+ snapshotFile.getAbsolutePath());
+
+ Assert.assertTrue(snapshotFile.getParentFile().exists());
+ }
+}
diff --git a/server/src/test/java/org/apache/iotdb/db/utils/EnvironmentUtils.java b/server/src/test/java/org/apache/iotdb/db/utils/EnvironmentUtils.java
index e1b7afac89..df70dcd56b 100644
--- a/server/src/test/java/org/apache/iotdb/db/utils/EnvironmentUtils.java
+++ b/server/src/test/java/org/apache/iotdb/db/utils/EnvironmentUtils.java
@@ -395,4 +395,21 @@ public class EnvironmentUtils {
File file = new File(dir);
file.mkdirs();
}
+
+ public static void recursiveDeleteFolder(String path) throws IOException {
+ File file = new File(path);
+ if (file.isDirectory()) {
+ File[] files = file.listFiles();
+ if (files == null || files.length == 0) {
+ FileUtils.deleteDirectory(file);
+ } else {
+ for (File f : files) {
+ recursiveDeleteFolder(f.getAbsolutePath());
+ }
+ FileUtils.deleteDirectory(file);
+ }
+ } else {
+ FileUtils.delete(file);
+ }
+ }
}
diff --git a/tsfile/src/main/java/org/apache/iotdb/tsfile/utils/TsFileGeneratorUtils.java b/tsfile/src/main/java/org/apache/iotdb/tsfile/utils/TsFileGeneratorUtils.java
index 7669cece20..919851ef76 100644
--- a/tsfile/src/main/java/org/apache/iotdb/tsfile/utils/TsFileGeneratorUtils.java
+++ b/tsfile/src/main/java/org/apache/iotdb/tsfile/utils/TsFileGeneratorUtils.java
@@ -128,57 +128,65 @@ public class TsFileGeneratorUtils {
if (file.exists()) {
file.delete();
}
- if (chunkGroupSize > 0)
- TSFileDescriptor.getInstance().getConfig().setGroupSizeInByte(chunkGroupSize);
- if (pageSize > 0)
- TSFileDescriptor.getInstance().getConfig().setMaxNumberOfPointsInPage(pageSize);
- try (TsFileWriter tsFileWriter = new TsFileWriter(file)) {
- // register align timeseries
- List<MeasurementSchema> alignedMeasurementSchemas = new ArrayList<>();
- for (int i = 0; i < measurementNum; i++) {
- alignedMeasurementSchemas.add(
- new MeasurementSchema("s" + i, TSDataType.INT64, TSEncoding.PLAIN));
- }
- for (int i = alignDeviceOffset; i < alignDeviceOffset + deviceNum; i++) {
- tsFileWriter.registerAlignedTimeseries(
- new Path(testStorageGroup + PATH_SEPARATOR + "d" + i), alignedMeasurementSchemas);
- }
+ int originGroupSize = TSFileDescriptor.getInstance().getConfig().getGroupSizeInByte();
+ int originPageSize = TSFileDescriptor.getInstance().getConfig().getMaxNumberOfPointsInPage();
+ try {
+ if (chunkGroupSize > 0)
+ TSFileDescriptor.getInstance().getConfig().setGroupSizeInByte(chunkGroupSize);
+ if (pageSize > 0)
+ TSFileDescriptor.getInstance().getConfig().setMaxNumberOfPointsInPage(pageSize);
+ try (TsFileWriter tsFileWriter = new TsFileWriter(file)) {
+ // register align timeseries
+ List<MeasurementSchema> alignedMeasurementSchemas = new ArrayList<>();
+ for (int i = 0; i < measurementNum; i++) {
+ alignedMeasurementSchemas.add(
+ new MeasurementSchema("s" + i, TSDataType.INT64, TSEncoding.PLAIN));
+ }
+ for (int i = alignDeviceOffset; i < alignDeviceOffset + deviceNum; i++) {
+ tsFileWriter.registerAlignedTimeseries(
+ new Path(testStorageGroup + PATH_SEPARATOR + "d" + i), alignedMeasurementSchemas);
+ }
- // write with record
- for (int i = alignDeviceOffset; i < alignDeviceOffset + deviceNum; i++) {
- writeWithTsRecord(
- tsFileWriter,
- testStorageGroup + PATH_SEPARATOR + "d" + i,
- alignedMeasurementSchemas,
- pointNum,
- startTime,
- startValue,
- true);
- }
+ // write with record
+ for (int i = alignDeviceOffset; i < alignDeviceOffset + deviceNum; i++) {
+ writeWithTsRecord(
+ tsFileWriter,
+ testStorageGroup + PATH_SEPARATOR + "d" + i,
+ alignedMeasurementSchemas,
+ pointNum,
+ startTime,
+ startValue,
+ true);
+ }
- // register nonAlign timeseries
- List<MeasurementSchema> measurementSchemas = new ArrayList<>();
- for (int i = 0; i < measurementNum; i++) {
- measurementSchemas.add(new MeasurementSchema("s" + i, TSDataType.INT64, TSEncoding.PLAIN));
- }
- for (int i = 0; i < deviceNum; i++) {
- tsFileWriter.registerTimeseries(
- new Path(testStorageGroup + PATH_SEPARATOR + "d" + i), measurementSchemas);
- }
+ // register nonAlign timeseries
+ List<MeasurementSchema> measurementSchemas = new ArrayList<>();
+ for (int i = 0; i < measurementNum; i++) {
+ measurementSchemas.add(
+ new MeasurementSchema("s" + i, TSDataType.INT64, TSEncoding.PLAIN));
+ }
+ for (int i = 0; i < deviceNum; i++) {
+ tsFileWriter.registerTimeseries(
+ new Path(testStorageGroup + PATH_SEPARATOR + "d" + i), measurementSchemas);
+ }
- // write with record
- for (int i = 0; i < deviceNum; i++) {
- writeWithTsRecord(
- tsFileWriter,
- testStorageGroup + PATH_SEPARATOR + "d" + i,
- measurementSchemas,
- pointNum,
- startTime,
- startValue,
- false);
+ // write with record
+ for (int i = 0; i < deviceNum; i++) {
+ writeWithTsRecord(
+ tsFileWriter,
+ testStorageGroup + PATH_SEPARATOR + "d" + i,
+ measurementSchemas,
+ pointNum,
+ startTime,
+ startValue,
+ false);
+ }
}
+ return file;
+ } finally {
+ TSFileDescriptor.getInstance().getConfig().setGroupSizeInByte(originGroupSize);
+ TSFileDescriptor.getInstance().getConfig().setMaxNumberOfPointsInPage(originPageSize);
}
- return file;
}
public static File generateAlignedTsFile(