##// END OF EJS Templates
stream-clone: avoid opening a revlog in case we do not need it...
Arseniy Alekseyev -
r51565:3b563954 default
parent child Browse files
Show More
@@ -290,6 +290,16 b' class revlog:'
290 290
291 291 _flagserrorclass = error.RevlogError
292 292
293 @staticmethod
294 def is_inline_index(header_bytes):
295 header = INDEX_HEADER.unpack(header_bytes)[0]
296
297 _format_flags = header & ~0xFFFF
298 _format_version = header & 0xFFFF
299
300 features = FEATURES_BY_VERSION[_format_version]
301 return features[b'inline'](_format_flags)
302
293 303 def __init__(
294 304 self,
295 305 opener,
@@ -16,6 +16,9 b' from .i18n import _'
16 16 from .pycompat import getattr
17 17 from .thirdparty import attr
18 18 from .node import hex
19 from .revlogutils.constants import (
20 INDEX_HEADER,
21 )
19 22 from . import (
20 23 changelog,
21 24 error,
@@ -23,6 +26,7 b' from . import ('
23 26 manifest,
24 27 policy,
25 28 pycompat,
29 revlog as revlogmod,
26 30 util,
27 31 vfs as vfsmod,
28 32 )
@@ -619,44 +623,70 b' class RevlogStoreEntry(BaseStoreEntry):'
619 623 copies=None,
620 624 max_changeset=None,
621 625 ):
622 if repo is None or max_changeset is None:
623 return super().get_streams(
624 repo=repo,
625 vfs=vfs,
626 copies=copies,
627 max_changeset=max_changeset,
628 )
629 if any(k.endswith(b'.idx') for k in self._details.keys()):
626 if (
627 repo is None
628 or max_changeset is None
630 629 # This use revlog-v2, ignore for now
630 or any(k.endswith(b'.idx') for k in self._details.keys())
631 # This is not inline, no race expected
632 or b'.d' in self._details
633 ):
631 634 return super().get_streams(
632 635 repo=repo,
633 636 vfs=vfs,
634 637 copies=copies,
635 638 max_changeset=max_changeset,
636 639 )
637 name_to_ext = {}
638 for ext in self._details.keys():
639 name_to_ext[self._path_prefix + ext] = ext
640
640 641 name_to_size = {}
641 642 for f in self.files():
642 643 name_to_size[f.unencoded_path] = f.file_size(None)
644
643 645 stream = [
644 646 f.get_stream(vfs, copies)
645 647 for f in self.files()
646 if name_to_ext[f.unencoded_path] not in (b'.d', b'.i')
648 if not f.unencoded_path.endswith(b'.i')
647 649 ]
648 650
649 is_inline = b'.d' not in self._details
651 index_path = self._path_prefix + b'.i'
650 652
651 rl = self.get_revlog_instance(repo).get_revlog()
652 rl_stream = rl.get_streams(max_changeset, force_inline=is_inline)
653 index_file = None
654 try:
655 index_file = vfs(index_path)
656 header = index_file.read(INDEX_HEADER.size)
657 if revlogmod.revlog.is_inline_index(header):
658 size = name_to_size[index_path]
653 659
654 for name, s, size in rl_stream:
655 if name_to_size.get(name, 0) != size:
656 msg = _(b"expected %d bytes but %d provided for %s")
657 msg %= name_to_size.get(name, 0), size, name
658 raise error.Abort(msg)
659 stream.extend(rl_stream)
660 # no split underneath, just return the stream
661 def get_stream():
662 fp = index_file
663 try:
664 fp.seek(0)
665 yield None
666 if size <= 65536:
667 yield fp.read(size)
668 else:
669 yield from util.filechunkiter(fp, limit=size)
670 finally:
671 fp.close()
672
673 s = get_stream()
674 next(s)
675 index_file = None
676 stream.append((index_path, s, size))
677 else:
678 rl = self.get_revlog_instance(repo).get_revlog()
679 rl_stream = rl.get_streams(max_changeset, force_inline=True)
680 for name, s, size in rl_stream:
681 if name_to_size.get(name, 0) != size:
682 msg = _(b"expected %d bytes but %d provided for %s")
683 msg %= name_to_size.get(name, 0), size, name
684 raise error.Abort(msg)
685 stream.extend(rl_stream)
686 finally:
687 if index_file is not None:
688 index_file.close()
689
660 690 files = self.files()
661 691 assert len(stream) == len(files), (
662 692 stream,
General Comments 0
You need to be logged in to leave comments. Login now