##// END OF EJS Templates
debug-revlog: keep the revlog open for the analysis duration...
marmoute -
r51910:edc44ab7 default
parent child Browse files
Show More
@@ -1,709 +1,712 b''
1 1 # revlogutils/debug.py - utility used for revlog debuging
2 2 #
3 3 # Copyright 2005-2007 Olivia Mackall <olivia@selenic.com>
4 4 # Copyright 2022 Octobus <contact@octobus.net>
5 5 #
6 6 # This software may be used and distributed according to the terms of the
7 7 # GNU General Public License version 2 or any later version.
8 8
9 9 import collections
10 10 import string
11 11
12 12 from .. import (
13 13 mdiff,
14 14 node as nodemod,
15 15 revlogutils,
16 16 )
17 17
18 18 from . import (
19 19 constants,
20 20 deltas as deltautil,
21 21 )
22 22
23 23 INDEX_ENTRY_DEBUG_COLUMN = []
24 24
25 25 NODE_SIZE = object()
26 26
27 27
28 28 class _column_base:
29 29 """constains the definition of a revlog column
30 30
31 31 name: the column header,
32 32 value_func: the function called to get a value,
33 33 size: the width of the column,
34 34 verbose_only: only include the column in verbose mode.
35 35 """
36 36
37 37 def __init__(self, name, value_func, size=None, verbose=False):
38 38 self.name = name
39 39 self.value_func = value_func
40 40 if size is not NODE_SIZE:
41 41 if size is None:
42 42 size = 8 # arbitrary default
43 43 size = max(len(name), size)
44 44 self._size = size
45 45 self.verbose_only = verbose
46 46
47 47 def get_size(self, node_size):
48 48 if self._size is NODE_SIZE:
49 49 return node_size
50 50 else:
51 51 return self._size
52 52
53 53
54 54 def debug_column(name, size=None, verbose=False):
55 55 """decorated function is registered as a column
56 56
57 57 name: the name of the column,
58 58 size: the expected size of the column.
59 59 """
60 60
61 61 def register(func):
62 62 entry = _column_base(
63 63 name=name,
64 64 value_func=func,
65 65 size=size,
66 66 verbose=verbose,
67 67 )
68 68 INDEX_ENTRY_DEBUG_COLUMN.append(entry)
69 69 return entry
70 70
71 71 return register
72 72
73 73
74 74 @debug_column(b"rev", size=6)
75 75 def _rev(index, rev, entry, hexfn):
76 76 return b"%d" % rev
77 77
78 78
79 79 @debug_column(b"rank", size=6, verbose=True)
80 80 def rank(index, rev, entry, hexfn):
81 81 return b"%d" % entry[constants.ENTRY_RANK]
82 82
83 83
84 84 @debug_column(b"linkrev", size=6)
85 85 def _linkrev(index, rev, entry, hexfn):
86 86 return b"%d" % entry[constants.ENTRY_LINK_REV]
87 87
88 88
89 89 @debug_column(b"nodeid", size=NODE_SIZE)
90 90 def _nodeid(index, rev, entry, hexfn):
91 91 return hexfn(entry[constants.ENTRY_NODE_ID])
92 92
93 93
94 94 @debug_column(b"p1-rev", size=6, verbose=True)
95 95 def _p1_rev(index, rev, entry, hexfn):
96 96 return b"%d" % entry[constants.ENTRY_PARENT_1]
97 97
98 98
99 99 @debug_column(b"p1-nodeid", size=NODE_SIZE)
100 100 def _p1_node(index, rev, entry, hexfn):
101 101 parent = entry[constants.ENTRY_PARENT_1]
102 102 p_entry = index[parent]
103 103 return hexfn(p_entry[constants.ENTRY_NODE_ID])
104 104
105 105
106 106 @debug_column(b"p2-rev", size=6, verbose=True)
107 107 def _p2_rev(index, rev, entry, hexfn):
108 108 return b"%d" % entry[constants.ENTRY_PARENT_2]
109 109
110 110
111 111 @debug_column(b"p2-nodeid", size=NODE_SIZE)
112 112 def _p2_node(index, rev, entry, hexfn):
113 113 parent = entry[constants.ENTRY_PARENT_2]
114 114 p_entry = index[parent]
115 115 return hexfn(p_entry[constants.ENTRY_NODE_ID])
116 116
117 117
118 118 @debug_column(b"full-size", size=20, verbose=True)
119 119 def full_size(index, rev, entry, hexfn):
120 120 return b"%d" % entry[constants.ENTRY_DATA_UNCOMPRESSED_LENGTH]
121 121
122 122
123 123 @debug_column(b"delta-base", size=6, verbose=True)
124 124 def delta_base(index, rev, entry, hexfn):
125 125 return b"%d" % entry[constants.ENTRY_DELTA_BASE]
126 126
127 127
128 128 @debug_column(b"flags", size=2, verbose=True)
129 129 def flags(index, rev, entry, hexfn):
130 130 field = entry[constants.ENTRY_DATA_OFFSET]
131 131 field &= 0xFFFF
132 132 return b"%d" % field
133 133
134 134
135 135 @debug_column(b"comp-mode", size=4, verbose=True)
136 136 def compression_mode(index, rev, entry, hexfn):
137 137 return b"%d" % entry[constants.ENTRY_DATA_COMPRESSION_MODE]
138 138
139 139
140 140 @debug_column(b"data-offset", size=20, verbose=True)
141 141 def data_offset(index, rev, entry, hexfn):
142 142 field = entry[constants.ENTRY_DATA_OFFSET]
143 143 field >>= 16
144 144 return b"%d" % field
145 145
146 146
147 147 @debug_column(b"chunk-size", size=10, verbose=True)
148 148 def data_chunk_size(index, rev, entry, hexfn):
149 149 return b"%d" % entry[constants.ENTRY_DATA_COMPRESSED_LENGTH]
150 150
151 151
152 152 @debug_column(b"sd-comp-mode", size=7, verbose=True)
153 153 def sidedata_compression_mode(index, rev, entry, hexfn):
154 154 compression = entry[constants.ENTRY_SIDEDATA_COMPRESSION_MODE]
155 155 if compression == constants.COMP_MODE_PLAIN:
156 156 return b"plain"
157 157 elif compression == constants.COMP_MODE_DEFAULT:
158 158 return b"default"
159 159 elif compression == constants.COMP_MODE_INLINE:
160 160 return b"inline"
161 161 else:
162 162 return b"%d" % compression
163 163
164 164
165 165 @debug_column(b"sidedata-offset", size=20, verbose=True)
166 166 def sidedata_offset(index, rev, entry, hexfn):
167 167 return b"%d" % entry[constants.ENTRY_SIDEDATA_OFFSET]
168 168
169 169
170 170 @debug_column(b"sd-chunk-size", size=10, verbose=True)
171 171 def sidedata_chunk_size(index, rev, entry, hexfn):
172 172 return b"%d" % entry[constants.ENTRY_SIDEDATA_COMPRESSED_LENGTH]
173 173
174 174
175 175 def debug_index(
176 176 ui,
177 177 repo,
178 178 formatter,
179 179 revlog,
180 180 full_node,
181 181 ):
182 182 """display index data for a revlog"""
183 183 if full_node:
184 184 hexfn = nodemod.hex
185 185 else:
186 186 hexfn = nodemod.short
187 187
188 188 idlen = 12
189 189 for i in revlog:
190 190 idlen = len(hexfn(revlog.node(i)))
191 191 break
192 192
193 193 fm = formatter
194 194
195 195 header_pieces = []
196 196 for column in INDEX_ENTRY_DEBUG_COLUMN:
197 197 if column.verbose_only and not ui.verbose:
198 198 continue
199 199 size = column.get_size(idlen)
200 200 name = column.name
201 201 header_pieces.append(name.rjust(size))
202 202
203 203 fm.plain(b' '.join(header_pieces) + b'\n')
204 204
205 205 index = revlog.index
206 206
207 207 for rev in revlog:
208 208 fm.startitem()
209 209 entry = index[rev]
210 210 first = True
211 211 for column in INDEX_ENTRY_DEBUG_COLUMN:
212 212 if column.verbose_only and not ui.verbose:
213 213 continue
214 214 if not first:
215 215 fm.plain(b' ')
216 216 first = False
217 217
218 218 size = column.get_size(idlen)
219 219 value = column.value_func(index, rev, entry, hexfn)
220 220 display = b"%%%ds" % size
221 221 fm.write(column.name, display, value)
222 222 fm.plain(b'\n')
223 223
224 224 fm.end()
225 225
226 226
227 227 def dump(ui, revlog):
228 228 """perform the work for `hg debugrevlog --dump"""
229 229 # XXX seems redundant with debug index ?
230 230 r = revlog
231 231 numrevs = len(r)
232 232 ui.write(
233 233 (
234 234 b"# rev p1rev p2rev start end deltastart base p1 p2"
235 235 b" rawsize totalsize compression heads chainlen\n"
236 236 )
237 237 )
238 238 ts = 0
239 239 heads = set()
240 240
241 241 for rev in range(numrevs):
242 242 dbase = r.deltaparent(rev)
243 243 if dbase == -1:
244 244 dbase = rev
245 245 cbase = r.chainbase(rev)
246 246 clen = r.chainlen(rev)
247 247 p1, p2 = r.parentrevs(rev)
248 248 rs = r.rawsize(rev)
249 249 ts = ts + rs
250 250 heads -= set(r.parentrevs(rev))
251 251 heads.add(rev)
252 252 try:
253 253 compression = ts / r.end(rev)
254 254 except ZeroDivisionError:
255 255 compression = 0
256 256 ui.write(
257 257 b"%5d %5d %5d %5d %5d %10d %4d %4d %4d %7d %9d "
258 258 b"%11d %5d %8d\n"
259 259 % (
260 260 rev,
261 261 p1,
262 262 p2,
263 263 r.start(rev),
264 264 r.end(rev),
265 265 r.start(dbase),
266 266 r.start(cbase),
267 267 r.start(p1),
268 268 r.start(p2),
269 269 rs,
270 270 ts,
271 271 compression,
272 272 len(heads),
273 273 clen,
274 274 )
275 275 )
276 276
277 277
278 278 def debug_revlog(ui, revlog):
279 279 """code for `hg debugrevlog`"""
280 280 r = revlog
281 281 format = r._format_version
282 282 v = r._format_flags
283 283 flags = []
284 284 gdelta = False
285 285 if v & constants.FLAG_INLINE_DATA:
286 286 flags.append(b'inline')
287 287 if v & constants.FLAG_GENERALDELTA:
288 288 gdelta = True
289 289 flags.append(b'generaldelta')
290 290 if not flags:
291 291 flags = [b'(none)']
292 292
293 293 ### the total size of stored content if incompressed.
294 294 full_text_total_size = 0
295 295 ### tracks merge vs single parent
296 296 nummerges = 0
297 297
298 298 ### tracks ways the "delta" are build
299 299 # nodelta
300 300 numempty = 0
301 301 numemptytext = 0
302 302 numemptydelta = 0
303 303 # full file content
304 304 numfull = 0
305 305 # intermediate snapshot against a prior snapshot
306 306 numsemi = 0
307 307 # snapshot count per depth
308 308 numsnapdepth = collections.defaultdict(lambda: 0)
309 309 # number of snapshots with a non-ancestor delta
310 310 numsnapdepth_nad = collections.defaultdict(lambda: 0)
311 311 # delta against previous revision
312 312 numprev = 0
313 313 # delta against prev, where prev is a non-ancestor
314 314 numprev_nad = 0
315 315 # delta against first or second parent (not prev)
316 316 nump1 = 0
317 317 nump2 = 0
318 318 # delta against neither prev nor parents
319 319 numother = 0
320 320 # delta against other that is a non-ancestor
321 321 numother_nad = 0
322 322 # delta against prev that are also first or second parent
323 323 # (details of `numprev`)
324 324 nump1prev = 0
325 325 nump2prev = 0
326 326
327 327 # data about delta chain of each revs
328 328 chainlengths = []
329 329 chainbases = []
330 330 chainspans = []
331 331
332 332 # data about each revision
333 333 datasize = [None, 0, 0]
334 334 fullsize = [None, 0, 0]
335 335 semisize = [None, 0, 0]
336 336 # snapshot count per depth
337 337 snapsizedepth = collections.defaultdict(lambda: [None, 0, 0])
338 338 deltasize = [None, 0, 0]
339 339 chunktypecounts = {}
340 340 chunktypesizes = {}
341 341
342 342 def addsize(size, l):
343 343 if l[0] is None or size < l[0]:
344 344 l[0] = size
345 345 if size > l[1]:
346 346 l[1] = size
347 347 l[2] += size
348 348
349 numrevs = len(r)
350 for rev in range(numrevs):
351 p1, p2 = r.parentrevs(rev)
352 delta = r.deltaparent(rev)
353 if format > 0:
354 s = r.rawsize(rev)
355 full_text_total_size += s
356 addsize(s, datasize)
357 if p2 != nodemod.nullrev:
358 nummerges += 1
359 size = r.length(rev)
360 if delta == nodemod.nullrev:
361 chainlengths.append(0)
362 chainbases.append(r.start(rev))
363 chainspans.append(size)
364 if size == 0:
365 numempty += 1
366 numemptytext += 1
349 with r.reading():
350 numrevs = len(r)
351 for rev in range(numrevs):
352 p1, p2 = r.parentrevs(rev)
353 delta = r.deltaparent(rev)
354 if format > 0:
355 s = r.rawsize(rev)
356 full_text_total_size += s
357 addsize(s, datasize)
358 if p2 != nodemod.nullrev:
359 nummerges += 1
360 size = r.length(rev)
361 if delta == nodemod.nullrev:
362 chainlengths.append(0)
363 chainbases.append(r.start(rev))
364 chainspans.append(size)
365 if size == 0:
366 numempty += 1
367 numemptytext += 1
368 else:
369 numfull += 1
370 numsnapdepth[0] += 1
371 addsize(size, fullsize)
372 addsize(size, snapsizedepth[0])
367 373 else:
368 numfull += 1
369 numsnapdepth[0] += 1
370 addsize(size, fullsize)
371 addsize(size, snapsizedepth[0])
372 else:
373 nad = (
374 delta != p1 and delta != p2 and not r.isancestorrev(delta, rev)
375 )
376 chainlengths.append(chainlengths[delta] + 1)
377 baseaddr = chainbases[delta]
378 revaddr = r.start(rev)
379 chainbases.append(baseaddr)
380 chainspans.append((revaddr - baseaddr) + size)
381 if size == 0:
382 numempty += 1
383 numemptydelta += 1
384 elif r.issnapshot(rev):
385 addsize(size, semisize)
386 numsemi += 1
387 depth = r.snapshotdepth(rev)
388 numsnapdepth[depth] += 1
389 if nad:
390 numsnapdepth_nad[depth] += 1
391 addsize(size, snapsizedepth[depth])
374 nad = (
375 delta != p1
376 and delta != p2
377 and not r.isancestorrev(delta, rev)
378 )
379 chainlengths.append(chainlengths[delta] + 1)
380 baseaddr = chainbases[delta]
381 revaddr = r.start(rev)
382 chainbases.append(baseaddr)
383 chainspans.append((revaddr - baseaddr) + size)
384 if size == 0:
385 numempty += 1
386 numemptydelta += 1
387 elif r.issnapshot(rev):
388 addsize(size, semisize)
389 numsemi += 1
390 depth = r.snapshotdepth(rev)
391 numsnapdepth[depth] += 1
392 if nad:
393 numsnapdepth_nad[depth] += 1
394 addsize(size, snapsizedepth[depth])
395 else:
396 addsize(size, deltasize)
397 if delta == rev - 1:
398 numprev += 1
399 if delta == p1:
400 nump1prev += 1
401 elif delta == p2:
402 nump2prev += 1
403 elif nad:
404 numprev_nad += 1
405 elif delta == p1:
406 nump1 += 1
407 elif delta == p2:
408 nump2 += 1
409 elif delta != nodemod.nullrev:
410 numother += 1
411 numother_nad += 1
412
413 # Obtain data on the raw chunks in the revlog.
414 if hasattr(r, '_getsegmentforrevs'):
415 segment = r._getsegmentforrevs(rev, rev)[1]
392 416 else:
393 addsize(size, deltasize)
394 if delta == rev - 1:
395 numprev += 1
396 if delta == p1:
397 nump1prev += 1
398 elif delta == p2:
399 nump2prev += 1
400 elif nad:
401 numprev_nad += 1
402 elif delta == p1:
403 nump1 += 1
404 elif delta == p2:
405 nump2 += 1
406 elif delta != nodemod.nullrev:
407 numother += 1
408 numother_nad += 1
417 segment = r._revlog._getsegmentforrevs(rev, rev)[1]
418 if segment:
419 chunktype = bytes(segment[0:1])
420 else:
421 chunktype = b'empty'
409 422
410 # Obtain data on the raw chunks in the revlog.
411 if hasattr(r, '_getsegmentforrevs'):
412 segment = r._getsegmentforrevs(rev, rev)[1]
413 else:
414 segment = r._revlog._getsegmentforrevs(rev, rev)[1]
415 if segment:
416 chunktype = bytes(segment[0:1])
417 else:
418 chunktype = b'empty'
423 if chunktype not in chunktypecounts:
424 chunktypecounts[chunktype] = 0
425 chunktypesizes[chunktype] = 0
419 426
420 if chunktype not in chunktypecounts:
421 chunktypecounts[chunktype] = 0
422 chunktypesizes[chunktype] = 0
423
424 chunktypecounts[chunktype] += 1
425 chunktypesizes[chunktype] += size
427 chunktypecounts[chunktype] += 1
428 chunktypesizes[chunktype] += size
426 429
427 430 # Adjust size min value for empty cases
428 431 for size in (datasize, fullsize, semisize, deltasize):
429 432 if size[0] is None:
430 433 size[0] = 0
431 434
432 435 numdeltas = numrevs - numfull - numempty - numsemi
433 436 numoprev = numprev - nump1prev - nump2prev - numprev_nad
434 437 num_other_ancestors = numother - numother_nad
435 438 totalrawsize = datasize[2]
436 439 datasize[2] /= numrevs
437 440 fulltotal = fullsize[2]
438 441 if numfull == 0:
439 442 fullsize[2] = 0
440 443 else:
441 444 fullsize[2] /= numfull
442 445 semitotal = semisize[2]
443 446 snaptotal = {}
444 447 if numsemi > 0:
445 448 semisize[2] /= numsemi
446 449 for depth in snapsizedepth:
447 450 snaptotal[depth] = snapsizedepth[depth][2]
448 451 snapsizedepth[depth][2] /= numsnapdepth[depth]
449 452
450 453 deltatotal = deltasize[2]
451 454 if numdeltas > 0:
452 455 deltasize[2] /= numdeltas
453 456 totalsize = fulltotal + semitotal + deltatotal
454 457 avgchainlen = sum(chainlengths) / numrevs
455 458 maxchainlen = max(chainlengths)
456 459 maxchainspan = max(chainspans)
457 460 compratio = 1
458 461 if totalsize:
459 462 compratio = totalrawsize / totalsize
460 463
461 464 basedfmtstr = b'%%%dd\n'
462 465 basepcfmtstr = b'%%%dd %s(%%5.2f%%%%)\n'
463 466
464 467 def dfmtstr(max):
465 468 return basedfmtstr % len(str(max))
466 469
467 470 def pcfmtstr(max, padding=0):
468 471 return basepcfmtstr % (len(str(max)), b' ' * padding)
469 472
470 473 def pcfmt(value, total):
471 474 if total:
472 475 return (value, 100 * float(value) / total)
473 476 else:
474 477 return value, 100.0
475 478
476 479 ui.writenoi18n(b'format : %d\n' % format)
477 480 ui.writenoi18n(b'flags : %s\n' % b', '.join(flags))
478 481
479 482 ui.write(b'\n')
480 483 fmt = pcfmtstr(totalsize)
481 484 fmt2 = dfmtstr(totalsize)
482 485 ui.writenoi18n(b'revisions : ' + fmt2 % numrevs)
483 486 ui.writenoi18n(b' merges : ' + fmt % pcfmt(nummerges, numrevs))
484 487 ui.writenoi18n(
485 488 b' normal : ' + fmt % pcfmt(numrevs - nummerges, numrevs)
486 489 )
487 490 ui.writenoi18n(b'revisions : ' + fmt2 % numrevs)
488 491 ui.writenoi18n(b' empty : ' + fmt % pcfmt(numempty, numrevs))
489 492 ui.writenoi18n(
490 493 b' text : '
491 494 + fmt % pcfmt(numemptytext, numemptytext + numemptydelta)
492 495 )
493 496 ui.writenoi18n(
494 497 b' delta : '
495 498 + fmt % pcfmt(numemptydelta, numemptytext + numemptydelta)
496 499 )
497 500 ui.writenoi18n(
498 501 b' snapshot : ' + fmt % pcfmt(numfull + numsemi, numrevs)
499 502 )
500 503 for depth in sorted(numsnapdepth):
501 504 base = b' lvl-%-3d : ' % depth
502 505 count = fmt % pcfmt(numsnapdepth[depth], numrevs)
503 506 pieces = [base, count]
504 507 if numsnapdepth_nad[depth]:
505 508 pieces[-1] = count = count[:-1] # drop the final '\n'
506 509 more = b' non-ancestor-bases: '
507 510 anc_count = fmt
508 511 anc_count %= pcfmt(numsnapdepth_nad[depth], numsnapdepth[depth])
509 512 pieces.append(more)
510 513 pieces.append(anc_count)
511 514 ui.write(b''.join(pieces))
512 515 ui.writenoi18n(b' deltas : ' + fmt % pcfmt(numdeltas, numrevs))
513 516 ui.writenoi18n(b'revision size : ' + fmt2 % totalsize)
514 517 ui.writenoi18n(
515 518 b' snapshot : ' + fmt % pcfmt(fulltotal + semitotal, totalsize)
516 519 )
517 520 for depth in sorted(numsnapdepth):
518 521 ui.write(
519 522 (b' lvl-%-3d : ' % depth)
520 523 + fmt % pcfmt(snaptotal[depth], totalsize)
521 524 )
522 525 ui.writenoi18n(b' deltas : ' + fmt % pcfmt(deltatotal, totalsize))
523 526
524 527 letters = string.ascii_letters.encode('ascii')
525 528
526 529 def fmtchunktype(chunktype):
527 530 if chunktype == b'empty':
528 531 return b' %s : ' % chunktype
529 532 elif chunktype in letters:
530 533 return b' 0x%s (%s) : ' % (nodemod.hex(chunktype), chunktype)
531 534 else:
532 535 return b' 0x%s : ' % nodemod.hex(chunktype)
533 536
534 537 ui.write(b'\n')
535 538 ui.writenoi18n(b'chunks : ' + fmt2 % numrevs)
536 539 for chunktype in sorted(chunktypecounts):
537 540 ui.write(fmtchunktype(chunktype))
538 541 ui.write(fmt % pcfmt(chunktypecounts[chunktype], numrevs))
539 542 ui.writenoi18n(b'chunks size : ' + fmt2 % totalsize)
540 543 for chunktype in sorted(chunktypecounts):
541 544 ui.write(fmtchunktype(chunktype))
542 545 ui.write(fmt % pcfmt(chunktypesizes[chunktype], totalsize))
543 546
544 547 ui.write(b'\n')
545 548 b_total = b"%d" % full_text_total_size
546 549 p_total = []
547 550 while len(b_total) > 3:
548 551 p_total.append(b_total[-3:])
549 552 b_total = b_total[:-3]
550 553 p_total.append(b_total)
551 554 p_total.reverse()
552 555 b_total = b' '.join(p_total)
553 556
554 557 ui.write(b'\n')
555 558 ui.writenoi18n(b'total-stored-content: %s bytes\n' % b_total)
556 559 ui.write(b'\n')
557 560 fmt = dfmtstr(max(avgchainlen, maxchainlen, maxchainspan, compratio))
558 561 ui.writenoi18n(b'avg chain length : ' + fmt % avgchainlen)
559 562 ui.writenoi18n(b'max chain length : ' + fmt % maxchainlen)
560 563 ui.writenoi18n(b'max chain reach : ' + fmt % maxchainspan)
561 564 ui.writenoi18n(b'compression ratio : ' + fmt % compratio)
562 565
563 566 if format > 0:
564 567 ui.write(b'\n')
565 568 ui.writenoi18n(
566 569 b'uncompressed data size (min/max/avg) : %d / %d / %d\n'
567 570 % tuple(datasize)
568 571 )
569 572 ui.writenoi18n(
570 573 b'full revision size (min/max/avg) : %d / %d / %d\n'
571 574 % tuple(fullsize)
572 575 )
573 576 ui.writenoi18n(
574 577 b'inter-snapshot size (min/max/avg) : %d / %d / %d\n'
575 578 % tuple(semisize)
576 579 )
577 580 for depth in sorted(snapsizedepth):
578 581 if depth == 0:
579 582 continue
580 583 ui.writenoi18n(
581 584 b' level-%-3d (min/max/avg) : %d / %d / %d\n'
582 585 % ((depth,) + tuple(snapsizedepth[depth]))
583 586 )
584 587 ui.writenoi18n(
585 588 b'delta size (min/max/avg) : %d / %d / %d\n'
586 589 % tuple(deltasize)
587 590 )
588 591
589 592 if numdeltas > 0:
590 593 ui.write(b'\n')
591 594 fmt = pcfmtstr(numdeltas)
592 595 fmt2 = pcfmtstr(numdeltas, 4)
593 596 ui.writenoi18n(
594 597 b'deltas against prev : ' + fmt % pcfmt(numprev, numdeltas)
595 598 )
596 599 if numprev > 0:
597 600 ui.writenoi18n(
598 601 b' where prev = p1 : ' + fmt2 % pcfmt(nump1prev, numprev)
599 602 )
600 603 ui.writenoi18n(
601 604 b' where prev = p2 : ' + fmt2 % pcfmt(nump2prev, numprev)
602 605 )
603 606 ui.writenoi18n(
604 607 b' other-ancestor : ' + fmt2 % pcfmt(numoprev, numprev)
605 608 )
606 609 ui.writenoi18n(
607 610 b' unrelated : ' + fmt2 % pcfmt(numoprev, numprev)
608 611 )
609 612 if gdelta:
610 613 ui.writenoi18n(
611 614 b'deltas against p1 : ' + fmt % pcfmt(nump1, numdeltas)
612 615 )
613 616 ui.writenoi18n(
614 617 b'deltas against p2 : ' + fmt % pcfmt(nump2, numdeltas)
615 618 )
616 619 ui.writenoi18n(
617 620 b'deltas against ancs : '
618 621 + fmt % pcfmt(num_other_ancestors, numdeltas)
619 622 )
620 623 ui.writenoi18n(
621 624 b'deltas against other : '
622 625 + fmt % pcfmt(numother_nad, numdeltas)
623 626 )
624 627
625 628
626 629 def debug_delta_find(ui, revlog, rev, base_rev=nodemod.nullrev):
627 630 """display the search process for a delta"""
628 631 deltacomputer = deltautil.deltacomputer(
629 632 revlog,
630 633 write_debug=ui.write,
631 634 debug_search=not ui.quiet,
632 635 )
633 636
634 637 node = revlog.node(rev)
635 638 p1r, p2r = revlog.parentrevs(rev)
636 639 p1 = revlog.node(p1r)
637 640 p2 = revlog.node(p2r)
638 641 full_text = revlog.revision(rev)
639 642 btext = [full_text]
640 643 textlen = len(btext[0])
641 644 cachedelta = None
642 645 flags = revlog.flags(rev)
643 646
644 647 if base_rev != nodemod.nullrev:
645 648 base_text = revlog.revision(base_rev)
646 649 delta = mdiff.textdiff(base_text, full_text)
647 650
648 651 cachedelta = (base_rev, delta, constants.DELTA_BASE_REUSE_TRY)
649 652 btext = [None]
650 653
651 654 revinfo = revlogutils.revisioninfo(
652 655 node,
653 656 p1,
654 657 p2,
655 658 btext,
656 659 textlen,
657 660 cachedelta,
658 661 flags,
659 662 )
660 663
661 664 fh = revlog._datafp()
662 665 deltacomputer.finddeltainfo(revinfo, fh, target_rev=rev)
663 666
664 667
665 668 def debug_revlog_stats(
666 669 repo, fm, changelog: bool, manifest: bool, filelogs: bool
667 670 ):
668 671 """Format revlog statistics for debugging purposes
669 672
670 673 fm: the output formatter.
671 674 """
672 675 fm.plain(b'rev-count data-size inl type target \n')
673 676
674 677 revlog_entries = [e for e in repo.store.walk() if e.is_revlog]
675 678 revlog_entries.sort(key=lambda e: (e.revlog_type, e.target_id))
676 679
677 680 for entry in revlog_entries:
678 681 if not changelog and entry.is_changelog:
679 682 continue
680 683 elif not manifest and entry.is_manifestlog:
681 684 continue
682 685 elif not filelogs and entry.is_filelog:
683 686 continue
684 687 rlog = entry.get_revlog_instance(repo).get_revlog()
685 688 fm.startitem()
686 689 nb_rev = len(rlog)
687 690 inline = rlog._inline
688 691 data_size = rlog._get_data_offset(nb_rev - 1)
689 692
690 693 target = rlog.target
691 694 revlog_type = b'unknown'
692 695 revlog_target = b''
693 696 if target[0] == constants.KIND_CHANGELOG:
694 697 revlog_type = b'changelog'
695 698 elif target[0] == constants.KIND_MANIFESTLOG:
696 699 revlog_type = b'manifest'
697 700 revlog_target = target[1]
698 701 elif target[0] == constants.KIND_FILELOG:
699 702 revlog_type = b'file'
700 703 revlog_target = target[1]
701 704
702 705 fm.write(b'revlog.rev-count', b'%9d', nb_rev)
703 706 fm.write(b'revlog.data-size', b'%12d', data_size)
704 707
705 708 fm.write(b'revlog.inline', b' %-3s', b'yes' if inline else b'no')
706 709 fm.write(b'revlog.type', b' %-9s', revlog_type)
707 710 fm.write(b'revlog.target', b' %s', revlog_target)
708 711
709 712 fm.plain(b'\n')
General Comments 0
You need to be logged in to leave comments. Login now