##// END OF EJS Templates
store: also gather files per revlog in `topfiles`...
marmoute -
r51374:b08243db default
parent child Browse files
Show More
@@ -1,1004 +1,1031 b''
1 # store.py - repository store handling for Mercurial
1 # store.py - repository store handling for Mercurial
2 #
2 #
3 # Copyright 2008 Olivia Mackall <olivia@selenic.com>
3 # Copyright 2008 Olivia Mackall <olivia@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 import collections
8 import collections
9 import functools
9 import functools
10 import os
10 import os
11 import re
11 import re
12 import stat
12 import stat
13 from typing import Generator
13 from typing import Generator
14
14
15 from .i18n import _
15 from .i18n import _
16 from .pycompat import getattr
16 from .pycompat import getattr
17 from .thirdparty import attr
17 from .thirdparty import attr
18 from .node import hex
18 from .node import hex
19 from . import (
19 from . import (
20 changelog,
20 changelog,
21 error,
21 error,
22 manifest,
22 manifest,
23 policy,
23 policy,
24 pycompat,
24 pycompat,
25 util,
25 util,
26 vfs as vfsmod,
26 vfs as vfsmod,
27 )
27 )
28 from .utils import hashutil
28 from .utils import hashutil
29
29
30 parsers = policy.importmod('parsers')
30 parsers = policy.importmod('parsers')
31 # how much bytes should be read from fncache in one read
31 # how much bytes should be read from fncache in one read
32 # It is done to prevent loading large fncache files into memory
32 # It is done to prevent loading large fncache files into memory
33 fncache_chunksize = 10 ** 6
33 fncache_chunksize = 10 ** 6
34
34
35
35
36 def _matchtrackedpath(path, matcher):
36 def _matchtrackedpath(path, matcher):
37 """parses a fncache entry and returns whether the entry is tracking a path
37 """parses a fncache entry and returns whether the entry is tracking a path
38 matched by matcher or not.
38 matched by matcher or not.
39
39
40 If matcher is None, returns True"""
40 If matcher is None, returns True"""
41
41
42 if matcher is None:
42 if matcher is None:
43 return True
43 return True
44 path = decodedir(path)
44 path = decodedir(path)
45 if path.startswith(b'data/'):
45 if path.startswith(b'data/'):
46 return matcher(path[len(b'data/') : -len(b'.i')])
46 return matcher(path[len(b'data/') : -len(b'.i')])
47 elif path.startswith(b'meta/'):
47 elif path.startswith(b'meta/'):
48 return matcher.visitdir(path[len(b'meta/') : -len(b'/00manifest.i')])
48 return matcher.visitdir(path[len(b'meta/') : -len(b'/00manifest.i')])
49
49
50 raise error.ProgrammingError(b"cannot decode path %s" % path)
50 raise error.ProgrammingError(b"cannot decode path %s" % path)
51
51
52
52
53 # This avoids a collision between a file named foo and a dir named
53 # This avoids a collision between a file named foo and a dir named
54 # foo.i or foo.d
54 # foo.i or foo.d
55 def _encodedir(path):
55 def _encodedir(path):
56 """
56 """
57 >>> _encodedir(b'data/foo.i')
57 >>> _encodedir(b'data/foo.i')
58 'data/foo.i'
58 'data/foo.i'
59 >>> _encodedir(b'data/foo.i/bla.i')
59 >>> _encodedir(b'data/foo.i/bla.i')
60 'data/foo.i.hg/bla.i'
60 'data/foo.i.hg/bla.i'
61 >>> _encodedir(b'data/foo.i.hg/bla.i')
61 >>> _encodedir(b'data/foo.i.hg/bla.i')
62 'data/foo.i.hg.hg/bla.i'
62 'data/foo.i.hg.hg/bla.i'
63 >>> _encodedir(b'data/foo.i\\ndata/foo.i/bla.i\\ndata/foo.i.hg/bla.i\\n')
63 >>> _encodedir(b'data/foo.i\\ndata/foo.i/bla.i\\ndata/foo.i.hg/bla.i\\n')
64 'data/foo.i\\ndata/foo.i.hg/bla.i\\ndata/foo.i.hg.hg/bla.i\\n'
64 'data/foo.i\\ndata/foo.i.hg/bla.i\\ndata/foo.i.hg.hg/bla.i\\n'
65 """
65 """
66 return (
66 return (
67 path.replace(b".hg/", b".hg.hg/")
67 path.replace(b".hg/", b".hg.hg/")
68 .replace(b".i/", b".i.hg/")
68 .replace(b".i/", b".i.hg/")
69 .replace(b".d/", b".d.hg/")
69 .replace(b".d/", b".d.hg/")
70 )
70 )
71
71
72
72
73 encodedir = getattr(parsers, 'encodedir', _encodedir)
73 encodedir = getattr(parsers, 'encodedir', _encodedir)
74
74
75
75
76 def decodedir(path):
76 def decodedir(path):
77 """
77 """
78 >>> decodedir(b'data/foo.i')
78 >>> decodedir(b'data/foo.i')
79 'data/foo.i'
79 'data/foo.i'
80 >>> decodedir(b'data/foo.i.hg/bla.i')
80 >>> decodedir(b'data/foo.i.hg/bla.i')
81 'data/foo.i/bla.i'
81 'data/foo.i/bla.i'
82 >>> decodedir(b'data/foo.i.hg.hg/bla.i')
82 >>> decodedir(b'data/foo.i.hg.hg/bla.i')
83 'data/foo.i.hg/bla.i'
83 'data/foo.i.hg/bla.i'
84 """
84 """
85 if b".hg/" not in path:
85 if b".hg/" not in path:
86 return path
86 return path
87 return (
87 return (
88 path.replace(b".d.hg/", b".d/")
88 path.replace(b".d.hg/", b".d/")
89 .replace(b".i.hg/", b".i/")
89 .replace(b".i.hg/", b".i/")
90 .replace(b".hg.hg/", b".hg/")
90 .replace(b".hg.hg/", b".hg/")
91 )
91 )
92
92
93
93
94 def _reserved():
94 def _reserved():
95 """characters that are problematic for filesystems
95 """characters that are problematic for filesystems
96
96
97 * ascii escapes (0..31)
97 * ascii escapes (0..31)
98 * ascii hi (126..255)
98 * ascii hi (126..255)
99 * windows specials
99 * windows specials
100
100
101 these characters will be escaped by encodefunctions
101 these characters will be escaped by encodefunctions
102 """
102 """
103 winreserved = [ord(x) for x in u'\\:*?"<>|']
103 winreserved = [ord(x) for x in u'\\:*?"<>|']
104 for x in range(32):
104 for x in range(32):
105 yield x
105 yield x
106 for x in range(126, 256):
106 for x in range(126, 256):
107 yield x
107 yield x
108 for x in winreserved:
108 for x in winreserved:
109 yield x
109 yield x
110
110
111
111
112 def _buildencodefun():
112 def _buildencodefun():
113 """
113 """
114 >>> enc, dec = _buildencodefun()
114 >>> enc, dec = _buildencodefun()
115
115
116 >>> enc(b'nothing/special.txt')
116 >>> enc(b'nothing/special.txt')
117 'nothing/special.txt'
117 'nothing/special.txt'
118 >>> dec(b'nothing/special.txt')
118 >>> dec(b'nothing/special.txt')
119 'nothing/special.txt'
119 'nothing/special.txt'
120
120
121 >>> enc(b'HELLO')
121 >>> enc(b'HELLO')
122 '_h_e_l_l_o'
122 '_h_e_l_l_o'
123 >>> dec(b'_h_e_l_l_o')
123 >>> dec(b'_h_e_l_l_o')
124 'HELLO'
124 'HELLO'
125
125
126 >>> enc(b'hello:world?')
126 >>> enc(b'hello:world?')
127 'hello~3aworld~3f'
127 'hello~3aworld~3f'
128 >>> dec(b'hello~3aworld~3f')
128 >>> dec(b'hello~3aworld~3f')
129 'hello:world?'
129 'hello:world?'
130
130
131 >>> enc(b'the\\x07quick\\xADshot')
131 >>> enc(b'the\\x07quick\\xADshot')
132 'the~07quick~adshot'
132 'the~07quick~adshot'
133 >>> dec(b'the~07quick~adshot')
133 >>> dec(b'the~07quick~adshot')
134 'the\\x07quick\\xadshot'
134 'the\\x07quick\\xadshot'
135 """
135 """
136 e = b'_'
136 e = b'_'
137 xchr = pycompat.bytechr
137 xchr = pycompat.bytechr
138 asciistr = list(map(xchr, range(127)))
138 asciistr = list(map(xchr, range(127)))
139 capitals = list(range(ord(b"A"), ord(b"Z") + 1))
139 capitals = list(range(ord(b"A"), ord(b"Z") + 1))
140
140
141 cmap = {x: x for x in asciistr}
141 cmap = {x: x for x in asciistr}
142 for x in _reserved():
142 for x in _reserved():
143 cmap[xchr(x)] = b"~%02x" % x
143 cmap[xchr(x)] = b"~%02x" % x
144 for x in capitals + [ord(e)]:
144 for x in capitals + [ord(e)]:
145 cmap[xchr(x)] = e + xchr(x).lower()
145 cmap[xchr(x)] = e + xchr(x).lower()
146
146
147 dmap = {}
147 dmap = {}
148 for k, v in cmap.items():
148 for k, v in cmap.items():
149 dmap[v] = k
149 dmap[v] = k
150
150
151 def decode(s):
151 def decode(s):
152 i = 0
152 i = 0
153 while i < len(s):
153 while i < len(s):
154 for l in range(1, 4):
154 for l in range(1, 4):
155 try:
155 try:
156 yield dmap[s[i : i + l]]
156 yield dmap[s[i : i + l]]
157 i += l
157 i += l
158 break
158 break
159 except KeyError:
159 except KeyError:
160 pass
160 pass
161 else:
161 else:
162 raise KeyError
162 raise KeyError
163
163
164 return (
164 return (
165 lambda s: b''.join([cmap[s[c : c + 1]] for c in range(len(s))]),
165 lambda s: b''.join([cmap[s[c : c + 1]] for c in range(len(s))]),
166 lambda s: b''.join(list(decode(s))),
166 lambda s: b''.join(list(decode(s))),
167 )
167 )
168
168
169
169
170 _encodefname, _decodefname = _buildencodefun()
170 _encodefname, _decodefname = _buildencodefun()
171
171
172
172
173 def encodefilename(s):
173 def encodefilename(s):
174 """
174 """
175 >>> encodefilename(b'foo.i/bar.d/bla.hg/hi:world?/HELLO')
175 >>> encodefilename(b'foo.i/bar.d/bla.hg/hi:world?/HELLO')
176 'foo.i.hg/bar.d.hg/bla.hg.hg/hi~3aworld~3f/_h_e_l_l_o'
176 'foo.i.hg/bar.d.hg/bla.hg.hg/hi~3aworld~3f/_h_e_l_l_o'
177 """
177 """
178 return _encodefname(encodedir(s))
178 return _encodefname(encodedir(s))
179
179
180
180
181 def decodefilename(s):
181 def decodefilename(s):
182 """
182 """
183 >>> decodefilename(b'foo.i.hg/bar.d.hg/bla.hg.hg/hi~3aworld~3f/_h_e_l_l_o')
183 >>> decodefilename(b'foo.i.hg/bar.d.hg/bla.hg.hg/hi~3aworld~3f/_h_e_l_l_o')
184 'foo.i/bar.d/bla.hg/hi:world?/HELLO'
184 'foo.i/bar.d/bla.hg/hi:world?/HELLO'
185 """
185 """
186 return decodedir(_decodefname(s))
186 return decodedir(_decodefname(s))
187
187
188
188
189 def _buildlowerencodefun():
189 def _buildlowerencodefun():
190 """
190 """
191 >>> f = _buildlowerencodefun()
191 >>> f = _buildlowerencodefun()
192 >>> f(b'nothing/special.txt')
192 >>> f(b'nothing/special.txt')
193 'nothing/special.txt'
193 'nothing/special.txt'
194 >>> f(b'HELLO')
194 >>> f(b'HELLO')
195 'hello'
195 'hello'
196 >>> f(b'hello:world?')
196 >>> f(b'hello:world?')
197 'hello~3aworld~3f'
197 'hello~3aworld~3f'
198 >>> f(b'the\\x07quick\\xADshot')
198 >>> f(b'the\\x07quick\\xADshot')
199 'the~07quick~adshot'
199 'the~07quick~adshot'
200 """
200 """
201 xchr = pycompat.bytechr
201 xchr = pycompat.bytechr
202 cmap = {xchr(x): xchr(x) for x in range(127)}
202 cmap = {xchr(x): xchr(x) for x in range(127)}
203 for x in _reserved():
203 for x in _reserved():
204 cmap[xchr(x)] = b"~%02x" % x
204 cmap[xchr(x)] = b"~%02x" % x
205 for x in range(ord(b"A"), ord(b"Z") + 1):
205 for x in range(ord(b"A"), ord(b"Z") + 1):
206 cmap[xchr(x)] = xchr(x).lower()
206 cmap[xchr(x)] = xchr(x).lower()
207
207
208 def lowerencode(s):
208 def lowerencode(s):
209 return b"".join([cmap[c] for c in pycompat.iterbytestr(s)])
209 return b"".join([cmap[c] for c in pycompat.iterbytestr(s)])
210
210
211 return lowerencode
211 return lowerencode
212
212
213
213
214 lowerencode = getattr(parsers, 'lowerencode', None) or _buildlowerencodefun()
214 lowerencode = getattr(parsers, 'lowerencode', None) or _buildlowerencodefun()
215
215
216 # Windows reserved names: con, prn, aux, nul, com1..com9, lpt1..lpt9
216 # Windows reserved names: con, prn, aux, nul, com1..com9, lpt1..lpt9
217 _winres3 = (b'aux', b'con', b'prn', b'nul') # length 3
217 _winres3 = (b'aux', b'con', b'prn', b'nul') # length 3
218 _winres4 = (b'com', b'lpt') # length 4 (with trailing 1..9)
218 _winres4 = (b'com', b'lpt') # length 4 (with trailing 1..9)
219
219
220
220
221 def _auxencode(path, dotencode):
221 def _auxencode(path, dotencode):
222 """
222 """
223 Encodes filenames containing names reserved by Windows or which end in
223 Encodes filenames containing names reserved by Windows or which end in
224 period or space. Does not touch other single reserved characters c.
224 period or space. Does not touch other single reserved characters c.
225 Specifically, c in '\\:*?"<>|' or ord(c) <= 31 are *not* encoded here.
225 Specifically, c in '\\:*?"<>|' or ord(c) <= 31 are *not* encoded here.
226 Additionally encodes space or period at the beginning, if dotencode is
226 Additionally encodes space or period at the beginning, if dotencode is
227 True. Parameter path is assumed to be all lowercase.
227 True. Parameter path is assumed to be all lowercase.
228 A segment only needs encoding if a reserved name appears as a
228 A segment only needs encoding if a reserved name appears as a
229 basename (e.g. "aux", "aux.foo"). A directory or file named "foo.aux"
229 basename (e.g. "aux", "aux.foo"). A directory or file named "foo.aux"
230 doesn't need encoding.
230 doesn't need encoding.
231
231
232 >>> s = b'.foo/aux.txt/txt.aux/con/prn/nul/foo.'
232 >>> s = b'.foo/aux.txt/txt.aux/con/prn/nul/foo.'
233 >>> _auxencode(s.split(b'/'), True)
233 >>> _auxencode(s.split(b'/'), True)
234 ['~2efoo', 'au~78.txt', 'txt.aux', 'co~6e', 'pr~6e', 'nu~6c', 'foo~2e']
234 ['~2efoo', 'au~78.txt', 'txt.aux', 'co~6e', 'pr~6e', 'nu~6c', 'foo~2e']
235 >>> s = b'.com1com2/lpt9.lpt4.lpt1/conprn/com0/lpt0/foo.'
235 >>> s = b'.com1com2/lpt9.lpt4.lpt1/conprn/com0/lpt0/foo.'
236 >>> _auxencode(s.split(b'/'), False)
236 >>> _auxencode(s.split(b'/'), False)
237 ['.com1com2', 'lp~749.lpt4.lpt1', 'conprn', 'com0', 'lpt0', 'foo~2e']
237 ['.com1com2', 'lp~749.lpt4.lpt1', 'conprn', 'com0', 'lpt0', 'foo~2e']
238 >>> _auxencode([b'foo. '], True)
238 >>> _auxencode([b'foo. '], True)
239 ['foo.~20']
239 ['foo.~20']
240 >>> _auxencode([b' .foo'], True)
240 >>> _auxencode([b' .foo'], True)
241 ['~20.foo']
241 ['~20.foo']
242 """
242 """
243 for i, n in enumerate(path):
243 for i, n in enumerate(path):
244 if not n:
244 if not n:
245 continue
245 continue
246 if dotencode and n[0] in b'. ':
246 if dotencode and n[0] in b'. ':
247 n = b"~%02x" % ord(n[0:1]) + n[1:]
247 n = b"~%02x" % ord(n[0:1]) + n[1:]
248 path[i] = n
248 path[i] = n
249 else:
249 else:
250 l = n.find(b'.')
250 l = n.find(b'.')
251 if l == -1:
251 if l == -1:
252 l = len(n)
252 l = len(n)
253 if (l == 3 and n[:3] in _winres3) or (
253 if (l == 3 and n[:3] in _winres3) or (
254 l == 4
254 l == 4
255 and n[3:4] <= b'9'
255 and n[3:4] <= b'9'
256 and n[3:4] >= b'1'
256 and n[3:4] >= b'1'
257 and n[:3] in _winres4
257 and n[:3] in _winres4
258 ):
258 ):
259 # encode third letter ('aux' -> 'au~78')
259 # encode third letter ('aux' -> 'au~78')
260 ec = b"~%02x" % ord(n[2:3])
260 ec = b"~%02x" % ord(n[2:3])
261 n = n[0:2] + ec + n[3:]
261 n = n[0:2] + ec + n[3:]
262 path[i] = n
262 path[i] = n
263 if n[-1] in b'. ':
263 if n[-1] in b'. ':
264 # encode last period or space ('foo...' -> 'foo..~2e')
264 # encode last period or space ('foo...' -> 'foo..~2e')
265 path[i] = n[:-1] + b"~%02x" % ord(n[-1:])
265 path[i] = n[:-1] + b"~%02x" % ord(n[-1:])
266 return path
266 return path
267
267
268
268
269 _maxstorepathlen = 120
269 _maxstorepathlen = 120
270 _dirprefixlen = 8
270 _dirprefixlen = 8
271 _maxshortdirslen = 8 * (_dirprefixlen + 1) - 4
271 _maxshortdirslen = 8 * (_dirprefixlen + 1) - 4
272
272
273
273
274 def _hashencode(path, dotencode):
274 def _hashencode(path, dotencode):
275 digest = hex(hashutil.sha1(path).digest())
275 digest = hex(hashutil.sha1(path).digest())
276 le = lowerencode(path[5:]).split(b'/') # skips prefix 'data/' or 'meta/'
276 le = lowerencode(path[5:]).split(b'/') # skips prefix 'data/' or 'meta/'
277 parts = _auxencode(le, dotencode)
277 parts = _auxencode(le, dotencode)
278 basename = parts[-1]
278 basename = parts[-1]
279 _root, ext = os.path.splitext(basename)
279 _root, ext = os.path.splitext(basename)
280 sdirs = []
280 sdirs = []
281 sdirslen = 0
281 sdirslen = 0
282 for p in parts[:-1]:
282 for p in parts[:-1]:
283 d = p[:_dirprefixlen]
283 d = p[:_dirprefixlen]
284 if d[-1] in b'. ':
284 if d[-1] in b'. ':
285 # Windows can't access dirs ending in period or space
285 # Windows can't access dirs ending in period or space
286 d = d[:-1] + b'_'
286 d = d[:-1] + b'_'
287 if sdirslen == 0:
287 if sdirslen == 0:
288 t = len(d)
288 t = len(d)
289 else:
289 else:
290 t = sdirslen + 1 + len(d)
290 t = sdirslen + 1 + len(d)
291 if t > _maxshortdirslen:
291 if t > _maxshortdirslen:
292 break
292 break
293 sdirs.append(d)
293 sdirs.append(d)
294 sdirslen = t
294 sdirslen = t
295 dirs = b'/'.join(sdirs)
295 dirs = b'/'.join(sdirs)
296 if len(dirs) > 0:
296 if len(dirs) > 0:
297 dirs += b'/'
297 dirs += b'/'
298 res = b'dh/' + dirs + digest + ext
298 res = b'dh/' + dirs + digest + ext
299 spaceleft = _maxstorepathlen - len(res)
299 spaceleft = _maxstorepathlen - len(res)
300 if spaceleft > 0:
300 if spaceleft > 0:
301 filler = basename[:spaceleft]
301 filler = basename[:spaceleft]
302 res = b'dh/' + dirs + filler + digest + ext
302 res = b'dh/' + dirs + filler + digest + ext
303 return res
303 return res
304
304
305
305
306 def _hybridencode(path, dotencode):
306 def _hybridencode(path, dotencode):
307 """encodes path with a length limit
307 """encodes path with a length limit
308
308
309 Encodes all paths that begin with 'data/', according to the following.
309 Encodes all paths that begin with 'data/', according to the following.
310
310
311 Default encoding (reversible):
311 Default encoding (reversible):
312
312
313 Encodes all uppercase letters 'X' as '_x'. All reserved or illegal
313 Encodes all uppercase letters 'X' as '_x'. All reserved or illegal
314 characters are encoded as '~xx', where xx is the two digit hex code
314 characters are encoded as '~xx', where xx is the two digit hex code
315 of the character (see encodefilename).
315 of the character (see encodefilename).
316 Relevant path components consisting of Windows reserved filenames are
316 Relevant path components consisting of Windows reserved filenames are
317 masked by encoding the third character ('aux' -> 'au~78', see _auxencode).
317 masked by encoding the third character ('aux' -> 'au~78', see _auxencode).
318
318
319 Hashed encoding (not reversible):
319 Hashed encoding (not reversible):
320
320
321 If the default-encoded path is longer than _maxstorepathlen, a
321 If the default-encoded path is longer than _maxstorepathlen, a
322 non-reversible hybrid hashing of the path is done instead.
322 non-reversible hybrid hashing of the path is done instead.
323 This encoding uses up to _dirprefixlen characters of all directory
323 This encoding uses up to _dirprefixlen characters of all directory
324 levels of the lowerencoded path, but not more levels than can fit into
324 levels of the lowerencoded path, but not more levels than can fit into
325 _maxshortdirslen.
325 _maxshortdirslen.
326 Then follows the filler followed by the sha digest of the full path.
326 Then follows the filler followed by the sha digest of the full path.
327 The filler is the beginning of the basename of the lowerencoded path
327 The filler is the beginning of the basename of the lowerencoded path
328 (the basename is everything after the last path separator). The filler
328 (the basename is everything after the last path separator). The filler
329 is as long as possible, filling in characters from the basename until
329 is as long as possible, filling in characters from the basename until
330 the encoded path has _maxstorepathlen characters (or all chars of the
330 the encoded path has _maxstorepathlen characters (or all chars of the
331 basename have been taken).
331 basename have been taken).
332 The extension (e.g. '.i' or '.d') is preserved.
332 The extension (e.g. '.i' or '.d') is preserved.
333
333
334 The string 'data/' at the beginning is replaced with 'dh/', if the hashed
334 The string 'data/' at the beginning is replaced with 'dh/', if the hashed
335 encoding was used.
335 encoding was used.
336 """
336 """
337 path = encodedir(path)
337 path = encodedir(path)
338 ef = _encodefname(path).split(b'/')
338 ef = _encodefname(path).split(b'/')
339 res = b'/'.join(_auxencode(ef, dotencode))
339 res = b'/'.join(_auxencode(ef, dotencode))
340 if len(res) > _maxstorepathlen:
340 if len(res) > _maxstorepathlen:
341 res = _hashencode(path, dotencode)
341 res = _hashencode(path, dotencode)
342 return res
342 return res
343
343
344
344
345 def _pathencode(path):
345 def _pathencode(path):
346 de = encodedir(path)
346 de = encodedir(path)
347 if len(path) > _maxstorepathlen:
347 if len(path) > _maxstorepathlen:
348 return _hashencode(de, True)
348 return _hashencode(de, True)
349 ef = _encodefname(de).split(b'/')
349 ef = _encodefname(de).split(b'/')
350 res = b'/'.join(_auxencode(ef, True))
350 res = b'/'.join(_auxencode(ef, True))
351 if len(res) > _maxstorepathlen:
351 if len(res) > _maxstorepathlen:
352 return _hashencode(de, True)
352 return _hashencode(de, True)
353 return res
353 return res
354
354
355
355
356 _pathencode = getattr(parsers, 'pathencode', _pathencode)
356 _pathencode = getattr(parsers, 'pathencode', _pathencode)
357
357
358
358
359 def _plainhybridencode(f):
359 def _plainhybridencode(f):
360 return _hybridencode(f, False)
360 return _hybridencode(f, False)
361
361
362
362
363 def _calcmode(vfs):
363 def _calcmode(vfs):
364 try:
364 try:
365 # files in .hg/ will be created using this mode
365 # files in .hg/ will be created using this mode
366 mode = vfs.stat().st_mode
366 mode = vfs.stat().st_mode
367 # avoid some useless chmods
367 # avoid some useless chmods
368 if (0o777 & ~util.umask) == (0o777 & mode):
368 if (0o777 & ~util.umask) == (0o777 & mode):
369 mode = None
369 mode = None
370 except OSError:
370 except OSError:
371 mode = None
371 mode = None
372 return mode
372 return mode
373
373
374
374
375 _data = [
375 _data = [
376 b'bookmarks',
376 b'bookmarks',
377 b'narrowspec',
377 b'narrowspec',
378 b'data',
378 b'data',
379 b'meta',
379 b'meta',
380 b'00manifest.d',
380 b'00manifest.d',
381 b'00manifest.i',
381 b'00manifest.i',
382 b'00changelog.d',
382 b'00changelog.d',
383 b'00changelog.i',
383 b'00changelog.i',
384 b'phaseroots',
384 b'phaseroots',
385 b'obsstore',
385 b'obsstore',
386 b'requires',
386 b'requires',
387 ]
387 ]
388
388
389 REVLOG_FILES_MAIN_EXT = (b'.i',)
389 REVLOG_FILES_MAIN_EXT = (b'.i',)
390 REVLOG_FILES_OTHER_EXT = (
390 REVLOG_FILES_OTHER_EXT = (
391 b'.idx',
391 b'.idx',
392 b'.d',
392 b'.d',
393 b'.dat',
393 b'.dat',
394 b'.n',
394 b'.n',
395 b'.nd',
395 b'.nd',
396 b'.sda',
396 b'.sda',
397 )
397 )
398 # file extension that also use a `-SOMELONGIDHASH.ext` form
398 # file extension that also use a `-SOMELONGIDHASH.ext` form
399 REVLOG_FILES_LONG_EXT = (
399 REVLOG_FILES_LONG_EXT = (
400 b'.nd',
400 b'.nd',
401 b'.idx',
401 b'.idx',
402 b'.dat',
402 b'.dat',
403 b'.sda',
403 b'.sda',
404 )
404 )
405 # files that are "volatile" and might change between listing and streaming
405 # files that are "volatile" and might change between listing and streaming
406 #
406 #
407 # note: the ".nd" file are nodemap data and won't "change" but they might be
407 # note: the ".nd" file are nodemap data and won't "change" but they might be
408 # deleted.
408 # deleted.
409 REVLOG_FILES_VOLATILE_EXT = (b'.n', b'.nd')
409 REVLOG_FILES_VOLATILE_EXT = (b'.n', b'.nd')
410
410
411 # some exception to the above matching
411 # some exception to the above matching
412 #
412 #
413 # XXX This is currently not in use because of issue6542
413 # XXX This is currently not in use because of issue6542
414 EXCLUDED = re.compile(br'.*undo\.[^/]+\.(nd?|i)$')
414 EXCLUDED = re.compile(br'.*undo\.[^/]+\.(nd?|i)$')
415
415
416
416
417 def is_revlog(f, kind, st):
417 def is_revlog(f, kind, st):
418 if kind != stat.S_IFREG:
418 if kind != stat.S_IFREG:
419 return None
419 return None
420 return revlog_type(f)
420 return revlog_type(f)
421
421
422
422
423 def revlog_type(f):
423 def revlog_type(f):
424 # XXX we need to filter `undo.` created by the transaction here, however
424 # XXX we need to filter `undo.` created by the transaction here, however
425 # being naive about it also filter revlog for `undo.*` files, leading to
425 # being naive about it also filter revlog for `undo.*` files, leading to
426 # issue6542. So we no longer use EXCLUDED.
426 # issue6542. So we no longer use EXCLUDED.
427 if f.endswith(REVLOG_FILES_MAIN_EXT):
427 if f.endswith(REVLOG_FILES_MAIN_EXT):
428 return FILEFLAGS_REVLOG_MAIN
428 return FILEFLAGS_REVLOG_MAIN
429 elif f.endswith(REVLOG_FILES_OTHER_EXT):
429 elif f.endswith(REVLOG_FILES_OTHER_EXT):
430 t = FILETYPE_FILELOG_OTHER
430 t = FILETYPE_FILELOG_OTHER
431 if f.endswith(REVLOG_FILES_VOLATILE_EXT):
431 if f.endswith(REVLOG_FILES_VOLATILE_EXT):
432 t |= FILEFLAGS_VOLATILE
432 t |= FILEFLAGS_VOLATILE
433 return t
433 return t
434 return None
434 return None
435
435
436
436
437 # the file is part of changelog data
437 # the file is part of changelog data
438 FILEFLAGS_CHANGELOG = 1 << 13
438 FILEFLAGS_CHANGELOG = 1 << 13
439 # the file is part of manifest data
439 # the file is part of manifest data
440 FILEFLAGS_MANIFESTLOG = 1 << 12
440 FILEFLAGS_MANIFESTLOG = 1 << 12
441 # the file is part of filelog data
441 # the file is part of filelog data
442 FILEFLAGS_FILELOG = 1 << 11
442 FILEFLAGS_FILELOG = 1 << 11
443 # file that are not directly part of a revlog
443 # file that are not directly part of a revlog
444 FILEFLAGS_OTHER = 1 << 10
444 FILEFLAGS_OTHER = 1 << 10
445
445
446 # the main entry point for a revlog
446 # the main entry point for a revlog
447 FILEFLAGS_REVLOG_MAIN = 1 << 1
447 FILEFLAGS_REVLOG_MAIN = 1 << 1
448 # a secondary file for a revlog
448 # a secondary file for a revlog
449 FILEFLAGS_REVLOG_OTHER = 1 << 0
449 FILEFLAGS_REVLOG_OTHER = 1 << 0
450
450
451 # files that are "volatile" and might change between listing and streaming
451 # files that are "volatile" and might change between listing and streaming
452 FILEFLAGS_VOLATILE = 1 << 20
452 FILEFLAGS_VOLATILE = 1 << 20
453
453
454 FILETYPE_CHANGELOG_MAIN = FILEFLAGS_CHANGELOG | FILEFLAGS_REVLOG_MAIN
454 FILETYPE_CHANGELOG_MAIN = FILEFLAGS_CHANGELOG | FILEFLAGS_REVLOG_MAIN
455 FILETYPE_CHANGELOG_OTHER = FILEFLAGS_CHANGELOG | FILEFLAGS_REVLOG_OTHER
455 FILETYPE_CHANGELOG_OTHER = FILEFLAGS_CHANGELOG | FILEFLAGS_REVLOG_OTHER
456 FILETYPE_MANIFESTLOG_MAIN = FILEFLAGS_MANIFESTLOG | FILEFLAGS_REVLOG_MAIN
456 FILETYPE_MANIFESTLOG_MAIN = FILEFLAGS_MANIFESTLOG | FILEFLAGS_REVLOG_MAIN
457 FILETYPE_MANIFESTLOG_OTHER = FILEFLAGS_MANIFESTLOG | FILEFLAGS_REVLOG_OTHER
457 FILETYPE_MANIFESTLOG_OTHER = FILEFLAGS_MANIFESTLOG | FILEFLAGS_REVLOG_OTHER
458 FILETYPE_FILELOG_MAIN = FILEFLAGS_FILELOG | FILEFLAGS_REVLOG_MAIN
458 FILETYPE_FILELOG_MAIN = FILEFLAGS_FILELOG | FILEFLAGS_REVLOG_MAIN
459 FILETYPE_FILELOG_OTHER = FILEFLAGS_FILELOG | FILEFLAGS_REVLOG_OTHER
459 FILETYPE_FILELOG_OTHER = FILEFLAGS_FILELOG | FILEFLAGS_REVLOG_OTHER
460 FILETYPE_OTHER = FILEFLAGS_OTHER
460 FILETYPE_OTHER = FILEFLAGS_OTHER
461
461
462
462
463 @attr.s(slots=True, init=False)
463 @attr.s(slots=True, init=False)
464 class BaseStoreEntry:
464 class BaseStoreEntry:
465 """An entry in the store
465 """An entry in the store
466
466
467 This is returned by `store.walk` and represent some data in the store."""
467 This is returned by `store.walk` and represent some data in the store."""
468
468
469 unencoded_path = attr.ib()
469 unencoded_path = attr.ib()
470 _is_volatile = attr.ib(default=False)
470 _is_volatile = attr.ib(default=False)
471 _file_size = attr.ib(default=None)
471 _file_size = attr.ib(default=None)
472
472
473 def __init__(
473 def __init__(
474 self,
474 self,
475 unencoded_path,
475 unencoded_path,
476 is_volatile=False,
476 is_volatile=False,
477 file_size=None,
477 file_size=None,
478 ):
478 ):
479 self.unencoded_path = unencoded_path
479 self.unencoded_path = unencoded_path
480 self._is_volatile = is_volatile
480 self._is_volatile = is_volatile
481 self._file_size = file_size
481 self._file_size = file_size
482
482
483 def files(self):
483 def files(self):
484 return [
484 return [
485 StoreFile(
485 StoreFile(
486 unencoded_path=self.unencoded_path,
486 unencoded_path=self.unencoded_path,
487 file_size=self._file_size,
487 file_size=self._file_size,
488 is_volatile=self._is_volatile,
488 is_volatile=self._is_volatile,
489 )
489 )
490 ]
490 ]
491
491
492
492
493 @attr.s(slots=True, init=False)
493 @attr.s(slots=True, init=False)
494 class SimpleStoreEntry(BaseStoreEntry):
494 class SimpleStoreEntry(BaseStoreEntry):
495 """A generic entry in the store"""
495 """A generic entry in the store"""
496
496
497 is_revlog = False
497 is_revlog = False
498
498
499
499
500 @attr.s(slots=True, init=False)
500 @attr.s(slots=True, init=False)
501 class RevlogStoreEntry(BaseStoreEntry):
501 class RevlogStoreEntry(BaseStoreEntry):
502 """A revlog entry in the store"""
502 """A revlog entry in the store"""
503
503
504 is_revlog = True
504 is_revlog = True
505 revlog_type = attr.ib(default=None)
505 revlog_type = attr.ib(default=None)
506 is_revlog_main = attr.ib(default=None)
506 is_revlog_main = attr.ib(default=None)
507
507
508 def __init__(
508 def __init__(
509 self,
509 self,
510 unencoded_path,
510 unencoded_path,
511 revlog_type,
511 revlog_type,
512 is_revlog_main=False,
512 is_revlog_main=False,
513 is_volatile=False,
513 is_volatile=False,
514 file_size=None,
514 file_size=None,
515 ):
515 ):
516 super().__init__(
516 super().__init__(
517 unencoded_path=unencoded_path,
517 unencoded_path=unencoded_path,
518 is_volatile=is_volatile,
518 is_volatile=is_volatile,
519 file_size=file_size,
519 file_size=file_size,
520 )
520 )
521 self.revlog_type = revlog_type
521 self.revlog_type = revlog_type
522 self.is_revlog_main = is_revlog_main
522 self.is_revlog_main = is_revlog_main
523
523
524
524
525 @attr.s(slots=True)
525 @attr.s(slots=True)
526 class StoreFile:
526 class StoreFile:
527 """a file matching an entry"""
527 """a file matching an entry"""
528
528
529 unencoded_path = attr.ib()
529 unencoded_path = attr.ib()
530 _file_size = attr.ib(default=False)
530 _file_size = attr.ib(default=False)
531 is_volatile = attr.ib(default=False)
531 is_volatile = attr.ib(default=False)
532
532
533 def file_size(self, vfs):
533 def file_size(self, vfs):
534 if self._file_size is not None:
534 if self._file_size is not None:
535 return self._file_size
535 return self._file_size
536 try:
536 try:
537 return vfs.stat(self.unencoded_path).st_size
537 return vfs.stat(self.unencoded_path).st_size
538 except FileNotFoundError:
538 except FileNotFoundError:
539 return 0
539 return 0
540
540
541
541
542 def _gather_revlog(files_data):
542 def _gather_revlog(files_data):
543 """group files per revlog prefix
543 """group files per revlog prefix
544
544
545 The returns a two level nested dict. The top level key is the revlog prefix
545 The returns a two level nested dict. The top level key is the revlog prefix
546 without extension, the second level is all the file "suffix" that were
546 without extension, the second level is all the file "suffix" that were
547 seen for this revlog and arbitrary file data as value.
547 seen for this revlog and arbitrary file data as value.
548 """
548 """
549 revlogs = collections.defaultdict(dict)
549 revlogs = collections.defaultdict(dict)
550 for u, value in files_data:
550 for u, value in files_data:
551 name, ext = _split_revlog_ext(u)
551 name, ext = _split_revlog_ext(u)
552 revlogs[name][ext] = value
552 revlogs[name][ext] = value
553 return sorted(revlogs.items())
553 return sorted(revlogs.items())
554
554
555
555
556 def _split_revlog_ext(filename):
556 def _split_revlog_ext(filename):
557 """split the revlog file prefix from the variable extension"""
557 """split the revlog file prefix from the variable extension"""
558 if filename.endswith(REVLOG_FILES_LONG_EXT):
558 if filename.endswith(REVLOG_FILES_LONG_EXT):
559 char = b'-'
559 char = b'-'
560 else:
560 else:
561 char = b'.'
561 char = b'.'
562 idx = filename.rfind(char)
562 idx = filename.rfind(char)
563 return filename[:idx], filename[idx:]
563 return filename[:idx], filename[idx:]
564
564
565
565
566 def _ext_key(ext):
567 """a key to order revlog suffix
568
569 important to issue .i after other entry."""
570 # the only important part of this order is to keep the `.i` last.
571 if ext.endswith(b'.n'):
572 return (0, ext)
573 elif ext.endswith(b'.nd'):
574 return (10, ext)
575 elif ext.endswith(b'.d'):
576 return (20, ext)
577 elif ext.endswith(b'.i'):
578 return (50, ext)
579 else:
580 return (40, ext)
581
582
566 class basicstore:
583 class basicstore:
567 '''base class for local repository stores'''
584 '''base class for local repository stores'''
568
585
569 def __init__(self, path, vfstype):
586 def __init__(self, path, vfstype):
570 vfs = vfstype(path)
587 vfs = vfstype(path)
571 self.path = vfs.base
588 self.path = vfs.base
572 self.createmode = _calcmode(vfs)
589 self.createmode = _calcmode(vfs)
573 vfs.createmode = self.createmode
590 vfs.createmode = self.createmode
574 self.rawvfs = vfs
591 self.rawvfs = vfs
575 self.vfs = vfsmod.filtervfs(vfs, encodedir)
592 self.vfs = vfsmod.filtervfs(vfs, encodedir)
576 self.opener = self.vfs
593 self.opener = self.vfs
577
594
578 def join(self, f):
595 def join(self, f):
579 return self.path + b'/' + encodedir(f)
596 return self.path + b'/' + encodedir(f)
580
597
581 def _walk(self, relpath, recurse):
598 def _walk(self, relpath, recurse):
582 '''yields (revlog_type, unencoded, size)'''
599 '''yields (revlog_type, unencoded, size)'''
583 path = self.path
600 path = self.path
584 if relpath:
601 if relpath:
585 path += b'/' + relpath
602 path += b'/' + relpath
586 striplen = len(self.path) + 1
603 striplen = len(self.path) + 1
587 l = []
604 l = []
588 if self.rawvfs.isdir(path):
605 if self.rawvfs.isdir(path):
589 visit = [path]
606 visit = [path]
590 readdir = self.rawvfs.readdir
607 readdir = self.rawvfs.readdir
591 while visit:
608 while visit:
592 p = visit.pop()
609 p = visit.pop()
593 for f, kind, st in readdir(p, stat=True):
610 for f, kind, st in readdir(p, stat=True):
594 fp = p + b'/' + f
611 fp = p + b'/' + f
595 rl_type = is_revlog(f, kind, st)
612 rl_type = is_revlog(f, kind, st)
596 if rl_type is not None:
613 if rl_type is not None:
597 n = util.pconvert(fp[striplen:])
614 n = util.pconvert(fp[striplen:])
598 l.append((decodedir(n), (rl_type, st.st_size)))
615 l.append((decodedir(n), (rl_type, st.st_size)))
599 elif kind == stat.S_IFDIR and recurse:
616 elif kind == stat.S_IFDIR and recurse:
600 visit.append(fp)
617 visit.append(fp)
601
618
602 l.sort()
619 l.sort()
603 return l
620 return l
604
621
605 def changelog(self, trypending, concurrencychecker=None):
622 def changelog(self, trypending, concurrencychecker=None):
606 return changelog.changelog(
623 return changelog.changelog(
607 self.vfs,
624 self.vfs,
608 trypending=trypending,
625 trypending=trypending,
609 concurrencychecker=concurrencychecker,
626 concurrencychecker=concurrencychecker,
610 )
627 )
611
628
612 def manifestlog(self, repo, storenarrowmatch):
629 def manifestlog(self, repo, storenarrowmatch):
613 rootstore = manifest.manifestrevlog(repo.nodeconstants, self.vfs)
630 rootstore = manifest.manifestrevlog(repo.nodeconstants, self.vfs)
614 return manifest.manifestlog(self.vfs, repo, rootstore, storenarrowmatch)
631 return manifest.manifestlog(self.vfs, repo, rootstore, storenarrowmatch)
615
632
616 def datafiles(
633 def datafiles(
617 self, matcher=None, undecodable=None
634 self, matcher=None, undecodable=None
618 ) -> Generator[BaseStoreEntry, None, None]:
635 ) -> Generator[BaseStoreEntry, None, None]:
619 """Like walk, but excluding the changelog and root manifest.
636 """Like walk, but excluding the changelog and root manifest.
620
637
621 When [undecodable] is None, revlogs names that can't be
638 When [undecodable] is None, revlogs names that can't be
622 decoded cause an exception. When it is provided, it should
639 decoded cause an exception. When it is provided, it should
623 be a list and the filenames that can't be decoded are added
640 be a list and the filenames that can't be decoded are added
624 to it instead. This is very rarely needed."""
641 to it instead. This is very rarely needed."""
625 files = self._walk(b'data', True) + self._walk(b'meta', True)
642 files = self._walk(b'data', True) + self._walk(b'meta', True)
626 files = (f for f in files if f[1][0] is not None)
643 files = (f for f in files if f[1][0] is not None)
627 for revlog, details in _gather_revlog(files):
644 for revlog, details in _gather_revlog(files):
628 for ext, (t, s) in sorted(details.items()):
645 for ext, (t, s) in sorted(details.items()):
629 u = revlog + ext
646 u = revlog + ext
630 yield RevlogStoreEntry(
647 yield RevlogStoreEntry(
631 unencoded_path=u,
648 unencoded_path=u,
632 revlog_type=FILEFLAGS_FILELOG,
649 revlog_type=FILEFLAGS_FILELOG,
633 is_revlog_main=bool(t & FILEFLAGS_REVLOG_MAIN),
650 is_revlog_main=bool(t & FILEFLAGS_REVLOG_MAIN),
634 is_volatile=bool(t & FILEFLAGS_VOLATILE),
651 is_volatile=bool(t & FILEFLAGS_VOLATILE),
635 file_size=s,
652 file_size=s,
636 )
653 )
637
654
638 def topfiles(self) -> Generator[BaseStoreEntry, None, None]:
655 def topfiles(self) -> Generator[BaseStoreEntry, None, None]:
639 # yield manifest before changelog
656 files = reversed(self._walk(b'', False))
640 files = self._walk(b'', False)
657
641 # key is (type, path) (keeping ordering so we get 00changelog.i last)
658 changelogs = collections.defaultdict(dict)
642 type_key = lambda x: (x[1][0], x[0])
659 manifestlogs = collections.defaultdict(dict)
643 files = sorted(files, reverse=True, key=type_key)
660
644 for u, (t, s) in files:
661 for u, (t, s) in files:
645 if u.startswith(b'00changelog'):
662 if u.startswith(b'00changelog'):
646 yield RevlogStoreEntry(
663 name, ext = _split_revlog_ext(u)
647 unencoded_path=u,
664 changelogs[name][ext] = (t, s)
648 revlog_type=FILEFLAGS_CHANGELOG,
649 is_revlog_main=bool(t & FILEFLAGS_REVLOG_MAIN),
650 is_volatile=bool(t & FILEFLAGS_VOLATILE),
651 file_size=s,
652 )
653 elif u.startswith(b'00manifest'):
665 elif u.startswith(b'00manifest'):
654 yield RevlogStoreEntry(
666 name, ext = _split_revlog_ext(u)
655 unencoded_path=u,
667 manifestlogs[name][ext] = (t, s)
656 revlog_type=FILEFLAGS_MANIFESTLOG,
657 is_revlog_main=bool(t & FILEFLAGS_REVLOG_MAIN),
658 is_volatile=bool(t & FILEFLAGS_VOLATILE),
659 file_size=s,
660 )
661 else:
668 else:
662 yield SimpleStoreEntry(
669 yield SimpleStoreEntry(
663 unencoded_path=u,
670 unencoded_path=u,
664 is_volatile=bool(t & FILEFLAGS_VOLATILE),
671 is_volatile=bool(t & FILEFLAGS_VOLATILE),
665 file_size=s,
672 file_size=s,
666 )
673 )
674 # yield manifest before changelog
675 top_rl = [
676 (manifestlogs, FILEFLAGS_MANIFESTLOG),
677 (changelogs, FILEFLAGS_CHANGELOG),
678 ]
679 assert len(manifestlogs) <= 1
680 assert len(changelogs) <= 1
681 for data, revlog_type in top_rl:
682 for revlog, details in sorted(data.items()):
683 # (keeping ordering so we get 00changelog.i last)
684 key = lambda x: _ext_key(x[0])
685 for ext, (t, s) in sorted(details.items(), key=key):
686 u = revlog + ext
687 yield RevlogStoreEntry(
688 unencoded_path=u,
689 revlog_type=revlog_type,
690 is_revlog_main=bool(t & FILEFLAGS_REVLOG_MAIN),
691 is_volatile=bool(t & FILEFLAGS_VOLATILE),
692 file_size=s,
693 )
667
694
668 def walk(self, matcher=None) -> Generator[BaseStoreEntry, None, None]:
695 def walk(self, matcher=None) -> Generator[BaseStoreEntry, None, None]:
669 """return files related to data storage (ie: revlogs)
696 """return files related to data storage (ie: revlogs)
670
697
671 yields (file_type, unencoded, size)
698 yields (file_type, unencoded, size)
672
699
673 if a matcher is passed, storage files of only those tracked paths
700 if a matcher is passed, storage files of only those tracked paths
674 are passed with matches the matcher
701 are passed with matches the matcher
675 """
702 """
676 # yield data files first
703 # yield data files first
677 for x in self.datafiles(matcher):
704 for x in self.datafiles(matcher):
678 yield x
705 yield x
679 for x in self.topfiles():
706 for x in self.topfiles():
680 yield x
707 yield x
681
708
682 def copylist(self):
709 def copylist(self):
683 return _data
710 return _data
684
711
685 def write(self, tr):
712 def write(self, tr):
686 pass
713 pass
687
714
688 def invalidatecaches(self):
715 def invalidatecaches(self):
689 pass
716 pass
690
717
691 def markremoved(self, fn):
718 def markremoved(self, fn):
692 pass
719 pass
693
720
694 def __contains__(self, path):
721 def __contains__(self, path):
695 '''Checks if the store contains path'''
722 '''Checks if the store contains path'''
696 path = b"/".join((b"data", path))
723 path = b"/".join((b"data", path))
697 # file?
724 # file?
698 if self.vfs.exists(path + b".i"):
725 if self.vfs.exists(path + b".i"):
699 return True
726 return True
700 # dir?
727 # dir?
701 if not path.endswith(b"/"):
728 if not path.endswith(b"/"):
702 path = path + b"/"
729 path = path + b"/"
703 return self.vfs.exists(path)
730 return self.vfs.exists(path)
704
731
705
732
706 class encodedstore(basicstore):
733 class encodedstore(basicstore):
707 def __init__(self, path, vfstype):
734 def __init__(self, path, vfstype):
708 vfs = vfstype(path + b'/store')
735 vfs = vfstype(path + b'/store')
709 self.path = vfs.base
736 self.path = vfs.base
710 self.createmode = _calcmode(vfs)
737 self.createmode = _calcmode(vfs)
711 vfs.createmode = self.createmode
738 vfs.createmode = self.createmode
712 self.rawvfs = vfs
739 self.rawvfs = vfs
713 self.vfs = vfsmod.filtervfs(vfs, encodefilename)
740 self.vfs = vfsmod.filtervfs(vfs, encodefilename)
714 self.opener = self.vfs
741 self.opener = self.vfs
715
742
716 # note: topfiles would also need a decode phase. It is just that in
743 # note: topfiles would also need a decode phase. It is just that in
717 # practice we do not have any file outside of `data/` that needs encoding.
744 # practice we do not have any file outside of `data/` that needs encoding.
718 # However that might change so we should probably add a test and encoding
745 # However that might change so we should probably add a test and encoding
719 # decoding for it too. see issue6548
746 # decoding for it too. see issue6548
720
747
721 def datafiles(
748 def datafiles(
722 self, matcher=None, undecodable=None
749 self, matcher=None, undecodable=None
723 ) -> Generator[BaseStoreEntry, None, None]:
750 ) -> Generator[BaseStoreEntry, None, None]:
724 for entry in super(encodedstore, self).datafiles():
751 for entry in super(encodedstore, self).datafiles():
725 try:
752 try:
726 f1 = entry.unencoded_path
753 f1 = entry.unencoded_path
727 f2 = decodefilename(f1)
754 f2 = decodefilename(f1)
728 except KeyError:
755 except KeyError:
729 if undecodable is None:
756 if undecodable is None:
730 msg = _(b'undecodable revlog name %s') % f1
757 msg = _(b'undecodable revlog name %s') % f1
731 raise error.StorageError(msg)
758 raise error.StorageError(msg)
732 else:
759 else:
733 undecodable.append(f1)
760 undecodable.append(f1)
734 continue
761 continue
735 if not _matchtrackedpath(f2, matcher):
762 if not _matchtrackedpath(f2, matcher):
736 continue
763 continue
737 entry.unencoded_path = f2
764 entry.unencoded_path = f2
738 yield entry
765 yield entry
739
766
740 def join(self, f):
767 def join(self, f):
741 return self.path + b'/' + encodefilename(f)
768 return self.path + b'/' + encodefilename(f)
742
769
743 def copylist(self):
770 def copylist(self):
744 return [b'requires', b'00changelog.i'] + [b'store/' + f for f in _data]
771 return [b'requires', b'00changelog.i'] + [b'store/' + f for f in _data]
745
772
746
773
747 class fncache:
774 class fncache:
748 # the filename used to be partially encoded
775 # the filename used to be partially encoded
749 # hence the encodedir/decodedir dance
776 # hence the encodedir/decodedir dance
750 def __init__(self, vfs):
777 def __init__(self, vfs):
751 self.vfs = vfs
778 self.vfs = vfs
752 self._ignores = set()
779 self._ignores = set()
753 self.entries = None
780 self.entries = None
754 self._dirty = False
781 self._dirty = False
755 # set of new additions to fncache
782 # set of new additions to fncache
756 self.addls = set()
783 self.addls = set()
757
784
758 def ensureloaded(self, warn=None):
785 def ensureloaded(self, warn=None):
759 """read the fncache file if not already read.
786 """read the fncache file if not already read.
760
787
761 If the file on disk is corrupted, raise. If warn is provided,
788 If the file on disk is corrupted, raise. If warn is provided,
762 warn and keep going instead."""
789 warn and keep going instead."""
763 if self.entries is None:
790 if self.entries is None:
764 self._load(warn)
791 self._load(warn)
765
792
766 def _load(self, warn=None):
793 def _load(self, warn=None):
767 '''fill the entries from the fncache file'''
794 '''fill the entries from the fncache file'''
768 self._dirty = False
795 self._dirty = False
769 try:
796 try:
770 fp = self.vfs(b'fncache', mode=b'rb')
797 fp = self.vfs(b'fncache', mode=b'rb')
771 except IOError:
798 except IOError:
772 # skip nonexistent file
799 # skip nonexistent file
773 self.entries = set()
800 self.entries = set()
774 return
801 return
775
802
776 self.entries = set()
803 self.entries = set()
777 chunk = b''
804 chunk = b''
778 for c in iter(functools.partial(fp.read, fncache_chunksize), b''):
805 for c in iter(functools.partial(fp.read, fncache_chunksize), b''):
779 chunk += c
806 chunk += c
780 try:
807 try:
781 p = chunk.rindex(b'\n')
808 p = chunk.rindex(b'\n')
782 self.entries.update(decodedir(chunk[: p + 1]).splitlines())
809 self.entries.update(decodedir(chunk[: p + 1]).splitlines())
783 chunk = chunk[p + 1 :]
810 chunk = chunk[p + 1 :]
784 except ValueError:
811 except ValueError:
785 # substring '\n' not found, maybe the entry is bigger than the
812 # substring '\n' not found, maybe the entry is bigger than the
786 # chunksize, so let's keep iterating
813 # chunksize, so let's keep iterating
787 pass
814 pass
788
815
789 if chunk:
816 if chunk:
790 msg = _(b"fncache does not ends with a newline")
817 msg = _(b"fncache does not ends with a newline")
791 if warn:
818 if warn:
792 warn(msg + b'\n')
819 warn(msg + b'\n')
793 else:
820 else:
794 raise error.Abort(
821 raise error.Abort(
795 msg,
822 msg,
796 hint=_(
823 hint=_(
797 b"use 'hg debugrebuildfncache' to "
824 b"use 'hg debugrebuildfncache' to "
798 b"rebuild the fncache"
825 b"rebuild the fncache"
799 ),
826 ),
800 )
827 )
801 self._checkentries(fp, warn)
828 self._checkentries(fp, warn)
802 fp.close()
829 fp.close()
803
830
804 def _checkentries(self, fp, warn):
831 def _checkentries(self, fp, warn):
805 """make sure there is no empty string in entries"""
832 """make sure there is no empty string in entries"""
806 if b'' in self.entries:
833 if b'' in self.entries:
807 fp.seek(0)
834 fp.seek(0)
808 for n, line in enumerate(fp):
835 for n, line in enumerate(fp):
809 if not line.rstrip(b'\n'):
836 if not line.rstrip(b'\n'):
810 t = _(b'invalid entry in fncache, line %d') % (n + 1)
837 t = _(b'invalid entry in fncache, line %d') % (n + 1)
811 if warn:
838 if warn:
812 warn(t + b'\n')
839 warn(t + b'\n')
813 else:
840 else:
814 raise error.Abort(t)
841 raise error.Abort(t)
815
842
816 def write(self, tr):
843 def write(self, tr):
817 if self._dirty:
844 if self._dirty:
818 assert self.entries is not None
845 assert self.entries is not None
819 self.entries = self.entries | self.addls
846 self.entries = self.entries | self.addls
820 self.addls = set()
847 self.addls = set()
821 tr.addbackup(b'fncache')
848 tr.addbackup(b'fncache')
822 fp = self.vfs(b'fncache', mode=b'wb', atomictemp=True)
849 fp = self.vfs(b'fncache', mode=b'wb', atomictemp=True)
823 if self.entries:
850 if self.entries:
824 fp.write(encodedir(b'\n'.join(self.entries) + b'\n'))
851 fp.write(encodedir(b'\n'.join(self.entries) + b'\n'))
825 fp.close()
852 fp.close()
826 self._dirty = False
853 self._dirty = False
827 if self.addls:
854 if self.addls:
828 # if we have just new entries, let's append them to the fncache
855 # if we have just new entries, let's append them to the fncache
829 tr.addbackup(b'fncache')
856 tr.addbackup(b'fncache')
830 fp = self.vfs(b'fncache', mode=b'ab', atomictemp=True)
857 fp = self.vfs(b'fncache', mode=b'ab', atomictemp=True)
831 if self.addls:
858 if self.addls:
832 fp.write(encodedir(b'\n'.join(self.addls) + b'\n'))
859 fp.write(encodedir(b'\n'.join(self.addls) + b'\n'))
833 fp.close()
860 fp.close()
834 self.entries = None
861 self.entries = None
835 self.addls = set()
862 self.addls = set()
836
863
837 def addignore(self, fn):
864 def addignore(self, fn):
838 self._ignores.add(fn)
865 self._ignores.add(fn)
839
866
840 def add(self, fn):
867 def add(self, fn):
841 if fn in self._ignores:
868 if fn in self._ignores:
842 return
869 return
843 if self.entries is None:
870 if self.entries is None:
844 self._load()
871 self._load()
845 if fn not in self.entries:
872 if fn not in self.entries:
846 self.addls.add(fn)
873 self.addls.add(fn)
847
874
848 def remove(self, fn):
875 def remove(self, fn):
849 if self.entries is None:
876 if self.entries is None:
850 self._load()
877 self._load()
851 if fn in self.addls:
878 if fn in self.addls:
852 self.addls.remove(fn)
879 self.addls.remove(fn)
853 return
880 return
854 try:
881 try:
855 self.entries.remove(fn)
882 self.entries.remove(fn)
856 self._dirty = True
883 self._dirty = True
857 except KeyError:
884 except KeyError:
858 pass
885 pass
859
886
860 def __contains__(self, fn):
887 def __contains__(self, fn):
861 if fn in self.addls:
888 if fn in self.addls:
862 return True
889 return True
863 if self.entries is None:
890 if self.entries is None:
864 self._load()
891 self._load()
865 return fn in self.entries
892 return fn in self.entries
866
893
867 def __iter__(self):
894 def __iter__(self):
868 if self.entries is None:
895 if self.entries is None:
869 self._load()
896 self._load()
870 return iter(self.entries | self.addls)
897 return iter(self.entries | self.addls)
871
898
872
899
873 class _fncachevfs(vfsmod.proxyvfs):
900 class _fncachevfs(vfsmod.proxyvfs):
874 def __init__(self, vfs, fnc, encode):
901 def __init__(self, vfs, fnc, encode):
875 vfsmod.proxyvfs.__init__(self, vfs)
902 vfsmod.proxyvfs.__init__(self, vfs)
876 self.fncache = fnc
903 self.fncache = fnc
877 self.encode = encode
904 self.encode = encode
878
905
879 def __call__(self, path, mode=b'r', *args, **kw):
906 def __call__(self, path, mode=b'r', *args, **kw):
880 encoded = self.encode(path)
907 encoded = self.encode(path)
881 if (
908 if (
882 mode not in (b'r', b'rb')
909 mode not in (b'r', b'rb')
883 and (path.startswith(b'data/') or path.startswith(b'meta/'))
910 and (path.startswith(b'data/') or path.startswith(b'meta/'))
884 and revlog_type(path) is not None
911 and revlog_type(path) is not None
885 ):
912 ):
886 # do not trigger a fncache load when adding a file that already is
913 # do not trigger a fncache load when adding a file that already is
887 # known to exist.
914 # known to exist.
888 notload = self.fncache.entries is None and self.vfs.exists(encoded)
915 notload = self.fncache.entries is None and self.vfs.exists(encoded)
889 if notload and b'r+' in mode and not self.vfs.stat(encoded).st_size:
916 if notload and b'r+' in mode and not self.vfs.stat(encoded).st_size:
890 # when appending to an existing file, if the file has size zero,
917 # when appending to an existing file, if the file has size zero,
891 # it should be considered as missing. Such zero-size files are
918 # it should be considered as missing. Such zero-size files are
892 # the result of truncation when a transaction is aborted.
919 # the result of truncation when a transaction is aborted.
893 notload = False
920 notload = False
894 if not notload:
921 if not notload:
895 self.fncache.add(path)
922 self.fncache.add(path)
896 return self.vfs(encoded, mode, *args, **kw)
923 return self.vfs(encoded, mode, *args, **kw)
897
924
898 def join(self, path):
925 def join(self, path):
899 if path:
926 if path:
900 return self.vfs.join(self.encode(path))
927 return self.vfs.join(self.encode(path))
901 else:
928 else:
902 return self.vfs.join(path)
929 return self.vfs.join(path)
903
930
904 def register_file(self, path):
931 def register_file(self, path):
905 """generic hook point to lets fncache steer its stew"""
932 """generic hook point to lets fncache steer its stew"""
906 if path.startswith(b'data/') or path.startswith(b'meta/'):
933 if path.startswith(b'data/') or path.startswith(b'meta/'):
907 self.fncache.add(path)
934 self.fncache.add(path)
908
935
909
936
910 class fncachestore(basicstore):
937 class fncachestore(basicstore):
911 def __init__(self, path, vfstype, dotencode):
938 def __init__(self, path, vfstype, dotencode):
912 if dotencode:
939 if dotencode:
913 encode = _pathencode
940 encode = _pathencode
914 else:
941 else:
915 encode = _plainhybridencode
942 encode = _plainhybridencode
916 self.encode = encode
943 self.encode = encode
917 vfs = vfstype(path + b'/store')
944 vfs = vfstype(path + b'/store')
918 self.path = vfs.base
945 self.path = vfs.base
919 self.pathsep = self.path + b'/'
946 self.pathsep = self.path + b'/'
920 self.createmode = _calcmode(vfs)
947 self.createmode = _calcmode(vfs)
921 vfs.createmode = self.createmode
948 vfs.createmode = self.createmode
922 self.rawvfs = vfs
949 self.rawvfs = vfs
923 fnc = fncache(vfs)
950 fnc = fncache(vfs)
924 self.fncache = fnc
951 self.fncache = fnc
925 self.vfs = _fncachevfs(vfs, fnc, encode)
952 self.vfs = _fncachevfs(vfs, fnc, encode)
926 self.opener = self.vfs
953 self.opener = self.vfs
927
954
928 def join(self, f):
955 def join(self, f):
929 return self.pathsep + self.encode(f)
956 return self.pathsep + self.encode(f)
930
957
931 def getsize(self, path):
958 def getsize(self, path):
932 return self.rawvfs.stat(path).st_size
959 return self.rawvfs.stat(path).st_size
933
960
934 def datafiles(
961 def datafiles(
935 self, matcher=None, undecodable=None
962 self, matcher=None, undecodable=None
936 ) -> Generator[BaseStoreEntry, None, None]:
963 ) -> Generator[BaseStoreEntry, None, None]:
937 files = ((f, revlog_type(f)) for f in self.fncache)
964 files = ((f, revlog_type(f)) for f in self.fncache)
938 # Note: all files in fncache should be revlog related, However the
965 # Note: all files in fncache should be revlog related, However the
939 # fncache might contains such file added by previous version of
966 # fncache might contains such file added by previous version of
940 # Mercurial.
967 # Mercurial.
941 files = (f for f in files if f[1] is not None)
968 files = (f for f in files if f[1] is not None)
942 by_revlog = _gather_revlog(files)
969 by_revlog = _gather_revlog(files)
943 for revlog, details in by_revlog:
970 for revlog, details in by_revlog:
944 for ext, t in sorted(details.items()):
971 for ext, t in sorted(details.items()):
945 f = revlog + ext
972 f = revlog + ext
946 if not _matchtrackedpath(f, matcher):
973 if not _matchtrackedpath(f, matcher):
947 continue
974 continue
948 yield RevlogStoreEntry(
975 yield RevlogStoreEntry(
949 unencoded_path=f,
976 unencoded_path=f,
950 revlog_type=FILEFLAGS_FILELOG,
977 revlog_type=FILEFLAGS_FILELOG,
951 is_revlog_main=bool(t & FILEFLAGS_REVLOG_MAIN),
978 is_revlog_main=bool(t & FILEFLAGS_REVLOG_MAIN),
952 is_volatile=bool(t & FILEFLAGS_VOLATILE),
979 is_volatile=bool(t & FILEFLAGS_VOLATILE),
953 )
980 )
954
981
955 def copylist(self):
982 def copylist(self):
956 d = (
983 d = (
957 b'bookmarks',
984 b'bookmarks',
958 b'narrowspec',
985 b'narrowspec',
959 b'data',
986 b'data',
960 b'meta',
987 b'meta',
961 b'dh',
988 b'dh',
962 b'fncache',
989 b'fncache',
963 b'phaseroots',
990 b'phaseroots',
964 b'obsstore',
991 b'obsstore',
965 b'00manifest.d',
992 b'00manifest.d',
966 b'00manifest.i',
993 b'00manifest.i',
967 b'00changelog.d',
994 b'00changelog.d',
968 b'00changelog.i',
995 b'00changelog.i',
969 b'requires',
996 b'requires',
970 )
997 )
971 return [b'requires', b'00changelog.i'] + [b'store/' + f for f in d]
998 return [b'requires', b'00changelog.i'] + [b'store/' + f for f in d]
972
999
973 def write(self, tr):
1000 def write(self, tr):
974 self.fncache.write(tr)
1001 self.fncache.write(tr)
975
1002
976 def invalidatecaches(self):
1003 def invalidatecaches(self):
977 self.fncache.entries = None
1004 self.fncache.entries = None
978 self.fncache.addls = set()
1005 self.fncache.addls = set()
979
1006
980 def markremoved(self, fn):
1007 def markremoved(self, fn):
981 self.fncache.remove(fn)
1008 self.fncache.remove(fn)
982
1009
983 def _exists(self, f):
1010 def _exists(self, f):
984 ef = self.encode(f)
1011 ef = self.encode(f)
985 try:
1012 try:
986 self.getsize(ef)
1013 self.getsize(ef)
987 return True
1014 return True
988 except FileNotFoundError:
1015 except FileNotFoundError:
989 return False
1016 return False
990
1017
991 def __contains__(self, path):
1018 def __contains__(self, path):
992 '''Checks if the store contains path'''
1019 '''Checks if the store contains path'''
993 path = b"/".join((b"data", path))
1020 path = b"/".join((b"data", path))
994 # check for files (exact match)
1021 # check for files (exact match)
995 e = path + b'.i'
1022 e = path + b'.i'
996 if e in self.fncache and self._exists(e):
1023 if e in self.fncache and self._exists(e):
997 return True
1024 return True
998 # now check for directories (prefix match)
1025 # now check for directories (prefix match)
999 if not path.endswith(b'/'):
1026 if not path.endswith(b'/'):
1000 path += b'/'
1027 path += b'/'
1001 for e in self.fncache:
1028 for e in self.fncache:
1002 if e.startswith(path) and self._exists(e):
1029 if e.startswith(path) and self._exists(e):
1003 return True
1030 return True
1004 return False
1031 return False
@@ -1,1258 +1,1258 b''
1 ===================================
1 ===================================
2 Test the persistent on-disk nodemap
2 Test the persistent on-disk nodemap
3 ===================================
3 ===================================
4
4
5
5
6 $ cat << EOF >> $HGRCPATH
6 $ cat << EOF >> $HGRCPATH
7 > [format]
7 > [format]
8 > use-share-safe=yes
8 > use-share-safe=yes
9 > [extensions]
9 > [extensions]
10 > share=
10 > share=
11 > EOF
11 > EOF
12
12
13 #if no-rust
13 #if no-rust
14
14
15 $ cat << EOF >> $HGRCPATH
15 $ cat << EOF >> $HGRCPATH
16 > [format]
16 > [format]
17 > use-persistent-nodemap=yes
17 > use-persistent-nodemap=yes
18 > [devel]
18 > [devel]
19 > persistent-nodemap=yes
19 > persistent-nodemap=yes
20 > EOF
20 > EOF
21
21
22 #endif
22 #endif
23
23
24 $ hg init test-repo --config storage.revlog.persistent-nodemap.slow-path=allow
24 $ hg init test-repo --config storage.revlog.persistent-nodemap.slow-path=allow
25 $ cd test-repo
25 $ cd test-repo
26
26
27 Check handling of the default slow-path value
27 Check handling of the default slow-path value
28
28
29 #if no-pure no-rust
29 #if no-pure no-rust
30
30
31 $ hg id
31 $ hg id
32 abort: accessing `persistent-nodemap` repository without associated fast implementation.
32 abort: accessing `persistent-nodemap` repository without associated fast implementation.
33 (check `hg help config.format.use-persistent-nodemap` for details)
33 (check `hg help config.format.use-persistent-nodemap` for details)
34 [255]
34 [255]
35
35
36 Unlock further check (we are here to test the feature)
36 Unlock further check (we are here to test the feature)
37
37
38 $ cat << EOF >> $HGRCPATH
38 $ cat << EOF >> $HGRCPATH
39 > [storage]
39 > [storage]
40 > # to avoid spamming the test
40 > # to avoid spamming the test
41 > revlog.persistent-nodemap.slow-path=allow
41 > revlog.persistent-nodemap.slow-path=allow
42 > EOF
42 > EOF
43
43
44 #endif
44 #endif
45
45
46 #if rust
46 #if rust
47
47
48 Regression test for a previous bug in Rust/C FFI for the `Revlog_CAPI` capsule:
48 Regression test for a previous bug in Rust/C FFI for the `Revlog_CAPI` capsule:
49 in places where `mercurial/cext/revlog.c` function signatures use `Py_ssize_t`
49 in places where `mercurial/cext/revlog.c` function signatures use `Py_ssize_t`
50 (64 bits on Linux x86_64), corresponding declarations in `rust/hg-cpython/src/cindex.rs`
50 (64 bits on Linux x86_64), corresponding declarations in `rust/hg-cpython/src/cindex.rs`
51 incorrectly used `libc::c_int` (32 bits).
51 incorrectly used `libc::c_int` (32 bits).
52 As a result, -1 passed from Rust for the null revision became 4294967295 in C.
52 As a result, -1 passed from Rust for the null revision became 4294967295 in C.
53
53
54 $ hg log -r 00000000
54 $ hg log -r 00000000
55 changeset: -1:000000000000
55 changeset: -1:000000000000
56 tag: tip
56 tag: tip
57 user:
57 user:
58 date: Thu Jan 01 00:00:00 1970 +0000
58 date: Thu Jan 01 00:00:00 1970 +0000
59
59
60
60
61 #endif
61 #endif
62
62
63
63
64 $ hg debugformat
64 $ hg debugformat
65 format-variant repo
65 format-variant repo
66 fncache: yes
66 fncache: yes
67 dirstate-v2: no
67 dirstate-v2: no
68 tracked-hint: no
68 tracked-hint: no
69 dotencode: yes
69 dotencode: yes
70 generaldelta: yes
70 generaldelta: yes
71 share-safe: yes
71 share-safe: yes
72 sparserevlog: yes
72 sparserevlog: yes
73 persistent-nodemap: yes
73 persistent-nodemap: yes
74 copies-sdc: no
74 copies-sdc: no
75 revlog-v2: no
75 revlog-v2: no
76 changelog-v2: no
76 changelog-v2: no
77 plain-cl-delta: yes
77 plain-cl-delta: yes
78 compression: zlib (no-zstd !)
78 compression: zlib (no-zstd !)
79 compression: zstd (zstd !)
79 compression: zstd (zstd !)
80 compression-level: default
80 compression-level: default
81 $ hg debugbuilddag .+5000 --new-file
81 $ hg debugbuilddag .+5000 --new-file
82
82
83 $ hg debugnodemap --metadata
83 $ hg debugnodemap --metadata
84 uid: ???????? (glob)
84 uid: ???????? (glob)
85 tip-rev: 5000
85 tip-rev: 5000
86 tip-node: 6b02b8c7b96654c25e86ba69eda198d7e6ad8b3c
86 tip-node: 6b02b8c7b96654c25e86ba69eda198d7e6ad8b3c
87 data-length: 121088
87 data-length: 121088
88 data-unused: 0
88 data-unused: 0
89 data-unused: 0.000%
89 data-unused: 0.000%
90 $ f --size .hg/store/00changelog.n
90 $ f --size .hg/store/00changelog.n
91 .hg/store/00changelog.n: size=62
91 .hg/store/00changelog.n: size=62
92
92
93 Simple lookup works
93 Simple lookup works
94
94
95 $ ANYNODE=`hg log --template '{node|short}\n' --rev tip`
95 $ ANYNODE=`hg log --template '{node|short}\n' --rev tip`
96 $ hg log -r "$ANYNODE" --template '{rev}\n'
96 $ hg log -r "$ANYNODE" --template '{rev}\n'
97 5000
97 5000
98
98
99
99
100 #if rust
100 #if rust
101
101
102 $ f --sha256 .hg/store/00changelog-*.nd
102 $ f --sha256 .hg/store/00changelog-*.nd
103 .hg/store/00changelog-????????.nd: sha256=2e029d3200bd1a986b32784fc2ef1a3bd60dc331f025718bcf5ff44d93f026fd (glob)
103 .hg/store/00changelog-????????.nd: sha256=2e029d3200bd1a986b32784fc2ef1a3bd60dc331f025718bcf5ff44d93f026fd (glob)
104
104
105 $ f --sha256 .hg/store/00manifest-*.nd
105 $ f --sha256 .hg/store/00manifest-*.nd
106 .hg/store/00manifest-????????.nd: sha256=97117b1c064ea2f86664a124589e47db0e254e8d34739b5c5cc5bf31c9da2b51 (glob)
106 .hg/store/00manifest-????????.nd: sha256=97117b1c064ea2f86664a124589e47db0e254e8d34739b5c5cc5bf31c9da2b51 (glob)
107 $ hg debugnodemap --dump-new | f --sha256 --size
107 $ hg debugnodemap --dump-new | f --sha256 --size
108 size=121088, sha256=2e029d3200bd1a986b32784fc2ef1a3bd60dc331f025718bcf5ff44d93f026fd
108 size=121088, sha256=2e029d3200bd1a986b32784fc2ef1a3bd60dc331f025718bcf5ff44d93f026fd
109 $ hg debugnodemap --dump-disk | f --sha256 --bytes=256 --hexdump --size
109 $ hg debugnodemap --dump-disk | f --sha256 --bytes=256 --hexdump --size
110 size=121088, sha256=2e029d3200bd1a986b32784fc2ef1a3bd60dc331f025718bcf5ff44d93f026fd
110 size=121088, sha256=2e029d3200bd1a986b32784fc2ef1a3bd60dc331f025718bcf5ff44d93f026fd
111 0000: 00 00 00 91 00 00 00 20 00 00 00 bb 00 00 00 e7 |....... ........|
111 0000: 00 00 00 91 00 00 00 20 00 00 00 bb 00 00 00 e7 |....... ........|
112 0010: 00 00 00 66 00 00 00 a1 00 00 01 13 00 00 01 22 |...f..........."|
112 0010: 00 00 00 66 00 00 00 a1 00 00 01 13 00 00 01 22 |...f..........."|
113 0020: 00 00 00 23 00 00 00 fc 00 00 00 ba 00 00 00 5e |...#...........^|
113 0020: 00 00 00 23 00 00 00 fc 00 00 00 ba 00 00 00 5e |...#...........^|
114 0030: 00 00 00 df 00 00 01 4e 00 00 01 65 00 00 00 ab |.......N...e....|
114 0030: 00 00 00 df 00 00 01 4e 00 00 01 65 00 00 00 ab |.......N...e....|
115 0040: 00 00 00 a9 00 00 00 95 00 00 00 73 00 00 00 38 |...........s...8|
115 0040: 00 00 00 a9 00 00 00 95 00 00 00 73 00 00 00 38 |...........s...8|
116 0050: 00 00 00 cc 00 00 00 92 00 00 00 90 00 00 00 69 |...............i|
116 0050: 00 00 00 cc 00 00 00 92 00 00 00 90 00 00 00 69 |...............i|
117 0060: 00 00 00 ec 00 00 00 8d 00 00 01 4f 00 00 00 12 |...........O....|
117 0060: 00 00 00 ec 00 00 00 8d 00 00 01 4f 00 00 00 12 |...........O....|
118 0070: 00 00 02 0c 00 00 00 77 00 00 00 9c 00 00 00 8f |.......w........|
118 0070: 00 00 02 0c 00 00 00 77 00 00 00 9c 00 00 00 8f |.......w........|
119 0080: 00 00 00 d5 00 00 00 6b 00 00 00 48 00 00 00 b3 |.......k...H....|
119 0080: 00 00 00 d5 00 00 00 6b 00 00 00 48 00 00 00 b3 |.......k...H....|
120 0090: 00 00 00 e5 00 00 00 b5 00 00 00 8e 00 00 00 ad |................|
120 0090: 00 00 00 e5 00 00 00 b5 00 00 00 8e 00 00 00 ad |................|
121 00a0: 00 00 00 7b 00 00 00 7c 00 00 00 0b 00 00 00 2b |...{...|.......+|
121 00a0: 00 00 00 7b 00 00 00 7c 00 00 00 0b 00 00 00 2b |...{...|.......+|
122 00b0: 00 00 00 c6 00 00 00 1e 00 00 01 08 00 00 00 11 |................|
122 00b0: 00 00 00 c6 00 00 00 1e 00 00 01 08 00 00 00 11 |................|
123 00c0: 00 00 01 30 00 00 00 26 00 00 01 9c 00 00 00 35 |...0...&.......5|
123 00c0: 00 00 01 30 00 00 00 26 00 00 01 9c 00 00 00 35 |...0...&.......5|
124 00d0: 00 00 00 b8 00 00 01 31 00 00 00 2c 00 00 00 55 |.......1...,...U|
124 00d0: 00 00 00 b8 00 00 01 31 00 00 00 2c 00 00 00 55 |.......1...,...U|
125 00e0: 00 00 00 8a 00 00 00 9a 00 00 00 0c 00 00 01 1e |................|
125 00e0: 00 00 00 8a 00 00 00 9a 00 00 00 0c 00 00 01 1e |................|
126 00f0: 00 00 00 a4 00 00 00 83 00 00 00 c9 00 00 00 8c |................|
126 00f0: 00 00 00 a4 00 00 00 83 00 00 00 c9 00 00 00 8c |................|
127
127
128
128
129 #else
129 #else
130
130
131 $ f --sha256 .hg/store/00changelog-*.nd
131 $ f --sha256 .hg/store/00changelog-*.nd
132 .hg/store/00changelog-????????.nd: sha256=f544f5462ff46097432caf6d764091f6d8c46d6121be315ead8576d548c9dd79 (glob)
132 .hg/store/00changelog-????????.nd: sha256=f544f5462ff46097432caf6d764091f6d8c46d6121be315ead8576d548c9dd79 (glob)
133 $ hg debugnodemap --dump-new | f --sha256 --size
133 $ hg debugnodemap --dump-new | f --sha256 --size
134 size=121088, sha256=f544f5462ff46097432caf6d764091f6d8c46d6121be315ead8576d548c9dd79
134 size=121088, sha256=f544f5462ff46097432caf6d764091f6d8c46d6121be315ead8576d548c9dd79
135 $ hg debugnodemap --dump-disk | f --sha256 --bytes=256 --hexdump --size
135 $ hg debugnodemap --dump-disk | f --sha256 --bytes=256 --hexdump --size
136 size=121088, sha256=f544f5462ff46097432caf6d764091f6d8c46d6121be315ead8576d548c9dd79
136 size=121088, sha256=f544f5462ff46097432caf6d764091f6d8c46d6121be315ead8576d548c9dd79
137 0000: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
137 0000: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
138 0010: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
138 0010: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
139 0020: ff ff ff ff ff ff f5 06 ff ff ff ff ff ff f3 e7 |................|
139 0020: ff ff ff ff ff ff f5 06 ff ff ff ff ff ff f3 e7 |................|
140 0030: ff ff ef ca ff ff ff ff ff ff ff ff ff ff ff ff |................|
140 0030: ff ff ef ca ff ff ff ff ff ff ff ff ff ff ff ff |................|
141 0040: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
141 0040: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
142 0050: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ed 08 |................|
142 0050: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ed 08 |................|
143 0060: ff ff ed 66 ff ff ff ff ff ff ff ff ff ff ff ff |...f............|
143 0060: ff ff ed 66 ff ff ff ff ff ff ff ff ff ff ff ff |...f............|
144 0070: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
144 0070: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
145 0080: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
145 0080: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
146 0090: ff ff ff ff ff ff ff ff ff ff ff ff ff ff f6 ed |................|
146 0090: ff ff ff ff ff ff ff ff ff ff ff ff ff ff f6 ed |................|
147 00a0: ff ff ff ff ff ff fe 61 ff ff ff ff ff ff ff ff |.......a........|
147 00a0: ff ff ff ff ff ff fe 61 ff ff ff ff ff ff ff ff |.......a........|
148 00b0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
148 00b0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
149 00c0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
149 00c0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
150 00d0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
150 00d0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
151 00e0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff f1 02 |................|
151 00e0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff f1 02 |................|
152 00f0: ff ff ff ff ff ff ed 1b ff ff ff ff ff ff ff ff |................|
152 00f0: ff ff ff ff ff ff ed 1b ff ff ff ff ff ff ff ff |................|
153
153
154 #endif
154 #endif
155
155
156 $ hg debugnodemap --check
156 $ hg debugnodemap --check
157 revision in index: 5001
157 revision in index: 5001
158 revision in nodemap: 5001
158 revision in nodemap: 5001
159
159
160 add a new commit
160 add a new commit
161
161
162 $ hg up
162 $ hg up
163 5001 files updated, 0 files merged, 0 files removed, 0 files unresolved
163 5001 files updated, 0 files merged, 0 files removed, 0 files unresolved
164 $ echo foo > foo
164 $ echo foo > foo
165 $ hg add foo
165 $ hg add foo
166
166
167
167
168 Check slow-path config value handling
168 Check slow-path config value handling
169 -------------------------------------
169 -------------------------------------
170
170
171 #if no-pure no-rust
171 #if no-pure no-rust
172
172
173 $ hg id --config "storage.revlog.persistent-nodemap.slow-path=invalid-value"
173 $ hg id --config "storage.revlog.persistent-nodemap.slow-path=invalid-value"
174 unknown value for config "storage.revlog.persistent-nodemap.slow-path": "invalid-value"
174 unknown value for config "storage.revlog.persistent-nodemap.slow-path": "invalid-value"
175 falling back to default value: abort
175 falling back to default value: abort
176 abort: accessing `persistent-nodemap` repository without associated fast implementation.
176 abort: accessing `persistent-nodemap` repository without associated fast implementation.
177 (check `hg help config.format.use-persistent-nodemap` for details)
177 (check `hg help config.format.use-persistent-nodemap` for details)
178 [255]
178 [255]
179
179
180 $ hg log -r . --config "storage.revlog.persistent-nodemap.slow-path=warn"
180 $ hg log -r . --config "storage.revlog.persistent-nodemap.slow-path=warn"
181 warning: accessing `persistent-nodemap` repository without associated fast implementation.
181 warning: accessing `persistent-nodemap` repository without associated fast implementation.
182 (check `hg help config.format.use-persistent-nodemap` for details)
182 (check `hg help config.format.use-persistent-nodemap` for details)
183 changeset: 5000:6b02b8c7b966
183 changeset: 5000:6b02b8c7b966
184 tag: tip
184 tag: tip
185 user: debugbuilddag
185 user: debugbuilddag
186 date: Thu Jan 01 01:23:20 1970 +0000
186 date: Thu Jan 01 01:23:20 1970 +0000
187 summary: r5000
187 summary: r5000
188
188
189 $ hg ci -m 'foo' --config "storage.revlog.persistent-nodemap.slow-path=abort"
189 $ hg ci -m 'foo' --config "storage.revlog.persistent-nodemap.slow-path=abort"
190 abort: accessing `persistent-nodemap` repository without associated fast implementation.
190 abort: accessing `persistent-nodemap` repository without associated fast implementation.
191 (check `hg help config.format.use-persistent-nodemap` for details)
191 (check `hg help config.format.use-persistent-nodemap` for details)
192 [255]
192 [255]
193
193
194 #else
194 #else
195
195
196 $ hg id --config "storage.revlog.persistent-nodemap.slow-path=invalid-value"
196 $ hg id --config "storage.revlog.persistent-nodemap.slow-path=invalid-value"
197 unknown value for config "storage.revlog.persistent-nodemap.slow-path": "invalid-value"
197 unknown value for config "storage.revlog.persistent-nodemap.slow-path": "invalid-value"
198 falling back to default value: abort
198 falling back to default value: abort
199 6b02b8c7b966+ tip
199 6b02b8c7b966+ tip
200
200
201 #endif
201 #endif
202
202
203 $ hg ci -m 'foo'
203 $ hg ci -m 'foo'
204
204
205 #if no-pure no-rust
205 #if no-pure no-rust
206 $ hg debugnodemap --metadata
206 $ hg debugnodemap --metadata
207 uid: ???????? (glob)
207 uid: ???????? (glob)
208 tip-rev: 5001
208 tip-rev: 5001
209 tip-node: 16395c3cf7e231394735e6b1717823ada303fb0c
209 tip-node: 16395c3cf7e231394735e6b1717823ada303fb0c
210 data-length: 121088
210 data-length: 121088
211 data-unused: 0
211 data-unused: 0
212 data-unused: 0.000%
212 data-unused: 0.000%
213 #else
213 #else
214 $ hg debugnodemap --metadata
214 $ hg debugnodemap --metadata
215 uid: ???????? (glob)
215 uid: ???????? (glob)
216 tip-rev: 5001
216 tip-rev: 5001
217 tip-node: 16395c3cf7e231394735e6b1717823ada303fb0c
217 tip-node: 16395c3cf7e231394735e6b1717823ada303fb0c
218 data-length: 121344
218 data-length: 121344
219 data-unused: 256
219 data-unused: 256
220 data-unused: 0.211%
220 data-unused: 0.211%
221 #endif
221 #endif
222
222
223 $ f --size .hg/store/00changelog.n
223 $ f --size .hg/store/00changelog.n
224 .hg/store/00changelog.n: size=62
224 .hg/store/00changelog.n: size=62
225
225
226 (The pure code use the debug code that perform incremental update, the C code reencode from scratch)
226 (The pure code use the debug code that perform incremental update, the C code reencode from scratch)
227
227
228 #if pure
228 #if pure
229 $ f --sha256 .hg/store/00changelog-*.nd --size
229 $ f --sha256 .hg/store/00changelog-*.nd --size
230 .hg/store/00changelog-????????.nd: size=121344, sha256=cce54c5da5bde3ad72a4938673ed4064c86231b9c64376b082b163fdb20f8f66 (glob)
230 .hg/store/00changelog-????????.nd: size=121344, sha256=cce54c5da5bde3ad72a4938673ed4064c86231b9c64376b082b163fdb20f8f66 (glob)
231 #endif
231 #endif
232
232
233 #if rust
233 #if rust
234 $ f --sha256 .hg/store/00changelog-*.nd --size
234 $ f --sha256 .hg/store/00changelog-*.nd --size
235 .hg/store/00changelog-????????.nd: size=121344, sha256=952b042fcf614ceb37b542b1b723e04f18f83efe99bee4e0f5ccd232ef470e58 (glob)
235 .hg/store/00changelog-????????.nd: size=121344, sha256=952b042fcf614ceb37b542b1b723e04f18f83efe99bee4e0f5ccd232ef470e58 (glob)
236 #endif
236 #endif
237
237
238 #if no-pure no-rust
238 #if no-pure no-rust
239 $ f --sha256 .hg/store/00changelog-*.nd --size
239 $ f --sha256 .hg/store/00changelog-*.nd --size
240 .hg/store/00changelog-????????.nd: size=121088, sha256=df7c06a035b96cb28c7287d349d603baef43240be7736fe34eea419a49702e17 (glob)
240 .hg/store/00changelog-????????.nd: size=121088, sha256=df7c06a035b96cb28c7287d349d603baef43240be7736fe34eea419a49702e17 (glob)
241 #endif
241 #endif
242
242
243 $ hg debugnodemap --check
243 $ hg debugnodemap --check
244 revision in index: 5002
244 revision in index: 5002
245 revision in nodemap: 5002
245 revision in nodemap: 5002
246
246
247 Test code path without mmap
247 Test code path without mmap
248 ---------------------------
248 ---------------------------
249
249
250 $ echo bar > bar
250 $ echo bar > bar
251 $ hg add bar
251 $ hg add bar
252 $ hg ci -m 'bar' --config storage.revlog.persistent-nodemap.mmap=no
252 $ hg ci -m 'bar' --config storage.revlog.persistent-nodemap.mmap=no
253
253
254 $ hg debugnodemap --check --config storage.revlog.persistent-nodemap.mmap=yes
254 $ hg debugnodemap --check --config storage.revlog.persistent-nodemap.mmap=yes
255 revision in index: 5003
255 revision in index: 5003
256 revision in nodemap: 5003
256 revision in nodemap: 5003
257 $ hg debugnodemap --check --config storage.revlog.persistent-nodemap.mmap=no
257 $ hg debugnodemap --check --config storage.revlog.persistent-nodemap.mmap=no
258 revision in index: 5003
258 revision in index: 5003
259 revision in nodemap: 5003
259 revision in nodemap: 5003
260
260
261
261
262 #if pure
262 #if pure
263 $ hg debugnodemap --metadata
263 $ hg debugnodemap --metadata
264 uid: ???????? (glob)
264 uid: ???????? (glob)
265 tip-rev: 5002
265 tip-rev: 5002
266 tip-node: 880b18d239dfa9f632413a2071bfdbcc4806a4fd
266 tip-node: 880b18d239dfa9f632413a2071bfdbcc4806a4fd
267 data-length: 121600
267 data-length: 121600
268 data-unused: 512
268 data-unused: 512
269 data-unused: 0.421%
269 data-unused: 0.421%
270 $ f --sha256 .hg/store/00changelog-*.nd --size
270 $ f --sha256 .hg/store/00changelog-*.nd --size
271 .hg/store/00changelog-????????.nd: size=121600, sha256=def52503d049ccb823974af313a98a935319ba61f40f3aa06a8be4d35c215054 (glob)
271 .hg/store/00changelog-????????.nd: size=121600, sha256=def52503d049ccb823974af313a98a935319ba61f40f3aa06a8be4d35c215054 (glob)
272 #endif
272 #endif
273 #if rust
273 #if rust
274 $ hg debugnodemap --metadata
274 $ hg debugnodemap --metadata
275 uid: ???????? (glob)
275 uid: ???????? (glob)
276 tip-rev: 5002
276 tip-rev: 5002
277 tip-node: 880b18d239dfa9f632413a2071bfdbcc4806a4fd
277 tip-node: 880b18d239dfa9f632413a2071bfdbcc4806a4fd
278 data-length: 121600
278 data-length: 121600
279 data-unused: 512
279 data-unused: 512
280 data-unused: 0.421%
280 data-unused: 0.421%
281 $ f --sha256 .hg/store/00changelog-*.nd --size
281 $ f --sha256 .hg/store/00changelog-*.nd --size
282 .hg/store/00changelog-????????.nd: size=121600, sha256=dacf5b5f1d4585fee7527d0e67cad5b1ba0930e6a0928f650f779aefb04ce3fb (glob)
282 .hg/store/00changelog-????????.nd: size=121600, sha256=dacf5b5f1d4585fee7527d0e67cad5b1ba0930e6a0928f650f779aefb04ce3fb (glob)
283 #endif
283 #endif
284 #if no-pure no-rust
284 #if no-pure no-rust
285 $ hg debugnodemap --metadata
285 $ hg debugnodemap --metadata
286 uid: ???????? (glob)
286 uid: ???????? (glob)
287 tip-rev: 5002
287 tip-rev: 5002
288 tip-node: 880b18d239dfa9f632413a2071bfdbcc4806a4fd
288 tip-node: 880b18d239dfa9f632413a2071bfdbcc4806a4fd
289 data-length: 121088
289 data-length: 121088
290 data-unused: 0
290 data-unused: 0
291 data-unused: 0.000%
291 data-unused: 0.000%
292 $ f --sha256 .hg/store/00changelog-*.nd --size
292 $ f --sha256 .hg/store/00changelog-*.nd --size
293 .hg/store/00changelog-????????.nd: size=121088, sha256=59fcede3e3cc587755916ceed29e3c33748cd1aa7d2f91828ac83e7979d935e8 (glob)
293 .hg/store/00changelog-????????.nd: size=121088, sha256=59fcede3e3cc587755916ceed29e3c33748cd1aa7d2f91828ac83e7979d935e8 (glob)
294 #endif
294 #endif
295
295
296 Test force warming the cache
296 Test force warming the cache
297
297
298 $ rm .hg/store/00changelog.n
298 $ rm .hg/store/00changelog.n
299 $ hg debugnodemap --metadata
299 $ hg debugnodemap --metadata
300 $ hg debugupdatecache
300 $ hg debugupdatecache
301 #if pure
301 #if pure
302 $ hg debugnodemap --metadata
302 $ hg debugnodemap --metadata
303 uid: ???????? (glob)
303 uid: ???????? (glob)
304 tip-rev: 5002
304 tip-rev: 5002
305 tip-node: 880b18d239dfa9f632413a2071bfdbcc4806a4fd
305 tip-node: 880b18d239dfa9f632413a2071bfdbcc4806a4fd
306 data-length: 121088
306 data-length: 121088
307 data-unused: 0
307 data-unused: 0
308 data-unused: 0.000%
308 data-unused: 0.000%
309 #else
309 #else
310 $ hg debugnodemap --metadata
310 $ hg debugnodemap --metadata
311 uid: ???????? (glob)
311 uid: ???????? (glob)
312 tip-rev: 5002
312 tip-rev: 5002
313 tip-node: 880b18d239dfa9f632413a2071bfdbcc4806a4fd
313 tip-node: 880b18d239dfa9f632413a2071bfdbcc4806a4fd
314 data-length: 121088
314 data-length: 121088
315 data-unused: 0
315 data-unused: 0
316 data-unused: 0.000%
316 data-unused: 0.000%
317 #endif
317 #endif
318
318
319 Check out of sync nodemap
319 Check out of sync nodemap
320 =========================
320 =========================
321
321
322 First copy old data on the side.
322 First copy old data on the side.
323
323
324 $ mkdir ../tmp-copies
324 $ mkdir ../tmp-copies
325 $ cp .hg/store/00changelog-????????.nd .hg/store/00changelog.n ../tmp-copies
325 $ cp .hg/store/00changelog-????????.nd .hg/store/00changelog.n ../tmp-copies
326
326
327 Nodemap lagging behind
327 Nodemap lagging behind
328 ----------------------
328 ----------------------
329
329
330 make a new commit
330 make a new commit
331
331
332 $ echo bar2 > bar
332 $ echo bar2 > bar
333 $ hg ci -m 'bar2'
333 $ hg ci -m 'bar2'
334 $ NODE=`hg log -r tip -T '{node}\n'`
334 $ NODE=`hg log -r tip -T '{node}\n'`
335 $ hg log -r "$NODE" -T '{rev}\n'
335 $ hg log -r "$NODE" -T '{rev}\n'
336 5003
336 5003
337
337
338 If the nodemap is lagging behind, it can catch up fine
338 If the nodemap is lagging behind, it can catch up fine
339
339
340 $ hg debugnodemap --metadata
340 $ hg debugnodemap --metadata
341 uid: ???????? (glob)
341 uid: ???????? (glob)
342 tip-rev: 5003
342 tip-rev: 5003
343 tip-node: c9329770f979ade2d16912267c38ba5f82fd37b3
343 tip-node: c9329770f979ade2d16912267c38ba5f82fd37b3
344 data-length: 121344 (pure !)
344 data-length: 121344 (pure !)
345 data-length: 121344 (rust !)
345 data-length: 121344 (rust !)
346 data-length: 121152 (no-rust no-pure !)
346 data-length: 121152 (no-rust no-pure !)
347 data-unused: 192 (pure !)
347 data-unused: 192 (pure !)
348 data-unused: 192 (rust !)
348 data-unused: 192 (rust !)
349 data-unused: 0 (no-rust no-pure !)
349 data-unused: 0 (no-rust no-pure !)
350 data-unused: 0.158% (pure !)
350 data-unused: 0.158% (pure !)
351 data-unused: 0.158% (rust !)
351 data-unused: 0.158% (rust !)
352 data-unused: 0.000% (no-rust no-pure !)
352 data-unused: 0.000% (no-rust no-pure !)
353 $ cp -f ../tmp-copies/* .hg/store/
353 $ cp -f ../tmp-copies/* .hg/store/
354 $ hg debugnodemap --metadata
354 $ hg debugnodemap --metadata
355 uid: ???????? (glob)
355 uid: ???????? (glob)
356 tip-rev: 5002
356 tip-rev: 5002
357 tip-node: 880b18d239dfa9f632413a2071bfdbcc4806a4fd
357 tip-node: 880b18d239dfa9f632413a2071bfdbcc4806a4fd
358 data-length: 121088
358 data-length: 121088
359 data-unused: 0
359 data-unused: 0
360 data-unused: 0.000%
360 data-unused: 0.000%
361 $ hg log -r "$NODE" -T '{rev}\n'
361 $ hg log -r "$NODE" -T '{rev}\n'
362 5003
362 5003
363
363
364 changelog altered
364 changelog altered
365 -----------------
365 -----------------
366
366
367 If the nodemap is not gated behind a requirements, an unaware client can alter
367 If the nodemap is not gated behind a requirements, an unaware client can alter
368 the repository so the revlog used to generate the nodemap is not longer
368 the repository so the revlog used to generate the nodemap is not longer
369 compatible with the persistent nodemap. We need to detect that.
369 compatible with the persistent nodemap. We need to detect that.
370
370
371 $ hg up "$NODE~5"
371 $ hg up "$NODE~5"
372 0 files updated, 0 files merged, 4 files removed, 0 files unresolved
372 0 files updated, 0 files merged, 4 files removed, 0 files unresolved
373 $ echo bar > babar
373 $ echo bar > babar
374 $ hg add babar
374 $ hg add babar
375 $ hg ci -m 'babar'
375 $ hg ci -m 'babar'
376 created new head
376 created new head
377 $ OTHERNODE=`hg log -r tip -T '{node}\n'`
377 $ OTHERNODE=`hg log -r tip -T '{node}\n'`
378 $ hg log -r "$OTHERNODE" -T '{rev}\n'
378 $ hg log -r "$OTHERNODE" -T '{rev}\n'
379 5004
379 5004
380
380
381 $ hg --config extensions.strip= strip --rev "$NODE~1" --no-backup
381 $ hg --config extensions.strip= strip --rev "$NODE~1" --no-backup
382
382
383 the nodemap should detect the changelog have been tampered with and recover.
383 the nodemap should detect the changelog have been tampered with and recover.
384
384
385 $ hg debugnodemap --metadata
385 $ hg debugnodemap --metadata
386 uid: ???????? (glob)
386 uid: ???????? (glob)
387 tip-rev: 5002
387 tip-rev: 5002
388 tip-node: b355ef8adce0949b8bdf6afc72ca853740d65944
388 tip-node: b355ef8adce0949b8bdf6afc72ca853740d65944
389 data-length: 121536 (pure !)
389 data-length: 121536 (pure !)
390 data-length: 121088 (rust !)
390 data-length: 121088 (rust !)
391 data-length: 121088 (no-pure no-rust !)
391 data-length: 121088 (no-pure no-rust !)
392 data-unused: 448 (pure !)
392 data-unused: 448 (pure !)
393 data-unused: 0 (rust !)
393 data-unused: 0 (rust !)
394 data-unused: 0 (no-pure no-rust !)
394 data-unused: 0 (no-pure no-rust !)
395 data-unused: 0.000% (rust !)
395 data-unused: 0.000% (rust !)
396 data-unused: 0.369% (pure !)
396 data-unused: 0.369% (pure !)
397 data-unused: 0.000% (no-pure no-rust !)
397 data-unused: 0.000% (no-pure no-rust !)
398
398
399 $ cp -f ../tmp-copies/* .hg/store/
399 $ cp -f ../tmp-copies/* .hg/store/
400 $ hg debugnodemap --metadata
400 $ hg debugnodemap --metadata
401 uid: ???????? (glob)
401 uid: ???????? (glob)
402 tip-rev: 5002
402 tip-rev: 5002
403 tip-node: 880b18d239dfa9f632413a2071bfdbcc4806a4fd
403 tip-node: 880b18d239dfa9f632413a2071bfdbcc4806a4fd
404 data-length: 121088
404 data-length: 121088
405 data-unused: 0
405 data-unused: 0
406 data-unused: 0.000%
406 data-unused: 0.000%
407 $ hg log -r "$OTHERNODE" -T '{rev}\n'
407 $ hg log -r "$OTHERNODE" -T '{rev}\n'
408 5002
408 5002
409
409
410 missing data file
410 missing data file
411 -----------------
411 -----------------
412
412
413 $ UUID=`hg debugnodemap --metadata| grep 'uid:' | \
413 $ UUID=`hg debugnodemap --metadata| grep 'uid:' | \
414 > sed 's/uid: //'`
414 > sed 's/uid: //'`
415 $ FILE=.hg/store/00changelog-"${UUID}".nd
415 $ FILE=.hg/store/00changelog-"${UUID}".nd
416 $ mv $FILE ../tmp-data-file
416 $ mv $FILE ../tmp-data-file
417 $ cp .hg/store/00changelog.n ../tmp-docket
417 $ cp .hg/store/00changelog.n ../tmp-docket
418
418
419 mercurial don't crash
419 mercurial don't crash
420
420
421 $ hg log -r .
421 $ hg log -r .
422 changeset: 5002:b355ef8adce0
422 changeset: 5002:b355ef8adce0
423 tag: tip
423 tag: tip
424 parent: 4998:d918ad6d18d3
424 parent: 4998:d918ad6d18d3
425 user: test
425 user: test
426 date: Thu Jan 01 00:00:00 1970 +0000
426 date: Thu Jan 01 00:00:00 1970 +0000
427 summary: babar
427 summary: babar
428
428
429 $ hg debugnodemap --metadata
429 $ hg debugnodemap --metadata
430
430
431 $ hg debugupdatecache
431 $ hg debugupdatecache
432 $ hg debugnodemap --metadata
432 $ hg debugnodemap --metadata
433 uid: * (glob)
433 uid: * (glob)
434 tip-rev: 5002
434 tip-rev: 5002
435 tip-node: b355ef8adce0949b8bdf6afc72ca853740d65944
435 tip-node: b355ef8adce0949b8bdf6afc72ca853740d65944
436 data-length: 121088
436 data-length: 121088
437 data-unused: 0
437 data-unused: 0
438 data-unused: 0.000%
438 data-unused: 0.000%
439 $ mv ../tmp-data-file $FILE
439 $ mv ../tmp-data-file $FILE
440 $ mv ../tmp-docket .hg/store/00changelog.n
440 $ mv ../tmp-docket .hg/store/00changelog.n
441
441
442 Check transaction related property
442 Check transaction related property
443 ==================================
443 ==================================
444
444
445 An up to date nodemap should be available to shell hooks,
445 An up to date nodemap should be available to shell hooks,
446
446
447 $ echo dsljfl > a
447 $ echo dsljfl > a
448 $ hg add a
448 $ hg add a
449 $ hg ci -m a
449 $ hg ci -m a
450 $ hg debugnodemap --metadata
450 $ hg debugnodemap --metadata
451 uid: ???????? (glob)
451 uid: ???????? (glob)
452 tip-rev: 5003
452 tip-rev: 5003
453 tip-node: a52c5079765b5865d97b993b303a18740113bbb2
453 tip-node: a52c5079765b5865d97b993b303a18740113bbb2
454 data-length: 121088
454 data-length: 121088
455 data-unused: 0
455 data-unused: 0
456 data-unused: 0.000%
456 data-unused: 0.000%
457 $ echo babar2 > babar
457 $ echo babar2 > babar
458 $ hg ci -m 'babar2' --config "hooks.pretxnclose.nodemap-test=hg debugnodemap --metadata"
458 $ hg ci -m 'babar2' --config "hooks.pretxnclose.nodemap-test=hg debugnodemap --metadata"
459 uid: ???????? (glob)
459 uid: ???????? (glob)
460 tip-rev: 5004
460 tip-rev: 5004
461 tip-node: 2f5fb1c06a16834c5679d672e90da7c5f3b1a984
461 tip-node: 2f5fb1c06a16834c5679d672e90da7c5f3b1a984
462 data-length: 121280 (pure !)
462 data-length: 121280 (pure !)
463 data-length: 121280 (rust !)
463 data-length: 121280 (rust !)
464 data-length: 121088 (no-pure no-rust !)
464 data-length: 121088 (no-pure no-rust !)
465 data-unused: 192 (pure !)
465 data-unused: 192 (pure !)
466 data-unused: 192 (rust !)
466 data-unused: 192 (rust !)
467 data-unused: 0 (no-pure no-rust !)
467 data-unused: 0 (no-pure no-rust !)
468 data-unused: 0.158% (pure !)
468 data-unused: 0.158% (pure !)
469 data-unused: 0.158% (rust !)
469 data-unused: 0.158% (rust !)
470 data-unused: 0.000% (no-pure no-rust !)
470 data-unused: 0.000% (no-pure no-rust !)
471 $ hg debugnodemap --metadata
471 $ hg debugnodemap --metadata
472 uid: ???????? (glob)
472 uid: ???????? (glob)
473 tip-rev: 5004
473 tip-rev: 5004
474 tip-node: 2f5fb1c06a16834c5679d672e90da7c5f3b1a984
474 tip-node: 2f5fb1c06a16834c5679d672e90da7c5f3b1a984
475 data-length: 121280 (pure !)
475 data-length: 121280 (pure !)
476 data-length: 121280 (rust !)
476 data-length: 121280 (rust !)
477 data-length: 121088 (no-pure no-rust !)
477 data-length: 121088 (no-pure no-rust !)
478 data-unused: 192 (pure !)
478 data-unused: 192 (pure !)
479 data-unused: 192 (rust !)
479 data-unused: 192 (rust !)
480 data-unused: 0 (no-pure no-rust !)
480 data-unused: 0 (no-pure no-rust !)
481 data-unused: 0.158% (pure !)
481 data-unused: 0.158% (pure !)
482 data-unused: 0.158% (rust !)
482 data-unused: 0.158% (rust !)
483 data-unused: 0.000% (no-pure no-rust !)
483 data-unused: 0.000% (no-pure no-rust !)
484
484
485 Another process does not see the pending nodemap content during run.
485 Another process does not see the pending nodemap content during run.
486
486
487 $ echo qpoasp > a
487 $ echo qpoasp > a
488 $ hg ci -m a2 \
488 $ hg ci -m a2 \
489 > --config "hooks.pretxnclose=sh \"$RUNTESTDIR/testlib/wait-on-file\" 20 sync-repo-read sync-txn-pending" \
489 > --config "hooks.pretxnclose=sh \"$RUNTESTDIR/testlib/wait-on-file\" 20 sync-repo-read sync-txn-pending" \
490 > --config "hooks.txnclose=touch sync-txn-close" > output.txt 2>&1 &
490 > --config "hooks.txnclose=touch sync-txn-close" > output.txt 2>&1 &
491
491
492 (read the repository while the commit transaction is pending)
492 (read the repository while the commit transaction is pending)
493
493
494 $ sh "$RUNTESTDIR/testlib/wait-on-file" 20 sync-txn-pending && \
494 $ sh "$RUNTESTDIR/testlib/wait-on-file" 20 sync-txn-pending && \
495 > hg debugnodemap --metadata && \
495 > hg debugnodemap --metadata && \
496 > sh "$RUNTESTDIR/testlib/wait-on-file" 20 sync-txn-close sync-repo-read
496 > sh "$RUNTESTDIR/testlib/wait-on-file" 20 sync-txn-close sync-repo-read
497 uid: ???????? (glob)
497 uid: ???????? (glob)
498 tip-rev: 5004
498 tip-rev: 5004
499 tip-node: 2f5fb1c06a16834c5679d672e90da7c5f3b1a984
499 tip-node: 2f5fb1c06a16834c5679d672e90da7c5f3b1a984
500 data-length: 121280 (pure !)
500 data-length: 121280 (pure !)
501 data-length: 121280 (rust !)
501 data-length: 121280 (rust !)
502 data-length: 121088 (no-pure no-rust !)
502 data-length: 121088 (no-pure no-rust !)
503 data-unused: 192 (pure !)
503 data-unused: 192 (pure !)
504 data-unused: 192 (rust !)
504 data-unused: 192 (rust !)
505 data-unused: 0 (no-pure no-rust !)
505 data-unused: 0 (no-pure no-rust !)
506 data-unused: 0.158% (pure !)
506 data-unused: 0.158% (pure !)
507 data-unused: 0.158% (rust !)
507 data-unused: 0.158% (rust !)
508 data-unused: 0.000% (no-pure no-rust !)
508 data-unused: 0.000% (no-pure no-rust !)
509 $ hg debugnodemap --metadata
509 $ hg debugnodemap --metadata
510 uid: ???????? (glob)
510 uid: ???????? (glob)
511 tip-rev: 5005
511 tip-rev: 5005
512 tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe
512 tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe
513 data-length: 121536 (pure !)
513 data-length: 121536 (pure !)
514 data-length: 121536 (rust !)
514 data-length: 121536 (rust !)
515 data-length: 121088 (no-pure no-rust !)
515 data-length: 121088 (no-pure no-rust !)
516 data-unused: 448 (pure !)
516 data-unused: 448 (pure !)
517 data-unused: 448 (rust !)
517 data-unused: 448 (rust !)
518 data-unused: 0 (no-pure no-rust !)
518 data-unused: 0 (no-pure no-rust !)
519 data-unused: 0.369% (pure !)
519 data-unused: 0.369% (pure !)
520 data-unused: 0.369% (rust !)
520 data-unused: 0.369% (rust !)
521 data-unused: 0.000% (no-pure no-rust !)
521 data-unused: 0.000% (no-pure no-rust !)
522
522
523 $ cat output.txt
523 $ cat output.txt
524
524
525 Check that a failing transaction will properly revert the data
525 Check that a failing transaction will properly revert the data
526
526
527 $ echo plakfe > a
527 $ echo plakfe > a
528 $ f --size --sha256 .hg/store/00changelog-*.nd
528 $ f --size --sha256 .hg/store/00changelog-*.nd
529 .hg/store/00changelog-????????.nd: size=121536, sha256=bb414468d225cf52d69132e1237afba34d4346ee2eb81b505027e6197b107f03 (glob) (pure !)
529 .hg/store/00changelog-????????.nd: size=121536, sha256=bb414468d225cf52d69132e1237afba34d4346ee2eb81b505027e6197b107f03 (glob) (pure !)
530 .hg/store/00changelog-????????.nd: size=121536, sha256=909ac727bc4d1c0fda5f7bff3c620c98bd4a2967c143405a1503439e33b377da (glob) (rust !)
530 .hg/store/00changelog-????????.nd: size=121536, sha256=909ac727bc4d1c0fda5f7bff3c620c98bd4a2967c143405a1503439e33b377da (glob) (rust !)
531 .hg/store/00changelog-????????.nd: size=121088, sha256=342d36d30d86dde67d3cb6c002606c4a75bcad665595d941493845066d9c8ee0 (glob) (no-pure no-rust !)
531 .hg/store/00changelog-????????.nd: size=121088, sha256=342d36d30d86dde67d3cb6c002606c4a75bcad665595d941493845066d9c8ee0 (glob) (no-pure no-rust !)
532 $ hg ci -m a3 --config "extensions.abort=$RUNTESTDIR/testlib/crash_transaction_late.py"
532 $ hg ci -m a3 --config "extensions.abort=$RUNTESTDIR/testlib/crash_transaction_late.py"
533 transaction abort!
533 transaction abort!
534 rollback completed
534 rollback completed
535 abort: This is a late abort
535 abort: This is a late abort
536 [255]
536 [255]
537 $ hg debugnodemap --metadata
537 $ hg debugnodemap --metadata
538 uid: ???????? (glob)
538 uid: ???????? (glob)
539 tip-rev: 5005
539 tip-rev: 5005
540 tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe
540 tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe
541 data-length: 121536 (pure !)
541 data-length: 121536 (pure !)
542 data-length: 121536 (rust !)
542 data-length: 121536 (rust !)
543 data-length: 121088 (no-pure no-rust !)
543 data-length: 121088 (no-pure no-rust !)
544 data-unused: 448 (pure !)
544 data-unused: 448 (pure !)
545 data-unused: 448 (rust !)
545 data-unused: 448 (rust !)
546 data-unused: 0 (no-pure no-rust !)
546 data-unused: 0 (no-pure no-rust !)
547 data-unused: 0.369% (pure !)
547 data-unused: 0.369% (pure !)
548 data-unused: 0.369% (rust !)
548 data-unused: 0.369% (rust !)
549 data-unused: 0.000% (no-pure no-rust !)
549 data-unused: 0.000% (no-pure no-rust !)
550 $ f --size --sha256 .hg/store/00changelog-*.nd
550 $ f --size --sha256 .hg/store/00changelog-*.nd
551 .hg/store/00changelog-????????.nd: size=121536, sha256=bb414468d225cf52d69132e1237afba34d4346ee2eb81b505027e6197b107f03 (glob) (pure !)
551 .hg/store/00changelog-????????.nd: size=121536, sha256=bb414468d225cf52d69132e1237afba34d4346ee2eb81b505027e6197b107f03 (glob) (pure !)
552 .hg/store/00changelog-????????.nd: size=121536, sha256=909ac727bc4d1c0fda5f7bff3c620c98bd4a2967c143405a1503439e33b377da (glob) (rust !)
552 .hg/store/00changelog-????????.nd: size=121536, sha256=909ac727bc4d1c0fda5f7bff3c620c98bd4a2967c143405a1503439e33b377da (glob) (rust !)
553 .hg/store/00changelog-????????.nd: size=121088, sha256=342d36d30d86dde67d3cb6c002606c4a75bcad665595d941493845066d9c8ee0 (glob) (no-pure no-rust !)
553 .hg/store/00changelog-????????.nd: size=121088, sha256=342d36d30d86dde67d3cb6c002606c4a75bcad665595d941493845066d9c8ee0 (glob) (no-pure no-rust !)
554
554
555 Check that removing content does not confuse the nodemap
555 Check that removing content does not confuse the nodemap
556 --------------------------------------------------------
556 --------------------------------------------------------
557
557
558 removing data with rollback
558 removing data with rollback
559
559
560 $ echo aso > a
560 $ echo aso > a
561 $ hg ci -m a4
561 $ hg ci -m a4
562 $ hg rollback
562 $ hg rollback
563 repository tip rolled back to revision 5005 (undo commit)
563 repository tip rolled back to revision 5005 (undo commit)
564 working directory now based on revision 5005
564 working directory now based on revision 5005
565 $ hg id -r .
565 $ hg id -r .
566 90d5d3ba2fc4 tip
566 90d5d3ba2fc4 tip
567
567
568 removing data with strip
568 removing data with strip
569
569
570 $ echo aso > a
570 $ echo aso > a
571 $ hg ci -m a4
571 $ hg ci -m a4
572 $ hg --config extensions.strip= strip -r . --no-backup
572 $ hg --config extensions.strip= strip -r . --no-backup
573 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
573 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
574 $ hg id -r . --traceback
574 $ hg id -r . --traceback
575 90d5d3ba2fc4 tip
575 90d5d3ba2fc4 tip
576
576
577 (be a good citizen and regenerate the nodemap)
577 (be a good citizen and regenerate the nodemap)
578 $ hg debugupdatecaches
578 $ hg debugupdatecaches
579 $ hg debugnodemap --metadata
579 $ hg debugnodemap --metadata
580 uid: * (glob)
580 uid: * (glob)
581 tip-rev: 5005
581 tip-rev: 5005
582 tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe
582 tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe
583 data-length: 121088
583 data-length: 121088
584 data-unused: 0
584 data-unused: 0
585 data-unused: 0.000%
585 data-unused: 0.000%
586
586
587 Check race condition when multiple process write new data to the repository
587 Check race condition when multiple process write new data to the repository
588 ---------------------------------------------------------------------------
588 ---------------------------------------------------------------------------
589
589
590 In this test, we check that two writers touching the repositories will not
590 In this test, we check that two writers touching the repositories will not
591 overwrite each other data. This test is prompted by the existent of issue6554.
591 overwrite each other data. This test is prompted by the existent of issue6554.
592 Where a writer ended up using and outdated docket to update the repository. See
592 Where a writer ended up using and outdated docket to update the repository. See
593 the dedicated extension for details on the race windows and read/write schedule
593 the dedicated extension for details on the race windows and read/write schedule
594 necessary to end up in this situation: testlib/persistent-nodemap-race-ext.py
594 necessary to end up in this situation: testlib/persistent-nodemap-race-ext.py
595
595
596 The issue was initially observed on a server with a high push trafic, but it
596 The issue was initially observed on a server with a high push trafic, but it
597 can be reproduced using a share and two commiting process which seems simpler.
597 can be reproduced using a share and two commiting process which seems simpler.
598
598
599 The test is Rust only as the other implementation does not use the same
599 The test is Rust only as the other implementation does not use the same
600 read/write patterns.
600 read/write patterns.
601
601
602 $ cd ..
602 $ cd ..
603
603
604 #if rust
604 #if rust
605
605
606 $ cp -R test-repo race-repo
606 $ cp -R test-repo race-repo
607 $ hg share race-repo ./other-wc --config format.use-share-safe=yes
607 $ hg share race-repo ./other-wc --config format.use-share-safe=yes
608 updating working directory
608 updating working directory
609 5001 files updated, 0 files merged, 0 files removed, 0 files unresolved
609 5001 files updated, 0 files merged, 0 files removed, 0 files unresolved
610 $ hg debugformat -R ./race-repo | egrep 'share-safe|persistent-nodemap'
610 $ hg debugformat -R ./race-repo | egrep 'share-safe|persistent-nodemap'
611 share-safe: yes
611 share-safe: yes
612 persistent-nodemap: yes
612 persistent-nodemap: yes
613 $ hg debugformat -R ./other-wc/ | egrep 'share-safe|persistent-nodemap'
613 $ hg debugformat -R ./other-wc/ | egrep 'share-safe|persistent-nodemap'
614 share-safe: yes
614 share-safe: yes
615 persistent-nodemap: yes
615 persistent-nodemap: yes
616 $ hg -R ./other-wc update 'min(head())'
616 $ hg -R ./other-wc update 'min(head())'
617 3 files updated, 0 files merged, 2 files removed, 0 files unresolved
617 3 files updated, 0 files merged, 2 files removed, 0 files unresolved
618 $ hg -R ./race-repo debugnodemap --metadata
618 $ hg -R ./race-repo debugnodemap --metadata
619 uid: 43c37dde
619 uid: 43c37dde
620 tip-rev: 5005
620 tip-rev: 5005
621 tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe
621 tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe
622 data-length: 121088
622 data-length: 121088
623 data-unused: 0
623 data-unused: 0
624 data-unused: 0.000%
624 data-unused: 0.000%
625 $ hg -R ./race-repo log -G -r 'head()'
625 $ hg -R ./race-repo log -G -r 'head()'
626 @ changeset: 5005:90d5d3ba2fc4
626 @ changeset: 5005:90d5d3ba2fc4
627 | tag: tip
627 | tag: tip
628 ~ user: test
628 ~ user: test
629 date: Thu Jan 01 00:00:00 1970 +0000
629 date: Thu Jan 01 00:00:00 1970 +0000
630 summary: a2
630 summary: a2
631
631
632 o changeset: 5001:16395c3cf7e2
632 o changeset: 5001:16395c3cf7e2
633 | user: test
633 | user: test
634 ~ date: Thu Jan 01 00:00:00 1970 +0000
634 ~ date: Thu Jan 01 00:00:00 1970 +0000
635 summary: foo
635 summary: foo
636
636
637 $ hg -R ./other-wc log -G -r 'head()'
637 $ hg -R ./other-wc log -G -r 'head()'
638 o changeset: 5005:90d5d3ba2fc4
638 o changeset: 5005:90d5d3ba2fc4
639 | tag: tip
639 | tag: tip
640 ~ user: test
640 ~ user: test
641 date: Thu Jan 01 00:00:00 1970 +0000
641 date: Thu Jan 01 00:00:00 1970 +0000
642 summary: a2
642 summary: a2
643
643
644 @ changeset: 5001:16395c3cf7e2
644 @ changeset: 5001:16395c3cf7e2
645 | user: test
645 | user: test
646 ~ date: Thu Jan 01 00:00:00 1970 +0000
646 ~ date: Thu Jan 01 00:00:00 1970 +0000
647 summary: foo
647 summary: foo
648
648
649 $ echo left-side-race > race-repo/left-side-race
649 $ echo left-side-race > race-repo/left-side-race
650 $ hg -R ./race-repo/ add race-repo/left-side-race
650 $ hg -R ./race-repo/ add race-repo/left-side-race
651
651
652 $ echo right-side-race > ./other-wc/right-side-race
652 $ echo right-side-race > ./other-wc/right-side-race
653 $ hg -R ./other-wc/ add ./other-wc/right-side-race
653 $ hg -R ./other-wc/ add ./other-wc/right-side-race
654
654
655 $ mkdir sync-files
655 $ mkdir sync-files
656 $ mkdir outputs
656 $ mkdir outputs
657 $ (
657 $ (
658 > hg -R ./race-repo/ commit -m left-side-commit \
658 > hg -R ./race-repo/ commit -m left-side-commit \
659 > --config "extensions.race=${RUNTESTDIR}/testlib/persistent-nodemap-race-ext.py" \
659 > --config "extensions.race=${RUNTESTDIR}/testlib/persistent-nodemap-race-ext.py" \
660 > --config 'devel.nodemap-race.role=left';
660 > --config 'devel.nodemap-race.role=left';
661 > touch sync-files/left-done
661 > touch sync-files/left-done
662 > ) > outputs/left.txt 2>&1 &
662 > ) > outputs/left.txt 2>&1 &
663 $ (
663 $ (
664 > hg -R ./other-wc/ commit -m right-side-commit \
664 > hg -R ./other-wc/ commit -m right-side-commit \
665 > --config "extensions.race=${RUNTESTDIR}/testlib/persistent-nodemap-race-ext.py" \
665 > --config "extensions.race=${RUNTESTDIR}/testlib/persistent-nodemap-race-ext.py" \
666 > --config 'devel.nodemap-race.role=right';
666 > --config 'devel.nodemap-race.role=right';
667 > touch sync-files/right-done
667 > touch sync-files/right-done
668 > ) > outputs/right.txt 2>&1 &
668 > ) > outputs/right.txt 2>&1 &
669 $ (
669 $ (
670 > hg -R ./race-repo/ check-nodemap-race \
670 > hg -R ./race-repo/ check-nodemap-race \
671 > --config "extensions.race=${RUNTESTDIR}/testlib/persistent-nodemap-race-ext.py" \
671 > --config "extensions.race=${RUNTESTDIR}/testlib/persistent-nodemap-race-ext.py" \
672 > --config 'devel.nodemap-race.role=reader';
672 > --config 'devel.nodemap-race.role=reader';
673 > touch sync-files/reader-done
673 > touch sync-files/reader-done
674 > ) > outputs/reader.txt 2>&1 &
674 > ) > outputs/reader.txt 2>&1 &
675 $ sh "$RUNTESTDIR"/testlib/wait-on-file 10 sync-files/left-done
675 $ sh "$RUNTESTDIR"/testlib/wait-on-file 10 sync-files/left-done
676 $ cat outputs/left.txt
676 $ cat outputs/left.txt
677 docket-details:
677 docket-details:
678 uid: 43c37dde
678 uid: 43c37dde
679 actual-tip: 5005
679 actual-tip: 5005
680 tip-rev: 5005
680 tip-rev: 5005
681 data-length: 121088
681 data-length: 121088
682 nodemap-race: left side locked and ready to commit
682 nodemap-race: left side locked and ready to commit
683 docket-details:
683 docket-details:
684 uid: 43c37dde
684 uid: 43c37dde
685 actual-tip: 5005
685 actual-tip: 5005
686 tip-rev: 5005
686 tip-rev: 5005
687 data-length: 121088
687 data-length: 121088
688 finalized changelog write
688 finalized changelog write
689 persisting changelog nodemap
689 persisting changelog nodemap
690 new data start at 121088
690 new data start at 121088
691 persisted changelog nodemap
691 persisted changelog nodemap
692 docket-details:
692 docket-details:
693 uid: 43c37dde
693 uid: 43c37dde
694 actual-tip: 5006
694 actual-tip: 5006
695 tip-rev: 5006
695 tip-rev: 5006
696 data-length: 121280
696 data-length: 121280
697 $ sh "$RUNTESTDIR"/testlib/wait-on-file 10 sync-files/right-done
697 $ sh "$RUNTESTDIR"/testlib/wait-on-file 10 sync-files/right-done
698 $ cat outputs/right.txt
698 $ cat outputs/right.txt
699 nodemap-race: right side start of the locking sequence
699 nodemap-race: right side start of the locking sequence
700 nodemap-race: right side reading changelog
700 nodemap-race: right side reading changelog
701 nodemap-race: right side reading of changelog is done
701 nodemap-race: right side reading of changelog is done
702 docket-details:
702 docket-details:
703 uid: 43c37dde
703 uid: 43c37dde
704 actual-tip: 5006
704 actual-tip: 5006
705 tip-rev: 5005
705 tip-rev: 5005
706 data-length: 121088
706 data-length: 121088
707 nodemap-race: right side ready to wait for the lock
707 nodemap-race: right side ready to wait for the lock
708 nodemap-race: right side locked and ready to commit
708 nodemap-race: right side locked and ready to commit
709 docket-details:
709 docket-details:
710 uid: 43c37dde
710 uid: 43c37dde
711 actual-tip: 5006
711 actual-tip: 5006
712 tip-rev: 5006
712 tip-rev: 5006
713 data-length: 121280
713 data-length: 121280
714 right ready to write, waiting for reader
714 right ready to write, waiting for reader
715 right proceeding with writing its changelog index and nodemap
715 right proceeding with writing its changelog index and nodemap
716 finalized changelog write
716 finalized changelog write
717 persisting changelog nodemap
717 persisting changelog nodemap
718 new data start at 121280
718 new data start at 121280
719 persisted changelog nodemap
719 persisted changelog nodemap
720 docket-details:
720 docket-details:
721 uid: 43c37dde
721 uid: 43c37dde
722 actual-tip: 5007
722 actual-tip: 5007
723 tip-rev: 5007
723 tip-rev: 5007
724 data-length: 121536
724 data-length: 121536
725 $ sh "$RUNTESTDIR"/testlib/wait-on-file 10 sync-files/reader-done
725 $ sh "$RUNTESTDIR"/testlib/wait-on-file 10 sync-files/reader-done
726 $ cat outputs/reader.txt
726 $ cat outputs/reader.txt
727 reader: reading changelog
727 reader: reading changelog
728 reader ready to read the changelog, waiting for right
728 reader ready to read the changelog, waiting for right
729 reader: nodemap docket read
729 reader: nodemap docket read
730 record-data-length: 121280
730 record-data-length: 121280
731 actual-data-length: 121280
731 actual-data-length: 121280
732 file-actual-length: 121536
732 file-actual-length: 121536
733 reader: changelog read
733 reader: changelog read
734 docket-details:
734 docket-details:
735 uid: 43c37dde
735 uid: 43c37dde
736 actual-tip: 5006
736 actual-tip: 5006
737 tip-rev: 5006
737 tip-rev: 5006
738 data-length: 121280
738 data-length: 121280
739 tip-rev: 5006
739 tip-rev: 5006
740 tip-node: 492901161367
740 tip-node: 492901161367
741 node-rev: 5006
741 node-rev: 5006
742
742
743 $ hg -R ./race-repo log -G -r 'head()'
743 $ hg -R ./race-repo log -G -r 'head()'
744 o changeset: 5007:ac4a2abde241
744 o changeset: 5007:ac4a2abde241
745 | tag: tip
745 | tag: tip
746 ~ parent: 5001:16395c3cf7e2
746 ~ parent: 5001:16395c3cf7e2
747 user: test
747 user: test
748 date: Thu Jan 01 00:00:00 1970 +0000
748 date: Thu Jan 01 00:00:00 1970 +0000
749 summary: right-side-commit
749 summary: right-side-commit
750
750
751 @ changeset: 5006:492901161367
751 @ changeset: 5006:492901161367
752 | user: test
752 | user: test
753 ~ date: Thu Jan 01 00:00:00 1970 +0000
753 ~ date: Thu Jan 01 00:00:00 1970 +0000
754 summary: left-side-commit
754 summary: left-side-commit
755
755
756 $ hg -R ./other-wc log -G -r 'head()'
756 $ hg -R ./other-wc log -G -r 'head()'
757 @ changeset: 5007:ac4a2abde241
757 @ changeset: 5007:ac4a2abde241
758 | tag: tip
758 | tag: tip
759 ~ parent: 5001:16395c3cf7e2
759 ~ parent: 5001:16395c3cf7e2
760 user: test
760 user: test
761 date: Thu Jan 01 00:00:00 1970 +0000
761 date: Thu Jan 01 00:00:00 1970 +0000
762 summary: right-side-commit
762 summary: right-side-commit
763
763
764 o changeset: 5006:492901161367
764 o changeset: 5006:492901161367
765 | user: test
765 | user: test
766 ~ date: Thu Jan 01 00:00:00 1970 +0000
766 ~ date: Thu Jan 01 00:00:00 1970 +0000
767 summary: left-side-commit
767 summary: left-side-commit
768
768
769 #endif
769 #endif
770
770
771 Test upgrade / downgrade
771 Test upgrade / downgrade
772 ========================
772 ========================
773
773
774 $ cd ./test-repo/
774 $ cd ./test-repo/
775
775
776 downgrading
776 downgrading
777
777
778 $ cat << EOF >> .hg/hgrc
778 $ cat << EOF >> .hg/hgrc
779 > [format]
779 > [format]
780 > use-persistent-nodemap=no
780 > use-persistent-nodemap=no
781 > EOF
781 > EOF
782 $ hg debugformat -v
782 $ hg debugformat -v
783 format-variant repo config default
783 format-variant repo config default
784 fncache: yes yes yes
784 fncache: yes yes yes
785 dirstate-v2: no no no
785 dirstate-v2: no no no
786 tracked-hint: no no no
786 tracked-hint: no no no
787 dotencode: yes yes yes
787 dotencode: yes yes yes
788 generaldelta: yes yes yes
788 generaldelta: yes yes yes
789 share-safe: yes yes yes
789 share-safe: yes yes yes
790 sparserevlog: yes yes yes
790 sparserevlog: yes yes yes
791 persistent-nodemap: yes no no
791 persistent-nodemap: yes no no
792 copies-sdc: no no no
792 copies-sdc: no no no
793 revlog-v2: no no no
793 revlog-v2: no no no
794 changelog-v2: no no no
794 changelog-v2: no no no
795 plain-cl-delta: yes yes yes
795 plain-cl-delta: yes yes yes
796 compression: zlib zlib zlib (no-zstd !)
796 compression: zlib zlib zlib (no-zstd !)
797 compression: zstd zstd zstd (zstd !)
797 compression: zstd zstd zstd (zstd !)
798 compression-level: default default default
798 compression-level: default default default
799 $ hg debugupgraderepo --run --no-backup --quiet
799 $ hg debugupgraderepo --run --no-backup --quiet
800 upgrade will perform the following actions:
800 upgrade will perform the following actions:
801
801
802 requirements
802 requirements
803 preserved: dotencode, fncache, generaldelta, revlogv1, share-safe, sparserevlog, store (no-zstd no-dirstate-v2 !)
803 preserved: dotencode, fncache, generaldelta, revlogv1, share-safe, sparserevlog, store (no-zstd no-dirstate-v2 !)
804 preserved: dotencode, fncache, generaldelta, revlog-compression-zstd, revlogv1, share-safe, sparserevlog, store (zstd no-dirstate-v2 !)
804 preserved: dotencode, fncache, generaldelta, revlog-compression-zstd, revlogv1, share-safe, sparserevlog, store (zstd no-dirstate-v2 !)
805 preserved: dotencode, use-dirstate-v2, fncache, generaldelta, revlog-compression-zstd, revlogv1, share-safe, sparserevlog, store (zstd dirstate-v2 !)
805 preserved: dotencode, use-dirstate-v2, fncache, generaldelta, revlog-compression-zstd, revlogv1, share-safe, sparserevlog, store (zstd dirstate-v2 !)
806 removed: persistent-nodemap
806 removed: persistent-nodemap
807
807
808 processed revlogs:
808 processed revlogs:
809 - all-filelogs
809 - all-filelogs
810 - changelog
810 - changelog
811 - manifest
811 - manifest
812
812
813 $ ls -1 .hg/store/ | egrep '00(changelog|manifest)(\.n|-.*\.nd)'
813 $ ls -1 .hg/store/ | egrep '00(changelog|manifest)(\.n|-.*\.nd)'
814 [1]
814 [1]
815 $ hg debugnodemap --metadata
815 $ hg debugnodemap --metadata
816
816
817
817
818 upgrading
818 upgrading
819
819
820 $ cat << EOF >> .hg/hgrc
820 $ cat << EOF >> .hg/hgrc
821 > [format]
821 > [format]
822 > use-persistent-nodemap=yes
822 > use-persistent-nodemap=yes
823 > EOF
823 > EOF
824 $ hg debugformat -v
824 $ hg debugformat -v
825 format-variant repo config default
825 format-variant repo config default
826 fncache: yes yes yes
826 fncache: yes yes yes
827 dirstate-v2: no no no
827 dirstate-v2: no no no
828 tracked-hint: no no no
828 tracked-hint: no no no
829 dotencode: yes yes yes
829 dotencode: yes yes yes
830 generaldelta: yes yes yes
830 generaldelta: yes yes yes
831 share-safe: yes yes yes
831 share-safe: yes yes yes
832 sparserevlog: yes yes yes
832 sparserevlog: yes yes yes
833 persistent-nodemap: no yes no
833 persistent-nodemap: no yes no
834 copies-sdc: no no no
834 copies-sdc: no no no
835 revlog-v2: no no no
835 revlog-v2: no no no
836 changelog-v2: no no no
836 changelog-v2: no no no
837 plain-cl-delta: yes yes yes
837 plain-cl-delta: yes yes yes
838 compression: zlib zlib zlib (no-zstd !)
838 compression: zlib zlib zlib (no-zstd !)
839 compression: zstd zstd zstd (zstd !)
839 compression: zstd zstd zstd (zstd !)
840 compression-level: default default default
840 compression-level: default default default
841 $ hg debugupgraderepo --run --no-backup --quiet
841 $ hg debugupgraderepo --run --no-backup --quiet
842 upgrade will perform the following actions:
842 upgrade will perform the following actions:
843
843
844 requirements
844 requirements
845 preserved: dotencode, fncache, generaldelta, revlogv1, share-safe, sparserevlog, store (no-zstd no-dirstate-v2 !)
845 preserved: dotencode, fncache, generaldelta, revlogv1, share-safe, sparserevlog, store (no-zstd no-dirstate-v2 !)
846 preserved: dotencode, fncache, generaldelta, revlog-compression-zstd, revlogv1, share-safe, sparserevlog, store (zstd no-dirstate-v2 !)
846 preserved: dotencode, fncache, generaldelta, revlog-compression-zstd, revlogv1, share-safe, sparserevlog, store (zstd no-dirstate-v2 !)
847 preserved: dotencode, use-dirstate-v2, fncache, generaldelta, revlog-compression-zstd, revlogv1, share-safe, sparserevlog, store (zstd dirstate-v2 !)
847 preserved: dotencode, use-dirstate-v2, fncache, generaldelta, revlog-compression-zstd, revlogv1, share-safe, sparserevlog, store (zstd dirstate-v2 !)
848 added: persistent-nodemap
848 added: persistent-nodemap
849
849
850 processed revlogs:
850 processed revlogs:
851 - all-filelogs
851 - all-filelogs
852 - changelog
852 - changelog
853 - manifest
853 - manifest
854
854
855 $ ls -1 .hg/store/ | egrep '00(changelog|manifest)(\.n|-.*\.nd)'
855 $ ls -1 .hg/store/ | egrep '00(changelog|manifest)(\.n|-.*\.nd)'
856 00changelog-*.nd (glob)
856 00changelog-*.nd (glob)
857 00changelog.n
857 00changelog.n
858 00manifest-*.nd (glob)
858 00manifest-*.nd (glob)
859 00manifest.n
859 00manifest.n
860
860
861 $ hg debugnodemap --metadata
861 $ hg debugnodemap --metadata
862 uid: * (glob)
862 uid: * (glob)
863 tip-rev: 5005
863 tip-rev: 5005
864 tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe
864 tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe
865 data-length: 121088
865 data-length: 121088
866 data-unused: 0
866 data-unused: 0
867 data-unused: 0.000%
867 data-unused: 0.000%
868
868
869 Running unrelated upgrade
869 Running unrelated upgrade
870
870
871 $ hg debugupgraderepo --run --no-backup --quiet --optimize re-delta-all
871 $ hg debugupgraderepo --run --no-backup --quiet --optimize re-delta-all
872 upgrade will perform the following actions:
872 upgrade will perform the following actions:
873
873
874 requirements
874 requirements
875 preserved: dotencode, fncache, generaldelta, persistent-nodemap, revlogv1, share-safe, sparserevlog, store (no-zstd no-dirstate-v2 !)
875 preserved: dotencode, fncache, generaldelta, persistent-nodemap, revlogv1, share-safe, sparserevlog, store (no-zstd no-dirstate-v2 !)
876 preserved: dotencode, fncache, generaldelta, persistent-nodemap, revlog-compression-zstd, revlogv1, share-safe, sparserevlog, store (zstd no-dirstate-v2 !)
876 preserved: dotencode, fncache, generaldelta, persistent-nodemap, revlog-compression-zstd, revlogv1, share-safe, sparserevlog, store (zstd no-dirstate-v2 !)
877 preserved: dotencode, use-dirstate-v2, fncache, generaldelta, persistent-nodemap, revlog-compression-zstd, revlogv1, share-safe, sparserevlog, store (zstd dirstate-v2 !)
877 preserved: dotencode, use-dirstate-v2, fncache, generaldelta, persistent-nodemap, revlog-compression-zstd, revlogv1, share-safe, sparserevlog, store (zstd dirstate-v2 !)
878
878
879 optimisations: re-delta-all
879 optimisations: re-delta-all
880
880
881 processed revlogs:
881 processed revlogs:
882 - all-filelogs
882 - all-filelogs
883 - changelog
883 - changelog
884 - manifest
884 - manifest
885
885
886 $ ls -1 .hg/store/ | egrep '00(changelog|manifest)(\.n|-.*\.nd)'
886 $ ls -1 .hg/store/ | egrep '00(changelog|manifest)(\.n|-.*\.nd)'
887 00changelog-*.nd (glob)
887 00changelog-*.nd (glob)
888 00changelog.n
888 00changelog.n
889 00manifest-*.nd (glob)
889 00manifest-*.nd (glob)
890 00manifest.n
890 00manifest.n
891
891
892 $ hg debugnodemap --metadata
892 $ hg debugnodemap --metadata
893 uid: * (glob)
893 uid: * (glob)
894 tip-rev: 5005
894 tip-rev: 5005
895 tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe
895 tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe
896 data-length: 121088
896 data-length: 121088
897 data-unused: 0
897 data-unused: 0
898 data-unused: 0.000%
898 data-unused: 0.000%
899
899
900 Persistent nodemap and local/streaming clone
900 Persistent nodemap and local/streaming clone
901 ============================================
901 ============================================
902
902
903 $ cd ..
903 $ cd ..
904
904
905 standard clone
905 standard clone
906 --------------
906 --------------
907
907
908 The persistent nodemap should exist after a streaming clone
908 The persistent nodemap should exist after a streaming clone
909
909
910 $ hg clone --pull --quiet -U test-repo standard-clone
910 $ hg clone --pull --quiet -U test-repo standard-clone
911 $ ls -1 standard-clone/.hg/store/ | egrep '00(changelog|manifest)(\.n|-.*\.nd)'
911 $ ls -1 standard-clone/.hg/store/ | egrep '00(changelog|manifest)(\.n|-.*\.nd)'
912 00changelog-*.nd (glob)
912 00changelog-*.nd (glob)
913 00changelog.n
913 00changelog.n
914 00manifest-*.nd (glob)
914 00manifest-*.nd (glob)
915 00manifest.n
915 00manifest.n
916 $ hg -R standard-clone debugnodemap --metadata
916 $ hg -R standard-clone debugnodemap --metadata
917 uid: * (glob)
917 uid: * (glob)
918 tip-rev: 5005
918 tip-rev: 5005
919 tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe
919 tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe
920 data-length: 121088
920 data-length: 121088
921 data-unused: 0
921 data-unused: 0
922 data-unused: 0.000%
922 data-unused: 0.000%
923
923
924
924
925 local clone
925 local clone
926 ------------
926 ------------
927
927
928 The persistent nodemap should exist after a streaming clone
928 The persistent nodemap should exist after a streaming clone
929
929
930 $ hg clone -U test-repo local-clone
930 $ hg clone -U test-repo local-clone
931 $ ls -1 local-clone/.hg/store/ | egrep '00(changelog|manifest)(\.n|-.*\.nd)'
931 $ ls -1 local-clone/.hg/store/ | egrep '00(changelog|manifest)(\.n|-.*\.nd)'
932 00changelog-*.nd (glob)
932 00changelog-*.nd (glob)
933 00changelog.n
933 00changelog.n
934 00manifest-*.nd (glob)
934 00manifest-*.nd (glob)
935 00manifest.n
935 00manifest.n
936 $ hg -R local-clone debugnodemap --metadata
936 $ hg -R local-clone debugnodemap --metadata
937 uid: * (glob)
937 uid: * (glob)
938 tip-rev: 5005
938 tip-rev: 5005
939 tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe
939 tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe
940 data-length: 121088
940 data-length: 121088
941 data-unused: 0
941 data-unused: 0
942 data-unused: 0.000%
942 data-unused: 0.000%
943
943
944 Test various corruption case
944 Test various corruption case
945 ============================
945 ============================
946
946
947 Missing datafile
947 Missing datafile
948 ----------------
948 ----------------
949
949
950 Test behavior with a missing datafile
950 Test behavior with a missing datafile
951
951
952 $ hg clone --quiet --pull test-repo corruption-test-repo
952 $ hg clone --quiet --pull test-repo corruption-test-repo
953 $ ls -1 corruption-test-repo/.hg/store/00changelog*
953 $ ls -1 corruption-test-repo/.hg/store/00changelog*
954 corruption-test-repo/.hg/store/00changelog-*.nd (glob)
954 corruption-test-repo/.hg/store/00changelog-*.nd (glob)
955 corruption-test-repo/.hg/store/00changelog.d
955 corruption-test-repo/.hg/store/00changelog.d
956 corruption-test-repo/.hg/store/00changelog.i
956 corruption-test-repo/.hg/store/00changelog.i
957 corruption-test-repo/.hg/store/00changelog.n
957 corruption-test-repo/.hg/store/00changelog.n
958 $ rm corruption-test-repo/.hg/store/00changelog*.nd
958 $ rm corruption-test-repo/.hg/store/00changelog*.nd
959 $ hg log -R corruption-test-repo -r .
959 $ hg log -R corruption-test-repo -r .
960 changeset: 5005:90d5d3ba2fc4
960 changeset: 5005:90d5d3ba2fc4
961 tag: tip
961 tag: tip
962 user: test
962 user: test
963 date: Thu Jan 01 00:00:00 1970 +0000
963 date: Thu Jan 01 00:00:00 1970 +0000
964 summary: a2
964 summary: a2
965
965
966 $ ls -1 corruption-test-repo/.hg/store/00changelog*
966 $ ls -1 corruption-test-repo/.hg/store/00changelog*
967 corruption-test-repo/.hg/store/00changelog.d
967 corruption-test-repo/.hg/store/00changelog.d
968 corruption-test-repo/.hg/store/00changelog.i
968 corruption-test-repo/.hg/store/00changelog.i
969 corruption-test-repo/.hg/store/00changelog.n
969 corruption-test-repo/.hg/store/00changelog.n
970
970
971 Truncated data file
971 Truncated data file
972 -------------------
972 -------------------
973
973
974 Test behavior with a too short datafile
974 Test behavior with a too short datafile
975
975
976 rebuild the missing data
976 rebuild the missing data
977 $ hg -R corruption-test-repo debugupdatecache
977 $ hg -R corruption-test-repo debugupdatecache
978 $ ls -1 corruption-test-repo/.hg/store/00changelog*
978 $ ls -1 corruption-test-repo/.hg/store/00changelog*
979 corruption-test-repo/.hg/store/00changelog-*.nd (glob)
979 corruption-test-repo/.hg/store/00changelog-*.nd (glob)
980 corruption-test-repo/.hg/store/00changelog.d
980 corruption-test-repo/.hg/store/00changelog.d
981 corruption-test-repo/.hg/store/00changelog.i
981 corruption-test-repo/.hg/store/00changelog.i
982 corruption-test-repo/.hg/store/00changelog.n
982 corruption-test-repo/.hg/store/00changelog.n
983
983
984 truncate the file
984 truncate the file
985
985
986 $ datafilepath=`ls corruption-test-repo/.hg/store/00changelog*.nd`
986 $ datafilepath=`ls corruption-test-repo/.hg/store/00changelog*.nd`
987 $ f -s $datafilepath
987 $ f -s $datafilepath
988 corruption-test-repo/.hg/store/00changelog-*.nd: size=121088 (glob)
988 corruption-test-repo/.hg/store/00changelog-*.nd: size=121088 (glob)
989 $ dd if=$datafilepath bs=1000 count=10 of=$datafilepath-tmp
989 $ dd if=$datafilepath bs=1000 count=10 of=$datafilepath-tmp
990 10+0 records in
990 10+0 records in
991 10+0 records out
991 10+0 records out
992 * bytes * (glob)
992 * bytes * (glob)
993 $ mv $datafilepath-tmp $datafilepath
993 $ mv $datafilepath-tmp $datafilepath
994 $ f -s $datafilepath
994 $ f -s $datafilepath
995 corruption-test-repo/.hg/store/00changelog-*.nd: size=10000 (glob)
995 corruption-test-repo/.hg/store/00changelog-*.nd: size=10000 (glob)
996
996
997 Check that Mercurial reaction to this event
997 Check that Mercurial reaction to this event
998
998
999 $ hg -R corruption-test-repo log -r . --traceback
999 $ hg -R corruption-test-repo log -r . --traceback
1000 changeset: 5005:90d5d3ba2fc4
1000 changeset: 5005:90d5d3ba2fc4
1001 tag: tip
1001 tag: tip
1002 user: test
1002 user: test
1003 date: Thu Jan 01 00:00:00 1970 +0000
1003 date: Thu Jan 01 00:00:00 1970 +0000
1004 summary: a2
1004 summary: a2
1005
1005
1006
1006
1007
1007
1008 stream clone
1008 stream clone
1009 ============
1009 ============
1010
1010
1011 The persistent nodemap should exist after a streaming clone
1011 The persistent nodemap should exist after a streaming clone
1012
1012
1013 Simple case
1013 Simple case
1014 -----------
1014 -----------
1015
1015
1016 No race condition
1016 No race condition
1017
1017
1018 $ hg clone -U --stream ssh://user@dummy/test-repo stream-clone --debug | egrep '00(changelog|manifest)'
1018 $ hg clone -U --stream ssh://user@dummy/test-repo stream-clone --debug | egrep '00(changelog|manifest)'
1019 adding [s] 00manifest.n (62 bytes)
1019 adding [s] 00manifest.n (62 bytes)
1020 adding [s] 00manifest-*.nd (118 KB) (glob)
1020 adding [s] 00manifest-*.nd (118 KB) (glob)
1021 adding [s] 00manifest.d (491 KB) (zstd no-bigendian !)
1022 adding [s] 00manifest.d (452 KB) (no-zstd !)
1023 adding [s] 00manifest.d (492 KB) (zstd bigendian !)
1024 adding [s] 00manifest.i (313 KB)
1021 adding [s] 00changelog.n (62 bytes)
1025 adding [s] 00changelog.n (62 bytes)
1022 adding [s] 00changelog-*.nd (118 KB) (glob)
1026 adding [s] 00changelog-*.nd (118 KB) (glob)
1023 adding [s] 00manifest.d (452 KB) (no-zstd !)
1024 adding [s] 00manifest.d (491 KB) (zstd no-bigendian !)
1025 adding [s] 00manifest.d (492 KB) (zstd bigendian !)
1026 adding [s] 00changelog.d (360 KB) (no-zstd !)
1027 adding [s] 00changelog.d (360 KB) (no-zstd !)
1027 adding [s] 00changelog.d (368 KB) (zstd !)
1028 adding [s] 00changelog.d (368 KB) (zstd !)
1028 adding [s] 00manifest.i (313 KB)
1029 adding [s] 00changelog.i (313 KB)
1029 adding [s] 00changelog.i (313 KB)
1030 $ ls -1 stream-clone/.hg/store/ | egrep '00(changelog|manifest)(\.n|-.*\.nd)'
1030 $ ls -1 stream-clone/.hg/store/ | egrep '00(changelog|manifest)(\.n|-.*\.nd)'
1031 00changelog-*.nd (glob)
1031 00changelog-*.nd (glob)
1032 00changelog.n
1032 00changelog.n
1033 00manifest-*.nd (glob)
1033 00manifest-*.nd (glob)
1034 00manifest.n
1034 00manifest.n
1035 $ hg -R stream-clone debugnodemap --metadata
1035 $ hg -R stream-clone debugnodemap --metadata
1036 uid: * (glob)
1036 uid: * (glob)
1037 tip-rev: 5005
1037 tip-rev: 5005
1038 tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe
1038 tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe
1039 data-length: 121088
1039 data-length: 121088
1040 data-unused: 0
1040 data-unused: 0
1041 data-unused: 0.000%
1041 data-unused: 0.000%
1042
1042
1043 new data appened
1043 new data appened
1044 -----------------
1044 -----------------
1045
1045
1046 Other commit happening on the server during the stream clone
1046 Other commit happening on the server during the stream clone
1047
1047
1048 setup the step-by-step stream cloning
1048 setup the step-by-step stream cloning
1049
1049
1050 $ HG_TEST_STREAM_WALKED_FILE_1="$TESTTMP/sync_file_walked_1"
1050 $ HG_TEST_STREAM_WALKED_FILE_1="$TESTTMP/sync_file_walked_1"
1051 $ export HG_TEST_STREAM_WALKED_FILE_1
1051 $ export HG_TEST_STREAM_WALKED_FILE_1
1052 $ HG_TEST_STREAM_WALKED_FILE_2="$TESTTMP/sync_file_walked_2"
1052 $ HG_TEST_STREAM_WALKED_FILE_2="$TESTTMP/sync_file_walked_2"
1053 $ export HG_TEST_STREAM_WALKED_FILE_2
1053 $ export HG_TEST_STREAM_WALKED_FILE_2
1054 $ HG_TEST_STREAM_WALKED_FILE_3="$TESTTMP/sync_file_walked_3"
1054 $ HG_TEST_STREAM_WALKED_FILE_3="$TESTTMP/sync_file_walked_3"
1055 $ export HG_TEST_STREAM_WALKED_FILE_3
1055 $ export HG_TEST_STREAM_WALKED_FILE_3
1056 $ cat << EOF >> test-repo/.hg/hgrc
1056 $ cat << EOF >> test-repo/.hg/hgrc
1057 > [extensions]
1057 > [extensions]
1058 > steps=$RUNTESTDIR/testlib/ext-stream-clone-steps.py
1058 > steps=$RUNTESTDIR/testlib/ext-stream-clone-steps.py
1059 > EOF
1059 > EOF
1060
1060
1061 Check and record file state beforehand
1061 Check and record file state beforehand
1062
1062
1063 $ f --size test-repo/.hg/store/00changelog*
1063 $ f --size test-repo/.hg/store/00changelog*
1064 test-repo/.hg/store/00changelog-*.nd: size=121088 (glob)
1064 test-repo/.hg/store/00changelog-*.nd: size=121088 (glob)
1065 test-repo/.hg/store/00changelog.d: size=376891 (zstd no-bigendian !)
1065 test-repo/.hg/store/00changelog.d: size=376891 (zstd no-bigendian !)
1066 test-repo/.hg/store/00changelog.d: size=376889 (zstd bigendian !)
1066 test-repo/.hg/store/00changelog.d: size=376889 (zstd bigendian !)
1067 test-repo/.hg/store/00changelog.d: size=368890 (no-zstd !)
1067 test-repo/.hg/store/00changelog.d: size=368890 (no-zstd !)
1068 test-repo/.hg/store/00changelog.i: size=320384
1068 test-repo/.hg/store/00changelog.i: size=320384
1069 test-repo/.hg/store/00changelog.n: size=62
1069 test-repo/.hg/store/00changelog.n: size=62
1070 $ hg -R test-repo debugnodemap --metadata | tee server-metadata.txt
1070 $ hg -R test-repo debugnodemap --metadata | tee server-metadata.txt
1071 uid: * (glob)
1071 uid: * (glob)
1072 tip-rev: 5005
1072 tip-rev: 5005
1073 tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe
1073 tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe
1074 data-length: 121088
1074 data-length: 121088
1075 data-unused: 0
1075 data-unused: 0
1076 data-unused: 0.000%
1076 data-unused: 0.000%
1077
1077
1078 Prepare a commit
1078 Prepare a commit
1079
1079
1080 $ echo foo >> test-repo/foo
1080 $ echo foo >> test-repo/foo
1081 $ hg -R test-repo/ add test-repo/foo
1081 $ hg -R test-repo/ add test-repo/foo
1082
1082
1083 Do a mix of clone and commit at the same time so that the file listed on disk differ at actual transfer time.
1083 Do a mix of clone and commit at the same time so that the file listed on disk differ at actual transfer time.
1084
1084
1085 $ (hg clone -U --stream ssh://user@dummy/test-repo stream-clone-race-1 --debug 2>> clone-output | egrep '00(changelog|manifest)' >> clone-output; touch $HG_TEST_STREAM_WALKED_FILE_3) &
1085 $ (hg clone -U --stream ssh://user@dummy/test-repo stream-clone-race-1 --debug 2>> clone-output | egrep '00(changelog|manifest)' >> clone-output; touch $HG_TEST_STREAM_WALKED_FILE_3) &
1086 $ $RUNTESTDIR/testlib/wait-on-file 10 $HG_TEST_STREAM_WALKED_FILE_1
1086 $ $RUNTESTDIR/testlib/wait-on-file 10 $HG_TEST_STREAM_WALKED_FILE_1
1087 $ hg -R test-repo/ commit -m foo
1087 $ hg -R test-repo/ commit -m foo
1088 $ touch $HG_TEST_STREAM_WALKED_FILE_2
1088 $ touch $HG_TEST_STREAM_WALKED_FILE_2
1089 $ $RUNTESTDIR/testlib/wait-on-file 10 $HG_TEST_STREAM_WALKED_FILE_3
1089 $ $RUNTESTDIR/testlib/wait-on-file 10 $HG_TEST_STREAM_WALKED_FILE_3
1090 $ cat clone-output
1090 $ cat clone-output
1091 adding [s] 00manifest.n (62 bytes)
1091 adding [s] 00manifest.n (62 bytes)
1092 adding [s] 00manifest-*.nd (118 KB) (glob)
1092 adding [s] 00manifest-*.nd (118 KB) (glob)
1093 adding [s] 00manifest.d (491 KB) (zstd no-bigendian !)
1094 adding [s] 00manifest.d (452 KB) (no-zstd !)
1095 adding [s] 00manifest.d (492 KB) (zstd bigendian !)
1096 adding [s] 00manifest.i (313 KB)
1093 adding [s] 00changelog.n (62 bytes)
1097 adding [s] 00changelog.n (62 bytes)
1094 adding [s] 00changelog-*.nd (118 KB) (glob)
1098 adding [s] 00changelog-*.nd (118 KB) (glob)
1095 adding [s] 00manifest.d (452 KB) (no-zstd !)
1099 adding [s] 00changelog.d (368 KB) (zstd !)
1096 adding [s] 00manifest.d (491 KB) (zstd no-bigendian !)
1097 adding [s] 00manifest.d (492 KB) (zstd bigendian !)
1098 adding [s] 00changelog.d (360 KB) (no-zstd !)
1100 adding [s] 00changelog.d (360 KB) (no-zstd !)
1099 adding [s] 00changelog.d (368 KB) (zstd !)
1100 adding [s] 00manifest.i (313 KB)
1101 adding [s] 00changelog.i (313 KB)
1101 adding [s] 00changelog.i (313 KB)
1102
1102
1103 Check the result state
1103 Check the result state
1104
1104
1105 $ f --size stream-clone-race-1/.hg/store/00changelog*
1105 $ f --size stream-clone-race-1/.hg/store/00changelog*
1106 stream-clone-race-1/.hg/store/00changelog-*.nd: size=121088 (glob)
1106 stream-clone-race-1/.hg/store/00changelog-*.nd: size=121088 (glob)
1107 stream-clone-race-1/.hg/store/00changelog.d: size=368890 (no-zstd !)
1107 stream-clone-race-1/.hg/store/00changelog.d: size=368890 (no-zstd !)
1108 stream-clone-race-1/.hg/store/00changelog.d: size=376891 (zstd no-bigendian !)
1108 stream-clone-race-1/.hg/store/00changelog.d: size=376891 (zstd no-bigendian !)
1109 stream-clone-race-1/.hg/store/00changelog.d: size=376889 (zstd bigendian !)
1109 stream-clone-race-1/.hg/store/00changelog.d: size=376889 (zstd bigendian !)
1110 stream-clone-race-1/.hg/store/00changelog.i: size=320384
1110 stream-clone-race-1/.hg/store/00changelog.i: size=320384
1111 stream-clone-race-1/.hg/store/00changelog.n: size=62
1111 stream-clone-race-1/.hg/store/00changelog.n: size=62
1112
1112
1113 $ hg -R stream-clone-race-1 debugnodemap --metadata | tee client-metadata.txt
1113 $ hg -R stream-clone-race-1 debugnodemap --metadata | tee client-metadata.txt
1114 uid: * (glob)
1114 uid: * (glob)
1115 tip-rev: 5005
1115 tip-rev: 5005
1116 tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe
1116 tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe
1117 data-length: 121088
1117 data-length: 121088
1118 data-unused: 0
1118 data-unused: 0
1119 data-unused: 0.000%
1119 data-unused: 0.000%
1120
1120
1121 We get a usable nodemap, so no rewrite would be needed and the metadata should be identical
1121 We get a usable nodemap, so no rewrite would be needed and the metadata should be identical
1122 (ie: the following diff should be empty)
1122 (ie: the following diff should be empty)
1123
1123
1124 This isn't the case for the `no-rust` `no-pure` implementation as it use a very minimal nodemap implementation that unconditionnaly rewrite the nodemap "all the time".
1124 This isn't the case for the `no-rust` `no-pure` implementation as it use a very minimal nodemap implementation that unconditionnaly rewrite the nodemap "all the time".
1125
1125
1126 #if no-rust no-pure
1126 #if no-rust no-pure
1127 $ diff -u server-metadata.txt client-metadata.txt
1127 $ diff -u server-metadata.txt client-metadata.txt
1128 --- server-metadata.txt * (glob)
1128 --- server-metadata.txt * (glob)
1129 +++ client-metadata.txt * (glob)
1129 +++ client-metadata.txt * (glob)
1130 @@ -1,4 +1,4 @@
1130 @@ -1,4 +1,4 @@
1131 -uid: * (glob)
1131 -uid: * (glob)
1132 +uid: * (glob)
1132 +uid: * (glob)
1133 tip-rev: 5005
1133 tip-rev: 5005
1134 tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe
1134 tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe
1135 data-length: 121088
1135 data-length: 121088
1136 [1]
1136 [1]
1137 #else
1137 #else
1138 $ diff -u server-metadata.txt client-metadata.txt
1138 $ diff -u server-metadata.txt client-metadata.txt
1139 #endif
1139 #endif
1140
1140
1141
1141
1142 Clean up after the test.
1142 Clean up after the test.
1143
1143
1144 $ rm -f "$HG_TEST_STREAM_WALKED_FILE_1"
1144 $ rm -f "$HG_TEST_STREAM_WALKED_FILE_1"
1145 $ rm -f "$HG_TEST_STREAM_WALKED_FILE_2"
1145 $ rm -f "$HG_TEST_STREAM_WALKED_FILE_2"
1146 $ rm -f "$HG_TEST_STREAM_WALKED_FILE_3"
1146 $ rm -f "$HG_TEST_STREAM_WALKED_FILE_3"
1147
1147
1148 full regeneration
1148 full regeneration
1149 -----------------
1149 -----------------
1150
1150
1151 A full nodemap is generated
1151 A full nodemap is generated
1152
1152
1153 (ideally this test would append enough data to make sure the nodemap data file
1153 (ideally this test would append enough data to make sure the nodemap data file
1154 get changed, however to make thing simpler we will force the regeneration for
1154 get changed, however to make thing simpler we will force the regeneration for
1155 this test.
1155 this test.
1156
1156
1157 Check the initial state
1157 Check the initial state
1158
1158
1159 $ f --size test-repo/.hg/store/00changelog*
1159 $ f --size test-repo/.hg/store/00changelog*
1160 test-repo/.hg/store/00changelog-*.nd: size=121344 (glob) (rust !)
1160 test-repo/.hg/store/00changelog-*.nd: size=121344 (glob) (rust !)
1161 test-repo/.hg/store/00changelog-*.nd: size=121344 (glob) (pure !)
1161 test-repo/.hg/store/00changelog-*.nd: size=121344 (glob) (pure !)
1162 test-repo/.hg/store/00changelog-*.nd: size=121152 (glob) (no-rust no-pure !)
1162 test-repo/.hg/store/00changelog-*.nd: size=121152 (glob) (no-rust no-pure !)
1163 test-repo/.hg/store/00changelog.d: size=376950 (zstd no-bigendian !)
1163 test-repo/.hg/store/00changelog.d: size=376950 (zstd no-bigendian !)
1164 test-repo/.hg/store/00changelog.d: size=376948 (zstd bigendian !)
1164 test-repo/.hg/store/00changelog.d: size=376948 (zstd bigendian !)
1165 test-repo/.hg/store/00changelog.d: size=368949 (no-zstd !)
1165 test-repo/.hg/store/00changelog.d: size=368949 (no-zstd !)
1166 test-repo/.hg/store/00changelog.i: size=320448
1166 test-repo/.hg/store/00changelog.i: size=320448
1167 test-repo/.hg/store/00changelog.n: size=62
1167 test-repo/.hg/store/00changelog.n: size=62
1168 $ hg -R test-repo debugnodemap --metadata | tee server-metadata-2.txt
1168 $ hg -R test-repo debugnodemap --metadata | tee server-metadata-2.txt
1169 uid: * (glob)
1169 uid: * (glob)
1170 tip-rev: 5006
1170 tip-rev: 5006
1171 tip-node: ed2ec1eef9aa2a0ec5057c51483bc148d03e810b
1171 tip-node: ed2ec1eef9aa2a0ec5057c51483bc148d03e810b
1172 data-length: 121344 (rust !)
1172 data-length: 121344 (rust !)
1173 data-length: 121344 (pure !)
1173 data-length: 121344 (pure !)
1174 data-length: 121152 (no-rust no-pure !)
1174 data-length: 121152 (no-rust no-pure !)
1175 data-unused: 192 (rust !)
1175 data-unused: 192 (rust !)
1176 data-unused: 192 (pure !)
1176 data-unused: 192 (pure !)
1177 data-unused: 0 (no-rust no-pure !)
1177 data-unused: 0 (no-rust no-pure !)
1178 data-unused: 0.158% (rust !)
1178 data-unused: 0.158% (rust !)
1179 data-unused: 0.158% (pure !)
1179 data-unused: 0.158% (pure !)
1180 data-unused: 0.000% (no-rust no-pure !)
1180 data-unused: 0.000% (no-rust no-pure !)
1181
1181
1182 Performe the mix of clone and full refresh of the nodemap, so that the files
1182 Performe the mix of clone and full refresh of the nodemap, so that the files
1183 (and filenames) are different between listing time and actual transfer time.
1183 (and filenames) are different between listing time and actual transfer time.
1184
1184
1185 $ (hg clone -U --stream ssh://user@dummy/test-repo stream-clone-race-2 --debug 2>> clone-output-2 | egrep '00(changelog|manifest)' >> clone-output-2; touch $HG_TEST_STREAM_WALKED_FILE_3) &
1185 $ (hg clone -U --stream ssh://user@dummy/test-repo stream-clone-race-2 --debug 2>> clone-output-2 | egrep '00(changelog|manifest)' >> clone-output-2; touch $HG_TEST_STREAM_WALKED_FILE_3) &
1186 $ $RUNTESTDIR/testlib/wait-on-file 10 $HG_TEST_STREAM_WALKED_FILE_1
1186 $ $RUNTESTDIR/testlib/wait-on-file 10 $HG_TEST_STREAM_WALKED_FILE_1
1187 $ rm test-repo/.hg/store/00changelog.n
1187 $ rm test-repo/.hg/store/00changelog.n
1188 $ rm test-repo/.hg/store/00changelog-*.nd
1188 $ rm test-repo/.hg/store/00changelog-*.nd
1189 $ hg -R test-repo/ debugupdatecache
1189 $ hg -R test-repo/ debugupdatecache
1190 $ touch $HG_TEST_STREAM_WALKED_FILE_2
1190 $ touch $HG_TEST_STREAM_WALKED_FILE_2
1191 $ $RUNTESTDIR/testlib/wait-on-file 10 $HG_TEST_STREAM_WALKED_FILE_3
1191 $ $RUNTESTDIR/testlib/wait-on-file 10 $HG_TEST_STREAM_WALKED_FILE_3
1192
1192
1193 (note: the stream clone code wronly pick the `undo.` files)
1193 (note: the stream clone code wronly pick the `undo.` files)
1194
1194
1195 $ cat clone-output-2
1195 $ cat clone-output-2
1196 adding [s] 00manifest.n (62 bytes)
1196 adding [s] 00manifest.n (62 bytes)
1197 adding [s] 00manifest-*.nd (118 KB) (glob)
1197 adding [s] 00manifest-*.nd (118 KB) (glob)
1198 adding [s] 00changelog.n (62 bytes)
1199 adding [s] 00changelog-*.nd (118 KB) (glob)
1200 adding [s] 00manifest.d (492 KB) (zstd !)
1198 adding [s] 00manifest.d (492 KB) (zstd !)
1201 adding [s] 00manifest.d (452 KB) (no-zstd !)
1199 adding [s] 00manifest.d (452 KB) (no-zstd !)
1200 adding [s] 00manifest.i (313 KB)
1201 adding [s] 00changelog.n (62 bytes)
1202 adding [s] 00changelog-*.nd (118 KB) (glob)
1202 adding [s] 00changelog.d (360 KB) (no-zstd !)
1203 adding [s] 00changelog.d (360 KB) (no-zstd !)
1203 adding [s] 00changelog.d (368 KB) (zstd !)
1204 adding [s] 00changelog.d (368 KB) (zstd !)
1204 adding [s] 00manifest.i (313 KB)
1205 adding [s] 00changelog.i (313 KB)
1205 adding [s] 00changelog.i (313 KB)
1206
1206
1207 Check the result.
1207 Check the result.
1208
1208
1209 $ f --size stream-clone-race-2/.hg/store/00changelog*
1209 $ f --size stream-clone-race-2/.hg/store/00changelog*
1210 stream-clone-race-2/.hg/store/00changelog-*.nd: size=121344 (glob) (rust !)
1210 stream-clone-race-2/.hg/store/00changelog-*.nd: size=121344 (glob) (rust !)
1211 stream-clone-race-2/.hg/store/00changelog-*.nd: size=121344 (glob) (pure !)
1211 stream-clone-race-2/.hg/store/00changelog-*.nd: size=121344 (glob) (pure !)
1212 stream-clone-race-2/.hg/store/00changelog-*.nd: size=121152 (glob) (no-rust no-pure !)
1212 stream-clone-race-2/.hg/store/00changelog-*.nd: size=121152 (glob) (no-rust no-pure !)
1213 stream-clone-race-2/.hg/store/00changelog.d: size=376950 (zstd no-bigendian !)
1213 stream-clone-race-2/.hg/store/00changelog.d: size=376950 (zstd no-bigendian !)
1214 stream-clone-race-2/.hg/store/00changelog.d: size=376948 (zstd bigendian !)
1214 stream-clone-race-2/.hg/store/00changelog.d: size=376948 (zstd bigendian !)
1215 stream-clone-race-2/.hg/store/00changelog.d: size=368949 (no-zstd !)
1215 stream-clone-race-2/.hg/store/00changelog.d: size=368949 (no-zstd !)
1216 stream-clone-race-2/.hg/store/00changelog.i: size=320448
1216 stream-clone-race-2/.hg/store/00changelog.i: size=320448
1217 stream-clone-race-2/.hg/store/00changelog.n: size=62
1217 stream-clone-race-2/.hg/store/00changelog.n: size=62
1218
1218
1219 $ hg -R stream-clone-race-2 debugnodemap --metadata | tee client-metadata-2.txt
1219 $ hg -R stream-clone-race-2 debugnodemap --metadata | tee client-metadata-2.txt
1220 uid: * (glob)
1220 uid: * (glob)
1221 tip-rev: 5006
1221 tip-rev: 5006
1222 tip-node: ed2ec1eef9aa2a0ec5057c51483bc148d03e810b
1222 tip-node: ed2ec1eef9aa2a0ec5057c51483bc148d03e810b
1223 data-length: 121344 (rust !)
1223 data-length: 121344 (rust !)
1224 data-unused: 192 (rust !)
1224 data-unused: 192 (rust !)
1225 data-unused: 0.158% (rust !)
1225 data-unused: 0.158% (rust !)
1226 data-length: 121152 (no-rust no-pure !)
1226 data-length: 121152 (no-rust no-pure !)
1227 data-unused: 0 (no-rust no-pure !)
1227 data-unused: 0 (no-rust no-pure !)
1228 data-unused: 0.000% (no-rust no-pure !)
1228 data-unused: 0.000% (no-rust no-pure !)
1229 data-length: 121344 (pure !)
1229 data-length: 121344 (pure !)
1230 data-unused: 192 (pure !)
1230 data-unused: 192 (pure !)
1231 data-unused: 0.158% (pure !)
1231 data-unused: 0.158% (pure !)
1232
1232
1233 We get a usable nodemap, so no rewrite would be needed and the metadata should be identical
1233 We get a usable nodemap, so no rewrite would be needed and the metadata should be identical
1234 (ie: the following diff should be empty)
1234 (ie: the following diff should be empty)
1235
1235
1236 This isn't the case for the `no-rust` `no-pure` implementation as it use a very minimal nodemap implementation that unconditionnaly rewrite the nodemap "all the time".
1236 This isn't the case for the `no-rust` `no-pure` implementation as it use a very minimal nodemap implementation that unconditionnaly rewrite the nodemap "all the time".
1237
1237
1238 #if no-rust no-pure
1238 #if no-rust no-pure
1239 $ diff -u server-metadata-2.txt client-metadata-2.txt
1239 $ diff -u server-metadata-2.txt client-metadata-2.txt
1240 --- server-metadata-2.txt * (glob)
1240 --- server-metadata-2.txt * (glob)
1241 +++ client-metadata-2.txt * (glob)
1241 +++ client-metadata-2.txt * (glob)
1242 @@ -1,4 +1,4 @@
1242 @@ -1,4 +1,4 @@
1243 -uid: * (glob)
1243 -uid: * (glob)
1244 +uid: * (glob)
1244 +uid: * (glob)
1245 tip-rev: 5006
1245 tip-rev: 5006
1246 tip-node: ed2ec1eef9aa2a0ec5057c51483bc148d03e810b
1246 tip-node: ed2ec1eef9aa2a0ec5057c51483bc148d03e810b
1247 data-length: 121152
1247 data-length: 121152
1248 [1]
1248 [1]
1249 #else
1249 #else
1250 $ diff -u server-metadata-2.txt client-metadata-2.txt
1250 $ diff -u server-metadata-2.txt client-metadata-2.txt
1251 #endif
1251 #endif
1252
1252
1253 Clean up after the test
1253 Clean up after the test
1254
1254
1255 $ rm -f $HG_TEST_STREAM_WALKED_FILE_1
1255 $ rm -f $HG_TEST_STREAM_WALKED_FILE_1
1256 $ rm -f $HG_TEST_STREAM_WALKED_FILE_2
1256 $ rm -f $HG_TEST_STREAM_WALKED_FILE_2
1257 $ rm -f $HG_TEST_STREAM_WALKED_FILE_3
1257 $ rm -f $HG_TEST_STREAM_WALKED_FILE_3
1258
1258
General Comments 0
You need to be logged in to leave comments. Login now