{"thread":{"id":"16854","subject":"[JGIT PATCH] Teach TransportLocal how to use our own ReceivePack implementation","startedAt":"2008-12-23T18:34:59Z","lastAt":"2008-12-23T18:34:59Z","messageCount":1,"participants":["Shawn O. Pearce"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"98637","messageId":"1230057299-13783-1-git-send-email-spearce@spearce.org","threadId":"16854","inReplyTo":null,"subject":"[JGIT PATCH] Teach TransportLocal how to use our own ReceivePack implementation","fromName":"Shawn O. Pearce","fromEmail":"spearce@spearce.org","sentAt":"2008-12-23T18:34:59Z","receivedAt":"2008-12-23T18:34:59Z","isPatch":true,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"If the user hasn't reconfigured git receive-pack on this remote\nthen we can use our internal implementation instead of forking\nout to the C implementation.  It may be faster to stay within\nthe JVM then to start the external process.\n\nIn-memory pipes are constructed to copy the data between the\ncalling client thread and the background ReceivePack worker.\nIn certain cases we may even be able to do a faster copy by\ndirectly hard-linking object files and/or packs, but that\nisn't traditionally how Git behaves, so we use the standard\nnetwork protocol anyway.\n\nSince our ReceivePack process doesn't fire hooks by default\nwe no longer will invoke any hooks during a push to a local\nrepository.\n\nSigned-off-by: Shawn O. Pearce <spearce@spearce.org>\n---\n .../org/spearce/jgit/transport/TransportLocal.java |   88 +++++++++++++++++++-\n 1 files changed, 85 insertions(+), 3 deletions(-)\n\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/TransportLocal.java b/org.spearce.jgit/src/org/spearce/jgit/transport/TransportLocal.java\nindex d74f1b3..b5dd5fc 100644\n--- a/org.spearce.jgit/src/org/spearce/jgit/transport/TransportLocal.java\n+++ b/org.spearce.jgit/src/org/spearce/jgit/transport/TransportLocal.java\n@@ -43,6 +43,8 @@\n import java.io.File;\n import java.io.IOException;\n import java.io.InputStream;\n+import java.io.PipedInputStream;\n+import java.io.PipedOutputStream;\n \n import org.spearce.jgit.errors.NotSupportedException;\n import org.spearce.jgit.errors.TransportException;\n@@ -90,7 +92,10 @@ public FetchConnection openFetch() throws TransportException {\n \t@Override\n \tpublic PushConnection openPush() throws NotSupportedException,\n \t\t\tTransportException {\n-\t\treturn new LocalPushConnection();\n+\t\tfinal String rp = getOptionReceivePack();\n+\t\tif (\"git-receive-pack\".equals(rp) || \"git receive-pack\".equals(rp))\n+\t\t\treturn new InternalLocalPushConnection();\n+\t\treturn new ForkLocalPushConnection();\n \t}\n \n \t@Override\n@@ -151,10 +156,87 @@ public void close() {\n \t\t}\n \t}\n \n-\tclass LocalPushConnection extends BasePackPushConnection {\n+\tclass InternalLocalPushConnection extends BasePackPushConnection {\n+\t\tprivate Thread worker;\n+\n+\t\tInternalLocalPushConnection() throws TransportException {\n+\t\t\tsuper(TransportLocal.this);\n+\n+\t\t\tfinal Repository dst;\n+\t\t\ttry {\n+\t\t\t\tdst = new Repository(remoteGitDir);\n+\t\t\t} catch (IOException err) {\n+\t\t\t\tthrow new TransportException(uri, \"not a git directory\");\n+\t\t\t}\n+\n+\t\t\tfinal PipedInputStream in_r;\n+\t\t\tfinal PipedOutputStream in_w;\n+\n+\t\t\tfinal PipedInputStream out_r;\n+\t\t\tfinal PipedOutputStream out_w;\n+\t\t\ttry {\n+\t\t\t\tin_r = new PipedInputStream();\n+\t\t\t\tin_w = new PipedOutputStream(in_r);\n+\n+\t\t\t\tout_r = new PipedInputStream();\n+\t\t\t\tout_w = new PipedOutputStream(out_r);\n+\t\t\t} catch (IOException err) {\n+\t\t\t\tdst.close();\n+\t\t\t\tthrow new TransportException(uri, \"cannot connect pipes\", err);\n+\t\t\t}\n+\n+\t\t\tworker = new Thread(\"JGit-Receive-Pack\") {\n+\t\t\t\tpublic void run() {\n+\t\t\t\t\ttry {\n+\t\t\t\t\t\tfinal ReceivePack rp = new ReceivePack(dst);\n+\t\t\t\t\t\trp.receive(out_r, in_w, System.err);\n+\t\t\t\t\t} catch (IOException err) {\n+\t\t\t\t\t\t// Client side of the pipes should report the problem.\n+\t\t\t\t\t} catch (RuntimeException err) {\n+\t\t\t\t\t\t// Clients side will notice we went away, and report.\n+\t\t\t\t\t} finally {\n+\t\t\t\t\t\ttry {\n+\t\t\t\t\t\t\tout_r.close();\n+\t\t\t\t\t\t} catch (IOException e2) {\n+\t\t\t\t\t\t\t// Ignore close failure, we probably crashed above.\n+\t\t\t\t\t\t}\n+\n+\t\t\t\t\t\ttry {\n+\t\t\t\t\t\t\tin_w.close();\n+\t\t\t\t\t\t} catch (IOException e2) {\n+\t\t\t\t\t\t\t// Ignore close failure, we probably crashed above.\n+\t\t\t\t\t\t}\n+\n+\t\t\t\t\t\tdst.close();\n+\t\t\t\t\t}\n+\t\t\t\t}\n+\t\t\t};\n+\t\t\tworker.start();\n+\n+\t\t\tinit(in_r, out_w);\n+\t\t\treadAdvertisedRefs();\n+\t\t}\n+\n+\t\t@Override\n+\t\tpublic void close() {\n+\t\t\tsuper.close();\n+\n+\t\t\tif (worker != null) {\n+\t\t\t\ttry {\n+\t\t\t\t\tworker.join();\n+\t\t\t\t} catch (InterruptedException ie) {\n+\t\t\t\t\t// Stop waiting and return anyway.\n+\t\t\t\t} finally {\n+\t\t\t\t\tworker = null;\n+\t\t\t\t}\n+\t\t\t}\n+\t\t}\n+\t}\n+\n+\tclass ForkLocalPushConnection extends BasePackPushConnection {\n \t\tprivate Process receivePack;\n \n-\t\tLocalPushConnection() throws TransportException {\n+\t\tForkLocalPushConnection() throws TransportException {\n \t\t\tsuper(TransportLocal.this);\n \t\t\treceivePack = startProcessWithErrStream(getOptionReceivePack());\n \t\t\tinit(receivePack.getInputStream(), receivePack.getOutputStream());\n-- \n1.6.1.rc4.301.g5497a\n"}]}