mercurial/revlog.py
changeset 46646 e9901d01d135
parent 46561 7a93b7b3dc2d
child 46717 913485776542
--- a/mercurial/revlog.py	Tue Feb 23 22:58:30 2021 -0800
+++ b/mercurial/revlog.py	Wed Feb 03 16:33:10 2021 -0800
@@ -421,6 +421,11 @@
 
     If `upperboundcomp` is not None, this is the expected maximal gain from
     compression for the data content.
+
+    `concurrencychecker` is an optional function that receives 3 arguments: a
+    file handle, a filename, and an expected position. It should check whether
+    the current position in the file handle is valid, and log/warn/fail (by
+    raising).
     """
 
     _flagserrorclass = error.RevlogError
@@ -435,6 +440,7 @@
         censorable=False,
         upperboundcomp=None,
         persistentnodemap=False,
+        concurrencychecker=None,
     ):
         """
         create a revlog object
@@ -490,6 +496,8 @@
 
         self._loadindex()
 
+        self._concurrencychecker = concurrencychecker
+
     def _loadindex(self):
         mmapindexthreshold = None
         opts = self.opener.options
@@ -2284,6 +2292,21 @@
         curr = len(self)
         prev = curr - 1
         offset = self.end(prev)
+
+        if self._concurrencychecker:
+            if self._inline:
+                # offset is "as if" it were in the .d file, so we need to add on
+                # the size of the entry metadata.
+                self._concurrencychecker(
+                    ifh, self.indexfile, offset + curr * self._io.size
+                )
+            else:
+                # Entries in the .i are a consistent size.
+                self._concurrencychecker(
+                    ifh, self.indexfile, curr * self._io.size
+                )
+                self._concurrencychecker(dfh, self.datafile, offset)
+
         p1r, p2r = self.rev(p1), self.rev(p2)
 
         # full versions are inserted when the needed deltas