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