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 }