mercurial/revlog.py
changeset 37443 65250a66b55c
parent 37442 0596d27457c6
child 37449 a0d71618074f
equal deleted inserted replaced
37442:0596d27457c6 37443:65250a66b55c
   115 def packmeta(meta, text):
   115 def packmeta(meta, text):
   116     keys = sorted(meta)
   116     keys = sorted(meta)
   117     metatext = "".join("%s: %s\n" % (k, meta[k]) for k in keys)
   117     metatext = "".join("%s: %s\n" % (k, meta[k]) for k in keys)
   118     return "\1\n%s\1\n%s" % (metatext, text)
   118     return "\1\n%s\1\n%s" % (metatext, text)
   119 
   119 
       
   120 def _censoredtext(text):
       
   121     m, offs = parsemeta(text)
       
   122     return m and "censored" in m
       
   123 
   120 def addflagprocessor(flag, processor):
   124 def addflagprocessor(flag, processor):
   121     """Register a flag processor on a revision data flag.
   125     """Register a flag processor on a revision data flag.
   122 
   126 
   123     Invariant:
   127     Invariant:
   124     - Flags need to be defined in REVIDX_KNOWN_FLAGS and REVIDX_FLAGS_ORDER,
   128     - Flags need to be defined in REVIDX_KNOWN_FLAGS and REVIDX_FLAGS_ORDER,
   572     writing, to avoid file stat ambiguity.
   576     writing, to avoid file stat ambiguity.
   573 
   577 
   574     If mmaplargeindex is True, and an mmapindexthreshold is set, the
   578     If mmaplargeindex is True, and an mmapindexthreshold is set, the
   575     index will be mmapped rather than read if it is larger than the
   579     index will be mmapped rather than read if it is larger than the
   576     configured threshold.
   580     configured threshold.
       
   581 
       
   582     If censorable is True, the revlog can have censored revisions.
   577     """
   583     """
   578     def __init__(self, opener, indexfile, datafile=None, checkambig=False,
   584     def __init__(self, opener, indexfile, datafile=None, checkambig=False,
   579                  mmaplargeindex=False):
   585                  mmaplargeindex=False, censorable=False):
   580         """
   586         """
   581         create a revlog object
   587         create a revlog object
   582 
   588 
   583         opener is a function that abstracts the file opening operation
   589         opener is a function that abstracts the file opening operation
   584         and can be used to implement COW semantics or the like.
   590         and can be used to implement COW semantics or the like.
   587         self.datafile = datafile or (indexfile[:-2] + ".d")
   593         self.datafile = datafile or (indexfile[:-2] + ".d")
   588         self.opener = opener
   594         self.opener = opener
   589         #  When True, indexfile is opened with checkambig=True at writing, to
   595         #  When True, indexfile is opened with checkambig=True at writing, to
   590         #  avoid file stat ambiguity.
   596         #  avoid file stat ambiguity.
   591         self._checkambig = checkambig
   597         self._checkambig = checkambig
       
   598         self._censorable = censorable
   592         # 3-tuple of (node, rev, text) for a raw revision.
   599         # 3-tuple of (node, rev, text) for a raw revision.
   593         self._cache = None
   600         self._cache = None
   594         # Maps rev to chain base rev.
   601         # Maps rev to chain base rev.
   595         self._chainbasecache = util.lrucachedict(100)
   602         self._chainbasecache = util.lrucachedict(100)
   596         # 2-tuple of (offset, data) of raw data from the revlog at an offset.
   603         # 2-tuple of (offset, data) of raw data from the revlog at an offset.
  1865         """Check node hash integrity.
  1872         """Check node hash integrity.
  1866 
  1873 
  1867         Available as a function so that subclasses can extend hash mismatch
  1874         Available as a function so that subclasses can extend hash mismatch
  1868         behaviors as needed.
  1875         behaviors as needed.
  1869         """
  1876         """
  1870         if p1 is None and p2 is None:
  1877         try:
  1871             p1, p2 = self.parents(node)
  1878             if p1 is None and p2 is None:
  1872         if node != self.hash(text, p1, p2):
  1879                 p1, p2 = self.parents(node)
  1873             revornode = rev
  1880             if node != self.hash(text, p1, p2):
  1874             if revornode is None:
  1881                 revornode = rev
  1875                 revornode = templatefilters.short(hex(node))
  1882                 if revornode is None:
  1876             raise RevlogError(_("integrity check failed on %s:%s")
  1883                     revornode = templatefilters.short(hex(node))
  1877                 % (self.indexfile, pycompat.bytestr(revornode)))
  1884                 raise RevlogError(_("integrity check failed on %s:%s")
       
  1885                     % (self.indexfile, pycompat.bytestr(revornode)))
       
  1886         except RevlogError:
       
  1887             if self._censorable and _censoredtext(text):
       
  1888                 raise error.CensoredNodeError(self.indexfile, node, text)
       
  1889             raise
  1878 
  1890 
  1879     def _enforceinlinesize(self, tr, fp=None):
  1891     def _enforceinlinesize(self, tr, fp=None):
  1880         """Check if the revlog is too big for inline and convert if so.
  1892         """Check if the revlog is too big for inline and convert if so.
  1881 
  1893 
  1882         This should be called after revisions are added to the revlog. If the
  1894         This should be called after revisions are added to the revlog. If the
  2298 
  2310 
  2299         return nodes
  2311         return nodes
  2300 
  2312 
  2301     def iscensored(self, rev):
  2313     def iscensored(self, rev):
  2302         """Check if a file revision is censored."""
  2314         """Check if a file revision is censored."""
  2303         return False
  2315         if not self._censorable:
       
  2316             return False
       
  2317 
       
  2318         return self.flags(rev) & REVIDX_ISCENSORED
  2304 
  2319 
  2305     def _peek_iscensored(self, baserev, delta, flush):
  2320     def _peek_iscensored(self, baserev, delta, flush):
  2306         """Quickly check if a delta produces a censored revision."""
  2321         """Quickly check if a delta produces a censored revision."""
  2307         return False
  2322         if not self._censorable:
       
  2323             return False
       
  2324 
       
  2325         # Fragile heuristic: unless new file meta keys are added alphabetically
       
  2326         # preceding "censored", all censored revisions are prefixed by
       
  2327         # "\1\ncensored:". A delta producing such a censored revision must be a
       
  2328         # full-replacement delta, so we inspect the first and only patch in the
       
  2329         # delta for this prefix.
       
  2330         hlen = struct.calcsize(">lll")
       
  2331         if len(delta) <= hlen:
       
  2332             return False
       
  2333 
       
  2334         oldlen = self.rawsize(baserev)
       
  2335         newlen = len(delta) - hlen
       
  2336         if delta[:hlen] != mdiff.replacediffheader(oldlen, newlen):
       
  2337             return False
       
  2338 
       
  2339         add = "\1\ncensored:"
       
  2340         addlen = len(add)
       
  2341         return newlen >= addlen and delta[hlen:hlen + addlen] == add
  2308 
  2342 
  2309     def getstrippoint(self, minlink):
  2343     def getstrippoint(self, minlink):
  2310         """find the minimum rev that must be stripped to strip the linkrev
  2344         """find the minimum rev that must be stripped to strip the linkrev
  2311 
  2345 
  2312         Returns a tuple containing the minimum rev and a set of all revs that
  2346         Returns a tuple containing the minimum rev and a set of all revs that