GarbageCollectCommand.java

  1. /*
  2.  * Copyright (C) 2012, Matthias Sohn <matthias.sohn@sap.com> and others
  3.  *
  4.  * This program and the accompanying materials are made available under the
  5.  * terms of the Eclipse Distribution License v. 1.0 which is available at
  6.  * https://www.eclipse.org/org/documents/edl-v10.php.
  7.  *
  8.  * SPDX-License-Identifier: BSD-3-Clause
  9.  */
  10. package org.eclipse.jgit.api;

  11. import java.io.IOException;
  12. import java.text.MessageFormat;
  13. import java.text.ParseException;
  14. import java.util.Date;
  15. import java.util.Properties;

  16. import org.eclipse.jgit.api.errors.GitAPIException;
  17. import org.eclipse.jgit.api.errors.JGitInternalException;
  18. import org.eclipse.jgit.internal.JGitText;
  19. import org.eclipse.jgit.internal.storage.dfs.DfsGarbageCollector;
  20. import org.eclipse.jgit.internal.storage.dfs.DfsRepository;
  21. import org.eclipse.jgit.internal.storage.file.FileRepository;
  22. import org.eclipse.jgit.internal.storage.file.GC;
  23. import org.eclipse.jgit.internal.storage.file.GC.RepoStatistics;
  24. import org.eclipse.jgit.lib.ConfigConstants;
  25. import org.eclipse.jgit.lib.ProgressMonitor;
  26. import org.eclipse.jgit.lib.Repository;
  27. import org.eclipse.jgit.lib.StoredConfig;
  28. import org.eclipse.jgit.storage.pack.PackConfig;

  29. /**
  30.  * A class used to execute a {@code gc} command. It has setters for all
  31.  * supported options and arguments of this command and a {@link #call()} method
  32.  * to finally execute the command. Each instance of this class should only be
  33.  * used for one invocation of the command (means: one call to {@link #call()})
  34.  *
  35.  * @since 2.2
  36.  * @see <a href="http://www.kernel.org/pub/software/scm/git/docs/git-gc.html"
  37.  *      >Git documentation about gc</a>
  38.  */
  39. public class GarbageCollectCommand extends GitCommand<Properties> {
  40.     /**
  41.      * Default value of maximum delta chain depth during aggressive garbage
  42.      * collection: {@value}
  43.      *
  44.      * @since 3.6
  45.      */
  46.     public static final int DEFAULT_GC_AGGRESSIVE_DEPTH = 250;

  47.     /**
  48.      * Default window size during packing during aggressive garbage collection:
  49.      * * {@value}
  50.      *
  51.      * @since 3.6
  52.      */
  53.     public static final int DEFAULT_GC_AGGRESSIVE_WINDOW = 250;

  54.     private ProgressMonitor monitor;

  55.     private Date expire;

  56.     private PackConfig pconfig;

  57.     /**
  58.      * Constructor for GarbageCollectCommand.
  59.      *
  60.      * @param repo
  61.      *            a {@link org.eclipse.jgit.lib.Repository} object.
  62.      */
  63.     protected GarbageCollectCommand(Repository repo) {
  64.         super(repo);
  65.         pconfig = new PackConfig(repo);
  66.     }

  67.     /**
  68.      * Set progress monitor
  69.      *
  70.      * @param monitor
  71.      *            a progress monitor
  72.      * @return this instance
  73.      */
  74.     public GarbageCollectCommand setProgressMonitor(ProgressMonitor monitor) {
  75.         this.monitor = monitor;
  76.         return this;
  77.     }

  78.     /**
  79.      * During gc() or prune() each unreferenced, loose object which has been
  80.      * created or modified after <code>expire</code> will not be pruned. Only
  81.      * older objects may be pruned. If set to null then every object is a
  82.      * candidate for pruning. Use {@link org.eclipse.jgit.util.GitDateParser} to
  83.      * parse time formats used by git gc.
  84.      *
  85.      * @param expire
  86.      *            minimal age of objects to be pruned.
  87.      * @return this instance
  88.      */
  89.     public GarbageCollectCommand setExpire(Date expire) {
  90.         this.expire = expire;
  91.         return this;
  92.     }

  93.     /**
  94.      * Whether to use aggressive mode or not. If set to true JGit behaves more
  95.      * similar to native git's "git gc --aggressive". If set to
  96.      * <code>true</code> compressed objects found in old packs are not reused
  97.      * but every object is compressed again. Configuration variables
  98.      * pack.window and pack.depth are set to 250 for this GC.
  99.      *
  100.      * @since 3.6
  101.      * @param aggressive
  102.      *            whether to turn on or off aggressive mode
  103.      * @return this instance
  104.      */
  105.     public GarbageCollectCommand setAggressive(boolean aggressive) {
  106.         if (aggressive) {
  107.             StoredConfig repoConfig = repo.getConfig();
  108.             pconfig.setDeltaSearchWindowSize(repoConfig.getInt(
  109.                     ConfigConstants.CONFIG_GC_SECTION,
  110.                     ConfigConstants.CONFIG_KEY_AGGRESSIVE_WINDOW,
  111.                     DEFAULT_GC_AGGRESSIVE_WINDOW));
  112.             pconfig.setMaxDeltaDepth(repoConfig.getInt(
  113.                     ConfigConstants.CONFIG_GC_SECTION,
  114.                     ConfigConstants.CONFIG_KEY_AGGRESSIVE_DEPTH,
  115.                     DEFAULT_GC_AGGRESSIVE_DEPTH));
  116.             pconfig.setReuseObjects(false);
  117.         } else
  118.             pconfig = new PackConfig(repo);
  119.         return this;
  120.     }

  121.     /**
  122.      * Whether to preserve old pack files instead of deleting them.
  123.      *
  124.      * @since 4.7
  125.      * @param preserveOldPacks
  126.      *            whether to preserve old pack files
  127.      * @return this instance
  128.      */
  129.     public GarbageCollectCommand setPreserveOldPacks(boolean preserveOldPacks) {
  130.         if (pconfig == null)
  131.             pconfig = new PackConfig(repo);

  132.         pconfig.setPreserveOldPacks(preserveOldPacks);
  133.         return this;
  134.     }

  135.     /**
  136.      * Whether to prune preserved pack files in the preserved directory.
  137.      *
  138.      * @since 4.7
  139.      * @param prunePreserved
  140.      *            whether to prune preserved pack files
  141.      * @return this instance
  142.      */
  143.     public GarbageCollectCommand setPrunePreserved(boolean prunePreserved) {
  144.         if (pconfig == null)
  145.             pconfig = new PackConfig(repo);

  146.         pconfig.setPrunePreserved(prunePreserved);
  147.         return this;
  148.     }

  149.     /** {@inheritDoc} */
  150.     @Override
  151.     public Properties call() throws GitAPIException {
  152.         checkCallable();

  153.         try {
  154.             if (repo instanceof FileRepository) {
  155.                 GC gc = new GC((FileRepository) repo);
  156.                 gc.setPackConfig(pconfig);
  157.                 gc.setProgressMonitor(monitor);
  158.                 if (this.expire != null)
  159.                     gc.setExpire(expire);

  160.                 try {
  161.                     gc.gc();
  162.                     return toProperties(gc.getStatistics());
  163.                 } catch (ParseException e) {
  164.                     throw new JGitInternalException(JGitText.get().gcFailed, e);
  165.                 }
  166.             } else if (repo instanceof DfsRepository) {
  167.                 DfsGarbageCollector gc =
  168.                     new DfsGarbageCollector((DfsRepository) repo);
  169.                 gc.setPackConfig(pconfig);
  170.                 gc.pack(monitor);
  171.                 return new Properties();
  172.             } else {
  173.                 throw new UnsupportedOperationException(MessageFormat.format(
  174.                         JGitText.get().unsupportedGC,
  175.                         repo.getClass().toString()));
  176.             }
  177.         } catch (IOException e) {
  178.             throw new JGitInternalException(JGitText.get().gcFailed, e);
  179.         }
  180.     }

  181.     /**
  182.      * Computes and returns the repository statistics.
  183.      *
  184.      * @return the repository statistics
  185.      * @throws org.eclipse.jgit.api.errors.GitAPIException
  186.      *             thrown if the repository statistics cannot be computed
  187.      * @since 3.0
  188.      */
  189.     public Properties getStatistics() throws GitAPIException {
  190.         try {
  191.             if (repo instanceof FileRepository) {
  192.                 GC gc = new GC((FileRepository) repo);
  193.                 return toProperties(gc.getStatistics());
  194.             }
  195.             return new Properties();
  196.         } catch (IOException e) {
  197.             throw new JGitInternalException(
  198.                     JGitText.get().couldNotGetRepoStatistics, e);
  199.         }
  200.     }

  201.     @SuppressWarnings("boxing")
  202.     private static Properties toProperties(RepoStatistics stats) {
  203.         Properties p = new Properties();
  204.         p.put("numberOfLooseObjects", stats.numberOfLooseObjects); //$NON-NLS-1$
  205.         p.put("numberOfLooseRefs", stats.numberOfLooseRefs); //$NON-NLS-1$
  206.         p.put("numberOfPackedObjects", stats.numberOfPackedObjects); //$NON-NLS-1$
  207.         p.put("numberOfPackedRefs", stats.numberOfPackedRefs); //$NON-NLS-1$
  208.         p.put("numberOfPackFiles", stats.numberOfPackFiles); //$NON-NLS-1$
  209.         p.put("sizeOfLooseObjects", stats.sizeOfLooseObjects); //$NON-NLS-1$
  210.         p.put("sizeOfPackedObjects", stats.sizeOfPackedObjects); //$NON-NLS-1$
  211.         return p;
  212.     }
  213. }