changeset 47463:5fa083a5ff04

copies: Keep changelog sidedata file open during copy tracing Instead of having a callback that opens and closes that file many times, a add and use a context manager method on the `revlog` class that keeps files open for its duration. Differential Revision: https://phab.mercurial-scm.org/D10888
author Simon Sapin <simon.sapin@octobus.net>
date Thu, 17 Jun 2021 19:48:25 +0200
parents 75d4e60c7c81
children bc8536e09a20
files mercurial/copies.py mercurial/revlog.py mercurial/revlogutils/randomaccessfile.py
diffstat 3 files changed, 38 insertions(+), 9 deletions(-) [+]
line wrap: on
line diff
--- a/mercurial/copies.py	Tue Jun 22 13:18:29 2021 -0400
+++ b/mercurial/copies.py	Thu Jun 17 19:48:25 2021 +0200
@@ -318,15 +318,16 @@
                 if p in children_count:
                     children_count[p] += 1
         revinfo = _revinfo_getter(repo, match)
-        return _combine_changeset_copies(
-            revs,
-            children_count,
-            b.rev(),
-            revinfo,
-            match,
-            isancestor,
-            multi_thread,
-        )
+        with repo.changelog.reading():
+            return _combine_changeset_copies(
+                revs,
+                children_count,
+                b.rev(),
+                revinfo,
+                match,
+                isancestor,
+                multi_thread,
+            )
     else:
         # When not using side-data, we will process the edges "from" the parent.
         # so we need a full mapping of the parent -> children relation.
--- a/mercurial/revlog.py	Tue Jun 22 13:18:29 2021 -0400
+++ b/mercurial/revlog.py	Thu Jun 17 19:48:25 2021 +0200
@@ -2086,6 +2086,13 @@
         """called when trying to add a node already stored."""
 
     @contextlib.contextmanager
+    def reading(self):
+        """Context manager that keeps data and sidedata files open for reading"""
+        with self._segmentfile.reading():
+            with self._segmentfile_sidedata.reading():
+                yield
+
+    @contextlib.contextmanager
     def _writing(self, transaction):
         if self._trypending:
             msg = b'try to write in a `trypending` revlog: %s'
--- a/mercurial/revlogutils/randomaccessfile.py	Tue Jun 22 13:18:29 2021 -0400
+++ b/mercurial/revlogutils/randomaccessfile.py	Thu Jun 17 19:48:25 2021 +0200
@@ -40,6 +40,7 @@
         self.filename = filename
         self.default_cached_chunk_size = default_cached_chunk_size
         self.writing_handle = None  # This is set from revlog.py
+        self.reading_handle = None
         self._cached_chunk = b''
         self._cached_chunk_position = 0  # Offset from the start of the file
         if initial_cache:
@@ -67,11 +68,31 @@
         elif self.writing_handle:
             yield self.writing_handle
 
+        elif self.reading_handle:
+            yield self.reading_handle
+
         # Otherwise open a new file handle.
         else:
             with self._open() as fp:
                 yield fp
 
+    @contextlib.contextmanager
+    def reading(self):
+        """Context manager that keeps the file open for reading"""
+        if (
+            self.reading_handle is None
+            and self.writing_handle is None
+            and self.filename is not None
+        ):
+            with self._open() as fp:
+                self.reading_handle = fp
+                try:
+                    yield
+                finally:
+                    self.reading_handle = None
+        else:
+            yield
+
     def read_chunk(self, offset, length, existing_file_obj=None):
         """Read a chunk of bytes from the file.