Mercurial > hg4j
diff src/org/tmatesoft/hg/internal/PhasesHelper.java @ 449:5787e912f60e smartgit3
Speed up changeset phase detection when no parent cache is avalable
author | Artem Tikhomirov <tikhomirov.artem@gmail.com> |
---|---|
date | Thu, 07 Jun 2012 16:01:09 +0200 |
parents | 2e402c12ebc6 |
children | 39fe00407937 |
line wrap: on
line diff
--- a/src/org/tmatesoft/hg/internal/PhasesHelper.java Wed Jun 06 21:23:57 2012 +0200 +++ b/src/org/tmatesoft/hg/internal/PhasesHelper.java Thu Jun 07 16:01:09 2012 +0200 @@ -18,16 +18,13 @@ import static org.tmatesoft.hg.repo.HgPhase.Draft; import static org.tmatesoft.hg.repo.HgPhase.Secret; -import static org.tmatesoft.hg.repo.HgRepository.BAD_REVISION; import java.io.BufferedReader; import java.io.File; import java.io.FileReader; import java.io.IOException; -import java.util.Arrays; import java.util.Collections; import java.util.HashMap; -import java.util.HashSet; import java.util.LinkedList; import java.util.List; @@ -47,21 +44,20 @@ */ public final class PhasesHelper { - private final HgRepository hgRepo; + private final HgRepository repo; private final HgChangelog.ParentWalker parentHelper; private Boolean repoSupporsPhases; private List<Nodeid> draftPhaseRoots; private List<Nodeid> secretPhaseRoots; - private int[] earliestRevIndex = new int[HgPhase.values().length]; + private RevisionDescendants[][] phaseDescendants = new RevisionDescendants[HgPhase.values().length][]; - public PhasesHelper(HgRepository repo) { - this(repo, null); + public PhasesHelper(HgRepository hgRepo) { + this(hgRepo, null); } - public PhasesHelper(HgRepository repo, HgChangelog.ParentWalker pw) { - hgRepo = repo; + public PhasesHelper(HgRepository hgRepo, HgChangelog.ParentWalker pw) { + repo = hgRepo; parentHelper = pw; - Arrays.fill(earliestRevIndex, BAD_REVISION); } public boolean isCapableOfPhases() throws HgInvalidControlFileException { @@ -82,8 +78,9 @@ if (!isCapableOfPhases()) { return HgPhase.Undefined; } - if (csetRev == null || csetRev.isNull()) { - csetRev = hgRepo.getChangelog().getRevision(csetRevIndex); + // csetRev is only used when parentHelper is available + if (parentHelper != null && (csetRev == null || csetRev.isNull())) { + csetRev = repo.getChangelog().getRevision(csetRevIndex); } for (HgPhase phase : new HgPhase[] {HgPhase.Secret, HgPhase.Draft }) { @@ -91,49 +88,21 @@ if (roots.isEmpty()) { continue; } - if (roots.contains(csetRev)) { - return phase; - } if (parentHelper != null) { + if (roots.contains(csetRev)) { + return phase; + } if (parentHelper.childrenOf(roots).contains(csetRev)) { return phase; } } else { // no parent helper - // search all descendants - int earliestRootRevIndex = getEarliestPhaseRevision(phase); - if (earliestRootRevIndex > csetRevIndex) { - // this phase started later than our changeset was added, try another phase - continue; - } - /* - * TODO descendants() method to build a BitSet with 1 at index of those that are descendants - * wrap it into a class with root nodeid to - * (a) collect only for a subset of repository, - * (b) be able to answer isDescendant(int csetRevIndex) using absolute indexing (i.e bitAt(csetRevIndex - rootRevIndex)) - */ - final HashSet<Nodeid> parents2consider = new HashSet<Nodeid>(roots); - final boolean[] result = new boolean[] { false }; - hgRepo.getChangelog().walk(earliestRootRevIndex, csetRevIndex, new HgChangelog.ParentInspector() { - - public void next(int revisionIndex, Nodeid revision, int parent1, int parent2, Nodeid nidParent1, Nodeid nidParent2) { - boolean descendant = false; - if (!nidParent1.isNull() && parents2consider.contains(nidParent1)) { - parents2consider.add(revision); - descendant = true; - } - if (!nidParent2.isNull() && parents2consider.contains(nidParent2)) { - parents2consider.add(revision); - descendant = true; - } - if (descendant && revisionIndex == csetRevIndex) { - // revision of interest descends from one of the roots - result[0] = true; - } + // search all descendants.RevisuionDescendats includes root as well. + for (RevisionDescendants rd : getPhaseDescendants(phase)) { + // isCandidate is to go straight to another root if changeset was added later that the current root + if (rd.isCandidate(csetRevIndex) && rd.isDescendant(csetRevIndex)) { + return phase; } - }); - if (result[0]) { - return phase; } } } @@ -141,18 +110,9 @@ } - - private int[] toIndexes(List<Nodeid> roots) throws HgInvalidControlFileException { - int[] rv = new int[roots.size()]; - for (int i = 0; i < rv.length; i++) { - rv[i] = hgRepo.getChangelog().getRevisionIndex(roots.get(i)); - } - return rv; - } - private Boolean readRoots() throws HgInvalidControlFileException { // FIXME shall access phaseroots through HgRepository#repoPathHelper - File phaseroots = new File(HgInternals.getRepositoryDir(hgRepo), "store/phaseroots"); + File phaseroots = new File(HgInternals.getRepositoryDir(repo), "store/phaseroots"); try { if (!phaseroots.exists()) { return Boolean.FALSE; @@ -166,7 +126,7 @@ continue; } if (lc.length != 2) { - HgInternals.getContext(hgRepo).getLog().warn(getClass(), "Bad line in phaseroots:%s", line); + HgInternals.getContext(repo).getLog().warn(getClass(), "Bad line in phaseroots:%s", line); continue; } int phaseIndex = Integer.parseInt(lc[0]); @@ -193,15 +153,31 @@ } return Collections.emptyList(); } - - private int getEarliestPhaseRevision(HgPhase phase) throws HgInvalidControlFileException { + + + private RevisionDescendants[] getPhaseDescendants(HgPhase phase) throws HgInvalidControlFileException { int ordinal = phase.ordinal(); - if (earliestRevIndex[ordinal] == BAD_REVISION) { - int[] rootIndexes = toIndexes(getPhaseRoots(phase)); - Arrays.sort(rootIndexes); - // instead of MAX_VALUE may use clog.getLastRevision() + 1 - earliestRevIndex[ordinal] = rootIndexes.length == 0 ? Integer.MAX_VALUE : rootIndexes[0]; + if (phaseDescendants[ordinal] == null) { + phaseDescendants[ordinal] = buildPhaseDescendants(phase); } - return earliestRevIndex[ordinal]; + return phaseDescendants[ordinal]; + } + + private RevisionDescendants[] buildPhaseDescendants(HgPhase phase) throws HgInvalidControlFileException { + int[] roots = toIndexes(getPhaseRoots(phase)); + RevisionDescendants[] rv = new RevisionDescendants[roots.length]; + for (int i = 0; i < roots.length; i++) { + rv[i] = new RevisionDescendants(repo, roots[i]); + rv[i].build(); + } + return rv; + } + + private int[] toIndexes(List<Nodeid> roots) throws HgInvalidControlFileException { + int[] rv = new int[roots.size()]; + for (int i = 0; i < rv.length; i++) { + rv[i] = repo.getChangelog().getRevisionIndex(roots.get(i)); + } + return rv; } }