Add fetch statistics for the counts of advertised refs, wants and haves.
Also add the duration in milliseconds for the negotiation phase. For
non-bidirectional transports like HTTP, this is the time for the final
round that sends the pack back to the user.
Change-Id: I1af7ffd3cb7b62182340682e2a243691ea24ec2e
Signed-off-by: Terry Parker <tparker@google.com>
import java.util.zip.DeflaterOutputStream;
import org.eclipse.jgit.annotations.NonNull;
+import org.eclipse.jgit.annotations.Nullable;
import org.eclipse.jgit.errors.CorruptObjectException;
import org.eclipse.jgit.errors.IncorrectObjectTypeException;
import org.eclipse.jgit.errors.LargeObjectException;
* reader to read from the repository with.
*/
public PackWriter(final PackConfig config, final ObjectReader reader) {
+ this(config, reader, null);
+ }
+
+ /**
+ * Create writer with a specified configuration.
+ * <p>
+ * Objects for packing are specified in {@link #preparePack(Iterator)} or
+ * {@link #preparePack(ProgressMonitor, Set, Set)}.
+ *
+ * @param config
+ * configuration for the pack writer.
+ * @param reader
+ * reader to read from the repository with.
+ * @param statsAccumulator
+ * accumulator for statics
+ */
+ public PackWriter(PackConfig config, final ObjectReader reader,
+ @Nullable PackStatistics.Accumulator statsAccumulator) {
this.config = config;
this.reader = reader;
if (reader instanceof ObjectReuseAsIs)
deltaBaseAsOffset = config.isDeltaBaseAsOffset();
reuseDeltas = config.isReuseDeltas();
reuseValidate = true; // be paranoid by default
- stats = new PackStatistics.Accumulator();
+ stats = statsAccumulator != null ? statsAccumulator
+ : new PackStatistics.Accumulator();
state = new MutableState();
selfRef = new WeakReference<>(this);
instances.put(selfRef, Boolean.TRUE);
* POJO for accumulating the statistics.
*/
public static class Accumulator {
+ /**
+ * The count of references in the ref advertisement.
+ *
+ * @since 4.11
+ */
+ public long advertised;
+
+ /**
+ * The count of client wants.
+ *
+ * @since 4.11
+ */
+ public long wants;
+
+ /**
+ * The count of client haves.
+ *
+ * @since 4.11
+ */
+ public long haves;
+
+ /**
+ * Time in ms spent in the negotiation phase. For non-bidirectional
+ * transports (e.g., HTTP), this is only for the final request that
+ * sends back the pack file.
+ *
+ * @since 4.11
+ */
+ public long timeNegotiating;
+
/** The set of objects to be included in the pack. */
public Set<ObjectId> interestingObjects;
statistics = accumulator;
}
+ /**
+ * Get the count of references in the ref advertisement.
+ *
+ * @return count of refs in the ref advertisement.
+ * @since 4.11
+ */
+ public long getAdvertised() {
+ return statistics.advertised;
+ }
+
+ /**
+ * Get the count of client wants.
+ *
+ * @return count of client wants.
+ * @since 4.11
+ */
+ public long getWants() {
+ return statistics.wants;
+ }
+
+ /**
+ * Get the count of client haves.
+ *
+ * @return count of client haves.
+ * @since 4.11
+ */
+ public long getHaves() {
+ return statistics.haves;
+ }
+
+ /**
+ * Time in ms spent in the negotiation phase. For non-bidirectional
+ * transports (e.g., HTTP), this is only for the final request that sends
+ * back the pack file.
+ *
+ * @return time for ref advertisement in ms.
+ * @since 4.11
+ */
+ public long getTimeNegotiating() {
+ return statistics.timeNegotiating;
+ }
+
/**
* Get unmodifiable collection of objects to be included in the pack.
*
boolean sendPack = false;
// If it's a non-bidi request, we need to read the entire request before
// writing a response. Buffer the response until then.
+ PackStatistics.Accumulator accumulator = new PackStatistics.Accumulator();
try {
if (biDirectionalPipe)
sendAdvertisedRefs(new PacketLineOutRefAdvertiser(pckOut));
else
advertised = refIdSet(getAdvertisedOrDefaultRefs().values());
+ long negotiateStart = System.currentTimeMillis();
+ accumulator.advertised = advertised.size();
recvWants();
if (wantIds.isEmpty()) {
preUploadHook.onBeginNegotiateRound(this, wantIds, 0);
preUploadHook.onEndNegotiateRound(this, wantIds, 0, 0, false);
return;
}
+ accumulator.wants = wantIds.size();
if (options.contains(OPTION_MULTI_ACK_DETAILED)) {
multiAck = MultiAck.DETAILED;
processShallow();
if (!clientShallowCommits.isEmpty())
walk.assumeShallow(clientShallowCommits);
- sendPack = negotiate();
+ sendPack = negotiate(accumulator);
+ accumulator.timeNegotiating += System.currentTimeMillis()
+ - negotiateStart;
+
if (sendPack && !biDirectionalPipe) {
// Ensure the request was fully consumed. Any remaining input must
// be a protocol error. If we aren't at EOF the implementation is broken.
}
if (sendPack)
- sendPack();
+ sendPack(accumulator);
}
private static Set<ObjectId> refIdSet(Collection<Ref> refs) {
return UserAgent.getAgent(options, userAgent);
}
- private boolean negotiate() throws IOException {
+ private boolean negotiate(PackStatistics.Accumulator accumulator)
+ throws IOException {
okToGiveUp = Boolean.FALSE;
ObjectId last = ObjectId.zeroId();
} else if (line.startsWith("have ") && line.length() == 45) { //$NON-NLS-1$
peerHas.add(ObjectId.fromString(line.substring(5)));
-
+ accumulator.haves++;
} else if (line.equals("done")) { //$NON-NLS-1$
last = processHaveLines(peerHas, last);
return false;
}
- private void sendPack() throws IOException {
+ private void sendPack(PackStatistics.Accumulator accumulator)
+ throws IOException {
final boolean sideband = options.contains(OPTION_SIDE_BAND)
|| options.contains(OPTION_SIDE_BAND_64K);
if (sideband) {
try {
- sendPack(true);
+ sendPack(true, accumulator);
} catch (ServiceMayNotContinueException noPack) {
// This was already reported on (below).
throw noPack;
throw err;
}
} else {
- sendPack(false);
+ sendPack(false, accumulator);
}
}
}
@SuppressWarnings("deprecation")
- private void sendPack(final boolean sideband) throws IOException {
+ private void sendPack(final boolean sideband,
+ PackStatistics.Accumulator accumulator) throws IOException {
ProgressMonitor pm = NullProgressMonitor.INSTANCE;
OutputStream packOut = rawOut;
PackConfig cfg = packConfig;
if (cfg == null)
cfg = new PackConfig(db);
- final PackWriter pw = new PackWriter(cfg, walk.getObjectReader());
+ final PackWriter pw = new PackWriter(cfg, walk.getObjectReader(),
+ accumulator);
try {
pw.setIndexDisabled(true);
pw.setUseCachedPacks(true);