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