mercurial/utils/storageutil.py
changeset 40008 842ffcf1d42f
parent 40007 1470183068b8
child 40009 631c6f5058b9
equal deleted inserted replaced
40007:1470183068b8 40008:842ffcf1d42f
   260                 heads[p] = plinkrev
   260                 heads[p] = plinkrev
   261                 if plinkrev >= minlinkrev:
   261                 if plinkrev >= minlinkrev:
   262                     futurelargelinkrevs.add(plinkrev)
   262                     futurelargelinkrevs.add(plinkrev)
   263 
   263 
   264     return strippoint, brokenrevs
   264     return strippoint, brokenrevs
       
   265 
       
   266 def emitrevisions(store, revs, resultcls, deltaparentfn, candeltafn,
       
   267                   rawsizefn, revdifffn, flagsfn, sendfulltext=False,
       
   268                   revisiondata=False, assumehaveparentrevisions=False,
       
   269                   deltaprevious=False):
       
   270     """Generic implementation of ifiledata.emitrevisions().
       
   271 
       
   272     Emitting revision data is subtly complex. This function attempts to
       
   273     encapsulate all the logic for doing so in a backend-agnostic way.
       
   274 
       
   275     ``store``
       
   276        Object conforming to ``ifilestorage`` interface.
       
   277 
       
   278     ``revs``
       
   279        List of integer revision numbers whose data to emit.
       
   280 
       
   281     ``resultcls``
       
   282        A type implementing the ``irevisiondelta`` interface that will be
       
   283        constructed and returned.
       
   284 
       
   285     ``deltaparentfn``
       
   286        Callable receiving a revision number and returning the revision number
       
   287        of a revision that the internal delta is stored against. This delta
       
   288        will be preferred over computing a new arbitrary delta.
       
   289 
       
   290     ``candeltafn``
       
   291        Callable receiving a pair of revision numbers that returns a bool
       
   292        indicating whether a delta between them can be produced.
       
   293 
       
   294     ``rawsizefn``
       
   295        Callable receiving a revision number and returning the length of the
       
   296        ``store.revision(rev, raw=True)``.
       
   297 
       
   298     ``revdifffn``
       
   299        Callable receiving a pair of revision numbers that returns a delta
       
   300        between them.
       
   301 
       
   302     ``flagsfn``
       
   303        Callable receiving a revision number and returns the integer flags
       
   304        value for it.
       
   305 
       
   306     ``sendfulltext``
       
   307        Whether to send fulltext revisions instead of deltas, if allowed.
       
   308 
       
   309     ``revisiondata``
       
   310     ``assumehaveparentrevisions``
       
   311     ``deltaprevious``
       
   312        See ``ifiledata.emitrevisions()`` interface documentation.
       
   313     """
       
   314 
       
   315     fnode = store.node
       
   316 
       
   317     prevrev = None
       
   318 
       
   319     if deltaprevious or assumehaveparentrevisions:
       
   320         prevrev = store.parentrevs(revs[0])[0]
       
   321 
       
   322     # Set of revs available to delta against.
       
   323     available = set()
       
   324 
       
   325     for rev in revs:
       
   326         if rev == nullrev:
       
   327             continue
       
   328 
       
   329         node = fnode(rev)
       
   330         deltaparentrev = deltaparentfn(rev)
       
   331         p1rev, p2rev = store.parentrevs(rev)
       
   332 
       
   333         # Forced delta against previous mode.
       
   334         if deltaprevious:
       
   335             baserev = prevrev
       
   336 
       
   337         # We're instructed to send fulltext. Honor that.
       
   338         elif sendfulltext:
       
   339             baserev = nullrev
       
   340 
       
   341         # There is a delta in storage. We try to use that because it
       
   342         # amounts to effectively copying data from storage and is
       
   343         # therefore the fastest.
       
   344         elif deltaparentrev != nullrev:
       
   345             # Base revision was already emitted in this group. We can
       
   346             # always safely use the delta.
       
   347             if deltaparentrev in available:
       
   348                 baserev = deltaparentrev
       
   349 
       
   350             # Base revision is a parent that hasn't been emitted already.
       
   351             # Use it if we can assume the receiver has the parent revision.
       
   352             elif (assumehaveparentrevisions
       
   353                   and deltaparentrev in (p1rev, p2rev)):
       
   354                 baserev = deltaparentrev
       
   355 
       
   356             # No guarantee the receiver has the delta parent. Send delta
       
   357             # against last revision (if possible), which in the common case
       
   358             # should be similar enough to this revision that the delta is
       
   359             # reasonable.
       
   360             elif prevrev is not None:
       
   361                 baserev = prevrev
       
   362             else:
       
   363                 baserev = nullrev
       
   364 
       
   365         # Storage has a fulltext revision.
       
   366 
       
   367         # Let's use the previous revision, which is as good a guess as any.
       
   368         # There is definitely room to improve this logic.
       
   369         elif prevrev is not None:
       
   370             baserev = prevrev
       
   371         else:
       
   372             baserev = nullrev
       
   373 
       
   374         # But we can't actually use our chosen delta base for whatever
       
   375         # reason. Reset to fulltext.
       
   376         if baserev != nullrev and not candeltafn(baserev, rev):
       
   377             baserev = nullrev
       
   378 
       
   379         revision = None
       
   380         delta = None
       
   381         baserevisionsize = None
       
   382 
       
   383         if revisiondata:
       
   384             if store.iscensored(baserev) or store.iscensored(rev):
       
   385                 try:
       
   386                     revision = store.revision(node, raw=True)
       
   387                 except error.CensoredNodeError as e:
       
   388                     revision = e.tombstone
       
   389 
       
   390                 if baserev != nullrev:
       
   391                     baserevisionsize = rawsizefn(baserev)
       
   392 
       
   393             elif baserev == nullrev and not deltaprevious:
       
   394                 revision = store.revision(node, raw=True)
       
   395                 available.add(rev)
       
   396             else:
       
   397                 delta = revdifffn(baserev, rev)
       
   398                 available.add(rev)
       
   399 
       
   400         yield resultcls(
       
   401             node=node,
       
   402             p1node=fnode(p1rev),
       
   403             p2node=fnode(p2rev),
       
   404             basenode=fnode(baserev),
       
   405             flags=flagsfn(rev),
       
   406             baserevisionsize=baserevisionsize,
       
   407             revision=revision,
       
   408             delta=delta)
       
   409 
       
   410         prevrev = rev