Patchwork D10888: copies: Keep changelog sidedata file open during copy tracing

login
register
mail settings
Submitter phabricator
Date June 21, 2021, 7:47 a.m.
Message ID <differential-rev-PHID-DREV-bdvvt3m6psgnmoe73oqv-req@mercurial-scm.org>
Download mbox | patch
Permalink /patch/49202/
State Superseded
Headers show

Comments

phabricator - June 21, 2021, 7:47 a.m.
SimonSapin created this revision.
Herald added a reviewer: indygreg.
Herald added a reviewer: hg-reviewers.
Herald added a subscriber: mercurial-patches.

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

REPOSITORY
  rHG Mercurial

BRANCH
  default

REVISION DETAIL
  https://phab.mercurial-scm.org/D10888

AFFECTED FILES
  mercurial/copies.py
  mercurial/revlog.py
  mercurial/revlogutils/randomaccessfile.py

CHANGE DETAILS




To: SimonSapin, indygreg, #hg-reviewers
Cc: mercurial-patches, mercurial-devel

Patch

diff --git a/mercurial/revlogutils/randomaccessfile.py b/mercurial/revlogutils/randomaccessfile.py
--- a/mercurial/revlogutils/randomaccessfile.py
+++ b/mercurial/revlogutils/randomaccessfile.py
@@ -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,27 @@ 
         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:
+            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.
 
diff --git a/mercurial/revlog.py b/mercurial/revlog.py
--- a/mercurial/revlog.py
+++ b/mercurial/revlog.py
@@ -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'
diff --git a/mercurial/copies.py b/mercurial/copies.py
--- a/mercurial/copies.py
+++ b/mercurial/copies.py
@@ -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.