public static void postProcessBackup()

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;
            }
        });
    }