dirstate: add begin/endparentchange to dirstate
authorDurham Goode <durham@fb.com>
Fri, 05 Sep 2014 11:34:29 -0700
changeset 22404 12bc7f06fc41
parent 22403 41e9d58ec56f
child 22405 6f63c47cbb86
dirstate: add begin/endparentchange to dirstate It's possible for the dirstate to become incoherent (issue4353) if there is an exception in the middle of the dirstate parent and entries being written (like if the user ctrl+c's). This change adds begin/endparentchange which a future patch will require to be set before changing the dirstate parent. This will allow us to prevent writing the dirstate in the event of an exception while changing the parent.
mercurial/dirstate.py
mercurial/localrepo.py
--- a/mercurial/dirstate.py	Mon Sep 08 20:57:44 2014 +0200
+++ b/mercurial/dirstate.py	Fri Sep 05 11:34:29 2014 -0700
@@ -44,6 +44,30 @@
         self._lastnormaltime = 0
         self._ui = ui
         self._filecache = {}
+        self._parentwriters = 0
+
+    def beginparentchange(self):
+        '''Marks the beginning of a set of changes that involve changing
+        the dirstate parents. If there is an exception during this time,
+        the dirstate will not be written when the wlock is released. This
+        prevents writing an incoherent dirstate where the parent doesn't
+        match the contents.
+        '''
+        self._parentwriters += 1
+
+    def endparentchange(self):
+        '''Marks the end of a set of changes that involve changing the
+        dirstate parents. Once all parent changes have been marked done,
+        the wlock will be free to write the dirstate on release.
+        '''
+        if self._parentwriters > 0:
+            self._parentwriters -= 1
+
+    def pendingparentchange(self):
+        '''Returns true if the dirstate is in the middle of a set of changes
+        that modify the dirstate parent.
+        '''
+        return self._parentwriters > 0
 
     @propertycache
     def _map(self):
@@ -300,6 +324,7 @@
                 delattr(self, a)
         self._lastnormaltime = 0
         self._dirty = False
+        self._parentwriters = 0
 
     def copy(self, source, dest):
         """Mark dest as a copy of source. Unmark dest if source is None."""
--- a/mercurial/localrepo.py	Mon Sep 08 20:57:44 2014 +0200
+++ b/mercurial/localrepo.py	Fri Sep 05 11:34:29 2014 -0700
@@ -1102,7 +1102,11 @@
             return l
 
         def unlock():
-            self.dirstate.write()
+            if self.dirstate.pendingparentchange():
+                self.dirstate.invalidate()
+            else:
+                self.dirstate.write()
+
             self._filecache['dirstate'].refresh()
 
         l = self._lock(self.vfs, "wlock", wait, unlock,