private void runGcInCopy()

in git-server/src/main/java/jetbrains/buildServer/buildTriggers/vcs/git/Cleanup.java [224:306]


  private void runGcInCopy(@NotNull File originalRepo) {
    Lock rmLock = myRepositoryManager.getRmLock(originalRepo).readLock();
    rmLock.lock();
    File gcRepo;
    try {
      if (!isGcNeeded(originalRepo)) {
        CLEANUP.debug("[" + originalRepo.getName() + "] no git gc is needed");
        myGcErrors.clearError(originalRepo);
        return;
      }

      try {
        gcRepo = setupGcRepo(originalRepo);
      } catch (Exception e) {
        myGcErrors.registerError(originalRepo, "Failed to create temporary repository for garbage collection", e);
        CLEANUP.warnAndDebugDetails("Failed to create temporary repository for garbage collection, original repository: " + originalRepo.getAbsolutePath(), e);
        return;
      }

      CLEANUP.info("[" + originalRepo.getName() + "] run git gc in dedicated dir [" + gcRepo.getName() + "]");

      try {
        repack(gcRepo);
        packRefs(gcRepo);
      } catch (Exception e) {
        myGcErrors.registerError(originalRepo, "Error while running garbage collection", e);
        CLEANUP.warnAndDebugDetails("Error while running garbage collection in " + originalRepo.getAbsolutePath(), e);
        FileUtil.delete(gcRepo);
        return;
      }
    } finally {
      rmLock.unlock();
    }

    //remove alternates pointing to the original repo before swapping repositories
    FileUtil.delete(new File(gcRepo, "objects/info/alternates"));

    long swapStart = System.currentTimeMillis();
    File oldDir;
    try {
      oldDir = createTempDir(originalRepo.getParentFile(), originalRepo.getName() + ".old");
      FileUtil.delete(oldDir);
    } catch (Exception e) {
      myGcErrors.registerError(originalRepo, "Error while creating temporary directory", e);
      CLEANUP.warnAndDebugDetails("Error while creating temporary directory for " + originalRepo.getAbsolutePath(), e);
      FileUtil.delete(gcRepo);
      return;
    }

    //swap repositories with write rm lock which guarantees no one uses the original repository
    Lock rmWriteLock = myRepositoryManager.getRmLock(originalRepo).writeLock();
    long lockStart = System.currentTimeMillis();
    rmWriteLock.lock();
    long lockDuration = System.currentTimeMillis() - lockStart;
    try {
      if (!renameDir(originalRepo, oldDir, 5)) {
        myGcErrors.registerError(originalRepo, "Failed to rename " + originalRepo.getName() + " to " + oldDir.getName());
        CLEANUP.warn("Failed to rename " + originalRepo.getName() + " to " + oldDir.getName() + " after several attempts");
        return;
      }
      if (!renameDir(gcRepo, originalRepo, 5)) {
        myGcErrors.registerError(originalRepo, "Failed to rename " + gcRepo.getName() + " to " + originalRepo.getName());
        CLEANUP.warn("Failed to rename " + gcRepo.getName() + " to " + originalRepo.getName() + " after several attempts, will try restoring old repository");
        if (!oldDir.renameTo(originalRepo)) {
          CLEANUP.warn("Failed to rename " + oldDir.getName() + " to " + originalRepo.getName());
        }
        return;
      }
    } finally {
      rmWriteLock.unlock();
      FileUtil.delete(oldDir);
      FileUtil.delete(gcRepo);
    }
    long swapDuration = System.currentTimeMillis() - swapStart;
    if (swapDuration > TimeUnit.SECONDS.toMillis(5)) {
      String msg = "[" + originalRepo.getName() + "] swap with compacted repository finished in " + swapDuration + "ms";
      if (lockDuration > TimeUnit.SECONDS.toMillis(1)) {
        msg += " (lock acquired in " + lockDuration + "ms)";
      }
      CLEANUP.info(msg);
    }
    myGcErrors.clearError(originalRepo);
  }