git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[JGIT PATCH 5/5] Switch local fetch connection to use our own UploadPack

From
Shawn O. Pearce <spearce@spearce.org>
Date
Dec 23, 2008, 22:56 UTC
Message-ID
<1230073007-17337-6-git-send-email-spearce@spearce.org>
In-Reply-To
<1230073007-17337-5-git-send-email-spearce@spearce.org>

Just like with push, we now use our own version of upload pack to perform a fetch from a local repository.

Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
---
 .../jgit/transport/BasePackFetchConnection.java    |    2 +
 .../org/spearce/jgit/transport/TransportLocal.java |   96 +++++++++++++++++++-
 2 files changed, 95 insertions(+), 3 deletions(-)
diff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/BasePackFetchConnection.java b/org.spearce.jgit/src/org/spearce/jgit/transport/BasePackFetchConnection.java
index 1fe504b..19ac161 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/transport/BasePackFetchConnection.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/BasePackFetchConnection.java
@@ -86,6 +86,8 @@
 	 */
 	private static final int MAX_HAVES = 256;
 
+	protected static final int MAX_CLIENT_BUFFER = MAX_HAVES * 46 + 1024;
+
 	static final String OPTION_INCLUDE_TAG = "include-tag";
 
 	static final String OPTION_MULTI_ACK = "multi_ack";
diff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/TransportLocal.java b/org.spearce.jgit/src/org/spearce/jgit/transport/TransportLocal.java
index b5dd5fc..17d95c2 100644
--- a/org.spearce.jgit/src/org/spearce/jgit/transport/TransportLocal.java
+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/TransportLocal.java
@@ -86,7 +86,10 @@ TransportLocal(final Repository local, final URIish uri) {
 
 	@Override
 	public FetchConnection openFetch() throws TransportException {
-		return new LocalFetchConnection();
+		final String up = getOptionUploadPack();
+		if ("git-upload-pack".equals(up) || "git upload-pack".equals(up))
+			return new InternalLocalFetchConnection();
+		return new ForkLocalFetchConnection();
 	}
 
 	@Override
@@ -130,10 +133,97 @@ protected Process startProcessWithErrStream(final String cmd)
 		}
 	}
 
-	class LocalFetchConnection extends BasePackFetchConnection {
+	class InternalLocalFetchConnection extends BasePackFetchConnection {
+		private Thread worker;
+
+		InternalLocalFetchConnection() throws TransportException {
+			super(TransportLocal.this);
+
+			final Repository dst;
+			try {
+				dst = new Repository(remoteGitDir);
+			} catch (IOException err) {
+				throw new TransportException(uri, "not a git directory");
+			}
+
+			final PipedInputStream in_r;
+			final PipedOutputStream in_w;
+
+			final PipedInputStream out_r;
+			final PipedOutputStream out_w;
+			try {
+				in_r = new PipedInputStream();
+				in_w = new PipedOutputStream(in_r);
+
+				out_r = new PipedInputStream() {
+					// The client (BasePackFetchConnection) can write
+					// a huge burst before it reads again. We need to
+					// force the buffer to be big enough, otherwise it
+					// will deadlock both threads.
+					{
+						buffer = new byte[MAX_CLIENT_BUFFER];
+					}
+				};
+				out_w = new PipedOutputStream(out_r);
+			} catch (IOException err) {
+				dst.close();
+				throw new TransportException(uri, "cannot connect pipes", err);
+			}
+
+			worker = new Thread("JGit-Upload-Pack") {
+				public void run() {
+					try {
+						final UploadPack rp = new UploadPack(dst);
+						rp.upload(out_r, in_w, null);
+					} catch (IOException err) {
+						// Client side of the pipes should report the problem.
+						err.printStackTrace();
+					} catch (RuntimeException err) {
+						// Clients side will notice we went away, and report.
+						err.printStackTrace();
+					} finally {
+						try {
+							out_r.close();
+						} catch (IOException e2) {
+							// Ignore close failure, we probably crashed above.
+						}
+
+						try {
+							in_w.close();
+						} catch (IOException e2) {
+							// Ignore close failure, we probably crashed above.
+						}
+
+						dst.close();
+					}
+				}
+			};
+			worker.start();
+
+			init(in_r, out_w);
+			readAdvertisedRefs();
+		}
+
+		@Override
+		public void close() {
+			super.close();
+
+			if (worker != null) {
+				try {
+					worker.join();
+				} catch (InterruptedException ie) {
+					// Stop waiting and return anyway.
+				} finally {
+					worker = null;
+				}
+			}
+		}
+	}
+
+	class ForkLocalFetchConnection extends BasePackFetchConnection {
 		private Process uploadPack;
 
-		LocalFetchConnection() throws TransportException {
+		ForkLocalFetchConnection() throws TransportException {
 			super(TransportLocal.this);
 			uploadPack = startProcessWithErrStream(getOptionUploadPack());
 			init(uploadPack.getInputStream(), uploadPack.getOutputStream());
-- 
1.6.1.rc4.301.g5497a
Previous: Shawn O. Pearce
Message 6 of 6 in “Add "jgit upload-pack" for fetch service”
  1. 0/5 Add "jgit upload-pack" for fetch serviceShawn O. Pearce, Dec 23, 2008
  2. 1/5 Sort Ref objects by OrigName and not NameShawn O. Pearce, Dec 23, 2008
  3. 2/5 Permit subclass of ObjectId (e.g. RevObject) when calling PackWriterShawn O. Pearce, Dec 23, 2008
  4. 3/5 Implement "jgit upload-pack" to support fetching from jgitShawn O. Pearce, Dec 23, 2008
  5. 4/5 Fix BaseFetchPackConnection's output of selected capabilitiesShawn O. Pearce, Dec 23, 2008
  6. 5/5 Switch local fetch connection to use our own UploadPackShawn O. Pearce, Dec 23, 2008

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.