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):