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 14 package org.eclipse.jgit.lib; 15 16 import java.io.ByteArrayInputStream; 17 import java.io.EOFException; 18 import java.io.IOException; 19 import java.io.InputStream; 20 21 import org.eclipse.jgit.internal.JGitText; 22 import org.eclipse.jgit.transport.PackParser; 23 import org.eclipse.jgit.util.sha1.SHA1; 24 25 /** 26 * Inserts objects into an existing {@code ObjectDatabase}. 27 * <p> 28 * An inserter is not thread-safe. Individual threads should each obtain their 29 * own unique inserter instance, or must arrange for locking at a higher level 30 * to ensure the inserter is in use by no more than one thread at a time. 31 * <p> 32 * Objects written by an inserter may not be immediately visible for reading 33 * after the insert method completes. Callers must invoke either 34 * {@link #close()} or {@link #flush()} prior to updating references or 35 * otherwise making the returned ObjectIds visible to other code. 36 */ 37 public abstract class ObjectInserter implements AutoCloseable { 38 /** An inserter that can be used for formatting and id generation only. */ 39 public static class Formatter extends ObjectInserter { 40 @Override 41 public ObjectId insert(int objectType, long length, InputStream in) 42 throws IOException { 43 throw new UnsupportedOperationException(); 44 } 45 46 @Override 47 public PackParser newPackParser(InputStream in) throws IOException { 48 throw new UnsupportedOperationException(); 49 } 50 51 @Override 52 public ObjectReader newReader() { 53 throw new UnsupportedOperationException(); 54 } 55 56 @Override 57 public void flush() throws IOException { 58 // Do nothing. 59 } 60 61 @Override 62 public void close() { 63 // Do nothing. 64 } 65 } 66 67 /** Wraps a delegate ObjectInserter. */ 68 public abstract static class Filter extends ObjectInserter { 69 /** @return delegate ObjectInserter to handle all processing. */ 70 protected abstract ObjectInserter delegate(); 71 72 @Override 73 protected byte[] buffer() { 74 return delegate().buffer(); 75 } 76 77 @Override 78 public ObjectId idFor(int type, byte[] data) { 79 return delegate().idFor(type, data); 80 } 81 82 @Override 83 public ObjectId idFor(int type, byte[] data, int off, int len) { 84 return delegate().idFor(type, data, off, len); 85 } 86 87 @Override 88 public ObjectId idFor(int objectType, long length, InputStream in) 89 throws IOException { 90 return delegate().idFor(objectType, length, in); 91 } 92 93 @Override 94 public ObjectId idFor(TreeFormatter formatter) { 95 return delegate().idFor(formatter); 96 } 97 98 @Override 99 public ObjectId insert(int type, byte[] data) throws IOException { 100 return delegate().insert(type, data); 101 } 102 103 @Override 104 public ObjectId insert(int type, byte[] data, int off, int len) 105 throws IOException { 106 return delegate().insert(type, data, off, len); 107 } 108 109 @Override 110 public ObjectId insert(int objectType, long length, InputStream in) 111 throws IOException { 112 return delegate().insert(objectType, length, in); 113 } 114 115 @Override 116 public PackParser newPackParser(InputStream in) throws IOException { 117 return delegate().newPackParser(in); 118 } 119 120 @Override 121 public ObjectReader newReader() { 122 final ObjectReader dr = delegate().newReader(); 123 return new ObjectReader.Filter() { 124 @Override 125 protected ObjectReader delegate() { 126 return dr; 127 } 128 129 @Override 130 public ObjectInserter getCreatedFromInserter() { 131 return ObjectInserter.Filter.this; 132 } 133 }; 134 } 135 136 @Override 137 public void flush() throws IOException { 138 delegate().flush(); 139 } 140 141 @Override 142 public void close() { 143 delegate().close(); 144 } 145 } 146 147 private final SHA1 hasher = SHA1.newInstance(); 148 149 /** Temporary working buffer for streaming data through. */ 150 private byte[] tempBuffer; 151 152 /** 153 * Create a new inserter for a database. 154 */ 155 protected ObjectInserter() { 156 } 157 158 /** 159 * Obtain a temporary buffer for use by the ObjectInserter or its subclass. 160 * <p> 161 * This buffer is supplied by the ObjectInserter base class to itself and 162 * its subclasses for the purposes of pulling data from a supplied 163 * InputStream, passing it through a Deflater, or formatting the canonical 164 * format of a small object like a small tree or commit. 165 * <p> 166 * <strong>This buffer IS NOT for translation such as auto-CRLF or content 167 * filtering and must not be used for such purposes.</strong> 168 * <p> 169 * The returned buffer is small, around a few KiBs, and the size may change 170 * between versions of JGit. Callers using this buffer must always check the 171 * length of the returned array to ascertain how much space was provided. 172 * <p> 173 * There is a single buffer for each ObjectInserter, repeated calls to this 174 * method will (usually) always return the same buffer. If the caller needs 175 * more than one buffer, or needs a buffer of a larger size, it must manage 176 * that buffer on its own. 177 * <p> 178 * The buffer is usually on first demand for a buffer. 179 * 180 * @return a temporary byte array for use by the caller. 181 */ 182 protected byte[] buffer() { 183 byte[] b = tempBuffer; 184 if (b == null) 185 tempBuffer = b = new byte[8192]; 186 return b; 187 } 188 189 /** 190 * Compute digest to help compute an ObjectId 191 * 192 * @return digest to help compute an ObjectId 193 * @since 4.7 194 */ 195 protected SHA1 digest() { 196 return hasher.reset(); 197 } 198 199 /** 200 * Compute the name of an object, without inserting it. 201 * 202 * @param type 203 * type code of the object to store. 204 * @param data 205 * complete content of the object. 206 * @return the name of the object. 207 */ 208 public ObjectId idFor(int type, byte[] data) { 209 return idFor(type, data, 0, data.length); 210 } 211 212 /** 213 * Compute the name of an object, without inserting it. 214 * 215 * @param type 216 * type code of the object to store. 217 * @param data 218 * complete content of the object. 219 * @param off 220 * first position within {@code data}. 221 * @param len 222 * number of bytes to copy from {@code data}. 223 * @return the name of the object. 224 */ 225 public ObjectId idFor(int type, byte[] data, int off, int len) { 226 SHA1 md = SHA1.newInstance(); 227 md.update(Constants.encodedTypeString(type)); 228 md.update((byte) ' '); 229 md.update(Constants.encodeASCII(len)); 230 md.update((byte) 0); 231 md.update(data, off, len); 232 return md.toObjectId(); 233 } 234 235 /** 236 * Compute the name of an object, without inserting it. 237 * 238 * @param objectType 239 * type code of the object to store. 240 * @param length 241 * number of bytes to scan from {@code in}. 242 * @param in 243 * stream providing the object content. The caller is responsible 244 * for closing the stream. 245 * @return the name of the object. 246 * @throws java.io.IOException 247 * the source stream could not be read. 248 */ 249 public ObjectId idFor(int objectType, long length, InputStream in) 250 throws IOException { 251 SHA1 md = SHA1.newInstance(); 252 md.update(Constants.encodedTypeString(objectType)); 253 md.update((byte) ' '); 254 md.update(Constants.encodeASCII(length)); 255 md.update((byte) 0); 256 byte[] buf = buffer(); 257 while (length > 0) { 258 int n = in.read(buf, 0, (int) Math.min(length, buf.length)); 259 if (n < 0) 260 throw new EOFException(JGitText.get().unexpectedEndOfInput); 261 md.update(buf, 0, n); 262 length -= n; 263 } 264 return md.toObjectId(); 265 } 266 267 /** 268 * Compute the ObjectId for the given tree without inserting it. 269 * 270 * @param formatter 271 * a {@link org.eclipse.jgit.lib.TreeFormatter} object. 272 * @return the computed ObjectId 273 */ 274 public ObjectId idFor(TreeFormatter formatter) { 275 return formatter.computeId(this); 276 } 277 278 /** 279 * Insert a single tree into the store, returning its unique name. 280 * 281 * @param formatter 282 * the formatter containing the proposed tree's data. 283 * @return the name of the tree object. 284 * @throws java.io.IOException 285 * the object could not be stored. 286 */ 287 public final ObjectId insert(TreeFormatter formatter) throws IOException { 288 // Delegate to the formatter, as then it can pass the raw internal 289 // buffer back to this inserter, avoiding unnecessary data copying. 290 // 291 return formatter.insertTo(this); 292 } 293 294 /** 295 * Insert a single commit into the store, returning its unique name. 296 * 297 * @param builder 298 * the builder containing the proposed commit's data. 299 * @return the name of the commit object. 300 * @throws java.io.IOException 301 * the object could not be stored. 302 */ 303 public final ObjectId insert(CommitBuilder builder) throws IOException { 304 return insert(Constants.OBJ_COMMIT, builder.build()); 305 } 306 307 /** 308 * Insert a single annotated tag into the store, returning its unique name. 309 * 310 * @param builder 311 * the builder containing the proposed tag's data. 312 * @return the name of the tag object. 313 * @throws java.io.IOException 314 * the object could not be stored. 315 */ 316 public final ObjectId insert(TagBuilder builder) throws IOException { 317 return insert(Constants.OBJ_TAG, builder.build()); 318 } 319 320 /** 321 * Insert a single object into the store, returning its unique name. 322 * 323 * @param type 324 * type code of the object to store. 325 * @param data 326 * complete content of the object. 327 * @return the name of the object. 328 * @throws java.io.IOException 329 * the object could not be stored. 330 */ 331 public ObjectId insert(int type, byte[] data) 332 throws IOException { 333 return insert(type, data, 0, data.length); 334 } 335 336 /** 337 * Insert a single object into the store, returning its unique name. 338 * 339 * @param type 340 * type code of the object to store. 341 * @param data 342 * complete content of the object. 343 * @param off 344 * first position within {@code data}. 345 * @param len 346 * number of bytes to copy from {@code data}. 347 * @return the name of the object. 348 * @throws java.io.IOException 349 * the object could not be stored. 350 */ 351 public ObjectId insert(int type, byte[] data, int off, int len) 352 throws IOException { 353 return insert(type, len, new ByteArrayInputStream(data, off, len)); 354 } 355 356 /** 357 * Insert a single object into the store, returning its unique name. 358 * 359 * @param objectType 360 * type code of the object to store. 361 * @param length 362 * number of bytes to copy from {@code in}. 363 * @param in 364 * stream providing the object content. The caller is responsible 365 * for closing the stream. 366 * @return the name of the object. 367 * @throws java.io.IOException 368 * the object could not be stored, or the source stream could 369 * not be read. 370 */ 371 public abstract ObjectId insert(int objectType, long length, InputStream in) 372 throws IOException; 373 374 /** 375 * Initialize a parser to read from a pack formatted stream. 376 * 377 * @param in 378 * the input stream. The stream is not closed by the parser, and 379 * must instead be closed by the caller once parsing is complete. 380 * @return the pack parser. 381 * @throws java.io.IOException 382 * the parser instance, which can be configured and then used to 383 * parse objects into the ObjectDatabase. 384 */ 385 public abstract PackParser newPackParser(InputStream in) throws IOException; 386 387 /** 388 * Open a reader for objects that may have been written by this inserter. 389 * <p> 390 * The returned reader allows the calling thread to read back recently 391 * inserted objects without first calling {@code flush()} to make them 392 * visible to the repository. The returned reader should only be used from 393 * the same thread as the inserter. Objects written by this inserter may not 394 * be visible to {@code this.newReader().newReader()}. 395 * <p> 396 * The returned reader should return this inserter instance from {@link 397 * ObjectReader#getCreatedFromInserter()}. 398 * <p> 399 * Behavior is undefined if an insert method is called on the inserter in the 400 * middle of reading from an {@link ObjectStream} opened from this reader. For 401 * example, reading the remainder of the object may fail, or newly written 402 * data may even be corrupted. Interleaving whole object reads (including 403 * streaming reads) with inserts is fine, just not interleaving streaming 404 * <em>partial</em> object reads with inserts. 405 * 406 * @since 3.5 407 * @return reader for any object, including an object recently inserted by 408 * this inserter since the last flush. 409 */ 410 public abstract ObjectReader newReader(); 411 412 /** 413 * Make all inserted objects visible. 414 * <p> 415 * The flush may take some period of time to make the objects available to 416 * other threads. 417 * 418 * @throws java.io.IOException 419 * the flush could not be completed; objects inserted thus far 420 * are in an indeterminate state. 421 */ 422 public abstract void flush() throws IOException; 423 424 /** 425 * {@inheritDoc} 426 * <p> 427 * Release any resources used by this inserter. 428 * <p> 429 * An inserter that has been released can be used again, but may need to be 430 * released after the subsequent usage. 431 * 432 * @since 4.0 433 */ 434 @Override 435 public abstract void close(); 436 }