View Javadoc
1   /*
2    * Copyright (C) 2010, Google Inc.
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.lib;
45  
46  import java.io.IOException;
47  import java.util.ArrayList;
48  import java.util.Collection;
49  import java.util.Iterator;
50  import java.util.List;
51  import java.util.Set;
52  
53  import org.eclipse.jgit.errors.IncorrectObjectTypeException;
54  import org.eclipse.jgit.errors.MissingObjectException;
55  import org.eclipse.jgit.internal.storage.pack.ObjectReuseAsIs;
56  
57  /**
58   * Reads an {@link ObjectDatabase} for a single thread.
59   * <p>
60   * Readers that can support efficient reuse of pack encoded objects should also
61   * implement the companion interface {@link ObjectReuseAsIs}.
62   */
63  public abstract class ObjectReader implements AutoCloseable {
64  	/** Type hint indicating the caller doesn't know the type. */
65  	public static final int OBJ_ANY = -1;
66  
67  	/**
68  	 * Construct a new reader from the same data.
69  	 * <p>
70  	 * Applications can use this method to build a new reader from the same data
71  	 * source, but for an different thread.
72  	 *
73  	 * @return a brand new reader, using the same data source.
74  	 */
75  	public abstract ObjectReader newReader();
76  
77  	/**
78  	 * Obtain a unique abbreviation (prefix) of an object SHA-1.
79  	 *
80  	 * This method uses a reasonable default for the minimum length. Callers who
81  	 * don't care about the minimum length should prefer this method.
82  	 *
83  	 * The returned abbreviation would expand back to the argument ObjectId when
84  	 * passed to {@link #resolve(AbbreviatedObjectId)}, assuming no new objects
85  	 * are added to this repository between calls.
86  	 *
87  	 * @param objectId
88  	 *            object identity that needs to be abbreviated.
89  	 * @return SHA-1 abbreviation.
90  	 * @throws IOException
91  	 *             the object store cannot be read.
92  	 */
93  	public AbbreviatedObjectId abbreviate(AnyObjectId objectId)
94  			throws IOException {
95  		return abbreviate(objectId, 7);
96  	}
97  
98  	/**
99  	 * Obtain a unique abbreviation (prefix) of an object SHA-1.
100 	 *
101 	 * The returned abbreviation would expand back to the argument ObjectId when
102 	 * passed to {@link #resolve(AbbreviatedObjectId)}, assuming no new objects
103 	 * are added to this repository between calls.
104 	 *
105 	 * The default implementation of this method abbreviates the id to the
106 	 * minimum length, then resolves it to see if there are multiple results.
107 	 * When multiple results are found, the length is extended by 1 and resolve
108 	 * is tried again.
109 	 *
110 	 * @param objectId
111 	 *            object identity that needs to be abbreviated.
112 	 * @param len
113 	 *            minimum length of the abbreviated string. Must be in the range
114 	 *            [2, {@value Constants#OBJECT_ID_STRING_LENGTH}].
115 	 * @return SHA-1 abbreviation. If no matching objects exist in the
116 	 *         repository, the abbreviation will match the minimum length.
117 	 * @throws IOException
118 	 *             the object store cannot be read.
119 	 */
120 	public AbbreviatedObjectId abbreviate(AnyObjectId objectId, int len)
121 			throws IOException {
122 		if (len == Constants.OBJECT_ID_STRING_LENGTH)
123 			return AbbreviatedObjectId.fromObjectId(objectId);
124 
125 		AbbreviatedObjectId abbrev = objectId.abbreviate(len);
126 		Collection<ObjectId> matches = resolve(abbrev);
127 		while (1 < matches.size() && len < Constants.OBJECT_ID_STRING_LENGTH) {
128 			abbrev = objectId.abbreviate(++len);
129 			List<ObjectId> n = new ArrayList<ObjectId>(8);
130 			for (ObjectId candidate : matches) {
131 				if (abbrev.prefixCompare(candidate) == 0)
132 					n.add(candidate);
133 			}
134 			if (1 < n.size())
135 				matches = n;
136 			else
137 				matches = resolve(abbrev);
138 		}
139 		return abbrev;
140 	}
141 
142 	/**
143 	 * Resolve an abbreviated ObjectId to its full form.
144 	 *
145 	 * This method searches for an ObjectId that begins with the abbreviation,
146 	 * and returns at least some matching candidates.
147 	 *
148 	 * If the returned collection is empty, no objects start with this
149 	 * abbreviation. The abbreviation doesn't belong to this repository, or the
150 	 * repository lacks the necessary objects to complete it.
151 	 *
152 	 * If the collection contains exactly one member, the abbreviation is
153 	 * (currently) unique within this database. There is a reasonably high
154 	 * probability that the returned id is what was previously abbreviated.
155 	 *
156 	 * If the collection contains 2 or more members, the abbreviation is not
157 	 * unique. In this case the implementation is only required to return at
158 	 * least 2 candidates to signal the abbreviation has conflicts. User
159 	 * friendly implementations should return as many candidates as reasonably
160 	 * possible, as the caller may be able to disambiguate further based on
161 	 * context. However since databases can be very large (e.g. 10 million
162 	 * objects) returning 625,000 candidates for the abbreviation "0" is simply
163 	 * unreasonable, so implementors should draw the line at around 256 matches.
164 	 *
165 	 * @param id
166 	 *            abbreviated id to resolve to a complete identity. The
167 	 *            abbreviation must have a length of at least 2.
168 	 * @return candidates that begin with the abbreviated identity.
169 	 * @throws IOException
170 	 *             the object store cannot be read.
171 	 */
172 	public abstract Collection<ObjectId> resolve(AbbreviatedObjectId id)
173 			throws IOException;
174 
175 	/**
176 	 * Does the requested object exist in this database?
177 	 *
178 	 * @param objectId
179 	 *            identity of the object to test for existence of.
180 	 * @return true if the specified object is stored in this database.
181 	 * @throws IOException
182 	 *             the object store cannot be accessed.
183 	 */
184 	public boolean has(AnyObjectId objectId) throws IOException {
185 		return has(objectId, OBJ_ANY);
186 	}
187 
188 	/**
189 	 * Does the requested object exist in this database?
190 	 *
191 	 * @param objectId
192 	 *            identity of the object to test for existence of.
193 	 * @param typeHint
194 	 *            hint about the type of object being requested, e.g.
195 	 *            {@link Constants#OBJ_BLOB}; {@link #OBJ_ANY} if the object
196 	 *            type is not known, or does not matter to the caller.
197 	 * @return true if the specified object is stored in this database.
198 	 * @throws IncorrectObjectTypeException
199 	 *             typeHint was not OBJ_ANY, and the object's actual type does
200 	 *             not match typeHint.
201 	 * @throws IOException
202 	 *             the object store cannot be accessed.
203 	 */
204 	public boolean has(AnyObjectId objectId, int typeHint) throws IOException {
205 		try {
206 			open(objectId, typeHint);
207 			return true;
208 		} catch (MissingObjectException notFound) {
209 			return false;
210 		}
211 	}
212 
213 	/**
214 	 * Open an object from this database.
215 	 *
216 	 * @param objectId
217 	 *            identity of the object to open.
218 	 * @return a {@link ObjectLoader} for accessing the object.
219 	 * @throws MissingObjectException
220 	 *             the object does not exist.
221 	 * @throws IOException
222 	 *             the object store cannot be accessed.
223 	 */
224 	public ObjectLoader open(AnyObjectId objectId)
225 			throws MissingObjectException, IOException {
226 		return open(objectId, OBJ_ANY);
227 	}
228 
229 	/**
230 	 * Open an object from this database.
231 	 *
232 	 * @param objectId
233 	 *            identity of the object to open.
234 	 * @param typeHint
235 	 *            hint about the type of object being requested, e.g.
236 	 *            {@link Constants#OBJ_BLOB}; {@link #OBJ_ANY} if the object
237 	 *            type is not known, or does not matter to the caller.
238 	 * @return a {@link ObjectLoader} for accessing the object.
239 	 * @throws MissingObjectException
240 	 *             the object does not exist.
241 	 * @throws IncorrectObjectTypeException
242 	 *             typeHint was not OBJ_ANY, and the object's actual type does
243 	 *             not match typeHint.
244 	 * @throws IOException
245 	 *             the object store cannot be accessed.
246 	 */
247 	public abstract ObjectLoader open(AnyObjectId objectId, int typeHint)
248 			throws MissingObjectException, IncorrectObjectTypeException,
249 			IOException;
250 
251 	/**
252 	 * Returns IDs for those commits which should be considered as shallow.
253 	 *
254 	 * @return IDs of shallow commits
255 	 * @throws IOException
256 	 */
257 	public abstract Set<ObjectId> getShallowCommits() throws IOException;
258 
259 	/**
260 	 * Asynchronous object opening.
261 	 *
262 	 * @param <T>
263 	 *            type of identifier being supplied.
264 	 * @param objectIds
265 	 *            objects to open from the object store. The supplied collection
266 	 *            must not be modified until the queue has finished.
267 	 * @param reportMissing
268 	 *            if true missing objects are reported by calling failure with a
269 	 *            MissingObjectException. This may be more expensive for the
270 	 *            implementation to guarantee. If false the implementation may
271 	 *            choose to report MissingObjectException, or silently skip over
272 	 *            the object with no warning.
273 	 * @return queue to read the objects from.
274 	 */
275 	public <T extends ObjectId> AsyncObjectLoaderQueue<T> open(
276 			Iterable<T> objectIds, final boolean reportMissing) {
277 		final Iterator<T> idItr = objectIds.iterator();
278 		return new AsyncObjectLoaderQueue<T>() {
279 			private T cur;
280 
281 			public boolean next() throws MissingObjectException, IOException {
282 				if (idItr.hasNext()) {
283 					cur = idItr.next();
284 					return true;
285 				} else {
286 					return false;
287 				}
288 			}
289 
290 			public T getCurrent() {
291 				return cur;
292 			}
293 
294 			public ObjectId getObjectId() {
295 				return cur;
296 			}
297 
298 			public ObjectLoader open() throws IOException {
299 				return ObjectReader.this.open(cur, OBJ_ANY);
300 			}
301 
302 			public boolean cancel(boolean mayInterruptIfRunning) {
303 				return true;
304 			}
305 
306 			public void release() {
307 				// Since we are sequential by default, we don't
308 				// have any state to clean up if we terminate early.
309 			}
310 		};
311 	}
312 
313 	/**
314 	 * Get only the size of an object.
315 	 * <p>
316 	 * The default implementation of this method opens an ObjectLoader.
317 	 * Databases are encouraged to override this if a faster access method is
318 	 * available to them.
319 	 *
320 	 * @param objectId
321 	 *            identity of the object to open.
322 	 * @param typeHint
323 	 *            hint about the type of object being requested, e.g.
324 	 *            {@link Constants#OBJ_BLOB}; {@link #OBJ_ANY} if the object
325 	 *            type is not known, or does not matter to the caller.
326 	 * @return size of object in bytes.
327 	 * @throws MissingObjectException
328 	 *             the object does not exist.
329 	 * @throws IncorrectObjectTypeException
330 	 *             typeHint was not OBJ_ANY, and the object's actual type does
331 	 *             not match typeHint.
332 	 * @throws IOException
333 	 *             the object store cannot be accessed.
334 	 */
335 	public long getObjectSize(AnyObjectId objectId, int typeHint)
336 			throws MissingObjectException, IncorrectObjectTypeException,
337 			IOException {
338 		return open(objectId, typeHint).getSize();
339 	}
340 
341 	/**
342 	 * Asynchronous object size lookup.
343 	 *
344 	 * @param <T>
345 	 *            type of identifier being supplied.
346 	 * @param objectIds
347 	 *            objects to get the size of from the object store. The supplied
348 	 *            collection must not be modified until the queue has finished.
349 	 * @param reportMissing
350 	 *            if true missing objects are reported by calling failure with a
351 	 *            MissingObjectException. This may be more expensive for the
352 	 *            implementation to guarantee. If false the implementation may
353 	 *            choose to report MissingObjectException, or silently skip over
354 	 *            the object with no warning.
355 	 * @return queue to read object sizes from.
356 	 */
357 	public <T extends ObjectId> AsyncObjectSizeQueue<T> getObjectSize(
358 			Iterable<T> objectIds, final boolean reportMissing) {
359 		final Iterator<T> idItr = objectIds.iterator();
360 		return new AsyncObjectSizeQueue<T>() {
361 			private T cur;
362 
363 			private long sz;
364 
365 			public boolean next() throws MissingObjectException, IOException {
366 				if (idItr.hasNext()) {
367 					cur = idItr.next();
368 					sz = getObjectSize(cur, OBJ_ANY);
369 					return true;
370 				} else {
371 					return false;
372 				}
373 			}
374 
375 			public T getCurrent() {
376 				return cur;
377 			}
378 
379 			public ObjectId getObjectId() {
380 				return cur;
381 			}
382 
383 			public long getSize() {
384 				return sz;
385 			}
386 
387 			public boolean cancel(boolean mayInterruptIfRunning) {
388 				return true;
389 			}
390 
391 			public void release() {
392 				// Since we are sequential by default, we don't
393 				// have any state to clean up if we terminate early.
394 			}
395 		};
396 	}
397 
398 	/**
399 	 * Advise the reader to avoid unreachable objects.
400 	 * <p>
401 	 * While enabled the reader will skip over anything previously proven to be
402 	 * unreachable. This may be dangerous in the face of concurrent writes.
403 	 *
404 	 * @param avoid
405 	 *            true to avoid unreachable objects.
406 	 * @since 3.0
407 	 */
408 	public void setAvoidUnreachableObjects(boolean avoid) {
409 		// Do nothing by default.
410 	}
411 
412 	/**
413 	 * An index that can be used to speed up ObjectWalks.
414 	 *
415 	 * @return the index or null if one does not exist.
416 	 * @throws IOException
417 	 *             when the index fails to load
418 	 * @since 3.0
419 	 */
420 	public BitmapIndex getBitmapIndex() throws IOException {
421 		return null;
422 	}
423 
424 	/**
425 	 * Release any resources used by this reader.
426 	 * <p>
427 	 * A reader that has been released can be used again, but may need to be
428 	 * released after the subsequent usage.
429 	 *
430 	 * @since 4.0
431 	 */
432 	@Override
433 	public abstract void close();
434 }