##// END OF EJS Templates
repair: determine what upgrade will do...
Gregory Szorc -
r30776:3997edc4 default
parent child Browse files
Show More
@@ -431,11 +431,218 b' def upgradeallowednewrequirements(repo):'
431 'generaldelta',
431 'generaldelta',
432 ])
432 ])
433
433
434 deficiency = 'deficiency'
435 optimisation = 'optimization'
436
437 class upgradeimprovement(object):
438 """Represents an improvement that can be made as part of an upgrade.
439
440 The following attributes are defined on each instance:
441
442 name
443 Machine-readable string uniquely identifying this improvement. It
444 will be mapped to an action later in the upgrade process.
445
446 type
447 Either ``deficiency`` or ``optimisation``. A deficiency is an obvious
448 problem. An optimization is an action (sometimes optional) that
449 can be taken to further improve the state of the repository.
450
451 description
452 Message intended for humans explaining the improvement in more detail,
453 including the implications of it. For ``deficiency`` types, should be
454 worded in the present tense. For ``optimisation`` types, should be
455 worded in the future tense.
456
457 upgrademessage
458 Message intended for humans explaining what an upgrade addressing this
459 issue will do. Should be worded in the future tense.
460
461 fromdefault (``deficiency`` types only)
462 Boolean indicating whether the current (deficient) state deviates
463 from Mercurial's default configuration.
464
465 fromconfig (``deficiency`` types only)
466 Boolean indicating whether the current (deficient) state deviates
467 from the current Mercurial configuration.
468 """
469 def __init__(self, name, type, description, upgrademessage, **kwargs):
470 self.name = name
471 self.type = type
472 self.description = description
473 self.upgrademessage = upgrademessage
474
475 for k, v in kwargs.items():
476 setattr(self, k, v)
477
478 def upgradefindimprovements(repo):
479 """Determine improvements that can be made to the repo during upgrade.
480
481 Returns a list of ``upgradeimprovement`` describing repository deficiencies
482 and optimizations.
483 """
484 # Avoid cycle: cmdutil -> repair -> localrepo -> cmdutil
485 from . import localrepo
486
487 newreporeqs = localrepo.newreporequirements(repo)
488
489 improvements = []
490
491 # We could detect lack of revlogv1 and store here, but they were added
492 # in 0.9.2 and we don't support upgrading repos without these
493 # requirements, so let's not bother.
494
495 if 'fncache' not in repo.requirements:
496 improvements.append(upgradeimprovement(
497 name='fncache',
498 type=deficiency,
499 description=_('long and reserved filenames may not work correctly; '
500 'repository performance is sub-optimal'),
501 upgrademessage=_('repository will be more resilient to storing '
502 'certain paths and performance of certain '
503 'operations should be improved'),
504 fromdefault=True,
505 fromconfig='fncache' in newreporeqs))
506
507 if 'dotencode' not in repo.requirements:
508 improvements.append(upgradeimprovement(
509 name='dotencode',
510 type=deficiency,
511 description=_('storage of filenames beginning with a period or '
512 'space may not work correctly'),
513 upgrademessage=_('repository will be better able to store files '
514 'beginning with a space or period'),
515 fromdefault=True,
516 fromconfig='dotencode' in newreporeqs))
517
518 if 'generaldelta' not in repo.requirements:
519 improvements.append(upgradeimprovement(
520 name='generaldelta',
521 type=deficiency,
522 description=_('deltas within internal storage are unable to '
523 'choose optimal revisions; repository is larger and '
524 'slower than it could be; interaction with other '
525 'repositories may require extra network and CPU '
526 'resources, making "hg push" and "hg pull" slower'),
527 upgrademessage=_('repository storage will be able to create '
528 'optimal deltas; new repository data will be '
529 'smaller and read times should decrease; '
530 'interacting with other repositories using this '
531 'storage model should require less network and '
532 'CPU resources, making "hg push" and "hg pull" '
533 'faster'),
534 fromdefault=True,
535 fromconfig='generaldelta' in newreporeqs))
536
537 # Mercurial 4.0 changed changelogs to not use delta chains. Search for
538 # changelogs with deltas.
539 cl = repo.changelog
540 for rev in cl:
541 chainbase = cl.chainbase(rev)
542 if chainbase != rev:
543 improvements.append(upgradeimprovement(
544 name='removecldeltachain',
545 type=deficiency,
546 description=_('changelog storage is using deltas instead of '
547 'raw entries; changelog reading and any '
548 'operation relying on changelog data are slower '
549 'than they could be'),
550 upgrademessage=_('changelog storage will be reformated to '
551 'store raw entries; changelog reading will be '
552 'faster; changelog size may be reduced'),
553 fromdefault=True,
554 fromconfig=True))
555 break
556
557 # Now for the optimizations.
558
559 # These are unconditionally added. There is logic later that figures out
560 # which ones to apply.
561
562 improvements.append(upgradeimprovement(
563 name='redeltaparent',
564 type=optimisation,
565 description=_('deltas within internal storage will be recalculated to '
566 'choose an optimal base revision where this was not '
567 'already done; the size of the repository may shrink and '
568 'various operations may become faster; the first time '
569 'this optimization is performed could slow down upgrade '
570 'execution considerably; subsequent invocations should '
571 'not run noticeably slower'),
572 upgrademessage=_('deltas within internal storage will choose a new '
573 'base revision if needed')))
574
575 improvements.append(upgradeimprovement(
576 name='redeltamultibase',
577 type=optimisation,
578 description=_('deltas within internal storage will be recalculated '
579 'against multiple base revision and the smallest '
580 'difference will be used; the size of the repository may '
581 'shrink significantly when there are many merges; this '
582 'optimization will slow down execution in proportion to '
583 'the number of merges in the repository and the amount '
584 'of files in the repository; this slow down should not '
585 'be significant unless there are tens of thousands of '
586 'files and thousands of merges'),
587 upgrademessage=_('deltas within internal storage will choose an '
588 'optimal delta by computing deltas against multiple '
589 'parents; may slow down execution time '
590 'significantly')))
591
592 improvements.append(upgradeimprovement(
593 name='redeltaall',
594 type=optimisation,
595 description=_('deltas within internal storage will always be '
596 'recalculated without reusing prior deltas; this will '
597 'likely make execution run several times slower; this '
598 'optimization is typically not needed'),
599 upgrademessage=_('deltas within internal storage will be fully '
600 'recomputed; this will likely drastically slow down '
601 'execution time')))
602
603 return improvements
604
605 def upgradedetermineactions(repo, improvements, sourcereqs, destreqs,
606 optimize):
607 """Determine upgrade actions that will be performed.
608
609 Given a list of improvements as returned by ``upgradefindimprovements``,
610 determine the list of upgrade actions that will be performed.
611
612 The role of this function is to filter improvements if needed, apply
613 recommended optimizations from the improvements list that make sense,
614 etc.
615
616 Returns a list of action names.
617 """
618 newactions = []
619
620 knownreqs = upgradesupporteddestrequirements(repo)
621
622 for i in improvements:
623 name = i.name
624
625 # If the action is a requirement that doesn't show up in the
626 # destination requirements, prune the action.
627 if name in knownreqs and name not in destreqs:
628 continue
629
630 if i.type == deficiency:
631 newactions.append(name)
632
633 newactions.extend(o for o in sorted(optimize) if o not in newactions)
634
635 # FUTURE consider adding some optimizations here for certain transitions.
636 # e.g. adding generaldelta could schedule parent redeltas.
637
638 return newactions
639
434 def upgraderepo(ui, repo, run=False, optimize=None):
640 def upgraderepo(ui, repo, run=False, optimize=None):
435 """Upgrade a repository in place."""
641 """Upgrade a repository in place."""
436 # Avoid cycle: cmdutil -> repair -> localrepo -> cmdutil
642 # Avoid cycle: cmdutil -> repair -> localrepo -> cmdutil
437 from . import localrepo
643 from . import localrepo
438
644
645 optimize = set(optimize or [])
439 repo = repo.unfiltered()
646 repo = repo.unfiltered()
440
647
441 # Ensure the repository can be upgraded.
648 # Ensure the repository can be upgraded.
@@ -473,6 +680,25 b' def upgraderepo(ui, repo, run=False, opt'
473 'destination requirement: %s') %
680 'destination requirement: %s') %
474 _(', ').join(sorted(unsupportedreqs)))
681 _(', ').join(sorted(unsupportedreqs)))
475
682
683 # Find and validate all improvements that can be made.
684 improvements = upgradefindimprovements(repo)
685 for i in improvements:
686 if i.type not in (deficiency, optimisation):
687 raise error.Abort(_('unexpected improvement type %s for %s') % (
688 i.type, i.name))
689
690 # Validate arguments.
691 unknownoptimize = optimize - set(i.name for i in improvements
692 if i.type == optimisation)
693 if unknownoptimize:
694 raise error.Abort(_('unknown optimization action requested: %s') %
695 ', '.join(sorted(unknownoptimize)),
696 hint=_('run without arguments to see valid '
697 'optimizations'))
698
699 actions = upgradedetermineactions(repo, improvements, repo.requirements,
700 newreqs, optimize)
701
476 def printrequirements():
702 def printrequirements():
477 ui.write(_('requirements\n'))
703 ui.write(_('requirements\n'))
478 ui.write(_(' preserved: %s\n') %
704 ui.write(_(' preserved: %s\n') %
@@ -488,8 +714,60 b' def upgraderepo(ui, repo, run=False, opt'
488
714
489 ui.write('\n')
715 ui.write('\n')
490
716
717 def printupgradeactions():
718 for action in actions:
719 for i in improvements:
720 if i.name == action:
721 ui.write('%s\n %s\n\n' %
722 (i.name, i.upgrademessage))
723
491 if not run:
724 if not run:
725 fromdefault = []
726 fromconfig = []
727 optimizations = []
728
729 for i in improvements:
730 assert i.type in (deficiency, optimisation)
731 if i.type == deficiency:
732 if i.fromdefault:
733 fromdefault.append(i)
734 if i.fromconfig:
735 fromconfig.append(i)
736 else:
737 optimizations.append(i)
738
739 if fromdefault or fromconfig:
740 fromconfignames = set(x.name for x in fromconfig)
741 onlydefault = [i for i in fromdefault
742 if i.name not in fromconfignames]
743
744 if fromconfig:
745 ui.write(_('repository lacks features recommended by '
746 'current config options:\n\n'))
747 for i in fromconfig:
748 ui.write('%s\n %s\n\n' % (i.name, i.description))
749
750 if onlydefault:
751 ui.write(_('repository lacks features used by the default '
752 'config options:\n\n'))
753 for i in onlydefault:
754 ui.write('%s\n %s\n\n' % (i.name, i.description))
755
756 ui.write('\n')
757 else:
758 ui.write(_('(no feature deficiencies found in existing '
759 'repository)\n'))
760
492 ui.write(_('performing an upgrade with "--run" will make the following '
761 ui.write(_('performing an upgrade with "--run" will make the following '
493 'changes:\n\n'))
762 'changes:\n\n'))
494
763
495 printrequirements()
764 printrequirements()
765 printupgradeactions()
766
767 unusedoptimize = [i for i in improvements
768 if i.name not in actions and i.type == optimisation]
769 if unusedoptimize:
770 ui.write(_('additional optimizations are available by specifying '
771 '"--optimize <name>":\n\n'))
772 for i in unusedoptimize:
773 ui.write(_('%s\n %s\n\n') % (i.name, i.description))
@@ -49,3 +49,134 b' Cannot add manifestv2 or treemanifest re'
49 $ hg -R disallowaddedreq --config experimental.manifestv2=true --config experimental.treemanifest=true debugupgraderepo
49 $ hg -R disallowaddedreq --config experimental.manifestv2=true --config experimental.treemanifest=true debugupgraderepo
50 abort: cannot upgrade repository; do not support adding requirement: manifestv2, treemanifest
50 abort: cannot upgrade repository; do not support adding requirement: manifestv2, treemanifest
51 [255]
51 [255]
52
53 An upgrade of a repository created with recommended settings only suggests optimizations
54
55 $ hg init empty
56 $ cd empty
57 $ hg debugupgraderepo
58 (no feature deficiencies found in existing repository)
59 performing an upgrade with "--run" will make the following changes:
60
61 requirements
62 preserved: dotencode, fncache, generaldelta, revlogv1, store
63
64 additional optimizations are available by specifying "--optimize <name>":
65
66 redeltaparent
67 deltas within internal storage will be recalculated to choose an optimal base revision where this was not already done; the size of the repository may shrink and various operations may become faster; the first time this optimization is performed could slow down upgrade execution considerably; subsequent invocations should not run noticeably slower
68
69 redeltamultibase
70 deltas within internal storage will be recalculated against multiple base revision and the smallest difference will be used; the size of the repository may shrink significantly when there are many merges; this optimization will slow down execution in proportion to the number of merges in the repository and the amount of files in the repository; this slow down should not be significant unless there are tens of thousands of files and thousands of merges
71
72 redeltaall
73 deltas within internal storage will always be recalculated without reusing prior deltas; this will likely make execution run several times slower; this optimization is typically not needed
74
75
76 --optimize can be used to add optimizations
77
78 $ hg debugupgrade --optimize redeltaparent
79 (no feature deficiencies found in existing repository)
80 performing an upgrade with "--run" will make the following changes:
81
82 requirements
83 preserved: dotencode, fncache, generaldelta, revlogv1, store
84
85 redeltaparent
86 deltas within internal storage will choose a new base revision if needed
87
88 additional optimizations are available by specifying "--optimize <name>":
89
90 redeltamultibase
91 deltas within internal storage will be recalculated against multiple base revision and the smallest difference will be used; the size of the repository may shrink significantly when there are many merges; this optimization will slow down execution in proportion to the number of merges in the repository and the amount of files in the repository; this slow down should not be significant unless there are tens of thousands of files and thousands of merges
92
93 redeltaall
94 deltas within internal storage will always be recalculated without reusing prior deltas; this will likely make execution run several times slower; this optimization is typically not needed
95
96
97 Various sub-optimal detections work
98
99 $ cat > .hg/requires << EOF
100 > revlogv1
101 > store
102 > EOF
103
104 $ hg debugupgraderepo
105 repository lacks features recommended by current config options:
106
107 fncache
108 long and reserved filenames may not work correctly; repository performance is sub-optimal
109
110 dotencode
111 storage of filenames beginning with a period or space may not work correctly
112
113 generaldelta
114 deltas within internal storage are unable to choose optimal revisions; repository is larger and slower than it could be; interaction with other repositories may require extra network and CPU resources, making "hg push" and "hg pull" slower
115
116
117 performing an upgrade with "--run" will make the following changes:
118
119 requirements
120 preserved: revlogv1, store
121 added: dotencode, fncache, generaldelta
122
123 fncache
124 repository will be more resilient to storing certain paths and performance of certain operations should be improved
125
126 dotencode
127 repository will be better able to store files beginning with a space or period
128
129 generaldelta
130 repository storage will be able to create optimal deltas; new repository data will be smaller and read times should decrease; interacting with other repositories using this storage model should require less network and CPU resources, making "hg push" and "hg pull" faster
131
132 additional optimizations are available by specifying "--optimize <name>":
133
134 redeltaparent
135 deltas within internal storage will be recalculated to choose an optimal base revision where this was not already done; the size of the repository may shrink and various operations may become faster; the first time this optimization is performed could slow down upgrade execution considerably; subsequent invocations should not run noticeably slower
136
137 redeltamultibase
138 deltas within internal storage will be recalculated against multiple base revision and the smallest difference will be used; the size of the repository may shrink significantly when there are many merges; this optimization will slow down execution in proportion to the number of merges in the repository and the amount of files in the repository; this slow down should not be significant unless there are tens of thousands of files and thousands of merges
139
140 redeltaall
141 deltas within internal storage will always be recalculated without reusing prior deltas; this will likely make execution run several times slower; this optimization is typically not needed
142
143
144 $ hg --config format.dotencode=false debugupgraderepo
145 repository lacks features recommended by current config options:
146
147 fncache
148 long and reserved filenames may not work correctly; repository performance is sub-optimal
149
150 generaldelta
151 deltas within internal storage are unable to choose optimal revisions; repository is larger and slower than it could be; interaction with other repositories may require extra network and CPU resources, making "hg push" and "hg pull" slower
152
153 repository lacks features used by the default config options:
154
155 dotencode
156 storage of filenames beginning with a period or space may not work correctly
157
158
159 performing an upgrade with "--run" will make the following changes:
160
161 requirements
162 preserved: revlogv1, store
163 added: fncache, generaldelta
164
165 fncache
166 repository will be more resilient to storing certain paths and performance of certain operations should be improved
167
168 generaldelta
169 repository storage will be able to create optimal deltas; new repository data will be smaller and read times should decrease; interacting with other repositories using this storage model should require less network and CPU resources, making "hg push" and "hg pull" faster
170
171 additional optimizations are available by specifying "--optimize <name>":
172
173 redeltaparent
174 deltas within internal storage will be recalculated to choose an optimal base revision where this was not already done; the size of the repository may shrink and various operations may become faster; the first time this optimization is performed could slow down upgrade execution considerably; subsequent invocations should not run noticeably slower
175
176 redeltamultibase
177 deltas within internal storage will be recalculated against multiple base revision and the smallest difference will be used; the size of the repository may shrink significantly when there are many merges; this optimization will slow down execution in proportion to the number of merges in the repository and the amount of files in the repository; this slow down should not be significant unless there are tens of thousands of files and thousands of merges
178
179 redeltaall
180 deltas within internal storage will always be recalculated without reusing prior deltas; this will likely make execution run several times slower; this optimization is typically not needed
181
182
General Comments 0
You need to be logged in to leave comments. Login now