diff src/org/tmatesoft/hg/repo/HgDataFile.java @ 317:09628675bcee

Rework file history build approach to match rest of the API
author Artem Tikhomirov <tikhomirov.artem@gmail.com>
date Thu, 29 Sep 2011 03:20:28 +0200
parents 971baa95fb07
children d68dcb3b5f49
line wrap: on
line diff
--- a/src/org/tmatesoft/hg/repo/HgDataFile.java	Wed Sep 28 13:09:16 2011 +0200
+++ b/src/org/tmatesoft/hg/repo/HgDataFile.java	Thu Sep 29 03:20:28 2011 +0200
@@ -30,18 +30,15 @@
 import java.util.Collection;
 import java.util.Collections;
 import java.util.List;
-import java.util.NoSuchElementException;
 
 import org.tmatesoft.hg.core.HgDataStreamException;
 import org.tmatesoft.hg.core.HgException;
 import org.tmatesoft.hg.core.Nodeid;
 import org.tmatesoft.hg.internal.DataAccess;
-import org.tmatesoft.hg.internal.Experimental;
 import org.tmatesoft.hg.internal.FilterByteChannel;
 import org.tmatesoft.hg.internal.FilterDataAccess;
 import org.tmatesoft.hg.internal.IntMap;
 import org.tmatesoft.hg.internal.RevlogStream;
-import org.tmatesoft.hg.repo.HgChangelog.RawChangeset;
 import org.tmatesoft.hg.util.ByteChannel;
 import org.tmatesoft.hg.util.CancelSupport;
 import org.tmatesoft.hg.util.CancelledException;
@@ -231,135 +228,117 @@
 		}
 	}
 	
-	@Experimental(reason="Investigate approaches to build complete file history log")
-	public interface HistoryWalker {
-		void next();
-		boolean hasNext();
-		Nodeid changesetRevision();
-		RawChangeset changeset();
-		boolean isFork();
-		boolean isJoin();
-		Pair<Nodeid, Nodeid> parentChangesets();
-		Collection<Nodeid> childChangesets();
+	private static class HistoryNode {
+		int changeset;
+		Nodeid cset;
+		HistoryNode parent1, parent2;
+		List<HistoryNode> children;
+
+		HistoryNode(int cs, HistoryNode p1, HistoryNode p2) {
+			changeset = cs;
+			parent1 = p1;
+			parent2 = p2;
+			if (p1 != null) {
+				p1.addChild(this);
+			}
+			if (p2 != null) {
+				p2.addChild(this);
+			}
+		}
+		
+		Nodeid changesetRevision() {
+			assert cset != null : "we initialize all csets prior to use";
+			return cset;
+		}
+
+		void addChild(HistoryNode child) {
+			if (children == null) {
+				children = new ArrayList<HistoryNode>(2);
+			}
+			children.add(child);
+		}
 	}
 	
-	public HistoryWalker history() {
-		final boolean[] needsSorting = { false };
-		class HistoryNode {
-			int changeset;
-			Nodeid cset;
-			HistoryNode parent1, parent2;
-			List<HistoryNode> children;
-
-			public HistoryNode(int cs, HistoryNode p1, HistoryNode p2) {
-				changeset = cs;
-				parent1 = p1;
-				parent2 = p2;
-				if (p1 != null) {
-					p1.addChild(this);
+	public void history(HgChangelog.TreeInspector inspector) {
+		final CancelSupport cancelSupport = CancelSupport.Factory.get(inspector);
+		try {
+			final boolean[] needsSorting = { false };
+			final HistoryNode[] completeHistory = new HistoryNode[getRevisionCount()];
+			final int[] commitRevisions = new int[completeHistory.length];
+			RevlogStream.Inspector insp = new RevlogStream.Inspector() {
+				public void next(int revisionNumber, int actualLen, int baseRevision, int linkRevision, int parent1Revision, int parent2Revision, byte[] nodeid, DataAccess data) {
+					if (revisionNumber > 0) {
+						if (commitRevisions[revisionNumber-1] > linkRevision) {
+							needsSorting[0] = true;
+						}
+					}
+					commitRevisions[revisionNumber] = linkRevision;
+					HistoryNode p1 = null, p2 = null;
+					if (parent1Revision != -1) {
+						p1 = completeHistory[parent1Revision];
+					}
+					if (parent2Revision != -1) {
+						p2 = completeHistory[parent2Revision];
+					}
+					completeHistory[revisionNumber] = new HistoryNode(linkRevision, p1, p2);
 				}
-				if (p2 != null) {
-					p2.addChild(this);
+			};
+			content.iterate(0, getLastRevision(), false, insp);
+			cancelSupport.checkCancelled();
+			if (needsSorting[0]) {
+				Arrays.sort(commitRevisions);
+			}
+			// read changeset revisions at once (to avoid numerous changelog.getRevision reads)
+			// but just nodeids, not RawChangeset (changelog.iterate(data=false)
+			ArrayList<Nodeid> changesetRevisions = new ArrayList<Nodeid>(commitRevisions.length);
+			getRepo().getChangelog().getRevisionsInternal(changesetRevisions, commitRevisions);
+			cancelSupport.checkCancelled();
+			// assign them to corresponding HistoryNodes
+			for (int i = 0; i < completeHistory.length; i++ ) {
+				final HistoryNode n = completeHistory[i];
+				if (needsSorting[0]) {
+					int x = Arrays.binarySearch(commitRevisions, n.changeset);
+					assert x >= 0;
+					n.cset = changesetRevisions.get(x);
+				} else {
+					// commit revisions were not sorted, may use original index directly
+					n.cset = changesetRevisions.get(i);
 				}
 			}
-			
-			public Nodeid changesetRevision() {
-				if (cset == null) {
-					cset = getRepo().getChangelog().getRevision(changeset);
-				}
-				return cset;
-			}
-
-			public void addChild(HistoryNode child) {
-				if (children == null) {
-					children = new ArrayList<HistoryNode>(2);
-				}
-				children.add(child);
-			}
-		}
-		final HistoryNode[] completeHistory = new HistoryNode[getRevisionCount()];
-		final int[] commitRevisions = new int[completeHistory.length];
-		RevlogStream.Inspector insp = new RevlogStream.Inspector() {
-			public void next(int revisionNumber, int actualLen, int baseRevision, int linkRevision, int parent1Revision, int parent2Revision, byte[] nodeid, DataAccess data) {
-				if (revisionNumber > 0) {
-					if (commitRevisions[revisionNumber-1] > linkRevision) {
-						needsSorting[0] = true;
-					}
-				}
-				HistoryNode p1 = null, p2 = null;
-				if (parent1Revision != -1) {
-					p1 = completeHistory[parent1Revision];
-				}
-				if (parent2Revision != -1) {
-					p2 = completeHistory[parent2Revision];
-				}
-				completeHistory[revisionNumber] = new HistoryNode(linkRevision, p1, p2);
-			}
-		};
-		content.iterate(0, getLastRevision(), false, insp);
-		// XXX may read changeset revisions at once (to avoid numerous changelog.getRevision reads)
-		// but perhaps just nodeids, not RawChangeset (changelog.iterate(data=false)
-		// XXX sort completeHistory according to changeset numbers?
-		return new HistoryWalker() {
-			private int index = -1;
-			
-			public void next() {
-				if (!hasNext()) {
-					throw new NoSuchElementException();
-				}
-				index++;
-			}
-
-			public boolean hasNext() {
-				return index+1 < completeHistory.length;
-			}
-			
-			public Pair<Nodeid, Nodeid> parentChangesets() {
+			cancelSupport.checkCancelled();
+			// XXX shall sort completeHistory according to changeset numbers?
+			for (int i = 0; i < completeHistory.length; i++ ) {
+				final HistoryNode n = completeHistory[i];
 				HistoryNode p;
 				Nodeid p1, p2;
-				if ((p = completeHistory[index].parent1) != null) {
+				if ((p = n.parent1) != null) {
 					p1 = p.changesetRevision();
 				} else {
 					p1 = Nodeid.NULL;
 				}
-				if ((p = completeHistory[index].parent2) != null) {
+				if ((p= n.parent2) != null) {
 					p2 = p.changesetRevision();
 				} else {
 					p2 = Nodeid.NULL;
 				}
-				return new Pair<Nodeid, Nodeid>(p1, p2);
-			}
-
-			public boolean isJoin() {
-				return completeHistory[index].parent1 != null && completeHistory[index].parent2 != null;
-			}
-			
-			public boolean isFork() {
-				HistoryNode n = completeHistory[index];
-				return n.children != null && n.children.size() > 1;
-			}
-			
-			public Collection<Nodeid> childChangesets() {
-				HistoryNode n = completeHistory[index];
+				final Pair<Nodeid, Nodeid> parentChangesets = new Pair<Nodeid, Nodeid>(p1, p2);
+				final List<Nodeid> childChangesets;
 				if (n.children == null) {
-					return Collections.emptyList();
+					childChangesets = Collections.emptyList();
+				} else {
+					Nodeid[] revisions = new Nodeid[n.children.size()];
+					int j = 0;
+					for (HistoryNode hn : n.children) {
+						revisions[j++] = hn.changesetRevision();
+					}
+					childChangesets = Arrays.asList(revisions);
 				}
-				ArrayList<Nodeid> rv = new ArrayList<Nodeid>(n.children.size());
-				for (HistoryNode hn : n.children) {
-					rv.add(hn.changesetRevision());
-				}
-				return rv;
+				inspector.next(n.changesetRevision(), parentChangesets, childChangesets);
+				cancelSupport.checkCancelled();
 			}
-			
-			public Nodeid changesetRevision() {
-				return completeHistory[index].changesetRevision();
-			}
-			
-			public RawChangeset changeset() {
-				final int cs = completeHistory[index].changeset;
-				return getRepo().getChangelog().range(cs, cs).get(0);
-			}
-		};
+		} catch (CancelledException ex) {
+			return;
+		}
 	}
 	
 	public void history(HgChangelog.Inspector inspector) {