Show More
@@ -73,6 +73,7 b' from . import (' | |||
|
73 | 73 | repoview, |
|
74 | 74 | requirements, |
|
75 | 75 | revlog, |
|
76 | revlogutils, | |
|
76 | 77 | revset, |
|
77 | 78 | revsetlang, |
|
78 | 79 | scmutil, |
@@ -989,6 +990,65 b' def debugdeltachain(ui, repo, file_=None' | |||
|
989 | 990 | |
|
990 | 991 | |
|
991 | 992 | @command( |
|
993 | b'debug-delta-find', | |
|
994 | cmdutil.debugrevlogopts + cmdutil.formatteropts, | |
|
995 | _(b'-c|-m|FILE REV'), | |
|
996 | optionalrepo=True, | |
|
997 | ) | |
|
998 | def debugdeltafind(ui, repo, arg_1, arg_2=None, **opts): | |
|
999 | """display the computation to get to a valid delta for storing REV | |
|
1000 | ||
|
1001 | This command will replay the process used to find the "best" delta to store | |
|
1002 | a revision and display information about all the steps used to get to that | |
|
1003 | result. | |
|
1004 | ||
|
1005 | The revision use the revision number of the target storage (not changelog | |
|
1006 | revision number). | |
|
1007 | ||
|
1008 | note: the process is initiated from a full text of the revision to store. | |
|
1009 | """ | |
|
1010 | opts = pycompat.byteskwargs(opts) | |
|
1011 | if arg_2 is None: | |
|
1012 | file_ = None | |
|
1013 | rev = arg_1 | |
|
1014 | else: | |
|
1015 | file_ = arg_1 | |
|
1016 | rev = arg_2 | |
|
1017 | ||
|
1018 | rev = int(rev) | |
|
1019 | ||
|
1020 | revlog = cmdutil.openrevlog(repo, b'debugdeltachain', file_, opts) | |
|
1021 | ||
|
1022 | deltacomputer = deltautil.deltacomputer( | |
|
1023 | revlog, | |
|
1024 | write_debug=ui.write, | |
|
1025 | debug_search=True, | |
|
1026 | ) | |
|
1027 | ||
|
1028 | node = revlog.node(rev) | |
|
1029 | p1r, p2r = revlog.parentrevs(rev) | |
|
1030 | p1 = revlog.node(p1r) | |
|
1031 | p2 = revlog.node(p2r) | |
|
1032 | btext = [revlog.revision(rev)] | |
|
1033 | textlen = len(btext[0]) | |
|
1034 | cachedelta = None | |
|
1035 | flags = revlog.flags(rev) | |
|
1036 | ||
|
1037 | revinfo = revlogutils.revisioninfo( | |
|
1038 | node, | |
|
1039 | p1, | |
|
1040 | p2, | |
|
1041 | btext, | |
|
1042 | textlen, | |
|
1043 | cachedelta, | |
|
1044 | flags, | |
|
1045 | ) | |
|
1046 | ||
|
1047 | fh = revlog._datafp() | |
|
1048 | deltacomputer.finddeltainfo(revinfo, fh, target_rev=rev) | |
|
1049 | ||
|
1050 | ||
|
1051 | @command( | |
|
992 | 1052 | b'debugdirstate|debugstate', |
|
993 | 1053 | [ |
|
994 | 1054 | ( |
@@ -931,9 +931,10 b' def _rawgroups(revlog, p1, p2, cachedelt' | |||
|
931 | 931 | |
|
932 | 932 | |
|
933 | 933 | class deltacomputer: |
|
934 | def __init__(self, revlog, write_debug=None): | |
|
934 | def __init__(self, revlog, write_debug=None, debug_search=False): | |
|
935 | 935 | self.revlog = revlog |
|
936 | 936 | self._write_debug = write_debug |
|
937 | self._debug_search = debug_search | |
|
937 | 938 | |
|
938 | 939 | def buildtext(self, revinfo, fh): |
|
939 | 940 | """Builds a fulltext version of a revision |
@@ -980,6 +981,7 b' class deltacomputer:' | |||
|
980 | 981 | def _builddeltainfo(self, revinfo, base, fh): |
|
981 | 982 | # can we use the cached delta? |
|
982 | 983 | revlog = self.revlog |
|
984 | debug_search = self._write_debug is not None and self._debug_search | |
|
983 | 985 | chainbase = revlog.chainbase(base) |
|
984 | 986 | if revlog._generaldelta: |
|
985 | 987 | deltabase = base |
@@ -1009,13 +1011,27 b' class deltacomputer:' | |||
|
1009 | 1011 | delta = revinfo.cachedelta[1] |
|
1010 | 1012 | if delta is None: |
|
1011 | 1013 | delta = self._builddeltadiff(base, revinfo, fh) |
|
1014 | if debug_search: | |
|
1015 | msg = b"DBG-DELTAS-SEARCH: uncompressed-delta-size=%d\n" | |
|
1016 | msg %= len(delta) | |
|
1017 | self._write_debug(msg) | |
|
1012 | 1018 | # snapshotdept need to be neither None nor 0 level snapshot |
|
1013 | 1019 | if revlog.upperboundcomp is not None and snapshotdepth: |
|
1014 | 1020 | lowestrealisticdeltalen = len(delta) // revlog.upperboundcomp |
|
1015 | 1021 | snapshotlimit = revinfo.textlen >> snapshotdepth |
|
1022 | if debug_search: | |
|
1023 | msg = b"DBG-DELTAS-SEARCH: projected-lower-size=%d\n" | |
|
1024 | msg %= lowestrealisticdeltalen | |
|
1025 | self._write_debug(msg) | |
|
1016 | 1026 | if snapshotlimit < lowestrealisticdeltalen: |
|
1027 | if debug_search: | |
|
1028 | msg = b"DBG-DELTAS-SEARCH: DISCARDED (snapshot limit)\n" | |
|
1029 | self._write_debug(msg) | |
|
1017 | 1030 | return None |
|
1018 | 1031 | if revlog.length(base) < lowestrealisticdeltalen: |
|
1032 | if debug_search: | |
|
1033 | msg = b"DBG-DELTAS-SEARCH: DISCARDED (prev size)\n" | |
|
1034 | self._write_debug(msg) | |
|
1019 | 1035 | return None |
|
1020 | 1036 | header, data = revlog.compress(delta) |
|
1021 | 1037 | deltalen = len(header) + len(data) |
@@ -1090,6 +1106,8 b' class deltacomputer:' | |||
|
1090 | 1106 | if self._write_debug is not None: |
|
1091 | 1107 | start = util.timer() |
|
1092 | 1108 | |
|
1109 | debug_search = self._write_debug is not None and self._debug_search | |
|
1110 | ||
|
1093 | 1111 | # count the number of different delta we tried (for debug purpose) |
|
1094 | 1112 | dbg_try_count = 0 |
|
1095 | 1113 | # count the number of "search round" we did. (for debug purpose) |
@@ -1113,6 +1131,10 b' class deltacomputer:' | |||
|
1113 | 1131 | p2_chain_len = revlog._chaininfo(p2r)[0] |
|
1114 | 1132 | else: |
|
1115 | 1133 | p2_chain_len = -1 |
|
1134 | if debug_search: | |
|
1135 | msg = b"DBG-DELTAS-SEARCH: SEARCH rev=%d\n" | |
|
1136 | msg %= target_rev | |
|
1137 | self._write_debug(msg) | |
|
1116 | 1138 | |
|
1117 | 1139 | groups = _candidategroups( |
|
1118 | 1140 | self.revlog, revinfo.textlen, p1r, p2r, cachedelta |
@@ -1120,21 +1142,93 b' class deltacomputer:' | |||
|
1120 | 1142 | candidaterevs = next(groups) |
|
1121 | 1143 | while candidaterevs is not None: |
|
1122 | 1144 | dbg_try_rounds += 1 |
|
1145 | if debug_search: | |
|
1146 | prev = None | |
|
1147 | if deltainfo is not None: | |
|
1148 | prev = deltainfo.base | |
|
1149 | ||
|
1150 | if p1 in candidaterevs or p2 in candidaterevs: | |
|
1151 | round_type = b"parents" | |
|
1152 | elif prev is not None and all(c < prev for c in candidaterevs): | |
|
1153 | round_type = b"refine-down" | |
|
1154 | elif prev is not None and all(c > prev for c in candidaterevs): | |
|
1155 | round_type = b"refine-up" | |
|
1156 | else: | |
|
1157 | round_type = b"search-down" | |
|
1158 | msg = b"DBG-DELTAS-SEARCH: ROUND #%d - %d candidates - %s\n" | |
|
1159 | msg %= (dbg_try_rounds, len(candidaterevs), round_type) | |
|
1160 | self._write_debug(msg) | |
|
1123 | 1161 | nominateddeltas = [] |
|
1124 | 1162 | if deltainfo is not None: |
|
1163 | if debug_search: | |
|
1164 | msg = ( | |
|
1165 | b"DBG-DELTAS-SEARCH: CONTENDER: rev=%d - length=%d\n" | |
|
1166 | ) | |
|
1167 | msg %= (deltainfo.base, deltainfo.deltalen) | |
|
1168 | self._write_debug(msg) | |
|
1125 | 1169 | # if we already found a good delta, |
|
1126 | 1170 | # challenge it against refined candidates |
|
1127 | 1171 | nominateddeltas.append(deltainfo) |
|
1128 | 1172 | for candidaterev in candidaterevs: |
|
1173 | if debug_search: | |
|
1174 | msg = b"DBG-DELTAS-SEARCH: CANDIDATE: rev=%d\n" | |
|
1175 | msg %= candidaterev | |
|
1176 | self._write_debug(msg) | |
|
1177 | candidate_type = None | |
|
1178 | if candidaterev == p1: | |
|
1179 | candidate_type = b"p1" | |
|
1180 | elif candidaterev == p2: | |
|
1181 | candidate_type = b"p2" | |
|
1182 | elif self.revlog.issnapshot(candidaterev): | |
|
1183 | candidate_type = b"snapshot-%d" | |
|
1184 | candidate_type %= self.revlog.snapshotdepth( | |
|
1185 | candidaterev | |
|
1186 | ) | |
|
1187 | ||
|
1188 | if candidate_type is not None: | |
|
1189 | msg = b"DBG-DELTAS-SEARCH: type=%s\n" | |
|
1190 | msg %= candidate_type | |
|
1191 | self._write_debug(msg) | |
|
1192 | msg = b"DBG-DELTAS-SEARCH: size=%d\n" | |
|
1193 | msg %= self.revlog.length(candidaterev) | |
|
1194 | self._write_debug(msg) | |
|
1195 | msg = b"DBG-DELTAS-SEARCH: base=%d\n" | |
|
1196 | msg %= self.revlog.deltaparent(candidaterev) | |
|
1197 | self._write_debug(msg) | |
|
1129 | 1198 | if candidaterev in excluded_bases: |
|
1199 | if debug_search: | |
|
1200 | msg = b"DBG-DELTAS-SEARCH: EXCLUDED\n" | |
|
1201 | self._write_debug(msg) | |
|
1130 | 1202 | continue |
|
1131 | 1203 | if candidaterev >= target_rev: |
|
1204 | if debug_search: | |
|
1205 | msg = b"DBG-DELTAS-SEARCH: TOO-HIGH\n" | |
|
1206 | self._write_debug(msg) | |
|
1132 | 1207 | continue |
|
1133 | 1208 | dbg_try_count += 1 |
|
1209 | ||
|
1210 | if debug_search: | |
|
1211 | delta_start = util.timer() | |
|
1134 | 1212 | candidatedelta = self._builddeltainfo(revinfo, candidaterev, fh) |
|
1213 | if debug_search: | |
|
1214 | delta_end = util.timer() | |
|
1215 | msg = b"DBG-DELTAS-SEARCH: delta-search-time=%f\n" | |
|
1216 | msg %= delta_end - delta_start | |
|
1217 | self._write_debug(msg) | |
|
1135 | 1218 | if candidatedelta is not None: |
|
1136 | 1219 | if isgooddeltainfo(self.revlog, candidatedelta, revinfo): |
|
1220 | if debug_search: | |
|
1221 | msg = b"DBG-DELTAS-SEARCH: DELTA: length=%d (GOOD)\n" | |
|
1222 | msg %= candidatedelta.deltalen | |
|
1223 | self._write_debug(msg) | |
|
1137 | 1224 | nominateddeltas.append(candidatedelta) |
|
1225 | elif debug_search: | |
|
1226 | msg = b"DBG-DELTAS-SEARCH: DELTA: length=%d (BAD)\n" | |
|
1227 | msg %= candidatedelta.deltalen | |
|
1228 | self._write_debug(msg) | |
|
1229 | elif debug_search: | |
|
1230 | msg = b"DBG-DELTAS-SEARCH: NO-DELTA\n" | |
|
1231 | self._write_debug(msg) | |
|
1138 | 1232 | if nominateddeltas: |
|
1139 | 1233 | deltainfo = min(nominateddeltas, key=lambda x: x.deltalen) |
|
1140 | 1234 | if deltainfo is not None: |
@@ -1145,7 +1239,7 b' class deltacomputer:' | |||
|
1145 | 1239 | if deltainfo is None: |
|
1146 | 1240 | dbg_type = b"full" |
|
1147 | 1241 | deltainfo = self._fullsnapshotinfo(fh, revinfo, target_rev) |
|
1148 | elif deltainfo.snapshotdepth: | |
|
1242 | elif deltainfo.snapshotdepth: # pytype: disable=attribute-error | |
|
1149 | 1243 | dbg_type = b"snapshot" |
|
1150 | 1244 | else: |
|
1151 | 1245 | dbg_type = b"delta" |
@@ -1161,8 +1255,13 b' class deltacomputer:' | |||
|
1161 | 1255 | 'p1-chain-len': p1_chain_len, |
|
1162 | 1256 | 'p2-chain-len': p2_chain_len, |
|
1163 | 1257 | } |
|
1164 | if deltainfo.snapshotdepth is not None: | |
|
1165 | dbg['snapshot-depth'] = deltainfo.snapshotdepth | |
|
1258 | if ( | |
|
1259 | deltainfo.snapshotdepth # pytype: disable=attribute-error | |
|
1260 | is not None | |
|
1261 | ): | |
|
1262 | dbg[ | |
|
1263 | 'snapshot-depth' | |
|
1264 | ] = deltainfo.snapshotdepth # pytype: disable=attribute-error | |
|
1166 | 1265 | else: |
|
1167 | 1266 | dbg['snapshot-depth'] = 0 |
|
1168 | 1267 | target_revlog = b"UNKNOWN" |
@@ -74,6 +74,7 b' Do not show debug commands if there are ' | |||
|
74 | 74 | |
|
75 | 75 | Show debug commands if there are no other candidates |
|
76 | 76 | $ hg debugcomplete debug |
|
77 | debug-delta-find | |
|
77 | 78 | debug-repair-issue6528 |
|
78 | 79 | debugancestor |
|
79 | 80 | debugantivirusrunning |
@@ -267,6 +268,7 b' Show all commands + options' | |||
|
267 | 268 | config: untrusted, exp-all-known, edit, local, source, shared, non-shared, global, template |
|
268 | 269 | continue: dry-run |
|
269 | 270 | copy: forget, after, at-rev, force, include, exclude, dry-run |
|
271 | debug-delta-find: changelog, manifest, dir, template | |
|
270 | 272 | debug-repair-issue6528: to-report, from-report, paranoid, dry-run |
|
271 | 273 | debugancestor: |
|
272 | 274 | debugantivirusrunning: |
@@ -978,6 +978,8 b' Test list of internal help commands' | |||
|
978 | 978 | $ hg help debug |
|
979 | 979 | debug commands (internal and unsupported): |
|
980 | 980 | |
|
981 | debug-delta-find | |
|
982 | display the computation to get to a valid delta for storing REV | |
|
981 | 983 | debug-repair-issue6528 |
|
982 | 984 | find affected revisions and repair them. See issue6528 for more |
|
983 | 985 | details. |
@@ -149,4 +149,46 b' repeatedly while some of it changes rare' | |||
|
149 | 149 | deltas against p2 : 63 ( 1.36%) |
|
150 | 150 | deltas against other : 0 ( 0.00%) |
|
151 | 151 | |
|
152 | ||
|
153 | Test `debug-delta-find` | |
|
154 | ----------------------- | |
|
155 | ||
|
156 | $ ls -1 | |
|
157 | SPARSE-REVLOG-TEST-FILE | |
|
158 | $ hg debugdeltachain SPARSE-REVLOG-TEST-FILE | grep other | tail -1 | |
|
159 | 4971 3 5 4930 other 19179 346472 427596 1.23414 15994877 15567281 36.40652 427596 179288 1.00000 5 | |
|
160 | $ hg debug-delta-find SPARSE-REVLOG-TEST-FILE 4971 | |
|
161 | DBG-DELTAS-SEARCH: SEARCH rev=4971 | |
|
162 | DBG-DELTAS-SEARCH: ROUND #1 - 2 candidates - search-down | |
|
163 | DBG-DELTAS-SEARCH: CANDIDATE: rev=4962 | |
|
164 | DBG-DELTAS-SEARCH: type=snapshot-4 | |
|
165 | DBG-DELTAS-SEARCH: size=18296 | |
|
166 | DBG-DELTAS-SEARCH: base=4930 | |
|
167 | DBG-DELTAS-SEARCH: uncompressed-delta-size=30377 | |
|
168 | DBG-DELTAS-SEARCH: delta-search-time=* (glob) | |
|
169 | DBG-DELTAS-SEARCH: DELTA: length=16872 (BAD) | |
|
170 | DBG-DELTAS-SEARCH: CANDIDATE: rev=4971 | |
|
171 | DBG-DELTAS-SEARCH: type=snapshot-4 | |
|
172 | DBG-DELTAS-SEARCH: size=19179 | |
|
173 | DBG-DELTAS-SEARCH: base=4930 | |
|
174 | DBG-DELTAS-SEARCH: TOO-HIGH | |
|
175 | DBG-DELTAS-SEARCH: ROUND #2 - 1 candidates - search-down | |
|
176 | DBG-DELTAS-SEARCH: CANDIDATE: rev=4930 | |
|
177 | DBG-DELTAS-SEARCH: type=snapshot-3 | |
|
178 | DBG-DELTAS-SEARCH: size=39228 | |
|
179 | DBG-DELTAS-SEARCH: base=4799 | |
|
180 | DBG-DELTAS-SEARCH: uncompressed-delta-size=33050 | |
|
181 | DBG-DELTAS-SEARCH: delta-search-time=* (glob) | |
|
182 | DBG-DELTAS-SEARCH: DELTA: length=19179 (GOOD) | |
|
183 | DBG-DELTAS-SEARCH: ROUND #3 - 1 candidates - refine-down | |
|
184 | DBG-DELTAS-SEARCH: CONTENDER: rev=4930 - length=19179 | |
|
185 | DBG-DELTAS-SEARCH: CANDIDATE: rev=4799 | |
|
186 | DBG-DELTAS-SEARCH: type=snapshot-2 | |
|
187 | DBG-DELTAS-SEARCH: size=50213 | |
|
188 | DBG-DELTAS-SEARCH: base=4623 | |
|
189 | DBG-DELTAS-SEARCH: uncompressed-delta-size=82661 | |
|
190 | DBG-DELTAS-SEARCH: delta-search-time=* (glob) | |
|
191 | DBG-DELTAS-SEARCH: DELTA: length=49132 (BAD) | |
|
192 | DBG-DELTAS: FILELOG:SPARSE-REVLOG-TEST-FILE: rev=4971: search-rounds=3 try-count=3 - delta-type=snapshot snap-depth=4 - p1-chain-length=15 p2-chain-length=-1 - duration=* (glob) | |
|
193 | ||
|
152 | 194 | $ cd .. |
General Comments 0
You need to be logged in to leave comments.
Login now