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 java.util.concurrent.ExecutionException;

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

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

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

  55.     private ProgressMonitor monitor;

  56.     private Date expire;

  57.     private PackConfig pconfig;

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

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

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

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

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

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

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

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

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

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

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

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

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