Mercurial > public > mercurial-scm > hg-stable
comparison mercurial/changelog.py @ 47759:d7515d29761d stable 5.9rc0
branching: merge default into stable
This mark the start of the 5.9 freeze.
author | Pierre-Yves David <pierre-yves.david@octobus.net> |
---|---|
date | Wed, 21 Jul 2021 22:52:09 +0200 |
parents | cac0e0621ceb |
children | 6000f5b25c9b |
comparison
equal
deleted
inserted
replaced
47054:29ea3b4c4f62 | 47759:d7515d29761d |
---|---|
9 | 9 |
10 from .i18n import _ | 10 from .i18n import _ |
11 from .node import ( | 11 from .node import ( |
12 bin, | 12 bin, |
13 hex, | 13 hex, |
14 nullid, | |
15 ) | 14 ) |
16 from .thirdparty import attr | 15 from .thirdparty import attr |
17 | 16 |
18 from . import ( | 17 from . import ( |
19 encoding, | 18 encoding, |
24 ) | 23 ) |
25 from .utils import ( | 24 from .utils import ( |
26 dateutil, | 25 dateutil, |
27 stringutil, | 26 stringutil, |
28 ) | 27 ) |
29 from .revlogutils import flagutil | 28 from .revlogutils import ( |
29 constants as revlog_constants, | |
30 flagutil, | |
31 ) | |
30 | 32 |
31 _defaultextra = {b'branch': b'default'} | 33 _defaultextra = {b'branch': b'default'} |
32 | 34 |
33 | 35 |
34 def _string_escape(text): | 36 def _string_escape(text): |
219 '_changes', | 221 '_changes', |
220 ) | 222 ) |
221 | 223 |
222 def __new__(cls, cl, text, sidedata, cpsd): | 224 def __new__(cls, cl, text, sidedata, cpsd): |
223 if not text: | 225 if not text: |
224 return _changelogrevision(extra=_defaultextra, manifest=nullid) | 226 return _changelogrevision(extra=_defaultextra, manifest=cl.nullid) |
225 | 227 |
226 self = super(changelogrevision, cls).__new__(cls) | 228 self = super(changelogrevision, cls).__new__(cls) |
227 # We could return here and implement the following as an __init__. | 229 # We could return here and implement the following as an __init__. |
228 # But doing it here is equivalent and saves an extra function call. | 230 # But doing it here is equivalent and saves an extra function call. |
229 | 231 |
391 hooks processes) accessing data before a transaction is finalized. | 393 hooks processes) accessing data before a transaction is finalized. |
392 | 394 |
393 ``concurrencychecker`` will be passed to the revlog init function, see | 395 ``concurrencychecker`` will be passed to the revlog init function, see |
394 the documentation there. | 396 the documentation there. |
395 """ | 397 """ |
396 if trypending and opener.exists(b'00changelog.i.a'): | |
397 indexfile = b'00changelog.i.a' | |
398 else: | |
399 indexfile = b'00changelog.i' | |
400 | |
401 datafile = b'00changelog.d' | |
402 revlog.revlog.__init__( | 398 revlog.revlog.__init__( |
403 self, | 399 self, |
404 opener, | 400 opener, |
405 indexfile, | 401 target=(revlog_constants.KIND_CHANGELOG, None), |
406 datafile=datafile, | 402 radix=b'00changelog', |
407 checkambig=True, | 403 checkambig=True, |
408 mmaplargeindex=True, | 404 mmaplargeindex=True, |
409 persistentnodemap=opener.options.get(b'persistent-nodemap', False), | 405 persistentnodemap=opener.options.get(b'persistent-nodemap', False), |
410 concurrencychecker=concurrencychecker, | 406 concurrencychecker=concurrencychecker, |
407 trypending=trypending, | |
411 ) | 408 ) |
412 | 409 |
413 if self._initempty and (self.version & 0xFFFF == revlog.REVLOGV1): | 410 if self._initempty and (self._format_version == revlog.REVLOGV1): |
414 # changelogs don't benefit from generaldelta. | 411 # changelogs don't benefit from generaldelta. |
415 | 412 |
416 self.version &= ~revlog.FLAG_GENERALDELTA | 413 self._format_flags &= ~revlog.FLAG_GENERALDELTA |
417 self._generaldelta = False | 414 self._generaldelta = False |
418 | 415 |
419 # Delta chains for changelogs tend to be very small because entries | 416 # Delta chains for changelogs tend to be very small because entries |
420 # tend to be small and don't delta well with each. So disable delta | 417 # tend to be small and don't delta well with each. So disable delta |
421 # chains. | 418 # chains. |
426 self._delaybuf = None | 423 self._delaybuf = None |
427 self._divert = False | 424 self._divert = False |
428 self._filteredrevs = frozenset() | 425 self._filteredrevs = frozenset() |
429 self._filteredrevs_hashcache = {} | 426 self._filteredrevs_hashcache = {} |
430 self._copiesstorage = opener.options.get(b'copies-storage') | 427 self._copiesstorage = opener.options.get(b'copies-storage') |
431 self.revlog_kind = b'changelog' | |
432 | 428 |
433 @property | 429 @property |
434 def filteredrevs(self): | 430 def filteredrevs(self): |
435 return self._filteredrevs | 431 return self._filteredrevs |
436 | 432 |
439 # Ensure all updates go through this function | 435 # Ensure all updates go through this function |
440 assert isinstance(val, frozenset) | 436 assert isinstance(val, frozenset) |
441 self._filteredrevs = val | 437 self._filteredrevs = val |
442 self._filteredrevs_hashcache = {} | 438 self._filteredrevs_hashcache = {} |
443 | 439 |
440 def _write_docket(self, tr): | |
441 if not self._delayed: | |
442 super(changelog, self)._write_docket(tr) | |
443 | |
444 def delayupdate(self, tr): | 444 def delayupdate(self, tr): |
445 """delay visibility of index updates to other readers""" | 445 """delay visibility of index updates to other readers""" |
446 | 446 if self._docket is None and not self._delayed: |
447 if not self._delayed: | |
448 if len(self) == 0: | 447 if len(self) == 0: |
449 self._divert = True | 448 self._divert = True |
450 if self._realopener.exists(self.indexfile + b'.a'): | 449 if self._realopener.exists(self._indexfile + b'.a'): |
451 self._realopener.unlink(self.indexfile + b'.a') | 450 self._realopener.unlink(self._indexfile + b'.a') |
452 self.opener = _divertopener(self._realopener, self.indexfile) | 451 self.opener = _divertopener(self._realopener, self._indexfile) |
453 else: | 452 else: |
454 self._delaybuf = [] | 453 self._delaybuf = [] |
455 self.opener = _delayopener( | 454 self.opener = _delayopener( |
456 self._realopener, self.indexfile, self._delaybuf | 455 self._realopener, self._indexfile, self._delaybuf |
457 ) | 456 ) |
457 self._segmentfile.opener = self.opener | |
458 self._segmentfile_sidedata.opener = self.opener | |
458 self._delayed = True | 459 self._delayed = True |
459 tr.addpending(b'cl-%i' % id(self), self._writepending) | 460 tr.addpending(b'cl-%i' % id(self), self._writepending) |
460 tr.addfinalize(b'cl-%i' % id(self), self._finalize) | 461 tr.addfinalize(b'cl-%i' % id(self), self._finalize) |
461 | 462 |
462 def _finalize(self, tr): | 463 def _finalize(self, tr): |
463 """finalize index updates""" | 464 """finalize index updates""" |
464 self._delayed = False | 465 self._delayed = False |
465 self.opener = self._realopener | 466 self.opener = self._realopener |
467 self._segmentfile.opener = self.opener | |
468 self._segmentfile_sidedata.opener = self.opener | |
466 # move redirected index data back into place | 469 # move redirected index data back into place |
467 if self._divert: | 470 if self._docket is not None: |
471 self._write_docket(tr) | |
472 elif self._divert: | |
468 assert not self._delaybuf | 473 assert not self._delaybuf |
469 tmpname = self.indexfile + b".a" | 474 tmpname = self._indexfile + b".a" |
470 nfile = self.opener.open(tmpname) | 475 nfile = self.opener.open(tmpname) |
471 nfile.close() | 476 nfile.close() |
472 self.opener.rename(tmpname, self.indexfile, checkambig=True) | 477 self.opener.rename(tmpname, self._indexfile, checkambig=True) |
473 elif self._delaybuf: | 478 elif self._delaybuf: |
474 fp = self.opener(self.indexfile, b'a', checkambig=True) | 479 fp = self.opener(self._indexfile, b'a', checkambig=True) |
475 fp.write(b"".join(self._delaybuf)) | 480 fp.write(b"".join(self._delaybuf)) |
476 fp.close() | 481 fp.close() |
477 self._delaybuf = None | 482 self._delaybuf = None |
478 self._divert = False | 483 self._divert = False |
479 # split when we're done | 484 # split when we're done |
480 self._enforceinlinesize(tr) | 485 self._enforceinlinesize(tr) |
481 | 486 |
482 def _writepending(self, tr): | 487 def _writepending(self, tr): |
483 """create a file containing the unfinalized state for | 488 """create a file containing the unfinalized state for |
484 pretxnchangegroup""" | 489 pretxnchangegroup""" |
490 if self._docket: | |
491 return self._docket.write(tr, pending=True) | |
485 if self._delaybuf: | 492 if self._delaybuf: |
486 # make a temporary copy of the index | 493 # make a temporary copy of the index |
487 fp1 = self._realopener(self.indexfile) | 494 fp1 = self._realopener(self._indexfile) |
488 pendingfilename = self.indexfile + b".a" | 495 pendingfilename = self._indexfile + b".a" |
489 # register as a temp file to ensure cleanup on failure | 496 # register as a temp file to ensure cleanup on failure |
490 tr.registertmp(pendingfilename) | 497 tr.registertmp(pendingfilename) |
491 # write existing data | 498 # write existing data |
492 fp2 = self._realopener(pendingfilename, b"w") | 499 fp2 = self._realopener(pendingfilename, b"w") |
493 fp2.write(fp1.read()) | 500 fp2.write(fp1.read()) |
495 fp2.write(b"".join(self._delaybuf)) | 502 fp2.write(b"".join(self._delaybuf)) |
496 fp2.close() | 503 fp2.close() |
497 # switch modes so finalize can simply rename | 504 # switch modes so finalize can simply rename |
498 self._delaybuf = None | 505 self._delaybuf = None |
499 self._divert = True | 506 self._divert = True |
500 self.opener = _divertopener(self._realopener, self.indexfile) | 507 self.opener = _divertopener(self._realopener, self._indexfile) |
508 self._segmentfile.opener = self.opener | |
509 self._segmentfile_sidedata.opener = self.opener | |
501 | 510 |
502 if self._divert: | 511 if self._divert: |
503 return True | 512 return True |
504 | 513 |
505 return False | 514 return False |
506 | 515 |
507 def _enforceinlinesize(self, tr, fp=None): | 516 def _enforceinlinesize(self, tr): |
508 if not self._delayed: | 517 if not self._delayed: |
509 revlog.revlog._enforceinlinesize(self, tr, fp) | 518 revlog.revlog._enforceinlinesize(self, tr) |
510 | 519 |
511 def read(self, nodeorrev): | 520 def read(self, nodeorrev): |
512 """Obtain data from a parsed changelog revision. | 521 """Obtain data from a parsed changelog revision. |
513 | 522 |
514 Returns a 6-tuple of: | 523 Returns a 6-tuple of: |
522 | 531 |
523 Unless you need to access all fields, consider calling | 532 Unless you need to access all fields, consider calling |
524 ``changelogrevision`` instead, as it is faster for partial object | 533 ``changelogrevision`` instead, as it is faster for partial object |
525 access. | 534 access. |
526 """ | 535 """ |
527 d, s = self._revisiondata(nodeorrev) | 536 d = self._revisiondata(nodeorrev) |
528 c = changelogrevision( | 537 sidedata = self.sidedata(nodeorrev) |
529 self, d, s, self._copiesstorage == b'changeset-sidedata' | 538 copy_sd = self._copiesstorage == b'changeset-sidedata' |
530 ) | 539 c = changelogrevision(self, d, sidedata, copy_sd) |
531 return (c.manifest, c.user, c.date, c.files, c.description, c.extra) | 540 return (c.manifest, c.user, c.date, c.files, c.description, c.extra) |
532 | 541 |
533 def changelogrevision(self, nodeorrev): | 542 def changelogrevision(self, nodeorrev): |
534 """Obtain a ``changelogrevision`` for a node or revision.""" | 543 """Obtain a ``changelogrevision`` for a node or revision.""" |
535 text, sidedata = self._revisiondata(nodeorrev) | 544 text = self._revisiondata(nodeorrev) |
545 sidedata = self.sidedata(nodeorrev) | |
536 return changelogrevision( | 546 return changelogrevision( |
537 self, text, sidedata, self._copiesstorage == b'changeset-sidedata' | 547 self, text, sidedata, self._copiesstorage == b'changeset-sidedata' |
538 ) | 548 ) |
539 | 549 |
540 def readfiles(self, nodeorrev): | 550 def readfiles(self, nodeorrev): |