From 46ef61a7027449198abe2f18c3ee1d6c578cf949 Mon Sep 17 00:00:00 2001 From: Shawn Pearce Date: Wed, 10 Apr 2013 10:17:25 -0700 Subject: [PATCH] Tighten object header writing in PackOutuptStream Most objects are written as OFS_DELTA with the base in the pack, that is why this case comes first in writeHeader(). Rewrite the condition to always examine this first and cache the PackWriter's formatting flag for use of OFS_DELTA headers, in modern Git networks this is true more often then it it is false. Assume the cost of write() is high, especially due to entering the MessageDigest to update the pack footer SHA-1 computation. Combine the OFS_DELTA information as part of the header buffer so that the entire burst is a single write call, rather than two relatively small ones. Most OFS_DELTA headers are <= 6 bytes, so this rewrite tranforms 2 writes of 3 bytes each into 1 write of ~6 bytes. Try to simplify the objectHeader code to reduce branches and use more local registers. This shouldn't really be necessary if the compiler is well optimized, but it isn't very hard to clarify data usage to either javac or the JIT, which may make it easier for the JIT to produce better machine code for this method. Change-Id: I2b12788ad6866076fabbf7fa11f8cce44e963f35 --- .../storage/pack/PackOutputStream.java | 71 +++++++++++-------- 1 file changed, 40 insertions(+), 31 deletions(-) diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/PackOutputStream.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/PackOutputStream.java index 68f74641b..2533e906e 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/PackOutputStream.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/PackOutputStream.java @@ -44,6 +44,10 @@ package org.eclipse.jgit.internal.storage.pack; +import static org.eclipse.jgit.lib.Constants.OBJ_OFS_DELTA; +import static org.eclipse.jgit.lib.Constants.OBJ_REF_DELTA; +import static org.eclipse.jgit.lib.Constants.PACK_SIGNATURE; + import java.io.IOException; import java.io.OutputStream; import java.security.MessageDigest; @@ -73,6 +77,8 @@ public final class PackOutputStream extends OutputStream { private long checkCancelAt; + private boolean ofsDelta; + /** * Initialize a pack output stream. *

@@ -132,10 +138,11 @@ public final class PackOutputStream extends OutputStream { final void writeFileHeader(int version, long objectCount) throws IOException { - System.arraycopy(Constants.PACK_SIGNATURE, 0, headerBuffer, 0, 4); + System.arraycopy(PACK_SIGNATURE, 0, headerBuffer, 0, 4); NB.encodeInt32(headerBuffer, 4, version); NB.encodeInt32(headerBuffer, 8, (int) objectCount); write(headerBuffer, 0, 12); + ofsDelta = packWriter.isDeltaBaseAsOffset(); } /** @@ -175,43 +182,45 @@ public final class PackOutputStream extends OutputStream { */ public final void writeHeader(ObjectToPack otp, long rawLength) throws IOException { - if (otp.isDeltaRepresentation()) { - if (packWriter.isDeltaBaseAsOffset()) { - ObjectToPack baseInPack = otp.getDeltaBase(); - if (baseInPack != null && baseInPack.isWritten()) { - final long start = count; - int n = encodeTypeSize(Constants.OBJ_OFS_DELTA, rawLength); - write(headerBuffer, 0, n); - - long offsetDiff = start - baseInPack.getOffset(); - n = headerBuffer.length - 1; - headerBuffer[n] = (byte) (offsetDiff & 0x7F); - while ((offsetDiff >>= 7) > 0) - headerBuffer[--n] = (byte) (0x80 | (--offsetDiff & 0x7F)); - write(headerBuffer, n, headerBuffer.length - n); - return; - } - } - - int n = encodeTypeSize(Constants.OBJ_REF_DELTA, rawLength); + ObjectToPack b = otp.getDeltaBase(); + if (b != null && (b.isWritten() & ofsDelta)) { + int n = objectHeader(rawLength, OBJ_OFS_DELTA, headerBuffer); + n = ofsDelta(count - b.getOffset(), headerBuffer, n); + write(headerBuffer, 0, n); + } else if (otp.isDeltaRepresentation()) { + int n = objectHeader(rawLength, OBJ_REF_DELTA, headerBuffer); otp.getDeltaBaseId().copyRawTo(headerBuffer, n); - write(headerBuffer, 0, n + Constants.OBJECT_ID_LENGTH); + write(headerBuffer, 0, n + 20); } else { - int n = encodeTypeSize(otp.getType(), rawLength); + int n = objectHeader(rawLength, otp.getType(), headerBuffer); write(headerBuffer, 0, n); } } - private final int encodeTypeSize(int type, long rawLength) { - long nextLength = rawLength >>> 4; - headerBuffer[0] = (byte) ((nextLength > 0 ? 0x80 : 0x00) | (type << 4) | (rawLength & 0x0F)); - rawLength = nextLength; - int n = 1; - while (rawLength > 0) { - nextLength >>>= 7; - headerBuffer[n++] = (byte) ((nextLength > 0 ? 0x80 : 0x00) | (rawLength & 0x7F)); - rawLength = nextLength; + private static final int objectHeader(long len, int type, byte[] buf) { + byte b = (byte) ((type << 4) | (len & 0x0F)); + int n = 0; + for (len >>>= 4; len != 0; len >>>= 7) { + buf[n++] = (byte) (0x80 | b); + b = (byte) (len & 0x7F); } + buf[n++] = b; + return n; + } + + private static final int ofsDelta(long diff, byte[] buf, int p) { + p += ofsDeltaVarIntLength(diff); + int n = p; + buf[--n] = (byte) (diff & 0x7F); + while ((diff >>>= 7) != 0) + buf[--n] = (byte) (0x80 | (--diff & 0x7F)); + return p; + } + + private static final int ofsDeltaVarIntLength(long v) { + int n = 1; + for (; (v >>>= 7) != 0; n++) + --v; return n; }