##// END OF EJS Templates
upgrade: support upgrade to/from zstd storage (issue6088)...
marmoute -
r42306:d086ba38 default
parent child Browse files
Show More
@@ -1,955 +1,980
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 from __future__ import absolute_import
9 9
10 10 import stat
11 11
12 12 from .i18n import _
13 13 from . import (
14 14 changelog,
15 15 error,
16 16 filelog,
17 17 hg,
18 18 localrepo,
19 19 manifest,
20 20 pycompat,
21 21 revlog,
22 22 scmutil,
23 23 util,
24 24 vfs as vfsmod,
25 25 )
26 26
27 from .utils import (
28 compression,
29 )
30
27 31 def requiredsourcerequirements(repo):
28 32 """Obtain requirements required to be present to upgrade a repo.
29 33
30 34 An upgrade will not be allowed if the repository doesn't have the
31 35 requirements returned by this function.
32 36 """
33 37 return {
34 38 # Introduced in Mercurial 0.9.2.
35 39 'revlogv1',
36 40 # Introduced in Mercurial 0.9.2.
37 41 'store',
38 42 }
39 43
40 44 def blocksourcerequirements(repo):
41 45 """Obtain requirements that will prevent an upgrade from occurring.
42 46
43 47 An upgrade cannot be performed if the source repository contains a
44 48 requirements in the returned set.
45 49 """
46 50 return {
47 51 # The upgrade code does not yet support these experimental features.
48 52 # This is an artificial limitation.
49 53 'treemanifest',
50 54 # This was a precursor to generaldelta and was never enabled by default.
51 55 # It should (hopefully) not exist in the wild.
52 56 'parentdelta',
53 57 # Upgrade should operate on the actual store, not the shared link.
54 58 'shared',
55 59 }
56 60
57 61 def supportremovedrequirements(repo):
58 62 """Obtain requirements that can be removed during an upgrade.
59 63
60 64 If an upgrade were to create a repository that dropped a requirement,
61 65 the dropped requirement must appear in the returned set for the upgrade
62 66 to be allowed.
63 67 """
64 return {
68 supported = {
65 69 localrepo.SPARSEREVLOG_REQUIREMENT,
66 70 }
71 for name in compression.compengines:
72 engine = compression.compengines[name]
73 if engine.available() and engine.revlogheader():
74 supported.add(b'exp-compression-%s' % name)
75 if engine.name() == 'zstd':
76 supported.add(b'revlog-compression-zstd')
77 return supported
67 78
68 79 def supporteddestrequirements(repo):
69 80 """Obtain requirements that upgrade supports in the destination.
70 81
71 82 If the result of the upgrade would create requirements not in this set,
72 83 the upgrade is disallowed.
73 84
74 85 Extensions should monkeypatch this to add their custom requirements.
75 86 """
76 return {
87 supported = {
77 88 'dotencode',
78 89 'fncache',
79 90 'generaldelta',
80 91 'revlogv1',
81 92 'store',
82 93 localrepo.SPARSEREVLOG_REQUIREMENT,
83 94 }
95 for name in compression.compengines:
96 engine = compression.compengines[name]
97 if engine.available() and engine.revlogheader():
98 supported.add(b'exp-compression-%s' % name)
99 if engine.name() == 'zstd':
100 supported.add(b'revlog-compression-zstd')
101 return supported
84 102
85 103 def allowednewrequirements(repo):
86 104 """Obtain requirements that can be added to a repository during upgrade.
87 105
88 106 This is used to disallow proposed requirements from being added when
89 107 they weren't present before.
90 108
91 109 We use a list of allowed requirement additions instead of a list of known
92 110 bad additions because the whitelist approach is safer and will prevent
93 111 future, unknown requirements from accidentally being added.
94 112 """
95 return {
113 supported = {
96 114 'dotencode',
97 115 'fncache',
98 116 'generaldelta',
99 117 localrepo.SPARSEREVLOG_REQUIREMENT,
100 118 }
119 for name in compression.compengines:
120 engine = compression.compengines[name]
121 if engine.available() and engine.revlogheader():
122 supported.add(b'exp-compression-%s' % name)
123 if engine.name() == 'zstd':
124 supported.add(b'revlog-compression-zstd')
125 return supported
101 126
102 127 def preservedrequirements(repo):
103 128 return set()
104 129
105 130 deficiency = 'deficiency'
106 131 optimisation = 'optimization'
107 132
108 133 class improvement(object):
109 134 """Represents an improvement that can be made as part of an upgrade.
110 135
111 136 The following attributes are defined on each instance:
112 137
113 138 name
114 139 Machine-readable string uniquely identifying this improvement. It
115 140 will be mapped to an action later in the upgrade process.
116 141
117 142 type
118 143 Either ``deficiency`` or ``optimisation``. A deficiency is an obvious
119 144 problem. An optimization is an action (sometimes optional) that
120 145 can be taken to further improve the state of the repository.
121 146
122 147 description
123 148 Message intended for humans explaining the improvement in more detail,
124 149 including the implications of it. For ``deficiency`` types, should be
125 150 worded in the present tense. For ``optimisation`` types, should be
126 151 worded in the future tense.
127 152
128 153 upgrademessage
129 154 Message intended for humans explaining what an upgrade addressing this
130 155 issue will do. Should be worded in the future tense.
131 156 """
132 157 def __init__(self, name, type, description, upgrademessage):
133 158 self.name = name
134 159 self.type = type
135 160 self.description = description
136 161 self.upgrademessage = upgrademessage
137 162
138 163 def __eq__(self, other):
139 164 if not isinstance(other, improvement):
140 165 # This is what python tell use to do
141 166 return NotImplemented
142 167 return self.name == other.name
143 168
144 169 def __ne__(self, other):
145 170 return not (self == other)
146 171
147 172 def __hash__(self):
148 173 return hash(self.name)
149 174
150 175 allformatvariant = []
151 176
152 177 def registerformatvariant(cls):
153 178 allformatvariant.append(cls)
154 179 return cls
155 180
156 181 class formatvariant(improvement):
157 182 """an improvement subclass dedicated to repository format"""
158 183 type = deficiency
159 184 ### The following attributes should be defined for each class:
160 185
161 186 # machine-readable string uniquely identifying this improvement. it will be
162 187 # mapped to an action later in the upgrade process.
163 188 name = None
164 189
165 190 # message intended for humans explaining the improvement in more detail,
166 191 # including the implications of it ``deficiency`` types, should be worded
167 192 # in the present tense.
168 193 description = None
169 194
170 195 # message intended for humans explaining what an upgrade addressing this
171 196 # issue will do. should be worded in the future tense.
172 197 upgrademessage = None
173 198
174 199 # value of current Mercurial default for new repository
175 200 default = None
176 201
177 202 def __init__(self):
178 203 raise NotImplementedError()
179 204
180 205 @staticmethod
181 206 def fromrepo(repo):
182 207 """current value of the variant in the repository"""
183 208 raise NotImplementedError()
184 209
185 210 @staticmethod
186 211 def fromconfig(repo):
187 212 """current value of the variant in the configuration"""
188 213 raise NotImplementedError()
189 214
190 215 class requirementformatvariant(formatvariant):
191 216 """formatvariant based on a 'requirement' name.
192 217
193 218 Many format variant are controlled by a 'requirement'. We define a small
194 219 subclass to factor the code.
195 220 """
196 221
197 222 # the requirement that control this format variant
198 223 _requirement = None
199 224
200 225 @staticmethod
201 226 def _newreporequirements(ui):
202 227 return localrepo.newreporequirements(
203 228 ui, localrepo.defaultcreateopts(ui))
204 229
205 230 @classmethod
206 231 def fromrepo(cls, repo):
207 232 assert cls._requirement is not None
208 233 return cls._requirement in repo.requirements
209 234
210 235 @classmethod
211 236 def fromconfig(cls, repo):
212 237 assert cls._requirement is not None
213 238 return cls._requirement in cls._newreporequirements(repo.ui)
214 239
215 240 @registerformatvariant
216 241 class fncache(requirementformatvariant):
217 242 name = 'fncache'
218 243
219 244 _requirement = 'fncache'
220 245
221 246 default = True
222 247
223 248 description = _('long and reserved filenames may not work correctly; '
224 249 'repository performance is sub-optimal')
225 250
226 251 upgrademessage = _('repository will be more resilient to storing '
227 252 'certain paths and performance of certain '
228 253 'operations should be improved')
229 254
230 255 @registerformatvariant
231 256 class dotencode(requirementformatvariant):
232 257 name = 'dotencode'
233 258
234 259 _requirement = 'dotencode'
235 260
236 261 default = True
237 262
238 263 description = _('storage of filenames beginning with a period or '
239 264 'space may not work correctly')
240 265
241 266 upgrademessage = _('repository will be better able to store files '
242 267 'beginning with a space or period')
243 268
244 269 @registerformatvariant
245 270 class generaldelta(requirementformatvariant):
246 271 name = 'generaldelta'
247 272
248 273 _requirement = 'generaldelta'
249 274
250 275 default = True
251 276
252 277 description = _('deltas within internal storage are unable to '
253 278 'choose optimal revisions; repository is larger and '
254 279 'slower than it could be; interaction with other '
255 280 'repositories may require extra network and CPU '
256 281 'resources, making "hg push" and "hg pull" slower')
257 282
258 283 upgrademessage = _('repository storage will be able to create '
259 284 'optimal deltas; new repository data will be '
260 285 'smaller and read times should decrease; '
261 286 'interacting with other repositories using this '
262 287 'storage model should require less network and '
263 288 'CPU resources, making "hg push" and "hg pull" '
264 289 'faster')
265 290
266 291 @registerformatvariant
267 292 class sparserevlog(requirementformatvariant):
268 293 name = 'sparserevlog'
269 294
270 295 _requirement = localrepo.SPARSEREVLOG_REQUIREMENT
271 296
272 297 default = True
273 298
274 299 description = _('in order to limit disk reading and memory usage on older '
275 300 'version, the span of a delta chain from its root to its '
276 301 'end is limited, whatever the relevant data in this span. '
277 302 'This can severly limit Mercurial ability to build good '
278 303 'chain of delta resulting is much more storage space being '
279 304 'taken and limit reusability of on disk delta during '
280 305 'exchange.'
281 306 )
282 307
283 308 upgrademessage = _('Revlog supports delta chain with more unused data '
284 309 'between payload. These gaps will be skipped at read '
285 310 'time. This allows for better delta chains, making a '
286 311 'better compression and faster exchange with server.')
287 312
288 313 @registerformatvariant
289 314 class removecldeltachain(formatvariant):
290 315 name = 'plain-cl-delta'
291 316
292 317 default = True
293 318
294 319 description = _('changelog storage is using deltas instead of '
295 320 'raw entries; changelog reading and any '
296 321 'operation relying on changelog data are slower '
297 322 'than they could be')
298 323
299 324 upgrademessage = _('changelog storage will be reformated to '
300 325 'store raw entries; changelog reading will be '
301 326 'faster; changelog size may be reduced')
302 327
303 328 @staticmethod
304 329 def fromrepo(repo):
305 330 # Mercurial 4.0 changed changelogs to not use delta chains. Search for
306 331 # changelogs with deltas.
307 332 cl = repo.changelog
308 333 chainbase = cl.chainbase
309 334 return all(rev == chainbase(rev) for rev in cl)
310 335
311 336 @staticmethod
312 337 def fromconfig(repo):
313 338 return True
314 339
315 340 @registerformatvariant
316 341 class compressionengine(formatvariant):
317 342 name = 'compression'
318 343 default = 'zlib'
319 344
320 345 description = _('Compresion algorithm used to compress data. '
321 346 'Some engine are faster than other')
322 347
323 348 upgrademessage = _('revlog content will be recompressed with the new '
324 349 'algorithm.')
325 350
326 351 @classmethod
327 352 def fromrepo(cls, repo):
328 353 # we allow multiple compression engine requirement to co-exist because
329 354 # strickly speaking, revlog seems to support mixed compression style.
330 355 #
331 356 # The compression used for new entries will be "the last one"
332 357 compression = 'zlib'
333 358 for req in repo.requirements:
334 359 prefix = req.startswith
335 360 if prefix('revlog-compression-') or prefix('exp-compression-'):
336 361 compression = req.split('-', 2)[2]
337 362 return compression
338 363
339 364 @classmethod
340 365 def fromconfig(cls, repo):
341 366 return repo.ui.config('format', 'revlog-compression')
342 367
343 368 @registerformatvariant
344 369 class compressionlevel(formatvariant):
345 370 name = 'compression-level'
346 371 default = 'default'
347 372
348 373 description = _('compression level')
349 374
350 375 upgrademessage = _('revlog content will be recompressed')
351 376
352 377 @classmethod
353 378 def fromrepo(cls, repo):
354 379 comp = compressionengine.fromrepo(repo)
355 380 level = None
356 381 if comp == 'zlib':
357 382 level = repo.ui.configint('storage', 'revlog.zlib.level')
358 383 elif comp == 'zstd':
359 384 level = repo.ui.configint('storage', 'revlog.zstd.level')
360 385 if level is None:
361 386 return 'default'
362 387 return bytes(level)
363 388
364 389 @classmethod
365 390 def fromconfig(cls, repo):
366 391 comp = compressionengine.fromconfig(repo)
367 392 level = None
368 393 if comp == 'zlib':
369 394 level = repo.ui.configint('storage', 'revlog.zlib.level')
370 395 elif comp == 'zstd':
371 396 level = repo.ui.configint('storage', 'revlog.zstd.level')
372 397 if level is None:
373 398 return 'default'
374 399 return bytes(level)
375 400
376 401 def finddeficiencies(repo):
377 402 """returns a list of deficiencies that the repo suffer from"""
378 403 deficiencies = []
379 404
380 405 # We could detect lack of revlogv1 and store here, but they were added
381 406 # in 0.9.2 and we don't support upgrading repos without these
382 407 # requirements, so let's not bother.
383 408
384 409 for fv in allformatvariant:
385 410 if not fv.fromrepo(repo):
386 411 deficiencies.append(fv)
387 412
388 413 return deficiencies
389 414
390 415 # search without '-' to support older form on newer client.
391 416 #
392 417 # We don't enforce backward compatibility for debug command so this
393 418 # might eventually be dropped. However, having to use two different
394 419 # forms in script when comparing result is anoying enough to add
395 420 # backward compatibility for a while.
396 421 legacy_opts_map = {
397 422 'redeltaparent': 're-delta-parent',
398 423 'redeltamultibase': 're-delta-multibase',
399 424 'redeltaall': 're-delta-all',
400 425 'redeltafulladd': 're-delta-fulladd',
401 426 }
402 427
403 428 def findoptimizations(repo):
404 429 """Determine optimisation that could be used during upgrade"""
405 430 # These are unconditionally added. There is logic later that figures out
406 431 # which ones to apply.
407 432 optimizations = []
408 433
409 434 optimizations.append(improvement(
410 435 name='re-delta-parent',
411 436 type=optimisation,
412 437 description=_('deltas within internal storage will be recalculated to '
413 438 'choose an optimal base revision where this was not '
414 439 'already done; the size of the repository may shrink and '
415 440 'various operations may become faster; the first time '
416 441 'this optimization is performed could slow down upgrade '
417 442 'execution considerably; subsequent invocations should '
418 443 'not run noticeably slower'),
419 444 upgrademessage=_('deltas within internal storage will choose a new '
420 445 'base revision if needed')))
421 446
422 447 optimizations.append(improvement(
423 448 name='re-delta-multibase',
424 449 type=optimisation,
425 450 description=_('deltas within internal storage will be recalculated '
426 451 'against multiple base revision and the smallest '
427 452 'difference will be used; the size of the repository may '
428 453 'shrink significantly when there are many merges; this '
429 454 'optimization will slow down execution in proportion to '
430 455 'the number of merges in the repository and the amount '
431 456 'of files in the repository; this slow down should not '
432 457 'be significant unless there are tens of thousands of '
433 458 'files and thousands of merges'),
434 459 upgrademessage=_('deltas within internal storage will choose an '
435 460 'optimal delta by computing deltas against multiple '
436 461 'parents; may slow down execution time '
437 462 'significantly')))
438 463
439 464 optimizations.append(improvement(
440 465 name='re-delta-all',
441 466 type=optimisation,
442 467 description=_('deltas within internal storage will always be '
443 468 'recalculated without reusing prior deltas; this will '
444 469 'likely make execution run several times slower; this '
445 470 'optimization is typically not needed'),
446 471 upgrademessage=_('deltas within internal storage will be fully '
447 472 'recomputed; this will likely drastically slow down '
448 473 'execution time')))
449 474
450 475 optimizations.append(improvement(
451 476 name='re-delta-fulladd',
452 477 type=optimisation,
453 478 description=_('every revision will be re-added as if it was new '
454 479 'content. It will go through the full storage '
455 480 'mechanism giving extensions a chance to process it '
456 481 '(eg. lfs). This is similar to "re-delta-all" but even '
457 482 'slower since more logic is involved.'),
458 483 upgrademessage=_('each revision will be added as new content to the '
459 484 'internal storage; this will likely drastically slow '
460 485 'down execution time, but some extensions might need '
461 486 'it')))
462 487
463 488 return optimizations
464 489
465 490 def determineactions(repo, deficiencies, sourcereqs, destreqs):
466 491 """Determine upgrade actions that will be performed.
467 492
468 493 Given a list of improvements as returned by ``finddeficiencies`` and
469 494 ``findoptimizations``, determine the list of upgrade actions that
470 495 will be performed.
471 496
472 497 The role of this function is to filter improvements if needed, apply
473 498 recommended optimizations from the improvements list that make sense,
474 499 etc.
475 500
476 501 Returns a list of action names.
477 502 """
478 503 newactions = []
479 504
480 505 knownreqs = supporteddestrequirements(repo)
481 506
482 507 for d in deficiencies:
483 508 name = d.name
484 509
485 510 # If the action is a requirement that doesn't show up in the
486 511 # destination requirements, prune the action.
487 512 if name in knownreqs and name not in destreqs:
488 513 continue
489 514
490 515 newactions.append(d)
491 516
492 517 # FUTURE consider adding some optimizations here for certain transitions.
493 518 # e.g. adding generaldelta could schedule parent redeltas.
494 519
495 520 return newactions
496 521
497 522 def _revlogfrompath(repo, path):
498 523 """Obtain a revlog from a repo path.
499 524
500 525 An instance of the appropriate class is returned.
501 526 """
502 527 if path == '00changelog.i':
503 528 return changelog.changelog(repo.svfs)
504 529 elif path.endswith('00manifest.i'):
505 530 mandir = path[:-len('00manifest.i')]
506 531 return manifest.manifestrevlog(repo.svfs, tree=mandir)
507 532 else:
508 533 #reverse of "/".join(("data", path + ".i"))
509 534 return filelog.filelog(repo.svfs, path[5:-2])
510 535
511 536 def _copyrevlogs(ui, srcrepo, dstrepo, tr, deltareuse, forcedeltabothparents):
512 537 """Copy revlogs between 2 repos."""
513 538 revcount = 0
514 539 srcsize = 0
515 540 srcrawsize = 0
516 541 dstsize = 0
517 542 fcount = 0
518 543 frevcount = 0
519 544 fsrcsize = 0
520 545 frawsize = 0
521 546 fdstsize = 0
522 547 mcount = 0
523 548 mrevcount = 0
524 549 msrcsize = 0
525 550 mrawsize = 0
526 551 mdstsize = 0
527 552 crevcount = 0
528 553 csrcsize = 0
529 554 crawsize = 0
530 555 cdstsize = 0
531 556
532 557 # Perform a pass to collect metadata. This validates we can open all
533 558 # source files and allows a unified progress bar to be displayed.
534 559 for unencoded, encoded, size in srcrepo.store.walk():
535 560 if unencoded.endswith('.d'):
536 561 continue
537 562
538 563 rl = _revlogfrompath(srcrepo, unencoded)
539 564
540 565 info = rl.storageinfo(exclusivefiles=True, revisionscount=True,
541 566 trackedsize=True, storedsize=True)
542 567
543 568 revcount += info['revisionscount'] or 0
544 569 datasize = info['storedsize'] or 0
545 570 rawsize = info['trackedsize'] or 0
546 571
547 572 srcsize += datasize
548 573 srcrawsize += rawsize
549 574
550 575 # This is for the separate progress bars.
551 576 if isinstance(rl, changelog.changelog):
552 577 crevcount += len(rl)
553 578 csrcsize += datasize
554 579 crawsize += rawsize
555 580 elif isinstance(rl, manifest.manifestrevlog):
556 581 mcount += 1
557 582 mrevcount += len(rl)
558 583 msrcsize += datasize
559 584 mrawsize += rawsize
560 585 elif isinstance(rl, filelog.filelog):
561 586 fcount += 1
562 587 frevcount += len(rl)
563 588 fsrcsize += datasize
564 589 frawsize += rawsize
565 590 else:
566 591 error.ProgrammingError('unknown revlog type')
567 592
568 593 if not revcount:
569 594 return
570 595
571 596 ui.write(_('migrating %d total revisions (%d in filelogs, %d in manifests, '
572 597 '%d in changelog)\n') %
573 598 (revcount, frevcount, mrevcount, crevcount))
574 599 ui.write(_('migrating %s in store; %s tracked data\n') % (
575 600 (util.bytecount(srcsize), util.bytecount(srcrawsize))))
576 601
577 602 # Used to keep track of progress.
578 603 progress = None
579 604 def oncopiedrevision(rl, rev, node):
580 605 progress.increment()
581 606
582 607 # Do the actual copying.
583 608 # FUTURE this operation can be farmed off to worker processes.
584 609 seen = set()
585 610 for unencoded, encoded, size in srcrepo.store.walk():
586 611 if unencoded.endswith('.d'):
587 612 continue
588 613
589 614 oldrl = _revlogfrompath(srcrepo, unencoded)
590 615 newrl = _revlogfrompath(dstrepo, unencoded)
591 616
592 617 if isinstance(oldrl, changelog.changelog) and 'c' not in seen:
593 618 ui.write(_('finished migrating %d manifest revisions across %d '
594 619 'manifests; change in size: %s\n') %
595 620 (mrevcount, mcount, util.bytecount(mdstsize - msrcsize)))
596 621
597 622 ui.write(_('migrating changelog containing %d revisions '
598 623 '(%s in store; %s tracked data)\n') %
599 624 (crevcount, util.bytecount(csrcsize),
600 625 util.bytecount(crawsize)))
601 626 seen.add('c')
602 627 progress = srcrepo.ui.makeprogress(_('changelog revisions'),
603 628 total=crevcount)
604 629 elif isinstance(oldrl, manifest.manifestrevlog) and 'm' not in seen:
605 630 ui.write(_('finished migrating %d filelog revisions across %d '
606 631 'filelogs; change in size: %s\n') %
607 632 (frevcount, fcount, util.bytecount(fdstsize - fsrcsize)))
608 633
609 634 ui.write(_('migrating %d manifests containing %d revisions '
610 635 '(%s in store; %s tracked data)\n') %
611 636 (mcount, mrevcount, util.bytecount(msrcsize),
612 637 util.bytecount(mrawsize)))
613 638 seen.add('m')
614 639 if progress:
615 640 progress.complete()
616 641 progress = srcrepo.ui.makeprogress(_('manifest revisions'),
617 642 total=mrevcount)
618 643 elif 'f' not in seen:
619 644 ui.write(_('migrating %d filelogs containing %d revisions '
620 645 '(%s in store; %s tracked data)\n') %
621 646 (fcount, frevcount, util.bytecount(fsrcsize),
622 647 util.bytecount(frawsize)))
623 648 seen.add('f')
624 649 if progress:
625 650 progress.complete()
626 651 progress = srcrepo.ui.makeprogress(_('file revisions'),
627 652 total=frevcount)
628 653
629 654
630 655 ui.note(_('cloning %d revisions from %s\n') % (len(oldrl), unencoded))
631 656 oldrl.clone(tr, newrl, addrevisioncb=oncopiedrevision,
632 657 deltareuse=deltareuse,
633 658 forcedeltabothparents=forcedeltabothparents)
634 659
635 660 info = newrl.storageinfo(storedsize=True)
636 661 datasize = info['storedsize'] or 0
637 662
638 663 dstsize += datasize
639 664
640 665 if isinstance(newrl, changelog.changelog):
641 666 cdstsize += datasize
642 667 elif isinstance(newrl, manifest.manifestrevlog):
643 668 mdstsize += datasize
644 669 else:
645 670 fdstsize += datasize
646 671
647 672 progress.complete()
648 673
649 674 ui.write(_('finished migrating %d changelog revisions; change in size: '
650 675 '%s\n') % (crevcount, util.bytecount(cdstsize - csrcsize)))
651 676
652 677 ui.write(_('finished migrating %d total revisions; total change in store '
653 678 'size: %s\n') % (revcount, util.bytecount(dstsize - srcsize)))
654 679
655 680 def _filterstorefile(srcrepo, dstrepo, requirements, path, mode, st):
656 681 """Determine whether to copy a store file during upgrade.
657 682
658 683 This function is called when migrating store files from ``srcrepo`` to
659 684 ``dstrepo`` as part of upgrading a repository.
660 685
661 686 Args:
662 687 srcrepo: repo we are copying from
663 688 dstrepo: repo we are copying to
664 689 requirements: set of requirements for ``dstrepo``
665 690 path: store file being examined
666 691 mode: the ``ST_MODE`` file type of ``path``
667 692 st: ``stat`` data structure for ``path``
668 693
669 694 Function should return ``True`` if the file is to be copied.
670 695 """
671 696 # Skip revlogs.
672 697 if path.endswith(('.i', '.d')):
673 698 return False
674 699 # Skip transaction related files.
675 700 if path.startswith('undo'):
676 701 return False
677 702 # Only copy regular files.
678 703 if mode != stat.S_IFREG:
679 704 return False
680 705 # Skip other skipped files.
681 706 if path in ('lock', 'fncache'):
682 707 return False
683 708
684 709 return True
685 710
686 711 def _finishdatamigration(ui, srcrepo, dstrepo, requirements):
687 712 """Hook point for extensions to perform additional actions during upgrade.
688 713
689 714 This function is called after revlogs and store files have been copied but
690 715 before the new store is swapped into the original location.
691 716 """
692 717
693 718 def _upgraderepo(ui, srcrepo, dstrepo, requirements, actions):
694 719 """Do the low-level work of upgrading a repository.
695 720
696 721 The upgrade is effectively performed as a copy between a source
697 722 repository and a temporary destination repository.
698 723
699 724 The source repository is unmodified for as long as possible so the
700 725 upgrade can abort at any time without causing loss of service for
701 726 readers and without corrupting the source repository.
702 727 """
703 728 assert srcrepo.currentwlock()
704 729 assert dstrepo.currentwlock()
705 730
706 731 ui.write(_('(it is safe to interrupt this process any time before '
707 732 'data migration completes)\n'))
708 733
709 734 if 're-delta-all' in actions:
710 735 deltareuse = revlog.revlog.DELTAREUSENEVER
711 736 elif 're-delta-parent' in actions:
712 737 deltareuse = revlog.revlog.DELTAREUSESAMEREVS
713 738 elif 're-delta-multibase' in actions:
714 739 deltareuse = revlog.revlog.DELTAREUSESAMEREVS
715 740 elif 're-delta-fulladd' in actions:
716 741 deltareuse = revlog.revlog.DELTAREUSEFULLADD
717 742 else:
718 743 deltareuse = revlog.revlog.DELTAREUSEALWAYS
719 744
720 745 with dstrepo.transaction('upgrade') as tr:
721 746 _copyrevlogs(ui, srcrepo, dstrepo, tr, deltareuse,
722 747 're-delta-multibase' in actions)
723 748
724 749 # Now copy other files in the store directory.
725 750 # The sorted() makes execution deterministic.
726 751 for p, kind, st in sorted(srcrepo.store.vfs.readdir('', stat=True)):
727 752 if not _filterstorefile(srcrepo, dstrepo, requirements,
728 753 p, kind, st):
729 754 continue
730 755
731 756 srcrepo.ui.write(_('copying %s\n') % p)
732 757 src = srcrepo.store.rawvfs.join(p)
733 758 dst = dstrepo.store.rawvfs.join(p)
734 759 util.copyfile(src, dst, copystat=True)
735 760
736 761 _finishdatamigration(ui, srcrepo, dstrepo, requirements)
737 762
738 763 ui.write(_('data fully migrated to temporary repository\n'))
739 764
740 765 backuppath = pycompat.mkdtemp(prefix='upgradebackup.', dir=srcrepo.path)
741 766 backupvfs = vfsmod.vfs(backuppath)
742 767
743 768 # Make a backup of requires file first, as it is the first to be modified.
744 769 util.copyfile(srcrepo.vfs.join('requires'), backupvfs.join('requires'))
745 770
746 771 # We install an arbitrary requirement that clients must not support
747 772 # as a mechanism to lock out new clients during the data swap. This is
748 773 # better than allowing a client to continue while the repository is in
749 774 # an inconsistent state.
750 775 ui.write(_('marking source repository as being upgraded; clients will be '
751 776 'unable to read from repository\n'))
752 777 scmutil.writerequires(srcrepo.vfs,
753 778 srcrepo.requirements | {'upgradeinprogress'})
754 779
755 780 ui.write(_('starting in-place swap of repository data\n'))
756 781 ui.write(_('replaced files will be backed up at %s\n') %
757 782 backuppath)
758 783
759 784 # Now swap in the new store directory. Doing it as a rename should make
760 785 # the operation nearly instantaneous and atomic (at least in well-behaved
761 786 # environments).
762 787 ui.write(_('replacing store...\n'))
763 788 tstart = util.timer()
764 789 util.rename(srcrepo.spath, backupvfs.join('store'))
765 790 util.rename(dstrepo.spath, srcrepo.spath)
766 791 elapsed = util.timer() - tstart
767 792 ui.write(_('store replacement complete; repository was inconsistent for '
768 793 '%0.1fs\n') % elapsed)
769 794
770 795 # We first write the requirements file. Any new requirements will lock
771 796 # out legacy clients.
772 797 ui.write(_('finalizing requirements file and making repository readable '
773 798 'again\n'))
774 799 scmutil.writerequires(srcrepo.vfs, requirements)
775 800
776 801 # The lock file from the old store won't be removed because nothing has a
777 802 # reference to its new location. So clean it up manually. Alternatively, we
778 803 # could update srcrepo.svfs and other variables to point to the new
779 804 # location. This is simpler.
780 805 backupvfs.unlink('store/lock')
781 806
782 807 return backuppath
783 808
784 809 def upgraderepo(ui, repo, run=False, optimize=None, backup=True):
785 810 """Upgrade a repository in place."""
786 811 if optimize is None:
787 812 optimize = []
788 813 optimize = set(legacy_opts_map.get(o, o) for o in optimize)
789 814 repo = repo.unfiltered()
790 815
791 816 # Ensure the repository can be upgraded.
792 817 missingreqs = requiredsourcerequirements(repo) - repo.requirements
793 818 if missingreqs:
794 819 raise error.Abort(_('cannot upgrade repository; requirement '
795 820 'missing: %s') % _(', ').join(sorted(missingreqs)))
796 821
797 822 blockedreqs = blocksourcerequirements(repo) & repo.requirements
798 823 if blockedreqs:
799 824 raise error.Abort(_('cannot upgrade repository; unsupported source '
800 825 'requirement: %s') %
801 826 _(', ').join(sorted(blockedreqs)))
802 827
803 828 # FUTURE there is potentially a need to control the wanted requirements via
804 829 # command arguments or via an extension hook point.
805 830 newreqs = localrepo.newreporequirements(
806 831 repo.ui, localrepo.defaultcreateopts(repo.ui))
807 832 newreqs.update(preservedrequirements(repo))
808 833
809 834 noremovereqs = (repo.requirements - newreqs -
810 835 supportremovedrequirements(repo))
811 836 if noremovereqs:
812 837 raise error.Abort(_('cannot upgrade repository; requirement would be '
813 838 'removed: %s') % _(', ').join(sorted(noremovereqs)))
814 839
815 840 noaddreqs = (newreqs - repo.requirements -
816 841 allowednewrequirements(repo))
817 842 if noaddreqs:
818 843 raise error.Abort(_('cannot upgrade repository; do not support adding '
819 844 'requirement: %s') %
820 845 _(', ').join(sorted(noaddreqs)))
821 846
822 847 unsupportedreqs = newreqs - supporteddestrequirements(repo)
823 848 if unsupportedreqs:
824 849 raise error.Abort(_('cannot upgrade repository; do not support '
825 850 'destination requirement: %s') %
826 851 _(', ').join(sorted(unsupportedreqs)))
827 852
828 853 # Find and validate all improvements that can be made.
829 854 alloptimizations = findoptimizations(repo)
830 855
831 856 # Apply and Validate arguments.
832 857 optimizations = []
833 858 for o in alloptimizations:
834 859 if o.name in optimize:
835 860 optimizations.append(o)
836 861 optimize.discard(o.name)
837 862
838 863 if optimize: # anything left is unknown
839 864 raise error.Abort(_('unknown optimization action requested: %s') %
840 865 ', '.join(sorted(optimize)),
841 866 hint=_('run without arguments to see valid '
842 867 'optimizations'))
843 868
844 869 deficiencies = finddeficiencies(repo)
845 870 actions = determineactions(repo, deficiencies, repo.requirements, newreqs)
846 871 actions.extend(o for o in sorted(optimizations)
847 872 # determineactions could have added optimisation
848 873 if o not in actions)
849 874
850 875 def printrequirements():
851 876 ui.write(_('requirements\n'))
852 877 ui.write(_(' preserved: %s\n') %
853 878 _(', ').join(sorted(newreqs & repo.requirements)))
854 879
855 880 if repo.requirements - newreqs:
856 881 ui.write(_(' removed: %s\n') %
857 882 _(', ').join(sorted(repo.requirements - newreqs)))
858 883
859 884 if newreqs - repo.requirements:
860 885 ui.write(_(' added: %s\n') %
861 886 _(', ').join(sorted(newreqs - repo.requirements)))
862 887
863 888 ui.write('\n')
864 889
865 890 def printupgradeactions():
866 891 for a in actions:
867 892 ui.write('%s\n %s\n\n' % (a.name, a.upgrademessage))
868 893
869 894 if not run:
870 895 fromconfig = []
871 896 onlydefault = []
872 897
873 898 for d in deficiencies:
874 899 if d.fromconfig(repo):
875 900 fromconfig.append(d)
876 901 elif d.default:
877 902 onlydefault.append(d)
878 903
879 904 if fromconfig or onlydefault:
880 905
881 906 if fromconfig:
882 907 ui.write(_('repository lacks features recommended by '
883 908 'current config options:\n\n'))
884 909 for i in fromconfig:
885 910 ui.write('%s\n %s\n\n' % (i.name, i.description))
886 911
887 912 if onlydefault:
888 913 ui.write(_('repository lacks features used by the default '
889 914 'config options:\n\n'))
890 915 for i in onlydefault:
891 916 ui.write('%s\n %s\n\n' % (i.name, i.description))
892 917
893 918 ui.write('\n')
894 919 else:
895 920 ui.write(_('(no feature deficiencies found in existing '
896 921 'repository)\n'))
897 922
898 923 ui.write(_('performing an upgrade with "--run" will make the following '
899 924 'changes:\n\n'))
900 925
901 926 printrequirements()
902 927 printupgradeactions()
903 928
904 929 unusedoptimize = [i for i in alloptimizations if i not in actions]
905 930
906 931 if unusedoptimize:
907 932 ui.write(_('additional optimizations are available by specifying '
908 933 '"--optimize <name>":\n\n'))
909 934 for i in unusedoptimize:
910 935 ui.write(_('%s\n %s\n\n') % (i.name, i.description))
911 936 return
912 937
913 938 # Else we're in the run=true case.
914 939 ui.write(_('upgrade will perform the following actions:\n\n'))
915 940 printrequirements()
916 941 printupgradeactions()
917 942
918 943 upgradeactions = [a.name for a in actions]
919 944
920 945 ui.write(_('beginning upgrade...\n'))
921 946 with repo.wlock(), repo.lock():
922 947 ui.write(_('repository locked and read-only\n'))
923 948 # Our strategy for upgrading the repository is to create a new,
924 949 # temporary repository, write data to it, then do a swap of the
925 950 # data. There are less heavyweight ways to do this, but it is easier
926 951 # to create a new repo object than to instantiate all the components
927 952 # (like the store) separately.
928 953 tmppath = pycompat.mkdtemp(prefix='upgrade.', dir=repo.path)
929 954 backuppath = None
930 955 try:
931 956 ui.write(_('creating temporary repository to stage migrated '
932 957 'data: %s\n') % tmppath)
933 958
934 959 # clone ui without using ui.copy because repo.ui is protected
935 960 repoui = repo.ui.__class__(repo.ui)
936 961 dstrepo = hg.repository(repoui, path=tmppath, create=True)
937 962
938 963 with dstrepo.wlock(), dstrepo.lock():
939 964 backuppath = _upgraderepo(ui, repo, dstrepo, newreqs,
940 965 upgradeactions)
941 966 if not (backup or backuppath is None):
942 967 ui.write(_('removing old repository content%s\n') % backuppath)
943 968 repo.vfs.rmtree(backuppath, forcibly=True)
944 969 backuppath = None
945 970
946 971 finally:
947 972 ui.write(_('removing temporary repository %s\n') % tmppath)
948 973 repo.vfs.rmtree(tmppath, forcibly=True)
949 974
950 975 if backuppath:
951 976 ui.warn(_('copy of old repository backed up at %s\n') %
952 977 backuppath)
953 978 ui.warn(_('the old repository will not be deleted; remove '
954 979 'it to free up disk space once the upgraded '
955 980 'repository is verified\n'))
@@ -1,857 +1,931
1 1 #require no-reposimplestore
2 2
3 3 $ cat >> $HGRCPATH << EOF
4 4 > [extensions]
5 5 > share =
6 6 > EOF
7 7
8 8 store and revlogv1 are required in source
9 9
10 10 $ hg --config format.usestore=false init no-store
11 11 $ hg -R no-store debugupgraderepo
12 12 abort: cannot upgrade repository; requirement missing: store
13 13 [255]
14 14
15 15 $ hg init no-revlogv1
16 16 $ cat > no-revlogv1/.hg/requires << EOF
17 17 > dotencode
18 18 > fncache
19 19 > generaldelta
20 20 > store
21 21 > EOF
22 22
23 23 $ hg -R no-revlogv1 debugupgraderepo
24 24 abort: cannot upgrade repository; requirement missing: revlogv1
25 25 [255]
26 26
27 27 Cannot upgrade shared repositories
28 28
29 29 $ hg init share-parent
30 30 $ hg -q share share-parent share-child
31 31
32 32 $ hg -R share-child debugupgraderepo
33 33 abort: cannot upgrade repository; unsupported source requirement: shared
34 34 [255]
35 35
36 36 Do not yet support upgrading treemanifest repos
37 37
38 38 $ hg --config experimental.treemanifest=true init treemanifest
39 39 $ hg -R treemanifest debugupgraderepo
40 40 abort: cannot upgrade repository; unsupported source requirement: treemanifest
41 41 [255]
42 42
43 43 Cannot add treemanifest requirement during upgrade
44 44
45 45 $ hg init disallowaddedreq
46 46 $ hg -R disallowaddedreq --config experimental.treemanifest=true debugupgraderepo
47 47 abort: cannot upgrade repository; do not support adding requirement: treemanifest
48 48 [255]
49 49
50 50 An upgrade of a repository created with recommended settings only suggests optimizations
51 51
52 52 $ hg init empty
53 53 $ cd empty
54 54 $ hg debugformat
55 55 format-variant repo
56 56 fncache: yes
57 57 dotencode: yes
58 58 generaldelta: yes
59 59 sparserevlog: yes
60 60 plain-cl-delta: yes
61 61 compression: zlib
62 62 compression-level: default
63 63 $ hg debugformat --verbose
64 64 format-variant repo config default
65 65 fncache: yes yes yes
66 66 dotencode: yes yes yes
67 67 generaldelta: yes yes yes
68 68 sparserevlog: yes yes yes
69 69 plain-cl-delta: yes yes yes
70 70 compression: zlib zlib zlib
71 71 compression-level: default default default
72 72 $ hg debugformat --verbose --config format.usefncache=no
73 73 format-variant repo config default
74 74 fncache: yes no yes
75 75 dotencode: yes no yes
76 76 generaldelta: yes yes yes
77 77 sparserevlog: yes yes yes
78 78 plain-cl-delta: yes yes yes
79 79 compression: zlib zlib zlib
80 80 compression-level: default default default
81 81 $ hg debugformat --verbose --config format.usefncache=no --color=debug
82 82 format-variant repo config default
83 83 [formatvariant.name.mismatchconfig|fncache: ][formatvariant.repo.mismatchconfig| yes][formatvariant.config.special| no][formatvariant.default| yes]
84 84 [formatvariant.name.mismatchconfig|dotencode: ][formatvariant.repo.mismatchconfig| yes][formatvariant.config.special| no][formatvariant.default| yes]
85 85 [formatvariant.name.uptodate|generaldelta: ][formatvariant.repo.uptodate| yes][formatvariant.config.default| yes][formatvariant.default| yes]
86 86 [formatvariant.name.uptodate|sparserevlog: ][formatvariant.repo.uptodate| yes][formatvariant.config.default| yes][formatvariant.default| yes]
87 87 [formatvariant.name.uptodate|plain-cl-delta: ][formatvariant.repo.uptodate| yes][formatvariant.config.default| yes][formatvariant.default| yes]
88 88 [formatvariant.name.uptodate|compression: ][formatvariant.repo.uptodate| zlib][formatvariant.config.default| zlib][formatvariant.default| zlib]
89 89 [formatvariant.name.uptodate|compression-level:][formatvariant.repo.uptodate| default][formatvariant.config.default| default][formatvariant.default| default]
90 90 $ hg debugformat -Tjson
91 91 [
92 92 {
93 93 "config": true,
94 94 "default": true,
95 95 "name": "fncache",
96 96 "repo": true
97 97 },
98 98 {
99 99 "config": true,
100 100 "default": true,
101 101 "name": "dotencode",
102 102 "repo": true
103 103 },
104 104 {
105 105 "config": true,
106 106 "default": true,
107 107 "name": "generaldelta",
108 108 "repo": true
109 109 },
110 110 {
111 111 "config": true,
112 112 "default": true,
113 113 "name": "sparserevlog",
114 114 "repo": true
115 115 },
116 116 {
117 117 "config": true,
118 118 "default": true,
119 119 "name": "plain-cl-delta",
120 120 "repo": true
121 121 },
122 122 {
123 123 "config": "zlib",
124 124 "default": "zlib",
125 125 "name": "compression",
126 126 "repo": "zlib"
127 127 },
128 128 {
129 129 "config": "default",
130 130 "default": "default",
131 131 "name": "compression-level",
132 132 "repo": "default"
133 133 }
134 134 ]
135 135 $ hg debugupgraderepo
136 136 (no feature deficiencies found in existing repository)
137 137 performing an upgrade with "--run" will make the following changes:
138 138
139 139 requirements
140 140 preserved: dotencode, fncache, generaldelta, revlogv1, sparserevlog, store
141 141
142 142 additional optimizations are available by specifying "--optimize <name>":
143 143
144 144 re-delta-parent
145 145 deltas within internal storage will be recalculated to choose an optimal base revision where this was not already done; the size of the repository may shrink and various operations may become faster; the first time this optimization is performed could slow down upgrade execution considerably; subsequent invocations should not run noticeably slower
146 146
147 147 re-delta-multibase
148 148 deltas within internal storage will be recalculated against multiple base revision and the smallest difference will be used; the size of the repository may shrink significantly when there are many merges; this optimization will slow down execution in proportion to the number of merges in the repository and the amount of files in the repository; this slow down should not be significant unless there are tens of thousands of files and thousands of merges
149 149
150 150 re-delta-all
151 151 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
152 152
153 153 re-delta-fulladd
154 154 every revision will be re-added as if it was new content. It will go through the full storage mechanism giving extensions a chance to process it (eg. lfs). This is similar to "re-delta-all" but even slower since more logic is involved.
155 155
156 156
157 157 --optimize can be used to add optimizations
158 158
159 159 $ hg debugupgrade --optimize redeltaparent
160 160 (no feature deficiencies found in existing repository)
161 161 performing an upgrade with "--run" will make the following changes:
162 162
163 163 requirements
164 164 preserved: dotencode, fncache, generaldelta, revlogv1, sparserevlog, store
165 165
166 166 re-delta-parent
167 167 deltas within internal storage will choose a new base revision if needed
168 168
169 169 additional optimizations are available by specifying "--optimize <name>":
170 170
171 171 re-delta-multibase
172 172 deltas within internal storage will be recalculated against multiple base revision and the smallest difference will be used; the size of the repository may shrink significantly when there are many merges; this optimization will slow down execution in proportion to the number of merges in the repository and the amount of files in the repository; this slow down should not be significant unless there are tens of thousands of files and thousands of merges
173 173
174 174 re-delta-all
175 175 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
176 176
177 177 re-delta-fulladd
178 178 every revision will be re-added as if it was new content. It will go through the full storage mechanism giving extensions a chance to process it (eg. lfs). This is similar to "re-delta-all" but even slower since more logic is involved.
179 179
180 180
181 181 modern form of the option
182 182
183 183 $ hg debugupgrade --optimize re-delta-parent
184 184 (no feature deficiencies found in existing repository)
185 185 performing an upgrade with "--run" will make the following changes:
186 186
187 187 requirements
188 188 preserved: dotencode, fncache, generaldelta, revlogv1, sparserevlog, store
189 189
190 190 re-delta-parent
191 191 deltas within internal storage will choose a new base revision if needed
192 192
193 193 additional optimizations are available by specifying "--optimize <name>":
194 194
195 195 re-delta-multibase
196 196 deltas within internal storage will be recalculated against multiple base revision and the smallest difference will be used; the size of the repository may shrink significantly when there are many merges; this optimization will slow down execution in proportion to the number of merges in the repository and the amount of files in the repository; this slow down should not be significant unless there are tens of thousands of files and thousands of merges
197 197
198 198 re-delta-all
199 199 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
200 200
201 201 re-delta-fulladd
202 202 every revision will be re-added as if it was new content. It will go through the full storage mechanism giving extensions a chance to process it (eg. lfs). This is similar to "re-delta-all" but even slower since more logic is involved.
203 203
204 204
205 205 unknown optimization:
206 206
207 207 $ hg debugupgrade --optimize foobar
208 208 abort: unknown optimization action requested: foobar
209 209 (run without arguments to see valid optimizations)
210 210 [255]
211 211
212 212 Various sub-optimal detections work
213 213
214 214 $ cat > .hg/requires << EOF
215 215 > revlogv1
216 216 > store
217 217 > EOF
218 218
219 219 $ hg debugformat
220 220 format-variant repo
221 221 fncache: no
222 222 dotencode: no
223 223 generaldelta: no
224 224 sparserevlog: no
225 225 plain-cl-delta: yes
226 226 compression: zlib
227 227 compression-level: default
228 228 $ hg debugformat --verbose
229 229 format-variant repo config default
230 230 fncache: no yes yes
231 231 dotencode: no yes yes
232 232 generaldelta: no yes yes
233 233 sparserevlog: no yes yes
234 234 plain-cl-delta: yes yes yes
235 235 compression: zlib zlib zlib
236 236 compression-level: default default default
237 237 $ hg debugformat --verbose --config format.usegeneraldelta=no
238 238 format-variant repo config default
239 239 fncache: no yes yes
240 240 dotencode: no yes yes
241 241 generaldelta: no no yes
242 242 sparserevlog: no no yes
243 243 plain-cl-delta: yes yes yes
244 244 compression: zlib zlib zlib
245 245 compression-level: default default default
246 246 $ hg debugformat --verbose --config format.usegeneraldelta=no --color=debug
247 247 format-variant repo config default
248 248 [formatvariant.name.mismatchconfig|fncache: ][formatvariant.repo.mismatchconfig| no][formatvariant.config.default| yes][formatvariant.default| yes]
249 249 [formatvariant.name.mismatchconfig|dotencode: ][formatvariant.repo.mismatchconfig| no][formatvariant.config.default| yes][formatvariant.default| yes]
250 250 [formatvariant.name.mismatchdefault|generaldelta: ][formatvariant.repo.mismatchdefault| no][formatvariant.config.special| no][formatvariant.default| yes]
251 251 [formatvariant.name.mismatchdefault|sparserevlog: ][formatvariant.repo.mismatchdefault| no][formatvariant.config.special| no][formatvariant.default| yes]
252 252 [formatvariant.name.uptodate|plain-cl-delta: ][formatvariant.repo.uptodate| yes][formatvariant.config.default| yes][formatvariant.default| yes]
253 253 [formatvariant.name.uptodate|compression: ][formatvariant.repo.uptodate| zlib][formatvariant.config.default| zlib][formatvariant.default| zlib]
254 254 [formatvariant.name.uptodate|compression-level:][formatvariant.repo.uptodate| default][formatvariant.config.default| default][formatvariant.default| default]
255 255 $ hg debugupgraderepo
256 256 repository lacks features recommended by current config options:
257 257
258 258 fncache
259 259 long and reserved filenames may not work correctly; repository performance is sub-optimal
260 260
261 261 dotencode
262 262 storage of filenames beginning with a period or space may not work correctly
263 263
264 264 generaldelta
265 265 deltas within internal storage are unable to choose optimal revisions; repository is larger and slower than it could be; interaction with other repositories may require extra network and CPU resources, making "hg push" and "hg pull" slower
266 266
267 267 sparserevlog
268 268 in order to limit disk reading and memory usage on older version, the span of a delta chain from its root to its end is limited, whatever the relevant data in this span. This can severly limit Mercurial ability to build good chain of delta resulting is much more storage space being taken and limit reusability of on disk delta during exchange.
269 269
270 270
271 271 performing an upgrade with "--run" will make the following changes:
272 272
273 273 requirements
274 274 preserved: revlogv1, store
275 275 added: dotencode, fncache, generaldelta, sparserevlog
276 276
277 277 fncache
278 278 repository will be more resilient to storing certain paths and performance of certain operations should be improved
279 279
280 280 dotencode
281 281 repository will be better able to store files beginning with a space or period
282 282
283 283 generaldelta
284 284 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
285 285
286 286 sparserevlog
287 287 Revlog supports delta chain with more unused data between payload. These gaps will be skipped at read time. This allows for better delta chains, making a better compression and faster exchange with server.
288 288
289 289 additional optimizations are available by specifying "--optimize <name>":
290 290
291 291 re-delta-parent
292 292 deltas within internal storage will be recalculated to choose an optimal base revision where this was not already done; the size of the repository may shrink and various operations may become faster; the first time this optimization is performed could slow down upgrade execution considerably; subsequent invocations should not run noticeably slower
293 293
294 294 re-delta-multibase
295 295 deltas within internal storage will be recalculated against multiple base revision and the smallest difference will be used; the size of the repository may shrink significantly when there are many merges; this optimization will slow down execution in proportion to the number of merges in the repository and the amount of files in the repository; this slow down should not be significant unless there are tens of thousands of files and thousands of merges
296 296
297 297 re-delta-all
298 298 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
299 299
300 300 re-delta-fulladd
301 301 every revision will be re-added as if it was new content. It will go through the full storage mechanism giving extensions a chance to process it (eg. lfs). This is similar to "re-delta-all" but even slower since more logic is involved.
302 302
303 303
304 304 $ hg --config format.dotencode=false debugupgraderepo
305 305 repository lacks features recommended by current config options:
306 306
307 307 fncache
308 308 long and reserved filenames may not work correctly; repository performance is sub-optimal
309 309
310 310 generaldelta
311 311 deltas within internal storage are unable to choose optimal revisions; repository is larger and slower than it could be; interaction with other repositories may require extra network and CPU resources, making "hg push" and "hg pull" slower
312 312
313 313 sparserevlog
314 314 in order to limit disk reading and memory usage on older version, the span of a delta chain from its root to its end is limited, whatever the relevant data in this span. This can severly limit Mercurial ability to build good chain of delta resulting is much more storage space being taken and limit reusability of on disk delta during exchange.
315 315
316 316 repository lacks features used by the default config options:
317 317
318 318 dotencode
319 319 storage of filenames beginning with a period or space may not work correctly
320 320
321 321
322 322 performing an upgrade with "--run" will make the following changes:
323 323
324 324 requirements
325 325 preserved: revlogv1, store
326 326 added: fncache, generaldelta, sparserevlog
327 327
328 328 fncache
329 329 repository will be more resilient to storing certain paths and performance of certain operations should be improved
330 330
331 331 generaldelta
332 332 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
333 333
334 334 sparserevlog
335 335 Revlog supports delta chain with more unused data between payload. These gaps will be skipped at read time. This allows for better delta chains, making a better compression and faster exchange with server.
336 336
337 337 additional optimizations are available by specifying "--optimize <name>":
338 338
339 339 re-delta-parent
340 340 deltas within internal storage will be recalculated to choose an optimal base revision where this was not already done; the size of the repository may shrink and various operations may become faster; the first time this optimization is performed could slow down upgrade execution considerably; subsequent invocations should not run noticeably slower
341 341
342 342 re-delta-multibase
343 343 deltas within internal storage will be recalculated against multiple base revision and the smallest difference will be used; the size of the repository may shrink significantly when there are many merges; this optimization will slow down execution in proportion to the number of merges in the repository and the amount of files in the repository; this slow down should not be significant unless there are tens of thousands of files and thousands of merges
344 344
345 345 re-delta-all
346 346 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
347 347
348 348 re-delta-fulladd
349 349 every revision will be re-added as if it was new content. It will go through the full storage mechanism giving extensions a chance to process it (eg. lfs). This is similar to "re-delta-all" but even slower since more logic is involved.
350 350
351 351
352 352 $ cd ..
353 353
354 354 Upgrading a repository that is already modern essentially no-ops
355 355
356 356 $ hg init modern
357 357 $ hg -R modern debugupgraderepo --run
358 358 upgrade will perform the following actions:
359 359
360 360 requirements
361 361 preserved: dotencode, fncache, generaldelta, revlogv1, sparserevlog, store
362 362
363 363 beginning upgrade...
364 364 repository locked and read-only
365 365 creating temporary repository to stage migrated data: $TESTTMP/modern/.hg/upgrade.* (glob)
366 366 (it is safe to interrupt this process any time before data migration completes)
367 367 data fully migrated to temporary repository
368 368 marking source repository as being upgraded; clients will be unable to read from repository
369 369 starting in-place swap of repository data
370 370 replaced files will be backed up at $TESTTMP/modern/.hg/upgradebackup.* (glob)
371 371 replacing store...
372 372 store replacement complete; repository was inconsistent for *s (glob)
373 373 finalizing requirements file and making repository readable again
374 374 removing temporary repository $TESTTMP/modern/.hg/upgrade.* (glob)
375 375 copy of old repository backed up at $TESTTMP/modern/.hg/upgradebackup.* (glob)
376 376 the old repository will not be deleted; remove it to free up disk space once the upgraded repository is verified
377 377
378 378 Upgrading a repository to generaldelta works
379 379
380 380 $ hg --config format.usegeneraldelta=false init upgradegd
381 381 $ cd upgradegd
382 382 $ touch f0
383 383 $ hg -q commit -A -m initial
384 384 $ touch f1
385 385 $ hg -q commit -A -m 'add f1'
386 386 $ hg -q up -r 0
387 387 $ touch f2
388 388 $ hg -q commit -A -m 'add f2'
389 389
390 390 $ hg debugupgraderepo --run --config format.sparse-revlog=false
391 391 upgrade will perform the following actions:
392 392
393 393 requirements
394 394 preserved: dotencode, fncache, revlogv1, store
395 395 added: generaldelta
396 396
397 397 generaldelta
398 398 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
399 399
400 400 beginning upgrade...
401 401 repository locked and read-only
402 402 creating temporary repository to stage migrated data: $TESTTMP/upgradegd/.hg/upgrade.* (glob)
403 403 (it is safe to interrupt this process any time before data migration completes)
404 404 migrating 9 total revisions (3 in filelogs, 3 in manifests, 3 in changelog)
405 405 migrating 917 bytes in store; 401 bytes tracked data
406 406 migrating 3 filelogs containing 3 revisions (192 bytes in store; 0 bytes tracked data)
407 407 finished migrating 3 filelog revisions across 3 filelogs; change in size: 0 bytes
408 408 migrating 1 manifests containing 3 revisions (349 bytes in store; 220 bytes tracked data)
409 409 finished migrating 3 manifest revisions across 1 manifests; change in size: 0 bytes
410 410 migrating changelog containing 3 revisions (376 bytes in store; 181 bytes tracked data)
411 411 finished migrating 3 changelog revisions; change in size: 0 bytes
412 412 finished migrating 9 total revisions; total change in store size: 0 bytes
413 413 copying phaseroots
414 414 data fully migrated to temporary repository
415 415 marking source repository as being upgraded; clients will be unable to read from repository
416 416 starting in-place swap of repository data
417 417 replaced files will be backed up at $TESTTMP/upgradegd/.hg/upgradebackup.* (glob)
418 418 replacing store...
419 419 store replacement complete; repository was inconsistent for *s (glob)
420 420 finalizing requirements file and making repository readable again
421 421 removing temporary repository $TESTTMP/upgradegd/.hg/upgrade.* (glob)
422 422 copy of old repository backed up at $TESTTMP/upgradegd/.hg/upgradebackup.* (glob)
423 423 the old repository will not be deleted; remove it to free up disk space once the upgraded repository is verified
424 424
425 425 Original requirements backed up
426 426
427 427 $ cat .hg/upgradebackup.*/requires
428 428 dotencode
429 429 fncache
430 430 revlogv1
431 431 store
432 432
433 433 generaldelta added to original requirements files
434 434
435 435 $ cat .hg/requires
436 436 dotencode
437 437 fncache
438 438 generaldelta
439 439 revlogv1
440 440 store
441 441
442 442 store directory has files we expect
443 443
444 444 $ ls .hg/store
445 445 00changelog.i
446 446 00manifest.i
447 447 data
448 448 fncache
449 449 phaseroots
450 450 undo
451 451 undo.backupfiles
452 452 undo.phaseroots
453 453
454 454 manifest should be generaldelta
455 455
456 456 $ hg debugrevlog -m | grep flags
457 457 flags : inline, generaldelta
458 458
459 459 verify should be happy
460 460
461 461 $ hg verify
462 462 checking changesets
463 463 checking manifests
464 464 crosschecking files in changesets and manifests
465 465 checking files
466 466 checked 3 changesets with 3 changes to 3 files
467 467
468 468 old store should be backed up
469 469
470 470 $ ls -d .hg/upgradebackup.*/
471 471 .hg/upgradebackup.*/ (glob)
472 472 $ ls .hg/upgradebackup.*/store
473 473 00changelog.i
474 474 00manifest.i
475 475 data
476 476 fncache
477 477 phaseroots
478 478 undo
479 479 undo.backup.fncache
480 480 undo.backupfiles
481 481 undo.phaseroots
482 482
483 483 unless --no-backup is passed
484 484
485 485 $ rm -rf .hg/upgradebackup.*/
486 486 $ hg debugupgraderepo --run --no-backup
487 487 upgrade will perform the following actions:
488 488
489 489 requirements
490 490 preserved: dotencode, fncache, generaldelta, revlogv1, store
491 491 added: sparserevlog
492 492
493 493 sparserevlog
494 494 Revlog supports delta chain with more unused data between payload. These gaps will be skipped at read time. This allows for better delta chains, making a better compression and faster exchange with server.
495 495
496 496 beginning upgrade...
497 497 repository locked and read-only
498 498 creating temporary repository to stage migrated data: $TESTTMP/upgradegd/.hg/upgrade.* (glob)
499 499 (it is safe to interrupt this process any time before data migration completes)
500 500 migrating 9 total revisions (3 in filelogs, 3 in manifests, 3 in changelog)
501 501 migrating 917 bytes in store; 401 bytes tracked data
502 502 migrating 3 filelogs containing 3 revisions (192 bytes in store; 0 bytes tracked data)
503 503 finished migrating 3 filelog revisions across 3 filelogs; change in size: 0 bytes
504 504 migrating 1 manifests containing 3 revisions (349 bytes in store; 220 bytes tracked data)
505 505 finished migrating 3 manifest revisions across 1 manifests; change in size: 0 bytes
506 506 migrating changelog containing 3 revisions (376 bytes in store; 181 bytes tracked data)
507 507 finished migrating 3 changelog revisions; change in size: 0 bytes
508 508 finished migrating 9 total revisions; total change in store size: 0 bytes
509 509 copying phaseroots
510 510 data fully migrated to temporary repository
511 511 marking source repository as being upgraded; clients will be unable to read from repository
512 512 starting in-place swap of repository data
513 513 replaced files will be backed up at $TESTTMP/upgradegd/.hg/upgradebackup.* (glob)
514 514 replacing store...
515 515 store replacement complete; repository was inconsistent for * (glob)
516 516 finalizing requirements file and making repository readable again
517 517 removing old repository content$TESTTMP/upgradegd/.hg/upgradebackup.* (glob)
518 518 removing temporary repository $TESTTMP/upgradegd/.hg/upgrade.* (glob)
519 519 $ ls -1 .hg/ | grep upgradebackup
520 520 [1]
521 521 $ cd ..
522 522
523 523
524 524 store files with special filenames aren't encoded during copy
525 525
526 526 $ hg init store-filenames
527 527 $ cd store-filenames
528 528 $ touch foo
529 529 $ hg -q commit -A -m initial
530 530 $ touch .hg/store/.XX_special_filename
531 531
532 532 $ hg debugupgraderepo --run
533 533 upgrade will perform the following actions:
534 534
535 535 requirements
536 536 preserved: dotencode, fncache, generaldelta, revlogv1, sparserevlog, store
537 537
538 538 beginning upgrade...
539 539 repository locked and read-only
540 540 creating temporary repository to stage migrated data: $TESTTMP/store-filenames/.hg/upgrade.* (glob)
541 541 (it is safe to interrupt this process any time before data migration completes)
542 542 migrating 3 total revisions (1 in filelogs, 1 in manifests, 1 in changelog)
543 543 migrating 301 bytes in store; 107 bytes tracked data
544 544 migrating 1 filelogs containing 1 revisions (64 bytes in store; 0 bytes tracked data)
545 545 finished migrating 1 filelog revisions across 1 filelogs; change in size: 0 bytes
546 546 migrating 1 manifests containing 1 revisions (110 bytes in store; 45 bytes tracked data)
547 547 finished migrating 1 manifest revisions across 1 manifests; change in size: 0 bytes
548 548 migrating changelog containing 1 revisions (127 bytes in store; 62 bytes tracked data)
549 549 finished migrating 1 changelog revisions; change in size: 0 bytes
550 550 finished migrating 3 total revisions; total change in store size: 0 bytes
551 551 copying .XX_special_filename
552 552 copying phaseroots
553 553 data fully migrated to temporary repository
554 554 marking source repository as being upgraded; clients will be unable to read from repository
555 555 starting in-place swap of repository data
556 556 replaced files will be backed up at $TESTTMP/store-filenames/.hg/upgradebackup.* (glob)
557 557 replacing store...
558 558 store replacement complete; repository was inconsistent for *s (glob)
559 559 finalizing requirements file and making repository readable again
560 560 removing temporary repository $TESTTMP/store-filenames/.hg/upgrade.* (glob)
561 561 copy of old repository backed up at $TESTTMP/store-filenames/.hg/upgradebackup.* (glob)
562 562 the old repository will not be deleted; remove it to free up disk space once the upgraded repository is verified
563 563 $ hg debugupgraderepo --run --optimize redeltafulladd
564 564 upgrade will perform the following actions:
565 565
566 566 requirements
567 567 preserved: dotencode, fncache, generaldelta, revlogv1, sparserevlog, store
568 568
569 569 re-delta-fulladd
570 570 each revision will be added as new content to the internal storage; this will likely drastically slow down execution time, but some extensions might need it
571 571
572 572 beginning upgrade...
573 573 repository locked and read-only
574 574 creating temporary repository to stage migrated data: $TESTTMP/store-filenames/.hg/upgrade.* (glob)
575 575 (it is safe to interrupt this process any time before data migration completes)
576 576 migrating 3 total revisions (1 in filelogs, 1 in manifests, 1 in changelog)
577 577 migrating 301 bytes in store; 107 bytes tracked data
578 578 migrating 1 filelogs containing 1 revisions (64 bytes in store; 0 bytes tracked data)
579 579 finished migrating 1 filelog revisions across 1 filelogs; change in size: 0 bytes
580 580 migrating 1 manifests containing 1 revisions (110 bytes in store; 45 bytes tracked data)
581 581 finished migrating 1 manifest revisions across 1 manifests; change in size: 0 bytes
582 582 migrating changelog containing 1 revisions (127 bytes in store; 62 bytes tracked data)
583 583 finished migrating 1 changelog revisions; change in size: 0 bytes
584 584 finished migrating 3 total revisions; total change in store size: 0 bytes
585 585 copying .XX_special_filename
586 586 copying phaseroots
587 587 data fully migrated to temporary repository
588 588 marking source repository as being upgraded; clients will be unable to read from repository
589 589 starting in-place swap of repository data
590 590 replaced files will be backed up at $TESTTMP/store-filenames/.hg/upgradebackup.* (glob)
591 591 replacing store...
592 592 store replacement complete; repository was inconsistent for *s (glob)
593 593 finalizing requirements file and making repository readable again
594 594 removing temporary repository $TESTTMP/store-filenames/.hg/upgrade.* (glob)
595 595 copy of old repository backed up at $TESTTMP/store-filenames/.hg/upgradebackup.* (glob)
596 596 the old repository will not be deleted; remove it to free up disk space once the upgraded repository is verified
597 597
598 598 fncache is valid after upgrade
599 599
600 600 $ hg debugrebuildfncache
601 601 fncache already up to date
602 602
603 603 $ cd ..
604 604
605 605 Check upgrading a large file repository
606 606 ---------------------------------------
607 607
608 608 $ hg init largefilesrepo
609 609 $ cat << EOF >> largefilesrepo/.hg/hgrc
610 610 > [extensions]
611 611 > largefiles =
612 612 > EOF
613 613
614 614 $ cd largefilesrepo
615 615 $ touch foo
616 616 $ hg add --large foo
617 617 $ hg -q commit -m initial
618 618 $ cat .hg/requires
619 619 dotencode
620 620 fncache
621 621 generaldelta
622 622 largefiles
623 623 revlogv1
624 624 sparserevlog
625 625 store
626 626
627 627 $ hg debugupgraderepo --run
628 628 upgrade will perform the following actions:
629 629
630 630 requirements
631 631 preserved: dotencode, fncache, generaldelta, largefiles, revlogv1, sparserevlog, store
632 632
633 633 beginning upgrade...
634 634 repository locked and read-only
635 635 creating temporary repository to stage migrated data: $TESTTMP/largefilesrepo/.hg/upgrade.* (glob)
636 636 (it is safe to interrupt this process any time before data migration completes)
637 637 migrating 3 total revisions (1 in filelogs, 1 in manifests, 1 in changelog)
638 638 migrating 355 bytes in store; 160 bytes tracked data
639 639 migrating 1 filelogs containing 1 revisions (106 bytes in store; 41 bytes tracked data)
640 640 finished migrating 1 filelog revisions across 1 filelogs; change in size: 0 bytes
641 641 migrating 1 manifests containing 1 revisions (116 bytes in store; 51 bytes tracked data)
642 642 finished migrating 1 manifest revisions across 1 manifests; change in size: 0 bytes
643 643 migrating changelog containing 1 revisions (133 bytes in store; 68 bytes tracked data)
644 644 finished migrating 1 changelog revisions; change in size: 0 bytes
645 645 finished migrating 3 total revisions; total change in store size: 0 bytes
646 646 copying phaseroots
647 647 data fully migrated to temporary repository
648 648 marking source repository as being upgraded; clients will be unable to read from repository
649 649 starting in-place swap of repository data
650 650 replaced files will be backed up at $TESTTMP/largefilesrepo/.hg/upgradebackup.* (glob)
651 651 replacing store...
652 652 store replacement complete; repository was inconsistent for *s (glob)
653 653 finalizing requirements file and making repository readable again
654 654 removing temporary repository $TESTTMP/largefilesrepo/.hg/upgrade.* (glob)
655 655 copy of old repository backed up at $TESTTMP/largefilesrepo/.hg/upgradebackup.* (glob)
656 656 the old repository will not be deleted; remove it to free up disk space once the upgraded repository is verified
657 657 $ cat .hg/requires
658 658 dotencode
659 659 fncache
660 660 generaldelta
661 661 largefiles
662 662 revlogv1
663 663 sparserevlog
664 664 store
665 665
666 666 $ cat << EOF >> .hg/hgrc
667 667 > [extensions]
668 668 > lfs =
669 669 > [lfs]
670 670 > threshold = 10
671 671 > EOF
672 672 $ echo '123456789012345' > lfs.bin
673 673 $ hg ci -Am 'lfs.bin'
674 674 adding lfs.bin
675 675 $ grep lfs .hg/requires
676 676 lfs
677 677 $ find .hg/store/lfs -type f
678 678 .hg/store/lfs/objects/d0/beab232adff5ba365880366ad30b1edb85c4c5372442b5d2fe27adc96d653f
679 679
680 680 $ hg debugupgraderepo --run
681 681 upgrade will perform the following actions:
682 682
683 683 requirements
684 684 preserved: dotencode, fncache, generaldelta, largefiles, lfs, revlogv1, sparserevlog, store
685 685
686 686 beginning upgrade...
687 687 repository locked and read-only
688 688 creating temporary repository to stage migrated data: $TESTTMP/largefilesrepo/.hg/upgrade.* (glob)
689 689 (it is safe to interrupt this process any time before data migration completes)
690 690 migrating 6 total revisions (2 in filelogs, 2 in manifests, 2 in changelog)
691 691 migrating 801 bytes in store; 467 bytes tracked data
692 692 migrating 2 filelogs containing 2 revisions (296 bytes in store; 182 bytes tracked data)
693 693 finished migrating 2 filelog revisions across 2 filelogs; change in size: 0 bytes
694 694 migrating 1 manifests containing 2 revisions (241 bytes in store; 151 bytes tracked data)
695 695 finished migrating 2 manifest revisions across 1 manifests; change in size: 0 bytes
696 696 migrating changelog containing 2 revisions (264 bytes in store; 134 bytes tracked data)
697 697 finished migrating 2 changelog revisions; change in size: 0 bytes
698 698 finished migrating 6 total revisions; total change in store size: 0 bytes
699 699 copying phaseroots
700 700 copying lfs blob d0beab232adff5ba365880366ad30b1edb85c4c5372442b5d2fe27adc96d653f
701 701 data fully migrated to temporary repository
702 702 marking source repository as being upgraded; clients will be unable to read from repository
703 703 starting in-place swap of repository data
704 704 replaced files will be backed up at $TESTTMP/largefilesrepo/.hg/upgradebackup.* (glob)
705 705 replacing store...
706 706 store replacement complete; repository was inconsistent for *s (glob)
707 707 finalizing requirements file and making repository readable again
708 708 removing temporary repository $TESTTMP/largefilesrepo/.hg/upgrade.* (glob)
709 709 copy of old repository backed up at $TESTTMP/largefilesrepo/.hg/upgradebackup.* (glob)
710 710 the old repository will not be deleted; remove it to free up disk space once the upgraded repository is verified
711 711
712 712 $ grep lfs .hg/requires
713 713 lfs
714 714 $ find .hg/store/lfs -type f
715 715 .hg/store/lfs/objects/d0/beab232adff5ba365880366ad30b1edb85c4c5372442b5d2fe27adc96d653f
716 716 $ hg verify
717 717 checking changesets
718 718 checking manifests
719 719 crosschecking files in changesets and manifests
720 720 checking files
721 721 checked 2 changesets with 2 changes to 2 files
722 722 $ hg debugdata lfs.bin 0
723 723 version https://git-lfs.github.com/spec/v1
724 724 oid sha256:d0beab232adff5ba365880366ad30b1edb85c4c5372442b5d2fe27adc96d653f
725 725 size 16
726 726 x-is-binary 0
727 727
728 728 $ cd ..
729 729
730 730 repository config is taken in account
731 731 -------------------------------------
732 732
733 733 $ cat << EOF >> $HGRCPATH
734 734 > [format]
735 735 > maxchainlen = 1
736 736 > EOF
737 737
738 738 $ hg init localconfig
739 739 $ cd localconfig
740 740 $ cat << EOF > file
741 741 > some content
742 742 > with some length
743 743 > to make sure we get a delta
744 744 > after changes
745 745 > very long
746 746 > very long
747 747 > very long
748 748 > very long
749 749 > very long
750 750 > very long
751 751 > very long
752 752 > very long
753 753 > very long
754 754 > very long
755 755 > very long
756 756 > EOF
757 757 $ hg -q commit -A -m A
758 758 $ echo "new line" >> file
759 759 $ hg -q commit -m B
760 760 $ echo "new line" >> file
761 761 $ hg -q commit -m C
762 762
763 763 $ cat << EOF >> .hg/hgrc
764 764 > [format]
765 765 > maxchainlen = 9001
766 766 > EOF
767 767 $ hg config format
768 768 format.maxchainlen=9001
769 769 $ hg debugdeltachain file
770 770 rev chain# chainlen prev delta size rawsize chainsize ratio lindist extradist extraratio readsize largestblk rddensity srchunks
771 771 0 1 1 -1 base 77 182 77 0.42308 77 0 0.00000 77 77 1.00000 1
772 772 1 1 2 0 p1 21 191 98 0.51309 98 0 0.00000 98 98 1.00000 1
773 773 2 1 2 0 other 30 200 107 0.53500 128 21 0.19626 128 128 0.83594 1
774 774
775 775 $ hg debugupgraderepo --run --optimize redeltaall
776 776 upgrade will perform the following actions:
777 777
778 778 requirements
779 779 preserved: dotencode, fncache, generaldelta, revlogv1, sparserevlog, store
780 780
781 781 re-delta-all
782 782 deltas within internal storage will be fully recomputed; this will likely drastically slow down execution time
783 783
784 784 beginning upgrade...
785 785 repository locked and read-only
786 786 creating temporary repository to stage migrated data: $TESTTMP/localconfig/.hg/upgrade.* (glob)
787 787 (it is safe to interrupt this process any time before data migration completes)
788 788 migrating 9 total revisions (3 in filelogs, 3 in manifests, 3 in changelog)
789 789 migrating 1019 bytes in store; 882 bytes tracked data
790 790 migrating 1 filelogs containing 3 revisions (320 bytes in store; 573 bytes tracked data)
791 791 finished migrating 3 filelog revisions across 1 filelogs; change in size: -9 bytes
792 792 migrating 1 manifests containing 3 revisions (333 bytes in store; 138 bytes tracked data)
793 793 finished migrating 3 manifest revisions across 1 manifests; change in size: 0 bytes
794 794 migrating changelog containing 3 revisions (366 bytes in store; 171 bytes tracked data)
795 795 finished migrating 3 changelog revisions; change in size: 0 bytes
796 796 finished migrating 9 total revisions; total change in store size: -9 bytes
797 797 copying phaseroots
798 798 data fully migrated to temporary repository
799 799 marking source repository as being upgraded; clients will be unable to read from repository
800 800 starting in-place swap of repository data
801 801 replaced files will be backed up at $TESTTMP/localconfig/.hg/upgradebackup.* (glob)
802 802 replacing store...
803 803 store replacement complete; repository was inconsistent for *s (glob)
804 804 finalizing requirements file and making repository readable again
805 805 removing temporary repository $TESTTMP/localconfig/.hg/upgrade.* (glob)
806 806 copy of old repository backed up at $TESTTMP/localconfig/.hg/upgradebackup.* (glob)
807 807 the old repository will not be deleted; remove it to free up disk space once the upgraded repository is verified
808 808 $ hg debugdeltachain file
809 809 rev chain# chainlen prev delta size rawsize chainsize ratio lindist extradist extraratio readsize largestblk rddensity srchunks
810 810 0 1 1 -1 base 77 182 77 0.42308 77 0 0.00000 77 77 1.00000 1
811 811 1 1 2 0 p1 21 191 98 0.51309 98 0 0.00000 98 98 1.00000 1
812 812 2 1 3 1 p1 21 200 119 0.59500 119 0 0.00000 119 119 1.00000 1
813 813 $ cd ..
814 814
815 815 $ cat << EOF >> $HGRCPATH
816 816 > [format]
817 817 > maxchainlen = 9001
818 818 > EOF
819 819
820 820 Check upgrading a sparse-revlog repository
821 821 ---------------------------------------
822 822
823 823 $ hg init sparserevlogrepo --config format.sparse-revlog=no
824 824 $ cd sparserevlogrepo
825 825 $ touch foo
826 826 $ hg add foo
827 827 $ hg -q commit -m "foo"
828 828 $ cat .hg/requires
829 829 dotencode
830 830 fncache
831 831 generaldelta
832 832 revlogv1
833 833 store
834 834
835 835 Check that we can add the sparse-revlog format requirement
836 836 $ hg --config format.sparse-revlog=yes debugupgraderepo --run >/dev/null
837 837 copy of old repository backed up at $TESTTMP/sparserevlogrepo/.hg/upgradebackup.* (glob)
838 838 the old repository will not be deleted; remove it to free up disk space once the upgraded repository is verified
839 839 $ cat .hg/requires
840 840 dotencode
841 841 fncache
842 842 generaldelta
843 843 revlogv1
844 844 sparserevlog
845 845 store
846 846
847 847 Check that we can remove the sparse-revlog format requirement
848 848 $ hg --config format.sparse-revlog=no debugupgraderepo --run >/dev/null
849 849 copy of old repository backed up at $TESTTMP/sparserevlogrepo/.hg/upgradebackup.* (glob)
850 850 the old repository will not be deleted; remove it to free up disk space once the upgraded repository is verified
851 851 $ cat .hg/requires
852 852 dotencode
853 853 fncache
854 854 generaldelta
855 855 revlogv1
856 856 store
857
858 #if zstd
859
860 Check upgrading to a zstd revlog
861 --------------------------------
862
863 upgrade
864
865 $ hg --config format.revlog-compression=zstd debugupgraderepo --run --no-backup >/dev/null
866 $ hg debugformat -v
867 format-variant repo config default
868 fncache: yes yes yes
869 dotencode: yes yes yes
870 generaldelta: yes yes yes
871 sparserevlog: yes yes yes
872 plain-cl-delta: yes yes yes
873 compression: zstd zlib zlib
874 compression-level: default default default
875 $ cat .hg/requires
876 dotencode
877 fncache
878 generaldelta
879 revlog-compression-zstd
880 revlogv1
881 sparserevlog
882 store
883
884 downgrade
885
886 $ hg debugupgraderepo --run --no-backup > /dev/null
887 $ hg debugformat -v
888 format-variant repo config default
889 fncache: yes yes yes
890 dotencode: yes yes yes
891 generaldelta: yes yes yes
892 sparserevlog: yes yes yes
893 plain-cl-delta: yes yes yes
894 compression: zlib zlib zlib
895 compression-level: default default default
896 $ cat .hg/requires
897 dotencode
898 fncache
899 generaldelta
900 revlogv1
901 sparserevlog
902 store
903
904 upgrade from hgrc
905
906 $ cat >> .hg/hgrc << EOF
907 > [format]
908 > revlog-compression=zstd
909 > EOF
910 $ hg debugupgraderepo --run --no-backup > /dev/null
911 $ hg debugformat -v
912 format-variant repo config default
913 fncache: yes yes yes
914 dotencode: yes yes yes
915 generaldelta: yes yes yes
916 sparserevlog: yes yes yes
917 plain-cl-delta: yes yes yes
918 compression: zstd zstd zlib
919 compression-level: default default default
920 $ cat .hg/requires
921 dotencode
922 fncache
923 generaldelta
924 revlog-compression-zstd
925 revlogv1
926 sparserevlog
927 store
928
857 929 $ cd ..
930
931 #endif
General Comments 0
You need to be logged in to leave comments. Login now