James Moger
2013-11-20 bdfdc9c65c5eb2786b7dd8e33ba8a12a3bafe86d
src/main/java/com/gitblit/GCExecutor.java
@@ -31,20 +31,21 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.gitblit.manager.IRepositoryManager;
import com.gitblit.models.RepositoryModel;
import com.gitblit.utils.FileUtils;
/**
 * The GC executor handles periodic garbage collection in repositories.
 *
 *
 * @author James Moger
 *
 *
 */
public class GCExecutor implements Runnable {
   public static enum GCStatus {
      READY, COLLECTING;
      public boolean exceeds(GCStatus s) {
         return ordinal() > s.ordinal();
      }
@@ -52,37 +53,43 @@
   private final Logger logger = LoggerFactory.getLogger(GCExecutor.class);
   private final IStoredSettings settings;
   private final IRepositoryManager repositoryManager;
   private AtomicBoolean running = new AtomicBoolean(false);
   private AtomicBoolean forceClose = new AtomicBoolean(false);
   private final Map<String, GCStatus> gcCache = new ConcurrentHashMap<String, GCStatus>();
   public GCExecutor(IStoredSettings settings) {
   public GCExecutor(
         IStoredSettings settings,
         IRepositoryManager repositoryManager) {
      this.settings = settings;
      this.repositoryManager = repositoryManager;
   }
   /**
    * Indicates if the GC executor is ready to process repositories.
    *
    *
    * @return true if the GC executor is ready to process repositories
    */
   public boolean isReady() {
      return settings.getBoolean(Keys.git.enableGarbageCollection, false);
   }
   public boolean isRunning() {
      return running.get();
   }
   public boolean lock(String repositoryName) {
      return setGCStatus(repositoryName, GCStatus.COLLECTING);
   }
   /**
    * Tries to set a GCStatus for the specified repository.
    *
    *
    * @param repositoryName
    * @return true if the status has been set
    */
@@ -100,7 +107,7 @@
   /**
    * Returns true if Gitblit is actively collecting garbage in this repository.
    *
    *
    * @param repositoryName
    * @return true if actively collecting garbage
    */
@@ -111,13 +118,13 @@
   /**
    * Resets the GC status to ready.
    *
    *
    * @param repositoryName
    */
   public void releaseLock(String repositoryName) {
      gcCache.put(repositoryName.toLowerCase(), GCStatus.READY);
   }
   public void close() {
      forceClose.set(true);
   }
@@ -127,11 +134,11 @@
      if (!isReady()) {
         return;
      }
      running.set(true);
      running.set(true);
      Date now = new Date();
      for (String repositoryName : GitBlit.self().getRepositoryList()) {
      for (String repositoryName : repositoryManager.getRepositoryList()) {
         if (forceClose.get()) {
            break;
         }
@@ -143,13 +150,13 @@
         RepositoryModel model = null;
         Repository repository = null;
         try {
            model = GitBlit.self().getRepositoryModel(repositoryName);
            repository = GitBlit.self().getRepository(repositoryName);
            model = repositoryManager.getRepositoryModel(repositoryName);
            repository = repositoryManager.getRepository(repositoryName);
            if (repository == null) {
               logger.warn(MessageFormat.format("GCExecutor is missing repository {0}?!?", repositoryName));
               continue;
            }
            if (!isRepositoryIdle(repository)) {
               logger.debug(MessageFormat.format("GCExecutor is skipping {0} because it is not idle", repositoryName));
               continue;
@@ -162,13 +169,13 @@
               logger.warn(MessageFormat.format("Can not acquire GC lock for {0}, skipping", repositoryName));
               continue;
            }
            logger.debug(MessageFormat.format("GCExecutor locked idle repository {0}", repositoryName));
            Git git = new Git(repository);
            GarbageCollectCommand gc = git.gc();
            Properties stats = gc.getStatistics();
            // determine if this is a scheduled GC
            Calendar cal = Calendar.getInstance();
            cal.setTime(model.lastGC);
@@ -190,10 +197,10 @@
            if (hasGarbage && (hasEnoughGarbage || shouldCollectGarbage)) {
               long looseKB = sizeOfLooseObjects/1024L;
               logger.info(MessageFormat.format("Collecting {1} KB of loose objects from {0}", repositoryName, looseKB));
               // do the deed
               gc.call();
               garbageCollected = true;
            }
         } catch (Exception e) {
@@ -204,21 +211,21 @@
               if (garbageCollected) {
                  // update the last GC date
                  model.lastGC = new Date();
                  GitBlit.self().updateConfiguration(repository, model);
                  repositoryManager.updateConfiguration(repository, model);
               }
               repository.close();
            }
            // reset the GC lock
            // reset the GC lock
            releaseLock(repositoryName);
            logger.debug(MessageFormat.format("GCExecutor released GC lock for {0}", repositoryName));
         }
      }
      running.set(false);
   }
   private boolean isRepositoryIdle(Repository repository) {
      try {
         // Read the use count.