comparison mercurial/upgrade_utils/actions.py @ 47319:e985a36c2aa3

upgrade: Use `improvement` subclasses everywhere, not instances This changes the source definition of optimizations to match that of formats: a subclass with a decorator, instead of an instance passed to a function call. Not having any instance removes the confusion between class attributes and instance attributes, which were used interchangeably. Differential Revision: https://phab.mercurial-scm.org/D10768
author Simon Sapin <simon.sapin@octobus.net>
date Fri, 21 May 2021 17:12:47 +0200
parents ed0d54b20c5b
children a43d256c041a
comparison
equal deleted inserted replaced
47315:825d5a5907b4 47319:e985a36c2aa3
42 FORMAT_VARIANT = b'deficiency' 42 FORMAT_VARIANT = b'deficiency'
43 OPTIMISATION = b'optimization' 43 OPTIMISATION = b'optimization'
44 44
45 45
46 class improvement(object): 46 class improvement(object):
47 """Represents an improvement that can be made as part of an upgrade. 47 """Represents an improvement that can be made as part of an upgrade."""
48 48
49 The following attributes are defined on each instance: 49 ### The following attributes should be defined for each subclass:
50 50
51 name 51 # Either ``FORMAT_VARIANT`` or ``OPTIMISATION``.
52 Machine-readable string uniquely identifying this improvement. It 52 # A format variant is where we change the storage format. Not all format
53 will be mapped to an action later in the upgrade process. 53 # variant changes are an obvious problem.
54 54 # An optimization is an action (sometimes optional) that
55 type 55 # can be taken to further improve the state of the repository.
56 Either ``FORMAT_VARIANT`` or ``OPTIMISATION``. 56 type = None
57 A format variant is where we change the storage format. Not all format
58 variant changes are an obvious problem.
59 An optimization is an action (sometimes optional) that
60 can be taken to further improve the state of the repository.
61
62 description
63 Message intended for humans explaining the improvement in more detail,
64 including the implications of it. For ``FORMAT_VARIANT`` types, should be
65 worded in the present tense. For ``OPTIMISATION`` types, should be
66 worded in the future tense.
67
68 upgrademessage
69 Message intended for humans explaining what an upgrade addressing this
70 issue will do. Should be worded in the future tense.
71
72 postupgrademessage
73 Message intended for humans which will be shown post an upgrade
74 operation when the improvement will be added
75
76 postdowngrademessage
77 Message intended for humans which will be shown post an upgrade
78 operation in which this improvement was removed
79
80 touches_filelogs (bool)
81 Whether this improvement touches filelogs
82
83 touches_manifests (bool)
84 Whether this improvement touches manifests
85
86 touches_changelog (bool)
87 Whether this improvement touches changelog
88
89 touches_requirements (bool)
90 Whether this improvement changes repository requirements
91 """
92
93 def __init__(self, name, type, description, upgrademessage):
94 self.name = name
95 self.type = type
96 self.description = description
97 self.upgrademessage = upgrademessage
98 self.postupgrademessage = None
99 self.postdowngrademessage = None
100 # By default for now, we assume every improvement touches
101 # all the things
102 self.touches_filelogs = True
103 self.touches_manifests = True
104 self.touches_changelog = True
105 self.touches_requirements = True
106
107 def __eq__(self, other):
108 if not isinstance(other, improvement):
109 # This is what python tell use to do
110 return NotImplemented
111 return self.name == other.name
112
113 def __ne__(self, other):
114 return not (self == other)
115
116 def __hash__(self):
117 return hash(self.name)
118
119
120 allformatvariant = [] # type: List[Type['formatvariant']]
121
122
123 def registerformatvariant(cls):
124 allformatvariant.append(cls)
125 return cls
126
127
128 class formatvariant(improvement):
129 """an improvement subclass dedicated to repository format"""
130
131 type = FORMAT_VARIANT
132 ### The following attributes should be defined for each class:
133 57
134 # machine-readable string uniquely identifying this improvement. it will be 58 # machine-readable string uniquely identifying this improvement. it will be
135 # mapped to an action later in the upgrade process. 59 # mapped to an action later in the upgrade process.
136 name = None 60 name = None
137 61
155 # Message intended for humans which will be shown post an upgrade 79 # Message intended for humans which will be shown post an upgrade
156 # operation in which this improvement was removed 80 # operation in which this improvement was removed
157 postdowngrademessage = None 81 postdowngrademessage = None
158 82
159 # By default for now, we assume every improvement touches all the things 83 # By default for now, we assume every improvement touches all the things
84
85 # Whether this improvement touches filelogs
160 touches_filelogs = True 86 touches_filelogs = True
87
88 # Whether this improvement touches manifests
161 touches_manifests = True 89 touches_manifests = True
90
91 # Whether this improvement touches changelog
162 touches_changelog = True 92 touches_changelog = True
93
94 # Whether this improvement changes repository requirements
163 touches_requirements = True 95 touches_requirements = True
164 96
165 def __init__(self): 97
166 raise NotImplementedError() 98 allformatvariant = [] # type: List[Type['formatvariant']]
99
100
101 def registerformatvariant(cls):
102 allformatvariant.append(cls)
103 return cls
104
105
106 class formatvariant(improvement):
107 """an improvement subclass dedicated to repository format"""
108
109 type = FORMAT_VARIANT
167 110
168 @staticmethod 111 @staticmethod
169 def fromrepo(repo): 112 def fromrepo(repo):
170 """current value of the variant in the repository""" 113 """current value of the variant in the repository"""
171 raise NotImplementedError() 114 raise NotImplementedError()
543 def register_optimization(obj): 486 def register_optimization(obj):
544 ALL_OPTIMISATIONS.append(obj) 487 ALL_OPTIMISATIONS.append(obj)
545 return obj 488 return obj
546 489
547 490
548 register_optimization( 491 class optimization(improvement):
549 improvement( 492 """an improvement subclass dedicated to optimizations"""
550 name=b're-delta-parent', 493
551 type=OPTIMISATION, 494 type = OPTIMISATION
552 description=_( 495
553 b'deltas within internal storage will be recalculated to ' 496
554 b'choose an optimal base revision where this was not ' 497 @register_optimization
555 b'already done; the size of the repository may shrink and ' 498 class redeltaparents(optimization):
556 b'various operations may become faster; the first time ' 499 name = b're-delta-parent'
557 b'this optimization is performed could slow down upgrade ' 500
558 b'execution considerably; subsequent invocations should ' 501 type = OPTIMISATION
559 b'not run noticeably slower' 502
560 ), 503 description = _(
561 upgrademessage=_( 504 b'deltas within internal storage will be recalculated to '
562 b'deltas within internal storage will choose a new ' 505 b'choose an optimal base revision where this was not '
563 b'base revision if needed' 506 b'already done; the size of the repository may shrink and '
564 ), 507 b'various operations may become faster; the first time '
565 ) 508 b'this optimization is performed could slow down upgrade '
566 ) 509 b'execution considerably; subsequent invocations should '
567 510 b'not run noticeably slower'
568 register_optimization( 511 )
569 improvement( 512
570 name=b're-delta-multibase', 513 upgrademessage = _(
571 type=OPTIMISATION, 514 b'deltas within internal storage will choose a new '
572 description=_( 515 b'base revision if needed'
573 b'deltas within internal storage will be recalculated ' 516 )
574 b'against multiple base revision and the smallest ' 517
575 b'difference will be used; the size of the repository may ' 518
576 b'shrink significantly when there are many merges; this ' 519 @register_optimization
577 b'optimization will slow down execution in proportion to ' 520 class redeltamultibase(optimization):
578 b'the number of merges in the repository and the amount ' 521 name = b're-delta-multibase'
579 b'of files in the repository; this slow down should not ' 522
580 b'be significant unless there are tens of thousands of ' 523 type = OPTIMISATION
581 b'files and thousands of merges' 524
582 ), 525 description = _(
583 upgrademessage=_( 526 b'deltas within internal storage will be recalculated '
584 b'deltas within internal storage will choose an ' 527 b'against multiple base revision and the smallest '
585 b'optimal delta by computing deltas against multiple ' 528 b'difference will be used; the size of the repository may '
586 b'parents; may slow down execution time ' 529 b'shrink significantly when there are many merges; this '
587 b'significantly' 530 b'optimization will slow down execution in proportion to '
588 ), 531 b'the number of merges in the repository and the amount '
589 ) 532 b'of files in the repository; this slow down should not '
590 ) 533 b'be significant unless there are tens of thousands of '
591 534 b'files and thousands of merges'
592 register_optimization( 535 )
593 improvement( 536
594 name=b're-delta-all', 537 upgrademessage = _(
595 type=OPTIMISATION, 538 b'deltas within internal storage will choose an '
596 description=_( 539 b'optimal delta by computing deltas against multiple '
597 b'deltas within internal storage will always be ' 540 b'parents; may slow down execution time '
598 b'recalculated without reusing prior deltas; this will ' 541 b'significantly'
599 b'likely make execution run several times slower; this ' 542 )
600 b'optimization is typically not needed' 543
601 ), 544
602 upgrademessage=_( 545 @register_optimization
603 b'deltas within internal storage will be fully ' 546 class redeltaall(optimization):
604 b'recomputed; this will likely drastically slow down ' 547 name = b're-delta-all'
605 b'execution time' 548
606 ), 549 type = OPTIMISATION
607 ) 550
608 ) 551 description = _(
609 552 b'deltas within internal storage will always be '
610 register_optimization( 553 b'recalculated without reusing prior deltas; this will '
611 improvement( 554 b'likely make execution run several times slower; this '
612 name=b're-delta-fulladd', 555 b'optimization is typically not needed'
613 type=OPTIMISATION, 556 )
614 description=_( 557
615 b'every revision will be re-added as if it was new ' 558 upgrademessage = _(
616 b'content. It will go through the full storage ' 559 b'deltas within internal storage will be fully '
617 b'mechanism giving extensions a chance to process it ' 560 b'recomputed; this will likely drastically slow down '
618 b'(eg. lfs). This is similar to "re-delta-all" but even ' 561 b'execution time'
619 b'slower since more logic is involved.' 562 )
620 ), 563
621 upgrademessage=_( 564
622 b'each revision will be added as new content to the ' 565 @register_optimization
623 b'internal storage; this will likely drastically slow ' 566 class redeltafulladd(optimization):
624 b'down execution time, but some extensions might need ' 567 name = b're-delta-fulladd'
625 b'it' 568
626 ), 569 type = OPTIMISATION
627 ) 570
628 ) 571 description = _(
572 b'every revision will be re-added as if it was new '
573 b'content. It will go through the full storage '
574 b'mechanism giving extensions a chance to process it '
575 b'(eg. lfs). This is similar to "re-delta-all" but even '
576 b'slower since more logic is involved.'
577 )
578
579 upgrademessage = _(
580 b'each revision will be added as new content to the '
581 b'internal storage; this will likely drastically slow '
582 b'down execution time, but some extensions might need '
583 b'it'
584 )
629 585
630 586
631 def findoptimizations(repo): 587 def findoptimizations(repo):
632 """Determine optimisation that could be used during upgrade""" 588 """Determine optimisation that could be used during upgrade"""
633 # These are unconditionally added. There is logic later that figures out 589 # These are unconditionally added. There is logic later that figures out