Skip to content

Commit 07b9cb0

Browse files
authored
Fix empty snapshot loading and region cleanup (#17880)
1 parent c3e74a2 commit 07b9cb0

7 files changed

Lines changed: 115 additions & 42 deletions

File tree

integration-test/src/test/java/org/apache/iotdb/db/it/IoTDBMiscIT.java

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -55,46 +55,46 @@ public void testCompressionRatioFile() throws SQLException {
5555
Statement statement = connection.createStatement()) {
5656
statement.execute("insert into root.comprssion_ratio_file.d1(timestamp,s1) values(1,1.0)");
5757
statement.execute("flush");
58-
// one global file and two data region file (including one AUDIT region)
58+
// one global file and one data region file
5959
assertEquals(2, collectCompressionRatioFiles(nodeWrapper).size());
6060

6161
statement.execute("drop database root.comprssion_ratio_file");
62-
// one global file and system region file
62+
// one global file
6363
// deleting a file may not be sensed by other processes instantly
6464
Awaitility.await()
6565
.atMost(10, TimeUnit.SECONDS)
6666
.pollDelay(100, TimeUnit.MILLISECONDS)
67-
.until(() -> collectCompressionRatioFiles(nodeWrapper).size() == 2);
67+
.until(() -> collectCompressionRatioFiles(nodeWrapper).size() == 1);
6868

6969
statement.execute("insert into root.comprssion_ratio_file.d1(timestamp,s1) values(1,1.0)");
7070
statement.execute("flush");
71-
assertEquals(3, collectCompressionRatioFiles(nodeWrapper).size());
71+
assertEquals(2, collectCompressionRatioFiles(nodeWrapper).size());
7272

7373
statement.execute("drop database root.comprssion_ratio_file");
7474
Awaitility.await()
7575
.atMost(10, TimeUnit.SECONDS)
7676
.pollDelay(100, TimeUnit.MILLISECONDS)
77-
.until(() -> collectCompressionRatioFiles(nodeWrapper).size() == 2);
77+
.until(() -> collectCompressionRatioFiles(nodeWrapper).size() == 1);
7878

7979
statement.execute("insert into root.comprssion_ratio_file.d1(timestamp,s1) values(1,1.0)");
8080
statement.execute("flush");
81-
assertEquals(3, collectCompressionRatioFiles(nodeWrapper).size());
81+
assertEquals(2, collectCompressionRatioFiles(nodeWrapper).size());
8282

8383
statement.execute("insert into root.comprssion_ratio_file_2.d1(timestamp,s1) values(1,1.0)");
8484
statement.execute("flush");
85-
assertEquals(4, collectCompressionRatioFiles(nodeWrapper).size());
85+
assertEquals(3, collectCompressionRatioFiles(nodeWrapper).size());
8686

8787
statement.execute("drop database root.comprssion_ratio_file");
8888
Awaitility.await()
8989
.atMost(10, TimeUnit.SECONDS)
9090
.pollDelay(100, TimeUnit.MILLISECONDS)
91-
.until(() -> collectCompressionRatioFiles(nodeWrapper).size() == 3);
91+
.until(() -> collectCompressionRatioFiles(nodeWrapper).size() == 2);
9292

9393
statement.execute("drop database root.comprssion_ratio_file_2");
9494
Awaitility.await()
9595
.atMost(10, TimeUnit.SECONDS)
9696
.pollDelay(100, TimeUnit.MILLISECONDS)
97-
.until(() -> collectCompressionRatioFiles(nodeWrapper).size() == 2);
97+
.until(() -> collectCompressionRatioFiles(nodeWrapper).size() == 1);
9898
} finally {
9999
simpleEnv.cleanClusterEnvironment();
100100
}

iotdb-core/datanode/src/main/i18n/en/org/apache/iotdb/db/i18n/StorageEngineMessages.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -359,10 +359,26 @@ private StorageEngineMessages() {}
359359
// ======================== Snapshot ========================
360360

361361
public static final String EXCEPTION_LOAD_SNAPSHOT = "Exception occurs while load snapshot from {}";
362+
public static final String LOADING_SNAPSHOT_FOR = "Loading snapshot for {}-{}, source directory is {}";
363+
public static final String EXCEPTION_LOADING_SNAPSHOT_FOR = "Exception occurs when loading snapshot for {}-{}";
362364
public static final String READING_SNAPSHOT_LOG_FILE = "Reading snapshot log file {}";
363365
public static final String REMOVE_ALL_DATA_FILES_IN_ORIGINAL_DIR = "Remove all data files in original data dir";
364366
public static final String FAILED_TO_REMOVE_ORIGIN_DATA_FILES = "Failed to remove origin data files";
365367
public static final String MOVING_SNAPSHOT_FILE_TO_DATA_DIRS = "Moving snapshot file to data dirs";
368+
public static final String CANNOT_FIND_SNAPSHOT_DIRECTORY = "Cannot find snapshot directory %s";
369+
public static final String NO_SEQ_OR_UNSEQ_FILES_IN_SNAPSHOT =
370+
"No seq or unseq files in snapshot {}, skip creating file links";
371+
public static final String EXCEPTION_DELETING_TIME_PARTITION_DIR =
372+
"Exception occurs when deleting time partition directory for {}-{}";
373+
public static final String CANNOT_CREATE_LINK_FALLBACK_COPY =
374+
"Cannot create link from {} to {}, fallback to copy";
375+
public static final String FAILED_TO_PROCESS_SNAPSHOT_FILE =
376+
"Failed to process file {} in dir {}: {}";
377+
public static final String FAILED_TO_PROCESS_SNAPSHOT_FILE_AFTER_RETRIES =
378+
"Failed to process file after retries. Source: %s, Target suffix: %s";
379+
public static final String SNAPSHOT_FILE_NUM_MISMATCH =
380+
"The file num in log is %d, while file num in disk is %d";
381+
public static final String SNAPSHOT_FILE_NOT_IN_LOG = "File %s is not in the log file list";
366382
public static final String NO_COMPRESSION_RATIO_FILE_IN_DIR = "No compression ratio file in dir {}";
367383
public static final String CANNOT_LOAD_COMPRESSION_RATIO = "Cannot load compression ratio from {}";
368384
public static final String LOADED_COMPRESSION_RATIO = "Loaded compression ratio from {}";

iotdb-core/datanode/src/main/i18n/zh/org/apache/iotdb/db/i18n/StorageEngineMessages.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -359,10 +359,26 @@ private StorageEngineMessages() {}
359359
// ======================== Snapshot ========================
360360

361361
public static final String EXCEPTION_LOAD_SNAPSHOT = "从 {} 加载快照时发生异常";
362+
public static final String LOADING_SNAPSHOT_FOR = "正在为 {}-{} 加载快照,源目录为 {}";
363+
public static final String EXCEPTION_LOADING_SNAPSHOT_FOR = "为 {}-{} 加载快照时发生异常";
362364
public static final String READING_SNAPSHOT_LOG_FILE = "正在读取快照日志文件 {}";
363365
public static final String REMOVE_ALL_DATA_FILES_IN_ORIGINAL_DIR = "移除原始数据目录中的所有数据文件";
364366
public static final String FAILED_TO_REMOVE_ORIGIN_DATA_FILES = "移除原始数据文件失败";
365367
public static final String MOVING_SNAPSHOT_FILE_TO_DATA_DIRS = "正在将快照文件移动到数据目录";
368+
public static final String CANNOT_FIND_SNAPSHOT_DIRECTORY = "找不到快照目录 %s";
369+
public static final String NO_SEQ_OR_UNSEQ_FILES_IN_SNAPSHOT =
370+
"快照 {} 中没有顺序或乱序文件,跳过创建文件链接";
371+
public static final String EXCEPTION_DELETING_TIME_PARTITION_DIR =
372+
"删除 {}-{} 的时间分区目录时发生异常";
373+
public static final String CANNOT_CREATE_LINK_FALLBACK_COPY =
374+
"无法创建从 {} 到 {} 的链接,回退为复制";
375+
public static final String FAILED_TO_PROCESS_SNAPSHOT_FILE =
376+
"处理文件 {} 失败,所在目录为 {}: {}";
377+
public static final String FAILED_TO_PROCESS_SNAPSHOT_FILE_AFTER_RETRIES =
378+
"重试后仍无法处理文件。源文件: %s,目标后缀: %s";
379+
public static final String SNAPSHOT_FILE_NUM_MISMATCH =
380+
"日志中的文件数为 %d,但磁盘中的文件数为 %d";
381+
public static final String SNAPSHOT_FILE_NOT_IN_LOG = "文件 %s 不在日志文件列表中";
366382
public static final String NO_COMPRESSION_RATIO_FILE_IN_DIR = "目录 {} 中没有压缩率文件";
367383
public static final String CANNOT_LOAD_COMPRESSION_RATIO = "无法从 {} 加载压缩率";
368384
public static final String LOADED_COMPRESSION_RATIO = "已从 {} 加载压缩率";

iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/DataRegion.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2219,7 +2219,9 @@ public void deleteFolder(String systemDir) {
22192219
databaseName + "-" + dataRegionIdString,
22202220
systemDir);
22212221
int regionId = dataRegionId.getId();
2222-
TableDiskUsageIndex.getInstance().remove(databaseName, regionId);
2222+
if (isTableModel) {
2223+
TableDiskUsageIndex.getInstance().remove(databaseName, regionId);
2224+
}
22232225
FileTimeIndexCacheRecorder.getInstance().removeFileTimeIndexCache(regionId);
22242226
writeLock("deleteFolder");
22252227
try {

iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/snapshot/SnapshotLoader.java

Lines changed: 26 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -99,10 +99,7 @@ private File getSnapshotLogFile() {
9999
*/
100100
public DataRegion loadSnapshotForStateMachine() {
101101
LOGGER.info(
102-
"Loading snapshot for {}-{}, source directory is {}",
103-
storageGroupName,
104-
dataRegionId,
105-
snapshotPath);
102+
StorageEngineMessages.LOADING_SNAPSHOT_FOR, storageGroupName, dataRegionId, snapshotPath);
106103

107104
File snapshotLogFile = getSnapshotLogFile();
108105

@@ -129,7 +126,7 @@ private DataRegion loadSnapshotWithoutLog() {
129126
return loadSnapshot();
130127
} catch (IOException | DiskSpaceInsufficientException e) {
131128
LOGGER.error(
132-
"Exception occurs when loading snapshot for {}-{}", storageGroupName, dataRegionId, e);
129+
StorageEngineMessages.EXCEPTION_LOADING_SNAPSHOT_FOR, storageGroupName, dataRegionId, e);
133130
return null;
134131
}
135132
}
@@ -240,7 +237,7 @@ private void deleteAllFilesInDataDirs() throws IOException {
240237
}
241238
} catch (IOException e) {
242239
LOGGER.error(
243-
"Exception occurs when deleting time partition directory for {}-{}",
240+
StorageEngineMessages.EXCEPTION_DELETING_TIME_PARTITION_DIR,
244241
storageGroupName,
245242
dataRegionId,
246243
e);
@@ -250,6 +247,11 @@ private void deleteAllFilesInDataDirs() throws IOException {
250247

251248
private void createLinksFromSnapshotDirToDataDirWithoutLog(File sourceDir)
252249
throws IOException, DiskSpaceInsufficientException {
250+
if (!sourceDir.exists()) {
251+
throw new IOException(
252+
String.format(
253+
StorageEngineMessages.CANNOT_FIND_SNAPSHOT_DIRECTORY, sourceDir.getAbsolutePath()));
254+
}
253255
File seqFileDir =
254256
new File(
255257
sourceDir,
@@ -267,10 +269,8 @@ private void createLinksFromSnapshotDirToDataDirWithoutLog(File sourceDir)
267269
+ File.separator
268270
+ dataRegionId);
269271
if (!seqFileDir.exists() && !unseqFileDir.exists()) {
270-
throw new IOException(
271-
String.format(
272-
"Cannot find %s or %s",
273-
seqFileDir.getAbsolutePath(), unseqFileDir.getAbsolutePath()));
272+
LOGGER.warn(StorageEngineMessages.NO_SEQ_OR_UNSEQ_FILES_IN_SNAPSHOT, sourceDir);
273+
return;
274274
}
275275
FolderManager folderManager =
276276
new FolderManager(
@@ -329,24 +329,29 @@ private File createLinksFromSnapshotToSourceDir(
329329
if (!targetFile.getParentFile().exists() && !targetFile.getParentFile().mkdirs()) {
330330
throw new IOException(
331331
String.format(
332-
"Cannot create directory %s", targetFile.getParentFile().getAbsolutePath()));
332+
StorageEngineMessages.FAILED_TO_CREATE_DIR,
333+
targetFile.getParentFile().getAbsolutePath()));
333334
}
334335

335336
try {
336337
Files.createLink(targetFile.toPath(), file.toPath());
337-
LOGGER.debug("Created hard link from {} to {}", file, targetFile);
338+
LOGGER.debug(StorageEngineMessages.CREATED_HARD_LINK, file, targetFile);
338339
fileTarget.put(fileKey, finalDir);
339340
return targetFile;
340341
} catch (IOException e) {
341-
LOGGER.info("Cannot create link from {} to {}, fallback to copy", file, targetFile);
342+
LOGGER.info(StorageEngineMessages.CANNOT_CREATE_LINK_FALLBACK_COPY, file, targetFile);
342343
}
343344

344345
Files.copy(file.toPath(), targetFile.toPath());
345346
fileTarget.put(fileKey, finalDir);
346347
return targetFile;
347348
} catch (Exception e) {
348349
LOGGER.warn(
349-
"Failed to process file {} in dir {}: {}", file.getName(), finalDir, e.getMessage(), e);
350+
StorageEngineMessages.FAILED_TO_PROCESS_SNAPSHOT_FILE,
351+
file.getName(),
352+
finalDir,
353+
e.getMessage(),
354+
e);
350355
throw e;
351356
}
352357
}
@@ -381,8 +386,9 @@ private void createLinksFromSnapshotToSourceDir(
381386
} catch (Exception e) {
382387
throw new IOException(
383388
String.format(
384-
"Failed to process file after retries. Source: %s, Target suffix: %s",
385-
file.getAbsolutePath(), targetSuffix),
389+
StorageEngineMessages.FAILED_TO_PROCESS_SNAPSHOT_FILE_AFTER_RETRIES,
390+
file.getAbsolutePath(),
391+
targetSuffix),
386392
e);
387393
}
388394
}
@@ -409,8 +415,7 @@ private void createLinksFromSnapshotDirToDataDirWithLog() throws IOException {
409415
}
410416
if (fileCnt != loggedFileNum) {
411417
throw new IOException(
412-
String.format(
413-
"The file num in log is %d, while file num in disk is %d", loggedFileNum, fileCnt));
418+
String.format(StorageEngineMessages.SNAPSHOT_FILE_NUM_MISMATCH, loggedFileNum, fileCnt));
414419
}
415420
}
416421

@@ -492,13 +497,14 @@ private void createLinksFromSourceToTarget(File targetDir, File[] files, Set<Str
492497
String infoStr = getFileInfoString(file);
493498
if (!fileInfoSet.contains(infoStr)) {
494499
throw new IOException(
495-
String.format("File %s is not in the log file list", file.getAbsolutePath()));
500+
String.format(StorageEngineMessages.SNAPSHOT_FILE_NOT_IN_LOG, file.getAbsolutePath()));
496501
}
497502
File targetFile = new File(targetDir, file.getName());
498503
if (!targetFile.getParentFile().exists() && !targetFile.getParentFile().mkdirs()) {
499504
throw new IOException(
500505
String.format(
501-
"Cannot create directory %s", targetFile.getParentFile().getAbsolutePath()));
506+
StorageEngineMessages.FAILED_TO_CREATE_DIR,
507+
targetFile.getParentFile().getAbsolutePath()));
502508
}
503509
Files.createLink(targetFile.toPath(), file.toPath());
504510
}

iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/utils/tableDiskUsageIndex/TableDiskUsageIndex.java

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -443,18 +443,25 @@ private RemoveRegionOperation(String database, int regionId) {
443443

444444
@Override
445445
public void apply(TableDiskUsageIndex tableDiskUsageIndex) {
446-
tableDiskUsageIndex.writerMap.computeIfPresent(
447-
regionId,
448-
(k, writer) -> {
449-
if (writer.getActiveReaderNum() > 0) {
450-
// If there are active readers, defer removal until all readers finish
451-
writer.setRemovedFuture(future);
452-
return writer;
453-
}
454-
writer.close();
455-
future.complete(null);
456-
return null;
457-
});
446+
DataRegionTableSizeIndexWriter removedWriter = null;
447+
try {
448+
removedWriter =
449+
tableDiskUsageIndex.writerMap.computeIfPresent(
450+
regionId,
451+
(k, writer) -> {
452+
if (writer.getActiveReaderNum() > 0) {
453+
// If there are active readers, defer removal until all readers finish
454+
writer.setRemovedFuture(future);
455+
return writer;
456+
}
457+
writer.close();
458+
return null;
459+
});
460+
} finally {
461+
if (removedWriter == null) {
462+
future.complete(null);
463+
}
464+
}
458465
}
459466
}
460467

iotdb-core/datanode/src/test/java/org/apache/iotdb/db/storageengine/dataregion/snapshot/IoTDBSnapshotTest.java

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,32 @@ public void testCreateSnapshotWithUnclosedTsFile()
183183
}
184184
}
185185

186+
@Test
187+
public void testLoadEmptySnapshotWithoutLog() throws IOException {
188+
String[][] originDataDirs = IoTDBDescriptor.getInstance().getConfig().getTierDataDirs();
189+
IoTDBDescriptor.getInstance().getConfig().setTierDataDirs(testDataDirs);
190+
TierManager.getInstance().resetFolders();
191+
File snapshotDir = new File("target" + File.separator + "empty-snapshot");
192+
try {
193+
if (snapshotDir.exists()) {
194+
FileUtils.recursivelyDeleteFolder(snapshotDir.getAbsolutePath());
195+
}
196+
Assert.assertTrue(snapshotDir.mkdirs());
197+
198+
DataRegion dataRegion =
199+
new SnapshotLoader(snapshotDir.getAbsolutePath(), testSgName, "0")
200+
.loadSnapshotForStateMachine();
201+
202+
Assert.assertNotNull(dataRegion);
203+
assertEquals(0, dataRegion.getTsFileManager().getTsFileList(true).size());
204+
assertEquals(0, dataRegion.getTsFileManager().getTsFileList(false).size());
205+
} finally {
206+
FileUtils.recursivelyDeleteFolder(snapshotDir.getAbsolutePath());
207+
IoTDBDescriptor.getInstance().getConfig().setTierDataDirs(originDataDirs);
208+
TierManager.getInstance().resetFolders();
209+
}
210+
}
211+
186212
@Test
187213
public void testLoadSnapshot()
188214
throws IOException, WriteProcessException, DataRegionException, DirectoryNotLegalException {

0 commit comments

Comments
 (0)