UploadPack: Use more relevant refs first in object reachability check

The bitmap-bassed object reachability checker, tries to find the objects
in the first starter, then adding the second starter... and so on. This
rewards passing the most popular refs first.

Order the refs with heads first, then tags, then others (e.g. changes)
for the object reachability checker. Using streams, delay also the
resolution of the ref to RevObject until necessary.

Change-Id: I9414b76754d7c0ffee1e2eeed6939895c8e92cbe
Signed-off-by: Ivan Frade <ifrade@google.com>
This commit is contained in:
Ivan Frade 2020-04-06 14:35:52 -07:00
parent a661e2e9eb
commit c9d7285e80
1 changed files with 29 additions and 4 deletions

View File

@ -1903,7 +1903,6 @@ private static void checkNotAdvertisedWants(UploadPack up,
try (RevWalk walk = new RevWalk(reader)) {
walk.setRetainBody(false);
Set<ObjectId> reachableFrom = refIdSet(visibleRefs);
// Missing "wants" throw exception here
List<RevObject> wantsAsObjs = objectIdsToRevObjects(walk,
notAdvertisedWants);
@ -1930,12 +1929,15 @@ private static void checkNotAdvertisedWants(UploadPack up,
}
try (ObjectWalk objWalk = walk.toObjectWalkWithSameObjects()) {
List<RevObject> havesAsObjs = objectIdsToRevObjects(objWalk,
reachableFrom);
Stream<RevObject> startersAsObjs = importantRefsFirst(visibleRefs)
.map(UploadPack::refToObjectId)
.map(objId -> objectIdToRevObject(objWalk, objId))
.filter(Objects::nonNull); // Ignore missing tips
ObjectReachabilityChecker reachabilityChecker = objWalk
.createObjectReachabilityChecker();
Optional<RevObject> unreachable = reachabilityChecker
.areAllReachable(wantsAsObjs, havesAsObjs.stream());
.areAllReachable(wantsAsObjs, startersAsObjs);
if (unreachable.isPresent()) {
throw new WantNotValidException(unreachable.get());
}
@ -2007,6 +2009,29 @@ private static RevCommit objectIdToRevCommit(RevWalk walk,
}
}
/**
* Translate an object id to a RevObject.
*
* @param walk
* walk on the relevant object storage
* @param objectId
* Object Id
* @return RevObject instance or null if the object is missing
*/
@Nullable
private static RevObject objectIdToRevObject(RevWalk walk,
ObjectId objectId) {
if (objectId == null) {
return null;
}
try {
return walk.parseAny(objectId);
} catch (IOException e) {
return null;
}
}
// Resolve the ObjectIds into RevObjects. Any missing object raises an
// exception
private static List<RevObject> objectIdsToRevObjects(RevWalk walk,