View Javadoc
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  
12  import java.io.IOException;
13  import java.text.MessageFormat;
14  import java.text.ParseException;
15  import java.util.Date;
16  import java.util.Properties;
17  
18  import org.eclipse.jgit.api.errors.GitAPIException;
19  import org.eclipse.jgit.api.errors.JGitInternalException;
20  import org.eclipse.jgit.internal.JGitText;
21  import org.eclipse.jgit.internal.storage.dfs.DfsGarbageCollector;
22  import org.eclipse.jgit.internal.storage.dfs.DfsRepository;
23  import org.eclipse.jgit.internal.storage.file.FileRepository;
24  import org.eclipse.jgit.internal.storage.file.GC;
25  import org.eclipse.jgit.internal.storage.file.GC.RepoStatistics;
26  import org.eclipse.jgit.lib.ConfigConstants;
27  import org.eclipse.jgit.lib.ProgressMonitor;
28  import org.eclipse.jgit.lib.Repository;
29  import org.eclipse.jgit.lib.StoredConfig;
30  import org.eclipse.jgit.storage.pack.PackConfig;
31  
32  /**
33   * A class used to execute a {@code gc} command. It has setters for all
34   * supported options and arguments of this command and a {@link #call()} method
35   * to finally execute the command. Each instance of this class should only be
36   * used for one invocation of the command (means: one call to {@link #call()})
37   *
38   * @since 2.2
39   * @see <a href="http://www.kernel.org/pub/software/scm/git/docs/git-gc.html"
40   *      >Git documentation about gc</a>
41   */
42  public class GarbageCollectCommand extends GitCommand<Properties> {
43  	/**
44  	 * Default value of maximum delta chain depth during aggressive garbage
45  	 * collection: {@value}
46  	 *
47  	 * @since 3.6
48  	 */
49  	public static final int DEFAULT_GC_AGGRESSIVE_DEPTH = 250;
50  
51  	/**
52  	 * Default window size during packing during aggressive garbage collection:
53  	 * * {@value}
54  	 *
55  	 * @since 3.6
56  	 */
57  	public static final int DEFAULT_GC_AGGRESSIVE_WINDOW = 250;
58  
59  	private ProgressMonitor monitor;
60  
61  	private Date expire;
62  
63  	private PackConfig pconfig;
64  
65  	/**
66  	 * Constructor for GarbageCollectCommand.
67  	 *
68  	 * @param repo
69  	 *            a {@link org.eclipse.jgit.lib.Repository} object.
70  	 */
71  	protected GarbageCollectCommand(Repository repo) {
72  		super(repo);
73  		pconfig = new PackConfig(repo);
74  	}
75  
76  	/**
77  	 * Set progress monitor
78  	 *
79  	 * @param monitor
80  	 *            a progress monitor
81  	 * @return this instance
82  	 */
83  	public GarbageCollectCommand setProgressMonitor(ProgressMonitor monitor) {
84  		this.monitor = monitor;
85  		return this;
86  	}
87  
88  	/**
89  	 * During gc() or prune() each unreferenced, loose object which has been
90  	 * created or modified after <code>expire</code> will not be pruned. Only
91  	 * older objects may be pruned. If set to null then every object is a
92  	 * candidate for pruning. Use {@link org.eclipse.jgit.util.GitDateParser} to
93  	 * parse time formats used by git gc.
94  	 *
95  	 * @param expire
96  	 *            minimal age of objects to be pruned.
97  	 * @return this instance
98  	 */
99  	public GarbageCollectCommand setExpire(Date expire) {
100 		this.expire = expire;
101 		return this;
102 	}
103 
104 	/**
105 	 * Whether to use aggressive mode or not. If set to true JGit behaves more
106 	 * similar to native git's "git gc --aggressive". If set to
107 	 * <code>true</code> compressed objects found in old packs are not reused
108 	 * but every object is compressed again. Configuration variables
109 	 * pack.window and pack.depth are set to 250 for this GC.
110 	 *
111 	 * @since 3.6
112 	 * @param aggressive
113 	 *            whether to turn on or off aggressive mode
114 	 * @return this instance
115 	 */
116 	public GarbageCollectCommand setAggressive(boolean aggressive) {
117 		if (aggressive) {
118 			StoredConfig repoConfig = repo.getConfig();
119 			pconfig.setDeltaSearchWindowSize(repoConfig.getInt(
120 					ConfigConstants.CONFIG_GC_SECTION,
121 					ConfigConstants.CONFIG_KEY_AGGRESSIVE_WINDOW,
122 					DEFAULT_GC_AGGRESSIVE_WINDOW));
123 			pconfig.setMaxDeltaDepth(repoConfig.getInt(
124 					ConfigConstants.CONFIG_GC_SECTION,
125 					ConfigConstants.CONFIG_KEY_AGGRESSIVE_DEPTH,
126 					DEFAULT_GC_AGGRESSIVE_DEPTH));
127 			pconfig.setReuseObjects(false);
128 		} else
129 			pconfig = new PackConfig(repo);
130 		return this;
131 	}
132 
133 	/**
134 	 * Whether to preserve old pack files instead of deleting them.
135 	 *
136 	 * @since 4.7
137 	 * @param preserveOldPacks
138 	 *            whether to preserve old pack files
139 	 * @return this instance
140 	 */
141 	public GarbageCollectCommand setPreserveOldPacks(boolean preserveOldPacks) {
142 		if (pconfig == null)
143 			pconfig = new PackConfig(repo);
144 
145 		pconfig.setPreserveOldPacks(preserveOldPacks);
146 		return this;
147 	}
148 
149 	/**
150 	 * Whether to prune preserved pack files in the preserved directory.
151 	 *
152 	 * @since 4.7
153 	 * @param prunePreserved
154 	 *            whether to prune preserved pack files
155 	 * @return this instance
156 	 */
157 	public GarbageCollectCommand setPrunePreserved(boolean prunePreserved) {
158 		if (pconfig == null)
159 			pconfig = new PackConfig(repo);
160 
161 		pconfig.setPrunePreserved(prunePreserved);
162 		return this;
163 	}
164 
165 	/** {@inheritDoc} */
166 	@Override
167 	public Properties call() throws GitAPIException {
168 		checkCallable();
169 
170 		try {
171 			if (repo instanceof FileRepository) {
172 				GC gc = new GC((FileRepository) repo);
173 				gc.setPackConfig(pconfig);
174 				gc.setProgressMonitor(monitor);
175 				if (this.expire != null)
176 					gc.setExpire(expire);
177 
178 				try {
179 					gc.gc();
180 					return toProperties(gc.getStatistics());
181 				} catch (ParseException e) {
182 					throw new JGitInternalException(JGitText.get().gcFailed, e);
183 				}
184 			} else if (repo instanceof DfsRepository) {
185 				DfsGarbageCollector gc =
186 					new DfsGarbageCollector((DfsRepository) repo);
187 				gc.setPackConfig(pconfig);
188 				gc.pack(monitor);
189 				return new Properties();
190 			} else {
191 				throw new UnsupportedOperationException(MessageFormat.format(
192 						JGitText.get().unsupportedGC,
193 						repo.getClass().toString()));
194 			}
195 		} catch (IOException e) {
196 			throw new JGitInternalException(JGitText.get().gcFailed, e);
197 		}
198 	}
199 
200 	/**
201 	 * Computes and returns the repository statistics.
202 	 *
203 	 * @return the repository statistics
204 	 * @throws org.eclipse.jgit.api.errors.GitAPIException
205 	 *             thrown if the repository statistics cannot be computed
206 	 * @since 3.0
207 	 */
208 	public Properties getStatistics() throws GitAPIException {
209 		try {
210 			if (repo instanceof FileRepository) {
211 				GC gc = new GC((FileRepository) repo);
212 				return toProperties(gc.getStatistics());
213 			}
214 			return new Properties();
215 		} catch (IOException e) {
216 			throw new JGitInternalException(
217 					JGitText.get().couldNotGetRepoStatistics, e);
218 		}
219 	}
220 
221 	@SuppressWarnings("boxing")
222 	private static Properties toProperties(RepoStatistics stats) {
223 		Properties p = new Properties();
224 		p.put("numberOfLooseObjects", stats.numberOfLooseObjects); //$NON-NLS-1$
225 		p.put("numberOfLooseRefs", stats.numberOfLooseRefs); //$NON-NLS-1$
226 		p.put("numberOfPackedObjects", stats.numberOfPackedObjects); //$NON-NLS-1$
227 		p.put("numberOfPackedRefs", stats.numberOfPackedRefs); //$NON-NLS-1$
228 		p.put("numberOfPackFiles", stats.numberOfPackFiles); //$NON-NLS-1$
229 		p.put("sizeOfLooseObjects", stats.sizeOfLooseObjects); //$NON-NLS-1$
230 		p.put("sizeOfPackedObjects", stats.sizeOfPackedObjects); //$NON-NLS-1$
231 		return p;
232 	}
233 }