blob: fcde9a63d544eba81aa174dd174a9fd345d6cee0 [file] [log] [blame]
/*
* 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.storageengine.dataregion.compaction.execute.exception;
import org.apache.iotdb.commons.conf.IoTDBConstant;
import org.apache.iotdb.db.storageengine.dataregion.compaction.execute.utils.CompactionUtils;
import org.apache.iotdb.db.storageengine.dataregion.tsfile.TsFileManager;
import org.apache.iotdb.db.storageengine.dataregion.tsfile.TsFileResource;
import org.apache.iotdb.db.storageengine.dataregion.tsfile.TsFileResourceList;
import org.apache.iotdb.db.storageengine.dataregion.tsfile.TsFileResourceStatus;
import org.apache.iotdb.db.storageengine.rescon.memory.TsFileResourceManager;
import org.apache.commons.io.FileUtils;
import org.apache.tsfile.utils.TsFileUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
public class CompactionExceptionHandler {
private static final Logger LOGGER =
LoggerFactory.getLogger(IoTDBConstant.COMPACTION_LOGGER_NAME);
private CompactionExceptionHandler() {}
@SuppressWarnings("squid:S107")
public static void handleException(
String fullStorageGroupName,
File logFile,
List<TsFileResource> targetResourceList,
List<TsFileResource> seqResourceList,
List<TsFileResource> unseqResourceList,
TsFileManager tsFileManager,
long timePartition,
boolean isInnerSpace,
boolean isTargetSequence) {
String compactionType = isInnerSpace ? "inner" : "cross";
try {
if (logFile == null || !logFile.exists()) {
// the log file is null or the log file does not exists
// it means that compaction has not started yet
// we don't need to handle it
return;
}
LOGGER.info(
"{} [Compaction][ExceptionHandler] {} space compaction start handling exception, "
+ "source seqFiles is {}, "
+ "source unseqFiles is {}.",
fullStorageGroupName,
compactionType,
seqResourceList,
unseqResourceList);
boolean handleSuccess = true;
List<TsFileResource> lostSourceFiles = new ArrayList<>();
boolean allSourceSeqFilesExist = checkAllSourceFileExists(seqResourceList, lostSourceFiles);
boolean allSourceUnseqFilesExist =
checkAllSourceFileExists(unseqResourceList, lostSourceFiles);
if (allSourceSeqFilesExist && allSourceUnseqFilesExist) {
handleSuccess =
handleWhenAllSourceFilesExist(
targetResourceList,
seqResourceList,
unseqResourceList,
tsFileManager,
timePartition,
isTargetSequence,
fullStorageGroupName);
} else {
handleSuccess =
handleWhenSomeSourceFilesLost(
targetResourceList,
seqResourceList,
unseqResourceList,
lostSourceFiles,
fullStorageGroupName);
}
if (!handleSuccess) {
LOGGER.error(
"[Compaction][ExceptionHandler] Fail to handle {} space compaction exception, "
+ "storage group is {}",
compactionType,
fullStorageGroupName);
} else {
FileUtils.delete(logFile);
}
} catch (IOException e) {
// catch throwable when handling exception
LOGGER.error(
"[Compaction][ExceptionHandler] exception occurs when handling exception in {} space compaction. "
+ "storage group is {}",
compactionType,
fullStorageGroupName);
}
}
private static boolean checkAllSourceFileExists(
List<TsFileResource> tsFileResources, List<TsFileResource> lostFiles) {
for (TsFileResource tsFileResource : tsFileResources) {
if (!tsFileResource.getTsFile().exists() || !tsFileResource.resourceFileExists()) {
lostFiles.add(tsFileResource);
}
}
return lostFiles.isEmpty();
}
/**
* When all source files exists: (1) delete compaction mods files (2) delete target files, tmp
* target files and its corresponding files (3) recover memory. To avoid triggering OOM again
* under OOM errors, we do not check whether the target files are complete.
*
* @throws IOException if the deletion of compaction mods file failed or tsfile name is incorrect
*/
@SuppressWarnings("squid:S3776")
private static boolean handleWhenAllSourceFilesExist(
List<TsFileResource> targetResourceList,
List<TsFileResource> sourceSeqResourceList,
List<TsFileResource> sourceUnseqResourceList,
TsFileManager tsFileManager,
long timePartition,
boolean isTargetSequence,
String fullStorageGroupName)
throws IOException {
TsFileResourceList unseqTsFileResourceList =
tsFileManager.getOrCreateUnsequenceListByTimePartition(timePartition);
TsFileResourceList seqTsFileResourceList =
tsFileManager.getOrCreateSequenceListByTimePartition(timePartition);
// delete compaction mods files
CompactionUtils.deleteCompactionModsFile(sourceSeqResourceList, sourceUnseqResourceList);
boolean removeAllTargetFile = true;
tsFileManager.writeLock("CompactionExceptionHandler");
try {
for (TsFileResource targetTsFile : targetResourceList) {
if (targetTsFile == null) {
// target file has been deleted due to empty after compaction
continue;
}
// delete target file
targetTsFile.writeLock();
if (!targetTsFile.remove()) {
LOGGER.error(
"{} [Compaction][Exception] fail to delete target tsfile {} when handling exception",
fullStorageGroupName,
targetTsFile);
removeAllTargetFile = false;
}
targetTsFile.writeUnlock();
// remove target tsfile resource in memory
if (targetTsFile.isFileInList()) {
if (isTargetSequence) {
seqTsFileResourceList.remove(targetTsFile);
} else {
unseqTsFileResourceList.remove(targetTsFile);
}
TsFileResourceManager.getInstance().removeTsFileResource(targetTsFile);
}
}
// recover source tsfile resource in memory
for (TsFileResource tsFileResource : sourceSeqResourceList) {
if (!tsFileResource.isFileInList()) {
seqTsFileResourceList.keepOrderInsert(tsFileResource);
TsFileResourceManager.getInstance().registerSealedTsFileResource(tsFileResource);
}
}
for (TsFileResource tsFileResource : sourceUnseqResourceList) {
if (!tsFileResource.isFileInList()) {
unseqTsFileResourceList.keepOrderInsert(tsFileResource);
TsFileResourceManager.getInstance().registerSealedTsFileResource(tsFileResource);
}
}
} finally {
tsFileManager.writeUnlock();
}
return removeAllTargetFile;
}
/**
* Some source files are lost, check if all target files are complete. If all target files are
* complete, delete the remaining source files and compaction mods files. If some target files are
* not complete, print some error logs.
*
* @throws IOException if the io operations on file fails
*/
private static boolean handleWhenSomeSourceFilesLost(
List<TsFileResource> targetResourceList,
List<TsFileResource> sourceSeqResourceList,
List<TsFileResource> sourceUnseqResourceList,
List<TsFileResource> lostSourceResourceList,
String fullStorageGroupName)
throws IOException {
// check whether is all target files complete
if (!checkIsTargetFilesComplete(
targetResourceList, lostSourceResourceList, fullStorageGroupName)) {
return false;
}
// delete sources file
CompactionUtils.deleteSourceTsFileAndUpdateFileMetrics(
sourceSeqResourceList, sourceUnseqResourceList);
// delete compaction mods files
CompactionUtils.deleteCompactionModsFile(sourceSeqResourceList, sourceUnseqResourceList);
return true;
}
private static boolean checkIsTargetFilesComplete(
List<TsFileResource> targetResources,
List<TsFileResource> lostSourceResources,
String fullStorageGroupName)
throws IOException {
for (TsFileResource targetResource : targetResources) {
if (targetResource.isDeleted()) {
// target resource is empty after compaction, then delete it
targetResource.remove();
continue;
} else {
// set target resources to CLOSED, so that they can be selected to compact
targetResource.setStatus(TsFileResourceStatus.NORMAL);
}
if (!TsFileUtils.isTsFileComplete(targetResource.getTsFile())) {
LOGGER.error(
"{} [Compaction][ExceptionHandler] target file {} is not complete, "
+ "and some source files {} is lost, do nothing.",
fullStorageGroupName,
targetResource,
lostSourceResources);
return false;
}
}
return true;
}
}