mercurial/revlog.py
changeset 43077 687b865b95ad
parent 43076 2372284d9457
child 43089 c59eb1560c44
equal deleted inserted replaced
43076:2372284d9457 43077:687b865b95ad
   140     return int(q & 0xFFFF)
   140     return int(q & 0xFFFF)
   141 
   141 
   142 
   142 
   143 def offset_type(offset, type):
   143 def offset_type(offset, type):
   144     if (type & ~flagutil.REVIDX_KNOWN_FLAGS) != 0:
   144     if (type & ~flagutil.REVIDX_KNOWN_FLAGS) != 0:
   145         raise ValueError('unknown revlog index flags')
   145         raise ValueError(b'unknown revlog index flags')
   146     return int(int(offset) << 16 | type)
   146     return int(int(offset) << 16 | type)
   147 
   147 
   148 
   148 
   149 @attr.s(slots=True, frozen=True)
   149 @attr.s(slots=True, frozen=True)
   150 class _revisioninfo(object):
   150 class _revisioninfo(object):
   195 #  4 bytes: base rev
   195 #  4 bytes: base rev
   196 #  4 bytes: link rev
   196 #  4 bytes: link rev
   197 # 20 bytes: parent 1 nodeid
   197 # 20 bytes: parent 1 nodeid
   198 # 20 bytes: parent 2 nodeid
   198 # 20 bytes: parent 2 nodeid
   199 # 20 bytes: nodeid
   199 # 20 bytes: nodeid
   200 indexformatv0 = struct.Struct(">4l20s20s20s")
   200 indexformatv0 = struct.Struct(b">4l20s20s20s")
   201 indexformatv0_pack = indexformatv0.pack
   201 indexformatv0_pack = indexformatv0.pack
   202 indexformatv0_unpack = indexformatv0.unpack
   202 indexformatv0_unpack = indexformatv0.unpack
   203 
   203 
   204 
   204 
   205 class revlogoldindex(list):
   205 class revlogoldindex(list):
   241         return revlogoldindex(index), nodemap, None
   241         return revlogoldindex(index), nodemap, None
   242 
   242 
   243     def packentry(self, entry, node, version, rev):
   243     def packentry(self, entry, node, version, rev):
   244         if gettype(entry[0]):
   244         if gettype(entry[0]):
   245             raise error.RevlogError(
   245             raise error.RevlogError(
   246                 _('index entry flags need revlog ' 'version 1')
   246                 _(b'index entry flags need revlog ' b'version 1')
   247             )
   247             )
   248         e2 = (
   248         e2 = (
   249             getoffset(entry[0]),
   249             getoffset(entry[0]),
   250             entry[1],
   250             entry[1],
   251             entry[3],
   251             entry[3],
   265 #  4 bytes: base rev
   265 #  4 bytes: base rev
   266 #  4 bytes: link rev
   266 #  4 bytes: link rev
   267 #  4 bytes: parent 1 rev
   267 #  4 bytes: parent 1 rev
   268 #  4 bytes: parent 2 rev
   268 #  4 bytes: parent 2 rev
   269 # 32 bytes: nodeid
   269 # 32 bytes: nodeid
   270 indexformatng = struct.Struct(">Qiiiiii20s12x")
   270 indexformatng = struct.Struct(b">Qiiiiii20s12x")
   271 indexformatng_pack = indexformatng.pack
   271 indexformatng_pack = indexformatng.pack
   272 versionformat = struct.Struct(">I")
   272 versionformat = struct.Struct(b">I")
   273 versionformat_pack = versionformat.pack
   273 versionformat_pack = versionformat.pack
   274 versionformat_unpack = versionformat.unpack
   274 versionformat_unpack = versionformat.unpack
   275 
   275 
   276 # corresponds to uncompressed length of indexformatng (2 gigs, 4-byte
   276 # corresponds to uncompressed length of indexformatng (2 gigs, 4-byte
   277 # signed integer)
   277 # signed integer)
   351         and can be used to implement COW semantics or the like.
   351         and can be used to implement COW semantics or the like.
   352 
   352 
   353         """
   353         """
   354         self.upperboundcomp = upperboundcomp
   354         self.upperboundcomp = upperboundcomp
   355         self.indexfile = indexfile
   355         self.indexfile = indexfile
   356         self.datafile = datafile or (indexfile[:-2] + ".d")
   356         self.datafile = datafile or (indexfile[:-2] + b".d")
   357         self.opener = opener
   357         self.opener = opener
   358         #  When True, indexfile is opened with checkambig=True at writing, to
   358         #  When True, indexfile is opened with checkambig=True at writing, to
   359         #  avoid file stat ambiguity.
   359         #  avoid file stat ambiguity.
   360         self._checkambig = checkambig
   360         self._checkambig = checkambig
   361         self._mmaplargeindex = mmaplargeindex
   361         self._mmaplargeindex = mmaplargeindex
   363         # 3-tuple of (node, rev, text) for a raw revision.
   363         # 3-tuple of (node, rev, text) for a raw revision.
   364         self._revisioncache = None
   364         self._revisioncache = None
   365         # Maps rev to chain base rev.
   365         # Maps rev to chain base rev.
   366         self._chainbasecache = util.lrucachedict(100)
   366         self._chainbasecache = util.lrucachedict(100)
   367         # 2-tuple of (offset, data) of raw data from the revlog at an offset.
   367         # 2-tuple of (offset, data) of raw data from the revlog at an offset.
   368         self._chunkcache = (0, '')
   368         self._chunkcache = (0, b'')
   369         # How much data to read and cache into the raw revlog data cache.
   369         # How much data to read and cache into the raw revlog data cache.
   370         self._chunkcachesize = 65536
   370         self._chunkcachesize = 65536
   371         self._maxchainlen = None
   371         self._maxchainlen = None
   372         self._deltabothparents = True
   372         self._deltabothparents = True
   373         self.index = []
   373         self.index = []
   374         # Mapping of partial identifiers to full nodes.
   374         # Mapping of partial identifiers to full nodes.
   375         self._pcache = {}
   375         self._pcache = {}
   376         # Mapping of revision integer to full node.
   376         # Mapping of revision integer to full node.
   377         self._nodecache = {nullid: nullrev}
   377         self._nodecache = {nullid: nullrev}
   378         self._nodepos = None
   378         self._nodepos = None
   379         self._compengine = 'zlib'
   379         self._compengine = b'zlib'
   380         self._compengineopts = {}
   380         self._compengineopts = {}
   381         self._maxdeltachainspan = -1
   381         self._maxdeltachainspan = -1
   382         self._withsparseread = False
   382         self._withsparseread = False
   383         self._sparserevlog = False
   383         self._sparserevlog = False
   384         self._srdensitythreshold = 0.50
   384         self._srdensitythreshold = 0.50
   395 
   395 
   396     def _loadindex(self):
   396     def _loadindex(self):
   397         mmapindexthreshold = None
   397         mmapindexthreshold = None
   398         opts = self.opener.options
   398         opts = self.opener.options
   399 
   399 
   400         if 'revlogv2' in opts:
   400         if b'revlogv2' in opts:
   401             newversionflags = REVLOGV2 | FLAG_INLINE_DATA
   401             newversionflags = REVLOGV2 | FLAG_INLINE_DATA
   402         elif 'revlogv1' in opts:
   402         elif b'revlogv1' in opts:
   403             newversionflags = REVLOGV1 | FLAG_INLINE_DATA
   403             newversionflags = REVLOGV1 | FLAG_INLINE_DATA
   404             if 'generaldelta' in opts:
   404             if b'generaldelta' in opts:
   405                 newversionflags |= FLAG_GENERALDELTA
   405                 newversionflags |= FLAG_GENERALDELTA
   406         elif 'revlogv0' in self.opener.options:
   406         elif b'revlogv0' in self.opener.options:
   407             newversionflags = REVLOGV0
   407             newversionflags = REVLOGV0
   408         else:
   408         else:
   409             newversionflags = REVLOG_DEFAULT_VERSION
   409             newversionflags = REVLOG_DEFAULT_VERSION
   410 
   410 
   411         if 'chunkcachesize' in opts:
   411         if b'chunkcachesize' in opts:
   412             self._chunkcachesize = opts['chunkcachesize']
   412             self._chunkcachesize = opts[b'chunkcachesize']
   413         if 'maxchainlen' in opts:
   413         if b'maxchainlen' in opts:
   414             self._maxchainlen = opts['maxchainlen']
   414             self._maxchainlen = opts[b'maxchainlen']
   415         if 'deltabothparents' in opts:
   415         if b'deltabothparents' in opts:
   416             self._deltabothparents = opts['deltabothparents']
   416             self._deltabothparents = opts[b'deltabothparents']
   417         self._lazydelta = bool(opts.get('lazydelta', True))
   417         self._lazydelta = bool(opts.get(b'lazydelta', True))
   418         self._lazydeltabase = False
   418         self._lazydeltabase = False
   419         if self._lazydelta:
   419         if self._lazydelta:
   420             self._lazydeltabase = bool(opts.get('lazydeltabase', False))
   420             self._lazydeltabase = bool(opts.get(b'lazydeltabase', False))
   421         if 'compengine' in opts:
   421         if b'compengine' in opts:
   422             self._compengine = opts['compengine']
   422             self._compengine = opts[b'compengine']
   423         if 'zlib.level' in opts:
   423         if b'zlib.level' in opts:
   424             self._compengineopts['zlib.level'] = opts['zlib.level']
   424             self._compengineopts[b'zlib.level'] = opts[b'zlib.level']
   425         if 'zstd.level' in opts:
   425         if b'zstd.level' in opts:
   426             self._compengineopts['zstd.level'] = opts['zstd.level']
   426             self._compengineopts[b'zstd.level'] = opts[b'zstd.level']
   427         if 'maxdeltachainspan' in opts:
   427         if b'maxdeltachainspan' in opts:
   428             self._maxdeltachainspan = opts['maxdeltachainspan']
   428             self._maxdeltachainspan = opts[b'maxdeltachainspan']
   429         if self._mmaplargeindex and 'mmapindexthreshold' in opts:
   429         if self._mmaplargeindex and b'mmapindexthreshold' in opts:
   430             mmapindexthreshold = opts['mmapindexthreshold']
   430             mmapindexthreshold = opts[b'mmapindexthreshold']
   431         self.hassidedata = bool(opts.get('side-data', False))
   431         self.hassidedata = bool(opts.get(b'side-data', False))
   432         if self.hassidedata:
   432         if self.hassidedata:
   433             self._flagprocessors[REVIDX_SIDEDATA] = sidedatautil.processors
   433             self._flagprocessors[REVIDX_SIDEDATA] = sidedatautil.processors
   434         self._sparserevlog = bool(opts.get('sparse-revlog', False))
   434         self._sparserevlog = bool(opts.get(b'sparse-revlog', False))
   435         withsparseread = bool(opts.get('with-sparse-read', False))
   435         withsparseread = bool(opts.get(b'with-sparse-read', False))
   436         # sparse-revlog forces sparse-read
   436         # sparse-revlog forces sparse-read
   437         self._withsparseread = self._sparserevlog or withsparseread
   437         self._withsparseread = self._sparserevlog or withsparseread
   438         if 'sparse-read-density-threshold' in opts:
   438         if b'sparse-read-density-threshold' in opts:
   439             self._srdensitythreshold = opts['sparse-read-density-threshold']
   439             self._srdensitythreshold = opts[b'sparse-read-density-threshold']
   440         if 'sparse-read-min-gap-size' in opts:
   440         if b'sparse-read-min-gap-size' in opts:
   441             self._srmingapsize = opts['sparse-read-min-gap-size']
   441             self._srmingapsize = opts[b'sparse-read-min-gap-size']
   442         if opts.get('enableellipsis'):
   442         if opts.get(b'enableellipsis'):
   443             self._flagprocessors[REVIDX_ELLIPSIS] = ellipsisprocessor
   443             self._flagprocessors[REVIDX_ELLIPSIS] = ellipsisprocessor
   444 
   444 
   445         # revlog v0 doesn't have flag processors
   445         # revlog v0 doesn't have flag processors
   446         for flag, processor in opts.get(b'flagprocessors', {}).iteritems():
   446         for flag, processor in opts.get(b'flagprocessors', {}).iteritems():
   447             flagutil.insertflagprocessor(flag, processor, self._flagprocessors)
   447             flagutil.insertflagprocessor(flag, processor, self._flagprocessors)
   448 
   448 
   449         if self._chunkcachesize <= 0:
   449         if self._chunkcachesize <= 0:
   450             raise error.RevlogError(
   450             raise error.RevlogError(
   451                 _('revlog chunk cache size %r is not ' 'greater than 0')
   451                 _(b'revlog chunk cache size %r is not ' b'greater than 0')
   452                 % self._chunkcachesize
   452                 % self._chunkcachesize
   453             )
   453             )
   454         elif self._chunkcachesize & (self._chunkcachesize - 1):
   454         elif self._chunkcachesize & (self._chunkcachesize - 1):
   455             raise error.RevlogError(
   455             raise error.RevlogError(
   456                 _('revlog chunk cache size %r is not a ' 'power of 2')
   456                 _(b'revlog chunk cache size %r is not a ' b'power of 2')
   457                 % self._chunkcachesize
   457                 % self._chunkcachesize
   458             )
   458             )
   459 
   459 
   460         indexdata = ''
   460         indexdata = b''
   461         self._initempty = True
   461         self._initempty = True
   462         try:
   462         try:
   463             with self._indexfp() as f:
   463             with self._indexfp() as f:
   464                 if (
   464                 if (
   465                     mmapindexthreshold is not None
   465                     mmapindexthreshold is not None
   487         fmt = versionflags & 0xFFFF
   487         fmt = versionflags & 0xFFFF
   488 
   488 
   489         if fmt == REVLOGV0:
   489         if fmt == REVLOGV0:
   490             if flags:
   490             if flags:
   491                 raise error.RevlogError(
   491                 raise error.RevlogError(
   492                     _('unknown flags (%#04x) in version %d ' 'revlog %s')
   492                     _(b'unknown flags (%#04x) in version %d ' b'revlog %s')
   493                     % (flags >> 16, fmt, self.indexfile)
   493                     % (flags >> 16, fmt, self.indexfile)
   494                 )
   494                 )
   495 
   495 
   496             self._inline = False
   496             self._inline = False
   497             self._generaldelta = False
   497             self._generaldelta = False
   498 
   498 
   499         elif fmt == REVLOGV1:
   499         elif fmt == REVLOGV1:
   500             if flags & ~REVLOGV1_FLAGS:
   500             if flags & ~REVLOGV1_FLAGS:
   501                 raise error.RevlogError(
   501                 raise error.RevlogError(
   502                     _('unknown flags (%#04x) in version %d ' 'revlog %s')
   502                     _(b'unknown flags (%#04x) in version %d ' b'revlog %s')
   503                     % (flags >> 16, fmt, self.indexfile)
   503                     % (flags >> 16, fmt, self.indexfile)
   504                 )
   504                 )
   505 
   505 
   506             self._inline = versionflags & FLAG_INLINE_DATA
   506             self._inline = versionflags & FLAG_INLINE_DATA
   507             self._generaldelta = versionflags & FLAG_GENERALDELTA
   507             self._generaldelta = versionflags & FLAG_GENERALDELTA
   508 
   508 
   509         elif fmt == REVLOGV2:
   509         elif fmt == REVLOGV2:
   510             if flags & ~REVLOGV2_FLAGS:
   510             if flags & ~REVLOGV2_FLAGS:
   511                 raise error.RevlogError(
   511                 raise error.RevlogError(
   512                     _('unknown flags (%#04x) in version %d ' 'revlog %s')
   512                     _(b'unknown flags (%#04x) in version %d ' b'revlog %s')
   513                     % (flags >> 16, fmt, self.indexfile)
   513                     % (flags >> 16, fmt, self.indexfile)
   514                 )
   514                 )
   515 
   515 
   516             self._inline = versionflags & FLAG_INLINE_DATA
   516             self._inline = versionflags & FLAG_INLINE_DATA
   517             # generaldelta implied by version 2 revlogs.
   517             # generaldelta implied by version 2 revlogs.
   518             self._generaldelta = True
   518             self._generaldelta = True
   519 
   519 
   520         else:
   520         else:
   521             raise error.RevlogError(
   521             raise error.RevlogError(
   522                 _('unknown version (%d) in revlog %s') % (fmt, self.indexfile)
   522                 _(b'unknown version (%d) in revlog %s') % (fmt, self.indexfile)
   523             )
   523             )
   524         # sparse-revlog can't be on without general-delta (issue6056)
   524         # sparse-revlog can't be on without general-delta (issue6056)
   525         if not self._generaldelta:
   525         if not self._generaldelta:
   526             self._sparserevlog = False
   526             self._sparserevlog = False
   527 
   527 
   531         if self.version == REVLOGV0:
   531         if self.version == REVLOGV0:
   532             self._io = revlogoldio()
   532             self._io = revlogoldio()
   533         try:
   533         try:
   534             d = self._io.parseindex(indexdata, self._inline)
   534             d = self._io.parseindex(indexdata, self._inline)
   535         except (ValueError, IndexError):
   535         except (ValueError, IndexError):
   536             raise error.RevlogError(_("index %s is corrupted") % self.indexfile)
   536             raise error.RevlogError(
       
   537                 _(b"index %s is corrupted") % self.indexfile
       
   538             )
   537         self.index, nodemap, self._chunkcache = d
   539         self.index, nodemap, self._chunkcache = d
   538         if nodemap is not None:
   540         if nodemap is not None:
   539             self.nodemap = self._nodecache = nodemap
   541             self.nodemap = self._nodecache = nodemap
   540         if not self._chunkcache:
   542         if not self._chunkcache:
   541             self._chunkclear()
   543             self._chunkclear()
   547     @util.propertycache
   549     @util.propertycache
   548     def _compressor(self):
   550     def _compressor(self):
   549         engine = util.compengines[self._compengine]
   551         engine = util.compengines[self._compengine]
   550         return engine.revlogcompressor(self._compengineopts)
   552         return engine.revlogcompressor(self._compengineopts)
   551 
   553 
   552     def _indexfp(self, mode='r'):
   554     def _indexfp(self, mode=b'r'):
   553         """file object for the revlog's index file"""
   555         """file object for the revlog's index file"""
   554         args = {r'mode': mode}
   556         args = {r'mode': mode}
   555         if mode != 'r':
   557         if mode != b'r':
   556             args[r'checkambig'] = self._checkambig
   558             args[r'checkambig'] = self._checkambig
   557         if mode == 'w':
   559         if mode == b'w':
   558             args[r'atomictemp'] = True
   560             args[r'atomictemp'] = True
   559         return self.opener(self.indexfile, **args)
   561         return self.opener(self.indexfile, **args)
   560 
   562 
   561     def _datafp(self, mode='r'):
   563     def _datafp(self, mode=b'r'):
   562         """file object for the revlog's data file"""
   564         """file object for the revlog's data file"""
   563         return self.opener(self.datafile, mode=mode)
   565         return self.opener(self.datafile, mode=mode)
   564 
   566 
   565     @contextlib.contextmanager
   567     @contextlib.contextmanager
   566     def _datareadfp(self, existingfp=None):
   568     def _datareadfp(self, existingfp=None):
   633         return True
   635         return True
   634 
   636 
   635     def clearcaches(self):
   637     def clearcaches(self):
   636         self._revisioncache = None
   638         self._revisioncache = None
   637         self._chainbasecache.clear()
   639         self._chainbasecache.clear()
   638         self._chunkcache = (0, '')
   640         self._chunkcache = (0, b'')
   639         self._pcache = {}
   641         self._pcache = {}
   640 
   642 
   641         try:
   643         try:
   642             # If we are using the native C version, you are in a fun case
   644             # If we are using the native C version, you are in a fun case
   643             # where self.index, self.nodemap and self._nodecaches is the same
   645             # where self.index, self.nodemap and self._nodecaches is the same
   654             raise
   656             raise
   655         except error.RevlogError:
   657         except error.RevlogError:
   656             # parsers.c radix tree lookup failed
   658             # parsers.c radix tree lookup failed
   657             if node == wdirid or node in wdirfilenodeids:
   659             if node == wdirid or node in wdirfilenodeids:
   658                 raise error.WdirUnsupported
   660                 raise error.WdirUnsupported
   659             raise error.LookupError(node, self.indexfile, _('no node'))
   661             raise error.LookupError(node, self.indexfile, _(b'no node'))
   660         except KeyError:
   662         except KeyError:
   661             # pure python cache lookup failed
   663             # pure python cache lookup failed
   662             n = self._nodecache
   664             n = self._nodecache
   663             i = self.index
   665             i = self.index
   664             p = self._nodepos
   666             p = self._nodepos
   672                 if v == node:
   674                 if v == node:
   673                     self._nodepos = r - 1
   675                     self._nodepos = r - 1
   674                     return r
   676                     return r
   675             if node == wdirid or node in wdirfilenodeids:
   677             if node == wdirid or node in wdirfilenodeids:
   676                 raise error.WdirUnsupported
   678                 raise error.WdirUnsupported
   677             raise error.LookupError(node, self.indexfile, _('no node'))
   679             raise error.LookupError(node, self.indexfile, _(b'no node'))
   678 
   680 
   679     # Accessors for index entries.
   681     # Accessors for index entries.
   680 
   682 
   681     # First tuple entry is 8 bytes. First 6 bytes are offset. Last 2 bytes
   683     # First tuple entry is 8 bytes. First 6 bytes are offset. Last 2 bytes
   682     # are flags.
   684     # are flags.
   846         # and we're sure ancestors aren't filtered as well
   848         # and we're sure ancestors aren't filtered as well
   847 
   849 
   848         if rustancestor is not None:
   850         if rustancestor is not None:
   849             lazyancestors = rustancestor.LazyAncestors
   851             lazyancestors = rustancestor.LazyAncestors
   850             arg = self.index
   852             arg = self.index
   851         elif util.safehasattr(parsers, 'rustlazyancestors'):
   853         elif util.safehasattr(parsers, b'rustlazyancestors'):
   852             lazyancestors = ancestor.rustlazyancestors
   854             lazyancestors = ancestor.rustlazyancestors
   853             arg = self.index
   855             arg = self.index
   854         else:
   856         else:
   855             lazyancestors = ancestor.lazyancestors
   857             lazyancestors = ancestor.lazyancestors
   856             arg = self._uncheckedparentrevs
   858             arg = self._uncheckedparentrevs
  1287             except error.LookupError:
  1289             except error.LookupError:
  1288                 pass  # may be partial hex id
  1290                 pass  # may be partial hex id
  1289         try:
  1291         try:
  1290             # str(rev)
  1292             # str(rev)
  1291             rev = int(id)
  1293             rev = int(id)
  1292             if "%d" % rev != id:
  1294             if b"%d" % rev != id:
  1293                 raise ValueError
  1295                 raise ValueError
  1294             if rev < 0:
  1296             if rev < 0:
  1295                 rev = len(self) + rev
  1297                 rev = len(self) + rev
  1296             if rev < 0 or rev >= len(self):
  1298             if rev < 0 or rev >= len(self):
  1297                 raise ValueError
  1299                 raise ValueError
  1324         except error.RevlogError:
  1326         except error.RevlogError:
  1325             # parsers.c radix tree lookup gave multiple matches
  1327             # parsers.c radix tree lookup gave multiple matches
  1326             # fast path: for unfiltered changelog, radix tree is accurate
  1328             # fast path: for unfiltered changelog, radix tree is accurate
  1327             if not getattr(self, 'filteredrevs', None):
  1329             if not getattr(self, 'filteredrevs', None):
  1328                 raise error.AmbiguousPrefixLookupError(
  1330                 raise error.AmbiguousPrefixLookupError(
  1329                     id, self.indexfile, _('ambiguous identifier')
  1331                     id, self.indexfile, _(b'ambiguous identifier')
  1330                 )
  1332                 )
  1331             # fall through to slow path that filters hidden revisions
  1333             # fall through to slow path that filters hidden revisions
  1332         except (AttributeError, ValueError):
  1334         except (AttributeError, ValueError):
  1333             # we are pure python, or key was too short to search radix tree
  1335             # we are pure python, or key was too short to search radix tree
  1334             pass
  1336             pass
  1350                 if len(nl) > 0:
  1352                 if len(nl) > 0:
  1351                     if len(nl) == 1 and not maybewdir:
  1353                     if len(nl) == 1 and not maybewdir:
  1352                         self._pcache[id] = nl[0]
  1354                         self._pcache[id] = nl[0]
  1353                         return nl[0]
  1355                         return nl[0]
  1354                     raise error.AmbiguousPrefixLookupError(
  1356                     raise error.AmbiguousPrefixLookupError(
  1355                         id, self.indexfile, _('ambiguous identifier')
  1357                         id, self.indexfile, _(b'ambiguous identifier')
  1356                     )
  1358                     )
  1357                 if maybewdir:
  1359                 if maybewdir:
  1358                     raise error.WdirUnsupported
  1360                     raise error.WdirUnsupported
  1359                 return None
  1361                 return None
  1360             except TypeError:
  1362             except TypeError:
  1370             return n
  1372             return n
  1371         n = self._partialmatch(id)
  1373         n = self._partialmatch(id)
  1372         if n:
  1374         if n:
  1373             return n
  1375             return n
  1374 
  1376 
  1375         raise error.LookupError(id, self.indexfile, _('no match found'))
  1377         raise error.LookupError(id, self.indexfile, _(b'no match found'))
  1376 
  1378 
  1377     def shortest(self, node, minlength=1):
  1379     def shortest(self, node, minlength=1):
  1378         """Find the shortest unambiguous prefix that matches node."""
  1380         """Find the shortest unambiguous prefix that matches node."""
  1379 
  1381 
  1380         def isvalid(prefix):
  1382         def isvalid(prefix):
  1384                 return False
  1386                 return False
  1385             except error.WdirUnsupported:
  1387             except error.WdirUnsupported:
  1386                 # single 'ff...' match
  1388                 # single 'ff...' match
  1387                 return True
  1389                 return True
  1388             if matchednode is None:
  1390             if matchednode is None:
  1389                 raise error.LookupError(node, self.indexfile, _('no node'))
  1391                 raise error.LookupError(node, self.indexfile, _(b'no node'))
  1390             return True
  1392             return True
  1391 
  1393 
  1392         def maybewdir(prefix):
  1394         def maybewdir(prefix):
  1393             return all(c == 'f' for c in pycompat.iterbytestr(prefix))
  1395             return all(c == b'f' for c in pycompat.iterbytestr(prefix))
  1394 
  1396 
  1395         hexnode = hex(node)
  1397         hexnode = hex(node)
  1396 
  1398 
  1397         def disambiguate(hexnode, minlength):
  1399         def disambiguate(hexnode, minlength):
  1398             """Disambiguate against wdirid."""
  1400             """Disambiguate against wdirid."""
  1405             try:
  1407             try:
  1406                 length = max(self.index.shortest(node), minlength)
  1408                 length = max(self.index.shortest(node), minlength)
  1407                 return disambiguate(hexnode, length)
  1409                 return disambiguate(hexnode, length)
  1408             except error.RevlogError:
  1410             except error.RevlogError:
  1409                 if node != wdirid:
  1411                 if node != wdirid:
  1410                     raise error.LookupError(node, self.indexfile, _('no node'))
  1412                     raise error.LookupError(node, self.indexfile, _(b'no node'))
  1411             except AttributeError:
  1413             except AttributeError:
  1412                 # Fall through to pure code
  1414                 # Fall through to pure code
  1413                 pass
  1415                 pass
  1414 
  1416 
  1415         if node == wdirid:
  1417         if node == wdirid:
  1472         if offset != realoffset or reallength != length:
  1474         if offset != realoffset or reallength != length:
  1473             startoffset = offset - realoffset
  1475             startoffset = offset - realoffset
  1474             if len(d) - startoffset < length:
  1476             if len(d) - startoffset < length:
  1475                 raise error.RevlogError(
  1477                 raise error.RevlogError(
  1476                     _(
  1478                     _(
  1477                         'partial read of revlog %s; expected %d bytes from '
  1479                         b'partial read of revlog %s; expected %d bytes from '
  1478                         'offset %d, got %d'
  1480                         b'offset %d, got %d'
  1479                     )
  1481                     )
  1480                     % (
  1482                     % (
  1481                         self.indexfile if self._inline else self.datafile,
  1483                         self.indexfile if self._inline else self.datafile,
  1482                         length,
  1484                         length,
  1483                         realoffset,
  1485                         realoffset,
  1488             return util.buffer(d, startoffset, length)
  1490             return util.buffer(d, startoffset, length)
  1489 
  1491 
  1490         if len(d) < length:
  1492         if len(d) < length:
  1491             raise error.RevlogError(
  1493             raise error.RevlogError(
  1492                 _(
  1494                 _(
  1493                     'partial read of revlog %s; expected %d bytes from offset '
  1495                     b'partial read of revlog %s; expected %d bytes from offset '
  1494                     '%d, got %d'
  1496                     b'%d, got %d'
  1495                 )
  1497                 )
  1496                 % (
  1498                 % (
  1497                     self.indexfile if self._inline else self.datafile,
  1499                     self.indexfile if self._inline else self.datafile,
  1498                     length,
  1500                     length,
  1499                     offset,
  1501                     offset,
  1627 
  1629 
  1628         return l
  1630         return l
  1629 
  1631 
  1630     def _chunkclear(self):
  1632     def _chunkclear(self):
  1631         """Clear the raw chunk cache."""
  1633         """Clear the raw chunk cache."""
  1632         self._chunkcache = (0, '')
  1634         self._chunkcache = (0, b'')
  1633 
  1635 
  1634     def deltaparent(self, rev):
  1636     def deltaparent(self, rev):
  1635         """return deltaparent of the given revision"""
  1637         """return deltaparent of the given revision"""
  1636         base = self.index[rev][3]
  1638         base = self.index[rev][3]
  1637         if base == rev:
  1639         if base == rev:
  1644     def issnapshot(self, rev):
  1646     def issnapshot(self, rev):
  1645         """tells whether rev is a snapshot
  1647         """tells whether rev is a snapshot
  1646         """
  1648         """
  1647         if not self._sparserevlog:
  1649         if not self._sparserevlog:
  1648             return self.deltaparent(rev) == nullrev
  1650             return self.deltaparent(rev) == nullrev
  1649         elif util.safehasattr(self.index, 'issnapshot'):
  1651         elif util.safehasattr(self.index, b'issnapshot'):
  1650             # directly assign the method to cache the testing and access
  1652             # directly assign the method to cache the testing and access
  1651             self.issnapshot = self.index.issnapshot
  1653             self.issnapshot = self.index.issnapshot
  1652             return self.issnapshot(rev)
  1654             return self.issnapshot(rev)
  1653         if rev == nullrev:
  1655         if rev == nullrev:
  1654             return True
  1656             return True
  1665         return self.issnapshot(base)
  1667         return self.issnapshot(base)
  1666 
  1668 
  1667     def snapshotdepth(self, rev):
  1669     def snapshotdepth(self, rev):
  1668         """number of snapshot in the chain before this one"""
  1670         """number of snapshot in the chain before this one"""
  1669         if not self.issnapshot(rev):
  1671         if not self.issnapshot(rev):
  1670             raise error.ProgrammingError('revision %d not a snapshot')
  1672             raise error.ProgrammingError(b'revision %d not a snapshot')
  1671         return len(self._deltachain(rev)[0]) - 1
  1673         return len(self._deltachain(rev)[0]) - 1
  1672 
  1674 
  1673     def revdiff(self, rev1, rev2):
  1675     def revdiff(self, rev1, rev2):
  1674         """return or calculate a delta between two revisions
  1676         """return or calculate a delta between two revisions
  1675 
  1677 
  1681 
  1683 
  1682         return mdiff.textdiff(self.rawdata(rev1), self.rawdata(rev2))
  1684         return mdiff.textdiff(self.rawdata(rev1), self.rawdata(rev2))
  1683 
  1685 
  1684     def _processflags(self, text, flags, operation, raw=False):
  1686     def _processflags(self, text, flags, operation, raw=False):
  1685         """deprecated entry point to access flag processors"""
  1687         """deprecated entry point to access flag processors"""
  1686         msg = '_processflag(...) use the specialized variant'
  1688         msg = b'_processflag(...) use the specialized variant'
  1687         util.nouideprecwarn(msg, '5.2', stacklevel=2)
  1689         util.nouideprecwarn(msg, b'5.2', stacklevel=2)
  1688         if raw:
  1690         if raw:
  1689             return text, flagutil.processflagsraw(self, text, flags)
  1691             return text, flagutil.processflagsraw(self, text, flags)
  1690         elif operation == 'read':
  1692         elif operation == b'read':
  1691             return flagutil.processflagsread(self, text, flags)
  1693             return flagutil.processflagsread(self, text, flags)
  1692         else:  # write operation
  1694         else:  # write operation
  1693             return flagutil.processflagswrite(self, text, flags)
  1695             return flagutil.processflagswrite(self, text, flags)
  1694 
  1696 
  1695     def revision(self, nodeorrev, _df=None, raw=False):
  1697     def revision(self, nodeorrev, _df=None, raw=False):
  1701         treated as raw data when applying flag transforms. 'raw' should be set
  1703         treated as raw data when applying flag transforms. 'raw' should be set
  1702         to True when generating changegroups or in debug commands.
  1704         to True when generating changegroups or in debug commands.
  1703         """
  1705         """
  1704         if raw:
  1706         if raw:
  1705             msg = (
  1707             msg = (
  1706                 'revlog.revision(..., raw=True) is deprecated, '
  1708                 b'revlog.revision(..., raw=True) is deprecated, '
  1707                 'use revlog.rawdata(...)'
  1709                 b'use revlog.rawdata(...)'
  1708             )
  1710             )
  1709             util.nouideprecwarn(msg, '5.2', stacklevel=2)
  1711             util.nouideprecwarn(msg, b'5.2', stacklevel=2)
  1710         return self._revisiondata(nodeorrev, _df, raw=raw)[0]
  1712         return self._revisiondata(nodeorrev, _df, raw=raw)[0]
  1711 
  1713 
  1712     def sidedata(self, nodeorrev, _df=None):
  1714     def sidedata(self, nodeorrev, _df=None):
  1713         """a map of extra data related to the changeset but not part of the hash
  1715         """a map of extra data related to the changeset but not part of the hash
  1714 
  1716 
  1727             node = nodeorrev
  1729             node = nodeorrev
  1728             rev = None
  1730             rev = None
  1729 
  1731 
  1730         # fast path the special `nullid` rev
  1732         # fast path the special `nullid` rev
  1731         if node == nullid:
  1733         if node == nullid:
  1732             return "", {}
  1734             return b"", {}
  1733 
  1735 
  1734         # The text as stored inside the revlog. Might be the revision or might
  1736         # The text as stored inside the revlog. Might be the revision or might
  1735         # need to be processed to retrieve the revision.
  1737         # need to be processed to retrieve the revision.
  1736         rawtext = None
  1738         rawtext = None
  1737 
  1739 
  1757             text = rawtext
  1759             text = rawtext
  1758         else:
  1760         else:
  1759             try:
  1761             try:
  1760                 r = flagutil.processflagsread(self, rawtext, flags)
  1762                 r = flagutil.processflagsread(self, rawtext, flags)
  1761             except error.SidedataHashError as exc:
  1763             except error.SidedataHashError as exc:
  1762                 msg = _("integrity check failed on %s:%s sidedata key %d")
  1764                 msg = _(b"integrity check failed on %s:%s sidedata key %d")
  1763                 msg %= (self.indexfile, pycompat.bytestr(rev), exc.sidedatakey)
  1765                 msg %= (self.indexfile, pycompat.bytestr(rev), exc.sidedatakey)
  1764                 raise error.RevlogError(msg)
  1766                 raise error.RevlogError(msg)
  1765             text, validatehash, sidedata = r
  1767             text, validatehash, sidedata = r
  1766         if validatehash:
  1768         if validatehash:
  1767             self.checkhash(text, node, rev=rev)
  1769             self.checkhash(text, node, rev=rev)
  1849 
  1851 
  1850                 revornode = rev
  1852                 revornode = rev
  1851                 if revornode is None:
  1853                 if revornode is None:
  1852                     revornode = templatefilters.short(hex(node))
  1854                     revornode = templatefilters.short(hex(node))
  1853                 raise error.RevlogError(
  1855                 raise error.RevlogError(
  1854                     _("integrity check failed on %s:%s")
  1856                     _(b"integrity check failed on %s:%s")
  1855                     % (self.indexfile, pycompat.bytestr(revornode))
  1857                     % (self.indexfile, pycompat.bytestr(revornode))
  1856                 )
  1858                 )
  1857         except error.RevlogError:
  1859         except error.RevlogError:
  1858             if self._censorable and storageutil.iscensoredtext(text):
  1860             if self._censorable and storageutil.iscensoredtext(text):
  1859                 raise error.CensoredNodeError(self.indexfile, node, text)
  1861                 raise error.CensoredNodeError(self.indexfile, node, text)
  1874             return
  1876             return
  1875 
  1877 
  1876         trinfo = tr.find(self.indexfile)
  1878         trinfo = tr.find(self.indexfile)
  1877         if trinfo is None:
  1879         if trinfo is None:
  1878             raise error.RevlogError(
  1880             raise error.RevlogError(
  1879                 _("%s not found in the transaction") % self.indexfile
  1881                 _(b"%s not found in the transaction") % self.indexfile
  1880             )
  1882             )
  1881 
  1883 
  1882         trindex = trinfo[2]
  1884         trindex = trinfo[2]
  1883         if trindex is not None:
  1885         if trindex is not None:
  1884             dataoff = self.start(trindex)
  1886             dataoff = self.start(trindex)
  1894             fp.close()
  1896             fp.close()
  1895             # We can't use the cached file handle after close(). So prevent
  1897             # We can't use the cached file handle after close(). So prevent
  1896             # its usage.
  1898             # its usage.
  1897             self._writinghandles = None
  1899             self._writinghandles = None
  1898 
  1900 
  1899         with self._indexfp('r') as ifh, self._datafp('w') as dfh:
  1901         with self._indexfp(b'r') as ifh, self._datafp(b'w') as dfh:
  1900             for r in self:
  1902             for r in self:
  1901                 dfh.write(self._getsegmentforrevs(r, r, df=ifh)[1])
  1903                 dfh.write(self._getsegmentforrevs(r, r, df=ifh)[1])
  1902 
  1904 
  1903         with self._indexfp('w') as fp:
  1905         with self._indexfp(b'w') as fp:
  1904             self.version &= ~FLAG_INLINE_DATA
  1906             self.version &= ~FLAG_INLINE_DATA
  1905             self._inline = False
  1907             self._inline = False
  1906             io = self._io
  1908             io = self._io
  1907             for i in self:
  1909             for i in self:
  1908                 e = io.packentry(self.index[i], self.node, self.version, i)
  1910                 e = io.packentry(self.index[i], self.node, self.version, i)
  1945         deltacomputer - an optional deltacomputer instance shared between
  1947         deltacomputer - an optional deltacomputer instance shared between
  1946             multiple calls
  1948             multiple calls
  1947         """
  1949         """
  1948         if link == nullrev:
  1950         if link == nullrev:
  1949             raise error.RevlogError(
  1951             raise error.RevlogError(
  1950                 _("attempted to add linkrev -1 to %s") % self.indexfile
  1952                 _(b"attempted to add linkrev -1 to %s") % self.indexfile
  1951             )
  1953             )
  1952 
  1954 
  1953         if sidedata is None:
  1955         if sidedata is None:
  1954             sidedata = {}
  1956             sidedata = {}
  1955             flags = flags & ~REVIDX_SIDEDATA
  1957             flags = flags & ~REVIDX_SIDEDATA
  1956         elif not self.hassidedata:
  1958         elif not self.hassidedata:
  1957             raise error.ProgrammingError(
  1959             raise error.ProgrammingError(
  1958                 _("trying to add sidedata to a revlog who don't support them")
  1960                 _(b"trying to add sidedata to a revlog who don't support them")
  1959             )
  1961             )
  1960         else:
  1962         else:
  1961             flags |= REVIDX_SIDEDATA
  1963             flags |= REVIDX_SIDEDATA
  1962 
  1964 
  1963         if flags:
  1965         if flags:
  1972         if rawtext != text:
  1974         if rawtext != text:
  1973             cachedelta = None
  1975             cachedelta = None
  1974 
  1976 
  1975         if len(rawtext) > _maxentrysize:
  1977         if len(rawtext) > _maxentrysize:
  1976             raise error.RevlogError(
  1978             raise error.RevlogError(
  1977                 _("%s: size of %d bytes exceeds maximum revlog storage of 2GiB")
  1979                 _(
       
  1980                     b"%s: size of %d bytes exceeds maximum revlog storage of 2GiB"
       
  1981                 )
  1978                 % (self.indexfile, len(rawtext))
  1982                 % (self.indexfile, len(rawtext))
  1979             )
  1983             )
  1980 
  1984 
  1981         node = node or self.hash(rawtext, p1, p2)
  1985         node = node or self.hash(rawtext, p1, p2)
  1982         if node in self.nodemap:
  1986         if node in self.nodemap:
  2013         useful when reusing a revision not stored in this revlog (ex: received
  2017         useful when reusing a revision not stored in this revlog (ex: received
  2014         over wire, or read from an external bundle).
  2018         over wire, or read from an external bundle).
  2015         """
  2019         """
  2016         dfh = None
  2020         dfh = None
  2017         if not self._inline:
  2021         if not self._inline:
  2018             dfh = self._datafp("a+")
  2022             dfh = self._datafp(b"a+")
  2019         ifh = self._indexfp("a+")
  2023         ifh = self._indexfp(b"a+")
  2020         try:
  2024         try:
  2021             return self._addrevision(
  2025             return self._addrevision(
  2022                 node,
  2026                 node,
  2023                 rawtext,
  2027                 rawtext,
  2024                 transaction,
  2028                 transaction,
  2037             ifh.close()
  2041             ifh.close()
  2038 
  2042 
  2039     def compress(self, data):
  2043     def compress(self, data):
  2040         """Generate a possibly-compressed representation of data."""
  2044         """Generate a possibly-compressed representation of data."""
  2041         if not data:
  2045         if not data:
  2042             return '', data
  2046             return b'', data
  2043 
  2047 
  2044         compressed = self._compressor.compress(data)
  2048         compressed = self._compressor.compress(data)
  2045 
  2049 
  2046         if compressed:
  2050         if compressed:
  2047             # The revlog compressor added the header in the returned data.
  2051             # The revlog compressor added the header in the returned data.
  2048             return '', compressed
  2052             return b'', compressed
  2049 
  2053 
  2050         if data[0:1] == '\0':
  2054         if data[0:1] == b'\0':
  2051             return '', data
  2055             return b'', data
  2052         return 'u', data
  2056         return b'u', data
  2053 
  2057 
  2054     def decompress(self, data):
  2058     def decompress(self, data):
  2055         """Decompress a revlog chunk.
  2059         """Decompress a revlog chunk.
  2056 
  2060 
  2057         The chunk is expected to begin with a header identifying the
  2061         The chunk is expected to begin with a header identifying the
  2081         #
  2085         #
  2082         # According to `hg perfrevlogchunks`, this is ~0.5% faster for zlib
  2086         # According to `hg perfrevlogchunks`, this is ~0.5% faster for zlib
  2083         # compressed chunks. And this matters for changelog and manifest reads.
  2087         # compressed chunks. And this matters for changelog and manifest reads.
  2084         t = data[0:1]
  2088         t = data[0:1]
  2085 
  2089 
  2086         if t == 'x':
  2090         if t == b'x':
  2087             try:
  2091             try:
  2088                 return _zlibdecompress(data)
  2092                 return _zlibdecompress(data)
  2089             except zlib.error as e:
  2093             except zlib.error as e:
  2090                 raise error.RevlogError(
  2094                 raise error.RevlogError(
  2091                     _('revlog decompress error: %s')
  2095                     _(b'revlog decompress error: %s')
  2092                     % stringutil.forcebytestr(e)
  2096                     % stringutil.forcebytestr(e)
  2093                 )
  2097                 )
  2094         # '\0' is more common than 'u' so it goes first.
  2098         # '\0' is more common than 'u' so it goes first.
  2095         elif t == '\0':
  2099         elif t == b'\0':
  2096             return data
  2100             return data
  2097         elif t == 'u':
  2101         elif t == b'u':
  2098             return util.buffer(data, 1)
  2102             return util.buffer(data, 1)
  2099 
  2103 
  2100         try:
  2104         try:
  2101             compressor = self._decompressors[t]
  2105             compressor = self._decompressors[t]
  2102         except KeyError:
  2106         except KeyError:
  2103             try:
  2107             try:
  2104                 engine = util.compengines.forrevlogheader(t)
  2108                 engine = util.compengines.forrevlogheader(t)
  2105                 compressor = engine.revlogcompressor(self._compengineopts)
  2109                 compressor = engine.revlogcompressor(self._compengineopts)
  2106                 self._decompressors[t] = compressor
  2110                 self._decompressors[t] = compressor
  2107             except KeyError:
  2111             except KeyError:
  2108                 raise error.RevlogError(_('unknown compression type %r') % t)
  2112                 raise error.RevlogError(_(b'unknown compression type %r') % t)
  2109 
  2113 
  2110         return compressor.decompress(data)
  2114         return compressor.decompress(data)
  2111 
  2115 
  2112     def _addrevision(
  2116     def _addrevision(
  2113         self,
  2117         self,
  2137         - rawtext is optional (can be None); if not set, cachedelta must be set.
  2141         - rawtext is optional (can be None); if not set, cachedelta must be set.
  2138           if both are set, they must correspond to each other.
  2142           if both are set, they must correspond to each other.
  2139         """
  2143         """
  2140         if node == nullid:
  2144         if node == nullid:
  2141             raise error.RevlogError(
  2145             raise error.RevlogError(
  2142                 _("%s: attempt to add null revision") % self.indexfile
  2146                 _(b"%s: attempt to add null revision") % self.indexfile
  2143             )
  2147             )
  2144         if node == wdirid or node in wdirfilenodeids:
  2148         if node == wdirid or node in wdirfilenodeids:
  2145             raise error.RevlogError(
  2149             raise error.RevlogError(
  2146                 _("%s: attempt to add wdir revision") % self.indexfile
  2150                 _(b"%s: attempt to add wdir revision") % self.indexfile
  2147             )
  2151             )
  2148 
  2152 
  2149         if self._inline:
  2153         if self._inline:
  2150             fh = ifh
  2154             fh = ifh
  2151         else:
  2155         else:
  2254         If ``addrevisioncb`` is defined, it will be called with arguments of
  2258         If ``addrevisioncb`` is defined, it will be called with arguments of
  2255         this revlog and the node that was added.
  2259         this revlog and the node that was added.
  2256         """
  2260         """
  2257 
  2261 
  2258         if self._writinghandles:
  2262         if self._writinghandles:
  2259             raise error.ProgrammingError('cannot nest addgroup() calls')
  2263             raise error.ProgrammingError(b'cannot nest addgroup() calls')
  2260 
  2264 
  2261         nodes = []
  2265         nodes = []
  2262 
  2266 
  2263         r = len(self)
  2267         r = len(self)
  2264         end = 0
  2268         end = 0
  2265         if r:
  2269         if r:
  2266             end = self.end(r - 1)
  2270             end = self.end(r - 1)
  2267         ifh = self._indexfp("a+")
  2271         ifh = self._indexfp(b"a+")
  2268         isize = r * self._io.size
  2272         isize = r * self._io.size
  2269         if self._inline:
  2273         if self._inline:
  2270             transaction.add(self.indexfile, end + isize, r)
  2274             transaction.add(self.indexfile, end + isize, r)
  2271             dfh = None
  2275             dfh = None
  2272         else:
  2276         else:
  2273             transaction.add(self.indexfile, isize, r)
  2277             transaction.add(self.indexfile, isize, r)
  2274             transaction.add(self.datafile, end)
  2278             transaction.add(self.datafile, end)
  2275             dfh = self._datafp("a+")
  2279             dfh = self._datafp(b"a+")
  2276 
  2280 
  2277         def flush():
  2281         def flush():
  2278             if dfh:
  2282             if dfh:
  2279                 dfh.flush()
  2283                 dfh.flush()
  2280             ifh.flush()
  2284             ifh.flush()
  2297                     continue
  2301                     continue
  2298 
  2302 
  2299                 for p in (p1, p2):
  2303                 for p in (p1, p2):
  2300                     if p not in self.nodemap:
  2304                     if p not in self.nodemap:
  2301                         raise error.LookupError(
  2305                         raise error.LookupError(
  2302                             p, self.indexfile, _('unknown parent')
  2306                             p, self.indexfile, _(b'unknown parent')
  2303                         )
  2307                         )
  2304 
  2308 
  2305                 if deltabase not in self.nodemap:
  2309                 if deltabase not in self.nodemap:
  2306                     raise error.LookupError(
  2310                     raise error.LookupError(
  2307                         deltabase, self.indexfile, _('unknown delta base')
  2311                         deltabase, self.indexfile, _(b'unknown delta base')
  2308                     )
  2312                     )
  2309 
  2313 
  2310                 baserev = self.rev(deltabase)
  2314                 baserev = self.rev(deltabase)
  2311 
  2315 
  2312                 if baserev != nullrev and self.iscensored(baserev):
  2316                 if baserev != nullrev and self.iscensored(baserev):
  2313                     # if base is censored, delta must be full replacement in a
  2317                     # if base is censored, delta must be full replacement in a
  2314                     # single patch operation
  2318                     # single patch operation
  2315                     hlen = struct.calcsize(">lll")
  2319                     hlen = struct.calcsize(b">lll")
  2316                     oldlen = self.rawsize(baserev)
  2320                     oldlen = self.rawsize(baserev)
  2317                     newlen = len(delta) - hlen
  2321                     newlen = len(delta) - hlen
  2318                     if delta[:hlen] != mdiff.replacediffheader(oldlen, newlen):
  2322                     if delta[:hlen] != mdiff.replacediffheader(oldlen, newlen):
  2319                         raise error.CensoredBaseError(
  2323                         raise error.CensoredBaseError(
  2320                             self.indexfile, self.node(baserev)
  2324                             self.indexfile, self.node(baserev)
  2350 
  2354 
  2351                 if not dfh and not self._inline:
  2355                 if not dfh and not self._inline:
  2352                     # addrevision switched from inline to conventional
  2356                     # addrevision switched from inline to conventional
  2353                     # reopen the index
  2357                     # reopen the index
  2354                     ifh.close()
  2358                     ifh.close()
  2355                     dfh = self._datafp("a+")
  2359                     dfh = self._datafp(b"a+")
  2356                     ifh = self._indexfp("a+")
  2360                     ifh = self._indexfp(b"a+")
  2357                     self._writinghandles = (ifh, dfh)
  2361                     self._writinghandles = (ifh, dfh)
  2358         finally:
  2362         finally:
  2359             self._writinghandles = None
  2363             self._writinghandles = None
  2360 
  2364 
  2361             if dfh:
  2365             if dfh:
  2489         nodesorder=None,
  2493         nodesorder=None,
  2490         revisiondata=False,
  2494         revisiondata=False,
  2491         assumehaveparentrevisions=False,
  2495         assumehaveparentrevisions=False,
  2492         deltamode=repository.CG_DELTAMODE_STD,
  2496         deltamode=repository.CG_DELTAMODE_STD,
  2493     ):
  2497     ):
  2494         if nodesorder not in ('nodes', 'storage', 'linear', None):
  2498         if nodesorder not in (b'nodes', b'storage', b'linear', None):
  2495             raise error.ProgrammingError(
  2499             raise error.ProgrammingError(
  2496                 'unhandled value for nodesorder: %s' % nodesorder
  2500                 b'unhandled value for nodesorder: %s' % nodesorder
  2497             )
  2501             )
  2498 
  2502 
  2499         if nodesorder is None and not self._generaldelta:
  2503         if nodesorder is None and not self._generaldelta:
  2500             nodesorder = 'storage'
  2504             nodesorder = b'storage'
  2501 
  2505 
  2502         if (
  2506         if (
  2503             not self._storedeltachains
  2507             not self._storedeltachains
  2504             and deltamode != repository.CG_DELTAMODE_PREV
  2508             and deltamode != repository.CG_DELTAMODE_PREV
  2505         ):
  2509         ):
  2518             deltamode=deltamode,
  2522             deltamode=deltamode,
  2519             revisiondata=revisiondata,
  2523             revisiondata=revisiondata,
  2520             assumehaveparentrevisions=assumehaveparentrevisions,
  2524             assumehaveparentrevisions=assumehaveparentrevisions,
  2521         )
  2525         )
  2522 
  2526 
  2523     DELTAREUSEALWAYS = 'always'
  2527     DELTAREUSEALWAYS = b'always'
  2524     DELTAREUSESAMEREVS = 'samerevs'
  2528     DELTAREUSESAMEREVS = b'samerevs'
  2525     DELTAREUSENEVER = 'never'
  2529     DELTAREUSENEVER = b'never'
  2526 
  2530 
  2527     DELTAREUSEFULLADD = 'fulladd'
  2531     DELTAREUSEFULLADD = b'fulladd'
  2528 
  2532 
  2529     DELTAREUSEALL = {'always', 'samerevs', 'never', 'fulladd'}
  2533     DELTAREUSEALL = {b'always', b'samerevs', b'never', b'fulladd'}
  2530 
  2534 
  2531     def clone(
  2535     def clone(
  2532         self,
  2536         self,
  2533         tr,
  2537         tr,
  2534         destrevlog,
  2538         destrevlog,
  2576         In addition to the delta policy, the ``forcedeltabothparents``
  2580         In addition to the delta policy, the ``forcedeltabothparents``
  2577         argument controls whether to force compute deltas against both parents
  2581         argument controls whether to force compute deltas against both parents
  2578         for merges. By default, the current default is used.
  2582         for merges. By default, the current default is used.
  2579         """
  2583         """
  2580         if deltareuse not in self.DELTAREUSEALL:
  2584         if deltareuse not in self.DELTAREUSEALL:
  2581             raise ValueError(_('value for deltareuse invalid: %s') % deltareuse)
  2585             raise ValueError(
       
  2586                 _(b'value for deltareuse invalid: %s') % deltareuse
       
  2587             )
  2582 
  2588 
  2583         if len(destrevlog):
  2589         if len(destrevlog):
  2584             raise ValueError(_('destination revlog is not empty'))
  2590             raise ValueError(_(b'destination revlog is not empty'))
  2585 
  2591 
  2586         if getattr(self, 'filteredrevs', None):
  2592         if getattr(self, 'filteredrevs', None):
  2587             raise ValueError(_('source revlog has filtered revisions'))
  2593             raise ValueError(_(b'source revlog has filtered revisions'))
  2588         if getattr(destrevlog, 'filteredrevs', None):
  2594         if getattr(destrevlog, 'filteredrevs', None):
  2589             raise ValueError(_('destination revlog has filtered revisions'))
  2595             raise ValueError(_(b'destination revlog has filtered revisions'))
  2590 
  2596 
  2591         # lazydelta and lazydeltabase controls whether to reuse a cached delta,
  2597         # lazydelta and lazydeltabase controls whether to reuse a cached delta,
  2592         # if possible.
  2598         # if possible.
  2593         oldlazydelta = destrevlog._lazydelta
  2599         oldlazydelta = destrevlog._lazydelta
  2594         oldlazydeltabase = destrevlog._lazydeltabase
  2600         oldlazydeltabase = destrevlog._lazydeltabase
  2658 
  2664 
  2659                 if not cachedelta:
  2665                 if not cachedelta:
  2660                     rawtext = self.rawdata(rev)
  2666                     rawtext = self.rawdata(rev)
  2661 
  2667 
  2662                 ifh = destrevlog.opener(
  2668                 ifh = destrevlog.opener(
  2663                     destrevlog.indexfile, 'a+', checkambig=False
  2669                     destrevlog.indexfile, b'a+', checkambig=False
  2664                 )
  2670                 )
  2665                 dfh = None
  2671                 dfh = None
  2666                 if not destrevlog._inline:
  2672                 if not destrevlog._inline:
  2667                     dfh = destrevlog.opener(destrevlog.datafile, 'a+')
  2673                     dfh = destrevlog.opener(destrevlog.datafile, b'a+')
  2668                 try:
  2674                 try:
  2669                     destrevlog._addrevision(
  2675                     destrevlog._addrevision(
  2670                         node,
  2676                         node,
  2671                         rawtext,
  2677                         rawtext,
  2672                         tr,
  2678                         tr,
  2688                 addrevisioncb(self, rev, node)
  2694                 addrevisioncb(self, rev, node)
  2689 
  2695 
  2690     def censorrevision(self, tr, censornode, tombstone=b''):
  2696     def censorrevision(self, tr, censornode, tombstone=b''):
  2691         if (self.version & 0xFFFF) == REVLOGV0:
  2697         if (self.version & 0xFFFF) == REVLOGV0:
  2692             raise error.RevlogError(
  2698             raise error.RevlogError(
  2693                 _('cannot censor with version %d revlogs') % self.version
  2699                 _(b'cannot censor with version %d revlogs') % self.version
  2694             )
  2700             )
  2695 
  2701 
  2696         censorrev = self.rev(censornode)
  2702         censorrev = self.rev(censornode)
  2697         tombstone = storageutil.packmeta({b'censored': tombstone}, b'')
  2703         tombstone = storageutil.packmeta({b'censored': tombstone}, b'')
  2698 
  2704 
  2699         if len(tombstone) > self.rawsize(censorrev):
  2705         if len(tombstone) > self.rawsize(censorrev):
  2700             raise error.Abort(
  2706             raise error.Abort(
  2701                 _('censor tombstone must be no longer than ' 'censored data')
  2707                 _(b'censor tombstone must be no longer than ' b'censored data')
  2702             )
  2708             )
  2703 
  2709 
  2704         # Rewriting the revlog in place is hard. Our strategy for censoring is
  2710         # Rewriting the revlog in place is hard. Our strategy for censoring is
  2705         # to create a new revlog, copy all revisions to it, then replace the
  2711         # to create a new revlog, copy all revisions to it, then replace the
  2706         # revlogs on transaction close.
  2712         # revlogs on transaction close.
  2730                 )
  2736                 )
  2731 
  2737 
  2732                 if newrl.deltaparent(rev) != nullrev:
  2738                 if newrl.deltaparent(rev) != nullrev:
  2733                     raise error.Abort(
  2739                     raise error.Abort(
  2734                         _(
  2740                         _(
  2735                             'censored revision stored as delta; '
  2741                             b'censored revision stored as delta; '
  2736                             'cannot censor'
  2742                             b'cannot censor'
  2737                         ),
  2743                         ),
  2738                         hint=_(
  2744                         hint=_(
  2739                             'censoring of revlogs is not '
  2745                             b'censoring of revlogs is not '
  2740                             'fully implemented; please report '
  2746                             b'fully implemented; please report '
  2741                             'this bug'
  2747                             b'this bug'
  2742                         ),
  2748                         ),
  2743                     )
  2749                     )
  2744                 continue
  2750                 continue
  2745 
  2751 
  2746             if self.iscensored(rev):
  2752             if self.iscensored(rev):
  2747                 if self.deltaparent(rev) != nullrev:
  2753                 if self.deltaparent(rev) != nullrev:
  2748                     raise error.Abort(
  2754                     raise error.Abort(
  2749                         _(
  2755                         _(
  2750                             'cannot censor due to censored '
  2756                             b'cannot censor due to censored '
  2751                             'revision having delta stored'
  2757                             b'revision having delta stored'
  2752                         )
  2758                         )
  2753                     )
  2759                     )
  2754                 rawtext = self._chunk(rev)
  2760                 rawtext = self._chunk(rev)
  2755             else:
  2761             else:
  2756                 rawtext = self.rawdata(rev)
  2762                 rawtext = self.rawdata(rev)
  2757 
  2763 
  2758             newrl.addrawrevision(
  2764             newrl.addrawrevision(
  2759                 rawtext, tr, self.linkrev(rev), p1, p2, node, self.flags(rev)
  2765                 rawtext, tr, self.linkrev(rev), p1, p2, node, self.flags(rev)
  2760             )
  2766             )
  2761 
  2767 
  2762         tr.addbackup(self.indexfile, location='store')
  2768         tr.addbackup(self.indexfile, location=b'store')
  2763         if not self._inline:
  2769         if not self._inline:
  2764             tr.addbackup(self.datafile, location='store')
  2770             tr.addbackup(self.datafile, location=b'store')
  2765 
  2771 
  2766         self.opener.rename(newrl.indexfile, self.indexfile)
  2772         self.opener.rename(newrl.indexfile, self.indexfile)
  2767         if not self._inline:
  2773         if not self._inline:
  2768             self.opener.rename(newrl.datafile, self.datafile)
  2774             self.opener.rename(newrl.datafile, self.datafile)
  2769 
  2775 
  2776         Yields ``revlogproblem`` instances describing problems that are
  2782         Yields ``revlogproblem`` instances describing problems that are
  2777         found.
  2783         found.
  2778         """
  2784         """
  2779         dd, di = self.checksize()
  2785         dd, di = self.checksize()
  2780         if dd:
  2786         if dd:
  2781             yield revlogproblem(error=_('data length off by %d bytes') % dd)
  2787             yield revlogproblem(error=_(b'data length off by %d bytes') % dd)
  2782         if di:
  2788         if di:
  2783             yield revlogproblem(error=_('index contains %d extra bytes') % di)
  2789             yield revlogproblem(error=_(b'index contains %d extra bytes') % di)
  2784 
  2790 
  2785         version = self.version & 0xFFFF
  2791         version = self.version & 0xFFFF
  2786 
  2792 
  2787         # The verifier tells us what version revlog we should be.
  2793         # The verifier tells us what version revlog we should be.
  2788         if version != state['expectedversion']:
  2794         if version != state[b'expectedversion']:
  2789             yield revlogproblem(
  2795             yield revlogproblem(
  2790                 warning=_("warning: '%s' uses revlog format %d; expected %d")
  2796                 warning=_(b"warning: '%s' uses revlog format %d; expected %d")
  2791                 % (self.indexfile, version, state['expectedversion'])
  2797                 % (self.indexfile, version, state[b'expectedversion'])
  2792             )
  2798             )
  2793 
  2799 
  2794         state['skipread'] = set()
  2800         state[b'skipread'] = set()
  2795 
  2801 
  2796         for rev in self:
  2802         for rev in self:
  2797             node = self.node(rev)
  2803             node = self.node(rev)
  2798 
  2804 
  2799             # Verify contents. 4 cases to care about:
  2805             # Verify contents. 4 cases to care about:
  2843             #  1. length check: L1 == L2, in all cases.
  2849             #  1. length check: L1 == L2, in all cases.
  2844             #  2. hash check: depending on flag processor, we may need to
  2850             #  2. hash check: depending on flag processor, we may need to
  2845             #     use either "text" (external), or "rawtext" (in revlog).
  2851             #     use either "text" (external), or "rawtext" (in revlog).
  2846 
  2852 
  2847             try:
  2853             try:
  2848                 skipflags = state.get('skipflags', 0)
  2854                 skipflags = state.get(b'skipflags', 0)
  2849                 if skipflags:
  2855                 if skipflags:
  2850                     skipflags &= self.flags(rev)
  2856                     skipflags &= self.flags(rev)
  2851 
  2857 
  2852                 if skipflags:
  2858                 if skipflags:
  2853                     state['skipread'].add(node)
  2859                     state[b'skipread'].add(node)
  2854                 else:
  2860                 else:
  2855                     # Side-effect: read content and verify hash.
  2861                     # Side-effect: read content and verify hash.
  2856                     self.revision(node)
  2862                     self.revision(node)
  2857 
  2863 
  2858                 l1 = self.rawsize(rev)
  2864                 l1 = self.rawsize(rev)
  2859                 l2 = len(self.rawdata(node))
  2865                 l2 = len(self.rawdata(node))
  2860 
  2866 
  2861                 if l1 != l2:
  2867                 if l1 != l2:
  2862                     yield revlogproblem(
  2868                     yield revlogproblem(
  2863                         error=_('unpacked size is %d, %d expected') % (l2, l1),
  2869                         error=_(b'unpacked size is %d, %d expected') % (l2, l1),
  2864                         node=node,
  2870                         node=node,
  2865                     )
  2871                     )
  2866 
  2872 
  2867             except error.CensoredNodeError:
  2873             except error.CensoredNodeError:
  2868                 if state['erroroncensored']:
  2874                 if state[b'erroroncensored']:
  2869                     yield revlogproblem(
  2875                     yield revlogproblem(
  2870                         error=_('censored file data'), node=node
  2876                         error=_(b'censored file data'), node=node
  2871                     )
  2877                     )
  2872                     state['skipread'].add(node)
  2878                     state[b'skipread'].add(node)
  2873             except Exception as e:
  2879             except Exception as e:
  2874                 yield revlogproblem(
  2880                 yield revlogproblem(
  2875                     error=_('unpacking %s: %s')
  2881                     error=_(b'unpacking %s: %s')
  2876                     % (short(node), stringutil.forcebytestr(e)),
  2882                     % (short(node), stringutil.forcebytestr(e)),
  2877                     node=node,
  2883                     node=node,
  2878                 )
  2884                 )
  2879                 state['skipread'].add(node)
  2885                 state[b'skipread'].add(node)
  2880 
  2886 
  2881     def storageinfo(
  2887     def storageinfo(
  2882         self,
  2888         self,
  2883         exclusivefiles=False,
  2889         exclusivefiles=False,
  2884         sharedfiles=False,
  2890         sharedfiles=False,
  2887         storedsize=False,
  2893         storedsize=False,
  2888     ):
  2894     ):
  2889         d = {}
  2895         d = {}
  2890 
  2896 
  2891         if exclusivefiles:
  2897         if exclusivefiles:
  2892             d['exclusivefiles'] = [(self.opener, self.indexfile)]
  2898             d[b'exclusivefiles'] = [(self.opener, self.indexfile)]
  2893             if not self._inline:
  2899             if not self._inline:
  2894                 d['exclusivefiles'].append((self.opener, self.datafile))
  2900                 d[b'exclusivefiles'].append((self.opener, self.datafile))
  2895 
  2901 
  2896         if sharedfiles:
  2902         if sharedfiles:
  2897             d['sharedfiles'] = []
  2903             d[b'sharedfiles'] = []
  2898 
  2904 
  2899         if revisionscount:
  2905         if revisionscount:
  2900             d['revisionscount'] = len(self)
  2906             d[b'revisionscount'] = len(self)
  2901 
  2907 
  2902         if trackedsize:
  2908         if trackedsize:
  2903             d['trackedsize'] = sum(map(self.rawsize, iter(self)))
  2909             d[b'trackedsize'] = sum(map(self.rawsize, iter(self)))
  2904 
  2910 
  2905         if storedsize:
  2911         if storedsize:
  2906             d['storedsize'] = sum(
  2912             d[b'storedsize'] = sum(
  2907                 self.opener.stat(path).st_size for path in self.files()
  2913                 self.opener.stat(path).st_size for path in self.files()
  2908             )
  2914             )
  2909 
  2915 
  2910         return d
  2916         return d