Show More
@@ -10,6 +10,7 b' from __future__ import absolute_import' | |||
|
10 | 10 | |
|
11 | 11 | import errno |
|
12 | 12 | import hashlib |
|
13 | import tempfile | |
|
13 | 14 | |
|
14 | 15 | from .i18n import _ |
|
15 | 16 | from .node import short |
@@ -19,6 +20,7 b' from . import (' | |||
|
19 | 20 | error, |
|
20 | 21 | exchange, |
|
21 | 22 | obsolete, |
|
23 | scmutil, | |
|
22 | 24 | util, |
|
23 | 25 | ) |
|
24 | 26 | |
@@ -637,6 +639,50 b' def upgradedetermineactions(repo, improv' | |||
|
637 | 639 | |
|
638 | 640 | return newactions |
|
639 | 641 | |
|
642 | def _upgraderepo(ui, srcrepo, dstrepo, requirements, actions): | |
|
643 | """Do the low-level work of upgrading a repository. | |
|
644 | ||
|
645 | The upgrade is effectively performed as a copy between a source | |
|
646 | repository and a temporary destination repository. | |
|
647 | ||
|
648 | The source repository is unmodified for as long as possible so the | |
|
649 | upgrade can abort at any time without causing loss of service for | |
|
650 | readers and without corrupting the source repository. | |
|
651 | """ | |
|
652 | assert srcrepo.currentwlock() | |
|
653 | assert dstrepo.currentwlock() | |
|
654 | ||
|
655 | # TODO copy store | |
|
656 | ||
|
657 | backuppath = tempfile.mkdtemp(prefix='upgradebackup.', dir=srcrepo.path) | |
|
658 | backupvfs = scmutil.vfs(backuppath) | |
|
659 | ||
|
660 | # Make a backup of requires file first, as it is the first to be modified. | |
|
661 | util.copyfile(srcrepo.join('requires'), backupvfs.join('requires')) | |
|
662 | ||
|
663 | # We install an arbitrary requirement that clients must not support | |
|
664 | # as a mechanism to lock out new clients during the data swap. This is | |
|
665 | # better than allowing a client to continue while the repository is in | |
|
666 | # an inconsistent state. | |
|
667 | ui.write(_('marking source repository as being upgraded; clients will be ' | |
|
668 | 'unable to read from repository\n')) | |
|
669 | scmutil.writerequires(srcrepo.vfs, | |
|
670 | srcrepo.requirements | set(['upgradeinprogress'])) | |
|
671 | ||
|
672 | ui.write(_('starting in-place swap of repository data\n')) | |
|
673 | ui.write(_('replaced files will be backed up at %s\n') % | |
|
674 | backuppath) | |
|
675 | ||
|
676 | # TODO do the store swap here. | |
|
677 | ||
|
678 | # We first write the requirements file. Any new requirements will lock | |
|
679 | # out legacy clients. | |
|
680 | ui.write(_('finalizing requirements file and making repository readable ' | |
|
681 | 'again\n')) | |
|
682 | scmutil.writerequires(srcrepo.vfs, requirements) | |
|
683 | ||
|
684 | return backuppath | |
|
685 | ||
|
640 | 686 | def upgraderepo(ui, repo, run=False, optimize=None): |
|
641 | 687 | """Upgrade a repository in place.""" |
|
642 | 688 | # Avoid cycle: cmdutil -> repair -> localrepo -> cmdutil |
@@ -771,3 +817,43 b' def upgraderepo(ui, repo, run=False, opt' | |||
|
771 | 817 | '"--optimize <name>":\n\n')) |
|
772 | 818 | for i in unusedoptimize: |
|
773 | 819 | ui.write(_('%s\n %s\n\n') % (i.name, i.description)) |
|
820 | return | |
|
821 | ||
|
822 | # Else we're in the run=true case. | |
|
823 | ui.write(_('upgrade will perform the following actions:\n\n')) | |
|
824 | printrequirements() | |
|
825 | printupgradeactions() | |
|
826 | ||
|
827 | ui.write(_('beginning upgrade...\n')) | |
|
828 | with repo.wlock(): | |
|
829 | with repo.lock(): | |
|
830 | ui.write(_('repository locked and read-only\n')) | |
|
831 | # Our strategy for upgrading the repository is to create a new, | |
|
832 | # temporary repository, write data to it, then do a swap of the | |
|
833 | # data. There are less heavyweight ways to do this, but it is easier | |
|
834 | # to create a new repo object than to instantiate all the components | |
|
835 | # (like the store) separately. | |
|
836 | tmppath = tempfile.mkdtemp(prefix='upgrade.', dir=repo.path) | |
|
837 | backuppath = None | |
|
838 | try: | |
|
839 | ui.write(_('creating temporary repository to stage migrated ' | |
|
840 | 'data: %s\n') % tmppath) | |
|
841 | dstrepo = localrepo.localrepository(repo.baseui, | |
|
842 | path=tmppath, | |
|
843 | create=True) | |
|
844 | ||
|
845 | with dstrepo.wlock(): | |
|
846 | with dstrepo.lock(): | |
|
847 | backuppath = _upgraderepo(ui, repo, dstrepo, newreqs, | |
|
848 | actions) | |
|
849 | ||
|
850 | finally: | |
|
851 | ui.write(_('removing temporary repository %s\n') % tmppath) | |
|
852 | repo.vfs.rmtree(tmppath, forcibly=True) | |
|
853 | ||
|
854 | if backuppath: | |
|
855 | ui.warn(_('copy of old repository backed up at %s\n') % | |
|
856 | backuppath) | |
|
857 | ui.warn(_('the old repository will not be deleted; remove ' | |
|
858 | 'it to free up disk space once the upgraded ' | |
|
859 | 'repository is verified\n')) |
@@ -180,3 +180,76 b' Various sub-optimal detections work' | |||
|
180 | 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 | 181 | |
|
182 | 182 | |
|
183 | $ cd .. | |
|
184 | ||
|
185 | Upgrading a repository that is already modern essentially no-ops | |
|
186 | ||
|
187 | $ hg init modern | |
|
188 | $ hg -R modern debugupgraderepo --run | |
|
189 | upgrade will perform the following actions: | |
|
190 | ||
|
191 | requirements | |
|
192 | preserved: dotencode, fncache, generaldelta, revlogv1, store | |
|
193 | ||
|
194 | beginning upgrade... | |
|
195 | repository locked and read-only | |
|
196 | creating temporary repository to stage migrated data: $TESTTMP/modern/.hg/upgrade.* (glob) | |
|
197 | marking source repository as being upgraded; clients will be unable to read from repository | |
|
198 | starting in-place swap of repository data | |
|
199 | replaced files will be backed up at $TESTTMP/modern/.hg/upgradebackup.* (glob) | |
|
200 | finalizing requirements file and making repository readable again | |
|
201 | removing temporary repository $TESTTMP/modern/.hg/upgrade.* (glob) | |
|
202 | copy of old repository backed up at $TESTTMP/modern/.hg/upgradebackup.* (glob) | |
|
203 | the old repository will not be deleted; remove it to free up disk space once the upgraded repository is verified | |
|
204 | ||
|
205 | Upgrading a repository to generaldelta works | |
|
206 | ||
|
207 | $ hg --config format.usegeneraldelta=false init upgradegd | |
|
208 | $ cd upgradegd | |
|
209 | $ touch f0 | |
|
210 | $ hg -q commit -A -m initial | |
|
211 | $ touch f1 | |
|
212 | $ hg -q commit -A -m 'add f1' | |
|
213 | $ hg -q up -r 0 | |
|
214 | $ touch f2 | |
|
215 | $ hg -q commit -A -m 'add f2' | |
|
216 | ||
|
217 | $ hg debugupgraderepo --run | |
|
218 | upgrade will perform the following actions: | |
|
219 | ||
|
220 | requirements | |
|
221 | preserved: dotencode, fncache, revlogv1, store | |
|
222 | added: generaldelta | |
|
223 | ||
|
224 | generaldelta | |
|
225 | 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 | |
|
226 | ||
|
227 | beginning upgrade... | |
|
228 | repository locked and read-only | |
|
229 | creating temporary repository to stage migrated data: $TESTTMP/upgradegd/.hg/upgrade.* (glob) | |
|
230 | marking source repository as being upgraded; clients will be unable to read from repository | |
|
231 | starting in-place swap of repository data | |
|
232 | replaced files will be backed up at $TESTTMP/upgradegd/.hg/upgradebackup.* (glob) | |
|
233 | finalizing requirements file and making repository readable again | |
|
234 | removing temporary repository $TESTTMP/upgradegd/.hg/upgrade.* (glob) | |
|
235 | copy of old repository backed up at $TESTTMP/upgradegd/.hg/upgradebackup.* (glob) | |
|
236 | the old repository will not be deleted; remove it to free up disk space once the upgraded repository is verified | |
|
237 | ||
|
238 | Original requirements backed up | |
|
239 | ||
|
240 | $ cat .hg/upgradebackup.*/requires | |
|
241 | dotencode | |
|
242 | fncache | |
|
243 | revlogv1 | |
|
244 | store | |
|
245 | ||
|
246 | generaldelta added to original requirements files | |
|
247 | ||
|
248 | $ cat .hg/requires | |
|
249 | dotencode | |
|
250 | fncache | |
|
251 | generaldelta | |
|
252 | revlogv1 | |
|
253 | store | |
|
254 | ||
|
255 | $ cd .. |
General Comments 0
You need to be logged in to leave comments.
Login now