mercurial/revlog.py
changeset 36768 7bf80d9d9543
parent 36745 6bacb2f663cb
parent 35841 369aadf7a326
child 37087 f0b6fbea00cf
equal deleted inserted replaced
36767:4c71a26a4009 36768:7bf80d9d9543
    75     REVIDX_ISCENSORED,
    75     REVIDX_ISCENSORED,
    76     REVIDX_ELLIPSIS,
    76     REVIDX_ELLIPSIS,
    77     REVIDX_EXTSTORED,
    77     REVIDX_EXTSTORED,
    78 ]
    78 ]
    79 REVIDX_KNOWN_FLAGS = util.bitsfrom(REVIDX_FLAGS_ORDER)
    79 REVIDX_KNOWN_FLAGS = util.bitsfrom(REVIDX_FLAGS_ORDER)
       
    80 # bitmark for flags that could cause rawdata content change
       
    81 REVIDX_RAWTEXT_CHANGING_FLAGS = REVIDX_ISCENSORED | REVIDX_EXTSTORED
    80 
    82 
    81 # max size of revlog with inline data
    83 # max size of revlog with inline data
    82 _maxinline = 131072
    84 _maxinline = 131072
    83 _chunksize = 1048576
    85 _chunksize = 1048576
    84 
    86 
    94 
    96 
    95 def addflagprocessor(flag, processor):
    97 def addflagprocessor(flag, processor):
    96     """Register a flag processor on a revision data flag.
    98     """Register a flag processor on a revision data flag.
    97 
    99 
    98     Invariant:
   100     Invariant:
    99     - Flags need to be defined in REVIDX_KNOWN_FLAGS and REVIDX_FLAGS_ORDER.
   101     - Flags need to be defined in REVIDX_KNOWN_FLAGS and REVIDX_FLAGS_ORDER,
       
   102       and REVIDX_RAWTEXT_CHANGING_FLAGS if they can alter rawtext.
   100     - Only one flag processor can be registered on a specific flag.
   103     - Only one flag processor can be registered on a specific flag.
   101     - flagprocessors must be 3-tuples of functions (read, write, raw) with the
   104     - flagprocessors must be 3-tuples of functions (read, write, raw) with the
   102       following signatures:
   105       following signatures:
   103           - (read)  f(self, rawtext) -> text, bool
   106           - (read)  f(self, rawtext) -> text, bool
   104           - (write) f(self, text) -> rawtext, bool
   107           - (write) f(self, text) -> rawtext, bool
   331         hlen = struct.calcsize(">lll")
   334         hlen = struct.calcsize(">lll")
   332         if delta[:hlen] == mdiff.replacediffheader(revlog.rawsize(baserev),
   335         if delta[:hlen] == mdiff.replacediffheader(revlog.rawsize(baserev),
   333                                                    len(delta) - hlen):
   336                                                    len(delta) - hlen):
   334             btext[0] = delta[hlen:]
   337             btext[0] = delta[hlen:]
   335         else:
   338         else:
   336             basetext = revlog.revision(baserev, _df=fh, raw=True)
   339             # deltabase is rawtext before changed by flag processors, which is
       
   340             # equivalent to non-raw text
       
   341             basetext = revlog.revision(baserev, _df=fh, raw=False)
   337             btext[0] = mdiff.patch(basetext, delta)
   342             btext[0] = mdiff.patch(basetext, delta)
   338 
   343 
   339         try:
   344         try:
   340             res = revlog._processflags(btext[0], flags, 'read', raw=True)
   345             res = revlog._processflags(btext[0], flags, 'read', raw=True)
   341             btext[0], validatehash = res
   346             btext[0], validatehash = res
   402 
   407 
   403         deltainfo = None
   408         deltainfo = None
   404         for candidaterevs in self._getcandidaterevs(p1, p2, cachedelta):
   409         for candidaterevs in self._getcandidaterevs(p1, p2, cachedelta):
   405             nominateddeltas = []
   410             nominateddeltas = []
   406             for candidaterev in candidaterevs:
   411             for candidaterev in candidaterevs:
       
   412                 # no delta for rawtext-changing revs (see "candelta" for why)
       
   413                 if revlog.flags(candidaterev) & REVIDX_RAWTEXT_CHANGING_FLAGS:
       
   414                     continue
   407                 candidatedelta = self._builddeltainfo(revinfo, candidaterev, fh)
   415                 candidatedelta = self._builddeltainfo(revinfo, candidaterev, fh)
   408                 if revlog._isgooddeltainfo(candidatedelta, revinfo.textlen):
   416                 if revlog._isgooddeltainfo(candidatedelta, revinfo.textlen):
   409                     nominateddeltas.append(candidatedelta)
   417                     nominateddeltas.append(candidatedelta)
   410             if nominateddeltas:
   418             if nominateddeltas:
   411                 deltainfo = min(nominateddeltas, key=lambda x: x.deltalen)
   419                 deltainfo = min(nominateddeltas, key=lambda x: x.deltalen)
   735         try:
   743         try:
   736             self.rev(node)
   744             self.rev(node)
   737             return True
   745             return True
   738         except KeyError:
   746         except KeyError:
   739             return False
   747             return False
       
   748 
       
   749     def candelta(self, baserev, rev):
       
   750         """whether two revisions (baserev, rev) can be delta-ed or not"""
       
   751         # Disable delta if either rev requires a content-changing flag
       
   752         # processor (ex. LFS). This is because such flag processor can alter
       
   753         # the rawtext content that the delta will be based on, and two clients
       
   754         # could have a same revlog node with different flags (i.e. different
       
   755         # rawtext contents) and the delta could be incompatible.
       
   756         if ((self.flags(baserev) & REVIDX_RAWTEXT_CHANGING_FLAGS)
       
   757             or (self.flags(rev) & REVIDX_RAWTEXT_CHANGING_FLAGS)):
       
   758             return False
       
   759         return True
   740 
   760 
   741     def clearcaches(self):
   761     def clearcaches(self):
   742         self._cache = None
   762         self._cache = None
   743         self._chainbasecache.clear()
   763         self._chainbasecache.clear()
   744         self._chunkcache = (0, '')
   764         self._chunkcache = (0, '')
  2076         p1r, p2r = self.rev(p1), self.rev(p2)
  2096         p1r, p2r = self.rev(p1), self.rev(p2)
  2077 
  2097 
  2078         # full versions are inserted when the needed deltas
  2098         # full versions are inserted when the needed deltas
  2079         # become comparable to the uncompressed text
  2099         # become comparable to the uncompressed text
  2080         if rawtext is None:
  2100         if rawtext is None:
  2081             textlen = mdiff.patchedsize(self.rawsize(cachedelta[0]),
  2101             # need rawtext size, before changed by flag processors, which is
       
  2102             # the non-raw size. use revlog explicitly to avoid filelog's extra
       
  2103             # logic that might remove metadata size.
       
  2104             textlen = mdiff.patchedsize(revlog.size(self, cachedelta[0]),
  2082                                         cachedelta[1])
  2105                                         cachedelta[1])
  2083         else:
  2106         else:
  2084             textlen = len(rawtext)
  2107             textlen = len(rawtext)
  2085 
  2108 
  2086         if deltacomputer is None:
  2109         if deltacomputer is None:
  2087             deltacomputer = _deltacomputer(self)
  2110             deltacomputer = _deltacomputer(self)
  2088 
  2111 
  2089         revinfo = _revisioninfo(node, p1, p2, btext, textlen, cachedelta, flags)
  2112         revinfo = _revisioninfo(node, p1, p2, btext, textlen, cachedelta, flags)
  2090         deltainfo = deltacomputer.finddeltainfo(revinfo, fh)
  2113 
       
  2114         # no delta for flag processor revision (see "candelta" for why)
       
  2115         # not calling candelta since only one revision needs test, also to
       
  2116         # avoid overhead fetching flags again.
       
  2117         if flags & REVIDX_RAWTEXT_CHANGING_FLAGS:
       
  2118             deltainfo = None
       
  2119         else:
       
  2120             deltainfo = deltacomputer.finddeltainfo(revinfo, fh)
  2091 
  2121 
  2092         if deltainfo is not None:
  2122         if deltainfo is not None:
  2093             base = deltainfo.base
  2123             base = deltainfo.base
  2094             chainbase = deltainfo.chainbase
  2124             chainbase = deltainfo.chainbase
  2095             data = deltainfo.data
  2125             data = deltainfo.data