243 def fromfile(cls, repo): |
243 def fromfile(cls, repo): |
244 f = None |
244 f = None |
245 try: |
245 try: |
246 f = repo.cachevfs(cls._filename(repo)) |
246 f = repo.cachevfs(cls._filename(repo)) |
247 lineiter = iter(f) |
247 lineiter = iter(f) |
248 cachekey = next(lineiter).rstrip('\n').split(" ", 2) |
248 cachekey = next(lineiter).rstrip(b'\n').split(b" ", 2) |
249 last, lrev = cachekey[:2] |
249 last, lrev = cachekey[:2] |
250 last, lrev = bin(last), int(lrev) |
250 last, lrev = bin(last), int(lrev) |
251 filteredhash = None |
251 filteredhash = None |
252 hasnode = repo.changelog.hasnode |
252 hasnode = repo.changelog.hasnode |
253 if len(cachekey) > 2: |
253 if len(cachekey) > 2: |
281 |
281 |
282 def load(self, repo, lineiter): |
282 def load(self, repo, lineiter): |
283 """ fully loads the branchcache by reading from the file using the line |
283 """ fully loads the branchcache by reading from the file using the line |
284 iterator passed""" |
284 iterator passed""" |
285 for line in lineiter: |
285 for line in lineiter: |
286 line = line.rstrip('\n') |
286 line = line.rstrip(b'\n') |
287 if not line: |
287 if not line: |
288 continue |
288 continue |
289 node, state, label = line.split(" ", 2) |
289 node, state, label = line.split(b" ", 2) |
290 if state not in 'oc': |
290 if state not in b'oc': |
291 raise ValueError(r'invalid branch state') |
291 raise ValueError(r'invalid branch state') |
292 label = encoding.tolocal(label.strip()) |
292 label = encoding.tolocal(label.strip()) |
293 node = bin(node) |
293 node = bin(node) |
294 self._entries.setdefault(label, []).append(node) |
294 self._entries.setdefault(label, []).append(node) |
295 if state == 'c': |
295 if state == b'c': |
296 self._closednodes.add(node) |
296 self._closednodes.add(node) |
297 |
297 |
298 @staticmethod |
298 @staticmethod |
299 def _filename(repo): |
299 def _filename(repo): |
300 """name of a branchcache file for a given repo or repoview""" |
300 """name of a branchcache file for a given repo or repoview""" |
301 filename = "branch2" |
301 filename = b"branch2" |
302 if repo.filtername: |
302 if repo.filtername: |
303 filename = '%s-%s' % (filename, repo.filtername) |
303 filename = b'%s-%s' % (filename, repo.filtername) |
304 return filename |
304 return filename |
305 |
305 |
306 def validfor(self, repo): |
306 def validfor(self, repo): |
307 """Is the cache content valid regarding a repo |
307 """Is the cache content valid regarding a repo |
308 |
308 |
362 self._closednodes, |
362 self._closednodes, |
363 ) |
363 ) |
364 |
364 |
365 def write(self, repo): |
365 def write(self, repo): |
366 try: |
366 try: |
367 f = repo.cachevfs(self._filename(repo), "w", atomictemp=True) |
367 f = repo.cachevfs(self._filename(repo), b"w", atomictemp=True) |
368 cachekey = [hex(self.tipnode), '%d' % self.tiprev] |
368 cachekey = [hex(self.tipnode), b'%d' % self.tiprev] |
369 if self.filteredhash is not None: |
369 if self.filteredhash is not None: |
370 cachekey.append(hex(self.filteredhash)) |
370 cachekey.append(hex(self.filteredhash)) |
371 f.write(" ".join(cachekey) + '\n') |
371 f.write(b" ".join(cachekey) + b'\n') |
372 nodecount = 0 |
372 nodecount = 0 |
373 for label, nodes in sorted(self._entries.iteritems()): |
373 for label, nodes in sorted(self._entries.iteritems()): |
374 label = encoding.fromlocal(label) |
374 label = encoding.fromlocal(label) |
375 for node in nodes: |
375 for node in nodes: |
376 nodecount += 1 |
376 nodecount += 1 |
377 if node in self._closednodes: |
377 if node in self._closednodes: |
378 state = 'c' |
378 state = b'c' |
379 else: |
379 else: |
380 state = 'o' |
380 state = b'o' |
381 f.write("%s %s %s\n" % (hex(node), state, label)) |
381 f.write(b"%s %s %s\n" % (hex(node), state, label)) |
382 f.close() |
382 f.close() |
383 repo.ui.log( |
383 repo.ui.log( |
384 'branchcache', |
384 b'branchcache', |
385 'wrote %s with %d labels and %d nodes\n', |
385 b'wrote %s with %d labels and %d nodes\n', |
386 _branchcachedesc(repo), |
386 _branchcachedesc(repo), |
387 len(self._entries), |
387 len(self._entries), |
388 nodecount, |
388 nodecount, |
389 ) |
389 ) |
390 except (IOError, OSError, error.Abort) as inst: |
390 except (IOError, OSError, error.Abort) as inst: |
391 # 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 |
392 repo.ui.debug( |
392 repo.ui.debug( |
393 "couldn't write branch cache: %s\n" |
393 b"couldn't write branch cache: %s\n" |
394 % stringutil.forcebytestr(inst) |
394 % stringutil.forcebytestr(inst) |
395 ) |
395 ) |
396 |
396 |
397 def update(self, repo, revgen): |
397 def update(self, repo, revgen): |
398 """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 |
534 try: |
534 try: |
535 data = repo.cachevfs.read(_rbcrevs) |
535 data = repo.cachevfs.read(_rbcrevs) |
536 self._rbcrevs[:] = data |
536 self._rbcrevs[:] = data |
537 except (IOError, OSError) as inst: |
537 except (IOError, OSError) as inst: |
538 repo.ui.debug( |
538 repo.ui.debug( |
539 "couldn't read revision branch cache: %s\n" |
539 b"couldn't read revision branch cache: %s\n" |
540 % stringutil.forcebytestr(inst) |
540 % stringutil.forcebytestr(inst) |
541 ) |
541 ) |
542 # remember number of good records on disk |
542 # remember number of good records on disk |
543 self._rbcrevslen = min( |
543 self._rbcrevslen = min( |
544 len(self._rbcrevs) // _rbcrecsize, len(repo.changelog) |
544 len(self._rbcrevs) // _rbcrecsize, len(repo.changelog) |
580 _rbcrecfmt, util.buffer(self._rbcrevs), rbcrevidx |
580 _rbcrecfmt, util.buffer(self._rbcrevs), rbcrevidx |
581 ) |
581 ) |
582 close = bool(branchidx & _rbccloseflag) |
582 close = bool(branchidx & _rbccloseflag) |
583 if close: |
583 if close: |
584 branchidx &= _rbcbranchidxmask |
584 branchidx &= _rbcbranchidxmask |
585 if cachenode == '\0\0\0\0': |
585 if cachenode == b'\0\0\0\0': |
586 pass |
586 pass |
587 elif cachenode == reponode: |
587 elif cachenode == reponode: |
588 try: |
588 try: |
589 return self._names[branchidx], close |
589 return self._names[branchidx], close |
590 except IndexError: |
590 except IndexError: |
591 # recover from invalid reference to unknown branch |
591 # recover from invalid reference to unknown branch |
592 self._repo.ui.debug( |
592 self._repo.ui.debug( |
593 "referenced branch names not found" |
593 b"referenced branch names not found" |
594 " - rebuilding revision branch cache from scratch\n" |
594 b" - rebuilding revision branch cache from scratch\n" |
595 ) |
595 ) |
596 self._clear() |
596 self._clear() |
597 else: |
597 else: |
598 # rev/node map has changed, invalidate the cache from here up |
598 # rev/node map has changed, invalidate the cache from here up |
599 self._repo.ui.debug( |
599 self._repo.ui.debug( |
600 "history modification detected - truncating " |
600 b"history modification detected - truncating " |
601 "revision branch cache to revision %d\n" % rev |
601 b"revision branch cache to revision %d\n" % rev |
602 ) |
602 ) |
603 truncate = rbcrevidx + _rbcrecsize |
603 truncate = rbcrevidx + _rbcrecsize |
604 del self._rbcrevs[truncate:] |
604 del self._rbcrevs[truncate:] |
605 self._rbcrevslen = min(self._rbcrevslen, truncate) |
605 self._rbcrevslen = min(self._rbcrevslen, truncate) |
606 |
606 |
648 if rev == nullrev: |
648 if rev == nullrev: |
649 return |
649 return |
650 rbcrevidx = rev * _rbcrecsize |
650 rbcrevidx = rev * _rbcrecsize |
651 if len(self._rbcrevs) < rbcrevidx + _rbcrecsize: |
651 if len(self._rbcrevs) < rbcrevidx + _rbcrecsize: |
652 self._rbcrevs.extend( |
652 self._rbcrevs.extend( |
653 '\0' |
653 b'\0' |
654 * (len(self._repo.changelog) * _rbcrecsize - len(self._rbcrevs)) |
654 * (len(self._repo.changelog) * _rbcrecsize - len(self._rbcrevs)) |
655 ) |
655 ) |
656 pack_into(_rbcrecfmt, self._rbcrevs, rbcrevidx, node, branchidx) |
656 pack_into(_rbcrecfmt, self._rbcrevs, rbcrevidx, node, branchidx) |
657 self._rbcrevslen = min(self._rbcrevslen, rev) |
657 self._rbcrevslen = min(self._rbcrevslen, rev) |
658 |
658 |
659 tr = self._repo.currenttransaction() |
659 tr = self._repo.currenttransaction() |
660 if tr: |
660 if tr: |
661 tr.addfinalize('write-revbranchcache', self.write) |
661 tr.addfinalize(b'write-revbranchcache', self.write) |
662 |
662 |
663 def write(self, tr=None): |
663 def write(self, tr=None): |
664 """Save branch cache if it is dirty.""" |
664 """Save branch cache if it is dirty.""" |
665 repo = self._repo |
665 repo = self._repo |
666 wlock = None |
666 wlock = None |
667 step = '' |
667 step = b'' |
668 try: |
668 try: |
669 # write the new names |
669 # write the new names |
670 if self._rbcnamescount < len(self._names): |
670 if self._rbcnamescount < len(self._names): |
671 wlock = repo.wlock(wait=False) |
671 wlock = repo.wlock(wait=False) |
672 step = ' names' |
672 step = b' names' |
673 self._writenames(repo) |
673 self._writenames(repo) |
674 |
674 |
675 # write the new revs |
675 # write the new revs |
676 start = self._rbcrevslen * _rbcrecsize |
676 start = self._rbcrevslen * _rbcrecsize |
677 if start != len(self._rbcrevs): |
677 if start != len(self._rbcrevs): |
678 step = '' |
678 step = b'' |
679 if wlock is None: |
679 if wlock is None: |
680 wlock = repo.wlock(wait=False) |
680 wlock = repo.wlock(wait=False) |
681 self._writerevs(repo, start) |
681 self._writerevs(repo, start) |
682 |
682 |
683 except (IOError, OSError, error.Abort, error.LockError) as inst: |
683 except (IOError, OSError, error.Abort, error.LockError) as inst: |
684 repo.ui.debug( |
684 repo.ui.debug( |
685 "couldn't write revision branch cache%s: %s\n" |
685 b"couldn't write revision branch cache%s: %s\n" |
686 % (step, stringutil.forcebytestr(inst)) |
686 % (step, stringutil.forcebytestr(inst)) |
687 ) |
687 ) |
688 finally: |
688 finally: |
689 if wlock is not None: |
689 if wlock is not None: |
690 wlock.release() |
690 wlock.release() |
691 |
691 |
692 def _writenames(self, repo): |
692 def _writenames(self, repo): |
693 """ write the new branch names to revbranchcache """ |
693 """ write the new branch names to revbranchcache """ |
694 if self._rbcnamescount != 0: |
694 if self._rbcnamescount != 0: |
695 f = repo.cachevfs.open(_rbcnames, 'ab') |
695 f = repo.cachevfs.open(_rbcnames, b'ab') |
696 if f.tell() == self._rbcsnameslen: |
696 if f.tell() == self._rbcsnameslen: |
697 f.write('\0') |
697 f.write(b'\0') |
698 else: |
698 else: |
699 f.close() |
699 f.close() |
700 repo.ui.debug("%s changed - rewriting it\n" % _rbcnames) |
700 repo.ui.debug(b"%s changed - rewriting it\n" % _rbcnames) |
701 self._rbcnamescount = 0 |
701 self._rbcnamescount = 0 |
702 self._rbcrevslen = 0 |
702 self._rbcrevslen = 0 |
703 if self._rbcnamescount == 0: |
703 if self._rbcnamescount == 0: |
704 # before rewriting names, make sure references are removed |
704 # before rewriting names, make sure references are removed |
705 repo.cachevfs.unlinkpath(_rbcrevs, ignoremissing=True) |
705 repo.cachevfs.unlinkpath(_rbcrevs, ignoremissing=True) |
706 f = repo.cachevfs.open(_rbcnames, 'wb') |
706 f = repo.cachevfs.open(_rbcnames, b'wb') |
707 f.write( |
707 f.write( |
708 '\0'.join( |
708 b'\0'.join( |
709 encoding.fromlocal(b) |
709 encoding.fromlocal(b) |
710 for b in self._names[self._rbcnamescount :] |
710 for b in self._names[self._rbcnamescount :] |
711 ) |
711 ) |
712 ) |
712 ) |
713 self._rbcsnameslen = f.tell() |
713 self._rbcsnameslen = f.tell() |
715 self._rbcnamescount = len(self._names) |
715 self._rbcnamescount = len(self._names) |
716 |
716 |
717 def _writerevs(self, repo, start): |
717 def _writerevs(self, repo, start): |
718 """ write the new revs to revbranchcache """ |
718 """ write the new revs to revbranchcache """ |
719 revs = min(len(repo.changelog), len(self._rbcrevs) // _rbcrecsize) |
719 revs = min(len(repo.changelog), len(self._rbcrevs) // _rbcrecsize) |
720 with repo.cachevfs.open(_rbcrevs, 'ab') as f: |
720 with repo.cachevfs.open(_rbcrevs, b'ab') as f: |
721 if f.tell() != start: |
721 if f.tell() != start: |
722 repo.ui.debug("truncating cache/%s to %d\n" % (_rbcrevs, start)) |
722 repo.ui.debug( |
|
723 b"truncating cache/%s to %d\n" % (_rbcrevs, start) |
|
724 ) |
723 f.seek(start) |
725 f.seek(start) |
724 if f.tell() != start: |
726 if f.tell() != start: |
725 start = 0 |
727 start = 0 |
726 f.seek(start) |
728 f.seek(start) |
727 f.truncate() |
729 f.truncate() |