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 }