mercurial/revlogutils/deltas.py
changeset 51349 cc806f20d756
parent 51348 d58e14262587
child 51350 670e68729aa7
equal deleted inserted replaced
51348:d58e14262587 51349:cc806f20d756
   587 
   587 
   588 # If a revision's full text is that much bigger than a base candidate full
   588 # If a revision's full text is that much bigger than a base candidate full
   589 # text's, it is very unlikely that it will produce a valid delta. We no longer
   589 # text's, it is very unlikely that it will produce a valid delta. We no longer
   590 # consider these candidates.
   590 # consider these candidates.
   591 LIMIT_BASE2TEXT = 500
   591 LIMIT_BASE2TEXT = 500
       
   592 
       
   593 ### stage of the search, used for debug and to select and to adjust some logic.
       
   594 # initial stage, next step is unknown
       
   595 _STAGE_UNSPECIFIED = "unspecified"
       
   596 # trying the cached delta
       
   597 _STAGE_CACHED = "cached"
       
   598 # trying delta based on parents
       
   599 _STAGE_PARENTS = "parents"
       
   600 # trying to build a valid snapshot of any level
       
   601 _STAGE_SNAPSHOT = "snapshot"
       
   602 # trying to build a delta based of the previous revision
       
   603 _STAGE_PREV = "prev"
       
   604 # trying to build a full snapshot
       
   605 _STAGE_FULL = "full"
   592 
   606 
   593 
   607 
   594 class _BaseDeltaSearch(abc.ABC):
   608 class _BaseDeltaSearch(abc.ABC):
   595     """perform the search of a good delta for a single revlog revision
   609     """perform the search of a good delta for a single revlog revision
   596 
   610 
   632             snapshot_cache = SnapshotCache()
   646             snapshot_cache = SnapshotCache()
   633         self.snapshot_cache = snapshot_cache
   647         self.snapshot_cache = snapshot_cache
   634 
   648 
   635         self.tested = {nullrev}
   649         self.tested = {nullrev}
   636 
   650 
       
   651         self.current_stage = _STAGE_UNSPECIFIED
   637         self.current_group = None
   652         self.current_group = None
   638         self._init_group()
   653         self._init_group()
   639 
   654 
   640     def is_good_delta_info(self, deltainfo):
   655     def is_good_delta_info(self, deltainfo):
   641         """Returns True if the given delta is good.
   656         """Returns True if the given delta is good.
   788 
   803 
   789     This search variant is to be used in case where we should not store delta.
   804     This search variant is to be used in case where we should not store delta.
   790     """
   805     """
   791 
   806 
   792     def _init_group(self):
   807     def _init_group(self):
   793         pass
   808         self.current_stage = _STAGE_FULL
   794 
   809 
   795     def next_group(self, good_delta=None):
   810     def next_group(self, good_delta=None):
   796         pass
   811         pass
   797 
   812 
   798 
   813 
   802     This search variant is to be used when the format does not allow for delta
   817     This search variant is to be used when the format does not allow for delta
   803     against arbitrary bases.
   818     against arbitrary bases.
   804     """
   819     """
   805 
   820 
   806     def _init_group(self):
   821     def _init_group(self):
       
   822         self.current_stage = _STAGE_PREV
   807         self.current_group = [self.target_rev - 1]
   823         self.current_group = [self.target_rev - 1]
   808 
   824 
   809     def next_group(self, good_delta=None):
   825     def next_group(self, good_delta=None):
       
   826         self.current_stage = _STAGE_FULL
   810         self.current_group = None
   827         self.current_group = None
   811 
   828 
   812 
   829 
   813 class _DeltaSearch(_BaseDeltaSearch):
   830 class _DeltaSearch(_BaseDeltaSearch):
   814     """Generic delta search variants
   831     """Generic delta search variants
  1024             self.cachedelta is not None
  1041             self.cachedelta is not None
  1025             and self.cachedelta[2] > DELTA_BASE_REUSE_NO
  1042             and self.cachedelta[2] > DELTA_BASE_REUSE_NO
  1026         ):
  1043         ):
  1027             # Assume what we received from the server is a good choice
  1044             # Assume what we received from the server is a good choice
  1028             # build delta will reuse the cache
  1045             # build delta will reuse the cache
       
  1046             self.current_stage = _STAGE_CACHED
  1029             good = yield (self.cachedelta[0],)
  1047             good = yield (self.cachedelta[0],)
  1030             if good is not None:
  1048             if good is not None:
  1031                 yield None
  1049                 yield None
  1032                 return
  1050                 return
  1033         groups = self._raw_groups()
  1051         groups = self._raw_groups()
  1037                 break
  1055                 break
  1038 
  1056 
  1039         # If sparse revlog is enabled, we can try to refine the available
  1057         # If sparse revlog is enabled, we can try to refine the available
  1040         # deltas
  1058         # deltas
  1041         if not self.revlog.delta_config.sparse_revlog:
  1059         if not self.revlog.delta_config.sparse_revlog:
       
  1060             self.current_stage = _STAGE_FULL
  1042             yield None
  1061             yield None
  1043             return
  1062             return
  1044 
  1063 
  1045         # if we have a refinable value, try to refine it
  1064         # if we have a refinable value, try to refine it
  1046         if (
  1065         if (
  1047             good is not None
  1066             good is not None
  1048             and good not in (self.p1, self.p2)
  1067             and good not in (self.p1, self.p2)
  1049             and self.revlog.issnapshot(good)
  1068             and self.revlog.issnapshot(good)
  1050         ):
  1069         ):
       
  1070             self.current_stage = _STAGE_SNAPSHOT
  1051             # refine snapshot down
  1071             # refine snapshot down
  1052             previous = None
  1072             previous = None
  1053             while previous != good:
  1073             while previous != good:
  1054                 previous = good
  1074                 previous = good
  1055                 base = self.revlog.deltaparent(good)
  1075                 base = self.revlog.deltaparent(good)
  1065                 children = tuple(
  1085                 children = tuple(
  1066                     sorted(c for c in self.snapshot_cache.snapshots[good])
  1086                     sorted(c for c in self.snapshot_cache.snapshots[good])
  1067                 )
  1087                 )
  1068                 good = yield children
  1088                 good = yield children
  1069 
  1089 
       
  1090         self.current_stage = _STAGE_FULL
  1070         yield None
  1091         yield None
  1071 
  1092 
  1072     def _raw_groups(self):
  1093     def _raw_groups(self):
  1073         """Provides group of revision to be tested as delta base
  1094         """Provides group of revision to be tested as delta base
  1074 
  1095 
  1082         deltachain = lambda rev: self.revlog._deltachain(rev)[0]
  1103         deltachain = lambda rev: self.revlog._deltachain(rev)[0]
  1083 
  1104 
  1084         # exclude already lazy tested base if any
  1105         # exclude already lazy tested base if any
  1085         parents = [p for p in (self.p1, self.p2) if p != nullrev]
  1106         parents = [p for p in (self.p1, self.p2) if p != nullrev]
  1086 
  1107 
       
  1108         self.current_stage = _STAGE_PARENTS
  1087         if (
  1109         if (
  1088             not self.revlog.delta_config.delta_both_parents
  1110             not self.revlog.delta_config.delta_both_parents
  1089             and len(parents) == 2
  1111             and len(parents) == 2
  1090         ):
  1112         ):
  1091             parents.sort()
  1113             parents.sort()
  1097         elif len(parents) > 0:
  1119         elif len(parents) > 0:
  1098             # Test all parents (1 or 2), and keep the best candidate
  1120             # Test all parents (1 or 2), and keep the best candidate
  1099             yield parents
  1121             yield parents
  1100 
  1122 
  1101         if sparse and parents:
  1123         if sparse and parents:
       
  1124             self.current_stage = _STAGE_SNAPSHOT
  1102             # See if we can use an existing snapshot in the parent chains to
  1125             # See if we can use an existing snapshot in the parent chains to
  1103             # use as a base for a new intermediate-snapshot
  1126             # use as a base for a new intermediate-snapshot
  1104             #
  1127             #
  1105             # search for snapshot in parents delta chain map: snapshot-level:
  1128             # search for snapshot in parents delta chain map: snapshot-level:
  1106             # snapshot-rev
  1129             # snapshot-rev
  1186             yield tuple(sorted(full))
  1209             yield tuple(sorted(full))
  1187 
  1210 
  1188         if not sparse:
  1211         if not sparse:
  1189             # other approach failed try against prev to hopefully save us a
  1212             # other approach failed try against prev to hopefully save us a
  1190             # fulltext.
  1213             # fulltext.
       
  1214             self.current_stage = _STAGE_PREV
  1191             yield (prev,)
  1215             yield (prev,)
  1192 
  1216 
  1193 
  1217 
  1194 class SnapshotCache:
  1218 class SnapshotCache:
  1195     __slots__ = ('snapshots', '_start_rev', '_end_rev')
  1219     __slots__ = ('snapshots', '_start_rev', '_end_rev')