comparison mercurial/store.py @ 50473:5a2fb64d38b2

store: use specialized class for store entries We introduce two different classes for revlog and other entries. For now, we still have multiple entry for the same revlog, but we will work toward grouping the different file in a single entry in this series. Having the distinction is a step toward this goal.
author Pierre-Yves David <pierre-yves.david@octobus.net>
date Mon, 15 May 2023 08:56:56 +0200
parents 9fdc28e21b68
children c37450a5f1dc
comparison
equal deleted inserted replaced
50472:9fdc28e21b68 50473:5a2fb64d38b2
452 FILETYPE_FILELOG_OTHER = FILEFLAGS_FILELOG | FILEFLAGS_REVLOG_OTHER 452 FILETYPE_FILELOG_OTHER = FILEFLAGS_FILELOG | FILEFLAGS_REVLOG_OTHER
453 FILETYPE_OTHER = FILEFLAGS_OTHER 453 FILETYPE_OTHER = FILEFLAGS_OTHER
454 454
455 455
456 @attr.s(slots=True) 456 @attr.s(slots=True)
457 class StoreEntry: 457 class BaseStoreEntry:
458 """An entry in the store 458 """An entry in the store
459 459
460 This is returned by `store.walk` and represent some data in the store.""" 460 This is returned by `store.walk` and represent some data in the store."""
461 461
462 unencoded_path = attr.ib() 462 unencoded_path = attr.ib()
463 is_revlog = attr.ib(default=False)
464 revlog_type = attr.ib(default=None)
465 is_revlog_main = attr.ib(default=None)
466 is_volatile = attr.ib(default=False) 463 is_volatile = attr.ib(default=False)
467 file_size = attr.ib(default=None) 464 file_size = attr.ib(default=None)
468 465
469 def files(self): 466 def files(self):
470 return [ 467 return [
472 unencoded_path=self.unencoded_path, 469 unencoded_path=self.unencoded_path,
473 file_size=self.file_size, 470 file_size=self.file_size,
474 is_volatile=self.is_volatile, 471 is_volatile=self.is_volatile,
475 ) 472 )
476 ] 473 ]
474
475
476 @attr.s(slots=True)
477 class SimpleStoreEntry(BaseStoreEntry):
478 """A generic entry in the store"""
479
480 is_revlog = False
481
482
483 @attr.s(slots=True)
484 class RevlogStoreEntry(BaseStoreEntry):
485 """A revlog entry in the store"""
486
487 is_revlog = True
488 revlog_type = attr.ib(default=None)
489 is_revlog_main = attr.ib(default=None)
477 490
478 491
479 @attr.s(slots=True) 492 @attr.s(slots=True)
480 class StoreFile: 493 class StoreFile:
481 """a file matching an entry""" 494 """a file matching an entry"""
534 rootstore = manifest.manifestrevlog(repo.nodeconstants, self.vfs) 547 rootstore = manifest.manifestrevlog(repo.nodeconstants, self.vfs)
535 return manifest.manifestlog(self.vfs, repo, rootstore, storenarrowmatch) 548 return manifest.manifestlog(self.vfs, repo, rootstore, storenarrowmatch)
536 549
537 def datafiles( 550 def datafiles(
538 self, matcher=None, undecodable=None 551 self, matcher=None, undecodable=None
539 ) -> Generator[StoreEntry, None, None]: 552 ) -> Generator[BaseStoreEntry, None, None]:
540 """Like walk, but excluding the changelog and root manifest. 553 """Like walk, but excluding the changelog and root manifest.
541 554
542 When [undecodable] is None, revlogs names that can't be 555 When [undecodable] is None, revlogs names that can't be
543 decoded cause an exception. When it is provided, it should 556 decoded cause an exception. When it is provided, it should
544 be a list and the filenames that can't be decoded are added 557 be a list and the filenames that can't be decoded are added
545 to it instead. This is very rarely needed.""" 558 to it instead. This is very rarely needed."""
546 files = self._walk(b'data', True) + self._walk(b'meta', True) 559 files = self._walk(b'data', True) + self._walk(b'meta', True)
547 for (t, u, s) in files: 560 for (t, u, s) in files:
548 if t is not None: 561 if t is not None:
549 yield StoreEntry( 562 yield RevlogStoreEntry(
550 unencoded_path=u, 563 unencoded_path=u,
551 is_revlog=True,
552 revlog_type=FILEFLAGS_FILELOG, 564 revlog_type=FILEFLAGS_FILELOG,
553 is_revlog_main=bool(t & FILEFLAGS_REVLOG_MAIN), 565 is_revlog_main=bool(t & FILEFLAGS_REVLOG_MAIN),
554 is_volatile=bool(t & FILEFLAGS_VOLATILE), 566 is_volatile=bool(t & FILEFLAGS_VOLATILE),
555 file_size=s, 567 file_size=s,
556 ) 568 )
557 569
558 def topfiles(self) -> Generator[StoreEntry, None, None]: 570 def topfiles(self) -> Generator[BaseStoreEntry, None, None]:
559 # yield manifest before changelog 571 # yield manifest before changelog
560 files = reversed(self._walk(b'', False)) 572 files = reversed(self._walk(b'', False))
561 for (t, u, s) in files: 573 for (t, u, s) in files:
562 if u.startswith(b'00changelog'): 574 if u.startswith(b'00changelog'):
563 revlog_type = FILEFLAGS_CHANGELOG 575 yield RevlogStoreEntry(
576 unencoded_path=u,
577 revlog_type=FILEFLAGS_CHANGELOG,
578 is_revlog_main=bool(t & FILEFLAGS_REVLOG_MAIN),
579 is_volatile=bool(t & FILEFLAGS_VOLATILE),
580 file_size=s,
581 )
564 elif u.startswith(b'00manifest'): 582 elif u.startswith(b'00manifest'):
565 revlog_type = FILEFLAGS_MANIFESTLOG 583 yield RevlogStoreEntry(
584 unencoded_path=u,
585 revlog_type=FILEFLAGS_MANIFESTLOG,
586 is_revlog_main=bool(t & FILEFLAGS_REVLOG_MAIN),
587 is_volatile=bool(t & FILEFLAGS_VOLATILE),
588 file_size=s,
589 )
566 else: 590 else:
567 revlog_type = None 591 yield SimpleStoreEntry(
568 yield StoreEntry( 592 unencoded_path=u,
569 unencoded_path=u, 593 is_volatile=bool(t & FILEFLAGS_VOLATILE),
570 is_revlog=revlog_type is not None, 594 file_size=s,
571 revlog_type=revlog_type, 595 )
572 is_revlog_main=bool(t & FILEFLAGS_REVLOG_MAIN), 596
573 is_volatile=bool(t & FILEFLAGS_VOLATILE), 597 def walk(self, matcher=None) -> Generator[BaseStoreEntry, None, None]:
574 file_size=s,
575 )
576
577 def walk(self, matcher=None) -> Generator[StoreEntry, None, None]:
578 """return files related to data storage (ie: revlogs) 598 """return files related to data storage (ie: revlogs)
579 599
580 yields (file_type, unencoded, size) 600 yields (file_type, unencoded, size)
581 601
582 if a matcher is passed, storage files of only those tracked paths 602 if a matcher is passed, storage files of only those tracked paths
627 # However that might change so we should probably add a test and encoding 647 # However that might change so we should probably add a test and encoding
628 # decoding for it too. see issue6548 648 # decoding for it too. see issue6548
629 649
630 def datafiles( 650 def datafiles(
631 self, matcher=None, undecodable=None 651 self, matcher=None, undecodable=None
632 ) -> Generator[StoreEntry, None, None]: 652 ) -> Generator[BaseStoreEntry, None, None]:
633 for entry in super(encodedstore, self).datafiles(): 653 for entry in super(encodedstore, self).datafiles():
634 try: 654 try:
635 f1 = entry.unencoded_path 655 f1 = entry.unencoded_path
636 f2 = decodefilename(f1) 656 f2 = decodefilename(f1)
637 except KeyError: 657 except KeyError:
840 def getsize(self, path): 860 def getsize(self, path):
841 return self.rawvfs.stat(path).st_size 861 return self.rawvfs.stat(path).st_size
842 862
843 def datafiles( 863 def datafiles(
844 self, matcher=None, undecodable=None 864 self, matcher=None, undecodable=None
845 ) -> Generator[StoreEntry, None, None]: 865 ) -> Generator[BaseStoreEntry, None, None]:
846 for f in sorted(self.fncache): 866 for f in sorted(self.fncache):
847 if not _matchtrackedpath(f, matcher): 867 if not _matchtrackedpath(f, matcher):
848 continue 868 continue
849 ef = self.encode(f) 869 ef = self.encode(f)
850 t = revlog_type(f) 870 t = revlog_type(f)
852 # Note: this should not be in the fncache then… 872 # Note: this should not be in the fncache then…
853 # 873 #
854 # However the fncache might contains such file added by 874 # However the fncache might contains such file added by
855 # previous version of Mercurial. 875 # previous version of Mercurial.
856 continue 876 continue
857 t |= FILEFLAGS_FILELOG
858 try: 877 try:
859 yield StoreEntry( 878 yield RevlogStoreEntry(
860 unencoded_path=f, 879 unencoded_path=f,
861 is_revlog=True,
862 revlog_type=FILEFLAGS_FILELOG, 880 revlog_type=FILEFLAGS_FILELOG,
863 is_revlog_main=bool(t & FILEFLAGS_REVLOG_MAIN), 881 is_revlog_main=bool(t & FILEFLAGS_REVLOG_MAIN),
864 is_volatile=bool(t & FILEFLAGS_VOLATILE), 882 is_volatile=bool(t & FILEFLAGS_VOLATILE),
865 file_size=self.getsize(ef), 883 file_size=self.getsize(ef),
866 ) 884 )