--- a/mercurial/revlog.py Mon Sep 24 09:41:42 2018 -0700
+++ b/mercurial/revlog.py Fri Sep 21 14:28:21 2018 -0700
@@ -59,6 +59,7 @@
)
from . import (
ancestor,
+ dagop,
error,
mdiff,
policy,
@@ -242,17 +243,17 @@
flags = attr.ib()
@interfaceutil.implementer(repository.irevisiondelta)
-@attr.s(slots=True, frozen=True)
+@attr.s(slots=True)
class revlogrevisiondelta(object):
node = attr.ib()
p1node = attr.ib()
p2node = attr.ib()
basenode = attr.ib()
- linknode = attr.ib()
flags = attr.ib()
baserevisionsize = attr.ib()
revision = attr.ib()
delta = attr.ib()
+ linknode = attr.ib(default=None)
@interfaceutil.implementer(repository.iverifyproblem)
@attr.s(frozen=True)
@@ -2374,6 +2375,122 @@
prevrev = rev
+ def emitrevisions(self, nodes, nodesorder=None, revisiondata=False,
+ assumehaveparentrevisions=False, deltaprevious=False):
+ if nodesorder not in ('nodes', 'storage', None):
+ raise error.ProgrammingError('unhandled value for nodesorder: %s' %
+ nodesorder)
+
+ if nodesorder is None and not self._generaldelta:
+ nodesorder = 'storage'
+
+ frev = self.rev
+ fnode = self.node
+
+ if nodesorder == 'nodes':
+ revs = [frev(n) for n in nodes]
+ elif nodesorder == 'storage':
+ revs = sorted(frev(n) for n in nodes)
+ else:
+ assert self._generaldelta
+ revs = set(frev(n) for n in nodes)
+ revs = dagop.linearize(revs, self.parentrevs)
+
+ prevrev = None
+
+ if deltaprevious or assumehaveparentrevisions:
+ prevrev = self.parentrevs(revs[0])[0]
+
+ # Set of revs available to delta against.
+ available = set()
+
+ for rev in revs:
+ if rev == nullrev:
+ continue
+
+ node = fnode(rev)
+ deltaparentrev = self.deltaparent(rev)
+ p1rev, p2rev = self.parentrevs(rev)
+
+ # Forced delta against previous mode.
+ if deltaprevious:
+ baserev = prevrev
+
+ # Revlog is configured to use full snapshots. Stick to that.
+ elif not self._storedeltachains:
+ baserev = nullrev
+
+ # There is a delta in storage. We try to use that because it
+ # amounts to effectively copying data from storage and is
+ # therefore the fastest.
+ elif deltaparentrev != nullrev:
+ # Base revision was already emitted in this group. We can
+ # always safely use the delta.
+ if deltaparentrev in available:
+ baserev = deltaparentrev
+
+ # Base revision is a parent that hasn't been emitted already.
+ # Use it if we can assume the receiver has the parent revision.
+ elif (assumehaveparentrevisions
+ and deltaparentrev in (p1rev, p2rev)):
+ baserev = deltaparentrev
+
+ # No guarantee the receiver has the delta parent. Send delta
+ # against last revision (if possible), which in the common case
+ # should be similar enough to this revision that the delta is
+ # reasonable.
+ elif prevrev is not None:
+ baserev = prevrev
+ else:
+ baserev = nullrev
+
+ # Storage has a fulltext revision.
+
+ # Let's use the previous revision, which is as good a guess as any.
+ # There is definitely room to improve this logic.
+ elif prevrev is not None:
+ baserev = prevrev
+ else:
+ baserev = nullrev
+
+ # But we can't actually use our chosen delta base for whatever
+ # reason. Reset to fulltext.
+ if baserev != nullrev and not self.candelta(baserev, rev):
+ baserev = nullrev
+
+ revision = None
+ delta = None
+ baserevisionsize = None
+
+ if revisiondata:
+ if self.iscensored(baserev) or self.iscensored(rev):
+ try:
+ revision = self.revision(node, raw=True)
+ except error.CensoredNodeError as e:
+ revision = e.tombstone
+
+ if baserev != nullrev:
+ baserevisionsize = self.rawsize(baserev)
+
+ elif baserev == nullrev and not deltaprevious:
+ revision = self.revision(node, raw=True)
+ available.add(rev)
+ else:
+ delta = self.revdiff(baserev, rev)
+ available.add(rev)
+
+ yield revlogrevisiondelta(
+ node=node,
+ p1node=fnode(p1rev),
+ p2node=fnode(p2rev),
+ basenode=fnode(baserev),
+ flags=self.flags(rev),
+ baserevisionsize=baserevisionsize,
+ revision=revision,
+ delta=delta)
+
+ prevrev = rev
+
DELTAREUSEALWAYS = 'always'
DELTAREUSESAMEREVS = 'samerevs'
DELTAREUSENEVER = 'never'