comparison mercurial/branchmap.py @ 29615:a2a380e2750f stable

rbc: fix superfluous rebuilding from scratch - don't abuse self._rbcnamescount The code used self._rbcnamescount as if it was the length of self._names ... but actually it is just the number of good entries on disk. This caused the cache to be populated inefficiently. In some cases very inefficiently. Instead of checking the length before lookup, just try a lookup in self._names - that is also in most cases faster. Comments and debug messages are tweaked to help understanding the issue and the fix.
author Mads Kiilerich <madski@unity3d.com>
date Mon, 18 Jul 2016 22:25:09 +0200
parents db0095c83344
children 9f3c49ee4486
comparison
equal deleted inserted replaced
29614:5c79bae8166f 29615:a2a380e2750f
356 def __init__(self, repo, readonly=True): 356 def __init__(self, repo, readonly=True):
357 assert repo.filtername is None 357 assert repo.filtername is None
358 self._repo = repo 358 self._repo = repo
359 self._names = [] # branch names in local encoding with static index 359 self._names = [] # branch names in local encoding with static index
360 self._rbcrevs = array('c') # structs of type _rbcrecfmt 360 self._rbcrevs = array('c') # structs of type _rbcrecfmt
361 self._rbcsnameslen = 0 361 self._rbcsnameslen = 0 # length of names read at _rbcsnameslen
362 try: 362 try:
363 bndata = repo.vfs.read(_rbcnames) 363 bndata = repo.vfs.read(_rbcnames)
364 self._rbcsnameslen = len(bndata) # for verification before writing 364 self._rbcsnameslen = len(bndata) # for verification before writing
365 self._names = [encoding.tolocal(bn) for bn in bndata.split('\0')] 365 self._names = [encoding.tolocal(bn) for bn in bndata.split('\0')]
366 except (IOError, OSError): 366 except (IOError, OSError):
378 # remember number of good records on disk 378 # remember number of good records on disk
379 self._rbcrevslen = min(len(self._rbcrevs) // _rbcrecsize, 379 self._rbcrevslen = min(len(self._rbcrevs) // _rbcrecsize,
380 len(repo.changelog)) 380 len(repo.changelog))
381 if self._rbcrevslen == 0: 381 if self._rbcrevslen == 0:
382 self._names = [] 382 self._names = []
383 self._rbcnamescount = len(self._names) # number of good names on disk 383 self._rbcnamescount = len(self._names) # number of names read at
384 # _rbcsnameslen
384 self._namesreverse = dict((b, r) for r, b in enumerate(self._names)) 385 self._namesreverse = dict((b, r) for r, b in enumerate(self._names))
385 386
386 def _clear(self): 387 def _clear(self):
387 self._rbcsnameslen = 0 388 self._rbcsnameslen = 0
388 del self._names[:] 389 del self._names[:]
414 if close: 415 if close:
415 branchidx &= _rbcbranchidxmask 416 branchidx &= _rbcbranchidxmask
416 if cachenode == '\0\0\0\0': 417 if cachenode == '\0\0\0\0':
417 pass 418 pass
418 elif cachenode == reponode: 419 elif cachenode == reponode:
419 if branchidx < self._rbcnamescount: 420 try:
420 return self._names[branchidx], close 421 return self._names[branchidx], close
421 # referenced branch doesn't exist - rebuild is expensive but needed 422 except IndexError:
422 self._repo.ui.debug("rebuilding corrupted revision branch cache\n") 423 # recover from invalid reference to unknown branch
423 self._clear() 424 self._repo.ui.debug("referenced branch names not found"
425 " - rebuilding revision branch cache from scratch\n")
426 self._clear()
424 else: 427 else:
425 # rev/node map has changed, invalidate the cache from here up 428 # rev/node map has changed, invalidate the cache from here up
429 self._repo.ui.debug("history modification detected - truncating "
430 "revision branch cache to revision %s\n" % rev)
426 truncate = rbcrevidx + _rbcrecsize 431 truncate = rbcrevidx + _rbcrecsize
427 del self._rbcrevs[truncate:] 432 del self._rbcrevs[truncate:]
428 self._rbcrevslen = min(self._rbcrevslen, truncate) 433 self._rbcrevslen = min(self._rbcrevslen, truncate)
429 434
430 # fall back to slow path and make sure it will be written to disk 435 # fall back to slow path and make sure it will be written to disk