choubenson commented on code in PR #12122: URL: https://github.com/apache/iotdb/pull/12122#discussion_r1577328114
########## iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/compaction/selector/impl/SettleSelectorImpl.java: ########## @@ -0,0 +1,328 @@ +/* + * 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.selector.impl; + +import org.apache.iotdb.commons.conf.IoTDBConstant; +import org.apache.iotdb.commons.exception.IllegalPathException; +import org.apache.iotdb.commons.path.PartialPath; +import org.apache.iotdb.commons.utils.CommonDateTimeUtils; +import org.apache.iotdb.db.conf.IoTDBConfig; +import org.apache.iotdb.db.conf.IoTDBDescriptor; +import org.apache.iotdb.db.queryengine.plan.analyze.cache.schema.DataNodeTTLCache; +import org.apache.iotdb.db.storageengine.dataregion.compaction.execute.performer.ICompactionPerformer; +import org.apache.iotdb.db.storageengine.dataregion.compaction.execute.task.SettleCompactionTask; +import org.apache.iotdb.db.storageengine.dataregion.compaction.execute.utils.CompactionUtils; +import org.apache.iotdb.db.storageengine.dataregion.compaction.selector.ISettleSelector; +import org.apache.iotdb.db.storageengine.dataregion.modification.Deletion; +import org.apache.iotdb.db.storageengine.dataregion.modification.Modification; +import org.apache.iotdb.db.storageengine.dataregion.modification.ModificationFile; +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.TsFileResourceStatus; +import org.apache.iotdb.db.storageengine.dataregion.tsfile.timeindex.DeviceTimeIndex; +import org.apache.iotdb.db.storageengine.dataregion.tsfile.timeindex.ITimeIndex; +import org.apache.iotdb.tsfile.file.metadata.IDeviceID; +import org.apache.iotdb.tsfile.file.metadata.PlainDeviceID; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import static org.apache.iotdb.db.storageengine.dataregion.compaction.selector.impl.SettleSelectorImpl.DirtyStatus.PARTIAL_DELETED; + +public class SettleSelectorImpl implements ISettleSelector { + private static final Logger LOGGER = + LoggerFactory.getLogger(IoTDBConstant.COMPACTION_LOGGER_NAME); + private static final IoTDBConfig config = IoTDBDescriptor.getInstance().getConfig(); + + private final boolean heavySelect; + private final String storageGroupName; + private final String dataRegionId; + private final long timePartition; + private final TsFileManager tsFileManager; + private boolean isSeq; + + public SettleSelectorImpl( + boolean heavySelect, + String storageGroupName, + String dataRegionId, + long timePartition, + TsFileManager tsFileManager) { + this.heavySelect = heavySelect; + this.storageGroupName = storageGroupName; + this.dataRegionId = dataRegionId; + this.timePartition = timePartition; + this.tsFileManager = tsFileManager; + } + + static class AllDirtyResource { + List<TsFileResource> resources = new ArrayList<>(); + + public void add(TsFileResource resource) { + resources.add(resource); + } + + public List<TsFileResource> getResources() { + return resources; + } + } + + static class PartialDirtyResource { + List<TsFileResource> resources = new ArrayList<>(); + long totalFileSize = 0; + + public boolean add(TsFileResource resource, long dirtyDataSize) { + resources.add(resource); + totalFileSize += resource.getTsFileSize(); + totalFileSize -= dirtyDataSize; + return checkHasReachedThreshold(); + } + + public List<TsFileResource> getResources() { + return resources; + } + + public boolean checkHasReachedThreshold() { + return resources.size() >= config.getFileLimitPerInnerTask() + || totalFileSize >= config.getTargetCompactionFileSize(); + } + } + + @Override + public List<SettleCompactionTask> selectSettleTask(List<TsFileResource> tsFileResources) { + if (tsFileResources.isEmpty()) { + return Collections.emptyList(); + } + this.isSeq = tsFileResources.get(0).isSeq(); + return selectTasks(tsFileResources); + } + + private List<SettleCompactionTask> selectTasks(List<TsFileResource> resources) { + AllDirtyResource allDirtyResource = new AllDirtyResource(); + List<PartialDirtyResource> partialDirtyResourceList = new ArrayList<>(); + PartialDirtyResource partialDirtyResource = new PartialDirtyResource(); + try { + for (TsFileResource resource : resources) { + if (resource.getStatus() != TsFileResourceStatus.NORMAL) { + continue; + } + boolean shouldStop = false; + DirtyStatus dirtyStatus; + if (!heavySelect) { + dirtyStatus = selectFileBaseOnModSize(resource); + } else { + dirtyStatus = selectFileBaseOnDirtyData(resource); + } + + switch (dirtyStatus) { + case ALL_DELETED: + allDirtyResource.add(resource); + break; + case PARTIAL_DELETED: + shouldStop = partialDirtyResource.add(resource, dirtyStatus.getDirtyDataSize()); + break; + case NOT_SATISFIED: + shouldStop = !partialDirtyResource.getResources().isEmpty(); + break; + default: + // do nothing + } + + if (shouldStop) { + partialDirtyResourceList.add(partialDirtyResource); + partialDirtyResource = new PartialDirtyResource(); + if (!heavySelect) { + // Non-heavy selection is triggered more frequently. In order to avoid selecting too + // many files containing mods for compaction when the disk is insufficient, the number + // and size of files are limited here. + break; + } + } + } + partialDirtyResourceList.add(partialDirtyResource); + return creatTask(allDirtyResource, partialDirtyResourceList); + } catch (Exception e) { + LOGGER.error( + "{}-{} cannot select file for settle compaction", storageGroupName, dataRegionId, e); + } + return Collections.emptyList(); + } + + private DirtyStatus selectFileBaseOnModSize(TsFileResource resource) { + ModificationFile modFile = resource.getModFile(); + if (modFile == null || !modFile.exists()) { + return DirtyStatus.NOT_SATISFIED; + } + return modFile.getSize() > config.getInnerCompactionTaskSelectionModsFileThreshold() + || (!heavySelect + && !CompactionUtils.isDiskHasSpace( + config.getInnerCompactionTaskSelectionDiskRedundancy())) + ? PARTIAL_DELETED + : DirtyStatus.NOT_SATISFIED; + } + + /** + * Only when all devices with ttl are deleted may they be selected. On the basic of the previous, + * only when the number of deleted devices exceeds the threshold or has expired for too long will + * they be selected. + * + * @return dirty status means the status of current resource. + */ + private DirtyStatus selectFileBaseOnDirtyData(TsFileResource resource) + throws IOException, IllegalPathException { + ModificationFile modFile = resource.getModFile(); + DeviceTimeIndex deviceTimeIndex = + resource.getTimeIndexType() == ITimeIndex.FILE_TIME_INDEX_TYPE + ? resource.buildDeviceTimeIndex() + : (DeviceTimeIndex) resource.getTimeIndex(); + Set<IDeviceID> deletedDevices = new HashSet<>(); + boolean hasExpiredTooLong = false; + long currentTime = CommonDateTimeUtils.currentTime(); + + Collection<Modification> modifications = modFile.getModifications(); + for (IDeviceID device : deviceTimeIndex.getDevices()) { + // check expired device by ttl + long deviceTTL = DataNodeTTLCache.getInstance().getTTL(((PlainDeviceID) device).toStringID()); Review Comment: Resolved. -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: reviews-unsubscr...@iotdb.apache.org For queries about this service, please contact Infrastructure at: us...@infra.apache.org