ObjectToPack.java

  1. /*
  2.  * Copyright (C) 2008-2010, Google Inc.
  3.  * Copyright (C) 2008, Marek Zawirski <marek.zawirski@gmail.com> and others
  4.  *
  5.  * This program and the accompanying materials are made available under the
  6.  * terms of the Eclipse Distribution License v. 1.0 which is available at
  7.  * https://www.eclipse.org/org/documents/edl-v10.php.
  8.  *
  9.  * SPDX-License-Identifier: BSD-3-Clause
  10.  */

  11. package org.eclipse.jgit.internal.storage.pack;

  12. import org.eclipse.jgit.lib.AnyObjectId;
  13. import org.eclipse.jgit.lib.Constants;
  14. import org.eclipse.jgit.lib.ObjectId;
  15. import org.eclipse.jgit.transport.PackedObjectInfo;

  16. /**
  17.  * Per-object state used by
  18.  * {@link org.eclipse.jgit.internal.storage.pack.PackWriter}.
  19.  * <p>
  20.  * {@code PackWriter} uses this class to track the things it needs to include in
  21.  * the newly generated pack file, and how to efficiently obtain the raw data for
  22.  * each object as they are written to the output stream.
  23.  */
  24. public class ObjectToPack extends PackedObjectInfo {
  25.     private static final int REUSE_AS_IS = 1 << 0;
  26.     private static final int DELTA_ATTEMPTED = 1 << 1;
  27.     private static final int DO_NOT_DELTA = 1 << 2;
  28.     private static final int EDGE = 1 << 3;
  29.     private static final int ATTEMPT_DELTA_MASK = REUSE_AS_IS | DELTA_ATTEMPTED;
  30.     private static final int TYPE_SHIFT = 5;
  31.     private static final int EXT_SHIFT = 8;
  32.     private static final int EXT_MASK = 0xf;
  33.     private static final int DELTA_SHIFT = 12;
  34.     private static final int NON_EXT_MASK = ~(EXT_MASK << EXT_SHIFT);
  35.     private static final int NON_DELTA_MASK = 0xfff;

  36.     /** Other object being packed that this will delta against. */
  37.     private ObjectId deltaBase;

  38.     /**
  39.      * Bit field, from bit 0 to bit 31:
  40.      * <ul>
  41.      * <li>1 bit: canReuseAsIs</li>
  42.      * <li>1 bit: deltaAttempted</li>
  43.      * <li>1 bit: doNotDelta</li>
  44.      * <li>1 bit: edgeObject</li>
  45.      * <li>1 bit: unused</li>
  46.      * <li>3 bits: type</li>
  47.      * <li>4 bits: subclass flags (if any)</li>
  48.      * <li>--</li>
  49.      * <li>20 bits: deltaDepth</li>
  50.      * </ul>
  51.      */
  52.     private int flags;

  53.     /** Hash of the object's tree path. */
  54.     private int pathHash;

  55.     /** If present, deflated delta instruction stream for this object. */
  56.     private DeltaCache.Ref cachedDelta;

  57.     /**
  58.      * Construct for the specified object id.
  59.      *
  60.      * @param src
  61.      *            object id of object for packing
  62.      * @param type
  63.      *            real type code of the object, not its in-pack type.
  64.      */
  65.     public ObjectToPack(AnyObjectId src, int type) {
  66.         super(src);
  67.         flags = type << TYPE_SHIFT;
  68.     }

  69.     /**
  70.      * Get delta base object id if object is going to be packed in delta
  71.      * representation
  72.      *
  73.      * @return delta base object id if object is going to be packed in delta
  74.      *         representation; null otherwise - if going to be packed as a whole
  75.      *         object.
  76.      */
  77.     public final ObjectId getDeltaBaseId() {
  78.         return deltaBase;
  79.     }

  80.     /**
  81.      * Get delta base object to pack if object is going to be packed in delta
  82.      * representation and delta is specified as object to pack
  83.      *
  84.      * @return delta base object to pack if object is going to be packed in
  85.      *         delta representation and delta is specified as object to pack;
  86.      *         null otherwise - if going to be packed as a whole object or delta
  87.      *         base is specified only as id.
  88.      */
  89.     public final ObjectToPack getDeltaBase() {
  90.         if (deltaBase instanceof ObjectToPack)
  91.             return (ObjectToPack) deltaBase;
  92.         return null;
  93.     }

  94.     /**
  95.      * Set delta base for the object. Delta base set by this method is used
  96.      * by {@link PackWriter} to write object - determines its representation
  97.      * in a created pack.
  98.      *
  99.      * @param deltaBase
  100.      *            delta base object or null if object should be packed as a
  101.      *            whole object.
  102.      *
  103.      */
  104.     final void setDeltaBase(ObjectId deltaBase) {
  105.         this.deltaBase = deltaBase;
  106.     }

  107.     final void setCachedDelta(DeltaCache.Ref data) {
  108.         cachedDelta = data;
  109.     }

  110.     final DeltaCache.Ref popCachedDelta() {
  111.         DeltaCache.Ref r = cachedDelta;
  112.         if (r != null)
  113.             cachedDelta = null;
  114.         return r;
  115.     }

  116.     final void clearDeltaBase() {
  117.         this.deltaBase = null;

  118.         if (cachedDelta != null) {
  119.             cachedDelta.clear();
  120.             cachedDelta.enqueue();
  121.             cachedDelta = null;
  122.         }
  123.     }

  124.     /**
  125.      * Whether object is going to be written as delta
  126.      *
  127.      * @return true if object is going to be written as delta; false otherwise.
  128.      */
  129.     public final boolean isDeltaRepresentation() {
  130.         return deltaBase != null;
  131.     }

  132.     /**
  133.      * Check if object is already written in a pack. This information is
  134.      * used to achieve delta-base precedence in a pack file.
  135.      *
  136.      * @return true if object is already written; false otherwise.
  137.      */
  138.     public final boolean isWritten() {
  139.         return 1 < getOffset(); // markWantWrite sets 1.
  140.     }

  141.     /** {@inheritDoc} */
  142.     @Override
  143.     public final int getType() {
  144.         return (flags >> TYPE_SHIFT) & 0x7;
  145.     }

  146.     final int getDeltaDepth() {
  147.         return flags >>> DELTA_SHIFT;
  148.     }

  149.     final void setDeltaDepth(int d) {
  150.         flags = (d << DELTA_SHIFT) | (flags & NON_DELTA_MASK);
  151.     }

  152.     final int getChainLength() {
  153.         return getDeltaDepth();
  154.     }

  155.     final void setChainLength(int len) {
  156.         setDeltaDepth(len);
  157.     }

  158.     final void clearChainLength() {
  159.         flags &= NON_DELTA_MASK;
  160.     }

  161.     final boolean wantWrite() {
  162.         return getOffset() == 1;
  163.     }

  164.     final void markWantWrite() {
  165.         setOffset(1);
  166.     }

  167.     /**
  168.      * Whether an existing representation was selected to be reused as-is into
  169.      * the pack stream.
  170.      *
  171.      * @return true if an existing representation was selected to be reused
  172.      *         as-is into the pack stream.
  173.      */
  174.     public final boolean isReuseAsIs() {
  175.         return (flags & REUSE_AS_IS) != 0;
  176.     }

  177.     final void setReuseAsIs() {
  178.         flags |= REUSE_AS_IS;
  179.     }

  180.     /**
  181.      * Forget the reuse information previously stored.
  182.      * <p>
  183.      * Implementations may subclass this method, but they must also invoke the
  184.      * super version with {@code super.clearReuseAsIs()} to ensure the flag is
  185.      * properly cleared for the writer.
  186.      */
  187.     protected void clearReuseAsIs() {
  188.         flags &= ~REUSE_AS_IS;
  189.     }

  190.     final boolean isDoNotDelta() {
  191.         return (flags & DO_NOT_DELTA) != 0;
  192.     }

  193.     final void setDoNotDelta() {
  194.         flags |= DO_NOT_DELTA;
  195.     }

  196.     final boolean isEdge() {
  197.         return (flags & EDGE) != 0;
  198.     }

  199.     final void setEdge() {
  200.         flags |= EDGE;
  201.     }

  202.     final boolean doNotAttemptDelta() {
  203.         // Do not attempt if delta attempted and object reuse.
  204.         return (flags & ATTEMPT_DELTA_MASK) == ATTEMPT_DELTA_MASK;
  205.     }

  206.     final void setDeltaAttempted(boolean deltaAttempted) {
  207.         if (deltaAttempted)
  208.             flags |= DELTA_ATTEMPTED;
  209.         else
  210.             flags &= ~DELTA_ATTEMPTED;
  211.     }

  212.     /**
  213.      * Get the extended flags on this object, in the range [0x0, 0xf].
  214.      *
  215.      * @return the extended flags on this object, in the range [0x0, 0xf].
  216.      */
  217.     protected final int getExtendedFlags() {
  218.         return (flags >>> EXT_SHIFT) & EXT_MASK;
  219.     }

  220.     /**
  221.      * Determine if a particular extended flag bit has been set.
  222.      *
  223.      * This implementation may be faster than calling
  224.      * {@link #getExtendedFlags()} and testing the result.
  225.      *
  226.      * @param flag
  227.      *            the flag mask to test, must be between 0x0 and 0xf.
  228.      * @return true if any of the bits matching the mask are non-zero.
  229.      */
  230.     protected final boolean isExtendedFlag(int flag) {
  231.         return (flags & (flag << EXT_SHIFT)) != 0;
  232.     }

  233.     /**
  234.      * Set an extended flag bit.
  235.      *
  236.      * This implementation is more efficient than getting the extended flags,
  237.      * adding the bit, and setting them all back.
  238.      *
  239.      * @param flag
  240.      *            the bits to set, must be between 0x0 and 0xf.
  241.      */
  242.     protected final void setExtendedFlag(int flag) {
  243.         flags |= (flag & EXT_MASK) << EXT_SHIFT;
  244.     }

  245.     /**
  246.      * Clear an extended flag bit.
  247.      *
  248.      * This implementation is more efficient than getting the extended flags,
  249.      * removing the bit, and setting them all back.
  250.      *
  251.      * @param flag
  252.      *            the bits to clear, must be between 0x0 and 0xf.
  253.      */
  254.     protected final void clearExtendedFlag(int flag) {
  255.         flags &= ~((flag & EXT_MASK) << EXT_SHIFT);
  256.     }

  257.     /**
  258.      * Set the extended flags used by the subclass.
  259.      *
  260.      * Subclass implementations may store up to 4 bits of information inside of
  261.      * the internal flags field already used by the base ObjectToPack instance.
  262.      *
  263.      * @param extFlags
  264.      *            additional flag bits to store in the flags field. Due to space
  265.      *            constraints only values [0x0, 0xf] are permitted.
  266.      */
  267.     protected final void setExtendedFlags(int extFlags) {
  268.         flags = ((extFlags & EXT_MASK) << EXT_SHIFT) | (flags & NON_EXT_MASK);
  269.     }

  270.     final int getFormat() {
  271.         if (isReuseAsIs()) {
  272.             if (isDeltaRepresentation())
  273.                 return StoredObjectRepresentation.PACK_DELTA;
  274.             return StoredObjectRepresentation.PACK_WHOLE;
  275.         }
  276.         return StoredObjectRepresentation.FORMAT_OTHER;
  277.     }

  278.     // Overload weight into CRC since we don't need them at the same time.
  279.     final int getWeight() {
  280.         return getCRC();
  281.     }

  282.     final void setWeight(int weight) {
  283.         setCRC(weight);
  284.     }

  285.     final int getPathHash() {
  286.         return pathHash;
  287.     }

  288.     final void setPathHash(int hc) {
  289.         pathHash = hc;
  290.     }

  291.     final int getCachedSize() {
  292.         return pathHash;
  293.     }

  294.     final void setCachedSize(int sz) {
  295.         pathHash = sz;
  296.     }

  297.     /**
  298.      * Remember a specific representation for reuse at a later time.
  299.      * <p>
  300.      * Implementers should remember the representation chosen, so it can be
  301.      * reused at a later time.
  302.      * {@link org.eclipse.jgit.internal.storage.pack.PackWriter} may invoke this
  303.      * method multiple times for the same object, each time saving the current
  304.      * best representation found.
  305.      *
  306.      * @param ref
  307.      *            the object representation.
  308.      */
  309.     public void select(StoredObjectRepresentation ref) {
  310.         // Empty by default.
  311.     }

  312.     /** {@inheritDoc} */
  313.     @SuppressWarnings("nls")
  314.     @Override
  315.     public String toString() {
  316.         StringBuilder buf = new StringBuilder();
  317.         buf.append("ObjectToPack[");
  318.         buf.append(Constants.typeString(getType()));
  319.         buf.append(" ");
  320.         buf.append(name());
  321.         if (wantWrite())
  322.             buf.append(" wantWrite");
  323.         if (isReuseAsIs())
  324.             buf.append(" reuseAsIs");
  325.         if (isDoNotDelta())
  326.             buf.append(" doNotDelta");
  327.         if (isEdge())
  328.             buf.append(" edge");
  329.         if (getDeltaDepth() > 0)
  330.             buf.append(" depth=").append(getDeltaDepth());
  331.         if (isDeltaRepresentation()) {
  332.             if (getDeltaBase() != null)
  333.                 buf.append(" base=inpack:").append(getDeltaBase().name());
  334.             else
  335.                 buf.append(" base=edge:").append(getDeltaBaseId().name());
  336.         }
  337.         if (isWritten())
  338.             buf.append(" offset=").append(getOffset());
  339.         buf.append("]");
  340.         return buf.toString();
  341.     }
  342. }