Avoid expensive getAllRefsByPeeledObjectId() in PlotWalk constructor

Instead, do it when we return the first PlotCommit from next().
On a repository with many refs, getAllRefsByPeeledObjectId() can
take a while. Doing a late initialization simplifies the handling
of a PlotWalk.

EGit, for instance, creates and configures an instance, and then
does the real walk in a background job. With late initialization,
the potentially expensive getAllRefsByPeeledObjectId() also occurs
in that background job.

Bug: 485743
Change-Id: I84c020cf8f7afda6f181778786612b8e6ddd7ed8
Signed-off-by: Thomas Wolf <thomas.wolf@paranor.ch>
This commit is contained in:
Thomas Wolf 2018-06-15 16:01:58 +02:00
parent b92136f023
commit 2e76daec14
1 changed files with 39 additions and 7 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2008-2009, Robin Rosenberg <robin.rosenberg@dewire.com>
* Copyright (C) 2008-2018, Robin Rosenberg <robin.rosenberg@dewire.com>
* Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org>
* and other copyright owners as documented in the project's IP log.
*
@ -53,6 +53,7 @@
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
@ -75,13 +76,25 @@
*/
public class PlotWalk extends RevWalk {
private Map<AnyObjectId, Set<Ref>> additionalRefMap;
private Map<AnyObjectId, Set<Ref>> reverseRefMap;
private Repository repository;
/** {@inheritDoc} */
@Override
public void dispose() {
super.dispose();
reverseRefMap.clear();
if (reverseRefMap != null) {
reverseRefMap.clear();
reverseRefMap = null;
}
if (additionalRefMap != null) {
additionalRefMap.clear();
additionalRefMap = null;
}
repository = null;
}
/**
@ -93,7 +106,8 @@ public void dispose() {
public PlotWalk(Repository repo) {
super(repo);
super.sort(RevSort.TOPO, true);
reverseRefMap = repo.getAllRefsByPeeledObjectId();
additionalRefMap = new HashMap<>();
repository = repo;
}
/**
@ -105,14 +119,14 @@ public PlotWalk(Repository repo) {
*/
public void addAdditionalRefs(Iterable<Ref> refs) throws IOException {
for (Ref ref : refs) {
Set<Ref> set = reverseRefMap.get(ref.getObjectId());
Set<Ref> set = additionalRefMap.get(ref.getObjectId());
if (set == null)
set = Collections.singleton(ref);
else {
set = new HashSet<>(set);
set.add(ref);
}
reverseRefMap.put(ref.getObjectId(), set);
additionalRefMap.put(ref.getObjectId(), set);
}
}
@ -141,10 +155,28 @@ public RevCommit next() throws MissingObjectException,
}
private Ref[] getRefs(AnyObjectId commitId) {
if (reverseRefMap == null) {
reverseRefMap = repository.getAllRefsByPeeledObjectId();
for (Map.Entry<AnyObjectId, Set<Ref>> entry : additionalRefMap
.entrySet()) {
Set<Ref> set = reverseRefMap.get(entry.getKey());
Set<Ref> additional = entry.getValue();
if (set != null) {
if (additional.size() == 1) {
// It's an unmodifiable singleton set...
additional = new HashSet<>(additional);
}
additional.addAll(set);
}
reverseRefMap.put(entry.getKey(), additional);
}
additionalRefMap.clear();
additionalRefMap = null;
}
Collection<Ref> list = reverseRefMap.get(commitId);
if (list == null)
if (list == null) {
return PlotCommit.NO_REFS;
else {
} else {
Ref[] tags = list.toArray(new Ref[list.size()]);
Arrays.sort(tags, new PlotRefComparator());
return tags;