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