Patchwork [4,of,5] fsmonitor: write state with wlock held and dirstate unchanged (issue5581)

login
register
mail settings
Submitter Siddharth Agarwal
Date June 12, 2017, 10:36 p.m.
Message ID <1b02cda9518bbda5ad4a.1497306998@devvm31800.prn1.facebook.com>
Download mbox | patch
Permalink /patch/21353/
State Accepted
Headers show

Comments

Siddharth Agarwal - June 12, 2017, 10:36 p.m.
# HG changeset patch
# User Siddharth Agarwal <sid0@fb.com>
# Date 1497306871 25200
#      Mon Jun 12 15:34:31 2017 -0700
# Node ID 1b02cda9518bbda5ad4a08bbad5b3c3666646dbe
# Parent  f4563ba01434aec8b238693721c246fc86a40732
fsmonitor: write state with wlock held and dirstate unchanged (issue5581)

This means that the state will not be written if:

(1) either the wlock can't be obtained
(2) something else came along and changed the dirstate while we were in the
middle of a status run.

Patch

diff --git a/hgext/fsmonitor/__init__.py b/hgext/fsmonitor/__init__.py
--- a/hgext/fsmonitor/__init__.py
+++ b/hgext/fsmonitor/__init__.py
@@ -485,17 +485,14 @@  def overridestatus(
     else:
         stateunknown = listunknown
 
+    if updatestate:
+        ps = poststatus(startclock)
+        self.addpostdsstatus(ps)
+
     r = orig(node1, node2, match, listignored, listclean, stateunknown,
              listsubrepos)
     modified, added, removed, deleted, unknown, ignored, clean = r
 
-    if updatestate:
-        notefiles = modified + added + removed + deleted + unknown
-        self._fsmonitorstate.set(
-            self._fsmonitorstate.getlastclock() or startclock,
-            _hashignore(self.dirstate._ignore),
-            notefiles)
-
     if not listunknown:
         unknown = []
 
@@ -528,6 +525,17 @@  def overridestatus(
     return scmutil.status(
         modified, added, removed, deleted, unknown, ignored, clean)
 
+class poststatus(object):
+    def __init__(self, startclock):
+        self._startclock = startclock
+
+    def __call__(self, wctx, status):
+        clock = wctx.repo()._fsmonitorstate.getlastclock() or self._startclock
+        hashignore = _hashignore(wctx.repo().dirstate._ignore)
+        notefiles = (status.modified + status.added + status.removed +
+                     status.deleted + status.unknown)
+        wctx.repo()._fsmonitorstate.set(clock, hashignore, notefiles)
+
 def makedirstate(cls):
     class fsmonitordirstate(cls):
         def _fsmonitorinit(self, fsmonitorstate, watchmanclient):
diff --git a/tests/test-dirstate-race.t b/tests/test-dirstate-race.t
--- a/tests/test-dirstate-race.t
+++ b/tests/test-dirstate-race.t
@@ -157,3 +157,50 @@  treated differently in _checklookup() ac
   a
   $ hg debugdirstate
   n * * * a (glob)
+
+  $ rm b
+
+Set up a rebase situation for issue5581.
+
+  $ echo c2 > a
+  $ echo c2 > b
+  $ hg add b
+  $ hg commit -m c2
+  created new head
+  $ echo c3 >> a
+  $ hg commit -m c3
+  $ hg update 2
+  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  $ echo c4 >> a
+  $ echo c4 >> b
+  $ hg commit -m c4
+  created new head
+
+Configure a merge tool that runs status in the middle of the rebase.
+
+  $ cat >> $TESTTMP/mergetool-race.sh << EOF
+  > echo "custom merge tool"
+  > printf "c2\nc3\nc4\n" > \$1
+  > hg --cwd $TESTTMP/repo status
+  > echo "custom merge tool end"
+  > EOF
+  $ cat >> $HGRCPATH << EOF
+  > [extensions]
+  > rebase =
+  > [merge-tools]
+  > test.executable=sh
+  > test.args=$TESTTMP/mergetool-race.sh \$output
+  > EOF
+
+  $ hg rebase -s . -d 3 --tool test
+  rebasing 4:b08445fd6b2a "c4" (tip)
+  merging a
+  custom merge tool
+  M a
+  ? a.orig
+  custom merge tool end
+  saved backup bundle to $TESTTMP/repo/.hg/strip-backup/* (glob)
+
+This hg status should be empty, whether or not fsmonitor is enabled (issue5581).
+
+  $ hg status