##// END OF EJS Templates
repair: migrate revlogs during upgrade...
Gregory Szorc -
r30779:38aa1ca9 default
parent child Browse files
Show More
@@ -11,15 +11,19 b' from __future__ import absolute_import'
11 import errno
11 import errno
12 import hashlib
12 import hashlib
13 import tempfile
13 import tempfile
14 import time
14
15
15 from .i18n import _
16 from .i18n import _
16 from .node import short
17 from .node import short
17 from . import (
18 from . import (
18 bundle2,
19 bundle2,
19 changegroup,
20 changegroup,
21 changelog,
20 error,
22 error,
21 exchange,
23 exchange,
24 manifest,
22 obsolete,
25 obsolete,
26 revlog,
23 scmutil,
27 scmutil,
24 util,
28 util,
25 )
29 )
@@ -639,6 +643,162 b' def upgradedetermineactions(repo, improv'
639
643
640 return newactions
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 def _upgraderepo(ui, srcrepo, dstrepo, requirements, actions):
802 def _upgraderepo(ui, srcrepo, dstrepo, requirements, actions):
643 """Do the low-level work of upgrading a repository.
803 """Do the low-level work of upgrading a repository.
644
804
@@ -652,7 +812,25 b' def _upgraderepo(ui, srcrepo, dstrepo, r'
652 assert srcrepo.currentwlock()
812 assert srcrepo.currentwlock()
653 assert dstrepo.currentwlock()
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 backuppath = tempfile.mkdtemp(prefix='upgradebackup.', dir=srcrepo.path)
835 backuppath = tempfile.mkdtemp(prefix='upgradebackup.', dir=srcrepo.path)
658 backupvfs = scmutil.vfs(backuppath)
836 backupvfs = scmutil.vfs(backuppath)
@@ -673,7 +851,16 b' def _upgraderepo(ui, srcrepo, dstrepo, r'
673 ui.write(_('replaced files will be backed up at %s\n') %
851 ui.write(_('replaced files will be backed up at %s\n') %
674 backuppath)
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 # We first write the requirements file. Any new requirements will lock
865 # We first write the requirements file. Any new requirements will lock
679 # out legacy clients.
866 # out legacy clients.
@@ -194,9 +194,13 b' Upgrading a repository that is already m'
194 beginning upgrade...
194 beginning upgrade...
195 repository locked and read-only
195 repository locked and read-only
196 creating temporary repository to stage migrated data: $TESTTMP/modern/.hg/upgrade.* (glob)
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 marking source repository as being upgraded; clients will be unable to read from repository
199 marking source repository as being upgraded; clients will be unable to read from repository
198 starting in-place swap of repository data
200 starting in-place swap of repository data
199 replaced files will be backed up at $TESTTMP/modern/.hg/upgradebackup.* (glob)
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 finalizing requirements file and making repository readable again
204 finalizing requirements file and making repository readable again
201 removing temporary repository $TESTTMP/modern/.hg/upgrade.* (glob)
205 removing temporary repository $TESTTMP/modern/.hg/upgrade.* (glob)
202 copy of old repository backed up at $TESTTMP/modern/.hg/upgradebackup.* (glob)
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 beginning upgrade...
231 beginning upgrade...
228 repository locked and read-only
232 repository locked and read-only
229 creating temporary repository to stage migrated data: $TESTTMP/upgradegd/.hg/upgrade.* (glob)
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 marking source repository as being upgraded; clients will be unable to read from repository
245 marking source repository as being upgraded; clients will be unable to read from repository
231 starting in-place swap of repository data
246 starting in-place swap of repository data
232 replaced files will be backed up at $TESTTMP/upgradegd/.hg/upgradebackup.* (glob)
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 finalizing requirements file and making repository readable again
250 finalizing requirements file and making repository readable again
234 removing temporary repository $TESTTMP/upgradegd/.hg/upgrade.* (glob)
251 removing temporary repository $TESTTMP/upgradegd/.hg/upgrade.* (glob)
235 copy of old repository backed up at $TESTTMP/upgradegd/.hg/upgradebackup.* (glob)
252 copy of old repository backed up at $TESTTMP/upgradegd/.hg/upgradebackup.* (glob)
@@ -252,4 +269,43 b' generaldelta added to original requireme'
252 revlogv1
269 revlogv1
253 store
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 $ cd ..
311 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now