BasePackFetchConnection: Skip object/ref lookups if local repo is empty
When cloning repository some of the operations in `BasePackFetchConnection` can be skipped. We don't need to advertise packs, compute "wanted time" or wanted refs to send. All of those operations will try to read objects from an empty repository which always results in a missing object. This saves 99.9% of `LooseObjects.open()` calls which dramatically speeds up object negotiation in V2 protocol. In testing on JGit (v6.8.0.202311291450-r) repository, which contains 564 refs, the number of calls to `LooseObjects.open()` was reduced from 1187 to 1. Skipping a call to `markRefsAdvertised()` initially reduced be above number to 623. Then assuming "0" "want time" an on empty repository pushed the calls down to 312. Finally, skipping objects reachability on empty repository set calls down to 1. The last call is performed from `FetchProcess.asForIsComplete()` which probably needs to stay in place. Bug: jgit-5 Change-Id: I2480690726ea54d3b1593380bc8f8d15b4d6afc6
This commit is contained in:
parent
faa50c683d
commit
7884873160
|
@ -402,11 +402,14 @@ private void clearState() {
|
||||||
protected void doFetch(final ProgressMonitor monitor,
|
protected void doFetch(final ProgressMonitor monitor,
|
||||||
final Collection<Ref> want, final Set<ObjectId> have,
|
final Collection<Ref> want, final Set<ObjectId> have,
|
||||||
OutputStream outputStream) throws TransportException {
|
OutputStream outputStream) throws TransportException {
|
||||||
|
boolean hasObjects = !have.isEmpty();
|
||||||
try {
|
try {
|
||||||
noProgress = monitor == NullProgressMonitor.INSTANCE;
|
noProgress = monitor == NullProgressMonitor.INSTANCE;
|
||||||
|
|
||||||
markRefsAdvertised();
|
if (hasObjects) {
|
||||||
markReachable(want, have, maxTimeWanted(want));
|
markRefsAdvertised();
|
||||||
|
}
|
||||||
|
markReachable(want, have, maxTimeWanted(want, hasObjects));
|
||||||
|
|
||||||
if (TransferConfig.ProtocolVersion.V2
|
if (TransferConfig.ProtocolVersion.V2
|
||||||
.equals(getProtocolVersion())) {
|
.equals(getProtocolVersion())) {
|
||||||
|
@ -418,7 +421,7 @@ protected void doFetch(final ProgressMonitor monitor,
|
||||||
state = new TemporaryBuffer.Heap(Integer.MAX_VALUE);
|
state = new TemporaryBuffer.Heap(Integer.MAX_VALUE);
|
||||||
pckState = new PacketLineOut(state);
|
pckState = new PacketLineOut(state);
|
||||||
try {
|
try {
|
||||||
doFetchV2(monitor, want, outputStream);
|
doFetchV2(monitor, want, outputStream, hasObjects);
|
||||||
} finally {
|
} finally {
|
||||||
clearState();
|
clearState();
|
||||||
}
|
}
|
||||||
|
@ -430,7 +433,7 @@ protected void doFetch(final ProgressMonitor monitor,
|
||||||
pckState = new PacketLineOut(state);
|
pckState = new PacketLineOut(state);
|
||||||
}
|
}
|
||||||
PacketLineOut output = statelessRPC ? pckState : pckOut;
|
PacketLineOut output = statelessRPC ? pckState : pckOut;
|
||||||
if (sendWants(want, output)) {
|
if (sendWants(want, output, hasObjects)) {
|
||||||
boolean mayHaveShallow = depth != null || deepenSince != null || !deepenNots.isEmpty();
|
boolean mayHaveShallow = depth != null || deepenSince != null || !deepenNots.isEmpty();
|
||||||
Set<ObjectId> shallowCommits = local.getObjectDatabase().getShallowCommits();
|
Set<ObjectId> shallowCommits = local.getObjectDatabase().getShallowCommits();
|
||||||
if (isCapableOf(GitProtocolConstants.CAPABILITY_SHALLOW)) {
|
if (isCapableOf(GitProtocolConstants.CAPABILITY_SHALLOW)) {
|
||||||
|
@ -457,7 +460,8 @@ protected void doFetch(final ProgressMonitor monitor,
|
||||||
}
|
}
|
||||||
|
|
||||||
private void doFetchV2(ProgressMonitor monitor, Collection<Ref> want,
|
private void doFetchV2(ProgressMonitor monitor, Collection<Ref> want,
|
||||||
OutputStream outputStream) throws IOException, CancelledException {
|
OutputStream outputStream, boolean hasObjects)
|
||||||
|
throws IOException, CancelledException {
|
||||||
sideband = true;
|
sideband = true;
|
||||||
negotiateBegin();
|
negotiateBegin();
|
||||||
|
|
||||||
|
@ -479,7 +483,7 @@ private void doFetchV2(ProgressMonitor monitor, Collection<Ref> want,
|
||||||
pckState.writeString(capability);
|
pckState.writeString(capability);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!sendWants(want, pckState)) {
|
if (!sendWants(want, pckState, hasObjects)) {
|
||||||
// We already have everything we wanted.
|
// We already have everything we wanted.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -666,8 +670,12 @@ FetchConfig getFetchConfig() {
|
||||||
return local.getConfig().get(FetchConfig::new);
|
return local.getConfig().get(FetchConfig::new);
|
||||||
}
|
}
|
||||||
|
|
||||||
private int maxTimeWanted(Collection<Ref> wants) {
|
private int maxTimeWanted(Collection<Ref> wants, boolean hasObjects) {
|
||||||
int maxTime = 0;
|
int maxTime = 0;
|
||||||
|
if (!hasObjects) {
|
||||||
|
// we don't have any objects locally, we can immediately bail out
|
||||||
|
return maxTime;
|
||||||
|
}
|
||||||
for (Ref r : wants) {
|
for (Ref r : wants) {
|
||||||
try {
|
try {
|
||||||
final RevObject obj = walk.parseAny(r.getObjectId());
|
final RevObject obj = walk.parseAny(r.getObjectId());
|
||||||
|
@ -769,7 +777,8 @@ private void markReachable(ObjectId id) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean sendWants(Collection<Ref> want, PacketLineOut p)
|
private boolean sendWants(Collection<Ref> want, PacketLineOut p,
|
||||||
|
boolean hasObjects)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
boolean first = true;
|
boolean first = true;
|
||||||
for (Ref r : want) {
|
for (Ref r : want) {
|
||||||
|
@ -778,7 +787,9 @@ private boolean sendWants(Collection<Ref> want, PacketLineOut p)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// if depth is set we need to fetch the objects even if they are already available
|
// if depth is set we need to fetch the objects even if they are already available
|
||||||
if (transport.getDepth() == null) {
|
if (transport.getDepth() == null
|
||||||
|
// only check reachable objects when we have objects
|
||||||
|
&& hasObjects) {
|
||||||
try {
|
try {
|
||||||
if (walk.parseAny(objectId).has(REACHABLE)) {
|
if (walk.parseAny(objectId).has(REACHABLE)) {
|
||||||
// We already have this object. Asking for it is
|
// We already have this object. Asking for it is
|
||||||
|
|
Loading…
Reference in New Issue