diff mercurial/upgrade_utils/actions.py @ 47320:a43d256c041a

dirstate-v2: Add `hg debugupgraderepo` command support This command changes changes the file formats used inside an existing repository to what they would be in a new repository with the current config. For example: hg debugupgraderepo --config format.exp-dirstate-v2=1 --run hg debugupgraderepo --config format.exp-dirstate-v2=0 --run If a repository has a dirstate in v1 format, the first command would upgrade it to dirstate-v2. Conversely, if a repository has a dirstate in v2 format, the second command would downgrade it to v1. (Both may also run some unrelated upgrades.) Since `format.exp-dirstate-v2` is currently disabled by default, not specifying it in `--config` or any configuration file would result in the second command. Differential Revision: https://phab.mercurial-scm.org/D10769
author Simon Sapin <simon.sapin@octobus.net>
date Wed, 19 May 2021 18:35:43 +0200
parents e985a36c2aa3
children 4259a72fe528
line wrap: on
line diff
--- a/mercurial/upgrade_utils/actions.py	Fri May 21 17:12:47 2021 +0200
+++ b/mercurial/upgrade_utils/actions.py	Wed May 19 18:35:43 2021 +0200
@@ -80,7 +80,7 @@
     # operation in which this improvement was removed
     postdowngrademessage = None
 
-    # By default for now, we assume every improvement touches all the things
+    # By default we assume that every improvement touches requirements and all revlogs
 
     # Whether this improvement touches filelogs
     touches_filelogs = True
@@ -94,6 +94,9 @@
     # Whether this improvement changes repository requirements
     touches_requirements = True
 
+    # Whether this improvement touches the dirstate
+    touches_dirstate = False
+
 
 allformatvariant = []  # type: List[Type['formatvariant']]
 
@@ -167,6 +170,27 @@
 
 
 @registerformatvariant
+class dirstatev2(requirementformatvariant):
+    name = b'dirstate-v2'
+    _requirement = requirements.DIRSTATE_V2_REQUIREMENT
+
+    default = False
+
+    description = _(
+        b'version 1 of the dirstate file format requires '
+        b'reading and parsing it all at once.'
+    )
+
+    upgrademessage = _(b'"hg status" will be faster')
+
+    touches_filelogs = False
+    touches_manifests = False
+    touches_changelog = False
+    touches_requirements = True
+    touches_dirstate = True
+
+
+@registerformatvariant
 class dotencode(requirementformatvariant):
     name = b'dotencode'
 
@@ -644,7 +668,6 @@
         self.current_requirements = current_requirements
         # list of upgrade actions the operation will perform
         self.upgrade_actions = upgrade_actions
-        self._upgrade_actions_names = set([a.name for a in upgrade_actions])
         self.removed_actions = removed_actions
         self.revlogs_to_process = revlogs_to_process
         # requirements which will be added by the operation
@@ -667,41 +690,42 @@
         ]
 
         # delta reuse mode of this upgrade operation
+        upgrade_actions_names = self.upgrade_actions_names
         self.delta_reuse_mode = revlog.revlog.DELTAREUSEALWAYS
-        if b're-delta-all' in self._upgrade_actions_names:
+        if b're-delta-all' in upgrade_actions_names:
             self.delta_reuse_mode = revlog.revlog.DELTAREUSENEVER
-        elif b're-delta-parent' in self._upgrade_actions_names:
+        elif b're-delta-parent' in upgrade_actions_names:
             self.delta_reuse_mode = revlog.revlog.DELTAREUSESAMEREVS
-        elif b're-delta-multibase' in self._upgrade_actions_names:
+        elif b're-delta-multibase' in upgrade_actions_names:
             self.delta_reuse_mode = revlog.revlog.DELTAREUSESAMEREVS
-        elif b're-delta-fulladd' in self._upgrade_actions_names:
+        elif b're-delta-fulladd' in upgrade_actions_names:
             self.delta_reuse_mode = revlog.revlog.DELTAREUSEFULLADD
 
         # should this operation force re-delta of both parents
         self.force_re_delta_both_parents = (
-            b're-delta-multibase' in self._upgrade_actions_names
+            b're-delta-multibase' in upgrade_actions_names
         )
 
         # should this operation create a backup of the store
         self.backup_store = backup_store
 
-        # whether the operation touches different revlogs at all or not
-        self.touches_filelogs = self._touches_filelogs()
-        self.touches_manifests = self._touches_manifests()
-        self.touches_changelog = self._touches_changelog()
-        # whether the operation touches requirements file or not
-        self.touches_requirements = self._touches_requirements()
-        self.touches_store = (
-            self.touches_filelogs
-            or self.touches_manifests
-            or self.touches_changelog
-        )
+    @property
+    def upgrade_actions_names(self):
+        return set([a.name for a in self.upgrade_actions])
+
+    @property
+    def requirements_only(self):
         # does the operation only touches repository requirement
-        self.requirements_only = (
-            self.touches_requirements and not self.touches_store
+        return (
+            self.touches_requirements
+            and not self.touches_filelogs
+            and not self.touches_manifests
+            and not self.touches_changelog
+            and not self.touches_dirstate
         )
 
-    def _touches_filelogs(self):
+    @property
+    def touches_filelogs(self):
         for a in self.upgrade_actions:
             # in optimisations, we re-process the revlogs again
             if a.type == OPTIMISATION:
@@ -713,7 +737,8 @@
                 return True
         return False
 
-    def _touches_manifests(self):
+    @property
+    def touches_manifests(self):
         for a in self.upgrade_actions:
             # in optimisations, we re-process the revlogs again
             if a.type == OPTIMISATION:
@@ -725,7 +750,8 @@
                 return True
         return False
 
-    def _touches_changelog(self):
+    @property
+    def touches_changelog(self):
         for a in self.upgrade_actions:
             # in optimisations, we re-process the revlogs again
             if a.type == OPTIMISATION:
@@ -737,7 +763,8 @@
                 return True
         return False
 
-    def _touches_requirements(self):
+    @property
+    def touches_requirements(self):
         for a in self.upgrade_actions:
             # optimisations are used to re-process revlogs and does not result
             # in a requirement being added or removed
@@ -749,6 +776,18 @@
             if a.touches_requirements:
                 return True
 
+    @property
+    def touches_dirstate(self):
+        for a in self.upgrade_actions:
+            # revlog optimisations do not affect the dirstate
+            if a.type == OPTIMISATION:
+                pass
+            elif a.touches_dirstate:
+                return True
+        for a in self.removed_actions:
+            if a.touches_dirstate:
+                return True
+
         return False
 
     def _write_labeled(self, l, label):
@@ -908,6 +947,7 @@
         requirements.REVLOGV2_REQUIREMENT,
         requirements.CHANGELOGV2_REQUIREMENT,
         requirements.REVLOGV1_REQUIREMENT,
+        requirements.DIRSTATE_V2_REQUIREMENT,
     }
     for name in compression.compengines:
         engine = compression.compengines[name]
@@ -970,6 +1010,7 @@
         requirements.REVLOGV1_REQUIREMENT,
         requirements.REVLOGV2_REQUIREMENT,
         requirements.CHANGELOGV2_REQUIREMENT,
+        requirements.DIRSTATE_V2_REQUIREMENT,
     }
     for name in compression.compengines:
         engine = compression.compengines[name]