103 vfs.unlink(cleanup) |
103 vfs.unlink(cleanup) |
104 else: |
104 else: |
105 os.unlink(cleanup) |
105 os.unlink(cleanup) |
106 |
106 |
107 |
107 |
|
108 def _dbg_ubdl_line( |
|
109 ui, |
|
110 indent, |
|
111 key, |
|
112 base_value=None, |
|
113 percentage_base=None, |
|
114 percentage_key=None, |
|
115 ): |
|
116 """Print one line of debug_unbundle_debug_info""" |
|
117 line = b"DEBUG-UNBUNDLING: " |
|
118 line += b' ' * (2 * indent) |
|
119 key += b":" |
|
120 padding = b'' |
|
121 if base_value is not None: |
|
122 assert len(key) + 1 + (2 * indent) <= _KEY_PART_WIDTH |
|
123 line += key.ljust(_KEY_PART_WIDTH - (2 * indent)) |
|
124 if isinstance(base_value, float): |
|
125 line += b"%14.3f seconds" % base_value |
|
126 else: |
|
127 line += b"%10d" % base_value |
|
128 padding = b' ' |
|
129 else: |
|
130 line += key |
|
131 |
|
132 if percentage_base is not None: |
|
133 line += padding |
|
134 padding = b'' |
|
135 assert base_value is not None |
|
136 percentage = base_value * 100 // percentage_base |
|
137 if percentage_key is not None: |
|
138 line += b" (%3d%% of %s)" % ( |
|
139 percentage, |
|
140 percentage_key, |
|
141 ) |
|
142 else: |
|
143 line += b" (%3d%%)" % percentage |
|
144 |
|
145 line += b'\n' |
|
146 ui.write_err(line) |
|
147 |
|
148 |
|
149 def _sumf(items): |
|
150 # python < 3.8 does not support a `start=0.0` argument to sum |
|
151 # So we have to cheat a bit until we drop support for those version |
|
152 if not items: |
|
153 return 0.0 |
|
154 return sum(items) |
|
155 |
|
156 |
|
157 def display_unbundle_debug_info(ui, debug_info): |
|
158 """display an unbundling report from debug information""" |
|
159 cl_info = [] |
|
160 mn_info = [] |
|
161 fl_info = [] |
|
162 _dispatch = [ |
|
163 (b'CHANGELOG:', cl_info), |
|
164 (b'MANIFESTLOG:', mn_info), |
|
165 (b'FILELOG:', fl_info), |
|
166 ] |
|
167 for e in debug_info: |
|
168 for prefix, info in _dispatch: |
|
169 if e["target-revlog"].startswith(prefix): |
|
170 info.append(e) |
|
171 break |
|
172 else: |
|
173 assert False, 'unreachable' |
|
174 each_info = [ |
|
175 (b'changelog', cl_info), |
|
176 (b'manifests', mn_info), |
|
177 (b'files', fl_info), |
|
178 ] |
|
179 |
|
180 # General Revision Countss |
|
181 _dbg_ubdl_line(ui, 0, b'revisions', len(debug_info)) |
|
182 for key, info in each_info: |
|
183 if not info: |
|
184 continue |
|
185 _dbg_ubdl_line(ui, 1, key, len(info), len(debug_info)) |
|
186 |
|
187 # General Time spent |
|
188 all_durations = [e['duration'] for e in debug_info] |
|
189 all_durations.sort() |
|
190 total_duration = _sumf(all_durations) |
|
191 _dbg_ubdl_line(ui, 0, b'total-time', total_duration) |
|
192 |
|
193 for key, info in each_info: |
|
194 if not info: |
|
195 continue |
|
196 durations = [e['duration'] for e in info] |
|
197 durations.sort() |
|
198 _dbg_ubdl_line(ui, 1, key, _sumf(durations), total_duration) |
|
199 |
|
200 # Count and cache reuse per delta types |
|
201 each_types = {} |
|
202 for key, info in each_info: |
|
203 each_types[key] = types = { |
|
204 b'full': 0, |
|
205 b'full-cached': 0, |
|
206 b'snapshot': 0, |
|
207 b'snapshot-cached': 0, |
|
208 b'delta': 0, |
|
209 b'delta-cached': 0, |
|
210 b'unknown': 0, |
|
211 b'unknown-cached': 0, |
|
212 } |
|
213 for e in info: |
|
214 types[e['type']] += 1 |
|
215 if e['using-cached-base']: |
|
216 types[e['type'] + b'-cached'] += 1 |
|
217 |
|
218 EXPECTED_TYPES = (b'full', b'snapshot', b'delta', b'unknown') |
|
219 if debug_info: |
|
220 _dbg_ubdl_line(ui, 0, b'type-count') |
|
221 for key, info in each_info: |
|
222 if info: |
|
223 _dbg_ubdl_line(ui, 1, key) |
|
224 t = each_types[key] |
|
225 for tn in EXPECTED_TYPES: |
|
226 if t[tn]: |
|
227 tc = tn + b'-cached' |
|
228 _dbg_ubdl_line(ui, 2, tn, t[tn]) |
|
229 _dbg_ubdl_line(ui, 3, b'cached', t[tc], t[tn]) |
|
230 |
|
231 # time perf delta types and reuse |
|
232 each_type_time = {} |
|
233 for key, info in each_info: |
|
234 each_type_time[key] = t = { |
|
235 b'full': [], |
|
236 b'full-cached': [], |
|
237 b'snapshot': [], |
|
238 b'snapshot-cached': [], |
|
239 b'delta': [], |
|
240 b'delta-cached': [], |
|
241 b'unknown': [], |
|
242 b'unknown-cached': [], |
|
243 } |
|
244 for e in info: |
|
245 t[e['type']].append(e['duration']) |
|
246 if e['using-cached-base']: |
|
247 t[e['type'] + b'-cached'].append(e['duration']) |
|
248 for t_key, value in list(t.items()): |
|
249 value.sort() |
|
250 t[t_key] = _sumf(value) |
|
251 |
|
252 if debug_info: |
|
253 _dbg_ubdl_line(ui, 0, b'type-time') |
|
254 for key, info in each_info: |
|
255 if info: |
|
256 _dbg_ubdl_line(ui, 1, key) |
|
257 t = each_type_time[key] |
|
258 td = total_duration # to same space on next lines |
|
259 for tn in EXPECTED_TYPES: |
|
260 if t[tn]: |
|
261 tc = tn + b'-cached' |
|
262 _dbg_ubdl_line(ui, 2, tn, t[tn], td, b"total") |
|
263 _dbg_ubdl_line(ui, 3, b'cached', t[tc], td, b"total") |
|
264 |
|
265 |
108 class cg1unpacker: |
266 class cg1unpacker: |
109 """Unpacker for cg1 changegroup streams. |
267 """Unpacker for cg1 changegroup streams. |
110 |
268 |
111 A changegroup unpacker handles the framing of the revision data in |
269 A changegroup unpacker handles the framing of the revision data in |
112 the wire format. Most consumers will want to use the apply() |
270 the wire format. Most consumers will want to use the apply() |
252 next = pos + 2 ** 20 |
410 next = pos + 2 ** 20 |
253 yield chunk[pos:next] |
411 yield chunk[pos:next] |
254 pos = next |
412 pos = next |
255 yield closechunk() |
413 yield closechunk() |
256 |
414 |
257 def _unpackmanifests(self, repo, revmap, trp, prog, addrevisioncb=None): |
415 def _unpackmanifests( |
|
416 self, |
|
417 repo, |
|
418 revmap, |
|
419 trp, |
|
420 prog, |
|
421 addrevisioncb=None, |
|
422 debug_info=None, |
|
423 ): |
258 self.callback = prog.increment |
424 self.callback = prog.increment |
259 # no need to check for empty manifest group here: |
425 # no need to check for empty manifest group here: |
260 # if the result of the merge of 1 and 2 is the same in 3 and 4, |
426 # if the result of the merge of 1 and 2 is the same in 3 and 4, |
261 # no new manifest will be created and the manifest group will |
427 # no new manifest will be created and the manifest group will |
262 # be empty during the pull |
428 # be empty during the pull |
263 self.manifestheader() |
429 self.manifestheader() |
264 deltas = self.deltaiter() |
430 deltas = self.deltaiter() |
265 storage = repo.manifestlog.getstorage(b'') |
431 storage = repo.manifestlog.getstorage(b'') |
266 storage.addgroup(deltas, revmap, trp, addrevisioncb=addrevisioncb) |
432 storage.addgroup( |
|
433 deltas, |
|
434 revmap, |
|
435 trp, |
|
436 addrevisioncb=addrevisioncb, |
|
437 debug_info=debug_info, |
|
438 ) |
267 prog.complete() |
439 prog.complete() |
268 self.callback = None |
440 self.callback = None |
269 |
441 |
270 def apply( |
442 def apply( |
271 self, |
443 self, |
624 def _deltaheader(self, headertuple, prevnode): |
805 def _deltaheader(self, headertuple, prevnode): |
625 node, p1, p2, deltabase, cs, flags = headertuple |
806 node, p1, p2, deltabase, cs, flags = headertuple |
626 protocol_flags = 0 |
807 protocol_flags = 0 |
627 return node, p1, p2, deltabase, cs, flags, protocol_flags |
808 return node, p1, p2, deltabase, cs, flags, protocol_flags |
628 |
809 |
629 def _unpackmanifests(self, repo, revmap, trp, prog, addrevisioncb=None): |
810 def _unpackmanifests( |
|
811 self, |
|
812 repo, |
|
813 revmap, |
|
814 trp, |
|
815 prog, |
|
816 addrevisioncb=None, |
|
817 debug_info=None, |
|
818 ): |
630 super(cg3unpacker, self)._unpackmanifests( |
819 super(cg3unpacker, self)._unpackmanifests( |
631 repo, revmap, trp, prog, addrevisioncb=addrevisioncb |
820 repo, |
|
821 revmap, |
|
822 trp, |
|
823 prog, |
|
824 addrevisioncb=addrevisioncb, |
|
825 debug_info=debug_info, |
632 ) |
826 ) |
633 for chunkdata in iter(self.filelogheader, {}): |
827 for chunkdata in iter(self.filelogheader, {}): |
634 # If we get here, there are directory manifests in the changegroup |
828 # If we get here, there are directory manifests in the changegroup |
635 d = chunkdata[b"filename"] |
829 d = chunkdata[b"filename"] |
636 repo.ui.debug(b"adding %s revisions\n" % d) |
830 repo.ui.debug(b"adding %s revisions\n" % d) |
637 deltas = self.deltaiter() |
831 deltas = self.deltaiter() |
638 if not repo.manifestlog.getstorage(d).addgroup( |
832 if not repo.manifestlog.getstorage(d).addgroup( |
639 deltas, revmap, trp, addrevisioncb=addrevisioncb |
833 deltas, |
|
834 revmap, |
|
835 trp, |
|
836 addrevisioncb=addrevisioncb, |
|
837 debug_info=debug_info, |
640 ): |
838 ): |
641 raise error.Abort(_(b"received dir revlog group is empty")) |
839 raise error.Abort(_(b"received dir revlog group is empty")) |
642 |
840 |
643 |
841 |
644 class cg4unpacker(cg3unpacker): |
842 class cg4unpacker(cg3unpacker): |