changeset 49695:a3b1ab5f5dee stable

dirstate: deal with read-race for pure python code If we cannot read the dirstate data, this is probably because a writing process wrote it under our feet. So refresh the docket and try again a handful of time.
author Pierre-Yves David <pierre-yves.david@octobus.net>
date Tue, 28 Feb 2023 19:01:20 +0100
parents 53f196622699
children c9066fc609ef
files mercurial/dirstatemap.py tests/test-dirstate-read-race.t
diffstat 2 files changed, 37 insertions(+), 4 deletions(-) [+]
line wrap: on
line diff
--- a/mercurial/dirstatemap.py	Wed Mar 01 16:05:28 2023 +0100
+++ b/mercurial/dirstatemap.py	Tue Feb 28 19:01:20 2023 +0100
@@ -37,6 +37,9 @@
 WRITE_MODE_FORCE_APPEND = 2
 
 
+V2_MAX_READ_ATTEMPTS = 5
+
+
 class _dirstatemapcommon:
     """
     Methods that are identical for both implementations of the dirstatemap
@@ -125,6 +128,21 @@
         return self._docket
 
     def _read_v2_data(self):
+        data = None
+        attempts = 0
+        while attempts < V2_MAX_READ_ATTEMPTS:
+            attempts += 1
+            try:
+                data = self._opener.read(self.docket.data_filename())
+            except FileNotFoundError:
+                # read race detected between docket and data file
+                # reload the docket and retry
+                self._docket = None
+        if data is None:
+            assert attempts >= V2_MAX_READ_ATTEMPTS
+            msg = b"dirstate read race happened %d times in a row"
+            msg %= attempts
+            raise error.Abort(msg)
         return self._opener.read(self.docket.data_filename())
 
     def write_v2_no_append(self, tr, st, meta, packed):
--- a/tests/test-dirstate-read-race.t	Wed Mar 01 16:05:28 2023 +0100
+++ b/tests/test-dirstate-read-race.t	Tue Feb 28 19:01:20 2023 +0100
@@ -217,8 +217,12 @@
 #endif
 #else
   $ cat $TESTTMP/status-race-lock.out
+  A dir/n
+  A dir/o
+  R dir/nested/m
+  ? p
+  ? q
   $ cat $TESTTMP/status-race-lock.log
-  abort: $ENOENT$: '$TESTTMP/race-with-add/.hg/dirstate.* (glob)
 #endif
 #endif
 #endif
@@ -318,8 +322,12 @@
 #endif
 #else
   $ cat $TESTTMP/status-race-lock.out
+  M dir/o
+  ? dir/n
+  ? p
+  ? q
   $ cat $TESTTMP/status-race-lock.log
-  abort: $ENOENT$: '$TESTTMP/race-with-commit/.hg/dirstate.* (glob)
+  warning: ignoring unknown working parent 02a67a77ee9b!
 #endif
 #endif
 #endif
@@ -452,8 +460,11 @@
 #endif
 #else
   $ cat $TESTTMP/status-race-lock.out
+  A dir/o
+  ? dir/n
+  ? p
+  ? q
   $ cat $TESTTMP/status-race-lock.log
-  abort: $ENOENT$: '$TESTTMP/race-with-update/.hg/dirstate.* (glob)
 #endif
 #endif
 #endif
@@ -542,8 +553,12 @@
 #endif
 #else
   $ cat $TESTTMP/status-race-lock.out
+  A dir/o
+  R dir/nested/m
+  ? dir/n
+  ? p
+  ? q
   $ cat $TESTTMP/status-race-lock.log
-  abort: $ENOENT$: '$TESTTMP/race-with-status/.hg/dirstate.* (glob)
 #endif
 #endif
 #endif