# HG changeset patch # User Artem Tikhomirov # Date 1296019111 -3600 # Node ID 42bcb4bffd17be14a054e12522730d56a2301d1c # Parent 61eedab3eb3e5bbc5e8f3a5ceb526bd33798adb1 Refactored to simplify manifest collector diff -r 61eedab3eb3e -r 42bcb4bffd17 src/org/tmatesoft/hg/repo/StatusCollector.java --- a/src/org/tmatesoft/hg/repo/StatusCollector.java Wed Jan 26 05:46:47 2011 +0100 +++ b/src/org/tmatesoft/hg/repo/StatusCollector.java Wed Jan 26 06:18:31 2011 +0100 @@ -26,6 +26,7 @@ import java.util.LinkedList; import java.util.List; import java.util.Map; +import java.util.TreeMap; import java.util.TreeSet; import org.tmatesoft.hg.core.Nodeid; @@ -46,7 +47,7 @@ public StatusCollector(HgRepository hgRepo) { this.repo = hgRepo; cache = new HashMap(); - ManifestRevisionInspector emptyFakeState = new ManifestRevisionInspector(-1, -1); + ManifestRevisionInspector emptyFakeState = new ManifestRevisionInspector(); emptyFakeState.begin(-1, null); emptyFakeState.end(-1); // FIXME HgRepo.TIP == -1 as well, need to distinguish fake "prior to first" revision from "the very last" cache.put(-1, emptyFakeState); @@ -59,7 +60,7 @@ private ManifestRevisionInspector get(int rev) { ManifestRevisionInspector i = cache.get(rev); if (i == null) { - i = new ManifestRevisionInspector(rev, rev); + i = new ManifestRevisionInspector(); cache.put(rev, i); repo.getManifest().walk(rev, rev, i); } @@ -98,27 +99,48 @@ } // in fact, rev1 and rev2 are often next (or close) to each other, // thus, we can optimize Manifest reads here (manifest.walk(rev1, rev2)) - ManifestRevisionInspector r1, r2; + ManifestRevisionInspector r1, r2 ; if (!cache.containsKey(rev1) && !cache.containsKey(rev2) && Math.abs(rev1 - rev2) < 5 /*subjective equivalent of 'close enough'*/) { int minRev = rev1 < rev2 ? rev1 : rev2; int maxRev = minRev == rev1 ? rev2 : rev1; - r1 = r2 = new ManifestRevisionInspector(minRev, maxRev); - for (int i = minRev; i <= maxRev; i++) { - cache.put(i, r1); + if (minRev > 0) { + minRev--; // expand range a bit + // XXX perhaps, if revlog.baseRevision is cheap, shall expand minRev up to baseRevision + // which gonna be read anyway } - repo.getManifest().walk(minRev, maxRev, r1); - } else { - r1 = get(rev1); - r2 = get(rev2); + + repo.getManifest().walk(minRev, maxRev, new HgManifest.Inspector() { + private ManifestRevisionInspector delegate; + + public boolean begin(int revision, Nodeid nid) { + cache.put(revision, delegate = new ManifestRevisionInspector()); + delegate.begin(revision, nid); + return true; + } + + public boolean next(Nodeid nid, String fname, String flags) { + delegate.next(nid, fname, flags); + return true; + } + + public boolean end(int revision) { + delegate.end(revision); + delegate = null; + return true; + } + }); } + r1 = get(rev1); + r2 = get(rev2); + - TreeSet r1Files = new TreeSet(r1.files(rev1)); - for (String fname : r2.files(rev2)) { + TreeSet r1Files = new TreeSet(r1.files()); + for (String fname : r2.files()) { if (r1Files.remove(fname)) { - Nodeid nidR1 = r1.nodeid(rev1, fname); - Nodeid nidR2 = r2.nodeid(rev2, fname); - String flagsR1 = r1.flags(rev1, fname); - String flagsR2 = r2.flags(rev2, fname); + Nodeid nidR1 = r1.nodeid(fname); + Nodeid nidR2 = r2.nodeid(fname); + String flagsR1 = r1.flags(fname); + String flagsR2 = r2.flags(fname); if (nidR1.equals(nidR2) && ((flagsR2 == null && flagsR1 == null) || flagsR2.equals(flagsR1))) { inspector.clean(fname); } else { @@ -202,7 +224,7 @@ if ((modified == null || !modified.contains(fname)) && (removed == null || !removed.contains(fname))) { return null; } - return statusHelper.raw(startRev).nodeid(startRev, fname); + return statusHelper.raw(startRev).nodeid(fname); } public Nodeid nodeidAfterChange(String fname) { if (statusHelper == null || endRev == BAD_REVISION) { @@ -211,7 +233,7 @@ if ((modified == null || !modified.contains(fname)) && (added == null || !added.contains(fname))) { return null; } - return statusHelper.raw(endRev).nodeid(endRev, fname); + return statusHelper.raw(endRev).nodeid(fname); } public List getModified() { @@ -304,69 +326,41 @@ } } - // XXX in fact, indexed access brings more trouble than benefits, get rid of it? Distinct instance per revision is good enough - public /*XXX private, actually. Made public unless repo.statusLocal finds better place*/ static final class ManifestRevisionInspector implements HgManifest.Inspector { - private final HashMap[] idsMap; - private final HashMap[] flagsMap; - private final int baseRevision; - private int r = -1; // cursor + /*package-local*/ static final class ManifestRevisionInspector implements HgManifest.Inspector { + private final TreeMap idsMap; + private final TreeMap flagsMap; - /** - * [minRev, maxRev] - * [-1,-1] also accepted (for fake empty instance) - * @param minRev - inclusive - * @param maxRev - inclusive - */ - @SuppressWarnings("unchecked") - public ManifestRevisionInspector(int minRev, int maxRev) { - baseRevision = minRev; - int range = maxRev - minRev + 1; - idsMap = new HashMap[range]; - flagsMap = new HashMap[range]; + public ManifestRevisionInspector() { + idsMap = new TreeMap(); + flagsMap = new TreeMap(); } - public Collection files(int rev) { - if (rev < baseRevision || rev >= baseRevision + idsMap.length) { - throw new IllegalArgumentException(); - } - return idsMap[rev - baseRevision].keySet(); + public Collection files() { + return idsMap.keySet(); } - public Nodeid nodeid(int rev, String fname) { - if (rev < baseRevision || rev >= baseRevision + idsMap.length) { - throw new IllegalArgumentException(); - } - return idsMap[rev - baseRevision].get(fname); + public Nodeid nodeid(String fname) { + return idsMap.get(fname); } - public String flags(int rev, String fname) { - if (rev < baseRevision || rev >= baseRevision + idsMap.length) { - throw new IllegalArgumentException(); - } - return flagsMap[rev - baseRevision].get(fname); + public String flags(String fname) { + return flagsMap.get(fname); } // public boolean next(Nodeid nid, String fname, String flags) { - idsMap[r].put(fname, nid); - flagsMap[r].put(fname, flags); + idsMap.put(fname, nid); + flagsMap.put(fname, flags); return true; } public boolean end(int revision) { - assert revision == r + baseRevision; - r = -1; - return revision+1 < baseRevision + idsMap.length; + // in fact, this class cares about single revision + return false; } public boolean begin(int revision, Nodeid nid) { - if (revision < baseRevision || revision >= baseRevision + idsMap.length) { - throw new IllegalArgumentException(); - } - r = revision - baseRevision; - idsMap[r] = new HashMap(); - flagsMap[r] = new HashMap(); return true; } } diff -r 61eedab3eb3e -r 42bcb4bffd17 src/org/tmatesoft/hg/repo/WorkingCopyStatusCollector.java --- a/src/org/tmatesoft/hg/repo/WorkingCopyStatusCollector.java Wed Jan 26 05:46:47 2011 +0100 +++ b/src/org/tmatesoft/hg/repo/WorkingCopyStatusCollector.java Wed Jan 26 06:18:31 2011 +0100 @@ -28,6 +28,7 @@ import java.util.TreeSet; import org.tmatesoft.hg.core.Nodeid; +import org.tmatesoft.hg.repo.StatusCollector.ManifestRevisionInspector; import org.tmatesoft.hg.util.FileWalker; /** @@ -83,10 +84,10 @@ if (baseRevisionCollector != null) { collect = baseRevisionCollector.raw(baseRevision); } else { - collect = new StatusCollector.ManifestRevisionInspector(baseRevision, baseRevision); + collect = new StatusCollector.ManifestRevisionInspector(); repo.getManifest().walk(baseRevision, baseRevision, collect); } - baseRevFiles = new TreeSet(collect.files(baseRevision)); + baseRevFiles = new TreeSet(collect.files()); } if (inspector instanceof StatusCollector.Record) { StatusCollector sc = baseRevisionCollector == null ? new StatusCollector(repo) : baseRevisionCollector; @@ -102,9 +103,7 @@ } else if (knownEntries.remove(fname)) { // modified, added, removed, clean if (collect != null) { // need to check against base revision, not FS file - Nodeid nid1 = collect.nodeid(baseRevision, fname); - String flags = collect.flags(baseRevision, fname); - checkLocalStatusAgainstBaseRevision(baseRevFiles, nid1, flags, fname, f, inspector); + checkLocalStatusAgainstBaseRevision(baseRevFiles, collect, fname, f, inspector); baseRevFiles.remove(fname); } else { checkLocalStatusAgainstFile(fname, f, inspector); @@ -166,8 +165,10 @@ } // XXX refactor checkLocalStatus methods in more OO way - private void checkLocalStatusAgainstBaseRevision(Set baseRevNames, Nodeid nid1, String flags, String fname, File f, StatusCollector.Inspector inspector) { + private void checkLocalStatusAgainstBaseRevision(Set baseRevNames, ManifestRevisionInspector collect, String fname, File f, StatusCollector.Inspector inspector) { // fname is in the dirstate, either Normal, Added, Removed or Merged + Nodeid nid1 = collect.nodeid(fname); + String flags = collect.flags(fname); HgDirstate.Record r; if (nid1 == null) { // normal: added?