in compress/src/main/java/jetbrains/exodus/util/CompressBackupUtil.java [691:784]
public static void postProcessBackup(Path restoreDir) throws IOException {
Files.walkFileTree(restoreDir, new FileVisitor<>() {
private final HashMap<Path, TreeMap<Path, ArrayList<Path>>> filePeaces = new HashMap<>();
@Override
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) {
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
final String name = file.getFileName().toString();
final int fileExtIndex = name.lastIndexOf(".");
final int fileIndex;
final String indexStr;
final String fileName;
if (fileExtIndex >= 0 && fileExtIndex < name.length() - 1) {
indexStr = name.substring(fileExtIndex - 8, fileExtIndex);
fileName = name.substring(0, fileExtIndex - 9) + name.substring(fileExtIndex);
} else {
indexStr = name.substring(name.length() - 8);
fileName = name.substring(0, name.length() - 9);
}
fileIndex = Integer.parseInt(indexStr, 16);
final Path absolutePath = file.toRealPath();
final Path currentDirectory = absolutePath.getParent();
final Path realFileName = currentDirectory.resolve(fileName);
final TreeMap<Path, ArrayList<Path>> directoryFiles = filePeaces.computeIfAbsent(currentDirectory,
key -> new TreeMap<>());
final ArrayList<Path> pieces = directoryFiles.computeIfAbsent(realFileName, k -> new ArrayList<>());
while (pieces.size() <= fileIndex) {
pieces.add(null);
}
pieces.set(fileIndex, absolutePath);
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException {
throw new IOException(exc);
}
@Override
public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
if (exc != null) {
throw new IOException(exc);
}
final TreeMap<Path, ArrayList<Path>> directoryFiles = filePeaces.remove(dir);
if (directoryFiles != null) {
directoryFiles.forEach((fullFile, filePieces) -> {
try {
try {
Files.move(filePieces.get(0), fullFile, StandardCopyOption.ATOMIC_MOVE);
} catch (AtomicMoveNotSupportedException e) {
Files.move(filePieces.get(0), fullFile);
}
if (filePieces.size() == 1) {
return;
}
try (FileChannel channel =
FileChannel.open(fullFile, StandardOpenOption.WRITE, StandardOpenOption.APPEND)) {
for (final Path piece : filePieces.subList(1, filePieces.size())) {
long bytesWritten = 0;
final long bytesToWrite = Files.size(piece);
try (final FileChannel pieceChannel = FileChannel.open(piece, StandardOpenOption.READ)) {
while (bytesWritten < bytesToWrite) {
final long w = pieceChannel.transferTo(bytesWritten,
bytesToWrite - bytesWritten, channel);
bytesWritten += w;
}
}
Files.delete(piece);
}
}
} catch (IOException e) {
throw new ExodusException("Error during postprocessing of backup files.", e);
}
});
}
return FileVisitResult.CONTINUE;
}
});
}