##// END OF EJS Templates
upgrade: no longer keep all revlogs in memory at any point...
marmoute -
r50447:19948429 stable
parent child Browse files
Show More
@@ -1,679 +1,683
1 1 # upgrade.py - functions for in place upgrade of Mercurial repository
2 2 #
3 3 # Copyright (c) 2016-present, Gregory Szorc
4 4 #
5 5 # This software may be used and distributed according to the terms of the
6 6 # GNU General Public License version 2 or any later version.
7 7
8 8
9 9 import stat
10 10
11 11 from ..i18n import _
12 12 from ..pycompat import getattr
13 13 from .. import (
14 14 changelog,
15 15 error,
16 16 filelog,
17 17 manifest,
18 18 metadata,
19 19 pycompat,
20 20 requirements,
21 21 scmutil,
22 22 store,
23 23 util,
24 24 vfs as vfsmod,
25 25 )
26 26 from ..revlogutils import (
27 27 constants as revlogconst,
28 28 flagutil,
29 29 nodemap,
30 30 sidedata as sidedatamod,
31 31 )
32 32 from . import actions as upgrade_actions
33 33
34 34
35 35 def get_sidedata_helpers(srcrepo, dstrepo):
36 36 use_w = srcrepo.ui.configbool(b'experimental', b'worker.repository-upgrade')
37 37 sequential = pycompat.iswindows or not use_w
38 38 if not sequential:
39 39 srcrepo.register_sidedata_computer(
40 40 revlogconst.KIND_CHANGELOG,
41 41 sidedatamod.SD_FILES,
42 42 (sidedatamod.SD_FILES,),
43 43 metadata._get_worker_sidedata_adder(srcrepo, dstrepo),
44 44 flagutil.REVIDX_HASCOPIESINFO,
45 45 replace=True,
46 46 )
47 47 return sidedatamod.get_sidedata_helpers(srcrepo, dstrepo._wanted_sidedata)
48 48
49 49
50 50 def _revlogfrompath(repo, rl_type, path):
51 51 """Obtain a revlog from a repo path.
52 52
53 53 An instance of the appropriate class is returned.
54 54 """
55 55 if rl_type & store.FILEFLAGS_CHANGELOG:
56 56 return changelog.changelog(repo.svfs)
57 57 elif rl_type & store.FILEFLAGS_MANIFESTLOG:
58 58 mandir = b''
59 59 if b'/' in path:
60 60 mandir = path.rsplit(b'/', 1)[0]
61 61 return manifest.manifestrevlog(
62 62 repo.nodeconstants, repo.svfs, tree=mandir
63 63 )
64 64 else:
65 65 # drop the extension and the `data/` prefix
66 66 path_part = path.rsplit(b'.', 1)[0].split(b'/', 1)
67 67 if len(path_part) < 2:
68 68 msg = _(b'cannot recognize revlog from filename: %s')
69 69 msg %= path
70 70 raise error.Abort(msg)
71 71 path = path_part[1]
72 72 return filelog.filelog(repo.svfs, path)
73 73
74 74
75 75 def _copyrevlog(tr, destrepo, oldrl, rl_type, unencodedname):
76 76 """copy all relevant files for `oldrl` into `destrepo` store
77 77
78 78 Files are copied "as is" without any transformation. The copy is performed
79 79 without extra checks. Callers are responsible for making sure the copied
80 80 content is compatible with format of the destination repository.
81 81 """
82 82 oldrl = getattr(oldrl, '_revlog', oldrl)
83 83 newrl = _revlogfrompath(destrepo, rl_type, unencodedname)
84 84 newrl = getattr(newrl, '_revlog', newrl)
85 85
86 86 oldvfs = oldrl.opener
87 87 newvfs = newrl.opener
88 88 oldindex = oldvfs.join(oldrl._indexfile)
89 89 newindex = newvfs.join(newrl._indexfile)
90 90 olddata = oldvfs.join(oldrl._datafile)
91 91 newdata = newvfs.join(newrl._datafile)
92 92
93 93 with newvfs(newrl._indexfile, b'w'):
94 94 pass # create all the directories
95 95
96 96 util.copyfile(oldindex, newindex)
97 97 copydata = oldrl.opener.exists(oldrl._datafile)
98 98 if copydata:
99 99 util.copyfile(olddata, newdata)
100 100
101 101 if rl_type & store.FILEFLAGS_FILELOG:
102 102 destrepo.svfs.fncache.add(unencodedname)
103 103 if copydata:
104 104 destrepo.svfs.fncache.add(unencodedname[:-2] + b'.d')
105 105
106 106
107 107 UPGRADE_CHANGELOG = b"changelog"
108 108 UPGRADE_MANIFEST = b"manifest"
109 109 UPGRADE_FILELOGS = b"all-filelogs"
110 110
111 111 UPGRADE_ALL_REVLOGS = frozenset(
112 112 [UPGRADE_CHANGELOG, UPGRADE_MANIFEST, UPGRADE_FILELOGS]
113 113 )
114 114
115 115
116 116 def matchrevlog(revlogfilter, rl_type):
117 117 """check if a revlog is selected for cloning.
118 118
119 119 In other words, are there any updates which need to be done on revlog
120 120 or it can be blindly copied.
121 121
122 122 The store entry is checked against the passed filter"""
123 123 if rl_type & store.FILEFLAGS_CHANGELOG:
124 124 return UPGRADE_CHANGELOG in revlogfilter
125 125 elif rl_type & store.FILEFLAGS_MANIFESTLOG:
126 126 return UPGRADE_MANIFEST in revlogfilter
127 127 assert rl_type & store.FILEFLAGS_FILELOG
128 128 return UPGRADE_FILELOGS in revlogfilter
129 129
130 130
131 131 def _perform_clone(
132 132 ui,
133 133 dstrepo,
134 134 tr,
135 135 old_revlog,
136 136 rl_type,
137 137 unencoded,
138 138 upgrade_op,
139 139 sidedata_helpers,
140 140 oncopiedrevision,
141 141 ):
142 142 """returns the new revlog object created"""
143 143 newrl = None
144 144 if matchrevlog(upgrade_op.revlogs_to_process, rl_type):
145 145 ui.note(
146 146 _(b'cloning %d revisions from %s\n') % (len(old_revlog), unencoded)
147 147 )
148 148 newrl = _revlogfrompath(dstrepo, rl_type, unencoded)
149 149 old_revlog.clone(
150 150 tr,
151 151 newrl,
152 152 addrevisioncb=oncopiedrevision,
153 153 deltareuse=upgrade_op.delta_reuse_mode,
154 154 forcedeltabothparents=upgrade_op.force_re_delta_both_parents,
155 155 sidedata_helpers=sidedata_helpers,
156 156 )
157 157 else:
158 158 msg = _(b'blindly copying %s containing %i revisions\n')
159 159 ui.note(msg % (unencoded, len(old_revlog)))
160 160 _copyrevlog(tr, dstrepo, old_revlog, rl_type, unencoded)
161 161
162 162 newrl = _revlogfrompath(dstrepo, rl_type, unencoded)
163 163 return newrl
164 164
165 165
166 166 def _clonerevlogs(
167 167 ui,
168 168 srcrepo,
169 169 dstrepo,
170 170 tr,
171 171 upgrade_op,
172 172 ):
173 173 """Copy revlogs between 2 repos."""
174 174 revcount = 0
175 175 srcsize = 0
176 176 srcrawsize = 0
177 177 dstsize = 0
178 178 fcount = 0
179 179 frevcount = 0
180 180 fsrcsize = 0
181 181 frawsize = 0
182 182 fdstsize = 0
183 183 mcount = 0
184 184 mrevcount = 0
185 185 msrcsize = 0
186 186 mrawsize = 0
187 187 mdstsize = 0
188 188 crevcount = 0
189 189 csrcsize = 0
190 190 crawsize = 0
191 191 cdstsize = 0
192 192
193 193 alldatafiles = list(srcrepo.store.walk())
194 194 # mapping of data files which needs to be cloned
195 195 # key is unencoded filename
196 196 # value is revlog_object_from_srcrepo
197 197 manifests = {}
198 198 changelogs = {}
199 199 filelogs = {}
200 200
201 201 # Perform a pass to collect metadata. This validates we can open all
202 202 # source files and allows a unified progress bar to be displayed.
203 203 for rl_type, unencoded, size in alldatafiles:
204 204 if not rl_type & store.FILEFLAGS_REVLOG_MAIN:
205 205 continue
206 206
207 207 # the store.walk function will wrongly pickup transaction backup and
208 208 # get confused. As a quick fix for 5.9 release, we ignore those.
209 209 # (this is not a module constants because it seems better to keep the
210 210 # hack together)
211 211 skip_undo = (
212 212 b'undo.backup.00changelog.i',
213 213 b'undo.backup.00manifest.i',
214 214 )
215 215 if unencoded in skip_undo:
216 216 continue
217 217
218 218 rl = _revlogfrompath(srcrepo, rl_type, unencoded)
219 219
220 220 info = rl.storageinfo(
221 221 exclusivefiles=True,
222 222 revisionscount=True,
223 223 trackedsize=True,
224 224 storedsize=True,
225 225 )
226 226
227 227 revcount += info[b'revisionscount'] or 0
228 228 datasize = info[b'storedsize'] or 0
229 229 rawsize = info[b'trackedsize'] or 0
230 230
231 231 srcsize += datasize
232 232 srcrawsize += rawsize
233 233
234 234 # This is for the separate progress bars.
235 235 if rl_type & store.FILEFLAGS_CHANGELOG:
236 changelogs[unencoded] = (rl_type, rl)
236 changelogs[unencoded] = rl_type
237 237 crevcount += len(rl)
238 238 csrcsize += datasize
239 239 crawsize += rawsize
240 240 elif rl_type & store.FILEFLAGS_MANIFESTLOG:
241 manifests[unencoded] = (rl_type, rl)
241 manifests[unencoded] = rl_type
242 242 mcount += 1
243 243 mrevcount += len(rl)
244 244 msrcsize += datasize
245 245 mrawsize += rawsize
246 246 elif rl_type & store.FILEFLAGS_FILELOG:
247 filelogs[unencoded] = (rl_type, rl)
247 filelogs[unencoded] = rl_type
248 248 fcount += 1
249 249 frevcount += len(rl)
250 250 fsrcsize += datasize
251 251 frawsize += rawsize
252 252 else:
253 253 error.ProgrammingError(b'unknown revlog type')
254 254
255 255 if not revcount:
256 256 return
257 257
258 258 ui.status(
259 259 _(
260 260 b'migrating %d total revisions (%d in filelogs, %d in manifests, '
261 261 b'%d in changelog)\n'
262 262 )
263 263 % (revcount, frevcount, mrevcount, crevcount)
264 264 )
265 265 ui.status(
266 266 _(b'migrating %s in store; %s tracked data\n')
267 267 % ((util.bytecount(srcsize), util.bytecount(srcrawsize)))
268 268 )
269 269
270 270 # Used to keep track of progress.
271 271 progress = None
272 272
273 273 def oncopiedrevision(rl, rev, node):
274 274 progress.increment()
275 275
276 276 sidedata_helpers = get_sidedata_helpers(srcrepo, dstrepo)
277 277
278 278 # Migrating filelogs
279 279 ui.status(
280 280 _(
281 281 b'migrating %d filelogs containing %d revisions '
282 282 b'(%s in store; %s tracked data)\n'
283 283 )
284 284 % (
285 285 fcount,
286 286 frevcount,
287 287 util.bytecount(fsrcsize),
288 288 util.bytecount(frawsize),
289 289 )
290 290 )
291 291 progress = srcrepo.ui.makeprogress(_(b'file revisions'), total=frevcount)
292 for unencoded, (rl_type, oldrl) in sorted(filelogs.items()):
292 for unencoded, rl_type in sorted(filelogs.items()):
293 oldrl = _revlogfrompath(srcrepo, rl_type, unencoded)
294
293 295 newrl = _perform_clone(
294 296 ui,
295 297 dstrepo,
296 298 tr,
297 299 oldrl,
298 300 rl_type,
299 301 unencoded,
300 302 upgrade_op,
301 303 sidedata_helpers,
302 304 oncopiedrevision,
303 305 )
304 306 info = newrl.storageinfo(storedsize=True)
305 307 fdstsize += info[b'storedsize'] or 0
306 308 ui.status(
307 309 _(
308 310 b'finished migrating %d filelog revisions across %d '
309 311 b'filelogs; change in size: %s\n'
310 312 )
311 313 % (frevcount, fcount, util.bytecount(fdstsize - fsrcsize))
312 314 )
313 315
314 316 # Migrating manifests
315 317 ui.status(
316 318 _(
317 319 b'migrating %d manifests containing %d revisions '
318 320 b'(%s in store; %s tracked data)\n'
319 321 )
320 322 % (
321 323 mcount,
322 324 mrevcount,
323 325 util.bytecount(msrcsize),
324 326 util.bytecount(mrawsize),
325 327 )
326 328 )
327 329 if progress:
328 330 progress.complete()
329 331 progress = srcrepo.ui.makeprogress(
330 332 _(b'manifest revisions'), total=mrevcount
331 333 )
332 for unencoded, (rl_type, oldrl) in sorted(manifests.items()):
334 for unencoded, rl_type in sorted(manifests.items()):
335 oldrl = _revlogfrompath(srcrepo, rl_type, unencoded)
333 336 newrl = _perform_clone(
334 337 ui,
335 338 dstrepo,
336 339 tr,
337 340 oldrl,
338 341 rl_type,
339 342 unencoded,
340 343 upgrade_op,
341 344 sidedata_helpers,
342 345 oncopiedrevision,
343 346 )
344 347 info = newrl.storageinfo(storedsize=True)
345 348 mdstsize += info[b'storedsize'] or 0
346 349 ui.status(
347 350 _(
348 351 b'finished migrating %d manifest revisions across %d '
349 352 b'manifests; change in size: %s\n'
350 353 )
351 354 % (mrevcount, mcount, util.bytecount(mdstsize - msrcsize))
352 355 )
353 356
354 357 # Migrating changelog
355 358 ui.status(
356 359 _(
357 360 b'migrating changelog containing %d revisions '
358 361 b'(%s in store; %s tracked data)\n'
359 362 )
360 363 % (
361 364 crevcount,
362 365 util.bytecount(csrcsize),
363 366 util.bytecount(crawsize),
364 367 )
365 368 )
366 369 if progress:
367 370 progress.complete()
368 371 progress = srcrepo.ui.makeprogress(
369 372 _(b'changelog revisions'), total=crevcount
370 373 )
371 for unencoded, (rl_type, oldrl) in sorted(changelogs.items()):
374 for unencoded, rl_type in sorted(changelogs.items()):
375 oldrl = _revlogfrompath(srcrepo, rl_type, unencoded)
372 376 newrl = _perform_clone(
373 377 ui,
374 378 dstrepo,
375 379 tr,
376 380 oldrl,
377 381 rl_type,
378 382 unencoded,
379 383 upgrade_op,
380 384 sidedata_helpers,
381 385 oncopiedrevision,
382 386 )
383 387 info = newrl.storageinfo(storedsize=True)
384 388 cdstsize += info[b'storedsize'] or 0
385 389 progress.complete()
386 390 ui.status(
387 391 _(
388 392 b'finished migrating %d changelog revisions; change in size: '
389 393 b'%s\n'
390 394 )
391 395 % (crevcount, util.bytecount(cdstsize - csrcsize))
392 396 )
393 397
394 398 dstsize = fdstsize + mdstsize + cdstsize
395 399 ui.status(
396 400 _(
397 401 b'finished migrating %d total revisions; total change in store '
398 402 b'size: %s\n'
399 403 )
400 404 % (revcount, util.bytecount(dstsize - srcsize))
401 405 )
402 406
403 407
404 408 def _files_to_copy_post_revlog_clone(srcrepo):
405 409 """yields files which should be copied to destination after revlogs
406 410 are cloned"""
407 411 for path, kind, st in sorted(srcrepo.store.vfs.readdir(b'', stat=True)):
408 412 # don't copy revlogs as they are already cloned
409 413 if store.revlog_type(path) is not None:
410 414 continue
411 415 # Skip transaction related files.
412 416 if path.startswith(b'undo'):
413 417 continue
414 418 # Only copy regular files.
415 419 if kind != stat.S_IFREG:
416 420 continue
417 421 # Skip other skipped files.
418 422 if path in (b'lock', b'fncache'):
419 423 continue
420 424 # TODO: should we skip cache too?
421 425
422 426 yield path
423 427
424 428
425 429 def _replacestores(currentrepo, upgradedrepo, backupvfs, upgrade_op):
426 430 """Replace the stores after current repository is upgraded
427 431
428 432 Creates a backup of current repository store at backup path
429 433 Replaces upgraded store files in current repo from upgraded one
430 434
431 435 Arguments:
432 436 currentrepo: repo object of current repository
433 437 upgradedrepo: repo object of the upgraded data
434 438 backupvfs: vfs object for the backup path
435 439 upgrade_op: upgrade operation object
436 440 to be used to decide what all is upgraded
437 441 """
438 442 # TODO: don't blindly rename everything in store
439 443 # There can be upgrades where store is not touched at all
440 444 if upgrade_op.backup_store:
441 445 util.rename(currentrepo.spath, backupvfs.join(b'store'))
442 446 else:
443 447 currentrepo.vfs.rmtree(b'store', forcibly=True)
444 448 util.rename(upgradedrepo.spath, currentrepo.spath)
445 449
446 450
447 451 def finishdatamigration(ui, srcrepo, dstrepo, requirements):
448 452 """Hook point for extensions to perform additional actions during upgrade.
449 453
450 454 This function is called after revlogs and store files have been copied but
451 455 before the new store is swapped into the original location.
452 456 """
453 457
454 458
455 459 def upgrade(ui, srcrepo, dstrepo, upgrade_op):
456 460 """Do the low-level work of upgrading a repository.
457 461
458 462 The upgrade is effectively performed as a copy between a source
459 463 repository and a temporary destination repository.
460 464
461 465 The source repository is unmodified for as long as possible so the
462 466 upgrade can abort at any time without causing loss of service for
463 467 readers and without corrupting the source repository.
464 468 """
465 469 assert srcrepo.currentwlock()
466 470 assert dstrepo.currentwlock()
467 471 backuppath = None
468 472 backupvfs = None
469 473
470 474 ui.status(
471 475 _(
472 476 b'(it is safe to interrupt this process any time before '
473 477 b'data migration completes)\n'
474 478 )
475 479 )
476 480
477 481 if upgrade_actions.dirstatev2 in upgrade_op.upgrade_actions:
478 482 ui.status(_(b'upgrading to dirstate-v2 from v1\n'))
479 483 upgrade_dirstate(ui, srcrepo, upgrade_op, b'v1', b'v2')
480 484 upgrade_op.upgrade_actions.remove(upgrade_actions.dirstatev2)
481 485
482 486 if upgrade_actions.dirstatev2 in upgrade_op.removed_actions:
483 487 ui.status(_(b'downgrading from dirstate-v2 to v1\n'))
484 488 upgrade_dirstate(ui, srcrepo, upgrade_op, b'v2', b'v1')
485 489 upgrade_op.removed_actions.remove(upgrade_actions.dirstatev2)
486 490
487 491 if upgrade_actions.dirstatetrackedkey in upgrade_op.upgrade_actions:
488 492 ui.status(_(b'create dirstate-tracked-hint file\n'))
489 493 upgrade_tracked_hint(ui, srcrepo, upgrade_op, add=True)
490 494 upgrade_op.upgrade_actions.remove(upgrade_actions.dirstatetrackedkey)
491 495 elif upgrade_actions.dirstatetrackedkey in upgrade_op.removed_actions:
492 496 ui.status(_(b'remove dirstate-tracked-hint file\n'))
493 497 upgrade_tracked_hint(ui, srcrepo, upgrade_op, add=False)
494 498 upgrade_op.removed_actions.remove(upgrade_actions.dirstatetrackedkey)
495 499
496 500 if not (upgrade_op.upgrade_actions or upgrade_op.removed_actions):
497 501 return
498 502
499 503 if upgrade_op.requirements_only:
500 504 ui.status(_(b'upgrading repository requirements\n'))
501 505 scmutil.writereporequirements(srcrepo, upgrade_op.new_requirements)
502 506 # if there is only one action and that is persistent nodemap upgrade
503 507 # directly write the nodemap file and update requirements instead of going
504 508 # through the whole cloning process
505 509 elif (
506 510 len(upgrade_op.upgrade_actions) == 1
507 511 and b'persistent-nodemap' in upgrade_op.upgrade_actions_names
508 512 and not upgrade_op.removed_actions
509 513 ):
510 514 ui.status(
511 515 _(b'upgrading repository to use persistent nodemap feature\n')
512 516 )
513 517 with srcrepo.transaction(b'upgrade') as tr:
514 518 unfi = srcrepo.unfiltered()
515 519 cl = unfi.changelog
516 520 nodemap.persist_nodemap(tr, cl, force=True)
517 521 # we want to directly operate on the underlying revlog to force
518 522 # create a nodemap file. This is fine since this is upgrade code
519 523 # and it heavily relies on repository being revlog based
520 524 # hence accessing private attributes can be justified
521 525 nodemap.persist_nodemap(
522 526 tr, unfi.manifestlog._rootstore._revlog, force=True
523 527 )
524 528 scmutil.writereporequirements(srcrepo, upgrade_op.new_requirements)
525 529 elif (
526 530 len(upgrade_op.removed_actions) == 1
527 531 and [
528 532 x
529 533 for x in upgrade_op.removed_actions
530 534 if x.name == b'persistent-nodemap'
531 535 ]
532 536 and not upgrade_op.upgrade_actions
533 537 ):
534 538 ui.status(
535 539 _(b'downgrading repository to not use persistent nodemap feature\n')
536 540 )
537 541 with srcrepo.transaction(b'upgrade') as tr:
538 542 unfi = srcrepo.unfiltered()
539 543 cl = unfi.changelog
540 544 nodemap.delete_nodemap(tr, srcrepo, cl)
541 545 # check comment 20 lines above for accessing private attributes
542 546 nodemap.delete_nodemap(
543 547 tr, srcrepo, unfi.manifestlog._rootstore._revlog
544 548 )
545 549 scmutil.writereporequirements(srcrepo, upgrade_op.new_requirements)
546 550 else:
547 551 with dstrepo.transaction(b'upgrade') as tr:
548 552 _clonerevlogs(
549 553 ui,
550 554 srcrepo,
551 555 dstrepo,
552 556 tr,
553 557 upgrade_op,
554 558 )
555 559
556 560 # Now copy other files in the store directory.
557 561 for p in _files_to_copy_post_revlog_clone(srcrepo):
558 562 srcrepo.ui.status(_(b'copying %s\n') % p)
559 563 src = srcrepo.store.rawvfs.join(p)
560 564 dst = dstrepo.store.rawvfs.join(p)
561 565 util.copyfile(src, dst, copystat=True)
562 566
563 567 finishdatamigration(ui, srcrepo, dstrepo, requirements)
564 568
565 569 ui.status(_(b'data fully upgraded in a temporary repository\n'))
566 570
567 571 if upgrade_op.backup_store:
568 572 backuppath = pycompat.mkdtemp(
569 573 prefix=b'upgradebackup.', dir=srcrepo.path
570 574 )
571 575 backupvfs = vfsmod.vfs(backuppath)
572 576
573 577 # Make a backup of requires file first, as it is the first to be modified.
574 578 util.copyfile(
575 579 srcrepo.vfs.join(b'requires'), backupvfs.join(b'requires')
576 580 )
577 581
578 582 # We install an arbitrary requirement that clients must not support
579 583 # as a mechanism to lock out new clients during the data swap. This is
580 584 # better than allowing a client to continue while the repository is in
581 585 # an inconsistent state.
582 586 ui.status(
583 587 _(
584 588 b'marking source repository as being upgraded; clients will be '
585 589 b'unable to read from repository\n'
586 590 )
587 591 )
588 592 scmutil.writereporequirements(
589 593 srcrepo, srcrepo.requirements | {b'upgradeinprogress'}
590 594 )
591 595
592 596 ui.status(_(b'starting in-place swap of repository data\n'))
593 597 if upgrade_op.backup_store:
594 598 ui.status(
595 599 _(b'replaced files will be backed up at %s\n') % backuppath
596 600 )
597 601
598 602 # Now swap in the new store directory. Doing it as a rename should make
599 603 # the operation nearly instantaneous and atomic (at least in well-behaved
600 604 # environments).
601 605 ui.status(_(b'replacing store...\n'))
602 606 tstart = util.timer()
603 607 _replacestores(srcrepo, dstrepo, backupvfs, upgrade_op)
604 608 elapsed = util.timer() - tstart
605 609 ui.status(
606 610 _(
607 611 b'store replacement complete; repository was inconsistent for '
608 612 b'%0.1fs\n'
609 613 )
610 614 % elapsed
611 615 )
612 616
613 617 # We first write the requirements file. Any new requirements will lock
614 618 # out legacy clients.
615 619 ui.status(
616 620 _(
617 621 b'finalizing requirements file and making repository readable '
618 622 b'again\n'
619 623 )
620 624 )
621 625 scmutil.writereporequirements(srcrepo, upgrade_op.new_requirements)
622 626
623 627 if upgrade_op.backup_store:
624 628 # The lock file from the old store won't be removed because nothing has a
625 629 # reference to its new location. So clean it up manually. Alternatively, we
626 630 # could update srcrepo.svfs and other variables to point to the new
627 631 # location. This is simpler.
628 632 assert backupvfs is not None # help pytype
629 633 backupvfs.unlink(b'store/lock')
630 634
631 635 return backuppath
632 636
633 637
634 638 def upgrade_dirstate(ui, srcrepo, upgrade_op, old, new):
635 639 if upgrade_op.backup_store:
636 640 backuppath = pycompat.mkdtemp(
637 641 prefix=b'upgradebackup.', dir=srcrepo.path
638 642 )
639 643 ui.status(_(b'replaced files will be backed up at %s\n') % backuppath)
640 644 backupvfs = vfsmod.vfs(backuppath)
641 645 util.copyfile(
642 646 srcrepo.vfs.join(b'requires'), backupvfs.join(b'requires')
643 647 )
644 648 try:
645 649 util.copyfile(
646 650 srcrepo.vfs.join(b'dirstate'), backupvfs.join(b'dirstate')
647 651 )
648 652 except FileNotFoundError:
649 653 # The dirstate does not exist on an empty repo or a repo with no
650 654 # revision checked out
651 655 pass
652 656
653 657 assert srcrepo.dirstate._use_dirstate_v2 == (old == b'v2')
654 658 srcrepo.dirstate._map.preload()
655 659 srcrepo.dirstate._use_dirstate_v2 = new == b'v2'
656 660 srcrepo.dirstate._map._use_dirstate_v2 = srcrepo.dirstate._use_dirstate_v2
657 661 srcrepo.dirstate._dirty = True
658 662 try:
659 663 srcrepo.vfs.unlink(b'dirstate')
660 664 except FileNotFoundError:
661 665 # The dirstate does not exist on an empty repo or a repo with no
662 666 # revision checked out
663 667 pass
664 668
665 669 srcrepo.dirstate.write(None)
666 670
667 671 scmutil.writereporequirements(srcrepo, upgrade_op.new_requirements)
668 672
669 673
670 674 def upgrade_tracked_hint(ui, srcrepo, upgrade_op, add):
671 675 if add:
672 676 srcrepo.dirstate._use_tracked_hint = True
673 677 srcrepo.dirstate._dirty = True
674 678 srcrepo.dirstate._dirty_tracked_set = True
675 679 srcrepo.dirstate.write(None)
676 680 if not add:
677 681 srcrepo.dirstate.delete_tracked_hint()
678 682
679 683 scmutil.writereporequirements(srcrepo, upgrade_op.new_requirements)
General Comments 0
You need to be logged in to leave comments. Login now