in s3-artifact-storage-agent/src/main/java/jetbrains/buildServer/artifacts/s3/download/parallel/strategy/impl/SeparatePartFilesParallelDownloadStrategy.java [67:109]
protected void afterDownloadingParts(@NotNull Path targetFile,
@NotNull List<FilePart> fileParts,
long fileSize,
@NotNull ParallelDownloadState downloadState,
@NotNull ParallelDownloadContext downloadContext) throws IOException {
try {
LOGGER.debug(String.format("Restoring file %s from parts", targetFile));
Path unfinishedTargetFile = getUnfinishedFilePath(targetFile);
List<Path> partTargetFiles = fileParts.stream()
.map(part -> getPartTargetFile(part, targetFile, downloadContext))
.collect(Collectors.toList());
checkDownloadInterrupted(downloadState);
ensureDirectoryExists(unfinishedTargetFile.getParent());
reserveFileBytes(unfinishedTargetFile, fileSize);
checkDownloadInterrupted(downloadState);
try (FileChannel targetFileChannel = FileChannel.open(unfinishedTargetFile, WRITE)) {
long totalCopied = 0L;
for (FilePart filePart : fileParts) {
Path partTargetFile = partTargetFiles.get(filePart.getPartNumber());
copyPart(filePart, partTargetFile, targetFileChannel, unfinishedTargetFile, downloadState);
totalCopied += filePart.getSizeBytes();
}
if (totalCopied < fileSize) throw new IOException(String.format("Merged parts contain less bytes (%s) than expected (%s)", totalCopied, fileParts));
}
// rename file and delete parts
checkDownloadInterrupted(downloadState);
FileUtil.atomicRename(unfinishedTargetFile.toFile(), targetFile.toFile(), 10);
for (FilePart filePart : fileParts) {
checkDownloadInterrupted(downloadState);
Path partTargetFile = partTargetFiles.get(filePart.getPartNumber());
Files.deleteIfExists(partTargetFile);
}
LOGGER.debug(String.format("Restored file %s from parts", targetFile));
} catch (IOException | RuntimeException e) {
LOGGER.debug(String.format("Failed to restore file %s from parts", targetFile), e);
throw e;
}
}