private static boolean resolveAndArchiveFile(Path archiveDir, File currentFile,
    String archiveStartTime) throws IOException {
    // build path as it should be in the archive
    String filename = currentFile.getName();
    Path archiveFile = new Path(archiveDir, filename);
    FileSystem fs = currentFile.getFileSystem();

    // An existing destination file in the archive is unexpected, but we handle it here.
    if (fs.exists(archiveFile)) {
      if (!fs.exists(currentFile.getPath())) {
        // If the file already exists in the archive, and there is no current file to archive, then
        // assume that the file in archive is correct. This is an unexpected situation, suggesting a
        // race condition or split brain.
        // In HBASE-26718 this was found when compaction incorrectly happened during warmupRegion.
        LOG.warn("{} exists in archive. Attempted to archive nonexistent file {}.", archiveFile,
          currentFile);
        // We return success to match existing behavior in this method, where FileNotFoundException
        // in moveAndClose is ignored.
        return true;
      }
      // There is a conflict between the current file and the already existing archived file.
      // Move the archived file to a timestamped backup. This is a really, really unlikely
      // situation, where we get the same name for the existing file, but is included just for that
      // 1 in trillion chance. We are potentially incurring data loss in the archive directory if
      // the files are not identical. The timestamped backup will be cleaned by HFileCleaner as it
      // has no references.
      FileStatus curStatus = fs.getFileStatus(currentFile.getPath());
      FileStatus archiveStatus = fs.getFileStatus(archiveFile);
      long curLen = curStatus.getLen();
      long archiveLen = archiveStatus.getLen();
      long curMtime = curStatus.getModificationTime();
      long archiveMtime = archiveStatus.getModificationTime();
      if (curLen != archiveLen) {
        LOG.error(
          "{} already exists in archive with different size than current {}."
            + " archiveLen: {} currentLen: {} archiveMtime: {} currentMtime: {}",
          archiveFile, currentFile, archiveLen, curLen, archiveMtime, curMtime);
        throw new IOException(
          archiveFile + " already exists in archive with different size" + " than " + currentFile);
      }

      LOG.error(
        "{} already exists in archive, moving to timestamped backup and overwriting"
          + " current {}. archiveLen: {} currentLen: {} archiveMtime: {} currentMtime: {}",
        archiveFile, currentFile, archiveLen, curLen, archiveMtime, curMtime);

      // move the archive file to the stamped backup
      Path backedupArchiveFile = new Path(archiveDir, filename + SEPARATOR + archiveStartTime);
      if (!fs.rename(archiveFile, backedupArchiveFile)) {
        LOG.error("Could not rename archive file to backup: " + backedupArchiveFile
          + ", deleting existing file in favor of newer.");
        // try to delete the existing file, if we can't rename it
        if (!fs.delete(archiveFile, false)) {
          throw new IOException("Couldn't delete existing archive file (" + archiveFile
            + ") or rename it to the backup file (" + backedupArchiveFile
            + ") to make room for similarly named file.");
        }
      } else {
        LOG.info("Backed up archive file from {} to {}.", archiveFile, backedupArchiveFile);
      }
    }

    LOG.trace("No existing file in archive for {}, free to archive original file.", archiveFile);

    // at this point, we should have a free spot for the archive file
    boolean success = false;
    for (int i = 0; !success && i < DEFAULT_RETRIES_NUMBER; ++i) {
      if (i > 0) {
        // Ensure that the archive directory exists.
        // The previous "move to archive" operation has failed probably because
        // the cleaner has removed our archive directory (HBASE-7643).
        // (we're in a retry loop, so don't worry too much about the exception)
        try {
          if (!fs.exists(archiveDir)) {
            if (fs.mkdirs(archiveDir)) {
              LOG.debug("Created archive directory {}", archiveDir);
            }
          }
        } catch (IOException e) {
          LOG.warn("Failed to create directory {}", archiveDir, e);
        }
      }

      try {
        success = currentFile.moveAndClose(archiveFile);
      } catch (FileNotFoundException fnfe) {
        LOG.warn("Failed to archive " + currentFile
          + " because it does not exist! Skipping and continuing on.", fnfe);
        success = true;
      } catch (IOException e) {
        success = false;
        // When HFiles are placed on a filesystem other than HDFS a rename operation can be a
        // non-atomic file copy operation. It can take a long time to copy a large hfile and if
        // interrupted there may be a partially copied file present at the destination. We must
        // remove the partially copied file, if any, or otherwise the archive operation will fail
        // indefinitely from this point.
        LOG.warn("Failed to archive " + currentFile + " on try #" + i, e);
        try {
          fs.delete(archiveFile, false);
        } catch (FileNotFoundException fnfe) {
          // This case is fine.
        } catch (IOException ee) {
          // Complain about other IO exceptions
          LOG.warn("Failed to clean up from failure to archive " + currentFile + " on try #" + i,
            ee);
        }
      }
    }

    if (!success) {
      LOG.error("Failed to archive " + currentFile);
      return false;
    }

    LOG.debug("Archived from {} to {}", currentFile, archiveFile);
    return true;
  }
Attempt to archive the passed in file to the archive directory.
<p>
If the same file already exists in the archive, it is moved to a timestamped directory under
the archive directory and the new file is put in its place.
@param archiveDir       {@link Path} to the directory that stores the archives of the hfiles
@param currentFile      {@link Path} to the original HFile that will be archived
@param archiveStartTime time the archiving started, to resolve naming conflicts
@return <tt>true</tt> if the file is successfully archived. <tt>false</tt> if there was a
        problem, but the operation still completed.
@throws IOException on failure to complete {@link FileSystem} operations.
hbase-server/src/main/java/org/apache/hadoop/hbase/backup/HFileArchiver.java