# HG changeset patch # User Pierre-Yves David # Date 2023-03-01 01:38:20 # Node ID 379a78001d8e665c509a27177fd5b72cd6d0f31c # Parent 342c3c4640b787794ae9e68a6323d42483a59a07 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. diff --git a/mercurial/dirstatemap.py b/mercurial/dirstatemap.py --- a/mercurial/dirstatemap.py +++ b/mercurial/dirstatemap.py @@ -127,6 +127,7 @@ class _dirstatemapcommon: 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 @@ class dirstatemap(_dirstatemapcommon): ### 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 @@ class dirstatemap(_dirstatemapcommon): 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 @@ if rustmod is not None: ) parents = self.docket.parents else: + self._set_identity() self._map, parents = rustmod.DirstateMap.new_v1( self._readdirstatefile() )