Show More
@@ -11,15 +11,19 b' from __future__ import absolute_import' | |||
|
11 | 11 | import errno |
|
12 | 12 | import hashlib |
|
13 | 13 | import tempfile |
|
14 | import time | |
|
14 | 15 | |
|
15 | 16 | from .i18n import _ |
|
16 | 17 | from .node import short |
|
17 | 18 | from . import ( |
|
18 | 19 | bundle2, |
|
19 | 20 | changegroup, |
|
21 | changelog, | |
|
20 | 22 | error, |
|
21 | 23 | exchange, |
|
24 | manifest, | |
|
22 | 25 | obsolete, |
|
26 | revlog, | |
|
23 | 27 | scmutil, |
|
24 | 28 | util, |
|
25 | 29 | ) |
@@ -639,6 +643,162 b' def upgradedetermineactions(repo, improv' | |||
|
639 | 643 | |
|
640 | 644 | return newactions |
|
641 | 645 | |
|
646 | def _revlogfrompath(repo, path): | |
|
647 | """Obtain a revlog from a repo path. | |
|
648 | ||
|
649 | An instance of the appropriate class is returned. | |
|
650 | """ | |
|
651 | if path == '00changelog.i': | |
|
652 | return changelog.changelog(repo.svfs) | |
|
653 | elif path.endswith('00manifest.i'): | |
|
654 | mandir = path[:-len('00manifest.i')] | |
|
655 | return manifest.manifestrevlog(repo.svfs, dir=mandir) | |
|
656 | else: | |
|
657 | # Filelogs don't do anything special with settings. So we can use a | |
|
658 | # vanilla revlog. | |
|
659 | return revlog.revlog(repo.svfs, path) | |
|
660 | ||
|
661 | def _copyrevlogs(ui, srcrepo, dstrepo, tr, deltareuse, aggressivemergedeltas): | |
|
662 | """Copy revlogs between 2 repos.""" | |
|
663 | revcount = 0 | |
|
664 | srcsize = 0 | |
|
665 | srcrawsize = 0 | |
|
666 | dstsize = 0 | |
|
667 | fcount = 0 | |
|
668 | frevcount = 0 | |
|
669 | fsrcsize = 0 | |
|
670 | frawsize = 0 | |
|
671 | fdstsize = 0 | |
|
672 | mcount = 0 | |
|
673 | mrevcount = 0 | |
|
674 | msrcsize = 0 | |
|
675 | mrawsize = 0 | |
|
676 | mdstsize = 0 | |
|
677 | crevcount = 0 | |
|
678 | csrcsize = 0 | |
|
679 | crawsize = 0 | |
|
680 | cdstsize = 0 | |
|
681 | ||
|
682 | # Perform a pass to collect metadata. This validates we can open all | |
|
683 | # source files and allows a unified progress bar to be displayed. | |
|
684 | for unencoded, encoded, size in srcrepo.store.walk(): | |
|
685 | if unencoded.endswith('.d'): | |
|
686 | continue | |
|
687 | ||
|
688 | rl = _revlogfrompath(srcrepo, unencoded) | |
|
689 | revcount += len(rl) | |
|
690 | ||
|
691 | datasize = 0 | |
|
692 | rawsize = 0 | |
|
693 | idx = rl.index | |
|
694 | for rev in rl: | |
|
695 | e = idx[rev] | |
|
696 | datasize += e[1] | |
|
697 | rawsize += e[2] | |
|
698 | ||
|
699 | srcsize += datasize | |
|
700 | srcrawsize += rawsize | |
|
701 | ||
|
702 | # This is for the separate progress bars. | |
|
703 | if isinstance(rl, changelog.changelog): | |
|
704 | crevcount += len(rl) | |
|
705 | csrcsize += datasize | |
|
706 | crawsize += rawsize | |
|
707 | elif isinstance(rl, manifest.manifestrevlog): | |
|
708 | mcount += 1 | |
|
709 | mrevcount += len(rl) | |
|
710 | msrcsize += datasize | |
|
711 | mrawsize += rawsize | |
|
712 | elif isinstance(rl, revlog.revlog): | |
|
713 | fcount += 1 | |
|
714 | frevcount += len(rl) | |
|
715 | fsrcsize += datasize | |
|
716 | frawsize += rawsize | |
|
717 | ||
|
718 | if not revcount: | |
|
719 | return | |
|
720 | ||
|
721 | ui.write(_('migrating %d total revisions (%d in filelogs, %d in manifests, ' | |
|
722 | '%d in changelog)\n') % | |
|
723 | (revcount, frevcount, mrevcount, crevcount)) | |
|
724 | ui.write(_('migrating %s in store; %s tracked data\n') % ( | |
|
725 | (util.bytecount(srcsize), util.bytecount(srcrawsize)))) | |
|
726 | ||
|
727 | # Used to keep track of progress. | |
|
728 | progress = [] | |
|
729 | def oncopiedrevision(rl, rev, node): | |
|
730 | progress[1] += 1 | |
|
731 | srcrepo.ui.progress(progress[0], progress[1], total=progress[2]) | |
|
732 | ||
|
733 | # Do the actual copying. | |
|
734 | # FUTURE this operation can be farmed off to worker processes. | |
|
735 | seen = set() | |
|
736 | for unencoded, encoded, size in srcrepo.store.walk(): | |
|
737 | if unencoded.endswith('.d'): | |
|
738 | continue | |
|
739 | ||
|
740 | oldrl = _revlogfrompath(srcrepo, unencoded) | |
|
741 | newrl = _revlogfrompath(dstrepo, unencoded) | |
|
742 | ||
|
743 | if isinstance(oldrl, changelog.changelog) and 'c' not in seen: | |
|
744 | ui.write(_('finished migrating %d manifest revisions across %d ' | |
|
745 | 'manifests; change in size: %s\n') % | |
|
746 | (mrevcount, mcount, util.bytecount(mdstsize - msrcsize))) | |
|
747 | ||
|
748 | ui.write(_('migrating changelog containing %d revisions ' | |
|
749 | '(%s in store; %s tracked data)\n') % | |
|
750 | (crevcount, util.bytecount(csrcsize), | |
|
751 | util.bytecount(crawsize))) | |
|
752 | seen.add('c') | |
|
753 | progress[:] = [_('changelog revisions'), 0, crevcount] | |
|
754 | elif isinstance(oldrl, manifest.manifestrevlog) and 'm' not in seen: | |
|
755 | ui.write(_('finished migrating %d filelog revisions across %d ' | |
|
756 | 'filelogs; change in size: %s\n') % | |
|
757 | (frevcount, fcount, util.bytecount(fdstsize - fsrcsize))) | |
|
758 | ||
|
759 | ui.write(_('migrating %d manifests containing %d revisions ' | |
|
760 | '(%s in store; %s tracked data)\n') % | |
|
761 | (mcount, mrevcount, util.bytecount(msrcsize), | |
|
762 | util.bytecount(mrawsize))) | |
|
763 | seen.add('m') | |
|
764 | progress[:] = [_('manifest revisions'), 0, mrevcount] | |
|
765 | elif 'f' not in seen: | |
|
766 | ui.write(_('migrating %d filelogs containing %d revisions ' | |
|
767 | '(%s in store; %s tracked data)\n') % | |
|
768 | (fcount, frevcount, util.bytecount(fsrcsize), | |
|
769 | util.bytecount(frawsize))) | |
|
770 | seen.add('f') | |
|
771 | progress[:] = [_('file revisions'), 0, frevcount] | |
|
772 | ||
|
773 | ui.progress(progress[0], progress[1], total=progress[2]) | |
|
774 | ||
|
775 | ui.note(_('cloning %d revisions from %s\n') % (len(oldrl), unencoded)) | |
|
776 | oldrl.clone(tr, newrl, addrevisioncb=oncopiedrevision, | |
|
777 | deltareuse=deltareuse, | |
|
778 | aggressivemergedeltas=aggressivemergedeltas) | |
|
779 | ||
|
780 | datasize = 0 | |
|
781 | idx = newrl.index | |
|
782 | for rev in newrl: | |
|
783 | datasize += idx[rev][1] | |
|
784 | ||
|
785 | dstsize += datasize | |
|
786 | ||
|
787 | if isinstance(newrl, changelog.changelog): | |
|
788 | cdstsize += datasize | |
|
789 | elif isinstance(newrl, manifest.manifestrevlog): | |
|
790 | mdstsize += datasize | |
|
791 | else: | |
|
792 | fdstsize += datasize | |
|
793 | ||
|
794 | ui.progress(progress[0], None) | |
|
795 | ||
|
796 | ui.write(_('finished migrating %d changelog revisions; change in size: ' | |
|
797 | '%s\n') % (crevcount, util.bytecount(cdstsize - csrcsize))) | |
|
798 | ||
|
799 | ui.write(_('finished migrating %d total revisions; total change in store ' | |
|
800 | 'size: %s\n') % (revcount, util.bytecount(dstsize - srcsize))) | |
|
801 | ||
|
642 | 802 | def _upgraderepo(ui, srcrepo, dstrepo, requirements, actions): |
|
643 | 803 | """Do the low-level work of upgrading a repository. |
|
644 | 804 | |
@@ -652,7 +812,25 b' def _upgraderepo(ui, srcrepo, dstrepo, r' | |||
|
652 | 812 | assert srcrepo.currentwlock() |
|
653 | 813 | assert dstrepo.currentwlock() |
|
654 | 814 | |
|
655 | # TODO copy store | |
|
815 | ui.write(_('(it is safe to interrupt this process any time before ' | |
|
816 | 'data migration completes)\n')) | |
|
817 | ||
|
818 | if 'redeltaall' in actions: | |
|
819 | deltareuse = revlog.revlog.DELTAREUSENEVER | |
|
820 | elif 'redeltaparent' in actions: | |
|
821 | deltareuse = revlog.revlog.DELTAREUSESAMEREVS | |
|
822 | elif 'redeltamultibase' in actions: | |
|
823 | deltareuse = revlog.revlog.DELTAREUSESAMEREVS | |
|
824 | else: | |
|
825 | deltareuse = revlog.revlog.DELTAREUSEALWAYS | |
|
826 | ||
|
827 | with dstrepo.transaction('upgrade') as tr: | |
|
828 | _copyrevlogs(ui, srcrepo, dstrepo, tr, deltareuse, | |
|
829 | 'redeltamultibase' in actions) | |
|
830 | ||
|
831 | # TODO copy non-revlog store files | |
|
832 | ||
|
833 | ui.write(_('data fully migrated to temporary repository\n')) | |
|
656 | 834 | |
|
657 | 835 | backuppath = tempfile.mkdtemp(prefix='upgradebackup.', dir=srcrepo.path) |
|
658 | 836 | backupvfs = scmutil.vfs(backuppath) |
@@ -673,7 +851,16 b' def _upgraderepo(ui, srcrepo, dstrepo, r' | |||
|
673 | 851 | ui.write(_('replaced files will be backed up at %s\n') % |
|
674 | 852 | backuppath) |
|
675 | 853 | |
|
676 | # TODO do the store swap here. | |
|
854 | # Now swap in the new store directory. Doing it as a rename should make | |
|
855 | # the operation nearly instantaneous and atomic (at least in well-behaved | |
|
856 | # environments). | |
|
857 | ui.write(_('replacing store...\n')) | |
|
858 | tstart = time.time() | |
|
859 | util.rename(srcrepo.spath, backupvfs.join('store')) | |
|
860 | util.rename(dstrepo.spath, srcrepo.spath) | |
|
861 | elapsed = time.time() - tstart | |
|
862 | ui.write(_('store replacement complete; repository was inconsistent for ' | |
|
863 | '%0.1fs\n') % elapsed) | |
|
677 | 864 | |
|
678 | 865 | # We first write the requirements file. Any new requirements will lock |
|
679 | 866 | # out legacy clients. |
@@ -194,9 +194,13 b' Upgrading a repository that is already m' | |||
|
194 | 194 | beginning upgrade... |
|
195 | 195 | repository locked and read-only |
|
196 | 196 | creating temporary repository to stage migrated data: $TESTTMP/modern/.hg/upgrade.* (glob) |
|
197 | (it is safe to interrupt this process any time before data migration completes) | |
|
198 | data fully migrated to temporary repository | |
|
197 | 199 | marking source repository as being upgraded; clients will be unable to read from repository |
|
198 | 200 | starting in-place swap of repository data |
|
199 | 201 | replaced files will be backed up at $TESTTMP/modern/.hg/upgradebackup.* (glob) |
|
202 | replacing store... | |
|
203 | store replacement complete; repository was inconsistent for *s (glob) | |
|
200 | 204 | finalizing requirements file and making repository readable again |
|
201 | 205 | removing temporary repository $TESTTMP/modern/.hg/upgrade.* (glob) |
|
202 | 206 | copy of old repository backed up at $TESTTMP/modern/.hg/upgradebackup.* (glob) |
@@ -227,9 +231,22 b' Upgrading a repository to generaldelta w' | |||
|
227 | 231 | beginning upgrade... |
|
228 | 232 | repository locked and read-only |
|
229 | 233 | creating temporary repository to stage migrated data: $TESTTMP/upgradegd/.hg/upgrade.* (glob) |
|
234 | (it is safe to interrupt this process any time before data migration completes) | |
|
235 | migrating 9 total revisions (3 in filelogs, 3 in manifests, 3 in changelog) | |
|
236 | migrating 341 bytes in store; 401 bytes tracked data | |
|
237 | migrating 3 filelogs containing 3 revisions (0 bytes in store; 0 bytes tracked data) | |
|
238 | finished migrating 3 filelog revisions across 3 filelogs; change in size: 0 bytes | |
|
239 | migrating 1 manifests containing 3 revisions (157 bytes in store; 220 bytes tracked data) | |
|
240 | finished migrating 3 manifest revisions across 1 manifests; change in size: 0 bytes | |
|
241 | migrating changelog containing 3 revisions (184 bytes in store; 181 bytes tracked data) | |
|
242 | finished migrating 3 changelog revisions; change in size: 0 bytes | |
|
243 | finished migrating 9 total revisions; total change in store size: 0 bytes | |
|
244 | data fully migrated to temporary repository | |
|
230 | 245 | marking source repository as being upgraded; clients will be unable to read from repository |
|
231 | 246 | starting in-place swap of repository data |
|
232 | 247 | replaced files will be backed up at $TESTTMP/upgradegd/.hg/upgradebackup.* (glob) |
|
248 | replacing store... | |
|
249 | store replacement complete; repository was inconsistent for *s (glob) | |
|
233 | 250 | finalizing requirements file and making repository readable again |
|
234 | 251 | removing temporary repository $TESTTMP/upgradegd/.hg/upgrade.* (glob) |
|
235 | 252 | copy of old repository backed up at $TESTTMP/upgradegd/.hg/upgradebackup.* (glob) |
@@ -252,4 +269,43 b' generaldelta added to original requireme' | |||
|
252 | 269 | revlogv1 |
|
253 | 270 | store |
|
254 | 271 | |
|
272 | store directory has files we expect | |
|
273 | ||
|
274 | $ ls .hg/store | |
|
275 | 00changelog.i | |
|
276 | 00manifest.i | |
|
277 | data | |
|
278 | fncache | |
|
279 | undo | |
|
280 | undo.backupfiles | |
|
281 | undo.phaseroots | |
|
282 | ||
|
283 | manifest should be generaldelta | |
|
284 | ||
|
285 | $ hg debugrevlog -m | grep flags | |
|
286 | flags : inline, generaldelta | |
|
287 | ||
|
288 | verify should be happy | |
|
289 | ||
|
290 | $ hg verify | |
|
291 | checking changesets | |
|
292 | checking manifests | |
|
293 | crosschecking files in changesets and manifests | |
|
294 | checking files | |
|
295 | 3 files, 3 changesets, 3 total revisions | |
|
296 | ||
|
297 | old store should be backed up | |
|
298 | ||
|
299 | $ ls .hg/upgradebackup.*/store | |
|
300 | 00changelog.i | |
|
301 | 00manifest.i | |
|
302 | data | |
|
303 | fncache | |
|
304 | lock | |
|
305 | phaseroots | |
|
306 | undo | |
|
307 | undo.backup.fncache | |
|
308 | undo.backupfiles | |
|
309 | undo.phaseroots | |
|
310 | ||
|
255 | 311 | $ cd .. |
General Comments 0
You need to be logged in to leave comments.
Login now