hgext3rd/evolve/stablerange.py
changeset 3301 5c45df0c8e36
parent 3268 10badf5951e5
child 3302 f890d27df766
equal deleted inserted replaced
3300:2d49773a378b 3301:5c45df0c8e36
   323         The range `(<head>, <skip>)` contains all revisions stable-sorted from
   323         The range `(<head>, <skip>)` contains all revisions stable-sorted from
   324         <head>, skipping the <index>th lower revisions.
   324         <head>, skipping the <index>th lower revisions.
   325         """
   325         """
   326         limit = self.rangelength(repo, rangeid)
   326         limit = self.rangelength(repo, rangeid)
   327         return self._sortcache.get(repo, rangeid[0], limit=limit)
   327         return self._sortcache.get(repo, rangeid[0], limit=limit)
       
   328 
       
   329     def _stableparent(self, repo, headrev):
       
   330         """The parent of the changeset with reusable subrange
       
   331 
       
   332         For non-merge it is simple, there is a single parent. For Mercurial we
       
   333         have to find the right one. Since the stable sort use merge-point, we
       
   334         know that one of REV parents stable sort is a subset of REV stable
       
   335         sort. In other word:
       
   336 
       
   337             sort(::REV) = sort(::min(parents(REV))
       
   338                           + sort(only(max(parents(REV)), min(parents(REV)))
       
   339                           + [REV]
       
   340 
       
   341         We are looking for that `min(parents(REV))`. Since the subrange are
       
   342         based on the sort, we can reuse its subrange as well.
       
   343         """
       
   344         p1, p2 = repo.changelog.parentrevs(headrev)
       
   345         relevant_parent = None
       
   346         if p2 == nodemod.nullrev:
       
   347             relevant_parent = p1
       
   348         else:
       
   349             tiebreaker = stablesort._mergepoint_tie_breaker(repo)
       
   350             relevant_parent = min(p1, p2, key=tiebreaker)
       
   351         return relevant_parent
       
   352 
       
   353     def subranges(self, repo, rangeid):
       
   354         headrev, initial_index = rangeid
       
   355         # size 1 range can't be sliced
       
   356         if self.rangelength(repo, rangeid) == 1:
       
   357             return []
       
   358         # find were we need to slice
       
   359         slicepoint = self._slicepoint(repo, rangeid)
       
   360 
       
   361         stable_parent = self._stableparent(repo, headrev)
       
   362         stable_parent_depth = self.depthrev(repo, stable_parent)
       
   363         stable_parent_range = (stable_parent, initial_index)
       
   364 
       
   365         # top range is always the same, so we can build it early for all
       
   366         top_range = (headrev, slicepoint)
       
   367 
       
   368         # now find out about the lower range, if we are lucky there is only
       
   369         # one, otherwise we need to issue multiple one to cover every revision
       
   370         # on the lower set. (and cover them only once).
       
   371         if slicepoint == stable_parent_depth:
       
   372             # luckly shot, the parent is actually the head of the lower range
       
   373             subranges = [
       
   374                 stable_parent_range,
       
   375                 top_range,
       
   376             ]
       
   377         elif slicepoint < stable_parent_depth:
       
   378             # The parent is above the slice point,
       
   379             # it's lower subrange will be the same so we just get them,
       
   380             # (and the top range is always the same)
       
   381             subranges = self.subranges(repo, stable_parent_range)[:-1]
       
   382             subranges.append(top_range)
       
   383         elif initial_index < stable_parent_depth < slicepoint:
       
   384             # the parent is below the range we are considering, we need to
       
   385             # compute these uniques subranges
       
   386             subranges = [stable_parent_range]
       
   387             subranges.extend(self._unique_subranges(repo, headrev,
       
   388                                                     stable_parent_depth,
       
   389                                                     slicepoint))
       
   390             subranges.append(top_range)
       
   391         else:
       
   392             # we cannot reuse the parent range at all
       
   393             subranges = list(self._unique_subranges(repo, headrev,
       
   394                                                     initial_index,
       
   395                                                     slicepoint))
       
   396             subranges.append(top_range)
       
   397 
       
   398         return subranges
       
   399 
       
   400     def _unique_subranges(self, repo, headrev, initial_index, slicepoint):
       
   401         """Compute subrange unique to the exclusive part of merge"""
       
   402         result = []
       
   403         depth = repo.depthcache.get
       
   404         skips = depth(headrev) - slicepoint
       
   405 
       
   406         def nextrevs():
       
   407             revs = self._sortcache.walkfrom(repo, headrev)
       
   408             towalk = depth(headrev) - initial_index
       
   409             while 0 < towalk:
       
   410                 yield next(revs)
       
   411                 towalk -= 1
       
   412             yield None
       
   413         revs = nextrevs()
       
   414         for i in xrange(skips):
       
   415             next(revs)
       
   416         rangehead = current = next(revs)
       
   417         rangepath = self._sortcache.walkfrom(repo, current)
       
   418         nextonpath = next(rangepath, None)
       
   419         steps = 0
       
   420         while current is not None:
       
   421             while current == nextonpath and current is not None:
       
   422                 steps += 1
       
   423                 current = next(revs)
       
   424                 nextonpath = next(rangepath, None)
       
   425             result.append((rangehead, depth(rangehead) - steps))
       
   426             if current is not None:
       
   427                 rangehead = current
       
   428                 rangepath = self._sortcache.walkfrom(repo, current)
       
   429                 nextonpath = next(rangepath, None)
       
   430                 steps = 0
       
   431         result.reverse()
       
   432         return result
   328 
   433 
   329 class stablerange(stablerangecached):
   434 class stablerange(stablerangecached):
   330 
   435 
   331     def __init__(self, lrusize=2000):
   436     def __init__(self, lrusize=2000):
   332         # The point up to which we have data in cache
   437         # The point up to which we have data in cache