ObjectReader.java

  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. package org.eclipse.jgit.lib;

  11. import java.io.IOException;
  12. import java.util.ArrayList;
  13. import java.util.Collection;
  14. import java.util.Iterator;
  15. import java.util.List;
  16. import java.util.Set;

  17. import org.eclipse.jgit.annotations.NonNull;
  18. import org.eclipse.jgit.annotations.Nullable;
  19. import org.eclipse.jgit.errors.IncorrectObjectTypeException;
  20. import org.eclipse.jgit.errors.MissingObjectException;
  21. import org.eclipse.jgit.internal.revwalk.BitmappedObjectReachabilityChecker;
  22. import org.eclipse.jgit.internal.revwalk.BitmappedReachabilityChecker;
  23. import org.eclipse.jgit.internal.revwalk.PedestrianObjectReachabilityChecker;
  24. import org.eclipse.jgit.internal.revwalk.PedestrianReachabilityChecker;
  25. import org.eclipse.jgit.revwalk.ObjectReachabilityChecker;
  26. import org.eclipse.jgit.revwalk.ObjectWalk;
  27. import org.eclipse.jgit.revwalk.ReachabilityChecker;
  28. import org.eclipse.jgit.revwalk.RevWalk;

  29. /**
  30.  * Reads an {@link org.eclipse.jgit.lib.ObjectDatabase} for a single thread.
  31.  * <p>
  32.  * Readers that can support efficient reuse of pack encoded objects should also
  33.  * implement the companion interface
  34.  * {@link org.eclipse.jgit.internal.storage.pack.ObjectReuseAsIs}.
  35.  */
  36. public abstract class ObjectReader implements AutoCloseable {
  37.     /** Type hint indicating the caller doesn't know the type. */
  38.     public static final int OBJ_ANY = -1;

  39.     /**
  40.      * The threshold at which a file will be streamed rather than loaded
  41.      * entirely into memory.
  42.      * @since 4.6
  43.      */
  44.     protected int streamFileThreshold;

  45.     /**
  46.      * Construct a new reader from the same data.
  47.      * <p>
  48.      * Applications can use this method to build a new reader from the same data
  49.      * source, but for an different thread.
  50.      *
  51.      * @return a brand new reader, using the same data source.
  52.      */
  53.     public abstract ObjectReader newReader();

  54.     /**
  55.      * Obtain a unique abbreviation (prefix) of an object SHA-1.
  56.      *
  57.      * This method uses a reasonable default for the minimum length. Callers who
  58.      * don't care about the minimum length should prefer this method.
  59.      *
  60.      * The returned abbreviation would expand back to the argument ObjectId when
  61.      * passed to {@link #resolve(AbbreviatedObjectId)}, assuming no new objects
  62.      * are added to this repository between calls.
  63.      *
  64.      * @param objectId
  65.      *            object identity that needs to be abbreviated.
  66.      * @return SHA-1 abbreviation.
  67.      * @throws java.io.IOException
  68.      *             the object store cannot be read.
  69.      */
  70.     public AbbreviatedObjectId abbreviate(AnyObjectId objectId)
  71.             throws IOException {
  72.         return abbreviate(objectId, 7);
  73.     }

  74.     /**
  75.      * Obtain a unique abbreviation (prefix) of an object SHA-1.
  76.      *
  77.      * The returned abbreviation would expand back to the argument ObjectId when
  78.      * passed to {@link #resolve(AbbreviatedObjectId)}, assuming no new objects
  79.      * are added to this repository between calls.
  80.      *
  81.      * The default implementation of this method abbreviates the id to the
  82.      * minimum length, then resolves it to see if there are multiple results.
  83.      * When multiple results are found, the length is extended by 1 and resolve
  84.      * is tried again.
  85.      *
  86.      * @param objectId
  87.      *            object identity that needs to be abbreviated.
  88.      * @param len
  89.      *            minimum length of the abbreviated string. Must be in the range
  90.      *            [2, {@value Constants#OBJECT_ID_STRING_LENGTH}].
  91.      * @return SHA-1 abbreviation. If no matching objects exist in the
  92.      *         repository, the abbreviation will match the minimum length.
  93.      * @throws java.io.IOException
  94.      *             the object store cannot be read.
  95.      */
  96.     public AbbreviatedObjectId abbreviate(AnyObjectId objectId, int len)
  97.             throws IOException {
  98.         if (len == Constants.OBJECT_ID_STRING_LENGTH)
  99.             return AbbreviatedObjectId.fromObjectId(objectId);

  100.         AbbreviatedObjectId abbrev = objectId.abbreviate(len);
  101.         Collection<ObjectId> matches = resolve(abbrev);
  102.         while (1 < matches.size() && len < Constants.OBJECT_ID_STRING_LENGTH) {
  103.             abbrev = objectId.abbreviate(++len);
  104.             List<ObjectId> n = new ArrayList<>(8);
  105.             for (ObjectId candidate : matches) {
  106.                 if (abbrev.prefixCompare(candidate) == 0)
  107.                     n.add(candidate);
  108.             }
  109.             if (1 < n.size())
  110.                 matches = n;
  111.             else
  112.                 matches = resolve(abbrev);
  113.         }
  114.         return abbrev;
  115.     }

  116.     /**
  117.      * Resolve an abbreviated ObjectId to its full form.
  118.      *
  119.      * This method searches for an ObjectId that begins with the abbreviation,
  120.      * and returns at least some matching candidates.
  121.      *
  122.      * If the returned collection is empty, no objects start with this
  123.      * abbreviation. The abbreviation doesn't belong to this repository, or the
  124.      * repository lacks the necessary objects to complete it.
  125.      *
  126.      * If the collection contains exactly one member, the abbreviation is
  127.      * (currently) unique within this database. There is a reasonably high
  128.      * probability that the returned id is what was previously abbreviated.
  129.      *
  130.      * If the collection contains 2 or more members, the abbreviation is not
  131.      * unique. In this case the implementation is only required to return at
  132.      * least 2 candidates to signal the abbreviation has conflicts. User
  133.      * friendly implementations should return as many candidates as reasonably
  134.      * possible, as the caller may be able to disambiguate further based on
  135.      * context. However since databases can be very large (e.g. 10 million
  136.      * objects) returning 625,000 candidates for the abbreviation "0" is simply
  137.      * unreasonable, so implementors should draw the line at around 256 matches.
  138.      *
  139.      * @param id
  140.      *            abbreviated id to resolve to a complete identity. The
  141.      *            abbreviation must have a length of at least 2.
  142.      * @return candidates that begin with the abbreviated identity.
  143.      * @throws java.io.IOException
  144.      *             the object store cannot be read.
  145.      */
  146.     public abstract Collection<ObjectId> resolve(AbbreviatedObjectId id)
  147.             throws IOException;

  148.     /**
  149.      * Does the requested object exist in this database?
  150.      *
  151.      * @param objectId
  152.      *            identity of the object to test for existence of.
  153.      * @return true if the specified object is stored in this database.
  154.      * @throws java.io.IOException
  155.      *             the object store cannot be accessed.
  156.      */
  157.     public boolean has(AnyObjectId objectId) throws IOException {
  158.         return has(objectId, OBJ_ANY);
  159.     }

  160.     /**
  161.      * Does the requested object exist in this database?
  162.      *
  163.      * @param objectId
  164.      *            identity of the object to test for existence of.
  165.      * @param typeHint
  166.      *            hint about the type of object being requested, e.g.
  167.      *            {@link org.eclipse.jgit.lib.Constants#OBJ_BLOB};
  168.      *            {@link #OBJ_ANY} if the object type is not known, or does not
  169.      *            matter to the caller.
  170.      * @return true if the specified object is stored in this database.
  171.      * @throws IncorrectObjectTypeException
  172.      *             typeHint was not OBJ_ANY, and the object's actual type does
  173.      *             not match typeHint.
  174.      * @throws java.io.IOException
  175.      *             the object store cannot be accessed.
  176.      */
  177.     public boolean has(AnyObjectId objectId, int typeHint) throws IOException {
  178.         try {
  179.             open(objectId, typeHint);
  180.             return true;
  181.         } catch (MissingObjectException notFound) {
  182.             return false;
  183.         }
  184.     }

  185.     /**
  186.      * Open an object from this database.
  187.      *
  188.      * @param objectId
  189.      *            identity of the object to open.
  190.      * @return a {@link org.eclipse.jgit.lib.ObjectLoader} for accessing the
  191.      *         object.
  192.      * @throws org.eclipse.jgit.errors.MissingObjectException
  193.      *             the object does not exist.
  194.      * @throws java.io.IOException
  195.      *             the object store cannot be accessed.
  196.      */
  197.     public ObjectLoader open(AnyObjectId objectId)
  198.             throws MissingObjectException, IOException {
  199.         return open(objectId, OBJ_ANY);
  200.     }

  201.     /**
  202.      * Open an object from this database.
  203.      *
  204.      * @param objectId
  205.      *            identity of the object to open.
  206.      * @param typeHint
  207.      *            hint about the type of object being requested, e.g.
  208.      *            {@link org.eclipse.jgit.lib.Constants#OBJ_BLOB};
  209.      *            {@link #OBJ_ANY} if the object type is not known, or does not
  210.      *            matter to the caller.
  211.      * @return a {@link org.eclipse.jgit.lib.ObjectLoader} for accessing the
  212.      *         object.
  213.      * @throws org.eclipse.jgit.errors.MissingObjectException
  214.      *             the object does not exist.
  215.      * @throws org.eclipse.jgit.errors.IncorrectObjectTypeException
  216.      *             typeHint was not OBJ_ANY, and the object's actual type does
  217.      *             not match typeHint.
  218.      * @throws java.io.IOException
  219.      *             the object store cannot be accessed.
  220.      */
  221.     public abstract ObjectLoader open(AnyObjectId objectId, int typeHint)
  222.             throws MissingObjectException, IncorrectObjectTypeException,
  223.             IOException;

  224.     /**
  225.      * Returns IDs for those commits which should be considered as shallow.
  226.      *
  227.      * @return IDs of shallow commits
  228.      * @throws java.io.IOException
  229.      */
  230.     public abstract Set<ObjectId> getShallowCommits() throws IOException;

  231.     /**
  232.      * Asynchronous object opening.
  233.      *
  234.      * @param objectIds
  235.      *            objects to open from the object store. The supplied collection
  236.      *            must not be modified until the queue has finished.
  237.      * @param reportMissing
  238.      *            if true missing objects are reported by calling failure with a
  239.      *            MissingObjectException. This may be more expensive for the
  240.      *            implementation to guarantee. If false the implementation may
  241.      *            choose to report MissingObjectException, or silently skip over
  242.      *            the object with no warning.
  243.      * @return queue to read the objects from.
  244.      */
  245.     public <T extends ObjectId> AsyncObjectLoaderQueue<T> open(
  246.             Iterable<T> objectIds, final boolean reportMissing) {
  247.         final Iterator<T> idItr = objectIds.iterator();
  248.         return new AsyncObjectLoaderQueue<T>() {
  249.             private T cur;

  250.             @Override
  251.             public boolean next() throws MissingObjectException, IOException {
  252.                 if (idItr.hasNext()) {
  253.                     cur = idItr.next();
  254.                     return true;
  255.                 }
  256.                 return false;
  257.             }

  258.             @Override
  259.             public T getCurrent() {
  260.                 return cur;
  261.             }

  262.             @Override
  263.             public ObjectId getObjectId() {
  264.                 return cur;
  265.             }

  266.             @Override
  267.             public ObjectLoader open() throws IOException {
  268.                 return ObjectReader.this.open(cur, OBJ_ANY);
  269.             }

  270.             @Override
  271.             public boolean cancel(boolean mayInterruptIfRunning) {
  272.                 return true;
  273.             }

  274.             @Override
  275.             public void release() {
  276.                 // Since we are sequential by default, we don't
  277.                 // have any state to clean up if we terminate early.
  278.             }
  279.         };
  280.     }

  281.     /**
  282.      * Get only the size of an object.
  283.      * <p>
  284.      * The default implementation of this method opens an ObjectLoader.
  285.      * Databases are encouraged to override this if a faster access method is
  286.      * available to them.
  287.      *
  288.      * @param objectId
  289.      *            identity of the object to open.
  290.      * @param typeHint
  291.      *            hint about the type of object being requested, e.g.
  292.      *            {@link org.eclipse.jgit.lib.Constants#OBJ_BLOB};
  293.      *            {@link #OBJ_ANY} if the object type is not known, or does not
  294.      *            matter to the caller.
  295.      * @return size of object in bytes.
  296.      * @throws org.eclipse.jgit.errors.MissingObjectException
  297.      *             the object does not exist.
  298.      * @throws org.eclipse.jgit.errors.IncorrectObjectTypeException
  299.      *             typeHint was not OBJ_ANY, and the object's actual type does
  300.      *             not match typeHint.
  301.      * @throws java.io.IOException
  302.      *             the object store cannot be accessed.
  303.      */
  304.     public long getObjectSize(AnyObjectId objectId, int typeHint)
  305.             throws MissingObjectException, IncorrectObjectTypeException,
  306.             IOException {
  307.         return open(objectId, typeHint).getSize();
  308.     }

  309.     /**
  310.      * Asynchronous object size lookup.
  311.      *
  312.      * @param objectIds
  313.      *            objects to get the size of from the object store. The supplied
  314.      *            collection must not be modified until the queue has finished.
  315.      * @param reportMissing
  316.      *            if true missing objects are reported by calling failure with a
  317.      *            MissingObjectException. This may be more expensive for the
  318.      *            implementation to guarantee. If false the implementation may
  319.      *            choose to report MissingObjectException, or silently skip over
  320.      *            the object with no warning.
  321.      * @return queue to read object sizes from.
  322.      */
  323.     public <T extends ObjectId> AsyncObjectSizeQueue<T> getObjectSize(
  324.             Iterable<T> objectIds, final boolean reportMissing) {
  325.         final Iterator<T> idItr = objectIds.iterator();
  326.         return new AsyncObjectSizeQueue<T>() {
  327.             private T cur;

  328.             private long sz;

  329.             @Override
  330.             public boolean next() throws MissingObjectException, IOException {
  331.                 if (idItr.hasNext()) {
  332.                     cur = idItr.next();
  333.                     sz = getObjectSize(cur, OBJ_ANY);
  334.                     return true;
  335.                 }
  336.                 return false;
  337.             }

  338.             @Override
  339.             public T getCurrent() {
  340.                 return cur;
  341.             }

  342.             @Override
  343.             public ObjectId getObjectId() {
  344.                 return cur;
  345.             }

  346.             @Override
  347.             public long getSize() {
  348.                 return sz;
  349.             }

  350.             @Override
  351.             public boolean cancel(boolean mayInterruptIfRunning) {
  352.                 return true;
  353.             }

  354.             @Override
  355.             public void release() {
  356.                 // Since we are sequential by default, we don't
  357.                 // have any state to clean up if we terminate early.
  358.             }
  359.         };
  360.     }

  361.     /**
  362.      * Advise the reader to avoid unreachable objects.
  363.      * <p>
  364.      * While enabled the reader will skip over anything previously proven to be
  365.      * unreachable. This may be dangerous in the face of concurrent writes.
  366.      *
  367.      * @param avoid
  368.      *            true to avoid unreachable objects.
  369.      * @since 3.0
  370.      */
  371.     public void setAvoidUnreachableObjects(boolean avoid) {
  372.         // Do nothing by default.
  373.     }

  374.     /**
  375.      * An index that can be used to speed up ObjectWalks.
  376.      *
  377.      * @return the index or null if one does not exist.
  378.      * @throws java.io.IOException
  379.      *             when the index fails to load
  380.      * @since 3.0
  381.      */
  382.     public BitmapIndex getBitmapIndex() throws IOException {
  383.         return null;
  384.     }

  385.     /**
  386.      * Create a reachability checker that will use bitmaps if possible.
  387.      *
  388.      * @param rw
  389.      *            revwalk for use by the reachability checker
  390.      * @return the most efficient reachability checker for this repository.
  391.      * @throws IOException
  392.      *             if it cannot open any of the underlying indices.
  393.      *
  394.      * @since 5.11
  395.      */
  396.     @NonNull
  397.     public ReachabilityChecker createReachabilityChecker(RevWalk rw)
  398.             throws IOException {
  399.         if (getBitmapIndex() != null) {
  400.             return new BitmappedReachabilityChecker(rw);
  401.         }

  402.         return new PedestrianReachabilityChecker(true, rw);
  403.     }

  404.     /**
  405.      * Create an object reachability checker that will use bitmaps if possible.
  406.      *
  407.      * This reachability checker accepts any object as target. For checks
  408.      * exclusively between commits, use
  409.      * {@link #createReachabilityChecker(RevWalk)}.
  410.      *
  411.      * @param ow
  412.      *            objectwalk for use by the reachability checker
  413.      * @return the most efficient object reachability checker for this
  414.      *         repository.
  415.      *
  416.      * @throws IOException
  417.      *             if it cannot open any of the underlying indices.
  418.      *
  419.      * @since 5.11
  420.      */
  421.     @NonNull
  422.     public ObjectReachabilityChecker createObjectReachabilityChecker(
  423.             ObjectWalk ow) throws IOException {
  424.         if (getBitmapIndex() != null) {
  425.             return new BitmappedObjectReachabilityChecker(ow);
  426.         }

  427.         return new PedestrianObjectReachabilityChecker(ow);
  428.     }

  429.     /**
  430.      * Get the {@link org.eclipse.jgit.lib.ObjectInserter} from which this
  431.      * reader was created using {@code inserter.newReader()}
  432.      *
  433.      * @return the {@link org.eclipse.jgit.lib.ObjectInserter} from which this
  434.      *         reader was created using {@code inserter.newReader()}, or null if
  435.      *         this reader was not created from an inserter.
  436.      * @since 4.4
  437.      */
  438.     @Nullable
  439.     public ObjectInserter getCreatedFromInserter() {
  440.         return null;
  441.     }

  442.     /**
  443.      * {@inheritDoc}
  444.      * <p>
  445.      * Release any resources used by this reader.
  446.      * <p>
  447.      * A reader that has been released can be used again, but may need to be
  448.      * released after the subsequent usage.
  449.      *
  450.      * @since 4.0
  451.      */
  452.     @Override
  453.     public abstract void close();

  454.     /**
  455.      * Sets the threshold at which a file will be streamed rather than loaded
  456.      * entirely into memory
  457.      *
  458.      * @param threshold
  459.      *            the new threshold
  460.      * @since 4.6
  461.      */
  462.     public void setStreamFileThreshold(int threshold) {
  463.         streamFileThreshold = threshold;
  464.     }

  465.     /**
  466.      * Returns the threshold at which a file will be streamed rather than loaded
  467.      * entirely into memory
  468.      *
  469.      * @return the threshold in bytes
  470.      * @since 4.6
  471.      */
  472.     public int getStreamFileThreshold() {
  473.         return streamFileThreshold;
  474.     }

  475.     /**
  476.      * Wraps a delegate ObjectReader.
  477.      *
  478.      * @since 4.4
  479.      */
  480.     public abstract static class Filter extends ObjectReader {
  481.         /**
  482.          * @return delegate ObjectReader to handle all processing.
  483.          * @since 4.4
  484.          */
  485.         protected abstract ObjectReader delegate();

  486.         @Override
  487.         public ObjectReader newReader() {
  488.             return delegate().newReader();
  489.         }

  490.         @Override
  491.         public AbbreviatedObjectId abbreviate(AnyObjectId objectId)
  492.                 throws IOException {
  493.             return delegate().abbreviate(objectId);
  494.         }

  495.         @Override
  496.         public AbbreviatedObjectId abbreviate(AnyObjectId objectId, int len)
  497.                 throws IOException {
  498.             return delegate().abbreviate(objectId, len);
  499.         }

  500.         @Override
  501.         public Collection<ObjectId> resolve(AbbreviatedObjectId id)
  502.                 throws IOException {
  503.             return delegate().resolve(id);
  504.         }

  505.         @Override
  506.         public boolean has(AnyObjectId objectId) throws IOException {
  507.             return delegate().has(objectId);
  508.         }

  509.         @Override
  510.         public boolean has(AnyObjectId objectId, int typeHint) throws IOException {
  511.             return delegate().has(objectId, typeHint);
  512.         }

  513.         @Override
  514.         public ObjectLoader open(AnyObjectId objectId)
  515.                 throws MissingObjectException, IOException {
  516.             return delegate().open(objectId);
  517.         }

  518.         @Override
  519.         public ObjectLoader open(AnyObjectId objectId, int typeHint)
  520.                 throws MissingObjectException, IncorrectObjectTypeException,
  521.                 IOException {
  522.             return delegate().open(objectId, typeHint);
  523.         }

  524.         @Override
  525.         public Set<ObjectId> getShallowCommits() throws IOException {
  526.             return delegate().getShallowCommits();
  527.         }

  528.         @Override
  529.         public <T extends ObjectId> AsyncObjectLoaderQueue<T> open(
  530.                 Iterable<T> objectIds, boolean reportMissing) {
  531.             return delegate().open(objectIds, reportMissing);
  532.         }

  533.         @Override
  534.         public long getObjectSize(AnyObjectId objectId, int typeHint)
  535.                 throws MissingObjectException, IncorrectObjectTypeException,
  536.                 IOException {
  537.             return delegate().getObjectSize(objectId, typeHint);
  538.         }

  539.         @Override
  540.         public <T extends ObjectId> AsyncObjectSizeQueue<T> getObjectSize(
  541.                 Iterable<T> objectIds, boolean reportMissing) {
  542.             return delegate().getObjectSize(objectIds, reportMissing);
  543.         }

  544.         @Override
  545.         public void setAvoidUnreachableObjects(boolean avoid) {
  546.             delegate().setAvoidUnreachableObjects(avoid);
  547.         }

  548.         @Override
  549.         public BitmapIndex getBitmapIndex() throws IOException {
  550.             return delegate().getBitmapIndex();
  551.         }

  552.         @Override
  553.         @Nullable
  554.         public ObjectInserter getCreatedFromInserter() {
  555.             return delegate().getCreatedFromInserter();
  556.         }

  557.         @Override
  558.         public void close() {
  559.             delegate().close();
  560.         }
  561.     }
  562. }