changeset 89:42bcb4bffd17

Refactored to simplify manifest collector
author Artem Tikhomirov <tikhomirov.artem@gmail.com>
date Wed, 26 Jan 2011 06:18:31 +0100
parents 61eedab3eb3e
children a95c700408a9
files src/org/tmatesoft/hg/repo/StatusCollector.java src/org/tmatesoft/hg/repo/WorkingCopyStatusCollector.java
diffstat 2 files changed, 63 insertions(+), 68 deletions(-) [+]
line wrap: on
line diff
--- 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<Integer, ManifestRevisionInspector>();
-		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<String> r1Files = new TreeSet<String>(r1.files(rev1));
-		for (String fname : r2.files(rev2)) {
+		TreeSet<String> r1Files = new TreeSet<String>(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<String> 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<String, Nodeid>[] idsMap;
-		private final HashMap<String, String>[] flagsMap;
-		private final int baseRevision;
-		private int r = -1; // cursor
+	/*package-local*/ static final class ManifestRevisionInspector implements HgManifest.Inspector {
+		private final TreeMap<String, Nodeid> idsMap;
+		private final TreeMap<String, String> 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<String, Nodeid>();
+			flagsMap = new TreeMap<String, String>();
 		}
 		
-		public Collection<String> files(int rev) {
-			if (rev < baseRevision || rev >= baseRevision + idsMap.length) {
-				throw new IllegalArgumentException();
-			}
-			return idsMap[rev - baseRevision].keySet();
+		public Collection<String> 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<String, Nodeid>();
-			flagsMap[r] = new HashMap<String, String>();
 			return true;
 		}
 	}
--- 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<String>(collect.files(baseRevision));
+			baseRevFiles = new TreeSet<String>(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<String> baseRevNames, Nodeid nid1, String flags, String fname, File f, StatusCollector.Inspector inspector) {
+	private void checkLocalStatusAgainstBaseRevision(Set<String> 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?