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.annotations.Nullable;
54  import org.eclipse.jgit.errors.IncorrectObjectTypeException;
55  import org.eclipse.jgit.errors.MissingObjectException;
56  import org.eclipse.jgit.internal.storage.pack.ObjectReuseAsIs;
57  
58  /**
59   * Reads an {@link ObjectDatabase} for a single thread.
60   * <p>
61   * Readers that can support efficient reuse of pack encoded objects should also
62   * implement the companion interface {@link ObjectReuseAsIs}.
63   */
64  public abstract class ObjectReader implements AutoCloseable {
65  	/** Type hint indicating the caller doesn't know the type. */
66  	public static final int OBJ_ANY = -1;
67  
68  	/**
69  	 * The threshold at which a file will be streamed rather than loaded
70  	 * entirely into memory.
71  	 * @since 4.6
72  	 */
73  	protected int streamFileThreshold;
74  
75  	/**
76  	 * Construct a new reader from the same data.
77  	 * <p>
78  	 * Applications can use this method to build a new reader from the same data
79  	 * source, but for an different thread.
80  	 *
81  	 * @return a brand new reader, using the same data source.
82  	 */
83  	public abstract ObjectReader newReader();
84  
85  	/**
86  	 * Obtain a unique abbreviation (prefix) of an object SHA-1.
87  	 *
88  	 * This method uses a reasonable default for the minimum length. Callers who
89  	 * don't care about the minimum length should prefer this method.
90  	 *
91  	 * The returned abbreviation would expand back to the argument ObjectId when
92  	 * passed to {@link #resolve(AbbreviatedObjectId)}, assuming no new objects
93  	 * are added to this repository between calls.
94  	 *
95  	 * @param objectId
96  	 *            object identity that needs to be abbreviated.
97  	 * @return SHA-1 abbreviation.
98  	 * @throws IOException
99  	 *             the object store cannot be read.
100 	 */
101 	public AbbreviatedObjectId abbreviate(AnyObjectId objectId)
102 			throws IOException {
103 		return abbreviate(objectId, 7);
104 	}
105 
106 	/**
107 	 * Obtain a unique abbreviation (prefix) of an object SHA-1.
108 	 *
109 	 * The returned abbreviation would expand back to the argument ObjectId when
110 	 * passed to {@link #resolve(AbbreviatedObjectId)}, assuming no new objects
111 	 * are added to this repository between calls.
112 	 *
113 	 * The default implementation of this method abbreviates the id to the
114 	 * minimum length, then resolves it to see if there are multiple results.
115 	 * When multiple results are found, the length is extended by 1 and resolve
116 	 * is tried again.
117 	 *
118 	 * @param objectId
119 	 *            object identity that needs to be abbreviated.
120 	 * @param len
121 	 *            minimum length of the abbreviated string. Must be in the range
122 	 *            [2, {@value Constants#OBJECT_ID_STRING_LENGTH}].
123 	 * @return SHA-1 abbreviation. If no matching objects exist in the
124 	 *         repository, the abbreviation will match the minimum length.
125 	 * @throws IOException
126 	 *             the object store cannot be read.
127 	 */
128 	public AbbreviatedObjectId abbreviate(AnyObjectId objectId, int len)
129 			throws IOException {
130 		if (len == Constants.OBJECT_ID_STRING_LENGTH)
131 			return AbbreviatedObjectId.fromObjectId(objectId);
132 
133 		AbbreviatedObjectId abbrev = objectId.abbreviate(len);
134 		Collection<ObjectId> matches = resolve(abbrev);
135 		while (1 < matches.size() && len < Constants.OBJECT_ID_STRING_LENGTH) {
136 			abbrev = objectId.abbreviate(++len);
137 			List<ObjectId> n = new ArrayList<>(8);
138 			for (ObjectId candidate : matches) {
139 				if (abbrev.prefixCompare(candidate) == 0)
140 					n.add(candidate);
141 			}
142 			if (1 < n.size())
143 				matches = n;
144 			else
145 				matches = resolve(abbrev);
146 		}
147 		return abbrev;
148 	}
149 
150 	/**
151 	 * Resolve an abbreviated ObjectId to its full form.
152 	 *
153 	 * This method searches for an ObjectId that begins with the abbreviation,
154 	 * and returns at least some matching candidates.
155 	 *
156 	 * If the returned collection is empty, no objects start with this
157 	 * abbreviation. The abbreviation doesn't belong to this repository, or the
158 	 * repository lacks the necessary objects to complete it.
159 	 *
160 	 * If the collection contains exactly one member, the abbreviation is
161 	 * (currently) unique within this database. There is a reasonably high
162 	 * probability that the returned id is what was previously abbreviated.
163 	 *
164 	 * If the collection contains 2 or more members, the abbreviation is not
165 	 * unique. In this case the implementation is only required to return at
166 	 * least 2 candidates to signal the abbreviation has conflicts. User
167 	 * friendly implementations should return as many candidates as reasonably
168 	 * possible, as the caller may be able to disambiguate further based on
169 	 * context. However since databases can be very large (e.g. 10 million
170 	 * objects) returning 625,000 candidates for the abbreviation "0" is simply
171 	 * unreasonable, so implementors should draw the line at around 256 matches.
172 	 *
173 	 * @param id
174 	 *            abbreviated id to resolve to a complete identity. The
175 	 *            abbreviation must have a length of at least 2.
176 	 * @return candidates that begin with the abbreviated identity.
177 	 * @throws IOException
178 	 *             the object store cannot be read.
179 	 */
180 	public abstract Collection<ObjectId> resolve(AbbreviatedObjectId id)
181 			throws IOException;
182 
183 	/**
184 	 * Does the requested object exist in this database?
185 	 *
186 	 * @param objectId
187 	 *            identity of the object to test for existence of.
188 	 * @return true if the specified object is stored in this database.
189 	 * @throws IOException
190 	 *             the object store cannot be accessed.
191 	 */
192 	public boolean has(AnyObjectId objectId) throws IOException {
193 		return has(objectId, OBJ_ANY);
194 	}
195 
196 	/**
197 	 * Does the requested object exist in this database?
198 	 *
199 	 * @param objectId
200 	 *            identity of the object to test for existence of.
201 	 * @param typeHint
202 	 *            hint about the type of object being requested, e.g.
203 	 *            {@link Constants#OBJ_BLOB}; {@link #OBJ_ANY} if the object
204 	 *            type is not known, or does not matter to the caller.
205 	 * @return true if the specified object is stored in this database.
206 	 * @throws IncorrectObjectTypeException
207 	 *             typeHint was not OBJ_ANY, and the object's actual type does
208 	 *             not match typeHint.
209 	 * @throws IOException
210 	 *             the object store cannot be accessed.
211 	 */
212 	public boolean has(AnyObjectId objectId, int typeHint) throws IOException {
213 		try {
214 			open(objectId, typeHint);
215 			return true;
216 		} catch (MissingObjectException notFound) {
217 			return false;
218 		}
219 	}
220 
221 	/**
222 	 * Open an object from this database.
223 	 *
224 	 * @param objectId
225 	 *            identity of the object to open.
226 	 * @return a {@link ObjectLoader} for accessing the object.
227 	 * @throws MissingObjectException
228 	 *             the object does not exist.
229 	 * @throws IOException
230 	 *             the object store cannot be accessed.
231 	 */
232 	public ObjectLoader open(AnyObjectId objectId)
233 			throws MissingObjectException, IOException {
234 		return open(objectId, OBJ_ANY);
235 	}
236 
237 	/**
238 	 * Open an object from this database.
239 	 *
240 	 * @param objectId
241 	 *            identity of the object to open.
242 	 * @param typeHint
243 	 *            hint about the type of object being requested, e.g.
244 	 *            {@link Constants#OBJ_BLOB}; {@link #OBJ_ANY} if the object
245 	 *            type is not known, or does not matter to the caller.
246 	 * @return a {@link ObjectLoader} for accessing the object.
247 	 * @throws MissingObjectException
248 	 *             the object does not exist.
249 	 * @throws IncorrectObjectTypeException
250 	 *             typeHint was not OBJ_ANY, and the object's actual type does
251 	 *             not match typeHint.
252 	 * @throws IOException
253 	 *             the object store cannot be accessed.
254 	 */
255 	public abstract ObjectLoader open(AnyObjectId objectId, int typeHint)
256 			throws MissingObjectException, IncorrectObjectTypeException,
257 			IOException;
258 
259 	/**
260 	 * Returns IDs for those commits which should be considered as shallow.
261 	 *
262 	 * @return IDs of shallow commits
263 	 * @throws IOException
264 	 */
265 	public abstract Set<ObjectId> getShallowCommits() throws IOException;
266 
267 	/**
268 	 * Asynchronous object opening.
269 	 *
270 	 * @param <T>
271 	 *            type of identifier being supplied.
272 	 * @param objectIds
273 	 *            objects to open from the object store. The supplied collection
274 	 *            must not be modified until the queue has finished.
275 	 * @param reportMissing
276 	 *            if true missing objects are reported by calling failure with a
277 	 *            MissingObjectException. This may be more expensive for the
278 	 *            implementation to guarantee. If false the implementation may
279 	 *            choose to report MissingObjectException, or silently skip over
280 	 *            the object with no warning.
281 	 * @return queue to read the objects from.
282 	 */
283 	public <T extends ObjectId> AsyncObjectLoaderQueue<T> open(
284 			Iterable<T> objectIds, final boolean reportMissing) {
285 		final Iterator<T> idItr = objectIds.iterator();
286 		return new AsyncObjectLoaderQueue<T>() {
287 			private T cur;
288 
289 			@Override
290 			public boolean next() throws MissingObjectException, IOException {
291 				if (idItr.hasNext()) {
292 					cur = idItr.next();
293 					return true;
294 				} else {
295 					return false;
296 				}
297 			}
298 
299 			@Override
300 			public T getCurrent() {
301 				return cur;
302 			}
303 
304 			@Override
305 			public ObjectId getObjectId() {
306 				return cur;
307 			}
308 
309 			@Override
310 			public ObjectLoader open() throws IOException {
311 				return ObjectReader.this.open(cur, OBJ_ANY);
312 			}
313 
314 			@Override
315 			public boolean cancel(boolean mayInterruptIfRunning) {
316 				return true;
317 			}
318 
319 			@Override
320 			public void release() {
321 				// Since we are sequential by default, we don't
322 				// have any state to clean up if we terminate early.
323 			}
324 		};
325 	}
326 
327 	/**
328 	 * Get only the size of an object.
329 	 * <p>
330 	 * The default implementation of this method opens an ObjectLoader.
331 	 * Databases are encouraged to override this if a faster access method is
332 	 * available to them.
333 	 *
334 	 * @param objectId
335 	 *            identity of the object to open.
336 	 * @param typeHint
337 	 *            hint about the type of object being requested, e.g.
338 	 *            {@link Constants#OBJ_BLOB}; {@link #OBJ_ANY} if the object
339 	 *            type is not known, or does not matter to the caller.
340 	 * @return size of object in bytes.
341 	 * @throws MissingObjectException
342 	 *             the object does not exist.
343 	 * @throws IncorrectObjectTypeException
344 	 *             typeHint was not OBJ_ANY, and the object's actual type does
345 	 *             not match typeHint.
346 	 * @throws IOException
347 	 *             the object store cannot be accessed.
348 	 */
349 	public long getObjectSize(AnyObjectId objectId, int typeHint)
350 			throws MissingObjectException, IncorrectObjectTypeException,
351 			IOException {
352 		return open(objectId, typeHint).getSize();
353 	}
354 
355 	/**
356 	 * Asynchronous object size lookup.
357 	 *
358 	 * @param <T>
359 	 *            type of identifier being supplied.
360 	 * @param objectIds
361 	 *            objects to get the size of from the object store. The supplied
362 	 *            collection must not be modified until the queue has finished.
363 	 * @param reportMissing
364 	 *            if true missing objects are reported by calling failure with a
365 	 *            MissingObjectException. This may be more expensive for the
366 	 *            implementation to guarantee. If false the implementation may
367 	 *            choose to report MissingObjectException, or silently skip over
368 	 *            the object with no warning.
369 	 * @return queue to read object sizes from.
370 	 */
371 	public <T extends ObjectId> AsyncObjectSizeQueue<T> getObjectSize(
372 			Iterable<T> objectIds, final boolean reportMissing) {
373 		final Iterator<T> idItr = objectIds.iterator();
374 		return new AsyncObjectSizeQueue<T>() {
375 			private T cur;
376 
377 			private long sz;
378 
379 			@Override
380 			public boolean next() throws MissingObjectException, IOException {
381 				if (idItr.hasNext()) {
382 					cur = idItr.next();
383 					sz = getObjectSize(cur, OBJ_ANY);
384 					return true;
385 				} else {
386 					return false;
387 				}
388 			}
389 
390 			@Override
391 			public T getCurrent() {
392 				return cur;
393 			}
394 
395 			@Override
396 			public ObjectId getObjectId() {
397 				return cur;
398 			}
399 
400 			@Override
401 			public long getSize() {
402 				return sz;
403 			}
404 
405 			@Override
406 			public boolean cancel(boolean mayInterruptIfRunning) {
407 				return true;
408 			}
409 
410 			@Override
411 			public void release() {
412 				// Since we are sequential by default, we don't
413 				// have any state to clean up if we terminate early.
414 			}
415 		};
416 	}
417 
418 	/**
419 	 * Advise the reader to avoid unreachable objects.
420 	 * <p>
421 	 * While enabled the reader will skip over anything previously proven to be
422 	 * unreachable. This may be dangerous in the face of concurrent writes.
423 	 *
424 	 * @param avoid
425 	 *            true to avoid unreachable objects.
426 	 * @since 3.0
427 	 */
428 	public void setAvoidUnreachableObjects(boolean avoid) {
429 		// Do nothing by default.
430 	}
431 
432 	/**
433 	 * An index that can be used to speed up ObjectWalks.
434 	 *
435 	 * @return the index or null if one does not exist.
436 	 * @throws IOException
437 	 *             when the index fails to load
438 	 * @since 3.0
439 	 */
440 	public BitmapIndex getBitmapIndex() throws IOException {
441 		return null;
442 	}
443 
444 	/**
445 	 * @return the {@link ObjectInserter} from which this reader was created
446 	 *         using {@code inserter.newReader()}, or null if this reader was not
447 	 *         created from an inserter.
448 	 * @since 4.4
449 	 */
450 	@Nullable
451 	public ObjectInserter getCreatedFromInserter() {
452 		return null;
453 	}
454 
455 	/**
456 	 * Release any resources used by this reader.
457 	 * <p>
458 	 * A reader that has been released can be used again, but may need to be
459 	 * released after the subsequent usage.
460 	 *
461 	 * @since 4.0
462 	 */
463 	@Override
464 	public abstract void close();
465 
466 	/**
467 	 * Sets the threshold at which a file will be streamed rather than loaded
468 	 * entirely into memory
469 	 *
470 	 * @param threshold
471 	 *            the new threshold
472 	 * @since 4.6
473 	 */
474 	public void setStreamFileThreshold(int threshold) {
475 		streamFileThreshold = threshold;
476 	}
477 
478 	/**
479 	 * Returns the threshold at which a file will be streamed rather than loaded
480 	 * entirely into memory
481 	 *
482 	 * @return the threshold in bytes
483 	 * @since 4.6
484 	 */
485 	public int getStreamFileThreshold() {
486 		return streamFileThreshold;
487 	}
488 
489 	/**
490 	 * Wraps a delegate ObjectReader.
491 	 *
492 	 * @since 4.4
493 	 */
494 	public static abstract class Filter extends ObjectReader {
495 		/**
496 		 * @return delegate ObjectReader to handle all processing.
497 		 * @since 4.4
498 		 */
499 		protected abstract ObjectReader delegate();
500 
501 		@Override
502 		public ObjectReader newReader() {
503 			return delegate().newReader();
504 		}
505 
506 		@Override
507 		public AbbreviatedObjectId abbreviate(AnyObjectId objectId)
508 				throws IOException {
509 			return delegate().abbreviate(objectId);
510 		}
511 
512 		@Override
513 		public AbbreviatedObjectId abbreviate(AnyObjectId objectId, int len)
514 				throws IOException {
515 			return delegate().abbreviate(objectId, len);
516 		}
517 
518 		@Override
519 		public Collection<ObjectId> resolve(AbbreviatedObjectId id)
520 				throws IOException {
521 			return delegate().resolve(id);
522 		}
523 
524 		@Override
525 		public boolean has(AnyObjectId objectId) throws IOException {
526 			return delegate().has(objectId);
527 		}
528 
529 		@Override
530 		public boolean has(AnyObjectId objectId, int typeHint) throws IOException {
531 			return delegate().has(objectId, typeHint);
532 		}
533 
534 		@Override
535 		public ObjectLoader open(AnyObjectId objectId)
536 				throws MissingObjectException, IOException {
537 			return delegate().open(objectId);
538 		}
539 
540 		@Override
541 		public ObjectLoader open(AnyObjectId objectId, int typeHint)
542 				throws MissingObjectException, IncorrectObjectTypeException,
543 				IOException {
544 			return delegate().open(objectId, typeHint);
545 		}
546 
547 		@Override
548 		public Set<ObjectId> getShallowCommits() throws IOException {
549 			return delegate().getShallowCommits();
550 		}
551 
552 		@Override
553 		public <T extends ObjectId> AsyncObjectLoaderQueue<T> open(
554 				Iterable<T> objectIds, boolean reportMissing) {
555 			return delegate().open(objectIds, reportMissing);
556 		}
557 
558 		@Override
559 		public long getObjectSize(AnyObjectId objectId, int typeHint)
560 				throws MissingObjectException, IncorrectObjectTypeException,
561 				IOException {
562 			return delegate().getObjectSize(objectId, typeHint);
563 		}
564 
565 		@Override
566 		public <T extends ObjectId> AsyncObjectSizeQueue<T> getObjectSize(
567 				Iterable<T> objectIds, boolean reportMissing) {
568 			return delegate().getObjectSize(objectIds, reportMissing);
569 		}
570 
571 		@Override
572 		public void setAvoidUnreachableObjects(boolean avoid) {
573 			delegate().setAvoidUnreachableObjects(avoid);
574 		}
575 
576 		@Override
577 		public BitmapIndex getBitmapIndex() throws IOException {
578 			return delegate().getBitmapIndex();
579 		}
580 
581 		@Override
582 		@Nullable
583 		public ObjectInserter getCreatedFromInserter() {
584 			return delegate().getCreatedFromInserter();
585 		}
586 
587 		@Override
588 		public void close() {
589 			delegate().close();
590 		}
591 	}
592 }