protected void moveForgottenFiles()

in priam/src/main/java/com/netflix/priam/backupv2/ForgottenFilesManager.java [131:211]


    protected void moveForgottenFiles(File columnfamilyDir, Collection<File> columnfamilyFiles)
            throws IOException {
        // This is a list of potential forgotten file(s). Note that C* might still be using
        // files as part of read, so we really do not want to move them until we meet the
        // @link{IConfiguration#getForgottenFileGracePeriodDaysForRead} window elapses.

        final Path destDir = Paths.get(columnfamilyDir.getAbsolutePath(), LOST_FOUND);
        FileUtils.forceMkdir(destDir.toFile());
        final Collection<Path> columnfamilyPaths =
                columnfamilyFiles
                        .parallelStream()
                        .map(file -> Paths.get(file.getAbsolutePath()))
                        .collect(Collectors.toList());

        for (Path file : columnfamilyPaths) {
            try {
                final Path symbolic_link =
                        Paths.get(destDir.toFile().getAbsolutePath(), file.toFile().getName());
                // Lets see if there is a symbolic link to this file already?
                if (!Files.exists(symbolic_link)) {
                    // If not, lets create one and work on next file.
                    Files.createSymbolicLink(symbolic_link, file);
                    continue;
                } else if (Files.isSymbolicLink(symbolic_link)) {
                    // Symbolic link exists, is it older than our timeframe?
                    Instant last_modified_time =
                            Files.getLastModifiedTime(symbolic_link, LinkOption.NOFOLLOW_LINKS)
                                    .toInstant();
                    if (DateUtil.getInstant()
                            .isAfter(
                                    last_modified_time.plus(
                                            config.getForgottenFileGracePeriodDaysForRead(),
                                            ChronoUnit.DAYS))) {
                        // Eligible for move.
                        logger.info(
                                "Eligible for move: Forgotten file: {} found for CF: {}",
                                file,
                                columnfamilyDir.getName());
                        backupMetrics.incrementForgottenFiles(1);
                        if (config.isForgottenFileMoveEnabled()) {
                            try {
                                // Remove our symbolic link. Note that deletion of symbolic link
                                // does not remove the original file.
                                Files.delete(symbolic_link);
                                FileUtils.moveFileToDirectory(
                                        file.toFile(), destDir.toFile(), true);
                                logger.warn(
                                        "Successfully moved forgotten file: {} found for CF: {}",
                                        file,
                                        columnfamilyDir.getName());
                            } catch (IOException e) {
                                logger.error(
                                        "Exception occurred while trying to move forgottenFile: {}. Ignoring the error and continuing with remaining backup/forgotten files.",
                                        file);
                                e.printStackTrace();
                            }
                        }
                    }
                }

            } catch (IOException e) {
                logger.error("Forgotten file: Error while trying to process the file: {}", file);
                e.printStackTrace();
            }
        }

        // Clean LOST_FOUND directory of any previous symbolic link files which are not considered
        // lost any more.
        for (File file : FileUtils.listFiles(destDir.toFile(), null, false)) {
            Path filePath = Paths.get(file.getAbsolutePath());
            if (Files.isSymbolicLink(filePath)) {
                Path originalFile = Files.readSymbolicLink(filePath);
                if (!columnfamilyPaths.contains(originalFile)) {
                    Files.delete(filePath);
                    logger.info(
                            "Deleting the symbolic link as it is not considered as lost anymore. filePath: {}",
                            filePath);
                }
            }
        }
    }