701 if sparse and revlog.rawsize(rev) < (textlen // LIMIT_BASE2TEXT): |
706 if sparse and revlog.rawsize(rev) < (textlen // LIMIT_BASE2TEXT): |
702 continue |
707 continue |
703 # no delta for rawtext-changing revs (see "candelta" for why) |
708 # no delta for rawtext-changing revs (see "candelta" for why) |
704 if revlog.flags(rev) & REVIDX_RAWTEXT_CHANGING_FLAGS: |
709 if revlog.flags(rev) & REVIDX_RAWTEXT_CHANGING_FLAGS: |
705 continue |
710 continue |
|
711 |
706 # If we reach here, we are about to build and test a delta. |
712 # If we reach here, we are about to build and test a delta. |
707 # The delta building process will compute the chaininfo in all |
713 # The delta building process will compute the chaininfo in all |
708 # case, since that computation is cached, it is fine to access it |
714 # case, since that computation is cached, it is fine to access it |
709 # here too. |
715 # here too. |
710 chainlen, chainsize = revlog._chaininfo(rev) |
716 chainlen, chainsize = revlog._chaininfo(rev) |
766 # (or from the source revlog) |
772 # (or from the source revlog) |
767 # |
773 # |
768 # This logic only applies to general delta repositories and can be disabled |
774 # This logic only applies to general delta repositories and can be disabled |
769 # through configuration. Disabling reuse source delta is useful when |
775 # through configuration. Disabling reuse source delta is useful when |
770 # we want to make sure we recomputed "optimal" deltas. |
776 # we want to make sure we recomputed "optimal" deltas. |
|
777 debug_info = None |
771 if cachedelta and revlog._generaldelta and revlog._lazydeltabase: |
778 if cachedelta and revlog._generaldelta and revlog._lazydeltabase: |
772 # Assume what we received from the server is a good choice |
779 # Assume what we received from the server is a good choice |
773 # build delta will reuse the cache |
780 # build delta will reuse the cache |
|
781 if debug_info is not None: |
|
782 debug_info['cached-delta.tested'] += 1 |
774 good = yield (cachedelta[0],) |
783 good = yield (cachedelta[0],) |
775 if good is not None: |
784 if good is not None: |
|
785 if debug_info is not None: |
|
786 debug_info['cached-delta.accepted'] += 1 |
776 yield None |
787 yield None |
777 return |
788 return |
|
789 # XXX cache me higher |
778 snapshots = collections.defaultdict(list) |
790 snapshots = collections.defaultdict(list) |
779 for candidates in _rawgroups(revlog, p1, p2, cachedelta, snapshots): |
791 groups = _rawgroups( |
|
792 revlog, |
|
793 p1, |
|
794 p2, |
|
795 cachedelta, |
|
796 snapshots, |
|
797 ) |
|
798 for candidates in groups: |
780 good = yield candidates |
799 good = yield candidates |
781 if good is not None: |
800 if good is not None: |
782 break |
801 break |
783 |
802 |
784 # If sparse revlog is enabled, we can try to refine the available deltas |
803 # If sparse revlog is enabled, we can try to refine the available deltas |
803 while good != previous: |
822 while good != previous: |
804 previous = good |
823 previous = good |
805 children = tuple(sorted(c for c in snapshots[good])) |
824 children = tuple(sorted(c for c in snapshots[good])) |
806 good = yield children |
825 good = yield children |
807 |
826 |
808 # we have found nothing |
827 if debug_info is not None: |
|
828 if good is None: |
|
829 debug_info['no-solution'] += 1 |
|
830 |
809 yield None |
831 yield None |
810 |
832 |
811 |
833 |
812 def _rawgroups(revlog, p1, p2, cachedelta, snapshots=None): |
834 def _rawgroups(revlog, p1, p2, cachedelta, snapshots=None): |
813 """Provides group of revision to be tested as delta base |
835 """Provides group of revision to be tested as delta base |
929 # fulltext. |
951 # fulltext. |
930 yield (prev,) |
952 yield (prev,) |
931 |
953 |
932 |
954 |
933 class deltacomputer: |
955 class deltacomputer: |
934 def __init__(self, revlog, write_debug=None, debug_search=False): |
956 def __init__( |
|
957 self, |
|
958 revlog, |
|
959 write_debug=None, |
|
960 debug_search=False, |
|
961 debug_info=None, |
|
962 ): |
935 self.revlog = revlog |
963 self.revlog = revlog |
936 self._write_debug = write_debug |
964 self._write_debug = write_debug |
937 self._debug_search = debug_search |
965 self._debug_search = debug_search |
|
966 self._debug_info = debug_info |
938 |
967 |
939 def buildtext(self, revinfo, fh): |
968 def buildtext(self, revinfo, fh): |
940 """Builds a fulltext version of a revision |
969 """Builds a fulltext version of a revision |
941 |
970 |
942 revinfo: revisioninfo instance that contains all needed info |
971 revinfo: revisioninfo instance that contains all needed info |
1101 # not calling candelta since only one revision needs test, also to |
1130 # not calling candelta since only one revision needs test, also to |
1102 # avoid overhead fetching flags again. |
1131 # avoid overhead fetching flags again. |
1103 if revinfo.flags & REVIDX_RAWTEXT_CHANGING_FLAGS: |
1132 if revinfo.flags & REVIDX_RAWTEXT_CHANGING_FLAGS: |
1104 return self._fullsnapshotinfo(fh, revinfo, target_rev) |
1133 return self._fullsnapshotinfo(fh, revinfo, target_rev) |
1105 |
1134 |
1106 if self._write_debug is not None: |
1135 gather_debug = ( |
|
1136 self._write_debug is not None or self._debug_info is not None |
|
1137 ) |
|
1138 debug_search = self._write_debug is not None and self._debug_search |
|
1139 |
|
1140 if gather_debug: |
1107 start = util.timer() |
1141 start = util.timer() |
1108 |
|
1109 debug_search = self._write_debug is not None and self._debug_search |
|
1110 |
1142 |
1111 # count the number of different delta we tried (for debug purpose) |
1143 # count the number of different delta we tried (for debug purpose) |
1112 dbg_try_count = 0 |
1144 dbg_try_count = 0 |
1113 # count the number of "search round" we did. (for debug purpose) |
1145 # count the number of "search round" we did. (for debug purpose) |
1114 dbg_try_rounds = 0 |
1146 dbg_try_rounds = 0 |
1248 elif deltainfo.snapshotdepth: # pytype: disable=attribute-error |
1280 elif deltainfo.snapshotdepth: # pytype: disable=attribute-error |
1249 dbg_type = b"snapshot" |
1281 dbg_type = b"snapshot" |
1250 else: |
1282 else: |
1251 dbg_type = b"delta" |
1283 dbg_type = b"delta" |
1252 |
1284 |
1253 if self._write_debug is not None: |
1285 if gather_debug: |
1254 end = util.timer() |
1286 end = util.timer() |
1255 assert deltainfo is not None # please pytype |
|
1256 used_cached = ( |
1287 used_cached = ( |
1257 cachedelta is not None |
1288 cachedelta is not None |
1258 and dbg_try_rounds == 1 |
1289 and dbg_try_rounds == 1 |
1259 and dbg_try_count == 1 |
1290 and dbg_try_count == 1 |
1260 and deltainfo.base == cachedelta[0] |
1291 and deltainfo.base == cachedelta[0] |
1261 ) |
1292 ) |
1262 dbg = { |
1293 dbg = { |
1263 'duration': end - start, |
1294 'duration': end - start, |
1264 'revision': target_rev, |
1295 'revision': target_rev, |
1265 'delta-base': deltainfo.base, |
1296 'delta-base': deltainfo.base, # pytype: disable=attribute-error |
1266 'search_round_count': dbg_try_rounds, |
1297 'search_round_count': dbg_try_rounds, |
1267 'using-cached-base': used_cached, |
1298 'using-cached-base': used_cached, |
1268 'delta_try_count': dbg_try_count, |
1299 'delta_try_count': dbg_try_count, |
1269 'type': dbg_type, |
1300 'type': dbg_type, |
1270 'p1-chain-len': p1_chain_len, |
1301 'p1-chain-len': p1_chain_len, |
1292 target_revlog = b'FILELOG:' |
1323 target_revlog = b'FILELOG:' |
1293 if target_key: |
1324 if target_key: |
1294 target_revlog += b'%s:' % target_key |
1325 target_revlog += b'%s:' % target_key |
1295 dbg['target-revlog'] = target_revlog |
1326 dbg['target-revlog'] = target_revlog |
1296 |
1327 |
1297 msg = ( |
1328 if self._debug_info is not None: |
1298 b"DBG-DELTAS:" |
1329 self._debug_info.append(dbg) |
1299 b" %-12s" |
1330 |
1300 b" rev=%d:" |
1331 if self._write_debug is not None: |
1301 b" delta-base=%d" |
1332 msg = ( |
1302 b" is-cached=%d" |
1333 b"DBG-DELTAS:" |
1303 b" - search-rounds=%d" |
1334 b" %-12s" |
1304 b" try-count=%d" |
1335 b" rev=%d:" |
1305 b" - delta-type=%-6s" |
1336 b" delta-base=%d" |
1306 b" snap-depth=%d" |
1337 b" is-cached=%d" |
1307 b" - p1-chain-length=%d" |
1338 b" - search-rounds=%d" |
1308 b" p2-chain-length=%d" |
1339 b" try-count=%d" |
1309 b" - duration=%f" |
1340 b" - delta-type=%-6s" |
1310 b"\n" |
1341 b" snap-depth=%d" |
1311 ) |
1342 b" - p1-chain-length=%d" |
1312 msg %= ( |
1343 b" p2-chain-length=%d" |
1313 dbg["target-revlog"], |
1344 b" - duration=%f" |
1314 dbg["revision"], |
1345 b"\n" |
1315 dbg["delta-base"], |
1346 ) |
1316 dbg["using-cached-base"], |
1347 msg %= ( |
1317 dbg["search_round_count"], |
1348 dbg["target-revlog"], |
1318 dbg["delta_try_count"], |
1349 dbg["revision"], |
1319 dbg["type"], |
1350 dbg["delta-base"], |
1320 dbg["snapshot-depth"], |
1351 dbg["using-cached-base"], |
1321 dbg["p1-chain-len"], |
1352 dbg["search_round_count"], |
1322 dbg["p2-chain-len"], |
1353 dbg["delta_try_count"], |
1323 dbg["duration"], |
1354 dbg["type"], |
1324 ) |
1355 dbg["snapshot-depth"], |
1325 self._write_debug(msg) |
1356 dbg["p1-chain-len"], |
|
1357 dbg["p2-chain-len"], |
|
1358 dbg["duration"], |
|
1359 ) |
|
1360 self._write_debug(msg) |
1326 return deltainfo |
1361 return deltainfo |
1327 |
1362 |
1328 |
1363 |
1329 def delta_compression(default_compression_header, deltainfo): |
1364 def delta_compression(default_compression_header, deltainfo): |
1330 """return (COMPRESSION_MODE, deltainfo) |
1365 """return (COMPRESSION_MODE, deltainfo) |