diff --git a/mercurial/filelog.py b/mercurial/filelog.py --- a/mercurial/filelog.py +++ b/mercurial/filelog.py @@ -5,8 +5,8 @@ # This software may be used and distributed according to the terms of the # GNU General Public License version 2 or any later version. -import error, revlog -import re +import error, mdiff, revlog +import re, struct _mdre = re.compile('\1\n') def parsemeta(text): @@ -107,3 +107,23 @@ class filelog(revlog.revlog): def iscensored(self, rev): """Check if a file revision is censored.""" return self.flags(rev) & revlog.REVIDX_ISCENSORED + + def _peek_iscensored(self, baserev, delta, flush): + """Quickly check if a delta produces a censored revision.""" + # Fragile heuristic: unless new file meta keys are added alphabetically + # preceding "censored", all censored revisions are prefixed by + # "\1\ncensored:". A delta producing such a censored revision must be a + # full-replacement delta, so we inspect the first and only patch in the + # delta for this prefix. + hlen = struct.calcsize(">lll") + if len(delta) <= hlen: + return False + + oldlen = self.rawsize(baserev) + newlen = len(delta) - hlen + if delta[:hlen] != mdiff.replacediffheader(oldlen, newlen): + return False + + add = "\1\ncensored:" + addlen = len(add) + return newlen >= addlen and delta[hlen:hlen + addlen] == add diff --git a/mercurial/revlog.py b/mercurial/revlog.py --- a/mercurial/revlog.py +++ b/mercurial/revlog.py @@ -1386,7 +1386,10 @@ class revlog(object): transaction.add(self.indexfile, isize, r) transaction.add(self.datafile, end) dfh = self.opener(self.datafile, "a") - + def flush(): + if dfh: + dfh.flush() + ifh.flush() try: # loop through our set of deltas chain = None @@ -1430,9 +1433,13 @@ class revlog(object): raise error.CensoredBaseError(self.indexfile, self.node(baserev)) + flags = REVIDX_DEFAULT_FLAGS + if self._peek_iscensored(baserev, delta, flush): + flags |= REVIDX_ISCENSORED + chain = self._addrevision(node, None, transaction, link, - p1, p2, REVIDX_DEFAULT_FLAGS, - (baserev, delta), ifh, dfh) + p1, p2, flags, (baserev, delta), + ifh, dfh) if not dfh and not self._inline: # addrevision switched from inline to conventional # reopen the index @@ -1450,6 +1457,10 @@ class revlog(object): """Check if a file revision is censored.""" return False + def _peek_iscensored(self, baserev, delta, flush): + """Quickly check if a delta produces a censored revision.""" + return False + def getstrippoint(self, minlink): """find the minimum rev that must be stripped to strip the linkrev