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