Shawn Pearce
10 years ago
committed by
Gerrit Code Review @ Eclipse.org
10 changed files with 766 additions and 114 deletions
@ -0,0 +1,462 @@ |
|||||||
|
/* |
||||||
|
* 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; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,74 @@ |
|||||||
|
/* |
||||||
|
* 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); |
||||||
|
} |
@ -0,0 +1,90 @@ |
|||||||
|
/* |
||||||
|
* 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; |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue