comparison mercurial/branchmap.py @ 43076:2372284d9457

formatting: blacken the codebase This is using my patch to black (https://github.com/psf/black/pull/826) so we don't un-wrap collection literals. Done with: hg files 'set:**.py - mercurial/thirdparty/** - "contrib/python-zstandard/**"' | xargs black -S # skip-blame mass-reformatting only # no-check-commit reformats foo_bar functions Differential Revision: https://phab.mercurial-scm.org/D6971
author Augie Fackler <augie@google.com>
date Sun, 06 Oct 2019 09:45:02 -0400
parents 3018749a71bb
children 687b865b95ad
comparison
equal deleted inserted replaced
43075:57875cf423c9 43076:2372284d9457
25 from .utils import ( 25 from .utils import (
26 repoviewutil, 26 repoviewutil,
27 stringutil, 27 stringutil,
28 ) 28 )
29 29
30 subsettable = repoviewutil. subsettable 30 subsettable = repoviewutil.subsettable
31 31
32 calcsize = struct.calcsize 32 calcsize = struct.calcsize
33 pack_into = struct.pack_into 33 pack_into = struct.pack_into
34 unpack_from = struct.unpack_from 34 unpack_from = struct.unpack_from
35 35
36 36
37 class BranchMapCache(object): 37 class BranchMapCache(object):
38 """mapping of filtered views of repo with their branchcache""" 38 """mapping of filtered views of repo with their branchcache"""
39
39 def __init__(self): 40 def __init__(self):
40 self._per_filter = {} 41 self._per_filter = {}
41 42
42 def __getitem__(self, repo): 43 def __getitem__(self, repo):
43 self.updatecache(repo) 44 self.updatecache(repo)
99 closed.append(h) 100 closed.append(h)
100 101
101 if rbheads: 102 if rbheads:
102 rtiprev = max((int(clrev(node)) for node in rbheads)) 103 rtiprev = max((int(clrev(node)) for node in rbheads))
103 cache = branchcache( 104 cache = branchcache(
104 remotebranchmap, repo[rtiprev].node(), rtiprev, 105 remotebranchmap,
105 closednodes=closed) 106 repo[rtiprev].node(),
107 rtiprev,
108 closednodes=closed,
109 )
106 110
107 # Try to stick it as low as possible 111 # Try to stick it as low as possible
108 # filter above served are unlikely to be fetch from a clone 112 # filter above served are unlikely to be fetch from a clone
109 for candidate in ('base', 'immutable', 'served'): 113 for candidate in ('base', 'immutable', 'served'):
110 rview = repo.filtered(candidate) 114 rview = repo.filtered(candidate)
114 return 118 return
115 119
116 def clear(self): 120 def clear(self):
117 self._per_filter.clear() 121 self._per_filter.clear()
118 122
123
119 def _unknownnode(node): 124 def _unknownnode(node):
120 """ raises ValueError when branchcache found a node which does not exists 125 """ raises ValueError when branchcache found a node which does not exists
121 """ 126 """
122 raise ValueError(r'node %s does not exist' % pycompat.sysstr(hex(node))) 127 raise ValueError(r'node %s does not exist' % pycompat.sysstr(hex(node)))
128
123 129
124 def _branchcachedesc(repo): 130 def _branchcachedesc(repo):
125 if repo.filtername is not None: 131 if repo.filtername is not None:
126 return 'branch cache (%s)' % repo.filtername 132 return 'branch cache (%s)' % repo.filtername
127 else: 133 else:
128 return 'branch cache' 134 return 'branch cache'
129 135
136
130 class branchcache(object): 137 class branchcache(object):
131 """A dict like object that hold branches heads cache. 138 """A dict like object that hold branches heads cache.
132 139
133 This cache is used to avoid costly computations to determine all the 140 This cache is used to avoid costly computations to determine all the
134 branch heads of a repo. 141 branch heads of a repo.
147 The open/closed state is represented by a single letter 'o' or 'c'. 154 The open/closed state is represented by a single letter 'o' or 'c'.
148 This field can be used to avoid changelog reads when determining if a 155 This field can be used to avoid changelog reads when determining if a
149 branch head closes a branch or not. 156 branch head closes a branch or not.
150 """ 157 """
151 158
152 def __init__(self, entries=(), tipnode=nullid, tiprev=nullrev, 159 def __init__(
153 filteredhash=None, closednodes=None, hasnode=None): 160 self,
161 entries=(),
162 tipnode=nullid,
163 tiprev=nullrev,
164 filteredhash=None,
165 closednodes=None,
166 hasnode=None,
167 ):
154 """ hasnode is a function which can be used to verify whether changelog 168 """ hasnode is a function which can be used to verify whether changelog
155 has a given node or not. If it's not provided, we assume that every node 169 has a given node or not. If it's not provided, we assume that every node
156 we have exists in changelog """ 170 we have exists in changelog """
157 self.tipnode = tipnode 171 self.tipnode = tipnode
158 self.tiprev = tiprev 172 self.tiprev = tiprev
236 last, lrev = bin(last), int(lrev) 250 last, lrev = bin(last), int(lrev)
237 filteredhash = None 251 filteredhash = None
238 hasnode = repo.changelog.hasnode 252 hasnode = repo.changelog.hasnode
239 if len(cachekey) > 2: 253 if len(cachekey) > 2:
240 filteredhash = bin(cachekey[2]) 254 filteredhash = bin(cachekey[2])
241 bcache = cls(tipnode=last, tiprev=lrev, filteredhash=filteredhash, 255 bcache = cls(
242 hasnode=hasnode) 256 tipnode=last,
257 tiprev=lrev,
258 filteredhash=filteredhash,
259 hasnode=hasnode,
260 )
243 if not bcache.validfor(repo): 261 if not bcache.validfor(repo):
244 # invalidate the cache 262 # invalidate the cache
245 raise ValueError(r'tip differs') 263 raise ValueError(r'tip differs')
246 bcache.load(repo, lineiter) 264 bcache.load(repo, lineiter)
247 except (IOError, OSError): 265 except (IOError, OSError):
248 return None 266 return None
249 267
250 except Exception as inst: 268 except Exception as inst:
251 if repo.ui.debugflag: 269 if repo.ui.debugflag:
252 msg = 'invalid %s: %s\n' 270 msg = 'invalid %s: %s\n'
253 repo.ui.debug(msg % (_branchcachedesc(repo), 271 repo.ui.debug(
254 pycompat.bytestr(inst))) 272 msg % (_branchcachedesc(repo), pycompat.bytestr(inst))
273 )
255 bcache = None 274 bcache = None
256 275
257 finally: 276 finally:
258 if f: 277 if f:
259 f.close() 278 f.close()
288 """Is the cache content valid regarding a repo 307 """Is the cache content valid regarding a repo
289 308
290 - False when cached tipnode is unknown or if we detect a strip. 309 - False when cached tipnode is unknown or if we detect a strip.
291 - True when cache is up to date or a subset of current repo.""" 310 - True when cache is up to date or a subset of current repo."""
292 try: 311 try:
293 return ((self.tipnode == repo.changelog.node(self.tiprev)) 312 return (self.tipnode == repo.changelog.node(self.tiprev)) and (
294 and (self.filteredhash == 313 self.filteredhash == scmutil.filteredhash(repo, self.tiprev)
295 scmutil.filteredhash(repo, self.tiprev))) 314 )
296 except IndexError: 315 except IndexError:
297 return False 316 return False
298 317
299 def _branchtip(self, heads): 318 def _branchtip(self, heads):
300 '''Return tuple with last open head in heads and false, 319 '''Return tuple with last open head in heads and false,
334 return self._entries.itervalues() 353 return self._entries.itervalues()
335 354
336 def copy(self): 355 def copy(self):
337 """return an deep copy of the branchcache object""" 356 """return an deep copy of the branchcache object"""
338 return type(self)( 357 return type(self)(
339 self._entries, self.tipnode, self.tiprev, self.filteredhash, 358 self._entries,
340 self._closednodes) 359 self.tipnode,
360 self.tiprev,
361 self.filteredhash,
362 self._closednodes,
363 )
341 364
342 def write(self, repo): 365 def write(self, repo):
343 try: 366 try:
344 f = repo.cachevfs(self._filename(repo), "w", atomictemp=True) 367 f = repo.cachevfs(self._filename(repo), "w", atomictemp=True)
345 cachekey = [hex(self.tipnode), '%d' % self.tiprev] 368 cachekey = [hex(self.tipnode), '%d' % self.tiprev]
355 state = 'c' 378 state = 'c'
356 else: 379 else:
357 state = 'o' 380 state = 'o'
358 f.write("%s %s %s\n" % (hex(node), state, label)) 381 f.write("%s %s %s\n" % (hex(node), state, label))
359 f.close() 382 f.close()
360 repo.ui.log('branchcache', 'wrote %s with %d labels and %d nodes\n', 383 repo.ui.log(
361 _branchcachedesc(repo), len(self._entries), nodecount) 384 'branchcache',
385 'wrote %s with %d labels and %d nodes\n',
386 _branchcachedesc(repo),
387 len(self._entries),
388 nodecount,
389 )
362 except (IOError, OSError, error.Abort) as inst: 390 except (IOError, OSError, error.Abort) as inst:
363 # Abort may be raised by read only opener, so log and continue 391 # Abort may be raised by read only opener, so log and continue
364 repo.ui.debug("couldn't write branch cache: %s\n" % 392 repo.ui.debug(
365 stringutil.forcebytestr(inst)) 393 "couldn't write branch cache: %s\n"
394 % stringutil.forcebytestr(inst)
395 )
366 396
367 def update(self, repo, revgen): 397 def update(self, repo, revgen):
368 """Given a branchhead cache, self, that may have extra nodes or be 398 """Given a branchhead cache, self, that may have extra nodes or be
369 missing heads, and a generator of nodes that are strictly a superset of 399 missing heads, and a generator of nodes that are strictly a superset of
370 heads missing, this function updates self to be correct. 400 heads missing, this function updates self to be correct.
427 self.tipnode = cl.node(tiprev) 457 self.tipnode = cl.node(tiprev)
428 self.tiprev = tiprev 458 self.tiprev = tiprev
429 self.filteredhash = scmutil.filteredhash(repo, self.tiprev) 459 self.filteredhash = scmutil.filteredhash(repo, self.tiprev)
430 460
431 duration = util.timer() - starttime 461 duration = util.timer() - starttime
432 repo.ui.log('branchcache', 'updated %s in %.4f seconds\n', 462 repo.ui.log(
433 _branchcachedesc(repo), duration) 463 'branchcache',
464 'updated %s in %.4f seconds\n',
465 _branchcachedesc(repo),
466 duration,
467 )
434 468
435 self.write(repo) 469 self.write(repo)
436 470
437 471
438 class remotebranchcache(branchcache): 472 class remotebranchcache(branchcache):
439 """Branchmap info for a remote connection, should not write locally""" 473 """Branchmap info for a remote connection, should not write locally"""
474
440 def write(self, repo): 475 def write(self, repo):
441 pass 476 pass
442 477
443 478
444 # Revision branch info cache 479 # Revision branch info cache
448 _rbcrevs = 'rbc-revs' + _rbcversion 483 _rbcrevs = 'rbc-revs' + _rbcversion
449 # [4 byte hash prefix][4 byte branch name number with sign bit indicating open] 484 # [4 byte hash prefix][4 byte branch name number with sign bit indicating open]
450 _rbcrecfmt = '>4sI' 485 _rbcrecfmt = '>4sI'
451 _rbcrecsize = calcsize(_rbcrecfmt) 486 _rbcrecsize = calcsize(_rbcrecfmt)
452 _rbcnodelen = 4 487 _rbcnodelen = 4
453 _rbcbranchidxmask = 0x7fffffff 488 _rbcbranchidxmask = 0x7FFFFFFF
454 _rbccloseflag = 0x80000000 489 _rbccloseflag = 0x80000000
490
455 491
456 class revbranchcache(object): 492 class revbranchcache(object):
457 """Persistent cache, mapping from revision number to branch name and close. 493 """Persistent cache, mapping from revision number to branch name and close.
458 This is a low level cache, independent of filtering. 494 This is a low level cache, independent of filtering.
459 495
477 """ 513 """
478 514
479 def __init__(self, repo, readonly=True): 515 def __init__(self, repo, readonly=True):
480 assert repo.filtername is None 516 assert repo.filtername is None
481 self._repo = repo 517 self._repo = repo
482 self._names = [] # branch names in local encoding with static index 518 self._names = [] # branch names in local encoding with static index
483 self._rbcrevs = bytearray() 519 self._rbcrevs = bytearray()
484 self._rbcsnameslen = 0 # length of names read at _rbcsnameslen 520 self._rbcsnameslen = 0 # length of names read at _rbcsnameslen
485 try: 521 try:
486 bndata = repo.cachevfs.read(_rbcnames) 522 bndata = repo.cachevfs.read(_rbcnames)
487 self._rbcsnameslen = len(bndata) # for verification before writing 523 self._rbcsnameslen = len(bndata) # for verification before writing
488 if bndata: 524 if bndata:
489 self._names = [encoding.tolocal(bn) 525 self._names = [
490 for bn in bndata.split('\0')] 526 encoding.tolocal(bn) for bn in bndata.split('\0')
527 ]
491 except (IOError, OSError): 528 except (IOError, OSError):
492 if readonly: 529 if readonly:
493 # don't try to use cache - fall back to the slow path 530 # don't try to use cache - fall back to the slow path
494 self.branchinfo = self._branchinfo 531 self.branchinfo = self._branchinfo
495 532
496 if self._names: 533 if self._names:
497 try: 534 try:
498 data = repo.cachevfs.read(_rbcrevs) 535 data = repo.cachevfs.read(_rbcrevs)
499 self._rbcrevs[:] = data 536 self._rbcrevs[:] = data
500 except (IOError, OSError) as inst: 537 except (IOError, OSError) as inst:
501 repo.ui.debug("couldn't read revision branch cache: %s\n" % 538 repo.ui.debug(
502 stringutil.forcebytestr(inst)) 539 "couldn't read revision branch cache: %s\n"
540 % stringutil.forcebytestr(inst)
541 )
503 # remember number of good records on disk 542 # remember number of good records on disk
504 self._rbcrevslen = min(len(self._rbcrevs) // _rbcrecsize, 543 self._rbcrevslen = min(
505 len(repo.changelog)) 544 len(self._rbcrevs) // _rbcrecsize, len(repo.changelog)
545 )
506 if self._rbcrevslen == 0: 546 if self._rbcrevslen == 0:
507 self._names = [] 547 self._names = []
508 self._rbcnamescount = len(self._names) # number of names read at 548 self._rbcnamescount = len(self._names) # number of names read at
509 # _rbcsnameslen 549 # _rbcsnameslen
510 550
511 def _clear(self): 551 def _clear(self):
512 self._rbcsnameslen = 0 552 self._rbcsnameslen = 0
513 del self._names[:] 553 del self._names[:]
514 self._rbcnamescount = 0 554 self._rbcnamescount = 0
535 return self._branchinfo(rev) 575 return self._branchinfo(rev)
536 576
537 # fast path: extract data from cache, use it if node is matching 577 # fast path: extract data from cache, use it if node is matching
538 reponode = changelog.node(rev)[:_rbcnodelen] 578 reponode = changelog.node(rev)[:_rbcnodelen]
539 cachenode, branchidx = unpack_from( 579 cachenode, branchidx = unpack_from(
540 _rbcrecfmt, util.buffer(self._rbcrevs), rbcrevidx) 580 _rbcrecfmt, util.buffer(self._rbcrevs), rbcrevidx
581 )
541 close = bool(branchidx & _rbccloseflag) 582 close = bool(branchidx & _rbccloseflag)
542 if close: 583 if close:
543 branchidx &= _rbcbranchidxmask 584 branchidx &= _rbcbranchidxmask
544 if cachenode == '\0\0\0\0': 585 if cachenode == '\0\0\0\0':
545 pass 586 pass
546 elif cachenode == reponode: 587 elif cachenode == reponode:
547 try: 588 try:
548 return self._names[branchidx], close 589 return self._names[branchidx], close
549 except IndexError: 590 except IndexError:
550 # recover from invalid reference to unknown branch 591 # recover from invalid reference to unknown branch
551 self._repo.ui.debug("referenced branch names not found" 592 self._repo.ui.debug(
552 " - rebuilding revision branch cache from scratch\n") 593 "referenced branch names not found"
594 " - rebuilding revision branch cache from scratch\n"
595 )
553 self._clear() 596 self._clear()
554 else: 597 else:
555 # rev/node map has changed, invalidate the cache from here up 598 # rev/node map has changed, invalidate the cache from here up
556 self._repo.ui.debug("history modification detected - truncating " 599 self._repo.ui.debug(
557 "revision branch cache to revision %d\n" % rev) 600 "history modification detected - truncating "
601 "revision branch cache to revision %d\n" % rev
602 )
558 truncate = rbcrevidx + _rbcrecsize 603 truncate = rbcrevidx + _rbcrecsize
559 del self._rbcrevs[truncate:] 604 del self._rbcrevs[truncate:]
560 self._rbcrevslen = min(self._rbcrevslen, truncate) 605 self._rbcrevslen = min(self._rbcrevslen, truncate)
561 606
562 # fall back to slow path and make sure it will be written to disk 607 # fall back to slow path and make sure it will be written to disk
602 """Writes the node's branch data to the in-memory cache data.""" 647 """Writes the node's branch data to the in-memory cache data."""
603 if rev == nullrev: 648 if rev == nullrev:
604 return 649 return
605 rbcrevidx = rev * _rbcrecsize 650 rbcrevidx = rev * _rbcrecsize
606 if len(self._rbcrevs) < rbcrevidx + _rbcrecsize: 651 if len(self._rbcrevs) < rbcrevidx + _rbcrecsize:
607 self._rbcrevs.extend('\0' * 652 self._rbcrevs.extend(
608 (len(self._repo.changelog) * _rbcrecsize - 653 '\0'
609 len(self._rbcrevs))) 654 * (len(self._repo.changelog) * _rbcrecsize - len(self._rbcrevs))
655 )
610 pack_into(_rbcrecfmt, self._rbcrevs, rbcrevidx, node, branchidx) 656 pack_into(_rbcrecfmt, self._rbcrevs, rbcrevidx, node, branchidx)
611 self._rbcrevslen = min(self._rbcrevslen, rev) 657 self._rbcrevslen = min(self._rbcrevslen, rev)
612 658
613 tr = self._repo.currenttransaction() 659 tr = self._repo.currenttransaction()
614 if tr: 660 if tr:
633 if wlock is None: 679 if wlock is None:
634 wlock = repo.wlock(wait=False) 680 wlock = repo.wlock(wait=False)
635 self._writerevs(repo, start) 681 self._writerevs(repo, start)
636 682
637 except (IOError, OSError, error.Abort, error.LockError) as inst: 683 except (IOError, OSError, error.Abort, error.LockError) as inst:
638 repo.ui.debug("couldn't write revision branch cache%s: %s\n" 684 repo.ui.debug(
639 % (step, stringutil.forcebytestr(inst))) 685 "couldn't write revision branch cache%s: %s\n"
686 % (step, stringutil.forcebytestr(inst))
687 )
640 finally: 688 finally:
641 if wlock is not None: 689 if wlock is not None:
642 wlock.release() 690 wlock.release()
643 691
644 def _writenames(self, repo): 692 def _writenames(self, repo):
654 self._rbcrevslen = 0 702 self._rbcrevslen = 0
655 if self._rbcnamescount == 0: 703 if self._rbcnamescount == 0:
656 # before rewriting names, make sure references are removed 704 # before rewriting names, make sure references are removed
657 repo.cachevfs.unlinkpath(_rbcrevs, ignoremissing=True) 705 repo.cachevfs.unlinkpath(_rbcrevs, ignoremissing=True)
658 f = repo.cachevfs.open(_rbcnames, 'wb') 706 f = repo.cachevfs.open(_rbcnames, 'wb')
659 f.write('\0'.join(encoding.fromlocal(b) 707 f.write(
660 for b in self._names[self._rbcnamescount:])) 708 '\0'.join(
709 encoding.fromlocal(b)
710 for b in self._names[self._rbcnamescount :]
711 )
712 )
661 self._rbcsnameslen = f.tell() 713 self._rbcsnameslen = f.tell()
662 f.close() 714 f.close()
663 self._rbcnamescount = len(self._names) 715 self._rbcnamescount = len(self._names)
664 716
665 def _writerevs(self, repo, start): 717 def _writerevs(self, repo, start):