comparison mercurial/branchmap.py @ 23786:7d63398fbfd1

branchmap: use revbranchcache when updating branch map The revbranchcache is read on demand before it will be used for updating the branch map. It is written back when the branchmap is written and it will thus use the same locking as branchmap. The revbranchcache instance is short-lived; it is only stored in the branchmap from .update() is invoked and until .write() is invoked. Branchmap already assume that the repo is locked in that case. The use of revbranchcache for branch map updates will make sure that the revbranchcache "always" is kept up-to-date. The perfbranchmap benchmark is somewhat bogus, especially when we can see that the caching makes a significant difference between the realistic case of a first run and the rare case of rerunning it with a full cache. Here are some 'base' numbers on mozilla-central: Before: ! wall 6.912745 comb 6.910000 user 6.840000 sys 0.070000 (best of 3) After - initial, cache is empty: ! wall 7.792569 comb 7.790000 user 7.720000 sys 0.070000 (best of 3) After - cache is full: ! wall 0.879688 comb 0.880000 user 0.870000 sys 0.010000 (best of 4) The overhead when running with empty cache comes from checking, missing and updating it every time. Most of the performance improvement comes from not having to extract the branch info from the changelog. The last doubling of performance comes from no longer having to convert all branch names to local encoding but reuse the few already converted branch names. On the hg repo: Before: ! wall 0.715703 comb 0.710000 user 0.710000 sys 0.000000 (best of 14) After: ! wall 0.105489 comb 0.110000 user 0.110000 sys 0.000000 (best of 87)
author Mads Kiilerich <madski@unity3d.com>
date Thu, 08 Jan 2015 00:01:03 +0100
parents cb99bacb9b4e
children 6bf93440a717
comparison
equal deleted inserted replaced
23785:cb99bacb9b4e 23786:7d63398fbfd1
132 # heads. 132 # heads.
133 if closednodes is None: 133 if closednodes is None:
134 self._closednodes = set() 134 self._closednodes = set()
135 else: 135 else:
136 self._closednodes = closednodes 136 self._closednodes = closednodes
137 self._revbranchcache = None
137 138
138 def _hashfiltered(self, repo): 139 def _hashfiltered(self, repo):
139 """build hash of revision filtered in the current cache 140 """build hash of revision filtered in the current cache
140 141
141 Tracking tipnode and tiprev is not enough to ensure validity of the 142 Tracking tipnode and tiprev is not enough to ensure validity of the
223 repo.filtername, len(self), nodecount) 224 repo.filtername, len(self), nodecount)
224 except (IOError, OSError, util.Abort), inst: 225 except (IOError, OSError, util.Abort), inst:
225 repo.ui.debug("couldn't write branch cache: %s\n" % inst) 226 repo.ui.debug("couldn't write branch cache: %s\n" % inst)
226 # Abort may be raise by read only opener 227 # Abort may be raise by read only opener
227 pass 228 pass
229 if self._revbranchcache:
230 self._revbranchcache.write(repo.unfiltered())
231 self._revbranchcache = None
228 232
229 def update(self, repo, revgen): 233 def update(self, repo, revgen):
230 """Given a branchhead cache, self, that may have extra nodes or be 234 """Given a branchhead cache, self, that may have extra nodes or be
231 missing heads, and a generator of nodes that are strictly a superset of 235 missing heads, and a generator of nodes that are strictly a superset of
232 heads missing, this function updates self to be correct. 236 heads missing, this function updates self to be correct.
233 """ 237 """
234 starttime = time.time() 238 starttime = time.time()
235 cl = repo.changelog 239 cl = repo.changelog
236 # collect new branch entries 240 # collect new branch entries
237 newbranches = {} 241 newbranches = {}
238 getbranchinfo = cl.branchinfo 242 urepo = repo.unfiltered()
243 self._revbranchcache = revbranchcache(urepo)
244 getbranchinfo = self._revbranchcache.branchinfo
245 ucl = urepo.changelog
239 for r in revgen: 246 for r in revgen:
240 branch, closesbranch = getbranchinfo(r) 247 branch, closesbranch = getbranchinfo(ucl, r)
241 newbranches.setdefault(branch, []).append(r) 248 newbranches.setdefault(branch, []).append(r)
242 if closesbranch: 249 if closesbranch:
243 self._closednodes.add(cl.node(r)) 250 self._closednodes.add(cl.node(r))
244 251
245 # fetch current topological heads to speed up filtering 252 # fetch current topological heads to speed up filtering
359 if len(self._rbcrevs) < rbcrevidx + _rbcrecsize: 366 if len(self._rbcrevs) < rbcrevidx + _rbcrecsize:
360 first = len(self._rbcrevs) // _rbcrecsize 367 first = len(self._rbcrevs) // _rbcrecsize
361 self._rbcrevs.extend('\0' * (len(changelog) * _rbcrecsize - 368 self._rbcrevs.extend('\0' * (len(changelog) * _rbcrecsize -
362 len(self._rbcrevs))) 369 len(self._rbcrevs)))
363 for r in xrange(first, len(changelog)): 370 for r in xrange(first, len(changelog)):
364 self._branchinfo(r) 371 self._branchinfo(changelog, r)
365 372
366 # fast path: extract data from cache, use it if node is matching 373 # fast path: extract data from cache, use it if node is matching
367 reponode = changelog.node(rev)[:_rbcnodelen] 374 reponode = changelog.node(rev)[:_rbcnodelen]
368 cachenode, branchidx = unpack( 375 cachenode, branchidx = unpack(
369 _rbcrecfmt, buffer(self._rbcrevs, rbcrevidx, _rbcrecsize)) 376 _rbcrecfmt, buffer(self._rbcrevs, rbcrevidx, _rbcrecsize))
372 branchidx &= _rbcbranchidxmask 379 branchidx &= _rbcbranchidxmask
373 if cachenode == reponode: 380 if cachenode == reponode:
374 return self._names[branchidx], close 381 return self._names[branchidx], close
375 # fall back to slow path and make sure it will be written to disk 382 # fall back to slow path and make sure it will be written to disk
376 self._rbcrevslen = min(self._rbcrevslen, rev) 383 self._rbcrevslen = min(self._rbcrevslen, rev)
377 return self._branchinfo(rev) 384 return self._branchinfo(changelog, rev)
378 385
379 def _branchinfo(self, changelog, rev): 386 def _branchinfo(self, changelog, rev):
380 """Retrieve branch info from changelog and update _rbcrevs""" 387 """Retrieve branch info from changelog and update _rbcrevs"""
381 b, close = changelog.branchinfo(rev) 388 b, close = changelog.branchinfo(rev)
382 if b in self._namesreverse: 389 if b in self._namesreverse: