View Javadoc
1   /*
2    * Copyright (C) 2011, 2013 Google Inc., and others.
3    * and other copyright owners as documented in the project's IP log.
4    *
5    * This program and the accompanying materials are made available
6    * under the terms of the Eclipse Distribution License v1.0 which
7    * accompanies this distribution, is reproduced below, and is
8    * available at http://www.eclipse.org/org/documents/edl-v10.php
9    *
10   * All rights reserved.
11   *
12   * Redistribution and use in source and binary forms, with or
13   * without modification, are permitted provided that the following
14   * conditions are met:
15   *
16   * - Redistributions of source code must retain the above copyright
17   *   notice, this list of conditions and the following disclaimer.
18   *
19   * - Redistributions in binary form must reproduce the above
20   *   copyright notice, this list of conditions and the following
21   *   disclaimer in the documentation and/or other materials provided
22   *   with the distribution.
23   *
24   * - Neither the name of the Eclipse Foundation, Inc. nor the
25   *   names of its contributors may be used to endorse or promote
26   *   products derived from this software without specific prior
27   *   written permission.
28   *
29   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
30   * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
31   * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
32   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
33   * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
34   * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
35   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
36   * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
37   * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
38   * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39   * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
40   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
41   * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
42   */
43  
44  package org.eclipse.jgit.internal.storage.dfs;
45  
46  import static org.eclipse.jgit.internal.storage.pack.PackExt.PACK;
47  
48  import java.util.HashMap;
49  import java.util.Map;
50  
51  import org.eclipse.jgit.internal.storage.dfs.DfsObjDatabase.PackSource;
52  import org.eclipse.jgit.internal.storage.pack.PackExt;
53  import org.eclipse.jgit.storage.pack.PackStatistics;
54  
55  /**
56   * Description of a DFS stored pack/index file.
57   * <p>
58   * Implementors may extend this class and add additional data members.
59   * <p>
60   * Instances of this class are cached with the DfsPackFile, and should not be
61   * modified once initialized and presented to the JGit DFS library.
62   */
63  public class DfsPackDescription implements Comparable<DfsPackDescription> {
64  	private final DfsRepositoryDescription repoDesc;
65  
66  	private final String packName;
67  
68  	private PackSource packSource;
69  
70  	private long lastModified;
71  
72  	private final Map<PackExt, Long> sizeMap;
73  
74  	private long objectCount;
75  
76  	private long deltaCount;
77  
78  	private PackStatistics stats;
79  
80  	private int extensions;
81  
82  	private int indexVersion;
83  
84  	/**
85  	 * Initialize a description by pack name and repository.
86  	 * <p>
87  	 * The corresponding index file is assumed to exist. If this is not true
88  	 * implementors must extend the class and override
89  	 * {@link #getFileName(PackExt)}.
90  	 * <p>
91  	 * Callers should also try to fill in other fields if they are reasonably
92  	 * free to access at the time this instance is being initialized.
93  	 *
94  	 * @param name
95  	 *            name of the pack file. Must end with ".pack".
96  	 * @param repoDesc
97  	 *            description of the repo containing the pack file.
98  	 */
99  	public DfsPackDescription(DfsRepositoryDescription repoDesc, String name) {
100 		this.repoDesc = repoDesc;
101 		int dot = name.lastIndexOf('.');
102 		this.packName = (dot < 0) ? name : name.substring(0, dot);
103 		this.sizeMap = new HashMap<PackExt, Long>(PackExt.values().length * 2);
104 	}
105 
106 	/** @return description of the repository. */
107 	public DfsRepositoryDescription getRepositoryDescription() {
108 		return repoDesc;
109 	}
110 
111 	/**
112 	 * Adds the pack file extension to the known list.
113 	 *
114 	 * @param ext
115 	 *            the file extension
116 	 */
117 	public void addFileExt(PackExt ext) {
118 		extensions |= ext.getBit();
119 	}
120 
121 	/**
122 	 * @param ext
123 	 *            the file extension
124 	 * @return whether the pack file extensions is known to exist.
125 	 */
126 	public boolean hasFileExt(PackExt ext) {
127 		return (extensions & ext.getBit()) != 0;
128 	}
129 
130 	/**
131 	 * @param ext
132 	 *            the file extension
133 	 * @return name of the file.
134 	 */
135 	public String getFileName(PackExt ext) {
136 		return packName + '.' + ext.getExtension();
137 	}
138 
139 	/** @return the source of the pack. */
140 	public PackSource getPackSource() {
141 		return packSource;
142 	}
143 
144 	/**
145 	 * @param source
146 	 *            the source of the pack.
147 	 * @return {@code this}
148 	 */
149 	public DfsPackDescription setPackSource(PackSource source) {
150 		packSource = source;
151 		return this;
152 	}
153 
154 	/** @return time the pack was created, in milliseconds. */
155 	public long getLastModified() {
156 		return lastModified;
157 	}
158 
159 	/**
160 	 * @param timeMillis
161 	 *            time the pack was created, in milliseconds. 0 if not known.
162 	 * @return {@code this}
163 	 */
164 	public DfsPackDescription setLastModified(long timeMillis) {
165 		lastModified = timeMillis;
166 		return this;
167 	}
168 
169 	/**
170 	 * @param ext
171 	 *            the file extension.
172 	 * @param bytes
173 	 *            size of the file in bytes. If 0 the file is not known and will
174 	 *            be determined on first read.
175 	 * @return {@code this}
176 	 */
177 	public DfsPackDescription setFileSize(PackExt ext, long bytes) {
178 		sizeMap.put(ext, Long.valueOf(Math.max(0, bytes)));
179 		return this;
180 	}
181 
182 	/**
183 	 * @param ext
184 	 *            the file extension.
185 	 * @return size of the file, in bytes. If 0 the file size is not yet known.
186 	 */
187 	public long getFileSize(PackExt ext) {
188 		Long size = sizeMap.get(ext);
189 		return size == null ? 0 : size.longValue();
190 	}
191 
192 	/** @return number of objects in the pack. */
193 	public long getObjectCount() {
194 		return objectCount;
195 	}
196 
197 	/**
198 	 * @param cnt
199 	 *            number of objects in the pack.
200 	 * @return {@code this}
201 	 */
202 	public DfsPackDescription setObjectCount(long cnt) {
203 		objectCount = Math.max(0, cnt);
204 		return this;
205 	}
206 
207 	/** @return number of delta compressed objects in the pack. */
208 	public long getDeltaCount() {
209 		return deltaCount;
210 	}
211 
212 	/**
213 	 * @param cnt
214 	 *            number of delta compressed objects in the pack.
215 	 * @return {@code this}
216 	 */
217 	public DfsPackDescription setDeltaCount(long cnt) {
218 		deltaCount = Math.max(0, cnt);
219 		return this;
220 	}
221 
222 	/**
223 	 * @return statistics from PackWriter, if the pack was built with it.
224 	 *         Generally this is only available for packs created by
225 	 *         DfsGarbageCollector or DfsPackCompactor, and only when the pack
226 	 *         is being committed to the repository.
227 	 */
228 	public PackStatistics getPackStats() {
229 		return stats;
230 	}
231 
232 	DfsPackDescription setPackStats(PackStatistics stats) {
233 		this.stats = stats;
234 		setFileSize(PACK, stats.getTotalBytes());
235 		setObjectCount(stats.getTotalObjects());
236 		setDeltaCount(stats.getTotalDeltas());
237 		return this;
238 	}
239 
240 	/**
241 	 * Discard the pack statistics, if it was populated.
242 	 *
243 	 * @return {@code this}
244 	 */
245 	public DfsPackDescription clearPackStats() {
246 		stats = null;
247 		return this;
248 	}
249 
250 	/** @return the version of the index file written. */
251 	public int getIndexVersion() {
252 		return indexVersion;
253 	}
254 
255 	/**
256 	 * @param version
257 	 *            the version of the index file written.
258 	 * @return {@code this}
259 	 */
260 	public DfsPackDescription setIndexVersion(int version) {
261 		indexVersion = version;
262 		return this;
263 	}
264 
265 	@Override
266 	public int hashCode() {
267 		return packName.hashCode();
268 	}
269 
270 	@Override
271 	public boolean equals(Object b) {
272 		if (b instanceof DfsPackDescription) {
273 			DfsPackDescription desc = (DfsPackDescription) b;
274 			return packName.equals(desc.packName) &&
275 					getRepositoryDescription().equals(desc.getRepositoryDescription());
276 		}
277 		return false;
278 	}
279 
280 	/**
281 	 * Sort packs according to the optimal lookup ordering.
282 	 * <p>
283 	 * This method tries to position packs in the order readers should examine
284 	 * them when looking for objects by SHA-1. The default tries to sort packs
285 	 * with more recent modification dates before older packs, and packs with
286 	 * fewer objects before packs with more objects.
287 	 *
288 	 * @param b
289 	 *            the other pack.
290 	 */
291 	public int compareTo(DfsPackDescription b) {
292 		// Cluster by PackSource, pushing UNREACHABLE_GARBAGE to the end.
293 		PackSource as = getPackSource();
294 		PackSource bs = b.getPackSource();
295 		if (as != null && bs != null) {
296 			int cmp = as.category - bs.category;
297 			if (cmp != 0)
298 				return cmp;
299 		}
300 
301 		// Newer packs should sort first.
302 		int cmp = Long.signum(b.getLastModified() - getLastModified());
303 		if (cmp != 0)
304 			return cmp;
305 
306 		// Break ties on smaller index. Readers may get lucky and find
307 		// the object they care about in the smaller index. This also pushes
308 		// big historical packs to the end of the list, due to more objects.
309 		return Long.signum(getObjectCount() - b.getObjectCount());
310 	}
311 
312 	@Override
313 	public String toString() {
314 		return getFileName(PackExt.PACK);
315 	}
316 }