import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.revwalk.RevWalk;
import org.eclipse.jgit.storage.pack.PackConfig;
+import org.eclipse.jgit.storage.pack.PackStatistics;
import org.eclipse.jgit.util.io.CountingOutputStream;
/** Repack and garbage collect a repository. */
private final List<DfsPackDescription> newPackDesc;
- private final List<PackWriter.Statistics> newPackStats;
+ private final List<PackStatistics> newPackStats;
private final List<PackWriter.ObjectIdSet> newPackObj;
refdb = repo.getRefDatabase();
objdb = repo.getObjectDatabase();
newPackDesc = new ArrayList<DfsPackDescription>(4);
- newPackStats = new ArrayList<PackWriter.Statistics>(4);
+ newPackStats = new ArrayList<PackStatistics>(4);
newPackObj = new ArrayList<PackWriter.ObjectIdSet>(4);
packConfig = new PackConfig(repo);
}
/** @return statistics corresponding to the {@link #getNewPacks()}. */
- public List<PackWriter.Statistics> getNewPackStatistics() {
+ public List<PackStatistics> getNewPackStatistics() {
return newPackStats;
}
}
});
- PackWriter.Statistics stats = pw.getStatistics();
+ PackStatistics stats = pw.getStatistics();
pack.setPackStats(stats);
newPackStats.add(stats);
import org.eclipse.jgit.revwalk.RevObject;
import org.eclipse.jgit.revwalk.RevWalk;
import org.eclipse.jgit.storage.pack.PackConfig;
+import org.eclipse.jgit.storage.pack.PackStatistics;
import org.eclipse.jgit.util.BlockList;
import org.eclipse.jgit.util.io.CountingOutputStream;
private final List<DfsPackDescription> newPacks;
- private final List<PackWriter.Statistics> newStats;
+ private final List<PackStatistics> newStats;
private int autoAddSize;
srcPacks = new ArrayList<DfsPackFile>();
exclude = new ArrayList<PackWriter.ObjectIdSet>(4);
newPacks = new ArrayList<DfsPackDescription>(1);
- newStats = new ArrayList<PackWriter.Statistics>(1);
+ newStats = new ArrayList<PackStatistics>(1);
}
/**
writePack(objdb, pack, pw, pm);
writeIndex(objdb, pack, pw);
- PackWriter.Statistics stats = pw.getStatistics();
+ PackStatistics stats = pw.getStatistics();
pw.close();
pw = null;
}
/** @return statistics corresponding to the {@link #getNewPacks()}. */
- public List<PackWriter.Statistics> getNewPackStatistics() {
+ public List<PackStatistics> getNewPackStatistics() {
return newStats;
}
import org.eclipse.jgit.internal.storage.dfs.DfsObjDatabase.PackSource;
import org.eclipse.jgit.internal.storage.pack.PackExt;
-import org.eclipse.jgit.internal.storage.pack.PackWriter;
+import org.eclipse.jgit.storage.pack.PackStatistics;
/**
* Description of a DFS stored pack/index file.
private long deltaCount;
- private PackWriter.Statistics stats;
+ private PackStatistics stats;
private int extensions;
* DfsGarbageCollector or DfsPackCompactor, and only when the pack
* is being committed to the repository.
*/
- public PackWriter.Statistics getPackStats() {
+ public PackStatistics getPackStats() {
return stats;
}
- DfsPackDescription setPackStats(PackWriter.Statistics stats) {
+ DfsPackDescription setPackStats(PackStatistics stats) {
this.stats = stats;
setFileSize(PACK, stats.getTotalBytes());
setObjectCount(stats.getTotalObjects());
import org.eclipse.jgit.revwalk.RevTag;
import org.eclipse.jgit.revwalk.RevTree;
import org.eclipse.jgit.storage.pack.PackConfig;
+import org.eclipse.jgit.storage.pack.PackStatistics;
import org.eclipse.jgit.transport.ObjectCountCallback;
import org.eclipse.jgit.transport.WriteAbortedException;
import org.eclipse.jgit.util.BlockList;
private final PackConfig config;
- private final Statistics stats;
+ private final PackStatistics.Accumulator stats;
private final MutableState state;
private final WeakReference<PackWriter> selfRef;
- private Statistics.ObjectType typeStats;
+ private PackStatistics.ObjectType.Accumulator typeStats;
private List<ObjectToPack> sortedByName;
deltaBaseAsOffset = config.isDeltaBaseAsOffset();
reuseDeltas = config.isReuseDeltas();
reuseValidate = true; // be paranoid by default
- stats = new Statistics();
+ stats = new PackStatistics.Accumulator();
state = new MutableState();
selfRef = new WeakReference<PackWriter>(this);
instances.put(selfRef, Boolean.TRUE);
writeObjects(out);
if (!edgeObjects.isEmpty() || !cachedPacks.isEmpty()) {
- for (Statistics.ObjectType typeStat : stats.objectTypes) {
+ for (PackStatistics.ObjectType.Accumulator typeStat : stats.objectTypes) {
if (typeStat == null)
continue;
stats.thinPackBytes += typeStat.bytes;
stats.timeWriting = System.currentTimeMillis() - writeStart;
stats.depth = depth;
- for (Statistics.ObjectType typeStat : stats.objectTypes) {
+ for (PackStatistics.ObjectType.Accumulator typeStat : stats.objectTypes) {
if (typeStat == null)
continue;
typeStat.cntDeltas += typeStat.reusedDeltas;
* final pack stream. The object is only available to callers after
* {@link #writePack(ProgressMonitor, ProgressMonitor, OutputStream)}
*/
- public Statistics getStatistics() {
- return stats;
+ public PackStatistics getStatistics() {
+ return new PackStatistics(stats);
}
/** @return snapshot of the current state of this PackWriter. */
return true;
}
- /** Summary of how PackWriter created the pack. */
+ /**
+ * Summary of how PackWriter created the pack.
+ *
+ * @deprecated Use {@link PackStatistics} instead.
+ */
+ @Deprecated
public static class Statistics {
/** Statistics about a single class of object. */
public static class ObjectType {
- long cntObjects;
-
- long cntDeltas;
+ // All requests are forwarded to this object.
+ private PackStatistics.ObjectType objectType;
- long reusedObjects;
-
- long reusedDeltas;
-
- long bytes;
-
- long deltaBytes;
+ /**
+ * Wraps an
+ * {@link org.eclipse.jgit.storage.pack.PackStatistics.ObjectType}
+ * instance to maintain backwards compatibility with existing API.
+ *
+ * @param type
+ * the wrapped instance
+ */
+ public ObjectType(PackStatistics.ObjectType type) {
+ objectType = type;
+ }
/**
* @return total number of objects output. This total includes the
* value of {@link #getDeltas()}.
*/
public long getObjects() {
- return cntObjects;
+ return objectType.getObjects();
}
/**
* actual number of deltas if a cached pack was reused.
*/
public long getDeltas() {
- return cntDeltas;
+ return objectType.getDeltas();
}
/**
* {@link #getReusedDeltas()}.
*/
public long getReusedObjects() {
- return reusedObjects;
+ return objectType.getReusedObjects();
}
/**
* was reused.
*/
public long getReusedDeltas() {
- return reusedDeltas;
+ return objectType.getReusedDeltas();
}
/**
* also includes all of {@link #getDeltaBytes()}.
*/
public long getBytes() {
- return bytes;
+ return objectType.getBytes();
}
/**
* object headers for the delta objects.
*/
public long getDeltaBytes() {
- return deltaBytes;
+ return objectType.getDeltaBytes();
}
}
- Set<ObjectId> interestingObjects;
-
- Set<ObjectId> uninterestingObjects;
-
- Collection<CachedPack> reusedPacks;
-
- int depth;
-
- int deltaSearchNonEdgeObjects;
-
- int deltasFound;
-
- long totalObjects;
+ // All requests are forwarded to this object.
+ private PackStatistics statistics;
- long bitmapIndexMisses;
-
- long totalDeltas;
-
- long reusedObjects;
-
- long reusedDeltas;
-
- long totalBytes;
-
- long thinPackBytes;
-
- long timeCounting;
-
- long timeSearchingForReuse;
-
- long timeSearchingForSizes;
-
- long timeCompressing;
-
- long timeWriting;
-
- ObjectType[] objectTypes;
-
- {
- objectTypes = new ObjectType[5];
- objectTypes[OBJ_COMMIT] = new ObjectType();
- objectTypes[OBJ_TREE] = new ObjectType();
- objectTypes[OBJ_BLOB] = new ObjectType();
- objectTypes[OBJ_TAG] = new ObjectType();
+ /**
+ * Wraps a {@link PackStatistics} object to maintain backwards
+ * compatibility with existing API.
+ *
+ * @param stats
+ * the wrapped PackStatitics object
+ */
+ public Statistics(PackStatistics stats) {
+ statistics = stats;
}
/**
* test.
*/
public Set<ObjectId> getInterestingObjects() {
- return interestingObjects;
+ return statistics.getInterestingObjects();
}
/**
* has these objects.
*/
public Set<ObjectId> getUninterestingObjects() {
- return uninterestingObjects;
+ return statistics.getUninterestingObjects();
}
/**
* in the output, if any were selected for reuse.
*/
public Collection<CachedPack> getReusedPacks() {
- return reusedPacks;
+ return statistics.getReusedPacks();
}
/**
* delta search process in order to find a potential delta base.
*/
public int getDeltaSearchNonEdgeObjects() {
- return deltaSearchNonEdgeObjects;
+ return statistics.getDeltaSearchNonEdgeObjects();
}
/**
* {@link #getDeltaSearchNonEdgeObjects()}.
*/
public int getDeltasFound() {
- return deltasFound;
+ return statistics.getDeltasFound();
}
/**
* of {@link #getTotalDeltas()}.
*/
public long getTotalObjects() {
- return totalObjects;
+ return statistics.getTotalObjects();
}
/**
* @since 4.0
*/
public long getBitmapIndexMisses() {
- return bitmapIndexMisses;
+ return statistics.getBitmapIndexMisses();
}
/**
* actual number of deltas if a cached pack was reused.
*/
public long getTotalDeltas() {
- return totalDeltas;
+ return statistics.getTotalDeltas();
}
/**
* the output. This count includes {@link #getReusedDeltas()}.
*/
public long getReusedObjects() {
- return reusedObjects;
+ return statistics.getReusedObjects();
}
/**
* actual number of reused deltas if a cached pack was reused.
*/
public long getReusedDeltas() {
- return reusedDeltas;
+ return statistics.getReusedDeltas();
}
/**
* header, trailer, thin pack, and reused cached pack(s).
*/
public long getTotalBytes() {
- return totalBytes;
+ return statistics.getTotalBytes();
}
/**
* pack header or trailer.
*/
public long getThinPackBytes() {
- return thinPackBytes;
+ return statistics.getThinPackBytes();
}
/**
* @return information about this type of object in the pack.
*/
public ObjectType byObjectType(int typeCode) {
- return objectTypes[typeCode];
+ return new ObjectType(statistics.byObjectType(typeCode));
}
/** @return true if the resulting pack file was a shallow pack. */
public boolean isShallow() {
- return depth > 0;
+ return statistics.isShallow();
}
/** @return depth (in commits) the pack includes if shallow. */
public int getDepth() {
- return depth;
+ return statistics.getDepth();
}
/**
* that occur when a cached pack is selected for reuse.
*/
public long getTimeCounting() {
- return timeCounting;
+ return statistics.getTimeCounting();
}
/**
* can be assumed to already have.
*/
public long getTimeSearchingForReuse() {
- return timeSearchingForReuse;
+ return statistics.getTimeSearchingForReuse();
}
/**
* together and improve delta compression ratios.
*/
public long getTimeSearchingForSizes() {
- return timeSearchingForSizes;
+ return statistics.getTimeSearchingForSizes();
}
/**
* delta compression.
*/
public long getTimeCompressing() {
- return timeCompressing;
+ return statistics.getTimeCompressing();
}
/**
* value.
*/
public long getTimeWriting() {
- return timeWriting;
+ return statistics.getTimeWriting();
}
/** @return total time spent processing this pack. */
public long getTimeTotal() {
- return timeCounting
- + timeSearchingForReuse
- + timeSearchingForSizes
- + timeCompressing
- + timeWriting;
+ return statistics.getTimeTotal();
}
/**
* {@code getTotalBytes() / (getTimeWriting() / 1000.0)}.
*/
public double getTransferRate() {
- return getTotalBytes() / (getTimeWriting() / 1000.0);
+ return statistics.getTransferRate();
}
/** @return formatted message string for display to clients. */
public String getMessage() {
- return MessageFormat.format(JGitText.get().packWriterStatistics, //
- Long.valueOf(totalObjects), Long.valueOf(totalDeltas), //
- Long.valueOf(reusedObjects), Long.valueOf(reusedDeltas));
+ return statistics.getMessage();
}
}
--- /dev/null
+/*
+ * Copyright (C) 2015, Google Inc.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.storage.pack;
+
+import static org.eclipse.jgit.lib.Constants.OBJ_BLOB;
+import static org.eclipse.jgit.lib.Constants.OBJ_COMMIT;
+import static org.eclipse.jgit.lib.Constants.OBJ_TAG;
+import static org.eclipse.jgit.lib.Constants.OBJ_TREE;
+
+import java.text.MessageFormat;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.eclipse.jgit.internal.JGitText;
+import org.eclipse.jgit.internal.storage.pack.CachedPack;
+import org.eclipse.jgit.lib.ObjectId;
+
+/**
+ * Statistics about {@link org.eclipse.jgit.internal.storage.pack.PackWriter}
+ * pack creation.
+ *
+ * @since 4.1
+ */
+public class PackStatistics {
+ /**
+ * Statistics about a single type of object (commits, tags, trees and
+ * blobs).
+ */
+ public static class ObjectType {
+ /**
+ * POJO for accumulating the ObjectType statistics.
+ */
+ public static class Accumulator {
+ /** Count of objects of this type. */
+ public long cntObjects;
+
+ /** Count of deltas of this type. */
+ public long cntDeltas;
+
+ /** Count of reused objects of this type. */
+ public long reusedObjects;
+
+ /** Count of reused deltas of this type. */
+ public long reusedDeltas;
+
+ /** Count of bytes for all objects of this type. */
+ public long bytes;
+
+ /** Count of delta bytes for objects of this type. */
+ public long deltaBytes;
+ }
+
+ private ObjectType.Accumulator objectType;
+
+ /**
+ * Creates a new {@link ObjectType} object from the accumulator.
+ *
+ * @param accumulator
+ * the accumulator of the statistics
+ */
+ public ObjectType(ObjectType.Accumulator accumulator) {
+ objectType = accumulator;
+ }
+
+ /**
+ * @return total number of objects output. This total includes the value
+ * of {@link #getDeltas()}.
+ */
+ public long getObjects() {
+ return objectType.cntObjects;
+ }
+
+ /**
+ * @return total number of deltas output. This may be lower than the
+ * actual number of deltas if a cached pack was reused.
+ */
+ public long getDeltas() {
+ return objectType.cntDeltas;
+ }
+
+ /**
+ * @return number of objects whose existing representation was reused in
+ * the output. This count includes {@link #getReusedDeltas()}.
+ */
+ public long getReusedObjects() {
+ return objectType.reusedObjects;
+ }
+
+ /**
+ * @return number of deltas whose existing representation was reused in
+ * the output, as their base object was also output or was
+ * assumed present for a thin pack. This may be lower than the
+ * actual number of reused deltas if a cached pack was reused.
+ */
+ public long getReusedDeltas() {
+ return objectType.reusedDeltas;
+ }
+
+ /**
+ * @return total number of bytes written. This size includes the object
+ * headers as well as the compressed data. This size also
+ * includes all of {@link #getDeltaBytes()}.
+ */
+ public long getBytes() {
+ return objectType.bytes;
+ }
+
+ /**
+ * @return number of delta bytes written. This size includes the object
+ * headers for the delta objects.
+ */
+ public long getDeltaBytes() {
+ return objectType.deltaBytes;
+ }
+ }
+
+ /**
+ * POJO for accumulating the statistics.
+ */
+ public static class Accumulator {
+ /** The set of objects to be included in the pack. */
+ public Set<ObjectId> interestingObjects;
+
+ /** The set of objects to be excluded from the pack. */
+ public Set<ObjectId> uninterestingObjects;
+
+ /** The collection of reused packs in the upload. */
+ public List<CachedPack> reusedPacks;
+
+ /** If a shallow pack, the depth in commits. */
+ public int depth;
+
+ /**
+ * The count of objects in the pack that went through the delta search
+ * process in order to find a potential delta base.
+ */
+ public int deltaSearchNonEdgeObjects;
+
+ /**
+ * The count of objects in the pack that went through delta base search
+ * and found a suitable base. This is a subset of
+ * deltaSearchNonEdgeObjects.
+ */
+ public int deltasFound;
+
+ /** The total count of objects in the pack. */
+ public long totalObjects;
+
+ /**
+ * The count of objects that needed to be discovered through an object
+ * walk because they were not found in bitmap indices.
+ */
+ public long bitmapIndexMisses;
+
+ /** The total count of deltas output. */
+ public long totalDeltas;
+
+ /** The count of reused objects in the pack. */
+ public long reusedObjects;
+
+ /** The count of reused deltas in the pack. */
+ public long reusedDeltas;
+
+ /** The count of total bytes in the pack. */
+ public long totalBytes;
+
+ /** The size of the thin pack in bytes, if a thin pack was generated. */
+ public long thinPackBytes;
+
+ /** Time in ms spent counting the objects that will go into the pack. */
+ public long timeCounting;
+
+ /** Time in ms spent searching for objects to reuse. */
+ public long timeSearchingForReuse;
+
+ /** Time in ms spent searching for sizes of objects. */
+ public long timeSearchingForSizes;
+
+ /** Time in ms spent compressing the pack. */
+ public long timeCompressing;
+
+ /** Time in ms spent writing the pack. */
+ public long timeWriting;
+
+ /**
+ * Statistics about each object type in the pack (commits, tags, trees
+ * and blobs.)
+ */
+ public ObjectType.Accumulator[] objectTypes;
+
+ {
+ objectTypes = new ObjectType.Accumulator[5];
+ objectTypes[OBJ_COMMIT] = new ObjectType.Accumulator();
+ objectTypes[OBJ_TREE] = new ObjectType.Accumulator();
+ objectTypes[OBJ_BLOB] = new ObjectType.Accumulator();
+ objectTypes[OBJ_TAG] = new ObjectType.Accumulator();
+ }
+ }
+
+ private Accumulator statistics;
+
+ /**
+ * Creates a new {@link PackStatistics} object from the accumulator.
+ *
+ * @param accumulator
+ * the accumulator of the statistics
+ */
+ public PackStatistics(Accumulator accumulator) {
+ // Note: PackStatistics directly serves up the collections in the
+ // accumulator.
+ statistics = accumulator;
+ }
+
+ /**
+ * @return unmodifiable collection of objects to be included in the pack.
+ * May be {@code null} if the pack was hand-crafted in a unit test.
+ */
+ public Set<ObjectId> getInterestingObjects() {
+ return statistics.interestingObjects;
+ }
+
+ /**
+ * @return unmodifiable collection of objects that should be excluded from
+ * the pack, as the peer that will receive the pack already has
+ * these objects.
+ */
+ public Set<ObjectId> getUninterestingObjects() {
+ return statistics.uninterestingObjects;
+ }
+
+ /**
+ * @return unmodifiable list of the cached packs that were reused in the
+ * output, if any were selected for reuse.
+ */
+ public List<CachedPack> getReusedPacks() {
+ return statistics.reusedPacks;
+ }
+
+ /**
+ * @return number of objects in the output pack that went through the delta
+ * search process in order to find a potential delta base.
+ */
+ public int getDeltaSearchNonEdgeObjects() {
+ return statistics.deltaSearchNonEdgeObjects;
+ }
+
+ /**
+ * @return number of objects in the output pack that went through delta base
+ * search and found a suitable base. This is a subset of
+ * {@link #getDeltaSearchNonEdgeObjects()}.
+ */
+ public int getDeltasFound() {
+ return statistics.deltasFound;
+ }
+
+ /**
+ * @return total number of objects output. This total includes the value of
+ * {@link #getTotalDeltas()}.
+ */
+ public long getTotalObjects() {
+ return statistics.totalObjects;
+ }
+
+ /**
+ * @return the count of objects that needed to be discovered through an
+ * object walk because they were not found in bitmap indices.
+ * Returns -1 if no bitmap indices were found.
+ */
+ public long getBitmapIndexMisses() {
+ return statistics.bitmapIndexMisses;
+ }
+
+ /**
+ * @return total number of deltas output. This may be lower than the actual
+ * number of deltas if a cached pack was reused.
+ */
+ public long getTotalDeltas() {
+ return statistics.totalDeltas;
+ }
+
+ /**
+ * @return number of objects whose existing representation was reused in the
+ * output. This count includes {@link #getReusedDeltas()}.
+ */
+ public long getReusedObjects() {
+ return statistics.reusedObjects;
+ }
+
+ /**
+ * @return number of deltas whose existing representation was reused in the
+ * output, as their base object was also output or was assumed
+ * present for a thin pack. This may be lower than the actual number
+ * of reused deltas if a cached pack was reused.
+ */
+ public long getReusedDeltas() {
+ return statistics.reusedDeltas;
+ }
+
+ /**
+ * @return total number of bytes written. This size includes the pack
+ * header, trailer, thin pack, and reused cached pack(s).
+ */
+ public long getTotalBytes() {
+ return statistics.totalBytes;
+ }
+
+ /**
+ * @return size of the thin pack in bytes, if a thin pack was generated. A
+ * thin pack is created when the client already has objects and some
+ * deltas are created against those objects, or if a cached pack is
+ * being used and some deltas will reference objects in the cached
+ * pack. This size does not include the pack header or trailer.
+ */
+ public long getThinPackBytes() {
+ return statistics.thinPackBytes;
+ }
+
+ /**
+ * @param typeCode
+ * object type code, e.g. OBJ_COMMIT or OBJ_TREE.
+ * @return information about this type of object in the pack.
+ */
+ public ObjectType byObjectType(int typeCode) {
+ return new ObjectType(statistics.objectTypes[typeCode]);
+ }
+
+ /** @return true if the resulting pack file was a shallow pack. */
+ public boolean isShallow() {
+ return statistics.depth > 0;
+ }
+
+ /** @return depth (in commits) the pack includes if shallow. */
+ public int getDepth() {
+ return statistics.depth;
+ }
+
+ /**
+ * @return time in milliseconds spent enumerating the objects that need to
+ * be included in the output. This time includes any restarts that
+ * occur when a cached pack is selected for reuse.
+ */
+ public long getTimeCounting() {
+ return statistics.timeCounting;
+ }
+
+ /**
+ * @return time in milliseconds spent matching existing representations
+ * against objects that will be transmitted, or that the client can
+ * be assumed to already have.
+ */
+ public long getTimeSearchingForReuse() {
+ return statistics.timeSearchingForReuse;
+ }
+
+ /**
+ * @return time in milliseconds spent finding the sizes of all objects that
+ * will enter the delta compression search window. The sizes need to
+ * be known to better match similar objects together and improve
+ * delta compression ratios.
+ */
+ public long getTimeSearchingForSizes() {
+ return statistics.timeSearchingForSizes;
+ }
+
+ /**
+ * @return time in milliseconds spent on delta compression. This is observed
+ * wall-clock time and does not accurately track CPU time used when
+ * multiple threads were used to perform the delta compression.
+ */
+ public long getTimeCompressing() {
+ return statistics.timeCompressing;
+ }
+
+ /**
+ * @return time in milliseconds spent writing the pack output, from start of
+ * header until end of trailer. The transfer speed can be
+ * approximated by dividing {@link #getTotalBytes()} by this value.
+ */
+ public long getTimeWriting() {
+ return statistics.timeWriting;
+ }
+
+ /** @return total time spent processing this pack. */
+ public long getTimeTotal() {
+ return statistics.timeCounting + statistics.timeSearchingForReuse
+ + statistics.timeSearchingForSizes + statistics.timeCompressing
+ + statistics.timeWriting;
+ }
+
+ /**
+ * @return get the average output speed in terms of bytes-per-second.
+ * {@code getTotalBytes() / (getTimeWriting() / 1000.0)}.
+ */
+ public double getTransferRate() {
+ return getTotalBytes() / (getTimeWriting() / 1000.0);
+ }
+
+ /** @return formatted message string for display to clients. */
+ public String getMessage() {
+ return MessageFormat.format(JGitText.get().packWriterStatistics,
+ Long.valueOf(statistics.totalObjects),
+ Long.valueOf(statistics.totalDeltas),
+ Long.valueOf(statistics.reusedObjects),
+ Long.valueOf(statistics.reusedDeltas));
+ }
+
+ /** @return a map containing ObjectType statistics. */
+ public Map<Integer, ObjectType> getObjectTypes() {
+ HashMap<Integer, ObjectType> map = new HashMap<>();
+ map.put(Integer.valueOf(OBJ_BLOB), new ObjectType(
+ statistics.objectTypes[OBJ_BLOB]));
+ map.put(Integer.valueOf(OBJ_COMMIT), new ObjectType(
+ statistics.objectTypes[OBJ_COMMIT]));
+ map.put(Integer.valueOf(OBJ_TAG), new ObjectType(
+ statistics.objectTypes[OBJ_TAG]));
+ map.put(Integer.valueOf(OBJ_TREE), new ObjectType(
+ statistics.objectTypes[OBJ_TREE]));
+ return map;
+ }
+}
--- /dev/null
+/*
+ * Copyright (C) 2015, Google Inc.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.transport;
+
+import org.eclipse.jgit.internal.storage.pack.PackWriter;
+import org.eclipse.jgit.storage.pack.PackStatistics;
+
+/**
+ * Hook invoked by {@link UploadPack} after the pack has been uploaded.
+ * <p>
+ * Implementors of the interface are responsible for associating the current
+ * thread to a particular connection, if they need to also include connection
+ * information. One method is to use a {@link java.lang.ThreadLocal} to remember
+ * the connection information before invoking UploadPack.
+ *
+ * @since 4.1
+ */
+public interface PostUploadHook {
+ /** A simple no-op hook. */
+ public static final PostUploadHook NULL = new PostUploadHook() {
+ public void onPostUpload(PackStatistics stats) {
+ // Do nothing.
+ }
+ };
+
+ /**
+ * Notifies the hook that a pack has been sent.
+ *
+ * @param stats
+ * the statistics gathered by {@link PackWriter} for the uploaded
+ * pack
+ */
+ public void onPostUpload(PackStatistics stats);
+}
--- /dev/null
+/*
+ * Copyright (C) 2015, Google Inc.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.transport;
+
+import java.util.List;
+
+import org.eclipse.jgit.storage.pack.PackStatistics;
+
+/**
+ * {@link PostUploadHook} that delegates to a list of other hooks.
+ * <p>
+ * Hooks are run in the order passed to the constructor.
+ *
+ * @since 4.1
+ */
+public class PostUploadHookChain implements PostUploadHook {
+ private final PostUploadHook[] hooks;
+ private final int count;
+
+ /**
+ * Create a new hook chaining the given hooks together.
+ *
+ * @param hooks
+ * hooks to execute, in order.
+ * @return a new chain of the given hooks.
+ */
+ public static PostUploadHook newChain(List<? extends PostUploadHook> hooks) {
+ PostUploadHook[] newHooks = new PostUploadHook[hooks.size()];
+ int i = 0;
+ for (PostUploadHook hook : hooks)
+ if (hook != PostUploadHook.NULL)
+ newHooks[i++] = hook;
+ if (i == 0)
+ return PostUploadHook.NULL;
+ else if (i == 1)
+ return newHooks[0];
+ else
+ return new PostUploadHookChain(newHooks, i);
+ }
+
+ public void onPostUpload(PackStatistics stats) {
+ for (int i = 0; i < count; i++)
+ hooks[i].onPostUpload(stats);
+ }
+
+ private PostUploadHookChain(PostUploadHook[] hooks, int count) {
+ this.hooks = hooks;
+ this.count = count;
+ }
+}
import org.eclipse.jgit.revwalk.RevWalk;
import org.eclipse.jgit.revwalk.filter.CommitTimeRevFilter;
import org.eclipse.jgit.storage.pack.PackConfig;
+import org.eclipse.jgit.storage.pack.PackStatistics;
import org.eclipse.jgit.transport.GitProtocolConstants.MultiAck;
import org.eclipse.jgit.transport.RefAdvertiser.PacketLineOutRefAdvertiser;
import org.eclipse.jgit.util.io.InterruptTimer;
/** Hook handling the various upload phases. */
private PreUploadHook preUploadHook = PreUploadHook.NULL;
+ /** Hook for taking post upload actions. */
+ private PostUploadHook postUploadHook = PostUploadHook.NULL;
+
/** Capabilities requested by the client. */
private Set<String> options;
String userAgent;
private boolean noDone;
- private PackWriter.Statistics statistics;
+ private PackStatistics statistics;
private UploadPackLogger logger = UploadPackLogger.NULL;
this.refFilter = refFilter != null ? refFilter : RefFilter.DEFAULT;
}
- /** @return the configured upload hook. */
+ /** @return the configured pre upload hook. */
public PreUploadHook getPreUploadHook() {
return preUploadHook;
}
preUploadHook = hook != null ? hook : PreUploadHook.NULL;
}
+ /**
+ * @return the configured post upload hook.
+ * @since 4.1
+ */
+ public PostUploadHook getPostUploadHook() {
+ return postUploadHook;
+ }
+
+ /**
+ * Set the hook for post upload actions (logging, repacking).
+ *
+ * @param hook
+ * the hook; if null no special actions are taken.
+ * @since 4.1
+ */
+ public void setPostUploadHook(PostUploadHook hook) {
+ postUploadHook = hook != null ? hook : PostUploadHook.NULL;
+ }
+
/**
* Set the configuration used by the pack generator.
*
}
}
- /** @return the configured logger. */
+ /**
+ * @return the configured logger.
+ *
+ * @deprecated Use {@link #getPreUploadHook()}.
+ */
+ @Deprecated
public UploadPackLogger getLogger() {
return logger;
}
*
* @param logger
* the logger instance. If null, no logging occurs.
+ * @deprecated Use {@link #setPreUploadHook(PreUploadHook)}.
*/
+ @Deprecated
public void setLogger(UploadPackLogger logger) {
this.logger = logger;
}
* was sent, such as during the negotation phase of a smart HTTP
* connection, or if the client was already up-to-date.
* @since 3.0
+ * @deprecated Use {@link #getStatistics()}.
*/
+ @Deprecated
public PackWriter.Statistics getPackStatistics() {
+ return statistics == null ? null
+ : new PackWriter.Statistics(statistics);
+ }
+
+ /**
+ * Get the PackWriter's statistics if a pack was sent to the client.
+ *
+ * @return statistics about pack output, if a pack was sent. Null if no pack
+ * was sent, such as during the negotation phase of a smart HTTP
+ * connection, or if the client was already up-to-date.
+ * @since 4.1
+ */
+ public PackStatistics getStatistics() {
return statistics;
}
} finally {
statistics = pw.getStatistics();
- if (statistics != null)
- logger.onPackStatistics(statistics);
+ if (statistics != null) {
+ postUploadHook.onPostUpload(statistics);
+ logger.onPackStatistics(new PackWriter.Statistics(statistics));
+ }
pw.close();
}
* thread to a particular connection, if they need to also include connection
* information. One method is to use a {@link java.lang.ThreadLocal} to remember
* the connection information before invoking UploadPack.
+ *
+ * @deprecated use {@link PostUploadHook} instead
*/
+@Deprecated
public interface UploadPackLogger {
/** A simple no-op logger. */
public static final UploadPackLogger NULL = new UploadPackLogger() {
import org.eclipse.jgit.internal.storage.pack.PackWriter;
/**
- * {@link UploadPackLogger} that delegates to a list of other loggers.
+ * UploadPackLogger that delegates to a list of other loggers.
* <p>
* loggers are run in the order passed to the constructor.
+ *
+ * @deprecated Use {@link PostUploadHookChain} instead.
*/
+@Deprecated
public class UploadPackLoggerChain implements UploadPackLogger {
private final UploadPackLogger[] loggers;
private final int count;