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> * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org>
* and other copyright owners as documented in the project's IP log. * and other copyright owners as documented in the project's IP log.
* *
@ -53,6 +53,7 @@
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.Comparator; import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
@ -75,13 +76,25 @@
*/ */
public class PlotWalk extends RevWalk { public class PlotWalk extends RevWalk {
private Map<AnyObjectId, Set<Ref>> additionalRefMap;
private Map<AnyObjectId, Set<Ref>> reverseRefMap; private Map<AnyObjectId, Set<Ref>> reverseRefMap;
private Repository repository;
/** {@inheritDoc} */ /** {@inheritDoc} */
@Override @Override
public void dispose() { public void dispose() {
super.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) { public PlotWalk(Repository repo) {
super(repo); super(repo);
super.sort(RevSort.TOPO, true); 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 { public void addAdditionalRefs(Iterable<Ref> refs) throws IOException {
for (Ref ref : refs) { for (Ref ref : refs) {
Set<Ref> set = reverseRefMap.get(ref.getObjectId()); Set<Ref> set = additionalRefMap.get(ref.getObjectId());
if (set == null) if (set == null)
set = Collections.singleton(ref); set = Collections.singleton(ref);
else { else {
set = new HashSet<>(set); set = new HashSet<>(set);
set.add(ref); 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) { 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); Collection<Ref> list = reverseRefMap.get(commitId);
if (list == null) if (list == null) {
return PlotCommit.NO_REFS; return PlotCommit.NO_REFS;
else { } else {
Ref[] tags = list.toArray(new Ref[list.size()]); Ref[] tags = list.toArray(new Ref[list.size()]);
Arrays.sort(tags, new PlotRefComparator()); Arrays.sort(tags, new PlotRefComparator());
return tags; return tags;