ObjectInserter.java

  1. /*
  2.  * Copyright (C) 2007, Robin Rosenberg <robin.rosenberg@dewire.com>
  3.  * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org>
  4.  * Copyright (C) 2009, Google Inc.
  5.  * Copyright (C) 2010, Chris Aniszczyk <caniszczyk@gmail.com> and others
  6.  *
  7.  * This program and the accompanying materials are made available under the
  8.  * terms of the Eclipse Distribution License v. 1.0 which is available at
  9.  * https://www.eclipse.org/org/documents/edl-v10.php.
  10.  *
  11.  * SPDX-License-Identifier: BSD-3-Clause
  12.  */

  13. package org.eclipse.jgit.lib;

  14. import java.io.ByteArrayInputStream;
  15. import java.io.EOFException;
  16. import java.io.IOException;
  17. import java.io.InputStream;

  18. import org.eclipse.jgit.internal.JGitText;
  19. import org.eclipse.jgit.transport.PackParser;
  20. import org.eclipse.jgit.util.sha1.SHA1;

  21. /**
  22.  * Inserts objects into an existing {@code ObjectDatabase}.
  23.  * <p>
  24.  * An inserter is not thread-safe. Individual threads should each obtain their
  25.  * own unique inserter instance, or must arrange for locking at a higher level
  26.  * to ensure the inserter is in use by no more than one thread at a time.
  27.  * <p>
  28.  * Objects written by an inserter may not be immediately visible for reading
  29.  * after the insert method completes. Callers must invoke either
  30.  * {@link #close()} or {@link #flush()} prior to updating references or
  31.  * otherwise making the returned ObjectIds visible to other code.
  32.  */
  33. public abstract class ObjectInserter implements AutoCloseable {
  34.     /** An inserter that can be used for formatting and id generation only. */
  35.     public static class Formatter extends ObjectInserter {
  36.         @Override
  37.         public ObjectId insert(int objectType, long length, InputStream in)
  38.                 throws IOException {
  39.             throw new UnsupportedOperationException();
  40.         }

  41.         @Override
  42.         public PackParser newPackParser(InputStream in) throws IOException {
  43.             throw new UnsupportedOperationException();
  44.         }

  45.         @Override
  46.         public ObjectReader newReader() {
  47.             throw new UnsupportedOperationException();
  48.         }

  49.         @Override
  50.         public void flush() throws IOException {
  51.             // Do nothing.
  52.         }

  53.         @Override
  54.         public void close() {
  55.             // Do nothing.
  56.         }
  57.     }

  58.     /** Wraps a delegate ObjectInserter. */
  59.     public abstract static class Filter extends ObjectInserter {
  60.         /** @return delegate ObjectInserter to handle all processing. */
  61.         protected abstract ObjectInserter delegate();

  62.         @Override
  63.         protected byte[] buffer() {
  64.             return delegate().buffer();
  65.         }

  66.         @Override
  67.         public ObjectId idFor(int type, byte[] data) {
  68.             return delegate().idFor(type, data);
  69.         }

  70.         @Override
  71.         public ObjectId idFor(int type, byte[] data, int off, int len) {
  72.             return delegate().idFor(type, data, off, len);
  73.         }

  74.         @Override
  75.         public ObjectId idFor(int objectType, long length, InputStream in)
  76.                 throws IOException {
  77.             return delegate().idFor(objectType, length, in);
  78.         }

  79.         @Override
  80.         public ObjectId idFor(TreeFormatter formatter) {
  81.             return delegate().idFor(formatter);
  82.         }

  83.         @Override
  84.         public ObjectId insert(int type, byte[] data) throws IOException {
  85.             return delegate().insert(type, data);
  86.         }

  87.         @Override
  88.         public ObjectId insert(int type, byte[] data, int off, int len)
  89.                 throws IOException {
  90.             return delegate().insert(type, data, off, len);
  91.         }

  92.         @Override
  93.         public ObjectId insert(int objectType, long length, InputStream in)
  94.                 throws IOException {
  95.             return delegate().insert(objectType, length, in);
  96.         }

  97.         @Override
  98.         public PackParser newPackParser(InputStream in) throws IOException {
  99.             return delegate().newPackParser(in);
  100.         }

  101.         @Override
  102.         public ObjectReader newReader() {
  103.             final ObjectReader dr = delegate().newReader();
  104.             return new ObjectReader.Filter() {
  105.                 @Override
  106.                 protected ObjectReader delegate() {
  107.                     return dr;
  108.                 }

  109.                 @Override
  110.                 public ObjectInserter getCreatedFromInserter() {
  111.                     return ObjectInserter.Filter.this;
  112.                 }
  113.             };
  114.         }

  115.         @Override
  116.         public void flush() throws IOException {
  117.             delegate().flush();
  118.         }

  119.         @Override
  120.         public void close() {
  121.             delegate().close();
  122.         }
  123.     }

  124.     private final SHA1 hasher = SHA1.newInstance();

  125.     /** Temporary working buffer for streaming data through. */
  126.     private byte[] tempBuffer;

  127.     /**
  128.      * Create a new inserter for a database.
  129.      */
  130.     protected ObjectInserter() {
  131.     }

  132.     /**
  133.      * Obtain a temporary buffer for use by the ObjectInserter or its subclass.
  134.      * <p>
  135.      * This buffer is supplied by the ObjectInserter base class to itself and
  136.      * its subclasses for the purposes of pulling data from a supplied
  137.      * InputStream, passing it through a Deflater, or formatting the canonical
  138.      * format of a small object like a small tree or commit.
  139.      * <p>
  140.      * <strong>This buffer IS NOT for translation such as auto-CRLF or content
  141.      * filtering and must not be used for such purposes.</strong>
  142.      * <p>
  143.      * The returned buffer is small, around a few KiBs, and the size may change
  144.      * between versions of JGit. Callers using this buffer must always check the
  145.      * length of the returned array to ascertain how much space was provided.
  146.      * <p>
  147.      * There is a single buffer for each ObjectInserter, repeated calls to this
  148.      * method will (usually) always return the same buffer. If the caller needs
  149.      * more than one buffer, or needs a buffer of a larger size, it must manage
  150.      * that buffer on its own.
  151.      * <p>
  152.      * The buffer is usually on first demand for a buffer.
  153.      *
  154.      * @return a temporary byte array for use by the caller.
  155.      */
  156.     protected byte[] buffer() {
  157.         byte[] b = tempBuffer;
  158.         if (b == null)
  159.             tempBuffer = b = new byte[8192];
  160.         return b;
  161.     }

  162.     /**
  163.      * Compute digest to help compute an ObjectId
  164.      *
  165.      * @return digest to help compute an ObjectId
  166.      * @since 4.7
  167.      */
  168.     protected SHA1 digest() {
  169.         return hasher.reset();
  170.     }

  171.     /**
  172.      * Compute the name of an object, without inserting it.
  173.      *
  174.      * @param type
  175.      *            type code of the object to store.
  176.      * @param data
  177.      *            complete content of the object.
  178.      * @return the name of the object.
  179.      */
  180.     public ObjectId idFor(int type, byte[] data) {
  181.         return idFor(type, data, 0, data.length);
  182.     }

  183.     /**
  184.      * Compute the name of an object, without inserting it.
  185.      *
  186.      * @param type
  187.      *            type code of the object to store.
  188.      * @param data
  189.      *            complete content of the object.
  190.      * @param off
  191.      *            first position within {@code data}.
  192.      * @param len
  193.      *            number of bytes to copy from {@code data}.
  194.      * @return the name of the object.
  195.      */
  196.     public ObjectId idFor(int type, byte[] data, int off, int len) {
  197.         SHA1 md = SHA1.newInstance();
  198.         md.update(Constants.encodedTypeString(type));
  199.         md.update((byte) ' ');
  200.         md.update(Constants.encodeASCII(len));
  201.         md.update((byte) 0);
  202.         md.update(data, off, len);
  203.         return md.toObjectId();
  204.     }

  205.     /**
  206.      * Compute the name of an object, without inserting it.
  207.      *
  208.      * @param objectType
  209.      *            type code of the object to store.
  210.      * @param length
  211.      *            number of bytes to scan from {@code in}.
  212.      * @param in
  213.      *            stream providing the object content. The caller is responsible
  214.      *            for closing the stream.
  215.      * @return the name of the object.
  216.      * @throws java.io.IOException
  217.      *             the source stream could not be read.
  218.      */
  219.     public ObjectId idFor(int objectType, long length, InputStream in)
  220.             throws IOException {
  221.         SHA1 md = SHA1.newInstance();
  222.         md.update(Constants.encodedTypeString(objectType));
  223.         md.update((byte) ' ');
  224.         md.update(Constants.encodeASCII(length));
  225.         md.update((byte) 0);
  226.         byte[] buf = buffer();
  227.         while (length > 0) {
  228.             int n = in.read(buf, 0, (int) Math.min(length, buf.length));
  229.             if (n < 0)
  230.                 throw new EOFException(JGitText.get().unexpectedEndOfInput);
  231.             md.update(buf, 0, n);
  232.             length -= n;
  233.         }
  234.         return md.toObjectId();
  235.     }

  236.     /**
  237.      * Compute the ObjectId for the given tree without inserting it.
  238.      *
  239.      * @param formatter
  240.      *            a {@link org.eclipse.jgit.lib.TreeFormatter} object.
  241.      * @return the computed ObjectId
  242.      */
  243.     public ObjectId idFor(TreeFormatter formatter) {
  244.         return formatter.computeId(this);
  245.     }

  246.     /**
  247.      * Insert a single tree into the store, returning its unique name.
  248.      *
  249.      * @param formatter
  250.      *            the formatter containing the proposed tree's data.
  251.      * @return the name of the tree object.
  252.      * @throws java.io.IOException
  253.      *             the object could not be stored.
  254.      */
  255.     public final ObjectId insert(TreeFormatter formatter) throws IOException {
  256.         // Delegate to the formatter, as then it can pass the raw internal
  257.         // buffer back to this inserter, avoiding unnecessary data copying.
  258.         //
  259.         return formatter.insertTo(this);
  260.     }

  261.     /**
  262.      * Insert a single commit into the store, returning its unique name.
  263.      *
  264.      * @param builder
  265.      *            the builder containing the proposed commit's data.
  266.      * @return the name of the commit object.
  267.      * @throws java.io.IOException
  268.      *             the object could not be stored.
  269.      */
  270.     public final ObjectId insert(CommitBuilder builder) throws IOException {
  271.         return insert(Constants.OBJ_COMMIT, builder.build());
  272.     }

  273.     /**
  274.      * Insert a single annotated tag into the store, returning its unique name.
  275.      *
  276.      * @param builder
  277.      *            the builder containing the proposed tag's data.
  278.      * @return the name of the tag object.
  279.      * @throws java.io.IOException
  280.      *             the object could not be stored.
  281.      */
  282.     public final ObjectId insert(TagBuilder builder) throws IOException {
  283.         return insert(Constants.OBJ_TAG, builder.build());
  284.     }

  285.     /**
  286.      * Insert a single object into the store, returning its unique name.
  287.      *
  288.      * @param type
  289.      *            type code of the object to store.
  290.      * @param data
  291.      *            complete content of the object.
  292.      * @return the name of the object.
  293.      * @throws java.io.IOException
  294.      *             the object could not be stored.
  295.      */
  296.     public ObjectId insert(int type, byte[] data)
  297.             throws IOException {
  298.         return insert(type, data, 0, data.length);
  299.     }

  300.     /**
  301.      * Insert a single object into the store, returning its unique name.
  302.      *
  303.      * @param type
  304.      *            type code of the object to store.
  305.      * @param data
  306.      *            complete content of the object.
  307.      * @param off
  308.      *            first position within {@code data}.
  309.      * @param len
  310.      *            number of bytes to copy from {@code data}.
  311.      * @return the name of the object.
  312.      * @throws java.io.IOException
  313.      *             the object could not be stored.
  314.      */
  315.     public ObjectId insert(int type, byte[] data, int off, int len)
  316.             throws IOException {
  317.         return insert(type, len, new ByteArrayInputStream(data, off, len));
  318.     }

  319.     /**
  320.      * Insert a single object into the store, returning its unique name.
  321.      *
  322.      * @param objectType
  323.      *            type code of the object to store.
  324.      * @param length
  325.      *            number of bytes to copy from {@code in}.
  326.      * @param in
  327.      *            stream providing the object content. The caller is responsible
  328.      *            for closing the stream.
  329.      * @return the name of the object.
  330.      * @throws java.io.IOException
  331.      *             the object could not be stored, or the source stream could
  332.      *             not be read.
  333.      */
  334.     public abstract ObjectId insert(int objectType, long length, InputStream in)
  335.             throws IOException;

  336.     /**
  337.      * Initialize a parser to read from a pack formatted stream.
  338.      *
  339.      * @param in
  340.      *            the input stream. The stream is not closed by the parser, and
  341.      *            must instead be closed by the caller once parsing is complete.
  342.      * @return the pack parser.
  343.      * @throws java.io.IOException
  344.      *             the parser instance, which can be configured and then used to
  345.      *             parse objects into the ObjectDatabase.
  346.      */
  347.     public abstract PackParser newPackParser(InputStream in) throws IOException;

  348.     /**
  349.      * Open a reader for objects that may have been written by this inserter.
  350.      * <p>
  351.      * The returned reader allows the calling thread to read back recently
  352.      * inserted objects without first calling {@code flush()} to make them
  353.      * visible to the repository. The returned reader should only be used from
  354.      * the same thread as the inserter. Objects written by this inserter may not
  355.      * be visible to {@code this.newReader().newReader()}.
  356.      * <p>
  357.      * The returned reader should return this inserter instance from {@link
  358.      * ObjectReader#getCreatedFromInserter()}.
  359.      * <p>
  360.      * Behavior is undefined if an insert method is called on the inserter in the
  361.      * middle of reading from an {@link ObjectStream} opened from this reader. For
  362.      * example, reading the remainder of the object may fail, or newly written
  363.      * data may even be corrupted. Interleaving whole object reads (including
  364.      * streaming reads) with inserts is fine, just not interleaving streaming
  365.      * <em>partial</em> object reads with inserts.
  366.      *
  367.      * @since 3.5
  368.      * @return reader for any object, including an object recently inserted by
  369.      *         this inserter since the last flush.
  370.      */
  371.     public abstract ObjectReader newReader();

  372.     /**
  373.      * Make all inserted objects visible.
  374.      * <p>
  375.      * The flush may take some period of time to make the objects available to
  376.      * other threads.
  377.      *
  378.      * @throws java.io.IOException
  379.      *             the flush could not be completed; objects inserted thus far
  380.      *             are in an indeterminate state.
  381.      */
  382.     public abstract void flush() throws IOException;

  383.     /**
  384.      * {@inheritDoc}
  385.      * <p>
  386.      * Release any resources used by this inserter.
  387.      * <p>
  388.      * An inserter that has been released can be used again, but may need to be
  389.      * released after the subsequent usage.
  390.      *
  391.      * @since 4.0
  392.      */
  393.     @Override
  394.     public abstract void close();
  395. }