assertTrue(client.getObjectDatabase().has(tag.toObjectId()));
}
+ @Test
+ public void testUploadNewBytes() throws Exception {
+ String commonInBlob = "abcdefghijklmnopqrstuvwx";
+
+ RevBlob parentBlob = remote.blob(commonInBlob + "a");
+ RevCommit parent = remote.commit(remote.tree(remote.file("foo", parentBlob)));
+ RevBlob childBlob = remote.blob(commonInBlob + "b");
+ RevCommit child = remote.commit(remote.tree(remote.file("foo", childBlob)), parent);
+ remote.update("branch1", child);
+
+ ByteArrayInputStream recvStream = uploadPackV2(
+ "command=fetch\n",
+ PacketLineIn.delimiter(),
+ "want " + child.toObjectId().getName() + "\n",
+ "ofs-delta\n",
+ "done\n",
+ PacketLineIn.end());
+ PacketLineIn pckIn = new PacketLineIn(recvStream);
+ assertThat(pckIn.readString(), is("packfile"));
+ ReceivedPackStatistics receivedStats = parsePack(recvStream);
+ assertTrue(receivedStats.getNumBytesDuplicated() == 0);
+ assertTrue(receivedStats.getNumObjectsDuplicated() == 0);
+ }
+
+ @Test
+ public void testUploadRedundantBytes() throws Exception {
+ String commonInBlob = "abcdefghijklmnopqrstuvwxyz";
+
+ RevBlob parentBlob = remote.blob(commonInBlob + "a");
+ RevCommit parent = remote.commit(remote.tree(remote.file("foo", parentBlob)));
+ RevBlob childBlob = remote.blob(commonInBlob + "b");
+ RevCommit child = remote.commit(remote.tree(remote.file("foo", childBlob)), parent);
+ remote.update("branch1", child);
+
+ TestRepository<InMemoryRepository> local = new TestRepository<>(client);
+ RevBlob localParentBlob = local.blob(commonInBlob + "a");
+ RevCommit localParent = local.commit(local.tree(local.file("foo", localParentBlob)));
+ RevBlob localChildBlob = local.blob(commonInBlob + "b");
+ RevCommit localChild = local.commit(
+ local.tree(local.file("foo", localChildBlob)), localParent);
+ local.update("branch1", localChild);
+
+ ByteArrayInputStream recvStream = uploadPackV2(
+ "command=fetch\n",
+ PacketLineIn.delimiter(),
+ "want " + child.toObjectId().getName() + "\n",
+ "ofs-delta\n",
+ "done\n",
+ PacketLineIn.end());
+ PacketLineIn pckIn = new PacketLineIn(recvStream);
+ assertThat(pckIn.readString(), is("packfile"));
+ ReceivedPackStatistics receivedStats = parsePack(recvStream);
+
+ long sizeOfHeader = 12;
+ long sizeOfTrailer = 20;
+ long expectedSize = receivedStats.getNumBytesRead() - sizeOfHeader
+ - sizeOfTrailer;
+ assertTrue(receivedStats.getNumBytesDuplicated() == expectedSize);
+ assertTrue(receivedStats.getNumObjectsDuplicated() == 6);
+ }
+
@Test
public void testV2FetchOfsDelta() throws Exception {
String commonInBlob = "abcdefghijklmnopqrstuvwxyz";
verifySafeObject(tempObjectId, type, visit.data);
if (isCheckObjectCollisions() && readCurs.has(tempObjectId)) {
- checkObjectCollision(tempObjectId, type, visit.data);
+ checkObjectCollision(tempObjectId, type, visit.data,
+ visit.delta.sizeBeforeInflating);
}
PackedObjectInfo oe;
UnresolvedDelta n = onEndDelta();
n.position = streamPosition;
n.next = baseByPos.put(base, n);
+ n.sizeBeforeInflating = streamPosition() - streamPosition;
deltaCount++;
break;
}
inflateAndSkip(Source.INPUT, sz);
UnresolvedDelta n = onEndDelta();
n.position = streamPosition;
+ n.sizeBeforeInflating = streamPosition() - streamPosition;
r.add(n);
deltaCount++;
break;
verifySafeObject(tempObjectId, type, data);
}
+ long sizeBeforeInflating = streamPosition() - pos;
PackedObjectInfo obj = newInfo(tempObjectId, null, null);
obj.setOffset(pos);
obj.setType(type);
+ obj.setSize(sizeBeforeInflating);
onEndWholeObject(obj);
if (data != null)
onInflatedObjectData(obj, type, data);
sz -= n;
}
}
+ stats.incrementObjectsDuplicated();
+ stats.incrementNumBytesDuplicated(obj.getSize());
} catch (MissingObjectException notLocal) {
// This is OK, we don't have a copy of the object locally
// but the API throws when we try to read it as usually it's
}
}
- private void checkObjectCollision(AnyObjectId obj, int type, byte[] data)
- throws IOException {
+ private void checkObjectCollision(AnyObjectId obj, int type, byte[] data,
+ long sizeBeforeInflating) throws IOException {
try {
final ObjectLoader ldr = readCurs.open(obj, type);
final byte[] existingData = ldr.getCachedBytes(data.length);
if (!Arrays.equals(data, existingData)) {
- throw new IOException(MessageFormat.format(
- JGitText.get().collisionOn, obj.name()));
+ throw new IOException(MessageFormat
+ .format(JGitText.get().collisionOn, obj.name()));
}
+ stats.incrementObjectsDuplicated();
+ stats.incrementNumBytesDuplicated(sizeBeforeInflating);
} catch (MissingObjectException notLocal) {
// This is OK, we don't have a copy of the object locally
// but the API throws when we try to read it as usually its
UnresolvedDelta next;
+ long sizeBeforeInflating;
+
/** @return offset within the input stream. */
public long getOffset() {
return position;
private int type = Constants.OBJ_BAD;
+ private long sizeBeforeInflating;
+
PackedObjectInfo(final long headerOffset, final int packedCRC,
final AnyObjectId id) {
super(id);
public void setType(int type) {
this.type = type;
}
+
+ void setSize(long sizeBeforeInflating) {
+ this.sizeBeforeInflating = sizeBeforeInflating;
+ }
+
+ long getSize() {
+ return sizeBeforeInflating;
+ }
}
*/
public class ReceivedPackStatistics {
private long numBytesRead;
+ private long numBytesDuplicated;
private long numWholeCommit;
private long numWholeTree;
private long numWholeTag;
private long numOfsDelta;
private long numRefDelta;
+ private long numObjectsDuplicated;
private long numDeltaCommit;
private long numDeltaTree;
return numBytesRead;
}
+ /**
+ * Get number of bytes of objects already in the local database
+ *
+ * @return number of bytes of objects appeared in both the pack sent by the
+ * client and the local database
+ * @since 5.10
+ */
+ public long getNumBytesDuplicated() {
+ return numBytesDuplicated;
+ }
+
/**
* Get number of whole commit objects in the pack
*
return numRefDelta;
}
+ /**
+ * Get number of objects already in the local database
+ *
+ * @return number of objects appeared in both the pack sent by the client
+ * and the local database
+ * @since 5.10
+ */
+ public long getNumObjectsDuplicated() {
+ return numObjectsDuplicated;
+ }
+
/**
* Get number of delta commit objects in the pack
*
/** A builder for {@link ReceivedPackStatistics}. */
public static class Builder {
private long numBytesRead;
+ private long numBytesDuplicated;
private long numWholeCommit;
private long numWholeTree;
private long numWholeTag;
private long numOfsDelta;
private long numRefDelta;
+ private long numObjectsDuplicated;
private long numDeltaCommit;
private long numDeltaTree;
return this;
}
+ /**
+ * @param size
+ * additional bytes already in the local database
+ * @return this
+ * @since 5.10
+ */
+ Builder incrementNumBytesDuplicated(long size) {
+ numBytesDuplicated += size;
+ return this;
+ }
+
/**
* Increment a whole object count.
*
return this;
}
+ /**
+ * Increment the duplicated object count.
+ *
+ * @return this
+ * @since 5.10
+ */
+ Builder incrementObjectsDuplicated() {
+ numObjectsDuplicated++;
+ return this;
+ }
+
/**
* Increment a delta object count.
*
ReceivedPackStatistics build() {
ReceivedPackStatistics s = new ReceivedPackStatistics();
s.numBytesRead = numBytesRead;
+ s.numBytesDuplicated = numBytesDuplicated;
s.numWholeCommit = numWholeCommit;
s.numWholeTree = numWholeTree;
s.numWholeBlob = numWholeBlob;
s.numDeltaTree = numDeltaTree;
s.numDeltaBlob = numDeltaBlob;
s.numDeltaTag = numDeltaTag;
+ s.numObjectsDuplicated = numObjectsDuplicated;
return s;
}
}