comparison mercurial/revlog.py @ 27468:93ac15f03331

revlog: refactor delta chain computation into own function This code is already written in multiple locations. While this code needs to be fast and extracting it to its own function adds overhead, code paths reading delta chains typically read, decompress, and do binary patching on revlog data from the delta chain. This other work (especially zlib decompression) almost certainly accounts for a lot more time than the overhead of introducing a Python function call. So I'm not worried about the performance impact of this change.
author Gregory Szorc <gregory.szorc@gmail.com>
date Sun, 20 Dec 2015 18:56:05 -0800
parents 072a675c51f2
children fe79f86099ae
comparison
equal deleted inserted replaced
27467:fbe292b591ec 27468:93ac15f03331
427 # work. For cache hits the length is already included. 427 # work. For cache hits the length is already included.
428 compresseddeltalen += e[1] 428 compresseddeltalen += e[1]
429 r = (clen, compresseddeltalen) 429 r = (clen, compresseddeltalen)
430 chaininfocache[rev] = r 430 chaininfocache[rev] = r
431 return r 431 return r
432
433 def _deltachain(self, rev, stoprev=None):
434 """Obtain the delta chain for a revision.
435
436 ``stoprev`` specifies a revision to stop at. If not specified, we
437 stop at the base of the chain.
438
439 Returns a 2-tuple of (chain, stopped) where ``chain`` is a list of
440 revs in ascending order and ``stopped`` is a bool indicating whether
441 ``stoprev`` was hit.
442 """
443 chain = []
444
445 # Alias to prevent attribute lookup in tight loop.
446 index = self.index
447 generaldelta = self._generaldelta
448
449 iterrev = rev
450 e = index[iterrev]
451 while iterrev != e[3] and iterrev != stoprev:
452 chain.append(iterrev)
453 if generaldelta:
454 iterrev = e[3]
455 else:
456 iterrev -= 1
457 e = index[iterrev]
458
459 if iterrev == stoprev:
460 stopped = True
461 else:
462 chain.append(iterrev)
463 stopped = False
464
465 chain.reverse()
466 return chain, stopped
432 467
433 def flags(self, rev): 468 def flags(self, rev):
434 return self.index[rev][0] & 0xFFFF 469 return self.index[rev][0] & 0xFFFF
435 def rawsize(self, rev): 470 def rawsize(self, rev):
436 """return the length of the uncompressed text for a given revision""" 471 """return the length of the uncompressed text for a given revision"""
1158 # check rev flags 1193 # check rev flags
1159 if self.flags(rev) & ~REVIDX_KNOWN_FLAGS: 1194 if self.flags(rev) & ~REVIDX_KNOWN_FLAGS:
1160 raise RevlogError(_('incompatible revision flag %x') % 1195 raise RevlogError(_('incompatible revision flag %x') %
1161 (self.flags(rev) & ~REVIDX_KNOWN_FLAGS)) 1196 (self.flags(rev) & ~REVIDX_KNOWN_FLAGS))
1162 1197
1163 # build delta chain 1198 chain, stopped = self._deltachain(rev, stoprev=cachedrev)
1164 chain = [] 1199 if stopped:
1165 index = self.index # for performance
1166 generaldelta = self._generaldelta
1167 iterrev = rev
1168 e = index[iterrev]
1169 while iterrev != e[3] and iterrev != cachedrev:
1170 chain.append(iterrev)
1171 if generaldelta:
1172 iterrev = e[3]
1173 else:
1174 iterrev -= 1
1175 e = index[iterrev]
1176
1177 if iterrev == cachedrev:
1178 # cache hit
1179 text = self._cache[2] 1200 text = self._cache[2]
1180 else:
1181 chain.append(iterrev)
1182 chain.reverse()
1183 1201
1184 # drop cache to save memory 1202 # drop cache to save memory
1185 self._cache = None 1203 self._cache = None
1186 1204
1187 bins = self._chunks(chain, df=_df) 1205 bins = self._chunks(chain, df=_df)