# HG changeset patch # User Artem Tikhomirov # Date 1314963609 -7200 # Node ID 35125450c8045aa4f8158ca4bb11342ed750c8cc # Parent 23e3ea855097f68c9d84caee29d49f9f737123f2 Erroneous and slow status for working copies based on non-tip revision diff -r 23e3ea855097 -r 35125450c804 src/org/tmatesoft/hg/internal/RevlogStream.java --- 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; } diff -r 23e3ea855097 -r 35125450c804 src/org/tmatesoft/hg/repo/HgDirstate.java --- 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; diff -r 23e3ea855097 -r 35125450c804 src/org/tmatesoft/hg/repo/HgRepository.java --- 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")); } diff -r 23e3ea855097 -r 35125450c804 src/org/tmatesoft/hg/repo/HgWorkingCopyStatusCollector.java --- 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 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; } /**