changeset 280:35125450c804

Erroneous and slow status for working copies based on non-tip revision
author Artem Tikhomirov <tikhomirov.artem@gmail.com>
date Fri, 02 Sep 2011 13:40:09 +0200
parents 23e3ea855097
children 81e9a3c9bafe
files src/org/tmatesoft/hg/internal/RevlogStream.java src/org/tmatesoft/hg/repo/HgDirstate.java src/org/tmatesoft/hg/repo/HgRepository.java src/org/tmatesoft/hg/repo/HgWorkingCopyStatusCollector.java
diffstat 4 files changed, 43 insertions(+), 25 deletions(-) [+]
line wrap: on
line diff
--- a/src/org/tmatesoft/hg/internal/RevlogStream.java	Wed Aug 31 23:22:18 2011 +0200
+++ b/src/org/tmatesoft/hg/internal/RevlogStream.java	Fri Sep 02 13:40:09 2011 +0200
@@ -63,6 +63,8 @@
 	}
 
 	/*package*/ DataAccess getIndexStream() {
+		// XXX may supply a hint that I'll need really few bytes of data (perhaps, at some offset) 
+		// to avoid mmap files when only few bytes are to be read (i.e. #dataLength())
 		return dataAccess.create(indexFile);
 	}
 
@@ -81,7 +83,7 @@
 		// XXX in fact, use of iterate() instead of this implementation may be quite reasonable.
 		//
 		final int indexSize = revisionCount();
-		DataAccess daIndex = getIndexStream(); // XXX may supply a hint that I'll need really few bytes of data (although at some offset)
+		DataAccess daIndex = getIndexStream();
 		if (revision == TIP) {
 			revision = indexSize - 1;
 		}
--- a/src/org/tmatesoft/hg/repo/HgDirstate.java	Wed Aug 31 23:22:18 2011 +0200
+++ b/src/org/tmatesoft/hg/repo/HgDirstate.java	Fri Sep 02 13:40:09 2011 +0200
@@ -228,7 +228,9 @@
 	
 	/*package-local*/ static class Record {
 		final int mode;
-		final int size;
+		// it seems Dirstate keeps local file size (i.e. that with any filters already applied). 
+		// Thus, can't compare directly to HgDataFile.length()
+		final int size; 
 		final int time;
 		final String name1;
 		final String name2;
--- a/src/org/tmatesoft/hg/repo/HgRepository.java	Wed Aug 31 23:22:18 2011 +0200
+++ b/src/org/tmatesoft/hg/repo/HgRepository.java	Fri Sep 02 13:40:09 2011 +0200
@@ -271,6 +271,7 @@
 	}
 
 	// XXX package-local, unless there are cases when required from outside (guess, working dir/revision walkers may hide dirstate access and no public visibility needed)
+	// XXX consider passing Path pool or factory to produce (shared) Path instead of Strings
 	/*package-local*/ final HgDirstate loadDirstate() {
 		return new HgDirstate(this, new File(repoDir, "dirstate"));
 	}
--- a/src/org/tmatesoft/hg/repo/HgWorkingCopyStatusCollector.java	Wed Aug 31 23:22:18 2011 +0200
+++ b/src/org/tmatesoft/hg/repo/HgWorkingCopyStatusCollector.java	Fri Sep 02 13:40:09 2011 +0200
@@ -59,7 +59,6 @@
 	private HgDirstate dirstate;
 	private HgStatusCollector baseRevisionCollector;
 	private PathPool pathPool;
-	private ManifestRevision dirstateParentManifest;
 
 	public HgWorkingCopyStatusCollector(HgRepository hgRepo) {
 		this(hgRepo, new HgInternals(hgRepo).createWorkingDirWalker(null));
@@ -145,7 +144,7 @@
 		final PathPool pp = getPathPool();
 		while (repoWalker.hasNext()) {
 			repoWalker.next();
-			Path fname = pp.path(repoWalker.name());
+			final Path fname = pp.path(repoWalker.name());
 			File f = repoWalker.file();
 			if (!f.exists()) {
 				// file coming from iterator doesn't exist.
@@ -237,9 +236,13 @@
 		HgDirstate.Record r;
 		if ((r = getDirstate().checkNormal(fname)) != null) {
 			// either clean or modified
-			if (f.lastModified() / 1000 == r.time && r.size == f.length()) {
-				inspector.clean(getPathPool().path(fname));
+			final boolean timestampEqual = getFileModificationTime(f) == r.time, sizeEqual = r.size == f.length();
+			if (timestampEqual && sizeEqual) {
+				inspector.clean(fname);
+			} else if (!sizeEqual && r.size >= 0) {
+				inspector.modified(fname);
 			} else {
+				// size is the same or unknown, and, perhaps, different timestamp
 				// check actual content to avoid false modified files
 				HgDataFile df = repo.getFileNode(fname);
 				if (!areTheSame(f, df, HgRepository.TIP)) {
@@ -250,17 +253,22 @@
 			}
 		} else if ((r = getDirstate().checkAdded(fname)) != null) {
 			if (r.name2 == null) {
-				inspector.added(getPathPool().path(fname));
+				inspector.added(fname);
 			} else {
-				inspector.copied(getPathPool().path(r.name2), getPathPool().path(fname));
+				inspector.copied(getPathPool().path(r.name2), fname);
 			}
 		} else if ((r = getDirstate().checkRemoved(fname)) != null) {
-			inspector.removed(getPathPool().path(fname));
+			inspector.removed(fname);
 		} else if ((r = getDirstate().checkMerged(fname)) != null) {
-			inspector.modified(getPathPool().path(fname));
+			inspector.modified(fname);
 		}
 	}
 	
+	// return mtime analog, directly comparable to dirstate's mtime.
+	private static int getFileModificationTime(File f) {
+		return (int) (f.lastModified() / 1000);
+	}
+	
 	// XXX refactor checkLocalStatus methods in more OO way
 	private void checkLocalStatusAgainstBaseRevision(Set<String> baseRevNames, ManifestRevision collect, int baseRevision, Path fname, File f, HgStatusInspector inspector) {
 		// fname is in the dirstate, either Normal, Added, Removed or Merged
@@ -296,23 +304,28 @@
 			inspector.added(fname);
 		} else {
 			// was known; check whether clean or modified
-			// when added - seems to be the case of a file added once again, hence need to check if content is different
-			if ((r = getDirstate().checkNormal(fname)) != null || (r = getDirstate().checkMerged(fname)) != null || (r = getDirstate().checkAdded(fname)) != null) {
+			if ((r = getDirstate().checkNormal(fname)) != null) {
+				final boolean timestampEqual = getFileModificationTime(f) == r.time, sizeEqual = r.size == f.length();
+				if (timestampEqual && sizeEqual) {
+					inspector.clean(fname);
+					baseRevNames.remove(fname.toString()); // consumed, processed, handled.
+					return;
+				} else if (!sizeEqual && r.size >= 0) {
+					inspector.modified(fname);
+					baseRevNames.remove(fname.toString()); // consumed, processed, handled.
+					return;
+				}
+				// otherwise, shall check actual content (size not the same, or unknown (-1 or -2), or timestamp is different) 
+				// FALL THROUGH
+			}
+			if (r != null /*Normal dirstate, but needs extra check*/ || (r = getDirstate().checkMerged(fname)) != null || (r = getDirstate().checkAdded(fname)) != null) {
+				// when added - seems to be the case of a file added once again, hence need to check if content is different
 				// either clean or modified
-				HgDataFile fileNode = repo.getFileNode(fname);
-				int lengthAtRevision;
-				try {
-					lengthAtRevision = fileNode.length(nid1);
-				} catch (HgDataStreamException ex) {
-					ex.printStackTrace(); // XXX log error
-					lengthAtRevision = -1; // compare file content then
-				}
-				// XXX is it safe with respect to filters (keyword, eol) to compare lengthAtRevision (unprocessed) with size 
-				// from dirstate, which I assume is size of processed data?
-				if (r.size != -1 && r.size /* XXX File.length() ?! */ != lengthAtRevision || flags != todoGenerateFlags(fname /*java.io.File*/)) {
+				if (r.size != -1 /*XXX what about ==-2?*/&& r.size != f.length() || !todoCheckFlagsEqual(f, flags)) {
 					inspector.modified(fname);
 				} else {
 					// check actual content to see actual changes
+					HgDataFile fileNode = repo.getFileNode(fname);
 					if (areTheSame(f, fileNode, fileNode.getLocalRevision(nid1))) {
 						inspector.clean(fname);
 					} else {
@@ -412,9 +425,9 @@
 		return false;
 	}
 
-	private static String todoGenerateFlags(Path fname) {
+	private static boolean todoCheckFlagsEqual(File f, String manifestFlags) {
 		// FIXME implement
-		return null;
+		return true;
 	}
 
 	/**