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.
--- 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