From 9b917ac169e8cf33f0fbbec07c0e89cbc180cfd7 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Mon, 14 Mar 2011 15:36:17 -0700 Subject: [PATCH] Improve native Git transport when following repository If the client is only following the remote repository and has not created any new non-common commits, the client will wind up sending a "have %s" line for each tag in the repository. For some projects like git.git, this is 339 tags and growing, resulting in more than 16 KiB needing to be POSTed over 12 HTTP requests. Teach UploadPack (server side) to always execute the okToGiveUp() logic at least once per negotiation round to determine if the server can compute a pack right now. If it can, shove in an "ACK %s ready" message to tell the client this and try to prevent receiving ancient tags in future negotiation rounds. Teach BasePackFetchConnection (client side) to honor a "ACK %s ready" from the remote and break out of its SEND_HAVE loop once the remote knows it can create a pack. This avoids sending the remaining 307 tags of git.git. These two changes together reduce the number of HTTP RPCs from 13 down to 3 in order to fetch from git.git over smart HTTP. If either side is missing the change, the older behavior (and its 13 RPCs) is used. Change-Id: I64736318fd0abf9ee5e56bd0b737707adb580b37 Signed-off-by: Shawn O. Pearce --- .../eclipse/jgit/transport/BasePackFetchConnection.java | 5 ++++- .../src/org/eclipse/jgit/transport/UploadPack.java | 7 +++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/BasePackFetchConnection.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/BasePackFetchConnection.java index 4f3d1bb49..7d8590a77 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/BasePackFetchConnection.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/BasePackFetchConnection.java @@ -434,12 +434,13 @@ public abstract class BasePackFetchConnection extends BasePackConnection int havesSinceLastContinue = 0; boolean receivedContinue = false; boolean receivedAck = false; + boolean negotiate = true; if (statelessRPC) state.writeTo(out, null); negotiateBegin(); - SEND_HAVES: for (;;) { + SEND_HAVES: while (negotiate) { final RevCommit c = walk.next(); if (c == null) break SEND_HAVES; @@ -505,6 +506,8 @@ public abstract class BasePackFetchConnection extends BasePackConnection receivedAck = true; receivedContinue = true; havesSinceLastContinue = 0; + if (anr == AckNackResult.ACK_READY) + negotiate = false; break; } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPack.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPack.java index 798c4638f..58a48f10e 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPack.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPack.java @@ -591,9 +591,11 @@ public class UploadPack { // create a pack at this point, let the client know so it stops // telling us about its history. // + boolean didOkToGiveUp = false; for (int i = peerHas.size() - 1; i >= 0; i--) { ObjectId id = peerHas.get(i); if (walk.lookupOrNull(id) == null) { + didOkToGiveUp = true; if (okToGiveUp()) { switch (multiAck) { case OFF: @@ -610,6 +612,11 @@ public class UploadPack { } } + if (multiAck == MultiAck.DETAILED && !didOkToGiveUp && okToGiveUp()) { + ObjectId id = peerHas.get(peerHas.size() - 1); + pckOut.writeString("ACK " + id.name() + " ready\n"); + } + peerHas.clear(); return last; }