diff options
author | Shawn Pearce <spearce@spearce.org> | 2016-06-18 21:40:35 -0700 |
---|---|---|
committer | Shawn Pearce <spearce@spearce.org> | 2016-06-18 21:41:07 -0700 |
commit | 2ec3accb3bcc0bd45dfb1333511c72489ab835cb (patch) | |
tree | 254acfa17ca33a0e3806ff7ddee9cbe1b25c32ad /org.eclipse.jgit/src/org/eclipse/jgit/transport/RefAdvertiser.java | |
parent | 48cb5ffba6d2b11aea407cdd93e5a8ffb7bfec17 (diff) | |
download | jgit-2ec3accb3bcc0bd45dfb1333511c72489ab835cb.tar.gz jgit-2ec3accb3bcc0bd45dfb1333511c72489ab835cb.zip |
Optimize RefAdvertiser for wire protocol
The native wire protocol sends ref advertisements in the pkt-line
format, which requires encoding the ObjectId and ref name onto a byte
sequence. Busy servers show this is a very high source of garbage,
which pushes the garbage collector harder when there are many refs in
the repository (e.g. 70k, in a Gerrit managed repository).
Optimize the side band advertiser by retaining the CharsetEncoder,
minimizing the amount of temporary garbage built during encoding.
Change-Id: I406c654bf82c1eb94b38862da2425e98396134cb
Diffstat (limited to 'org.eclipse.jgit/src/org/eclipse/jgit/transport/RefAdvertiser.java')
-rw-r--r-- | org.eclipse.jgit/src/org/eclipse/jgit/transport/RefAdvertiser.java | 76 |
1 files changed, 74 insertions, 2 deletions
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/RefAdvertiser.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/RefAdvertiser.java index f72a4b2b30..0cd720c29d 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/RefAdvertiser.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/RefAdvertiser.java @@ -43,9 +43,16 @@ package org.eclipse.jgit.transport; +import static java.nio.charset.StandardCharsets.UTF_8; +import static org.eclipse.jgit.lib.Constants.OBJECT_ID_STRING_LENGTH; import static org.eclipse.jgit.transport.GitProtocolConstants.OPTION_SYMREF; import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.CharBuffer; +import java.nio.charset.CharacterCodingException; +import java.nio.charset.CharsetEncoder; +import java.nio.charset.CoderResult; import java.util.HashSet; import java.util.LinkedHashSet; import java.util.Map; @@ -64,8 +71,15 @@ import org.eclipse.jgit.util.RefMap; public abstract class RefAdvertiser { /** Advertiser which frames lines in a {@link PacketLineOut} format. */ public static class PacketLineOutRefAdvertiser extends RefAdvertiser { + private final CharsetEncoder utf8 = UTF_8.newEncoder(); private final PacketLineOut pckOut; + private byte[] binArr = new byte[256]; + private ByteBuffer binBuf = ByteBuffer.wrap(binArr); + + private char[] chArr = new char[256]; + private CharBuffer chBuf = CharBuffer.wrap(chArr); + /** * Create a new advertiser for the supplied stream. * @@ -77,6 +91,64 @@ public abstract class RefAdvertiser { } @Override + public void advertiseId(AnyObjectId id, String refName) + throws IOException { + id.copyTo(binArr, 0); + binArr[OBJECT_ID_STRING_LENGTH] = ' '; + binBuf.position(OBJECT_ID_STRING_LENGTH + 1); + append(refName); + if (first) { + first = false; + if (!capablities.isEmpty()) { + append('\0'); + for (String cap : capablities) { + append(' '); + append(cap); + } + } + } + append('\n'); + pckOut.writePacket(binArr, 0, binBuf.position()); + } + + private void append(String str) throws CharacterCodingException { + int n = str.length(); + if (n > chArr.length) { + chArr = new char[n + 256]; + chBuf = CharBuffer.wrap(chArr); + } + str.getChars(0, n, chArr, 0); + chBuf.position(0).limit(n); + utf8.reset(); + for (;;) { + CoderResult cr = utf8.encode(chBuf, binBuf, true); + if (cr.isOverflow()) { + grow(); + } else if (cr.isUnderflow()) { + break; + } else { + cr.throwException(); + } + } + } + + private void append(int b) { + if (!binBuf.hasRemaining()) { + grow(); + } + binBuf.put((byte) b); + } + + private void grow() { + int cnt = binBuf.position(); + byte[] tmp = new byte[binArr.length << 1]; + System.arraycopy(binArr, 0, tmp, 0, cnt); + binArr = tmp; + binBuf = ByteBuffer.wrap(binArr); + binBuf.position(cnt); + } + + @Override protected void writeOne(final CharSequence line) throws IOException { pckOut.writeString(line.toString()); } @@ -91,7 +163,7 @@ public abstract class RefAdvertiser { private final char[] tmpId = new char[Constants.OBJECT_ID_STRING_LENGTH]; - private final Set<String> capablities = new LinkedHashSet<String>(); + final Set<String> capablities = new LinkedHashSet<String>(); private final Set<ObjectId> sent = new HashSet<ObjectId>(); @@ -99,7 +171,7 @@ public abstract class RefAdvertiser { private boolean derefTags; - private boolean first = true; + boolean first = true; /** * Initialize this advertiser with a repository for peeling tags. |