Mercurial > hg
comparison tests/test-tags.t @ 24735:07200e3332a1
tags: extract .hgtags filenodes cache to a standalone file
Resolution of .hgtags filenodes values has historically been a
performance pain point for large repositories, where reading individual
manifests can take over 100ms. Multiplied by hundreds or even thousands
of heads and resolving .hgtags filenodes becomes a performance issue.
This patch establishes a standalone cache file holding the .hgtags
filenodes for each changeset. After this patch, the .hgtags filenode
for any particular changeset should only have to be computed once
during the lifetime of the repository.
The introduced hgtagsfnodes1 cache file is modeled after the rev branch
cache: the cache is effectively an array of entries consisting of a
changeset fragment and the filenode for a revision. The file grows in
proportion to the length of the repository (24 bytes per changeset) and
is truncated when the repository is stripped. The file is not written
unless tag info is requested and tags have changed since last time.
This patch partially addresses issue4550. Future patches will split the
"tags" cache file into per-filter files and will refactor the cache
format to not capture the .hgtags fnodes, as these are now stored in
the hgtagsfnodes1 cache. This patch is capable of standing alone. We
should not have to wait on the tags cache filter split and format
refactor for this patch to land.
author | Gregory Szorc <gregory.szorc@gmail.com> |
---|---|
date | Wed, 15 Apr 2015 17:42:38 -0400 |
parents | 5150b2b5b345 |
children | b061a2049662 |
comparison
equal
deleted
inserted
replaced
24734:fb6cb1b82f4f | 24735:07200e3332a1 |
---|---|
10 | 10 |
11 $ cacheexists() { | 11 $ cacheexists() { |
12 > [ -f .hg/cache/tags ] && echo "tag cache exists" || echo "no tag cache" | 12 > [ -f .hg/cache/tags ] && echo "tag cache exists" || echo "no tag cache" |
13 > } | 13 > } |
14 | 14 |
15 $ fnodescacheexists() { | |
16 > [ -f .hg/cache/hgtagsfnodes1 ] && echo "fnodes cache exists" || echo "no fnodes cache" | |
17 > } | |
18 | |
15 $ dumptags() { | 19 $ dumptags() { |
16 > rev=$1 | 20 > rev=$1 |
17 > echo "rev $rev: .hgtags:" | 21 > echo "rev $rev: .hgtags:" |
18 > hg cat -r$rev .hgtags | 22 > hg cat -r$rev .hgtags |
19 > } | 23 > } |
26 | 30 |
27 $ hg init t | 31 $ hg init t |
28 $ cd t | 32 $ cd t |
29 $ cacheexists | 33 $ cacheexists |
30 no tag cache | 34 no tag cache |
35 $ fnodescacheexists | |
36 no fnodes cache | |
31 $ hg id | 37 $ hg id |
32 000000000000 tip | 38 000000000000 tip |
33 $ cacheexists | 39 $ cacheexists |
34 no tag cache | 40 no tag cache |
41 $ fnodescacheexists | |
42 no fnodes cache | |
35 $ echo a > a | 43 $ echo a > a |
36 $ hg add a | 44 $ hg add a |
37 $ hg commit -m "test" | 45 $ hg commit -m "test" |
38 $ hg co | 46 $ hg co |
39 0 files updated, 0 files merged, 0 files removed, 0 files unresolved | 47 0 files updated, 0 files merged, 0 files removed, 0 files unresolved |
40 $ hg identify | 48 $ hg identify |
41 acb14030fe0a tip | 49 acb14030fe0a tip |
42 $ cacheexists | 50 $ cacheexists |
43 tag cache exists | 51 tag cache exists |
52 No fnodes cache because .hgtags file doesn't exist | |
53 (this is an implementation detail) | |
54 $ fnodescacheexists | |
55 no fnodes cache | |
44 | 56 |
45 Try corrupting the cache | 57 Try corrupting the cache |
46 | 58 |
47 $ printf 'a b' > .hg/cache/tags | 59 $ printf 'a b' > .hg/cache/tags |
48 $ hg identify | 60 $ hg identify |
49 acb14030fe0a tip | 61 acb14030fe0a tip |
50 $ cacheexists | 62 $ cacheexists |
51 tag cache exists | 63 tag cache exists |
64 $ fnodescacheexists | |
65 no fnodes cache | |
52 $ hg identify | 66 $ hg identify |
53 acb14030fe0a tip | 67 acb14030fe0a tip |
54 | 68 |
55 Create local tag with long name: | 69 Create local tag with long name: |
56 | 70 |
72 tip 1:b9154636be93 | 86 tip 1:b9154636be93 |
73 first 0:acb14030fe0a | 87 first 0:acb14030fe0a |
74 $ hg identify | 88 $ hg identify |
75 b9154636be93 tip | 89 b9154636be93 tip |
76 | 90 |
91 We should have a fnodes cache now that we have a real tag | |
92 The cache should have an empty entry for rev 0 and a valid entry for rev 1. | |
93 | |
94 | |
95 $ fnodescacheexists | |
96 fnodes cache exists | |
97 $ f --size --hexdump .hg/cache/hgtagsfnodes1 | |
98 .hg/cache/hgtagsfnodes1: size=48 | |
99 0000: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................| | |
100 0010: ff ff ff ff ff ff ff ff b9 15 46 36 26 b7 b4 a7 |..........F6&...| | |
101 0020: 73 e0 9e e3 c5 2f 51 0e 19 e0 5e 1f f9 66 d8 59 |s..../Q...^..f.Y| | |
102 | |
77 Repeat with cold tag cache: | 103 Repeat with cold tag cache: |
78 | 104 |
79 $ rm -f .hg/cache/tags | 105 $ rm -f .hg/cache/tags .hg/cache/hgtagsfnodes1 |
80 $ hg identify | 106 $ hg identify |
81 b9154636be93 tip | 107 b9154636be93 tip |
82 | 108 |
109 $ fnodescacheexists | |
110 fnodes cache exists | |
111 $ f --size --hexdump .hg/cache/hgtagsfnodes1 | |
112 .hg/cache/hgtagsfnodes1: size=48 | |
113 0000: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................| | |
114 0010: ff ff ff ff ff ff ff ff b9 15 46 36 26 b7 b4 a7 |..........F6&...| | |
115 0020: 73 e0 9e e3 c5 2f 51 0e 19 e0 5e 1f f9 66 d8 59 |s..../Q...^..f.Y| | |
116 | |
83 And again, but now unable to write tag cache: | 117 And again, but now unable to write tag cache: |
84 | 118 |
85 #if unix-permissions | 119 #if unix-permissions |
86 $ rm -f .hg/cache/tags | 120 $ rm -f .hg/cache/tags .hg/cache/hgtagsfnodes1 |
87 $ chmod 555 .hg | 121 $ chmod 555 .hg/cache |
88 $ hg identify | 122 $ hg identify |
89 b9154636be93 tip | 123 b9154636be93 tip |
90 $ chmod 755 .hg | 124 $ chmod 755 .hg/cache |
91 #endif | 125 #endif |
92 | 126 |
93 Tag cache debug info written to blackbox log | 127 Tag cache debug info written to blackbox log |
94 | 128 |
95 $ rm -f .hg/cache/tags | 129 $ rm -f .hg/cache/tags .hg/cache/hgtagsfnodes1 |
96 $ hg identify | 130 $ hg identify |
97 b9154636be93 tip | 131 b9154636be93 tip |
98 $ hg blackbox -l 4 | 132 $ hg blackbox -l 5 |
99 1970/01/01 00:00:00 bob> identify | 133 1970/01/01 00:00:00 bob> identify |
100 1970/01/01 00:00:00 bob> resolved 1 tags cache entries from 1 manifests in ?.???? seconds (glob) | 134 1970/01/01 00:00:00 bob> writing 48 bytes to cache/hgtagsfnodes1 |
135 1970/01/01 00:00:00 bob> 0/1 cache hits/lookups in * seconds (glob) | |
101 1970/01/01 00:00:00 bob> writing tags cache file with 1 heads and 1 tags | 136 1970/01/01 00:00:00 bob> writing tags cache file with 1 heads and 1 tags |
102 1970/01/01 00:00:00 bob> identify exited 0 after ?.?? seconds (glob) | 137 1970/01/01 00:00:00 bob> identify exited 0 after ?.?? seconds (glob) |
103 | 138 |
139 Failure to acquire lock results in no write | |
140 | |
141 $ rm -f .hg/cache/tags .hg/cache/hgtagsfnodes1 | |
142 $ echo 'foo:1' > .hg/wlock | |
143 $ hg identify | |
144 b9154636be93 tip | |
145 $ hg blackbox -l 5 | |
146 1970/01/01 00:00:00 bob> identify | |
147 1970/01/01 00:00:00 bob> not writing .hg/cache/hgtagsfnodes1 because lock held | |
148 1970/01/01 00:00:00 bob> 0/1 cache hits/lookups in * seconds (glob) | |
149 1970/01/01 00:00:00 bob> writing tags cache file with 1 heads and 1 tags | |
150 1970/01/01 00:00:00 bob> identify exited 0 after * seconds (glob) | |
151 | |
152 $ fnodescacheexists | |
153 no fnodes cache | |
154 | |
155 $ rm .hg/wlock | |
156 | |
157 $ rm -f .hg/cache/tags .hg/cache/hgtagsfnodes1 | |
158 $ hg identify | |
159 b9154636be93 tip | |
104 | 160 |
105 Create a branch: | 161 Create a branch: |
106 | 162 |
107 $ echo bb > a | 163 $ echo bb > a |
108 $ hg status | 164 $ hg status |
119 M a | 175 M a |
120 $ echo 1 > b | 176 $ echo 1 > b |
121 $ hg add b | 177 $ hg add b |
122 $ hg commit -m "branch" | 178 $ hg commit -m "branch" |
123 created new head | 179 created new head |
180 | |
181 Creating a new commit shouldn't append the .hgtags fnodes cache until | |
182 tags info is accessed | |
183 | |
184 $ f --size --hexdump .hg/cache/hgtagsfnodes1 | |
185 .hg/cache/hgtagsfnodes1: size=48 | |
186 0000: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................| | |
187 0010: ff ff ff ff ff ff ff ff b9 15 46 36 26 b7 b4 a7 |..........F6&...| | |
188 0020: 73 e0 9e e3 c5 2f 51 0e 19 e0 5e 1f f9 66 d8 59 |s..../Q...^..f.Y| | |
189 | |
124 $ hg id | 190 $ hg id |
125 c8edf04160c7 tip | 191 c8edf04160c7 tip |
192 | |
193 First 4 bytes of record 3 are changeset fragment | |
194 | |
195 $ f --size --hexdump .hg/cache/hgtagsfnodes1 | |
196 .hg/cache/hgtagsfnodes1: size=72 | |
197 0000: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................| | |
198 0010: ff ff ff ff ff ff ff ff b9 15 46 36 26 b7 b4 a7 |..........F6&...| | |
199 0020: 73 e0 9e e3 c5 2f 51 0e 19 e0 5e 1f f9 66 d8 59 |s..../Q...^..f.Y| | |
200 0030: c8 ed f0 41 00 00 00 00 00 00 00 00 00 00 00 00 |...A............| | |
201 0040: 00 00 00 00 00 00 00 00 |........| | |
126 | 202 |
127 Merge the two heads: | 203 Merge the two heads: |
128 | 204 |
129 $ hg merge 1 | 205 $ hg merge 1 |
130 1 files updated, 0 files merged, 0 files removed, 0 files unresolved | 206 1 files updated, 0 files merged, 0 files removed, 0 files unresolved |
241 2 7a94127795a33c10a370c93f731fd9fea0b79af6 0c04f2a8af31de17fab7422878ee5a2dadbc943d | 317 2 7a94127795a33c10a370c93f731fd9fea0b79af6 0c04f2a8af31de17fab7422878ee5a2dadbc943d |
242 | 318 |
243 bbd179dfa0a71671c253b3ae0aa1513b60d199fa bar | 319 bbd179dfa0a71671c253b3ae0aa1513b60d199fa bar |
244 bbd179dfa0a71671c253b3ae0aa1513b60d199fa bar | 320 bbd179dfa0a71671c253b3ae0aa1513b60d199fa bar |
245 78391a272241d70354aa14c874552cad6b51bb42 bar | 321 78391a272241d70354aa14c874552cad6b51bb42 bar |
322 | |
323 $ f --size --hexdump .hg/cache/hgtagsfnodes1 | |
324 .hg/cache/hgtagsfnodes1: size=120 | |
325 0000: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................| | |
326 0010: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................| | |
327 0020: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................| | |
328 0030: 7a 94 12 77 0c 04 f2 a8 af 31 de 17 fa b7 42 28 |z..w.....1....B(| | |
329 0040: 78 ee 5a 2d ad bc 94 3d 6f a4 50 21 7d 3b 71 8c |x.Z-...=o.P!};q.| | |
330 0050: 96 4e f3 7b 89 e5 50 eb da fd 57 89 e7 6c e1 b0 |.N.{..P...W..l..| | |
331 0060: 0c 19 2d 7d 0c 04 f2 a8 af 31 de 17 fa b7 42 28 |..-}.....1....B(| | |
332 0070: 78 ee 5a 2d ad bc 94 3d |x.Z-...=| | |
333 | |
334 Corrupt the .hgtags fnodes cache | |
335 Extra junk data at the end should get overwritten on next cache update | |
336 | |
337 $ echo extra >> .hg/cache/hgtagsfnodes1 | |
338 $ echo dummy1 > foo | |
339 $ hg commit -m throwaway1 | |
340 | |
341 $ hg tags | |
342 tip 5:8dbfe60eff30 | |
343 bar 1:78391a272241 | |
344 | |
345 $ hg blackbox -l 5 | |
346 1970/01/01 00:00:00 bob> tags | |
347 1970/01/01 00:00:00 bob> writing 24 bytes to cache/hgtagsfnodes1 | |
348 1970/01/01 00:00:00 bob> 0/1 cache hits/lookups in * seconds (glob) | |
349 1970/01/01 00:00:00 bob> writing tags cache file with 3 heads and 1 tags | |
350 1970/01/01 00:00:00 bob> tags exited 0 after * seconds (glob) | |
351 | |
352 #if unix-permissions no-root | |
353 Errors writing to .hgtags fnodes cache are silently ignored | |
354 | |
355 $ echo dummy2 > foo | |
356 $ hg commit -m throwaway2 | |
357 | |
358 $ chmod a-w .hg/cache/hgtagsfnodes1 | |
359 $ rm -f .hg/cache/tags | |
360 | |
361 $ hg tags | |
362 tip 6:b968051b5cf3 | |
363 bar 1:78391a272241 | |
364 | |
365 $ hg blackbox -l 5 | |
366 1970/01/01 00:00:00 bob> tags | |
367 1970/01/01 00:00:00 bob> couldn't write cache/hgtagsfnodes1: [Errno 13] Permission denied: '$TESTTMP/t2/.hg/cache/hgtagsfnodes1' | |
368 1970/01/01 00:00:00 bob> 2/3 cache hits/lookups in * seconds (glob) | |
369 1970/01/01 00:00:00 bob> writing tags cache file with 3 heads and 1 tags | |
370 1970/01/01 00:00:00 bob> tags exited 0 after * seconds (glob) | |
371 | |
372 $ chmod a+w .hg/cache/hgtagsfnodes1 | |
373 #endif | |
374 | |
375 $ rm -f .hg/cache/tags | |
376 $ hg tags | |
377 tip 6:b968051b5cf3 | |
378 bar 1:78391a272241 | |
379 | |
380 $ hg blackbox -l 5 | |
381 1970/01/01 00:00:00 bob> tags | |
382 1970/01/01 00:00:00 bob> writing 24 bytes to cache/hgtagsfnodes1 | |
383 1970/01/01 00:00:00 bob> 2/3 cache hits/lookups in * seconds (glob) | |
384 1970/01/01 00:00:00 bob> writing tags cache file with 3 heads and 1 tags | |
385 1970/01/01 00:00:00 bob> tags exited 0 after * seconds (glob) | |
386 | |
387 $ f --size .hg/cache/hgtagsfnodes1 | |
388 .hg/cache/hgtagsfnodes1: size=168 | |
389 | |
390 Stripping doesn't truncate the tags cache until new data is available | |
391 | |
392 $ hg -q --config extensions.strip= strip -r 5 --no-backup | |
393 $ hg tags | |
394 tip 4:0c192d7d5e6b | |
395 bar 1:78391a272241 | |
396 | |
397 $ hg blackbox -l 4 | |
398 1970/01/01 00:00:00 bob> tags | |
399 1970/01/01 00:00:00 bob> 1/1 cache hits/lookups in * seconds (glob) | |
400 1970/01/01 00:00:00 bob> writing tags cache file with 3 heads and 1 tags | |
401 1970/01/01 00:00:00 bob> tags exited 0 after * seconds (glob) | |
402 | |
403 $ f --size .hg/cache/hgtagsfnodes1 | |
404 .hg/cache/hgtagsfnodes1: size=168 | |
405 | |
406 $ echo dummy > foo | |
407 $ hg commit -m throwaway3 | |
408 | |
409 $ hg tags | |
410 tip 5:035f65efb448 | |
411 bar 1:78391a272241 | |
412 | |
413 $ hg blackbox -l 5 | |
414 1970/01/01 00:00:00 bob> tags | |
415 1970/01/01 00:00:00 bob> writing 24 bytes to cache/hgtagsfnodes1 | |
416 1970/01/01 00:00:00 bob> 0/1 cache hits/lookups in * seconds (glob) | |
417 1970/01/01 00:00:00 bob> writing tags cache file with 3 heads and 1 tags | |
418 1970/01/01 00:00:00 bob> tags exited 0 after * seconds (glob) | |
419 $ f --size .hg/cache/hgtagsfnodes1 | |
420 .hg/cache/hgtagsfnodes1: size=144 | |
421 | |
422 $ hg -q --config extensions.strip= strip -r 5 --no-backup | |
246 | 423 |
247 Test tag removal: | 424 Test tag removal: |
248 | 425 |
249 $ hg tag --remove bar # rev 5 | 426 $ hg tag --remove bar # rev 5 |
250 $ hg tip -vp | 427 $ hg tip -vp |