Ver código fonte

smart-http: Support progress in ReceivePack

As PackParser supports a progress meter for the "Resolving deltas"
phase of its work, we should export this to smart HTTP clients so
they know the server is still working on their (large) upload.

However this isn't as simple as just dropping in a binding for
the SmartOutputStream to flush when its told to.  We want to
avoid spurious flushes triggered by the use of sideband, or the
status report formatting in the send-pack/receive-pack protocol.

Change-Id: Ibd88022a298c5fed0edb23dfaf2e90278807ba8b
Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
tags/v0.12.1
Shawn O. Pearce 13 anos atrás
pai
commit
bd531eb998

+ 6
- 1
org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/ReceivePackServlet.java Ver arquivo

rp.setBiDirectionalPipe(false); rp.setBiDirectionalPipe(false);
rsp.setContentType(RSP_TYPE); rsp.setContentType(RSP_TYPE);


final SmartOutputStream out = new SmartOutputStream(req, rsp);
final SmartOutputStream out = new SmartOutputStream(req, rsp) {
@Override
public void flush() throws IOException {
doFlush();
}
};
rp.receive(getInputStream(req), out, null); rp.receive(getInputStream(req), out, null);
out.close(); out.close();



+ 16
- 1
org.eclipse.jgit/src/org/eclipse/jgit/transport/PacketLineOut.java Ver arquivo



private final byte[] lenbuffer; private final byte[] lenbuffer;


private boolean flushOnEnd;

/** /**
* Create a new packet line writer. * Create a new packet line writer.
* *
public PacketLineOut(final OutputStream outputStream) { public PacketLineOut(final OutputStream outputStream) {
out = outputStream; out = outputStream;
lenbuffer = new byte[5]; lenbuffer = new byte[5];
flushOnEnd = true;
}

/**
* Set the flush behavior during {@link #end()}.
*
* @param flushOnEnd
* if true, a flush-pkt written during {@link #end()} also
* flushes the underlying stream.
*/
public void setFlushOnEnd(boolean flushOnEnd) {
this.flushOnEnd = flushOnEnd;
} }


/** /**
public void end() throws IOException { public void end() throws IOException {
formatLength(0); formatLength(0);
out.write(lenbuffer, 0, 4); out.write(lenbuffer, 0, 4);
flush();
if (flushOnEnd)
flush();
} }


/** /**

+ 33
- 25
org.eclipse.jgit/src/org/eclipse/jgit/transport/ReceivePack.java Ver arquivo

import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.text.MessageFormat; import java.text.MessageFormat;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import org.eclipse.jgit.errors.PackProtocolException; import org.eclipse.jgit.errors.PackProtocolException;
import org.eclipse.jgit.errors.UnpackException; import org.eclipse.jgit.errors.UnpackException;
import org.eclipse.jgit.lib.Config; import org.eclipse.jgit.lib.Config;
import org.eclipse.jgit.lib.Config.SectionParser;
import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.NullProgressMonitor; import org.eclipse.jgit.lib.NullProgressMonitor;
import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.Ref; import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.RefUpdate; import org.eclipse.jgit.lib.RefUpdate;
import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.lib.Config.SectionParser;
import org.eclipse.jgit.revwalk.ObjectWalk; import org.eclipse.jgit.revwalk.ObjectWalk;
import org.eclipse.jgit.revwalk.RevBlob; import org.eclipse.jgit.revwalk.RevBlob;
import org.eclipse.jgit.revwalk.RevCommit; import org.eclipse.jgit.revwalk.RevCommit;


private OutputStream rawOut; private OutputStream rawOut;


private OutputStream msgOut;

private PacketLineIn pckIn; private PacketLineIn pckIn;


private PacketLineOut pckOut; private PacketLineOut pckOut;


private Writer msgs;

private SideBandOutputStream msgOut;

private PackParser parser; private PackParser parser;


/** The refs we advertised as existing at the start of the connection. */ /** The refs we advertised as existing at the start of the connection. */
advertiseError.append(what).append('\n'); advertiseError.append(what).append('\n');
} else { } else {
try { try {
if (msgs != null)
msgs.write("error: " + what + "\n");
if (msgOut != null)
msgOut.write(Constants.encode("error: " + what + "\n"));
} catch (IOException e) { } catch (IOException e) {
// Ignore write failures. // Ignore write failures.
} }
*/ */
public void sendMessage(final String what) { public void sendMessage(final String what) {
try { try {
if (msgs != null)
msgs.write(what + "\n");
if (msgOut != null)
msgOut.write(Constants.encode(what + "\n"));
} catch (IOException e) { } catch (IOException e) {
// Ignore write failures. // Ignore write failures.
} }
try { try {
rawIn = input; rawIn = input;
rawOut = output; rawOut = output;
msgOut = messages;


if (timeout > 0) { if (timeout > 0) {
final Thread caller = Thread.currentThread(); final Thread caller = Thread.currentThread();


pckIn = new PacketLineIn(rawIn); pckIn = new PacketLineIn(rawIn);
pckOut = new PacketLineOut(rawOut); pckOut = new PacketLineOut(rawOut);
if (messages != null)
msgs = new OutputStreamWriter(messages, Constants.CHARSET);
pckOut.setFlushOnEnd(false);


enabledCapablities = new HashSet<String>(); enabledCapablities = new HashSet<String>();
commands = new ArrayList<ReceiveCommand>(); commands = new ArrayList<ReceiveCommand>();
} finally { } finally {
walk.release(); walk.release();
try { try {
if (pckOut != null)
pckOut.flush();
if (msgs != null)
msgs.flush();

if (sideBand) { if (sideBand) {
// If we are using side band, we need to send a final // If we are using side band, we need to send a final
// flush-pkt to tell the remote peer the side band is // flush-pkt to tell the remote peer the side band is
// use the original output stream as rawOut is now the // use the original output stream as rawOut is now the
// side band data channel. // side band data channel.
// //
new PacketLineOut(output).end();
((SideBandOutputStream) msgOut).flushBuffer();
((SideBandOutputStream) rawOut).flushBuffer();

PacketLineOut plo = new PacketLineOut(output);
plo.setFlushOnEnd(false);
plo.end();
}

if (biDirectionalPipe) {
// If this was a native git connection, flush the pipe for
// the caller. For smart HTTP we don't do this flush and
// instead let the higher level HTTP servlet code do it.
//
if (!sideBand && msgOut != null)
msgOut.flush();
rawOut.flush();
} }
} finally { } finally {
unlockPack(); unlockPack();
timeoutIn = null; timeoutIn = null;
rawIn = null; rawIn = null;
rawOut = null; rawOut = null;
msgOut = null;
pckIn = null; pckIn = null;
pckOut = null; pckOut = null;
msgs = null;
refs = null; refs = null;
enabledCapablities = null; enabledCapablities = null;
commands = null; commands = null;
} }


private void service() throws IOException { private void service() throws IOException {
if (biDirectionalPipe)
if (biDirectionalPipe) {
sendAdvertisedRefs(new PacketLineOutRefAdvertiser(pckOut)); sendAdvertisedRefs(new PacketLineOutRefAdvertiser(pckOut));
else
pckOut.flush();
} else
refs = refFilter.filter(db.getAllRefs()); refs = refFilter.filter(db.getAllRefs());
if (advertiseError != null) if (advertiseError != null)
return; return;
} }
}); });
pckOut.end(); pckOut.end();
} else if (msgs != null) {
} else if (msgOut != null) {
sendStatusReport(false, new Reporter() { sendStatusReport(false, new Reporter() {
void sendString(final String s) throws IOException { void sendString(final String s) throws IOException {
msgs.write(s + "\n");
msgOut.write(Constants.encode(s + "\n"));
} }
}); });
} }


rawOut = new SideBandOutputStream(CH_DATA, MAX_BUF, out); rawOut = new SideBandOutputStream(CH_DATA, MAX_BUF, out);
msgOut = new SideBandOutputStream(CH_PROGRESS, MAX_BUF, out); msgOut = new SideBandOutputStream(CH_PROGRESS, MAX_BUF, out);

pckOut = new PacketLineOut(rawOut); pckOut = new PacketLineOut(rawOut);
msgs = new OutputStreamWriter(msgOut, Constants.CHARSET);
pckOut.setFlushOnEnd(false);
} }
} }



+ 6
- 2
org.eclipse.jgit/src/org/eclipse/jgit/transport/SideBandOutputStream.java Ver arquivo

cnt = HDR_SIZE; cnt = HDR_SIZE;
} }


@Override
public void flush() throws IOException {
void flushBuffer() throws IOException {
if (HDR_SIZE < cnt) if (HDR_SIZE < cnt)
writeBuffer(); writeBuffer();
}

@Override
public void flush() throws IOException {
flushBuffer();
out.flush(); out.flush();
} }



Carregando…
Cancelar
Salvar