dirstate: set identity whenever we read the dirstate's v2 docket stable
authorPierre-Yves David <pierre-yves.david@octobus.net>
Wed, 01 Mar 2023 02:38:20 +0100
branchstable
changeset 50242 379a78001d8e
parent 50241 342c3c4640b7
child 50243 6cce0afc1454
dirstate: set identity whenever we read the dirstate's v2 docket The docket can be loaded outside of a full read (for exemple when pre-fetching parents), so the current code would read/set the identity after loading the data, opening a race condition: A0: first process docket is read B0: other process appends new data to the dirstate (and changes the docket) A1: first process sets the identity (based on pre-B content, but with post-B identity) A1: first process loads the dirstatemap from the data file A1: first process does not detect the race and overwrites the update from B.
mercurial/dirstatemap.py
--- a/mercurial/dirstatemap.py	Tue Feb 21 15:10:12 2023 +0100
+++ b/mercurial/dirstatemap.py	Wed Mar 01 02:38:20 2023 +0100
@@ -127,6 +127,7 @@
                 raise error.ProgrammingError(
                     b'dirstate only has a docket in v2 format'
                 )
+            self._set_identity()
             self._docket = docketmod.DirstateDocket.parse(
                 self._readdirstatefile(), self._nodeconstants
             )
@@ -299,9 +300,6 @@
     ### disk interaction
 
     def read(self):
-        # ignore HG_PENDING because identity is used only for writing
-        self._set_identity()
-
         testing.wait_on_cfg(self._ui, b'dirstate.pre-read-file')
         if self._use_dirstate_v2:
 
@@ -310,6 +308,7 @@
             testing.wait_on_cfg(self._ui, b'dirstate.post-docket-read-file')
             st = self._read_v2_data()
         else:
+            self._set_identity()
             st = self._readdirstatefile()
 
         if not st:
@@ -581,6 +580,7 @@
                 )
                 parents = self.docket.parents
             else:
+                self._set_identity()
                 self._map, parents = rustmod.DirstateMap.new_v1(
                     self._readdirstatefile()
                 )