public static void reloadFailureRecovery(File indexDir)
      throws IOException {
    File parentDir = indexDir.getParentFile();

    // Recover index directory from segment backup directory if the segment backup directory exists
    File segmentBackupDir = new File(parentDir, indexDir.getName() + CommonConstants.Segment.SEGMENT_BACKUP_DIR_SUFFIX);
    if (segmentBackupDir.exists()) {
      LOGGER
          .info("Trying to recover index directory: {} from segment backup directory: {}", indexDir, segmentBackupDir);
      if (indexDir.exists()) {
        LOGGER.info("Deleting index directory: {}", indexDir);
        FileUtils.forceDelete(indexDir);
      }
      // The renaming operation is atomic, so if a failure happens during failure recovery, we will be left with the
      // segment backup directory, and can recover from that.
      Preconditions.checkState(segmentBackupDir.renameTo(indexDir),
          "Failed to rename segment backup directory: %s to index directory: %s", segmentBackupDir, indexDir);
    }

    // Delete segment temporary directory if it exists
    File segmentTempDir = new File(parentDir, indexDir.getName() + CommonConstants.Segment.SEGMENT_TEMP_DIR_SUFFIX);
    if (segmentTempDir.exists()) {
      LOGGER.info("Trying to delete segment temporary directory: {}", segmentTempDir);
      FileUtils.forceDelete(segmentTempDir);
    }
  }
@Test
  public void testReloadFailureRecovery()
      throws IOException {
    String segmentName = "dummySegment";
    String indexFileName = "dummyIndex";
    File indexDir = new File(TEST_DIR, segmentName);
    File segmentBackupDir = new File(TEST_DIR, segmentName + CommonConstants.Segment.SEGMENT_BACKUP_DIR_SUFFIX);
    File segmentTempDir = new File(TEST_DIR, segmentName + CommonConstants.Segment.SEGMENT_TEMP_DIR_SUFFIX);

    // Only index directory exists (normal case, or failed before the first renaming)
    Assert.assertTrue(indexDir.mkdir());
    FileUtils.touch(new File(indexDir, indexFileName));
    LoaderUtils.reloadFailureRecovery(indexDir);
    Assert.assertTrue(indexDir.exists());
    Assert.assertTrue(new File(indexDir, indexFileName).exists());
    Assert.assertFalse(segmentBackupDir.exists());
    Assert.assertFalse(segmentTempDir.exists());
    FileUtils.deleteDirectory(indexDir);

    // Only segment backup directory exists (failed after the first renaming but before copying happened)
    Assert.assertTrue(segmentBackupDir.mkdir());
    FileUtils.touch(new File(segmentBackupDir, indexFileName));
    LoaderUtils.reloadFailureRecovery(indexDir);
    Assert.assertTrue(indexDir.exists());
    Assert.assertTrue(new File(indexDir, indexFileName).exists());
    Assert.assertFalse(segmentBackupDir.exists());
    Assert.assertFalse(segmentTempDir.exists());
    FileUtils.deleteDirectory(indexDir);

    // Index directory and segment backup directory exist (failed before second renaming)
    Assert.assertTrue(indexDir.mkdir());
    Assert.assertTrue(segmentBackupDir.mkdir());
    FileUtils.touch(new File(segmentBackupDir, indexFileName));
    LoaderUtils.reloadFailureRecovery(indexDir);
    Assert.assertTrue(indexDir.exists());
    Assert.assertTrue(new File(indexDir, indexFileName).exists());
    Assert.assertFalse(segmentBackupDir.exists());
    Assert.assertFalse(segmentTempDir.exists());
    FileUtils.deleteDirectory(indexDir);

    // Index directory and segment temporary directory exist (failed after second renaming)
    Assert.assertTrue(indexDir.mkdir());
    FileUtils.touch(new File(indexDir, indexFileName));
    Assert.assertTrue(segmentTempDir.mkdir());
    LoaderUtils.reloadFailureRecovery(indexDir);
    Assert.assertTrue(indexDir.exists());
    Assert.assertTrue(new File(indexDir, indexFileName).exists());
    Assert.assertFalse(segmentBackupDir.exists());
    Assert.assertFalse(segmentTempDir.exists());
    FileUtils.deleteDirectory(indexDir);
  }