mercurial/revlog.py
changeset 40627 e9293c5f8bb9
parent 40626 87a872555e90
child 40738 8947f49daaa8
--- a/mercurial/revlog.py	Tue Nov 13 12:30:59 2018 -0800
+++ b/mercurial/revlog.py	Tue Nov 13 12:32:05 2018 -0800
@@ -375,6 +375,9 @@
         # custom flags.
         self._flagprocessors = dict(_flagprocessors)
 
+        # 2-tuple of file handles being used for active writing.
+        self._writinghandles = None
+
         mmapindexthreshold = None
         v = REVLOG_DEFAULT_VERSION
         opts = getattr(opener, 'options', None)
@@ -505,8 +508,21 @@
     @contextlib.contextmanager
     def _datareadfp(self, existingfp=None):
         """file object suitable to read data"""
+        # Use explicit file handle, if given.
         if existingfp is not None:
             yield existingfp
+
+        # Use a file handle being actively used for writes, if available.
+        # There is some danger to doing this because reads will seek the
+        # file. However, _writeentry() performs a SEEK_END before all writes,
+        # so we should be safe.
+        elif self._writinghandles:
+            if self._inline:
+                yield self._writinghandles[0]
+            else:
+                yield self._writinghandles[1]
+
+        # Otherwise open a new file handle.
         else:
             if self._inline:
                 func = self._indexfp
@@ -1750,6 +1766,9 @@
         if fp:
             fp.flush()
             fp.close()
+            # We can't use the cached file handle after close(). So prevent
+            # its usage.
+            self._writinghandles = None
 
         with self._indexfp('r') as ifh, self._datafp('w') as dfh:
             for r in self:
@@ -1996,7 +2015,9 @@
         # if the file was seeked to before the end. See issue4943 for more.
         #
         # We work around this issue by inserting a seek() before writing.
-        # Note: This is likely not necessary on Python 3.
+        # Note: This is likely not necessary on Python 3. However, because
+        # the file handle is reused for reads and may be seeked there, we need
+        # to be careful before changing this.
         ifh.seek(0, os.SEEK_END)
         if dfh:
             dfh.seek(0, os.SEEK_END)
@@ -2029,6 +2050,9 @@
         this revlog and the node that was added.
         """
 
+        if self._writinghandles:
+            raise error.ProgrammingError('cannot nest addgroup() calls')
+
         nodes = []
 
         r = len(self)
@@ -2048,6 +2072,9 @@
             if dfh:
                 dfh.flush()
             ifh.flush()
+
+        self._writinghandles = (ifh, dfh)
+
         try:
             deltacomputer = deltautil.deltacomputer(self)
             # loop through our set of deltas
@@ -2109,7 +2136,10 @@
                     ifh.close()
                     dfh = self._datafp("a+")
                     ifh = self._indexfp("a+")
+                    self._writinghandles = (ifh, dfh)
         finally:
+            self._writinghandles = None
+
             if dfh:
                 dfh.close()
             ifh.close()