revlog: special case expanding full-replacement deltas received by exchange
When a delta received through exchange is added to a revlog, it will very
often be expanded to a full text by applying the delta to its base. If
that delta is of a particular form, we can avoid decoding the base revision.
This avoids an exception if the base revision is censored.
For background and broader design of the censorship feature, see:
http://mercurial.selenic.com/wiki/CensorPlan
--- a/mercurial/revlog.py Tue Feb 10 16:17:15 2015 -0800
+++ b/mercurial/revlog.py Fri Feb 06 01:38:16 2015 +0000
@@ -1233,8 +1233,18 @@
if dfh:
dfh.flush()
ifh.flush()
- basetext = self.revision(self.node(cachedelta[0]))
- btext[0] = mdiff.patch(basetext, cachedelta[1])
+ baserev = cachedelta[0]
+ delta = cachedelta[1]
+ # special case deltas which replace entire base; no need to decode
+ # base revision. this neatly avoids censored bases, which throw when
+ # they're decoded.
+ hlen = struct.calcsize(">lll")
+ if delta[:hlen] == mdiff.replacediffheader(self.rawsize(baserev),
+ len(delta) - hlen):
+ btext[0] = delta[hlen:]
+ else:
+ basetext = self.revision(self.node(baserev))
+ btext[0] = mdiff.patch(basetext, delta)
try:
self.checkhash(btext[0], p1, p2, node)
if flags & REVIDX_ISCENSORED: