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