This is an automated email from the ASF dual-hosted git repository. xingtanzjr pushed a commit to branch tsfile_hardlink_combine in repository https://gitbox.apache.org/repos/asf/iotdb.git
commit 9a01de85d2e73cadb0d6ae999dd353a50e75a76a Author: Jinrui.Zhang <[email protected]> AuthorDate: Tue Oct 24 19:50:43 2023 +0800 add hard link method for TsFileResource to leverage hard link in an unified approach --- .../common/tsfile/PipeTsFileInsertionEvent.java | 2 +- .../resource/tsfile/PipeTsFileResourceManager.java | 15 ++-- .../dataregion/snapshot/SnapshotTaker.java | 14 +++- .../dataregion/tsfile/TsFileResource.java | 96 ++++++++++++---------- .../dataregion/tsfile/TsFileResourceStatus.java | 5 ++ .../resource/PipeTsFileResourceManagerTest.java | 22 +++-- 6 files changed, 94 insertions(+), 60 deletions(-) diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/event/common/tsfile/PipeTsFileInsertionEvent.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/event/common/tsfile/PipeTsFileInsertionEvent.java index 8914e56cbfa..78b519e0498 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/event/common/tsfile/PipeTsFileInsertionEvent.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/event/common/tsfile/PipeTsFileInsertionEvent.java @@ -126,7 +126,7 @@ public class PipeTsFileInsertionEvent extends EnrichedEvent implements TsFileIns @Override public boolean internallyIncreaseResourceReferenceCount(String holderMessage) { try { - tsFile = PipeResourceManager.tsfile().increaseFileReference(tsFile, true); + tsFile = PipeResourceManager.tsfile().increaseFileReference(tsFile, true, resource); return true; } catch (Exception e) { LOGGER.warn( diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/resource/tsfile/PipeTsFileResourceManager.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/resource/tsfile/PipeTsFileResourceManager.java index 9839d793a25..28094e2212b 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/resource/tsfile/PipeTsFileResourceManager.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/resource/tsfile/PipeTsFileResourceManager.java @@ -54,10 +54,12 @@ public class PipeTsFileResourceManager { * @param file tsfile, resource file or mod file. can be original file or hardlink/copy of * original file * @param isTsFile true to create hardlink, false to copy file + * @param resource original TsFileResource or null if isTsFile is false * @return the hardlink or copied file * @throws IOException when create hardlink or copy file failed */ - public synchronized File increaseFileReference(File file, boolean isTsFile) throws IOException { + public synchronized File increaseFileReference( + File file, boolean isTsFile, TsFileResource resource) throws IOException { // if the file is already a hardlink or copied file, just increase reference count and return it if (increaseReferenceIfExists(file.getPath())) { return file; @@ -77,9 +79,12 @@ public class PipeTsFileResourceManager { fileNameToFileMap.put(hardlinkOrCopiedFile.getPath(), hardlinkOrCopiedFile); // if the file is a tsfile, create a hardlink in pipe dir and return it. // otherwise, copy the file (.mod or .resource) to pipe dir and return it. - return isTsFile - ? createHardLink(file, hardlinkOrCopiedFile) - : copyFile(file, hardlinkOrCopiedFile); + if (isTsFile) { + resource.hardLinkOrCopyTsFileTo(hardlinkOrCopiedFile.toPath()); + } else { + copyFile(file, hardlinkOrCopiedFile); + } + return hardlinkOrCopiedFile; } private boolean increaseReferenceIfExists(String path) { @@ -181,7 +186,7 @@ public class PipeTsFileResourceManager { } public synchronized void pinTsFileResource(TsFileResource resource) throws IOException { - increaseFileReference(resource.getTsFile(), true); + increaseFileReference(resource.getTsFile(), true, resource); } public synchronized void unpinTsFileResource(TsFileResource resource) throws IOException { diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/snapshot/SnapshotTaker.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/snapshot/SnapshotTaker.java index b404ca2fd5e..39a44eddfd5 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/snapshot/SnapshotTaker.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/snapshot/SnapshotTaker.java @@ -172,7 +172,7 @@ public class SnapshotTaker { } File snapshotTsFile = getSnapshotFilePathForTsFile(tsFile, snapshotId); // create hard link for tsfile, resource, mods - createHardLink(snapshotTsFile, tsFile); + createHardLinkForTsFile(snapshotTsFile, resource); createHardLink( new File(snapshotTsFile.getAbsolutePath() + TsFileResource.RESOURCE_SUFFIX), new File(tsFile.getAbsolutePath() + TsFileResource.RESOURCE_SUFFIX)); @@ -201,6 +201,18 @@ public class SnapshotTaker { snapshotLogger.logFile(source); } + private void createHardLinkForTsFile(File target, TsFileResource source) throws IOException { + if (!target.getParentFile().exists()) { + LOGGER.error("Hard link target dir {} doesn't exist", target.getParentFile()); + } + if (!source.getTsFile().exists()) { + LOGGER.error("Hard link source file {} doesn't exist", source); + } + Files.deleteIfExists(target.toPath()); + source.hardLinkOrCopyTsFileTo(target.toPath()); + snapshotLogger.logFile(source.getTsFile()); + } + /** * 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", diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/tsfile/TsFileResource.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/tsfile/TsFileResource.java index ce49b700768..c6103673337 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/tsfile/TsFileResource.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/tsfile/TsFileResource.java @@ -38,7 +38,6 @@ import org.apache.iotdb.db.storageengine.dataregion.tsfile.timeindex.ITimeIndex; import org.apache.iotdb.db.storageengine.dataregion.tsfile.timeindex.TimeIndexLevel; import org.apache.iotdb.db.storageengine.rescon.disk.TierManager; import org.apache.iotdb.db.utils.DateTimeUtils; -import org.apache.iotdb.tsfile.common.constant.TsFileConstant; import org.apache.iotdb.tsfile.file.metadata.IChunkMetadata; import org.apache.iotdb.tsfile.file.metadata.ITimeSeriesMetadata; import org.apache.iotdb.tsfile.fileSystem.FSFactoryProducer; @@ -57,9 +56,8 @@ import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; -import java.nio.file.FileAlreadyExistsException; import java.nio.file.Files; -import java.nio.file.Paths; +import java.nio.file.Path; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -155,6 +153,11 @@ public class TsFileResource { private ProgressIndex maxProgressIndex; + private long dataSize; + + private boolean isMetaSplit = false; + private boolean hasHardLink = false; + public TsFileResource() {} public TsFileResource(TsFileResource other) throws IOException { @@ -659,6 +662,10 @@ public class TsFileResource { case COMPACTING: return compareAndSetStatus( TsFileResourceStatus.COMPACTION_CANDIDATE, TsFileResourceStatus.COMPACTING); + case HARD_LINKING: + return compareAndSetStatus(TsFileResourceStatus.NORMAL, TsFileResourceStatus.HARD_LINKING) + || compareAndSetStatus( + TsFileResourceStatus.COMPACTION_CANDIDATE, TsFileResourceStatus.HARD_LINKING); case COMPACTION_CANDIDATE: return compareAndSetStatus( TsFileResourceStatus.NORMAL, TsFileResourceStatus.COMPACTION_CANDIDATE); @@ -824,48 +831,6 @@ public class TsFileResource { return timeIndex.isSpanMultiTimePartitions(); } - /** - * Create a hardlink for the TsFile and modification file (if exists) The hardlink will have a - * suffix like ".{sysTime}_{randomLong}" - * - * @return a new TsFileResource with its file changed to the hardlink or null the hardlink cannot - * be created. - */ - public TsFileResource createHardlink() { - if (!file.exists()) { - return null; - } - - TsFileResource newResource; - try { - newResource = new TsFileResource(this); - } catch (IOException e) { - LOGGER.error("Cannot create hardlink for {}", file, e); - return null; - } - - while (true) { - String hardlinkSuffix = - TsFileConstant.PATH_SEPARATOR + System.currentTimeMillis() + "_" + random.nextLong(); - File hardlink = new File(file.getAbsolutePath() + hardlinkSuffix); - - try { - Files.createLink(Paths.get(hardlink.getAbsolutePath()), Paths.get(file.getAbsolutePath())); - newResource.setFile(hardlink); - if (modFile != null && modFile.exists()) { - newResource.setModFile(modFile.createHardlink()); - } - break; - } catch (FileAlreadyExistsException e) { - // retry a different name if the file is already created - } catch (IOException e) { - LOGGER.error("Cannot create hardlink for {}", file, e); - return null; - } - } - return newResource; - } - public void setModFile(ModificationFile modFile) { synchronized (this) { this.modFile = modFile; @@ -1154,4 +1119,45 @@ public class TsFileResource { public String getDataRegionId() { return file.getParentFile().getParentFile().getName(); } + + public void hardLinkOrCopyTsFileTo(Path targetPath) throws IOException { + if (setStatus(TsFileResourceStatus.HARD_LINKING)) { + // use hard link directly + Files.createLink(targetPath, getTsFile().toPath()); + this.hasHardLink = true; + } else { + // copy this file to target path + readLock(); + try { + if (isMetaSplit) { + // combine the data part and meta part into target file + + } else { + Files.copy(getTsFile().toPath(), targetPath); + } + } finally { + readUnlock(); + } + } + } + + public void setDataSize(long dataSize) { + this.dataSize = dataSize; + } + + public long getDataSize() { + return dataSize; + } + + public boolean isMetaSplit() { + return isMetaSplit; + } + + public void setMetaSplit(boolean metaSplit) { + isMetaSplit = metaSplit; + } + + public boolean isHasHardLink() { + return hasHardLink; + } } diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/tsfile/TsFileResourceStatus.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/tsfile/TsFileResourceStatus.java index 2cf69fac58d..8014da39618 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/tsfile/TsFileResourceStatus.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/tsfile/TsFileResourceStatus.java @@ -24,5 +24,10 @@ public enum TsFileResourceStatus { NORMAL, COMPACTION_CANDIDATE, COMPACTING, + /** + * Indicating the TsFile is prepared to be hard linked. It is seemed as a write operation because + * it cannot be modified by other module during hard linking + */ + HARD_LINKING, DELETED } diff --git a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/pipe/resource/PipeTsFileResourceManagerTest.java b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/pipe/resource/PipeTsFileResourceManagerTest.java index ef9496901f3..6ad7858f3cc 100644 --- a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/pipe/resource/PipeTsFileResourceManagerTest.java +++ b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/pipe/resource/PipeTsFileResourceManagerTest.java @@ -27,6 +27,7 @@ import org.apache.iotdb.db.pipe.resource.tsfile.PipeTsFileResourceManager; 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.TsFileResource; import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType; import org.apache.iotdb.tsfile.file.metadata.enums.TSEncoding; import org.apache.iotdb.tsfile.write.TsFileWriter; @@ -150,12 +151,14 @@ public class PipeTsFileResourceManagerTest { @Test public void testIncreaseTsfile() throws IOException { File originTsfile = new File(TS_FILE_NAME); + TsFileResource originTsFileResource = new TsFileResource(originTsfile); File originModFile = new File(MODS_FILE_NAME); Assert.assertEquals(0, pipeTsFileResourceManager.getFileReferenceCount(originTsfile)); Assert.assertEquals(0, pipeTsFileResourceManager.getFileReferenceCount(originModFile)); - File pipeTsfile = pipeTsFileResourceManager.increaseFileReference(originTsfile, true); - File pipeModFile = pipeTsFileResourceManager.increaseFileReference(originModFile, false); + File pipeTsfile = + pipeTsFileResourceManager.increaseFileReference(originTsfile, true, originTsFileResource); + File pipeModFile = pipeTsFileResourceManager.increaseFileReference(originModFile, false, null); Assert.assertEquals(1, pipeTsFileResourceManager.getFileReferenceCount(pipeTsfile)); Assert.assertEquals(1, pipeTsFileResourceManager.getFileReferenceCount(pipeModFile)); Assert.assertTrue(Files.exists(originTsfile.toPath())); @@ -163,19 +166,20 @@ public class PipeTsFileResourceManagerTest { Assert.assertTrue(Files.exists(pipeTsfile.toPath())); Assert.assertTrue(Files.exists(pipeModFile.toPath())); - pipeTsFileResourceManager.increaseFileReference(originTsfile, true); - pipeTsFileResourceManager.increaseFileReference(originModFile, false); + pipeTsFileResourceManager.increaseFileReference(originTsfile, true, originTsFileResource); + pipeTsFileResourceManager.increaseFileReference(originModFile, false, null); Assert.assertEquals(2, pipeTsFileResourceManager.getFileReferenceCount(pipeTsfile)); Assert.assertEquals(2, pipeTsFileResourceManager.getFileReferenceCount(pipeModFile)); // test use hardlinkTsFile to increase reference counts - pipeTsFileResourceManager.increaseFileReference(pipeTsfile, true); + pipeTsFileResourceManager.increaseFileReference( + pipeTsfile, true, new TsFileResource(pipeTsfile)); Assert.assertEquals(3, pipeTsFileResourceManager.getFileReferenceCount(pipeTsfile)); Assert.assertTrue(Files.exists(originTsfile.toPath())); Assert.assertTrue(Files.exists(pipeTsfile.toPath())); // test use copyFile to increase reference counts - pipeTsFileResourceManager.increaseFileReference(pipeModFile, false); + pipeTsFileResourceManager.increaseFileReference(pipeModFile, false, null); Assert.assertEquals(3, pipeTsFileResourceManager.getFileReferenceCount(pipeModFile)); Assert.assertTrue(Files.exists(originModFile.toPath())); Assert.assertTrue(Files.exists(pipeModFile.toPath())); @@ -191,8 +195,10 @@ public class PipeTsFileResourceManagerTest { Assert.assertEquals(0, pipeTsFileResourceManager.getFileReferenceCount(originFile)); Assert.assertEquals(0, pipeTsFileResourceManager.getFileReferenceCount(originModFile)); - File pipeTsfile = pipeTsFileResourceManager.increaseFileReference(originFile, true); - File pipeModFile = pipeTsFileResourceManager.increaseFileReference(originModFile, false); + File pipeTsfile = + pipeTsFileResourceManager.increaseFileReference( + originFile, true, new TsFileResource(originFile)); + File pipeModFile = pipeTsFileResourceManager.increaseFileReference(originModFile, false, null); Assert.assertEquals(1, pipeTsFileResourceManager.getFileReferenceCount(pipeTsfile)); Assert.assertEquals(1, pipeTsFileResourceManager.getFileReferenceCount(pipeModFile)); Assert.assertTrue(Files.exists(pipeTsfile.toPath()));
