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 static org.eclipse.jgit.lib.Constants.OBJECT_ID_ABBREV_STRING_LENGTH;

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

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

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

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

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

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

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

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

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

  149.     /**
  150.      * Does the requested object exist in this database?
  151.      *
  152.      * @param objectId
  153.      *            identity of the object to test for existence of.
  154.      * @return true if the specified object is stored in this database.
  155.      * @throws java.io.IOException
  156.      *             the object store cannot be accessed.
  157.      */
  158.     public boolean has(AnyObjectId objectId) throws IOException {
  159.         return has(objectId, OBJ_ANY);
  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.      * @param typeHint
  167.      *            hint about the type of object being requested, e.g.
  168.      *            {@link org.eclipse.jgit.lib.Constants#OBJ_BLOB};
  169.      *            {@link #OBJ_ANY} if the object type is not known, or does not
  170.      *            matter to the caller.
  171.      * @return true if the specified object is stored in this database.
  172.      * @throws IncorrectObjectTypeException
  173.      *             typeHint was not OBJ_ANY, and the object's actual type does
  174.      *             not match typeHint.
  175.      * @throws java.io.IOException
  176.      *             the object store cannot be accessed.
  177.      */
  178.     public boolean has(AnyObjectId objectId, int typeHint) throws IOException {
  179.         try {
  180.             open(objectId, typeHint);
  181.             return true;
  182.         } catch (MissingObjectException notFound) {
  183.             return false;
  184.         }
  185.     }

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

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

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

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

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

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

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

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

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

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

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

  310.     /**
  311.      * Check if the object size is less or equal than certain value
  312.      *
  313.      * By default, it reads the object from storage to get the size. Subclasses
  314.      * can implement more efficient lookups.
  315.      *
  316.      * @param objectId
  317.      *            identity of the object to open.
  318.      * @param typeHint
  319.      *            hint about the type of object being requested, e.g.
  320.      *            {@link org.eclipse.jgit.lib.Constants#OBJ_BLOB};
  321.      *            {@link #OBJ_ANY} if the object type is not known, or does not
  322.      *            matter to the caller.
  323.      * @param size
  324.      *            threshold value for the size of the object in bytes.
  325.      * @return true if the object size is equal or smaller than the threshold
  326.      *         value
  327.      * @throws org.eclipse.jgit.errors.MissingObjectException
  328.      *             the object does not exist.
  329.      * @throws org.eclipse.jgit.errors.IncorrectObjectTypeException
  330.      *             typeHint was not OBJ_ANY, and the object's actual type does
  331.      *             not match typeHint.
  332.      * @throws java.io.IOException
  333.      *             the object store cannot be accessed.
  334.      *
  335.      * @since 6.4
  336.      */
  337.     public boolean isNotLargerThan(AnyObjectId objectId, int typeHint, long size)
  338.             throws MissingObjectException, IncorrectObjectTypeException,
  339.             IOException {
  340.         return open(objectId, typeHint).getSize() <= size;
  341.     }

  342.     /**
  343.      * Asynchronous object size lookup.
  344.      *
  345.      * @param objectIds
  346.      *            objects to get the size of from the object store. The supplied
  347.      *            collection must not be modified until the queue has finished.
  348.      * @param reportMissing
  349.      *            if true missing objects are reported by calling failure with a
  350.      *            MissingObjectException. This may be more expensive for the
  351.      *            implementation to guarantee. If false the implementation may
  352.      *            choose to report MissingObjectException, or silently skip over
  353.      *            the object with no warning.
  354.      * @return queue to read object sizes from.
  355.      */
  356.     public <T extends ObjectId> AsyncObjectSizeQueue<T> getObjectSize(
  357.             Iterable<T> objectIds, final boolean reportMissing) {
  358.         final Iterator<T> idItr = objectIds.iterator();
  359.         return new AsyncObjectSizeQueue<>() {
  360.             private T cur;

  361.             private long sz;

  362.             @Override
  363.             public boolean next() throws MissingObjectException, IOException {
  364.                 if (idItr.hasNext()) {
  365.                     cur = idItr.next();
  366.                     sz = getObjectSize(cur, OBJ_ANY);
  367.                     return true;
  368.                 }
  369.                 return false;
  370.             }

  371.             @Override
  372.             public T getCurrent() {
  373.                 return cur;
  374.             }

  375.             @Override
  376.             public ObjectId getObjectId() {
  377.                 return cur;
  378.             }

  379.             @Override
  380.             public long getSize() {
  381.                 return sz;
  382.             }

  383.             @Override
  384.             public boolean cancel(boolean mayInterruptIfRunning) {
  385.                 return true;
  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.      * Advise the reader to avoid unreachable objects.
  396.      * <p>
  397.      * While enabled the reader will skip over anything previously proven to be
  398.      * unreachable. This may be dangerous in the face of concurrent writes.
  399.      *
  400.      * @param avoid
  401.      *            true to avoid unreachable objects.
  402.      * @since 3.0
  403.      */
  404.     public void setAvoidUnreachableObjects(boolean avoid) {
  405.         // Do nothing by default.
  406.     }

  407.     /**
  408.      * An index that can be used to speed up ObjectWalks.
  409.      *
  410.      * @return the index or null if one does not exist.
  411.      * @throws java.io.IOException
  412.      *             when the index fails to load
  413.      * @since 3.0
  414.      */
  415.     public BitmapIndex getBitmapIndex() throws IOException {
  416.         return null;
  417.     }

  418.     /**
  419.      * Create a reachability checker that will use bitmaps if possible.
  420.      *
  421.      * @param rw
  422.      *            revwalk for use by the reachability checker
  423.      * @return the most efficient reachability checker for this repository.
  424.      * @throws IOException
  425.      *             if it cannot open any of the underlying indices.
  426.      *
  427.      * @since 5.11
  428.      */
  429.     @NonNull
  430.     public ReachabilityChecker createReachabilityChecker(RevWalk rw)
  431.             throws IOException {
  432.         if (getBitmapIndex() != null) {
  433.             return new BitmappedReachabilityChecker(rw);
  434.         }

  435.         return new PedestrianReachabilityChecker(true, rw);
  436.     }

  437.     /**
  438.      * Create an object reachability checker that will use bitmaps if possible.
  439.      *
  440.      * This reachability checker accepts any object as target. For checks
  441.      * exclusively between commits, use
  442.      * {@link #createReachabilityChecker(RevWalk)}.
  443.      *
  444.      * @param ow
  445.      *            objectwalk for use by the reachability checker
  446.      * @return the most efficient object reachability checker for this
  447.      *         repository.
  448.      *
  449.      * @throws IOException
  450.      *             if it cannot open any of the underlying indices.
  451.      *
  452.      * @since 5.11
  453.      */
  454.     @NonNull
  455.     public ObjectReachabilityChecker createObjectReachabilityChecker(
  456.             ObjectWalk ow) throws IOException {
  457.         if (getBitmapIndex() != null) {
  458.             return new BitmappedObjectReachabilityChecker(ow);
  459.         }

  460.         return new PedestrianObjectReachabilityChecker(ow);
  461.     }

  462.     /**
  463.      * Get the {@link org.eclipse.jgit.lib.ObjectInserter} from which this
  464.      * reader was created using {@code inserter.newReader()}
  465.      *
  466.      * @return the {@link org.eclipse.jgit.lib.ObjectInserter} from which this
  467.      *         reader was created using {@code inserter.newReader()}, or null if
  468.      *         this reader was not created from an inserter.
  469.      * @since 4.4
  470.      */
  471.     @Nullable
  472.     public ObjectInserter getCreatedFromInserter() {
  473.         return null;
  474.     }

  475.     /**
  476.      * {@inheritDoc}
  477.      * <p>
  478.      * Release any resources used by this reader.
  479.      * <p>
  480.      * A reader that has been released can be used again, but may need to be
  481.      * released after the subsequent usage.
  482.      *
  483.      * @since 4.0
  484.      */
  485.     @Override
  486.     public abstract void close();

  487.     /**
  488.      * Sets the threshold at which a file will be streamed rather than loaded
  489.      * entirely into memory
  490.      *
  491.      * @param threshold
  492.      *            the new threshold
  493.      * @since 4.6
  494.      */
  495.     public void setStreamFileThreshold(int threshold) {
  496.         streamFileThreshold = threshold;
  497.     }

  498.     /**
  499.      * Returns the threshold at which a file will be streamed rather than loaded
  500.      * entirely into memory
  501.      *
  502.      * @return the threshold in bytes
  503.      * @since 4.6
  504.      */
  505.     public int getStreamFileThreshold() {
  506.         return streamFileThreshold;
  507.     }

  508.     /**
  509.      * Wraps a delegate ObjectReader.
  510.      *
  511.      * @since 4.4
  512.      */
  513.     public abstract static class Filter extends ObjectReader {
  514.         /**
  515.          * @return delegate ObjectReader to handle all processing.
  516.          * @since 4.4
  517.          */
  518.         protected abstract ObjectReader delegate();

  519.         @Override
  520.         public ObjectReader newReader() {
  521.             return delegate().newReader();
  522.         }

  523.         @Override
  524.         public AbbreviatedObjectId abbreviate(AnyObjectId objectId)
  525.                 throws IOException {
  526.             return delegate().abbreviate(objectId);
  527.         }

  528.         @Override
  529.         public AbbreviatedObjectId abbreviate(AnyObjectId objectId, int len)
  530.                 throws IOException {
  531.             return delegate().abbreviate(objectId, len);
  532.         }

  533.         @Override
  534.         public Collection<ObjectId> resolve(AbbreviatedObjectId id)
  535.                 throws IOException {
  536.             return delegate().resolve(id);
  537.         }

  538.         @Override
  539.         public boolean has(AnyObjectId objectId) throws IOException {
  540.             return delegate().has(objectId);
  541.         }

  542.         @Override
  543.         public boolean has(AnyObjectId objectId, int typeHint) throws IOException {
  544.             return delegate().has(objectId, typeHint);
  545.         }

  546.         @Override
  547.         public ObjectLoader open(AnyObjectId objectId)
  548.                 throws MissingObjectException, IOException {
  549.             return delegate().open(objectId);
  550.         }

  551.         @Override
  552.         public ObjectLoader open(AnyObjectId objectId, int typeHint)
  553.                 throws MissingObjectException, IncorrectObjectTypeException,
  554.                 IOException {
  555.             return delegate().open(objectId, typeHint);
  556.         }

  557.         @Override
  558.         public Set<ObjectId> getShallowCommits() throws IOException {
  559.             return delegate().getShallowCommits();
  560.         }

  561.         @Override
  562.         public <T extends ObjectId> AsyncObjectLoaderQueue<T> open(
  563.                 Iterable<T> objectIds, boolean reportMissing) {
  564.             return delegate().open(objectIds, reportMissing);
  565.         }

  566.         @Override
  567.         public long getObjectSize(AnyObjectId objectId, int typeHint)
  568.                 throws MissingObjectException, IncorrectObjectTypeException,
  569.                 IOException {
  570.             return delegate().getObjectSize(objectId, typeHint);
  571.         }

  572.         @Override
  573.         public <T extends ObjectId> AsyncObjectSizeQueue<T> getObjectSize(
  574.                 Iterable<T> objectIds, boolean reportMissing) {
  575.             return delegate().getObjectSize(objectIds, reportMissing);
  576.         }

  577.         @Override
  578.         public void setAvoidUnreachableObjects(boolean avoid) {
  579.             delegate().setAvoidUnreachableObjects(avoid);
  580.         }

  581.         @Override
  582.         public BitmapIndex getBitmapIndex() throws IOException {
  583.             return delegate().getBitmapIndex();
  584.         }

  585.         @Override
  586.         @Nullable
  587.         public ObjectInserter getCreatedFromInserter() {
  588.             return delegate().getCreatedFromInserter();
  589.         }

  590.         @Override
  591.         public void close() {
  592.             delegate().close();
  593.         }
  594.     }
  595. }