##// END OF EJS Templates
persistent-nodemap: also exchange the nodemap data over the wire...
marmoute -
r47040:7c1367c0 default
parent child Browse files
Show More
@@ -1,746 +1,750 b''
1 # store.py - repository store handling for Mercurial
1 # store.py - repository store handling for Mercurial
2 #
2 #
3 # Copyright 2008 Matt Mackall <mpm@selenic.com>
3 # Copyright 2008 Matt Mackall <mpm@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 from __future__ import absolute_import
8 from __future__ import absolute_import
9
9
10 import errno
10 import errno
11 import functools
11 import functools
12 import os
12 import os
13 import stat
13 import stat
14
14
15 from .i18n import _
15 from .i18n import _
16 from .pycompat import getattr
16 from .pycompat import getattr
17 from .node import hex
17 from .node import hex
18 from . import (
18 from . import (
19 changelog,
19 changelog,
20 error,
20 error,
21 manifest,
21 manifest,
22 policy,
22 policy,
23 pycompat,
23 pycompat,
24 util,
24 util,
25 vfs as vfsmod,
25 vfs as vfsmod,
26 )
26 )
27 from .utils import hashutil
27 from .utils import hashutil
28
28
29 parsers = policy.importmod('parsers')
29 parsers = policy.importmod('parsers')
30 # how much bytes should be read from fncache in one read
30 # how much bytes should be read from fncache in one read
31 # It is done to prevent loading large fncache files into memory
31 # It is done to prevent loading large fncache files into memory
32 fncache_chunksize = 10 ** 6
32 fncache_chunksize = 10 ** 6
33
33
34
34
35 def _matchtrackedpath(path, matcher):
35 def _matchtrackedpath(path, matcher):
36 """parses a fncache entry and returns whether the entry is tracking a path
36 """parses a fncache entry and returns whether the entry is tracking a path
37 matched by matcher or not.
37 matched by matcher or not.
38
38
39 If matcher is None, returns True"""
39 If matcher is None, returns True"""
40
40
41 if matcher is None:
41 if matcher is None:
42 return True
42 return True
43 path = decodedir(path)
43 path = decodedir(path)
44 if path.startswith(b'data/'):
44 if path.startswith(b'data/'):
45 return matcher(path[len(b'data/') : -len(b'.i')])
45 return matcher(path[len(b'data/') : -len(b'.i')])
46 elif path.startswith(b'meta/'):
46 elif path.startswith(b'meta/'):
47 return matcher.visitdir(path[len(b'meta/') : -len(b'/00manifest.i')])
47 return matcher.visitdir(path[len(b'meta/') : -len(b'/00manifest.i')])
48
48
49 raise error.ProgrammingError(b"cannot decode path %s" % path)
49 raise error.ProgrammingError(b"cannot decode path %s" % path)
50
50
51
51
52 # This avoids a collision between a file named foo and a dir named
52 # This avoids a collision between a file named foo and a dir named
53 # foo.i or foo.d
53 # foo.i or foo.d
54 def _encodedir(path):
54 def _encodedir(path):
55 """
55 """
56 >>> _encodedir(b'data/foo.i')
56 >>> _encodedir(b'data/foo.i')
57 'data/foo.i'
57 'data/foo.i'
58 >>> _encodedir(b'data/foo.i/bla.i')
58 >>> _encodedir(b'data/foo.i/bla.i')
59 'data/foo.i.hg/bla.i'
59 'data/foo.i.hg/bla.i'
60 >>> _encodedir(b'data/foo.i.hg/bla.i')
60 >>> _encodedir(b'data/foo.i.hg/bla.i')
61 'data/foo.i.hg.hg/bla.i'
61 'data/foo.i.hg.hg/bla.i'
62 >>> _encodedir(b'data/foo.i\\ndata/foo.i/bla.i\\ndata/foo.i.hg/bla.i\\n')
62 >>> _encodedir(b'data/foo.i\\ndata/foo.i/bla.i\\ndata/foo.i.hg/bla.i\\n')
63 'data/foo.i\\ndata/foo.i.hg/bla.i\\ndata/foo.i.hg.hg/bla.i\\n'
63 'data/foo.i\\ndata/foo.i.hg/bla.i\\ndata/foo.i.hg.hg/bla.i\\n'
64 """
64 """
65 return (
65 return (
66 path.replace(b".hg/", b".hg.hg/")
66 path.replace(b".hg/", b".hg.hg/")
67 .replace(b".i/", b".i.hg/")
67 .replace(b".i/", b".i.hg/")
68 .replace(b".d/", b".d.hg/")
68 .replace(b".d/", b".d.hg/")
69 )
69 )
70
70
71
71
72 encodedir = getattr(parsers, 'encodedir', _encodedir)
72 encodedir = getattr(parsers, 'encodedir', _encodedir)
73
73
74
74
75 def decodedir(path):
75 def decodedir(path):
76 """
76 """
77 >>> decodedir(b'data/foo.i')
77 >>> decodedir(b'data/foo.i')
78 'data/foo.i'
78 'data/foo.i'
79 >>> decodedir(b'data/foo.i.hg/bla.i')
79 >>> decodedir(b'data/foo.i.hg/bla.i')
80 'data/foo.i/bla.i'
80 'data/foo.i/bla.i'
81 >>> decodedir(b'data/foo.i.hg.hg/bla.i')
81 >>> decodedir(b'data/foo.i.hg.hg/bla.i')
82 'data/foo.i.hg/bla.i'
82 'data/foo.i.hg/bla.i'
83 """
83 """
84 if b".hg/" not in path:
84 if b".hg/" not in path:
85 return path
85 return path
86 return (
86 return (
87 path.replace(b".d.hg/", b".d/")
87 path.replace(b".d.hg/", b".d/")
88 .replace(b".i.hg/", b".i/")
88 .replace(b".i.hg/", b".i/")
89 .replace(b".hg.hg/", b".hg/")
89 .replace(b".hg.hg/", b".hg/")
90 )
90 )
91
91
92
92
93 def _reserved():
93 def _reserved():
94 """characters that are problematic for filesystems
94 """characters that are problematic for filesystems
95
95
96 * ascii escapes (0..31)
96 * ascii escapes (0..31)
97 * ascii hi (126..255)
97 * ascii hi (126..255)
98 * windows specials
98 * windows specials
99
99
100 these characters will be escaped by encodefunctions
100 these characters will be escaped by encodefunctions
101 """
101 """
102 winreserved = [ord(x) for x in u'\\:*?"<>|']
102 winreserved = [ord(x) for x in u'\\:*?"<>|']
103 for x in range(32):
103 for x in range(32):
104 yield x
104 yield x
105 for x in range(126, 256):
105 for x in range(126, 256):
106 yield x
106 yield x
107 for x in winreserved:
107 for x in winreserved:
108 yield x
108 yield x
109
109
110
110
111 def _buildencodefun():
111 def _buildencodefun():
112 """
112 """
113 >>> enc, dec = _buildencodefun()
113 >>> enc, dec = _buildencodefun()
114
114
115 >>> enc(b'nothing/special.txt')
115 >>> enc(b'nothing/special.txt')
116 'nothing/special.txt'
116 'nothing/special.txt'
117 >>> dec(b'nothing/special.txt')
117 >>> dec(b'nothing/special.txt')
118 'nothing/special.txt'
118 'nothing/special.txt'
119
119
120 >>> enc(b'HELLO')
120 >>> enc(b'HELLO')
121 '_h_e_l_l_o'
121 '_h_e_l_l_o'
122 >>> dec(b'_h_e_l_l_o')
122 >>> dec(b'_h_e_l_l_o')
123 'HELLO'
123 'HELLO'
124
124
125 >>> enc(b'hello:world?')
125 >>> enc(b'hello:world?')
126 'hello~3aworld~3f'
126 'hello~3aworld~3f'
127 >>> dec(b'hello~3aworld~3f')
127 >>> dec(b'hello~3aworld~3f')
128 'hello:world?'
128 'hello:world?'
129
129
130 >>> enc(b'the\\x07quick\\xADshot')
130 >>> enc(b'the\\x07quick\\xADshot')
131 'the~07quick~adshot'
131 'the~07quick~adshot'
132 >>> dec(b'the~07quick~adshot')
132 >>> dec(b'the~07quick~adshot')
133 'the\\x07quick\\xadshot'
133 'the\\x07quick\\xadshot'
134 """
134 """
135 e = b'_'
135 e = b'_'
136 xchr = pycompat.bytechr
136 xchr = pycompat.bytechr
137 asciistr = list(map(xchr, range(127)))
137 asciistr = list(map(xchr, range(127)))
138 capitals = list(range(ord(b"A"), ord(b"Z") + 1))
138 capitals = list(range(ord(b"A"), ord(b"Z") + 1))
139
139
140 cmap = {x: x for x in asciistr}
140 cmap = {x: x for x in asciistr}
141 for x in _reserved():
141 for x in _reserved():
142 cmap[xchr(x)] = b"~%02x" % x
142 cmap[xchr(x)] = b"~%02x" % x
143 for x in capitals + [ord(e)]:
143 for x in capitals + [ord(e)]:
144 cmap[xchr(x)] = e + xchr(x).lower()
144 cmap[xchr(x)] = e + xchr(x).lower()
145
145
146 dmap = {}
146 dmap = {}
147 for k, v in pycompat.iteritems(cmap):
147 for k, v in pycompat.iteritems(cmap):
148 dmap[v] = k
148 dmap[v] = k
149
149
150 def decode(s):
150 def decode(s):
151 i = 0
151 i = 0
152 while i < len(s):
152 while i < len(s):
153 for l in pycompat.xrange(1, 4):
153 for l in pycompat.xrange(1, 4):
154 try:
154 try:
155 yield dmap[s[i : i + l]]
155 yield dmap[s[i : i + l]]
156 i += l
156 i += l
157 break
157 break
158 except KeyError:
158 except KeyError:
159 pass
159 pass
160 else:
160 else:
161 raise KeyError
161 raise KeyError
162
162
163 return (
163 return (
164 lambda s: b''.join(
164 lambda s: b''.join(
165 [cmap[s[c : c + 1]] for c in pycompat.xrange(len(s))]
165 [cmap[s[c : c + 1]] for c in pycompat.xrange(len(s))]
166 ),
166 ),
167 lambda s: b''.join(list(decode(s))),
167 lambda s: b''.join(list(decode(s))),
168 )
168 )
169
169
170
170
171 _encodefname, _decodefname = _buildencodefun()
171 _encodefname, _decodefname = _buildencodefun()
172
172
173
173
174 def encodefilename(s):
174 def encodefilename(s):
175 """
175 """
176 >>> encodefilename(b'foo.i/bar.d/bla.hg/hi:world?/HELLO')
176 >>> encodefilename(b'foo.i/bar.d/bla.hg/hi:world?/HELLO')
177 'foo.i.hg/bar.d.hg/bla.hg.hg/hi~3aworld~3f/_h_e_l_l_o'
177 'foo.i.hg/bar.d.hg/bla.hg.hg/hi~3aworld~3f/_h_e_l_l_o'
178 """
178 """
179 return _encodefname(encodedir(s))
179 return _encodefname(encodedir(s))
180
180
181
181
182 def decodefilename(s):
182 def decodefilename(s):
183 """
183 """
184 >>> decodefilename(b'foo.i.hg/bar.d.hg/bla.hg.hg/hi~3aworld~3f/_h_e_l_l_o')
184 >>> decodefilename(b'foo.i.hg/bar.d.hg/bla.hg.hg/hi~3aworld~3f/_h_e_l_l_o')
185 'foo.i/bar.d/bla.hg/hi:world?/HELLO'
185 'foo.i/bar.d/bla.hg/hi:world?/HELLO'
186 """
186 """
187 return decodedir(_decodefname(s))
187 return decodedir(_decodefname(s))
188
188
189
189
190 def _buildlowerencodefun():
190 def _buildlowerencodefun():
191 """
191 """
192 >>> f = _buildlowerencodefun()
192 >>> f = _buildlowerencodefun()
193 >>> f(b'nothing/special.txt')
193 >>> f(b'nothing/special.txt')
194 'nothing/special.txt'
194 'nothing/special.txt'
195 >>> f(b'HELLO')
195 >>> f(b'HELLO')
196 'hello'
196 'hello'
197 >>> f(b'hello:world?')
197 >>> f(b'hello:world?')
198 'hello~3aworld~3f'
198 'hello~3aworld~3f'
199 >>> f(b'the\\x07quick\\xADshot')
199 >>> f(b'the\\x07quick\\xADshot')
200 'the~07quick~adshot'
200 'the~07quick~adshot'
201 """
201 """
202 xchr = pycompat.bytechr
202 xchr = pycompat.bytechr
203 cmap = {xchr(x): xchr(x) for x in pycompat.xrange(127)}
203 cmap = {xchr(x): xchr(x) for x in pycompat.xrange(127)}
204 for x in _reserved():
204 for x in _reserved():
205 cmap[xchr(x)] = b"~%02x" % x
205 cmap[xchr(x)] = b"~%02x" % x
206 for x in range(ord(b"A"), ord(b"Z") + 1):
206 for x in range(ord(b"A"), ord(b"Z") + 1):
207 cmap[xchr(x)] = xchr(x).lower()
207 cmap[xchr(x)] = xchr(x).lower()
208
208
209 def lowerencode(s):
209 def lowerencode(s):
210 return b"".join([cmap[c] for c in pycompat.iterbytestr(s)])
210 return b"".join([cmap[c] for c in pycompat.iterbytestr(s)])
211
211
212 return lowerencode
212 return lowerencode
213
213
214
214
215 lowerencode = getattr(parsers, 'lowerencode', None) or _buildlowerencodefun()
215 lowerencode = getattr(parsers, 'lowerencode', None) or _buildlowerencodefun()
216
216
217 # Windows reserved names: con, prn, aux, nul, com1..com9, lpt1..lpt9
217 # Windows reserved names: con, prn, aux, nul, com1..com9, lpt1..lpt9
218 _winres3 = (b'aux', b'con', b'prn', b'nul') # length 3
218 _winres3 = (b'aux', b'con', b'prn', b'nul') # length 3
219 _winres4 = (b'com', b'lpt') # length 4 (with trailing 1..9)
219 _winres4 = (b'com', b'lpt') # length 4 (with trailing 1..9)
220
220
221
221
222 def _auxencode(path, dotencode):
222 def _auxencode(path, dotencode):
223 """
223 """
224 Encodes filenames containing names reserved by Windows or which end in
224 Encodes filenames containing names reserved by Windows or which end in
225 period or space. Does not touch other single reserved characters c.
225 period or space. Does not touch other single reserved characters c.
226 Specifically, c in '\\:*?"<>|' or ord(c) <= 31 are *not* encoded here.
226 Specifically, c in '\\:*?"<>|' or ord(c) <= 31 are *not* encoded here.
227 Additionally encodes space or period at the beginning, if dotencode is
227 Additionally encodes space or period at the beginning, if dotencode is
228 True. Parameter path is assumed to be all lowercase.
228 True. Parameter path is assumed to be all lowercase.
229 A segment only needs encoding if a reserved name appears as a
229 A segment only needs encoding if a reserved name appears as a
230 basename (e.g. "aux", "aux.foo"). A directory or file named "foo.aux"
230 basename (e.g. "aux", "aux.foo"). A directory or file named "foo.aux"
231 doesn't need encoding.
231 doesn't need encoding.
232
232
233 >>> s = b'.foo/aux.txt/txt.aux/con/prn/nul/foo.'
233 >>> s = b'.foo/aux.txt/txt.aux/con/prn/nul/foo.'
234 >>> _auxencode(s.split(b'/'), True)
234 >>> _auxencode(s.split(b'/'), True)
235 ['~2efoo', 'au~78.txt', 'txt.aux', 'co~6e', 'pr~6e', 'nu~6c', 'foo~2e']
235 ['~2efoo', 'au~78.txt', 'txt.aux', 'co~6e', 'pr~6e', 'nu~6c', 'foo~2e']
236 >>> s = b'.com1com2/lpt9.lpt4.lpt1/conprn/com0/lpt0/foo.'
236 >>> s = b'.com1com2/lpt9.lpt4.lpt1/conprn/com0/lpt0/foo.'
237 >>> _auxencode(s.split(b'/'), False)
237 >>> _auxencode(s.split(b'/'), False)
238 ['.com1com2', 'lp~749.lpt4.lpt1', 'conprn', 'com0', 'lpt0', 'foo~2e']
238 ['.com1com2', 'lp~749.lpt4.lpt1', 'conprn', 'com0', 'lpt0', 'foo~2e']
239 >>> _auxencode([b'foo. '], True)
239 >>> _auxencode([b'foo. '], True)
240 ['foo.~20']
240 ['foo.~20']
241 >>> _auxencode([b' .foo'], True)
241 >>> _auxencode([b' .foo'], True)
242 ['~20.foo']
242 ['~20.foo']
243 """
243 """
244 for i, n in enumerate(path):
244 for i, n in enumerate(path):
245 if not n:
245 if not n:
246 continue
246 continue
247 if dotencode and n[0] in b'. ':
247 if dotencode and n[0] in b'. ':
248 n = b"~%02x" % ord(n[0:1]) + n[1:]
248 n = b"~%02x" % ord(n[0:1]) + n[1:]
249 path[i] = n
249 path[i] = n
250 else:
250 else:
251 l = n.find(b'.')
251 l = n.find(b'.')
252 if l == -1:
252 if l == -1:
253 l = len(n)
253 l = len(n)
254 if (l == 3 and n[:3] in _winres3) or (
254 if (l == 3 and n[:3] in _winres3) or (
255 l == 4
255 l == 4
256 and n[3:4] <= b'9'
256 and n[3:4] <= b'9'
257 and n[3:4] >= b'1'
257 and n[3:4] >= b'1'
258 and n[:3] in _winres4
258 and n[:3] in _winres4
259 ):
259 ):
260 # encode third letter ('aux' -> 'au~78')
260 # encode third letter ('aux' -> 'au~78')
261 ec = b"~%02x" % ord(n[2:3])
261 ec = b"~%02x" % ord(n[2:3])
262 n = n[0:2] + ec + n[3:]
262 n = n[0:2] + ec + n[3:]
263 path[i] = n
263 path[i] = n
264 if n[-1] in b'. ':
264 if n[-1] in b'. ':
265 # encode last period or space ('foo...' -> 'foo..~2e')
265 # encode last period or space ('foo...' -> 'foo..~2e')
266 path[i] = n[:-1] + b"~%02x" % ord(n[-1:])
266 path[i] = n[:-1] + b"~%02x" % ord(n[-1:])
267 return path
267 return path
268
268
269
269
270 _maxstorepathlen = 120
270 _maxstorepathlen = 120
271 _dirprefixlen = 8
271 _dirprefixlen = 8
272 _maxshortdirslen = 8 * (_dirprefixlen + 1) - 4
272 _maxshortdirslen = 8 * (_dirprefixlen + 1) - 4
273
273
274
274
275 def _hashencode(path, dotencode):
275 def _hashencode(path, dotencode):
276 digest = hex(hashutil.sha1(path).digest())
276 digest = hex(hashutil.sha1(path).digest())
277 le = lowerencode(path[5:]).split(b'/') # skips prefix 'data/' or 'meta/'
277 le = lowerencode(path[5:]).split(b'/') # skips prefix 'data/' or 'meta/'
278 parts = _auxencode(le, dotencode)
278 parts = _auxencode(le, dotencode)
279 basename = parts[-1]
279 basename = parts[-1]
280 _root, ext = os.path.splitext(basename)
280 _root, ext = os.path.splitext(basename)
281 sdirs = []
281 sdirs = []
282 sdirslen = 0
282 sdirslen = 0
283 for p in parts[:-1]:
283 for p in parts[:-1]:
284 d = p[:_dirprefixlen]
284 d = p[:_dirprefixlen]
285 if d[-1] in b'. ':
285 if d[-1] in b'. ':
286 # Windows can't access dirs ending in period or space
286 # Windows can't access dirs ending in period or space
287 d = d[:-1] + b'_'
287 d = d[:-1] + b'_'
288 if sdirslen == 0:
288 if sdirslen == 0:
289 t = len(d)
289 t = len(d)
290 else:
290 else:
291 t = sdirslen + 1 + len(d)
291 t = sdirslen + 1 + len(d)
292 if t > _maxshortdirslen:
292 if t > _maxshortdirslen:
293 break
293 break
294 sdirs.append(d)
294 sdirs.append(d)
295 sdirslen = t
295 sdirslen = t
296 dirs = b'/'.join(sdirs)
296 dirs = b'/'.join(sdirs)
297 if len(dirs) > 0:
297 if len(dirs) > 0:
298 dirs += b'/'
298 dirs += b'/'
299 res = b'dh/' + dirs + digest + ext
299 res = b'dh/' + dirs + digest + ext
300 spaceleft = _maxstorepathlen - len(res)
300 spaceleft = _maxstorepathlen - len(res)
301 if spaceleft > 0:
301 if spaceleft > 0:
302 filler = basename[:spaceleft]
302 filler = basename[:spaceleft]
303 res = b'dh/' + dirs + filler + digest + ext
303 res = b'dh/' + dirs + filler + digest + ext
304 return res
304 return res
305
305
306
306
307 def _hybridencode(path, dotencode):
307 def _hybridencode(path, dotencode):
308 """encodes path with a length limit
308 """encodes path with a length limit
309
309
310 Encodes all paths that begin with 'data/', according to the following.
310 Encodes all paths that begin with 'data/', according to the following.
311
311
312 Default encoding (reversible):
312 Default encoding (reversible):
313
313
314 Encodes all uppercase letters 'X' as '_x'. All reserved or illegal
314 Encodes all uppercase letters 'X' as '_x'. All reserved or illegal
315 characters are encoded as '~xx', where xx is the two digit hex code
315 characters are encoded as '~xx', where xx is the two digit hex code
316 of the character (see encodefilename).
316 of the character (see encodefilename).
317 Relevant path components consisting of Windows reserved filenames are
317 Relevant path components consisting of Windows reserved filenames are
318 masked by encoding the third character ('aux' -> 'au~78', see _auxencode).
318 masked by encoding the third character ('aux' -> 'au~78', see _auxencode).
319
319
320 Hashed encoding (not reversible):
320 Hashed encoding (not reversible):
321
321
322 If the default-encoded path is longer than _maxstorepathlen, a
322 If the default-encoded path is longer than _maxstorepathlen, a
323 non-reversible hybrid hashing of the path is done instead.
323 non-reversible hybrid hashing of the path is done instead.
324 This encoding uses up to _dirprefixlen characters of all directory
324 This encoding uses up to _dirprefixlen characters of all directory
325 levels of the lowerencoded path, but not more levels than can fit into
325 levels of the lowerencoded path, but not more levels than can fit into
326 _maxshortdirslen.
326 _maxshortdirslen.
327 Then follows the filler followed by the sha digest of the full path.
327 Then follows the filler followed by the sha digest of the full path.
328 The filler is the beginning of the basename of the lowerencoded path
328 The filler is the beginning of the basename of the lowerencoded path
329 (the basename is everything after the last path separator). The filler
329 (the basename is everything after the last path separator). The filler
330 is as long as possible, filling in characters from the basename until
330 is as long as possible, filling in characters from the basename until
331 the encoded path has _maxstorepathlen characters (or all chars of the
331 the encoded path has _maxstorepathlen characters (or all chars of the
332 basename have been taken).
332 basename have been taken).
333 The extension (e.g. '.i' or '.d') is preserved.
333 The extension (e.g. '.i' or '.d') is preserved.
334
334
335 The string 'data/' at the beginning is replaced with 'dh/', if the hashed
335 The string 'data/' at the beginning is replaced with 'dh/', if the hashed
336 encoding was used.
336 encoding was used.
337 """
337 """
338 path = encodedir(path)
338 path = encodedir(path)
339 ef = _encodefname(path).split(b'/')
339 ef = _encodefname(path).split(b'/')
340 res = b'/'.join(_auxencode(ef, dotencode))
340 res = b'/'.join(_auxencode(ef, dotencode))
341 if len(res) > _maxstorepathlen:
341 if len(res) > _maxstorepathlen:
342 res = _hashencode(path, dotencode)
342 res = _hashencode(path, dotencode)
343 return res
343 return res
344
344
345
345
346 def _pathencode(path):
346 def _pathencode(path):
347 de = encodedir(path)
347 de = encodedir(path)
348 if len(path) > _maxstorepathlen:
348 if len(path) > _maxstorepathlen:
349 return _hashencode(de, True)
349 return _hashencode(de, True)
350 ef = _encodefname(de).split(b'/')
350 ef = _encodefname(de).split(b'/')
351 res = b'/'.join(_auxencode(ef, True))
351 res = b'/'.join(_auxencode(ef, True))
352 if len(res) > _maxstorepathlen:
352 if len(res) > _maxstorepathlen:
353 return _hashencode(de, True)
353 return _hashencode(de, True)
354 return res
354 return res
355
355
356
356
357 _pathencode = getattr(parsers, 'pathencode', _pathencode)
357 _pathencode = getattr(parsers, 'pathencode', _pathencode)
358
358
359
359
360 def _plainhybridencode(f):
360 def _plainhybridencode(f):
361 return _hybridencode(f, False)
361 return _hybridencode(f, False)
362
362
363
363
364 def _calcmode(vfs):
364 def _calcmode(vfs):
365 try:
365 try:
366 # files in .hg/ will be created using this mode
366 # files in .hg/ will be created using this mode
367 mode = vfs.stat().st_mode
367 mode = vfs.stat().st_mode
368 # avoid some useless chmods
368 # avoid some useless chmods
369 if (0o777 & ~util.umask) == (0o777 & mode):
369 if (0o777 & ~util.umask) == (0o777 & mode):
370 mode = None
370 mode = None
371 except OSError:
371 except OSError:
372 mode = None
372 mode = None
373 return mode
373 return mode
374
374
375
375
376 _data = [
376 _data = [
377 b'bookmarks',
377 b'bookmarks',
378 b'narrowspec',
378 b'narrowspec',
379 b'data',
379 b'data',
380 b'meta',
380 b'meta',
381 b'00manifest.d',
381 b'00manifest.d',
382 b'00manifest.i',
382 b'00manifest.i',
383 b'00changelog.d',
383 b'00changelog.d',
384 b'00changelog.i',
384 b'00changelog.i',
385 b'phaseroots',
385 b'phaseroots',
386 b'obsstore',
386 b'obsstore',
387 b'requires',
387 b'requires',
388 ]
388 ]
389
389
390
390
391 def isrevlog(f, kind, st):
391 def isrevlog(f, kind, st):
392 return kind == stat.S_IFREG and f[-2:] in (b'.i', b'.d', b'.n', b'.nd')
392 if kind != stat.S_IFREG:
393 return False
394 if f[-2:] in (b'.i', b'.d', b'.n'):
395 return True
396 return f[-3:] == b'.nd'
393
397
394
398
395 class basicstore(object):
399 class basicstore(object):
396 '''base class for local repository stores'''
400 '''base class for local repository stores'''
397
401
398 def __init__(self, path, vfstype):
402 def __init__(self, path, vfstype):
399 vfs = vfstype(path)
403 vfs = vfstype(path)
400 self.path = vfs.base
404 self.path = vfs.base
401 self.createmode = _calcmode(vfs)
405 self.createmode = _calcmode(vfs)
402 vfs.createmode = self.createmode
406 vfs.createmode = self.createmode
403 self.rawvfs = vfs
407 self.rawvfs = vfs
404 self.vfs = vfsmod.filtervfs(vfs, encodedir)
408 self.vfs = vfsmod.filtervfs(vfs, encodedir)
405 self.opener = self.vfs
409 self.opener = self.vfs
406
410
407 def join(self, f):
411 def join(self, f):
408 return self.path + b'/' + encodedir(f)
412 return self.path + b'/' + encodedir(f)
409
413
410 def _walk(self, relpath, recurse, filefilter=isrevlog):
414 def _walk(self, relpath, recurse, filefilter=isrevlog):
411 '''yields (unencoded, encoded, size)'''
415 '''yields (unencoded, encoded, size)'''
412 path = self.path
416 path = self.path
413 if relpath:
417 if relpath:
414 path += b'/' + relpath
418 path += b'/' + relpath
415 striplen = len(self.path) + 1
419 striplen = len(self.path) + 1
416 l = []
420 l = []
417 if self.rawvfs.isdir(path):
421 if self.rawvfs.isdir(path):
418 visit = [path]
422 visit = [path]
419 readdir = self.rawvfs.readdir
423 readdir = self.rawvfs.readdir
420 while visit:
424 while visit:
421 p = visit.pop()
425 p = visit.pop()
422 for f, kind, st in readdir(p, stat=True):
426 for f, kind, st in readdir(p, stat=True):
423 fp = p + b'/' + f
427 fp = p + b'/' + f
424 if filefilter(f, kind, st):
428 if filefilter(f, kind, st):
425 n = util.pconvert(fp[striplen:])
429 n = util.pconvert(fp[striplen:])
426 l.append((decodedir(n), n, st.st_size))
430 l.append((decodedir(n), n, st.st_size))
427 elif kind == stat.S_IFDIR and recurse:
431 elif kind == stat.S_IFDIR and recurse:
428 visit.append(fp)
432 visit.append(fp)
429 l.sort()
433 l.sort()
430 return l
434 return l
431
435
432 def changelog(self, trypending):
436 def changelog(self, trypending):
433 return changelog.changelog(self.vfs, trypending=trypending)
437 return changelog.changelog(self.vfs, trypending=trypending)
434
438
435 def manifestlog(self, repo, storenarrowmatch):
439 def manifestlog(self, repo, storenarrowmatch):
436 rootstore = manifest.manifestrevlog(self.vfs)
440 rootstore = manifest.manifestrevlog(self.vfs)
437 return manifest.manifestlog(self.vfs, repo, rootstore, storenarrowmatch)
441 return manifest.manifestlog(self.vfs, repo, rootstore, storenarrowmatch)
438
442
439 def datafiles(self, matcher=None):
443 def datafiles(self, matcher=None):
440 return self._walk(b'data', True) + self._walk(b'meta', True)
444 return self._walk(b'data', True) + self._walk(b'meta', True)
441
445
442 def topfiles(self):
446 def topfiles(self):
443 # yield manifest before changelog
447 # yield manifest before changelog
444 return reversed(self._walk(b'', False))
448 return reversed(self._walk(b'', False))
445
449
446 def walk(self, matcher=None):
450 def walk(self, matcher=None):
447 """yields (unencoded, encoded, size)
451 """yields (unencoded, encoded, size)
448
452
449 if a matcher is passed, storage files of only those tracked paths
453 if a matcher is passed, storage files of only those tracked paths
450 are passed with matches the matcher
454 are passed with matches the matcher
451 """
455 """
452 # yield data files first
456 # yield data files first
453 for x in self.datafiles(matcher):
457 for x in self.datafiles(matcher):
454 yield x
458 yield x
455 for x in self.topfiles():
459 for x in self.topfiles():
456 yield x
460 yield x
457
461
458 def copylist(self):
462 def copylist(self):
459 return _data
463 return _data
460
464
461 def write(self, tr):
465 def write(self, tr):
462 pass
466 pass
463
467
464 def invalidatecaches(self):
468 def invalidatecaches(self):
465 pass
469 pass
466
470
467 def markremoved(self, fn):
471 def markremoved(self, fn):
468 pass
472 pass
469
473
470 def __contains__(self, path):
474 def __contains__(self, path):
471 '''Checks if the store contains path'''
475 '''Checks if the store contains path'''
472 path = b"/".join((b"data", path))
476 path = b"/".join((b"data", path))
473 # file?
477 # file?
474 if self.vfs.exists(path + b".i"):
478 if self.vfs.exists(path + b".i"):
475 return True
479 return True
476 # dir?
480 # dir?
477 if not path.endswith(b"/"):
481 if not path.endswith(b"/"):
478 path = path + b"/"
482 path = path + b"/"
479 return self.vfs.exists(path)
483 return self.vfs.exists(path)
480
484
481
485
482 class encodedstore(basicstore):
486 class encodedstore(basicstore):
483 def __init__(self, path, vfstype):
487 def __init__(self, path, vfstype):
484 vfs = vfstype(path + b'/store')
488 vfs = vfstype(path + b'/store')
485 self.path = vfs.base
489 self.path = vfs.base
486 self.createmode = _calcmode(vfs)
490 self.createmode = _calcmode(vfs)
487 vfs.createmode = self.createmode
491 vfs.createmode = self.createmode
488 self.rawvfs = vfs
492 self.rawvfs = vfs
489 self.vfs = vfsmod.filtervfs(vfs, encodefilename)
493 self.vfs = vfsmod.filtervfs(vfs, encodefilename)
490 self.opener = self.vfs
494 self.opener = self.vfs
491
495
492 def datafiles(self, matcher=None):
496 def datafiles(self, matcher=None):
493 for a, b, size in super(encodedstore, self).datafiles():
497 for a, b, size in super(encodedstore, self).datafiles():
494 try:
498 try:
495 a = decodefilename(a)
499 a = decodefilename(a)
496 except KeyError:
500 except KeyError:
497 a = None
501 a = None
498 if a is not None and not _matchtrackedpath(a, matcher):
502 if a is not None and not _matchtrackedpath(a, matcher):
499 continue
503 continue
500 yield a, b, size
504 yield a, b, size
501
505
502 def join(self, f):
506 def join(self, f):
503 return self.path + b'/' + encodefilename(f)
507 return self.path + b'/' + encodefilename(f)
504
508
505 def copylist(self):
509 def copylist(self):
506 return [b'requires', b'00changelog.i'] + [b'store/' + f for f in _data]
510 return [b'requires', b'00changelog.i'] + [b'store/' + f for f in _data]
507
511
508
512
509 class fncache(object):
513 class fncache(object):
510 # the filename used to be partially encoded
514 # the filename used to be partially encoded
511 # hence the encodedir/decodedir dance
515 # hence the encodedir/decodedir dance
512 def __init__(self, vfs):
516 def __init__(self, vfs):
513 self.vfs = vfs
517 self.vfs = vfs
514 self.entries = None
518 self.entries = None
515 self._dirty = False
519 self._dirty = False
516 # set of new additions to fncache
520 # set of new additions to fncache
517 self.addls = set()
521 self.addls = set()
518
522
519 def ensureloaded(self, warn=None):
523 def ensureloaded(self, warn=None):
520 """read the fncache file if not already read.
524 """read the fncache file if not already read.
521
525
522 If the file on disk is corrupted, raise. If warn is provided,
526 If the file on disk is corrupted, raise. If warn is provided,
523 warn and keep going instead."""
527 warn and keep going instead."""
524 if self.entries is None:
528 if self.entries is None:
525 self._load(warn)
529 self._load(warn)
526
530
527 def _load(self, warn=None):
531 def _load(self, warn=None):
528 '''fill the entries from the fncache file'''
532 '''fill the entries from the fncache file'''
529 self._dirty = False
533 self._dirty = False
530 try:
534 try:
531 fp = self.vfs(b'fncache', mode=b'rb')
535 fp = self.vfs(b'fncache', mode=b'rb')
532 except IOError:
536 except IOError:
533 # skip nonexistent file
537 # skip nonexistent file
534 self.entries = set()
538 self.entries = set()
535 return
539 return
536
540
537 self.entries = set()
541 self.entries = set()
538 chunk = b''
542 chunk = b''
539 for c in iter(functools.partial(fp.read, fncache_chunksize), b''):
543 for c in iter(functools.partial(fp.read, fncache_chunksize), b''):
540 chunk += c
544 chunk += c
541 try:
545 try:
542 p = chunk.rindex(b'\n')
546 p = chunk.rindex(b'\n')
543 self.entries.update(decodedir(chunk[: p + 1]).splitlines())
547 self.entries.update(decodedir(chunk[: p + 1]).splitlines())
544 chunk = chunk[p + 1 :]
548 chunk = chunk[p + 1 :]
545 except ValueError:
549 except ValueError:
546 # substring '\n' not found, maybe the entry is bigger than the
550 # substring '\n' not found, maybe the entry is bigger than the
547 # chunksize, so let's keep iterating
551 # chunksize, so let's keep iterating
548 pass
552 pass
549
553
550 if chunk:
554 if chunk:
551 msg = _(b"fncache does not ends with a newline")
555 msg = _(b"fncache does not ends with a newline")
552 if warn:
556 if warn:
553 warn(msg + b'\n')
557 warn(msg + b'\n')
554 else:
558 else:
555 raise error.Abort(
559 raise error.Abort(
556 msg,
560 msg,
557 hint=_(
561 hint=_(
558 b"use 'hg debugrebuildfncache' to "
562 b"use 'hg debugrebuildfncache' to "
559 b"rebuild the fncache"
563 b"rebuild the fncache"
560 ),
564 ),
561 )
565 )
562 self._checkentries(fp, warn)
566 self._checkentries(fp, warn)
563 fp.close()
567 fp.close()
564
568
565 def _checkentries(self, fp, warn):
569 def _checkentries(self, fp, warn):
566 """ make sure there is no empty string in entries """
570 """ make sure there is no empty string in entries """
567 if b'' in self.entries:
571 if b'' in self.entries:
568 fp.seek(0)
572 fp.seek(0)
569 for n, line in enumerate(util.iterfile(fp)):
573 for n, line in enumerate(util.iterfile(fp)):
570 if not line.rstrip(b'\n'):
574 if not line.rstrip(b'\n'):
571 t = _(b'invalid entry in fncache, line %d') % (n + 1)
575 t = _(b'invalid entry in fncache, line %d') % (n + 1)
572 if warn:
576 if warn:
573 warn(t + b'\n')
577 warn(t + b'\n')
574 else:
578 else:
575 raise error.Abort(t)
579 raise error.Abort(t)
576
580
577 def write(self, tr):
581 def write(self, tr):
578 if self._dirty:
582 if self._dirty:
579 assert self.entries is not None
583 assert self.entries is not None
580 self.entries = self.entries | self.addls
584 self.entries = self.entries | self.addls
581 self.addls = set()
585 self.addls = set()
582 tr.addbackup(b'fncache')
586 tr.addbackup(b'fncache')
583 fp = self.vfs(b'fncache', mode=b'wb', atomictemp=True)
587 fp = self.vfs(b'fncache', mode=b'wb', atomictemp=True)
584 if self.entries:
588 if self.entries:
585 fp.write(encodedir(b'\n'.join(self.entries) + b'\n'))
589 fp.write(encodedir(b'\n'.join(self.entries) + b'\n'))
586 fp.close()
590 fp.close()
587 self._dirty = False
591 self._dirty = False
588 if self.addls:
592 if self.addls:
589 # if we have just new entries, let's append them to the fncache
593 # if we have just new entries, let's append them to the fncache
590 tr.addbackup(b'fncache')
594 tr.addbackup(b'fncache')
591 fp = self.vfs(b'fncache', mode=b'ab', atomictemp=True)
595 fp = self.vfs(b'fncache', mode=b'ab', atomictemp=True)
592 if self.addls:
596 if self.addls:
593 fp.write(encodedir(b'\n'.join(self.addls) + b'\n'))
597 fp.write(encodedir(b'\n'.join(self.addls) + b'\n'))
594 fp.close()
598 fp.close()
595 self.entries = None
599 self.entries = None
596 self.addls = set()
600 self.addls = set()
597
601
598 def add(self, fn):
602 def add(self, fn):
599 if self.entries is None:
603 if self.entries is None:
600 self._load()
604 self._load()
601 if fn not in self.entries:
605 if fn not in self.entries:
602 self.addls.add(fn)
606 self.addls.add(fn)
603
607
604 def remove(self, fn):
608 def remove(self, fn):
605 if self.entries is None:
609 if self.entries is None:
606 self._load()
610 self._load()
607 if fn in self.addls:
611 if fn in self.addls:
608 self.addls.remove(fn)
612 self.addls.remove(fn)
609 return
613 return
610 try:
614 try:
611 self.entries.remove(fn)
615 self.entries.remove(fn)
612 self._dirty = True
616 self._dirty = True
613 except KeyError:
617 except KeyError:
614 pass
618 pass
615
619
616 def __contains__(self, fn):
620 def __contains__(self, fn):
617 if fn in self.addls:
621 if fn in self.addls:
618 return True
622 return True
619 if self.entries is None:
623 if self.entries is None:
620 self._load()
624 self._load()
621 return fn in self.entries
625 return fn in self.entries
622
626
623 def __iter__(self):
627 def __iter__(self):
624 if self.entries is None:
628 if self.entries is None:
625 self._load()
629 self._load()
626 return iter(self.entries | self.addls)
630 return iter(self.entries | self.addls)
627
631
628
632
629 class _fncachevfs(vfsmod.proxyvfs):
633 class _fncachevfs(vfsmod.proxyvfs):
630 def __init__(self, vfs, fnc, encode):
634 def __init__(self, vfs, fnc, encode):
631 vfsmod.proxyvfs.__init__(self, vfs)
635 vfsmod.proxyvfs.__init__(self, vfs)
632 self.fncache = fnc
636 self.fncache = fnc
633 self.encode = encode
637 self.encode = encode
634
638
635 def __call__(self, path, mode=b'r', *args, **kw):
639 def __call__(self, path, mode=b'r', *args, **kw):
636 encoded = self.encode(path)
640 encoded = self.encode(path)
637 if mode not in (b'r', b'rb') and (
641 if mode not in (b'r', b'rb') and (
638 path.startswith(b'data/') or path.startswith(b'meta/')
642 path.startswith(b'data/') or path.startswith(b'meta/')
639 ):
643 ):
640 # do not trigger a fncache load when adding a file that already is
644 # do not trigger a fncache load when adding a file that already is
641 # known to exist.
645 # known to exist.
642 notload = self.fncache.entries is None and self.vfs.exists(encoded)
646 notload = self.fncache.entries is None and self.vfs.exists(encoded)
643 if notload and b'a' in mode and not self.vfs.stat(encoded).st_size:
647 if notload and b'a' in mode and not self.vfs.stat(encoded).st_size:
644 # when appending to an existing file, if the file has size zero,
648 # when appending to an existing file, if the file has size zero,
645 # it should be considered as missing. Such zero-size files are
649 # it should be considered as missing. Such zero-size files are
646 # the result of truncation when a transaction is aborted.
650 # the result of truncation when a transaction is aborted.
647 notload = False
651 notload = False
648 if not notload:
652 if not notload:
649 self.fncache.add(path)
653 self.fncache.add(path)
650 return self.vfs(encoded, mode, *args, **kw)
654 return self.vfs(encoded, mode, *args, **kw)
651
655
652 def join(self, path):
656 def join(self, path):
653 if path:
657 if path:
654 return self.vfs.join(self.encode(path))
658 return self.vfs.join(self.encode(path))
655 else:
659 else:
656 return self.vfs.join(path)
660 return self.vfs.join(path)
657
661
658
662
659 class fncachestore(basicstore):
663 class fncachestore(basicstore):
660 def __init__(self, path, vfstype, dotencode):
664 def __init__(self, path, vfstype, dotencode):
661 if dotencode:
665 if dotencode:
662 encode = _pathencode
666 encode = _pathencode
663 else:
667 else:
664 encode = _plainhybridencode
668 encode = _plainhybridencode
665 self.encode = encode
669 self.encode = encode
666 vfs = vfstype(path + b'/store')
670 vfs = vfstype(path + b'/store')
667 self.path = vfs.base
671 self.path = vfs.base
668 self.pathsep = self.path + b'/'
672 self.pathsep = self.path + b'/'
669 self.createmode = _calcmode(vfs)
673 self.createmode = _calcmode(vfs)
670 vfs.createmode = self.createmode
674 vfs.createmode = self.createmode
671 self.rawvfs = vfs
675 self.rawvfs = vfs
672 fnc = fncache(vfs)
676 fnc = fncache(vfs)
673 self.fncache = fnc
677 self.fncache = fnc
674 self.vfs = _fncachevfs(vfs, fnc, encode)
678 self.vfs = _fncachevfs(vfs, fnc, encode)
675 self.opener = self.vfs
679 self.opener = self.vfs
676
680
677 def join(self, f):
681 def join(self, f):
678 return self.pathsep + self.encode(f)
682 return self.pathsep + self.encode(f)
679
683
680 def getsize(self, path):
684 def getsize(self, path):
681 return self.rawvfs.stat(path).st_size
685 return self.rawvfs.stat(path).st_size
682
686
683 def datafiles(self, matcher=None):
687 def datafiles(self, matcher=None):
684 for f in sorted(self.fncache):
688 for f in sorted(self.fncache):
685 if not _matchtrackedpath(f, matcher):
689 if not _matchtrackedpath(f, matcher):
686 continue
690 continue
687 ef = self.encode(f)
691 ef = self.encode(f)
688 try:
692 try:
689 yield f, ef, self.getsize(ef)
693 yield f, ef, self.getsize(ef)
690 except OSError as err:
694 except OSError as err:
691 if err.errno != errno.ENOENT:
695 if err.errno != errno.ENOENT:
692 raise
696 raise
693
697
694 def copylist(self):
698 def copylist(self):
695 d = (
699 d = (
696 b'bookmarks',
700 b'bookmarks',
697 b'narrowspec',
701 b'narrowspec',
698 b'data',
702 b'data',
699 b'meta',
703 b'meta',
700 b'dh',
704 b'dh',
701 b'fncache',
705 b'fncache',
702 b'phaseroots',
706 b'phaseroots',
703 b'obsstore',
707 b'obsstore',
704 b'00manifest.d',
708 b'00manifest.d',
705 b'00manifest.i',
709 b'00manifest.i',
706 b'00changelog.d',
710 b'00changelog.d',
707 b'00changelog.i',
711 b'00changelog.i',
708 b'requires',
712 b'requires',
709 )
713 )
710 return [b'requires', b'00changelog.i'] + [b'store/' + f for f in d]
714 return [b'requires', b'00changelog.i'] + [b'store/' + f for f in d]
711
715
712 def write(self, tr):
716 def write(self, tr):
713 self.fncache.write(tr)
717 self.fncache.write(tr)
714
718
715 def invalidatecaches(self):
719 def invalidatecaches(self):
716 self.fncache.entries = None
720 self.fncache.entries = None
717 self.fncache.addls = set()
721 self.fncache.addls = set()
718
722
719 def markremoved(self, fn):
723 def markremoved(self, fn):
720 self.fncache.remove(fn)
724 self.fncache.remove(fn)
721
725
722 def _exists(self, f):
726 def _exists(self, f):
723 ef = self.encode(f)
727 ef = self.encode(f)
724 try:
728 try:
725 self.getsize(ef)
729 self.getsize(ef)
726 return True
730 return True
727 except OSError as err:
731 except OSError as err:
728 if err.errno != errno.ENOENT:
732 if err.errno != errno.ENOENT:
729 raise
733 raise
730 # nonexistent entry
734 # nonexistent entry
731 return False
735 return False
732
736
733 def __contains__(self, path):
737 def __contains__(self, path):
734 '''Checks if the store contains path'''
738 '''Checks if the store contains path'''
735 path = b"/".join((b"data", path))
739 path = b"/".join((b"data", path))
736 # check for files (exact match)
740 # check for files (exact match)
737 e = path + b'.i'
741 e = path + b'.i'
738 if e in self.fncache and self._exists(e):
742 if e in self.fncache and self._exists(e):
739 return True
743 return True
740 # now check for directories (prefix match)
744 # now check for directories (prefix match)
741 if not path.endswith(b'/'):
745 if not path.endswith(b'/'):
742 path += b'/'
746 path += b'/'
743 for e in self.fncache:
747 for e in self.fncache:
744 if e.startswith(path) and self._exists(e):
748 if e.startswith(path) and self._exists(e):
745 return True
749 return True
746 return False
750 return False
@@ -1,725 +1,727 b''
1 ===================================
1 ===================================
2 Test the persistent on-disk nodemap
2 Test the persistent on-disk nodemap
3 ===================================
3 ===================================
4
4
5 $ cat << EOF >> $HGRCPATH
5 $ cat << EOF >> $HGRCPATH
6 > [format]
6 > [format]
7 > use-persistent-nodemap=yes
7 > use-persistent-nodemap=yes
8 > [devel]
8 > [devel]
9 > persistent-nodemap=yes
9 > persistent-nodemap=yes
10 > EOF
10 > EOF
11
11
12 $ hg init test-repo --config storage.revlog.persistent-nodemap.slow-path=allow
12 $ hg init test-repo --config storage.revlog.persistent-nodemap.slow-path=allow
13 $ cd test-repo
13 $ cd test-repo
14
14
15 Check handling of the default slow-path value
15 Check handling of the default slow-path value
16
16
17 #if no-pure no-rust
17 #if no-pure no-rust
18
18
19 $ hg id
19 $ hg id
20 abort: accessing `persistent-nodemap` repository without associated fast implementation.
20 abort: accessing `persistent-nodemap` repository without associated fast implementation.
21 (check `hg help config.format.use-persistent-nodemap` for details)
21 (check `hg help config.format.use-persistent-nodemap` for details)
22 [255]
22 [255]
23
23
24 Unlock further check (we are here to test the feature)
24 Unlock further check (we are here to test the feature)
25
25
26 $ cat << EOF >> $HGRCPATH
26 $ cat << EOF >> $HGRCPATH
27 > [storage]
27 > [storage]
28 > # to avoid spamming the test
28 > # to avoid spamming the test
29 > revlog.persistent-nodemap.slow-path=allow
29 > revlog.persistent-nodemap.slow-path=allow
30 > EOF
30 > EOF
31
31
32 #endif
32 #endif
33
33
34
34
35 $ hg debugformat
35 $ hg debugformat
36 format-variant repo
36 format-variant repo
37 fncache: yes
37 fncache: yes
38 dotencode: yes
38 dotencode: yes
39 generaldelta: yes
39 generaldelta: yes
40 exp-sharesafe: no
40 exp-sharesafe: no
41 sparserevlog: yes
41 sparserevlog: yes
42 sidedata: no
42 sidedata: no
43 persistent-nodemap: yes
43 persistent-nodemap: yes
44 copies-sdc: no
44 copies-sdc: no
45 plain-cl-delta: yes
45 plain-cl-delta: yes
46 compression: zlib
46 compression: zlib
47 compression-level: default
47 compression-level: default
48 $ hg debugbuilddag .+5000 --new-file
48 $ hg debugbuilddag .+5000 --new-file
49
49
50 $ hg debugnodemap --metadata
50 $ hg debugnodemap --metadata
51 uid: ???????????????? (glob)
51 uid: ???????????????? (glob)
52 tip-rev: 5000
52 tip-rev: 5000
53 tip-node: 6b02b8c7b96654c25e86ba69eda198d7e6ad8b3c
53 tip-node: 6b02b8c7b96654c25e86ba69eda198d7e6ad8b3c
54 data-length: 121088
54 data-length: 121088
55 data-unused: 0
55 data-unused: 0
56 data-unused: 0.000%
56 data-unused: 0.000%
57 $ f --size .hg/store/00changelog.n
57 $ f --size .hg/store/00changelog.n
58 .hg/store/00changelog.n: size=70
58 .hg/store/00changelog.n: size=70
59
59
60 Simple lookup works
60 Simple lookup works
61
61
62 $ ANYNODE=`hg log --template '{node|short}\n' --rev tip`
62 $ ANYNODE=`hg log --template '{node|short}\n' --rev tip`
63 $ hg log -r "$ANYNODE" --template '{rev}\n'
63 $ hg log -r "$ANYNODE" --template '{rev}\n'
64 5000
64 5000
65
65
66
66
67 #if rust
67 #if rust
68
68
69 $ f --sha256 .hg/store/00changelog-*.nd
69 $ f --sha256 .hg/store/00changelog-*.nd
70 .hg/store/00changelog-????????????????.nd: sha256=2e029d3200bd1a986b32784fc2ef1a3bd60dc331f025718bcf5ff44d93f026fd (glob)
70 .hg/store/00changelog-????????????????.nd: sha256=2e029d3200bd1a986b32784fc2ef1a3bd60dc331f025718bcf5ff44d93f026fd (glob)
71
71
72 $ f --sha256 .hg/store/00manifest-*.nd
72 $ f --sha256 .hg/store/00manifest-*.nd
73 .hg/store/00manifest-????????????????.nd: sha256=97117b1c064ea2f86664a124589e47db0e254e8d34739b5c5cc5bf31c9da2b51 (glob)
73 .hg/store/00manifest-????????????????.nd: sha256=97117b1c064ea2f86664a124589e47db0e254e8d34739b5c5cc5bf31c9da2b51 (glob)
74 $ hg debugnodemap --dump-new | f --sha256 --size
74 $ hg debugnodemap --dump-new | f --sha256 --size
75 size=121088, sha256=2e029d3200bd1a986b32784fc2ef1a3bd60dc331f025718bcf5ff44d93f026fd
75 size=121088, sha256=2e029d3200bd1a986b32784fc2ef1a3bd60dc331f025718bcf5ff44d93f026fd
76 $ hg debugnodemap --dump-disk | f --sha256 --bytes=256 --hexdump --size
76 $ hg debugnodemap --dump-disk | f --sha256 --bytes=256 --hexdump --size
77 size=121088, sha256=2e029d3200bd1a986b32784fc2ef1a3bd60dc331f025718bcf5ff44d93f026fd
77 size=121088, sha256=2e029d3200bd1a986b32784fc2ef1a3bd60dc331f025718bcf5ff44d93f026fd
78 0000: 00 00 00 91 00 00 00 20 00 00 00 bb 00 00 00 e7 |....... ........|
78 0000: 00 00 00 91 00 00 00 20 00 00 00 bb 00 00 00 e7 |....... ........|
79 0010: 00 00 00 66 00 00 00 a1 00 00 01 13 00 00 01 22 |...f..........."|
79 0010: 00 00 00 66 00 00 00 a1 00 00 01 13 00 00 01 22 |...f..........."|
80 0020: 00 00 00 23 00 00 00 fc 00 00 00 ba 00 00 00 5e |...#...........^|
80 0020: 00 00 00 23 00 00 00 fc 00 00 00 ba 00 00 00 5e |...#...........^|
81 0030: 00 00 00 df 00 00 01 4e 00 00 01 65 00 00 00 ab |.......N...e....|
81 0030: 00 00 00 df 00 00 01 4e 00 00 01 65 00 00 00 ab |.......N...e....|
82 0040: 00 00 00 a9 00 00 00 95 00 00 00 73 00 00 00 38 |...........s...8|
82 0040: 00 00 00 a9 00 00 00 95 00 00 00 73 00 00 00 38 |...........s...8|
83 0050: 00 00 00 cc 00 00 00 92 00 00 00 90 00 00 00 69 |...............i|
83 0050: 00 00 00 cc 00 00 00 92 00 00 00 90 00 00 00 69 |...............i|
84 0060: 00 00 00 ec 00 00 00 8d 00 00 01 4f 00 00 00 12 |...........O....|
84 0060: 00 00 00 ec 00 00 00 8d 00 00 01 4f 00 00 00 12 |...........O....|
85 0070: 00 00 02 0c 00 00 00 77 00 00 00 9c 00 00 00 8f |.......w........|
85 0070: 00 00 02 0c 00 00 00 77 00 00 00 9c 00 00 00 8f |.......w........|
86 0080: 00 00 00 d5 00 00 00 6b 00 00 00 48 00 00 00 b3 |.......k...H....|
86 0080: 00 00 00 d5 00 00 00 6b 00 00 00 48 00 00 00 b3 |.......k...H....|
87 0090: 00 00 00 e5 00 00 00 b5 00 00 00 8e 00 00 00 ad |................|
87 0090: 00 00 00 e5 00 00 00 b5 00 00 00 8e 00 00 00 ad |................|
88 00a0: 00 00 00 7b 00 00 00 7c 00 00 00 0b 00 00 00 2b |...{...|.......+|
88 00a0: 00 00 00 7b 00 00 00 7c 00 00 00 0b 00 00 00 2b |...{...|.......+|
89 00b0: 00 00 00 c6 00 00 00 1e 00 00 01 08 00 00 00 11 |................|
89 00b0: 00 00 00 c6 00 00 00 1e 00 00 01 08 00 00 00 11 |................|
90 00c0: 00 00 01 30 00 00 00 26 00 00 01 9c 00 00 00 35 |...0...&.......5|
90 00c0: 00 00 01 30 00 00 00 26 00 00 01 9c 00 00 00 35 |...0...&.......5|
91 00d0: 00 00 00 b8 00 00 01 31 00 00 00 2c 00 00 00 55 |.......1...,...U|
91 00d0: 00 00 00 b8 00 00 01 31 00 00 00 2c 00 00 00 55 |.......1...,...U|
92 00e0: 00 00 00 8a 00 00 00 9a 00 00 00 0c 00 00 01 1e |................|
92 00e0: 00 00 00 8a 00 00 00 9a 00 00 00 0c 00 00 01 1e |................|
93 00f0: 00 00 00 a4 00 00 00 83 00 00 00 c9 00 00 00 8c |................|
93 00f0: 00 00 00 a4 00 00 00 83 00 00 00 c9 00 00 00 8c |................|
94
94
95
95
96 #else
96 #else
97
97
98 $ f --sha256 .hg/store/00changelog-*.nd
98 $ f --sha256 .hg/store/00changelog-*.nd
99 .hg/store/00changelog-????????????????.nd: sha256=f544f5462ff46097432caf6d764091f6d8c46d6121be315ead8576d548c9dd79 (glob)
99 .hg/store/00changelog-????????????????.nd: sha256=f544f5462ff46097432caf6d764091f6d8c46d6121be315ead8576d548c9dd79 (glob)
100 $ hg debugnodemap --dump-new | f --sha256 --size
100 $ hg debugnodemap --dump-new | f --sha256 --size
101 size=121088, sha256=f544f5462ff46097432caf6d764091f6d8c46d6121be315ead8576d548c9dd79
101 size=121088, sha256=f544f5462ff46097432caf6d764091f6d8c46d6121be315ead8576d548c9dd79
102 $ hg debugnodemap --dump-disk | f --sha256 --bytes=256 --hexdump --size
102 $ hg debugnodemap --dump-disk | f --sha256 --bytes=256 --hexdump --size
103 size=121088, sha256=f544f5462ff46097432caf6d764091f6d8c46d6121be315ead8576d548c9dd79
103 size=121088, sha256=f544f5462ff46097432caf6d764091f6d8c46d6121be315ead8576d548c9dd79
104 0000: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
104 0000: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
105 0010: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
105 0010: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
106 0020: ff ff ff ff ff ff f5 06 ff ff ff ff ff ff f3 e7 |................|
106 0020: ff ff ff ff ff ff f5 06 ff ff ff ff ff ff f3 e7 |................|
107 0030: ff ff ef ca ff ff ff ff ff ff ff ff ff ff ff ff |................|
107 0030: ff ff ef ca ff ff ff ff ff ff ff ff ff ff ff ff |................|
108 0040: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
108 0040: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
109 0050: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ed 08 |................|
109 0050: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ed 08 |................|
110 0060: ff ff ed 66 ff ff ff ff ff ff ff ff ff ff ff ff |...f............|
110 0060: ff ff ed 66 ff ff ff ff ff ff ff ff ff ff ff ff |...f............|
111 0070: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
111 0070: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
112 0080: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
112 0080: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
113 0090: ff ff ff ff ff ff ff ff ff ff ff ff ff ff f6 ed |................|
113 0090: ff ff ff ff ff ff ff ff ff ff ff ff ff ff f6 ed |................|
114 00a0: ff ff ff ff ff ff fe 61 ff ff ff ff ff ff ff ff |.......a........|
114 00a0: ff ff ff ff ff ff fe 61 ff ff ff ff ff ff ff ff |.......a........|
115 00b0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
115 00b0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
116 00c0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
116 00c0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
117 00d0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
117 00d0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
118 00e0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff f1 02 |................|
118 00e0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff f1 02 |................|
119 00f0: ff ff ff ff ff ff ed 1b ff ff ff ff ff ff ff ff |................|
119 00f0: ff ff ff ff ff ff ed 1b ff ff ff ff ff ff ff ff |................|
120
120
121 #endif
121 #endif
122
122
123 $ hg debugnodemap --check
123 $ hg debugnodemap --check
124 revision in index: 5001
124 revision in index: 5001
125 revision in nodemap: 5001
125 revision in nodemap: 5001
126
126
127 add a new commit
127 add a new commit
128
128
129 $ hg up
129 $ hg up
130 5001 files updated, 0 files merged, 0 files removed, 0 files unresolved
130 5001 files updated, 0 files merged, 0 files removed, 0 files unresolved
131 $ echo foo > foo
131 $ echo foo > foo
132 $ hg add foo
132 $ hg add foo
133
133
134
134
135 Check slow-path config value handling
135 Check slow-path config value handling
136 -------------------------------------
136 -------------------------------------
137
137
138 #if no-pure no-rust
138 #if no-pure no-rust
139
139
140 $ hg id --config "storage.revlog.persistent-nodemap.slow-path=invalid-value"
140 $ hg id --config "storage.revlog.persistent-nodemap.slow-path=invalid-value"
141 unknown value for config "storage.revlog.persistent-nodemap.slow-path": "invalid-value"
141 unknown value for config "storage.revlog.persistent-nodemap.slow-path": "invalid-value"
142 falling back to default value: abort
142 falling back to default value: abort
143 abort: accessing `persistent-nodemap` repository without associated fast implementation.
143 abort: accessing `persistent-nodemap` repository without associated fast implementation.
144 (check `hg help config.format.use-persistent-nodemap` for details)
144 (check `hg help config.format.use-persistent-nodemap` for details)
145 [255]
145 [255]
146
146
147 $ hg log -r . --config "storage.revlog.persistent-nodemap.slow-path=warn"
147 $ hg log -r . --config "storage.revlog.persistent-nodemap.slow-path=warn"
148 warning: accessing `persistent-nodemap` repository without associated fast implementation.
148 warning: accessing `persistent-nodemap` repository without associated fast implementation.
149 (check `hg help config.format.use-persistent-nodemap` for details)
149 (check `hg help config.format.use-persistent-nodemap` for details)
150 changeset: 5000:6b02b8c7b966
150 changeset: 5000:6b02b8c7b966
151 tag: tip
151 tag: tip
152 user: debugbuilddag
152 user: debugbuilddag
153 date: Thu Jan 01 01:23:20 1970 +0000
153 date: Thu Jan 01 01:23:20 1970 +0000
154 summary: r5000
154 summary: r5000
155
155
156 $ hg ci -m 'foo' --config "storage.revlog.persistent-nodemap.slow-path=abort"
156 $ hg ci -m 'foo' --config "storage.revlog.persistent-nodemap.slow-path=abort"
157 abort: accessing `persistent-nodemap` repository without associated fast implementation.
157 abort: accessing `persistent-nodemap` repository without associated fast implementation.
158 (check `hg help config.format.use-persistent-nodemap` for details)
158 (check `hg help config.format.use-persistent-nodemap` for details)
159 [255]
159 [255]
160
160
161 #else
161 #else
162
162
163 $ hg id --config "storage.revlog.persistent-nodemap.slow-path=invalid-value"
163 $ hg id --config "storage.revlog.persistent-nodemap.slow-path=invalid-value"
164 unknown value for config "storage.revlog.persistent-nodemap.slow-path": "invalid-value"
164 unknown value for config "storage.revlog.persistent-nodemap.slow-path": "invalid-value"
165 falling back to default value: abort
165 falling back to default value: abort
166 6b02b8c7b966+ tip
166 6b02b8c7b966+ tip
167
167
168 #endif
168 #endif
169
169
170 $ hg ci -m 'foo'
170 $ hg ci -m 'foo'
171
171
172 #if no-pure no-rust
172 #if no-pure no-rust
173 $ hg debugnodemap --metadata
173 $ hg debugnodemap --metadata
174 uid: ???????????????? (glob)
174 uid: ???????????????? (glob)
175 tip-rev: 5001
175 tip-rev: 5001
176 tip-node: 16395c3cf7e231394735e6b1717823ada303fb0c
176 tip-node: 16395c3cf7e231394735e6b1717823ada303fb0c
177 data-length: 121088
177 data-length: 121088
178 data-unused: 0
178 data-unused: 0
179 data-unused: 0.000%
179 data-unused: 0.000%
180 #else
180 #else
181 $ hg debugnodemap --metadata
181 $ hg debugnodemap --metadata
182 uid: ???????????????? (glob)
182 uid: ???????????????? (glob)
183 tip-rev: 5001
183 tip-rev: 5001
184 tip-node: 16395c3cf7e231394735e6b1717823ada303fb0c
184 tip-node: 16395c3cf7e231394735e6b1717823ada303fb0c
185 data-length: 121344
185 data-length: 121344
186 data-unused: 256
186 data-unused: 256
187 data-unused: 0.211%
187 data-unused: 0.211%
188 #endif
188 #endif
189
189
190 $ f --size .hg/store/00changelog.n
190 $ f --size .hg/store/00changelog.n
191 .hg/store/00changelog.n: size=70
191 .hg/store/00changelog.n: size=70
192
192
193 (The pure code use the debug code that perform incremental update, the C code reencode from scratch)
193 (The pure code use the debug code that perform incremental update, the C code reencode from scratch)
194
194
195 #if pure
195 #if pure
196 $ f --sha256 .hg/store/00changelog-*.nd --size
196 $ f --sha256 .hg/store/00changelog-*.nd --size
197 .hg/store/00changelog-????????????????.nd: size=121344, sha256=cce54c5da5bde3ad72a4938673ed4064c86231b9c64376b082b163fdb20f8f66 (glob)
197 .hg/store/00changelog-????????????????.nd: size=121344, sha256=cce54c5da5bde3ad72a4938673ed4064c86231b9c64376b082b163fdb20f8f66 (glob)
198 #endif
198 #endif
199
199
200 #if rust
200 #if rust
201 $ f --sha256 .hg/store/00changelog-*.nd --size
201 $ f --sha256 .hg/store/00changelog-*.nd --size
202 .hg/store/00changelog-????????????????.nd: size=121344, sha256=952b042fcf614ceb37b542b1b723e04f18f83efe99bee4e0f5ccd232ef470e58 (glob)
202 .hg/store/00changelog-????????????????.nd: size=121344, sha256=952b042fcf614ceb37b542b1b723e04f18f83efe99bee4e0f5ccd232ef470e58 (glob)
203 #endif
203 #endif
204
204
205 #if no-pure no-rust
205 #if no-pure no-rust
206 $ f --sha256 .hg/store/00changelog-*.nd --size
206 $ f --sha256 .hg/store/00changelog-*.nd --size
207 .hg/store/00changelog-????????????????.nd: size=121088, sha256=df7c06a035b96cb28c7287d349d603baef43240be7736fe34eea419a49702e17 (glob)
207 .hg/store/00changelog-????????????????.nd: size=121088, sha256=df7c06a035b96cb28c7287d349d603baef43240be7736fe34eea419a49702e17 (glob)
208 #endif
208 #endif
209
209
210 $ hg debugnodemap --check
210 $ hg debugnodemap --check
211 revision in index: 5002
211 revision in index: 5002
212 revision in nodemap: 5002
212 revision in nodemap: 5002
213
213
214 Test code path without mmap
214 Test code path without mmap
215 ---------------------------
215 ---------------------------
216
216
217 $ echo bar > bar
217 $ echo bar > bar
218 $ hg add bar
218 $ hg add bar
219 $ hg ci -m 'bar' --config storage.revlog.persistent-nodemap.mmap=no
219 $ hg ci -m 'bar' --config storage.revlog.persistent-nodemap.mmap=no
220
220
221 $ hg debugnodemap --check --config storage.revlog.persistent-nodemap.mmap=yes
221 $ hg debugnodemap --check --config storage.revlog.persistent-nodemap.mmap=yes
222 revision in index: 5003
222 revision in index: 5003
223 revision in nodemap: 5003
223 revision in nodemap: 5003
224 $ hg debugnodemap --check --config storage.revlog.persistent-nodemap.mmap=no
224 $ hg debugnodemap --check --config storage.revlog.persistent-nodemap.mmap=no
225 revision in index: 5003
225 revision in index: 5003
226 revision in nodemap: 5003
226 revision in nodemap: 5003
227
227
228
228
229 #if pure
229 #if pure
230 $ hg debugnodemap --metadata
230 $ hg debugnodemap --metadata
231 uid: ???????????????? (glob)
231 uid: ???????????????? (glob)
232 tip-rev: 5002
232 tip-rev: 5002
233 tip-node: 880b18d239dfa9f632413a2071bfdbcc4806a4fd
233 tip-node: 880b18d239dfa9f632413a2071bfdbcc4806a4fd
234 data-length: 121600
234 data-length: 121600
235 data-unused: 512
235 data-unused: 512
236 data-unused: 0.421%
236 data-unused: 0.421%
237 $ f --sha256 .hg/store/00changelog-*.nd --size
237 $ f --sha256 .hg/store/00changelog-*.nd --size
238 .hg/store/00changelog-????????????????.nd: size=121600, sha256=def52503d049ccb823974af313a98a935319ba61f40f3aa06a8be4d35c215054 (glob)
238 .hg/store/00changelog-????????????????.nd: size=121600, sha256=def52503d049ccb823974af313a98a935319ba61f40f3aa06a8be4d35c215054 (glob)
239 #endif
239 #endif
240 #if rust
240 #if rust
241 $ hg debugnodemap --metadata
241 $ hg debugnodemap --metadata
242 uid: ???????????????? (glob)
242 uid: ???????????????? (glob)
243 tip-rev: 5002
243 tip-rev: 5002
244 tip-node: 880b18d239dfa9f632413a2071bfdbcc4806a4fd
244 tip-node: 880b18d239dfa9f632413a2071bfdbcc4806a4fd
245 data-length: 121600
245 data-length: 121600
246 data-unused: 512
246 data-unused: 512
247 data-unused: 0.421%
247 data-unused: 0.421%
248 $ f --sha256 .hg/store/00changelog-*.nd --size
248 $ f --sha256 .hg/store/00changelog-*.nd --size
249 .hg/store/00changelog-????????????????.nd: size=121600, sha256=dacf5b5f1d4585fee7527d0e67cad5b1ba0930e6a0928f650f779aefb04ce3fb (glob)
249 .hg/store/00changelog-????????????????.nd: size=121600, sha256=dacf5b5f1d4585fee7527d0e67cad5b1ba0930e6a0928f650f779aefb04ce3fb (glob)
250 #endif
250 #endif
251 #if no-pure no-rust
251 #if no-pure no-rust
252 $ hg debugnodemap --metadata
252 $ hg debugnodemap --metadata
253 uid: ???????????????? (glob)
253 uid: ???????????????? (glob)
254 tip-rev: 5002
254 tip-rev: 5002
255 tip-node: 880b18d239dfa9f632413a2071bfdbcc4806a4fd
255 tip-node: 880b18d239dfa9f632413a2071bfdbcc4806a4fd
256 data-length: 121088
256 data-length: 121088
257 data-unused: 0
257 data-unused: 0
258 data-unused: 0.000%
258 data-unused: 0.000%
259 $ f --sha256 .hg/store/00changelog-*.nd --size
259 $ f --sha256 .hg/store/00changelog-*.nd --size
260 .hg/store/00changelog-????????????????.nd: size=121088, sha256=59fcede3e3cc587755916ceed29e3c33748cd1aa7d2f91828ac83e7979d935e8 (glob)
260 .hg/store/00changelog-????????????????.nd: size=121088, sha256=59fcede3e3cc587755916ceed29e3c33748cd1aa7d2f91828ac83e7979d935e8 (glob)
261 #endif
261 #endif
262
262
263 Test force warming the cache
263 Test force warming the cache
264
264
265 $ rm .hg/store/00changelog.n
265 $ rm .hg/store/00changelog.n
266 $ hg debugnodemap --metadata
266 $ hg debugnodemap --metadata
267 $ hg debugupdatecache
267 $ hg debugupdatecache
268 #if pure
268 #if pure
269 $ hg debugnodemap --metadata
269 $ hg debugnodemap --metadata
270 uid: ???????????????? (glob)
270 uid: ???????????????? (glob)
271 tip-rev: 5002
271 tip-rev: 5002
272 tip-node: 880b18d239dfa9f632413a2071bfdbcc4806a4fd
272 tip-node: 880b18d239dfa9f632413a2071bfdbcc4806a4fd
273 data-length: 121088
273 data-length: 121088
274 data-unused: 0
274 data-unused: 0
275 data-unused: 0.000%
275 data-unused: 0.000%
276 #else
276 #else
277 $ hg debugnodemap --metadata
277 $ hg debugnodemap --metadata
278 uid: ???????????????? (glob)
278 uid: ???????????????? (glob)
279 tip-rev: 5002
279 tip-rev: 5002
280 tip-node: 880b18d239dfa9f632413a2071bfdbcc4806a4fd
280 tip-node: 880b18d239dfa9f632413a2071bfdbcc4806a4fd
281 data-length: 121088
281 data-length: 121088
282 data-unused: 0
282 data-unused: 0
283 data-unused: 0.000%
283 data-unused: 0.000%
284 #endif
284 #endif
285
285
286 Check out of sync nodemap
286 Check out of sync nodemap
287 =========================
287 =========================
288
288
289 First copy old data on the side.
289 First copy old data on the side.
290
290
291 $ mkdir ../tmp-copies
291 $ mkdir ../tmp-copies
292 $ cp .hg/store/00changelog-????????????????.nd .hg/store/00changelog.n ../tmp-copies
292 $ cp .hg/store/00changelog-????????????????.nd .hg/store/00changelog.n ../tmp-copies
293
293
294 Nodemap lagging behind
294 Nodemap lagging behind
295 ----------------------
295 ----------------------
296
296
297 make a new commit
297 make a new commit
298
298
299 $ echo bar2 > bar
299 $ echo bar2 > bar
300 $ hg ci -m 'bar2'
300 $ hg ci -m 'bar2'
301 $ NODE=`hg log -r tip -T '{node}\n'`
301 $ NODE=`hg log -r tip -T '{node}\n'`
302 $ hg log -r "$NODE" -T '{rev}\n'
302 $ hg log -r "$NODE" -T '{rev}\n'
303 5003
303 5003
304
304
305 If the nodemap is lagging behind, it can catch up fine
305 If the nodemap is lagging behind, it can catch up fine
306
306
307 $ hg debugnodemap --metadata
307 $ hg debugnodemap --metadata
308 uid: ???????????????? (glob)
308 uid: ???????????????? (glob)
309 tip-rev: 5003
309 tip-rev: 5003
310 tip-node: c9329770f979ade2d16912267c38ba5f82fd37b3
310 tip-node: c9329770f979ade2d16912267c38ba5f82fd37b3
311 data-length: 121344 (pure !)
311 data-length: 121344 (pure !)
312 data-length: 121344 (rust !)
312 data-length: 121344 (rust !)
313 data-length: 121152 (no-rust no-pure !)
313 data-length: 121152 (no-rust no-pure !)
314 data-unused: 192 (pure !)
314 data-unused: 192 (pure !)
315 data-unused: 192 (rust !)
315 data-unused: 192 (rust !)
316 data-unused: 0 (no-rust no-pure !)
316 data-unused: 0 (no-rust no-pure !)
317 data-unused: 0.158% (pure !)
317 data-unused: 0.158% (pure !)
318 data-unused: 0.158% (rust !)
318 data-unused: 0.158% (rust !)
319 data-unused: 0.000% (no-rust no-pure !)
319 data-unused: 0.000% (no-rust no-pure !)
320 $ cp -f ../tmp-copies/* .hg/store/
320 $ cp -f ../tmp-copies/* .hg/store/
321 $ hg debugnodemap --metadata
321 $ hg debugnodemap --metadata
322 uid: ???????????????? (glob)
322 uid: ???????????????? (glob)
323 tip-rev: 5002
323 tip-rev: 5002
324 tip-node: 880b18d239dfa9f632413a2071bfdbcc4806a4fd
324 tip-node: 880b18d239dfa9f632413a2071bfdbcc4806a4fd
325 data-length: 121088
325 data-length: 121088
326 data-unused: 0
326 data-unused: 0
327 data-unused: 0.000%
327 data-unused: 0.000%
328 $ hg log -r "$NODE" -T '{rev}\n'
328 $ hg log -r "$NODE" -T '{rev}\n'
329 5003
329 5003
330
330
331 changelog altered
331 changelog altered
332 -----------------
332 -----------------
333
333
334 If the nodemap is not gated behind a requirements, an unaware client can alter
334 If the nodemap is not gated behind a requirements, an unaware client can alter
335 the repository so the revlog used to generate the nodemap is not longer
335 the repository so the revlog used to generate the nodemap is not longer
336 compatible with the persistent nodemap. We need to detect that.
336 compatible with the persistent nodemap. We need to detect that.
337
337
338 $ hg up "$NODE~5"
338 $ hg up "$NODE~5"
339 0 files updated, 0 files merged, 4 files removed, 0 files unresolved
339 0 files updated, 0 files merged, 4 files removed, 0 files unresolved
340 $ echo bar > babar
340 $ echo bar > babar
341 $ hg add babar
341 $ hg add babar
342 $ hg ci -m 'babar'
342 $ hg ci -m 'babar'
343 created new head
343 created new head
344 $ OTHERNODE=`hg log -r tip -T '{node}\n'`
344 $ OTHERNODE=`hg log -r tip -T '{node}\n'`
345 $ hg log -r "$OTHERNODE" -T '{rev}\n'
345 $ hg log -r "$OTHERNODE" -T '{rev}\n'
346 5004
346 5004
347
347
348 $ hg --config extensions.strip= strip --rev "$NODE~1" --no-backup
348 $ hg --config extensions.strip= strip --rev "$NODE~1" --no-backup
349
349
350 the nodemap should detect the changelog have been tampered with and recover.
350 the nodemap should detect the changelog have been tampered with and recover.
351
351
352 $ hg debugnodemap --metadata
352 $ hg debugnodemap --metadata
353 uid: ???????????????? (glob)
353 uid: ???????????????? (glob)
354 tip-rev: 5002
354 tip-rev: 5002
355 tip-node: b355ef8adce0949b8bdf6afc72ca853740d65944
355 tip-node: b355ef8adce0949b8bdf6afc72ca853740d65944
356 data-length: 121536 (pure !)
356 data-length: 121536 (pure !)
357 data-length: 121088 (rust !)
357 data-length: 121088 (rust !)
358 data-length: 121088 (no-pure no-rust !)
358 data-length: 121088 (no-pure no-rust !)
359 data-unused: 448 (pure !)
359 data-unused: 448 (pure !)
360 data-unused: 0 (rust !)
360 data-unused: 0 (rust !)
361 data-unused: 0 (no-pure no-rust !)
361 data-unused: 0 (no-pure no-rust !)
362 data-unused: 0.000% (rust !)
362 data-unused: 0.000% (rust !)
363 data-unused: 0.369% (pure !)
363 data-unused: 0.369% (pure !)
364 data-unused: 0.000% (no-pure no-rust !)
364 data-unused: 0.000% (no-pure no-rust !)
365
365
366 $ cp -f ../tmp-copies/* .hg/store/
366 $ cp -f ../tmp-copies/* .hg/store/
367 $ hg debugnodemap --metadata
367 $ hg debugnodemap --metadata
368 uid: ???????????????? (glob)
368 uid: ???????????????? (glob)
369 tip-rev: 5002
369 tip-rev: 5002
370 tip-node: 880b18d239dfa9f632413a2071bfdbcc4806a4fd
370 tip-node: 880b18d239dfa9f632413a2071bfdbcc4806a4fd
371 data-length: 121088
371 data-length: 121088
372 data-unused: 0
372 data-unused: 0
373 data-unused: 0.000%
373 data-unused: 0.000%
374 $ hg log -r "$OTHERNODE" -T '{rev}\n'
374 $ hg log -r "$OTHERNODE" -T '{rev}\n'
375 5002
375 5002
376
376
377 missing data file
377 missing data file
378 -----------------
378 -----------------
379
379
380 $ UUID=`hg debugnodemap --metadata| grep 'uid:' | \
380 $ UUID=`hg debugnodemap --metadata| grep 'uid:' | \
381 > sed 's/uid: //'`
381 > sed 's/uid: //'`
382 $ FILE=.hg/store/00changelog-"${UUID}".nd
382 $ FILE=.hg/store/00changelog-"${UUID}".nd
383 $ mv $FILE ../tmp-data-file
383 $ mv $FILE ../tmp-data-file
384 $ cp .hg/store/00changelog.n ../tmp-docket
384 $ cp .hg/store/00changelog.n ../tmp-docket
385
385
386 mercurial don't crash
386 mercurial don't crash
387
387
388 $ hg log -r .
388 $ hg log -r .
389 changeset: 5002:b355ef8adce0
389 changeset: 5002:b355ef8adce0
390 tag: tip
390 tag: tip
391 parent: 4998:d918ad6d18d3
391 parent: 4998:d918ad6d18d3
392 user: test
392 user: test
393 date: Thu Jan 01 00:00:00 1970 +0000
393 date: Thu Jan 01 00:00:00 1970 +0000
394 summary: babar
394 summary: babar
395
395
396 $ hg debugnodemap --metadata
396 $ hg debugnodemap --metadata
397
397
398 $ hg debugupdatecache
398 $ hg debugupdatecache
399 $ hg debugnodemap --metadata
399 $ hg debugnodemap --metadata
400 uid: * (glob)
400 uid: * (glob)
401 tip-rev: 5002
401 tip-rev: 5002
402 tip-node: b355ef8adce0949b8bdf6afc72ca853740d65944
402 tip-node: b355ef8adce0949b8bdf6afc72ca853740d65944
403 data-length: 121088
403 data-length: 121088
404 data-unused: 0
404 data-unused: 0
405 data-unused: 0.000%
405 data-unused: 0.000%
406 $ mv ../tmp-data-file $FILE
406 $ mv ../tmp-data-file $FILE
407 $ mv ../tmp-docket .hg/store/00changelog.n
407 $ mv ../tmp-docket .hg/store/00changelog.n
408
408
409 Check transaction related property
409 Check transaction related property
410 ==================================
410 ==================================
411
411
412 An up to date nodemap should be available to shell hooks,
412 An up to date nodemap should be available to shell hooks,
413
413
414 $ echo dsljfl > a
414 $ echo dsljfl > a
415 $ hg add a
415 $ hg add a
416 $ hg ci -m a
416 $ hg ci -m a
417 $ hg debugnodemap --metadata
417 $ hg debugnodemap --metadata
418 uid: ???????????????? (glob)
418 uid: ???????????????? (glob)
419 tip-rev: 5003
419 tip-rev: 5003
420 tip-node: a52c5079765b5865d97b993b303a18740113bbb2
420 tip-node: a52c5079765b5865d97b993b303a18740113bbb2
421 data-length: 121088
421 data-length: 121088
422 data-unused: 0
422 data-unused: 0
423 data-unused: 0.000%
423 data-unused: 0.000%
424 $ echo babar2 > babar
424 $ echo babar2 > babar
425 $ hg ci -m 'babar2' --config "hooks.pretxnclose.nodemap-test=hg debugnodemap --metadata"
425 $ hg ci -m 'babar2' --config "hooks.pretxnclose.nodemap-test=hg debugnodemap --metadata"
426 uid: ???????????????? (glob)
426 uid: ???????????????? (glob)
427 tip-rev: 5004
427 tip-rev: 5004
428 tip-node: 2f5fb1c06a16834c5679d672e90da7c5f3b1a984
428 tip-node: 2f5fb1c06a16834c5679d672e90da7c5f3b1a984
429 data-length: 121280 (pure !)
429 data-length: 121280 (pure !)
430 data-length: 121280 (rust !)
430 data-length: 121280 (rust !)
431 data-length: 121088 (no-pure no-rust !)
431 data-length: 121088 (no-pure no-rust !)
432 data-unused: 192 (pure !)
432 data-unused: 192 (pure !)
433 data-unused: 192 (rust !)
433 data-unused: 192 (rust !)
434 data-unused: 0 (no-pure no-rust !)
434 data-unused: 0 (no-pure no-rust !)
435 data-unused: 0.158% (pure !)
435 data-unused: 0.158% (pure !)
436 data-unused: 0.158% (rust !)
436 data-unused: 0.158% (rust !)
437 data-unused: 0.000% (no-pure no-rust !)
437 data-unused: 0.000% (no-pure no-rust !)
438 $ hg debugnodemap --metadata
438 $ hg debugnodemap --metadata
439 uid: ???????????????? (glob)
439 uid: ???????????????? (glob)
440 tip-rev: 5004
440 tip-rev: 5004
441 tip-node: 2f5fb1c06a16834c5679d672e90da7c5f3b1a984
441 tip-node: 2f5fb1c06a16834c5679d672e90da7c5f3b1a984
442 data-length: 121280 (pure !)
442 data-length: 121280 (pure !)
443 data-length: 121280 (rust !)
443 data-length: 121280 (rust !)
444 data-length: 121088 (no-pure no-rust !)
444 data-length: 121088 (no-pure no-rust !)
445 data-unused: 192 (pure !)
445 data-unused: 192 (pure !)
446 data-unused: 192 (rust !)
446 data-unused: 192 (rust !)
447 data-unused: 0 (no-pure no-rust !)
447 data-unused: 0 (no-pure no-rust !)
448 data-unused: 0.158% (pure !)
448 data-unused: 0.158% (pure !)
449 data-unused: 0.158% (rust !)
449 data-unused: 0.158% (rust !)
450 data-unused: 0.000% (no-pure no-rust !)
450 data-unused: 0.000% (no-pure no-rust !)
451
451
452 Another process does not see the pending nodemap content during run.
452 Another process does not see the pending nodemap content during run.
453
453
454 $ PATH=$RUNTESTDIR/testlib/:$PATH
454 $ PATH=$RUNTESTDIR/testlib/:$PATH
455 $ echo qpoasp > a
455 $ echo qpoasp > a
456 $ hg ci -m a2 \
456 $ hg ci -m a2 \
457 > --config "hooks.pretxnclose=wait-on-file 20 sync-repo-read sync-txn-pending" \
457 > --config "hooks.pretxnclose=wait-on-file 20 sync-repo-read sync-txn-pending" \
458 > --config "hooks.txnclose=touch sync-txn-close" > output.txt 2>&1 &
458 > --config "hooks.txnclose=touch sync-txn-close" > output.txt 2>&1 &
459
459
460 (read the repository while the commit transaction is pending)
460 (read the repository while the commit transaction is pending)
461
461
462 $ wait-on-file 20 sync-txn-pending && \
462 $ wait-on-file 20 sync-txn-pending && \
463 > hg debugnodemap --metadata && \
463 > hg debugnodemap --metadata && \
464 > wait-on-file 20 sync-txn-close sync-repo-read
464 > wait-on-file 20 sync-txn-close sync-repo-read
465 uid: ???????????????? (glob)
465 uid: ???????????????? (glob)
466 tip-rev: 5004
466 tip-rev: 5004
467 tip-node: 2f5fb1c06a16834c5679d672e90da7c5f3b1a984
467 tip-node: 2f5fb1c06a16834c5679d672e90da7c5f3b1a984
468 data-length: 121280 (pure !)
468 data-length: 121280 (pure !)
469 data-length: 121280 (rust !)
469 data-length: 121280 (rust !)
470 data-length: 121088 (no-pure no-rust !)
470 data-length: 121088 (no-pure no-rust !)
471 data-unused: 192 (pure !)
471 data-unused: 192 (pure !)
472 data-unused: 192 (rust !)
472 data-unused: 192 (rust !)
473 data-unused: 0 (no-pure no-rust !)
473 data-unused: 0 (no-pure no-rust !)
474 data-unused: 0.158% (pure !)
474 data-unused: 0.158% (pure !)
475 data-unused: 0.158% (rust !)
475 data-unused: 0.158% (rust !)
476 data-unused: 0.000% (no-pure no-rust !)
476 data-unused: 0.000% (no-pure no-rust !)
477 $ hg debugnodemap --metadata
477 $ hg debugnodemap --metadata
478 uid: ???????????????? (glob)
478 uid: ???????????????? (glob)
479 tip-rev: 5005
479 tip-rev: 5005
480 tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe
480 tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe
481 data-length: 121536 (pure !)
481 data-length: 121536 (pure !)
482 data-length: 121536 (rust !)
482 data-length: 121536 (rust !)
483 data-length: 121088 (no-pure no-rust !)
483 data-length: 121088 (no-pure no-rust !)
484 data-unused: 448 (pure !)
484 data-unused: 448 (pure !)
485 data-unused: 448 (rust !)
485 data-unused: 448 (rust !)
486 data-unused: 0 (no-pure no-rust !)
486 data-unused: 0 (no-pure no-rust !)
487 data-unused: 0.369% (pure !)
487 data-unused: 0.369% (pure !)
488 data-unused: 0.369% (rust !)
488 data-unused: 0.369% (rust !)
489 data-unused: 0.000% (no-pure no-rust !)
489 data-unused: 0.000% (no-pure no-rust !)
490
490
491 $ cat output.txt
491 $ cat output.txt
492
492
493 Check that a failing transaction will properly revert the data
493 Check that a failing transaction will properly revert the data
494
494
495 $ echo plakfe > a
495 $ echo plakfe > a
496 $ f --size --sha256 .hg/store/00changelog-*.nd
496 $ f --size --sha256 .hg/store/00changelog-*.nd
497 .hg/store/00changelog-????????????????.nd: size=121536, sha256=bb414468d225cf52d69132e1237afba34d4346ee2eb81b505027e6197b107f03 (glob) (pure !)
497 .hg/store/00changelog-????????????????.nd: size=121536, sha256=bb414468d225cf52d69132e1237afba34d4346ee2eb81b505027e6197b107f03 (glob) (pure !)
498 .hg/store/00changelog-????????????????.nd: size=121536, sha256=909ac727bc4d1c0fda5f7bff3c620c98bd4a2967c143405a1503439e33b377da (glob) (rust !)
498 .hg/store/00changelog-????????????????.nd: size=121536, sha256=909ac727bc4d1c0fda5f7bff3c620c98bd4a2967c143405a1503439e33b377da (glob) (rust !)
499 .hg/store/00changelog-????????????????.nd: size=121088, sha256=342d36d30d86dde67d3cb6c002606c4a75bcad665595d941493845066d9c8ee0 (glob) (no-pure no-rust !)
499 .hg/store/00changelog-????????????????.nd: size=121088, sha256=342d36d30d86dde67d3cb6c002606c4a75bcad665595d941493845066d9c8ee0 (glob) (no-pure no-rust !)
500 $ hg ci -m a3 --config "extensions.abort=$RUNTESTDIR/testlib/crash_transaction_late.py"
500 $ hg ci -m a3 --config "extensions.abort=$RUNTESTDIR/testlib/crash_transaction_late.py"
501 transaction abort!
501 transaction abort!
502 rollback completed
502 rollback completed
503 abort: This is a late abort
503 abort: This is a late abort
504 [255]
504 [255]
505 $ hg debugnodemap --metadata
505 $ hg debugnodemap --metadata
506 uid: ???????????????? (glob)
506 uid: ???????????????? (glob)
507 tip-rev: 5005
507 tip-rev: 5005
508 tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe
508 tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe
509 data-length: 121536 (pure !)
509 data-length: 121536 (pure !)
510 data-length: 121536 (rust !)
510 data-length: 121536 (rust !)
511 data-length: 121088 (no-pure no-rust !)
511 data-length: 121088 (no-pure no-rust !)
512 data-unused: 448 (pure !)
512 data-unused: 448 (pure !)
513 data-unused: 448 (rust !)
513 data-unused: 448 (rust !)
514 data-unused: 0 (no-pure no-rust !)
514 data-unused: 0 (no-pure no-rust !)
515 data-unused: 0.369% (pure !)
515 data-unused: 0.369% (pure !)
516 data-unused: 0.369% (rust !)
516 data-unused: 0.369% (rust !)
517 data-unused: 0.000% (no-pure no-rust !)
517 data-unused: 0.000% (no-pure no-rust !)
518 $ f --size --sha256 .hg/store/00changelog-*.nd
518 $ f --size --sha256 .hg/store/00changelog-*.nd
519 .hg/store/00changelog-????????????????.nd: size=121536, sha256=bb414468d225cf52d69132e1237afba34d4346ee2eb81b505027e6197b107f03 (glob) (pure !)
519 .hg/store/00changelog-????????????????.nd: size=121536, sha256=bb414468d225cf52d69132e1237afba34d4346ee2eb81b505027e6197b107f03 (glob) (pure !)
520 .hg/store/00changelog-????????????????.nd: size=121536, sha256=909ac727bc4d1c0fda5f7bff3c620c98bd4a2967c143405a1503439e33b377da (glob) (rust !)
520 .hg/store/00changelog-????????????????.nd: size=121536, sha256=909ac727bc4d1c0fda5f7bff3c620c98bd4a2967c143405a1503439e33b377da (glob) (rust !)
521 .hg/store/00changelog-????????????????.nd: size=121088, sha256=342d36d30d86dde67d3cb6c002606c4a75bcad665595d941493845066d9c8ee0 (glob) (no-pure no-rust !)
521 .hg/store/00changelog-????????????????.nd: size=121088, sha256=342d36d30d86dde67d3cb6c002606c4a75bcad665595d941493845066d9c8ee0 (glob) (no-pure no-rust !)
522
522
523 Check that removing content does not confuse the nodemap
523 Check that removing content does not confuse the nodemap
524 --------------------------------------------------------
524 --------------------------------------------------------
525
525
526 removing data with rollback
526 removing data with rollback
527
527
528 $ echo aso > a
528 $ echo aso > a
529 $ hg ci -m a4
529 $ hg ci -m a4
530 $ hg rollback
530 $ hg rollback
531 repository tip rolled back to revision 5005 (undo commit)
531 repository tip rolled back to revision 5005 (undo commit)
532 working directory now based on revision 5005
532 working directory now based on revision 5005
533 $ hg id -r .
533 $ hg id -r .
534 90d5d3ba2fc4 tip
534 90d5d3ba2fc4 tip
535
535
536 roming data with strip
536 roming data with strip
537
537
538 $ echo aso > a
538 $ echo aso > a
539 $ hg ci -m a4
539 $ hg ci -m a4
540 $ hg --config extensions.strip= strip -r . --no-backup
540 $ hg --config extensions.strip= strip -r . --no-backup
541 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
541 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
542 $ hg id -r . --traceback
542 $ hg id -r . --traceback
543 90d5d3ba2fc4 tip
543 90d5d3ba2fc4 tip
544
544
545 Test upgrade / downgrade
545 Test upgrade / downgrade
546 ========================
546 ========================
547
547
548 downgrading
548 downgrading
549
549
550 $ cat << EOF >> .hg/hgrc
550 $ cat << EOF >> .hg/hgrc
551 > [format]
551 > [format]
552 > use-persistent-nodemap=no
552 > use-persistent-nodemap=no
553 > EOF
553 > EOF
554 $ hg debugformat -v
554 $ hg debugformat -v
555 format-variant repo config default
555 format-variant repo config default
556 fncache: yes yes yes
556 fncache: yes yes yes
557 dotencode: yes yes yes
557 dotencode: yes yes yes
558 generaldelta: yes yes yes
558 generaldelta: yes yes yes
559 exp-sharesafe: no no no
559 exp-sharesafe: no no no
560 sparserevlog: yes yes yes
560 sparserevlog: yes yes yes
561 sidedata: no no no
561 sidedata: no no no
562 persistent-nodemap: yes no no
562 persistent-nodemap: yes no no
563 copies-sdc: no no no
563 copies-sdc: no no no
564 plain-cl-delta: yes yes yes
564 plain-cl-delta: yes yes yes
565 compression: zlib zlib zlib
565 compression: zlib zlib zlib
566 compression-level: default default default
566 compression-level: default default default
567 $ hg debugupgraderepo --run --no-backup --quiet
567 $ hg debugupgraderepo --run --no-backup --quiet
568 upgrade will perform the following actions:
568 upgrade will perform the following actions:
569
569
570 requirements
570 requirements
571 preserved: dotencode, fncache, generaldelta, revlogv1, sparserevlog, store
571 preserved: dotencode, fncache, generaldelta, revlogv1, sparserevlog, store
572 removed: persistent-nodemap
572 removed: persistent-nodemap
573
573
574 processed revlogs:
574 processed revlogs:
575 - all-filelogs
575 - all-filelogs
576 - changelog
576 - changelog
577 - manifest
577 - manifest
578
578
579 $ ls -1 .hg/store/ | egrep '00(changelog|manifest)(\.n|-.*\.nd)'
579 $ ls -1 .hg/store/ | egrep '00(changelog|manifest)(\.n|-.*\.nd)'
580 [1]
580 [1]
581 $ hg debugnodemap --metadata
581 $ hg debugnodemap --metadata
582
582
583
583
584 upgrading
584 upgrading
585
585
586 $ cat << EOF >> .hg/hgrc
586 $ cat << EOF >> .hg/hgrc
587 > [format]
587 > [format]
588 > use-persistent-nodemap=yes
588 > use-persistent-nodemap=yes
589 > EOF
589 > EOF
590 $ hg debugformat -v
590 $ hg debugformat -v
591 format-variant repo config default
591 format-variant repo config default
592 fncache: yes yes yes
592 fncache: yes yes yes
593 dotencode: yes yes yes
593 dotencode: yes yes yes
594 generaldelta: yes yes yes
594 generaldelta: yes yes yes
595 exp-sharesafe: no no no
595 exp-sharesafe: no no no
596 sparserevlog: yes yes yes
596 sparserevlog: yes yes yes
597 sidedata: no no no
597 sidedata: no no no
598 persistent-nodemap: no yes no
598 persistent-nodemap: no yes no
599 copies-sdc: no no no
599 copies-sdc: no no no
600 plain-cl-delta: yes yes yes
600 plain-cl-delta: yes yes yes
601 compression: zlib zlib zlib
601 compression: zlib zlib zlib
602 compression-level: default default default
602 compression-level: default default default
603 $ hg debugupgraderepo --run --no-backup --quiet
603 $ hg debugupgraderepo --run --no-backup --quiet
604 upgrade will perform the following actions:
604 upgrade will perform the following actions:
605
605
606 requirements
606 requirements
607 preserved: dotencode, fncache, generaldelta, revlogv1, sparserevlog, store
607 preserved: dotencode, fncache, generaldelta, revlogv1, sparserevlog, store
608 added: persistent-nodemap
608 added: persistent-nodemap
609
609
610 processed revlogs:
610 processed revlogs:
611 - all-filelogs
611 - all-filelogs
612 - changelog
612 - changelog
613 - manifest
613 - manifest
614
614
615 $ ls -1 .hg/store/ | egrep '00(changelog|manifest)(\.n|-.*\.nd)'
615 $ ls -1 .hg/store/ | egrep '00(changelog|manifest)(\.n|-.*\.nd)'
616 00changelog-*.nd (glob)
616 00changelog-*.nd (glob)
617 00changelog.n
617 00changelog.n
618 00manifest-*.nd (glob)
618 00manifest-*.nd (glob)
619 00manifest.n
619 00manifest.n
620
620
621 $ hg debugnodemap --metadata
621 $ hg debugnodemap --metadata
622 uid: * (glob)
622 uid: * (glob)
623 tip-rev: 5005
623 tip-rev: 5005
624 tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe
624 tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe
625 data-length: 121088
625 data-length: 121088
626 data-unused: 0
626 data-unused: 0
627 data-unused: 0.000%
627 data-unused: 0.000%
628
628
629 Running unrelated upgrade
629 Running unrelated upgrade
630
630
631 $ hg debugupgraderepo --run --no-backup --quiet --optimize re-delta-all
631 $ hg debugupgraderepo --run --no-backup --quiet --optimize re-delta-all
632 upgrade will perform the following actions:
632 upgrade will perform the following actions:
633
633
634 requirements
634 requirements
635 preserved: dotencode, fncache, generaldelta, persistent-nodemap, revlogv1, sparserevlog, store
635 preserved: dotencode, fncache, generaldelta, persistent-nodemap, revlogv1, sparserevlog, store
636
636
637 optimisations: re-delta-all
637 optimisations: re-delta-all
638
638
639 processed revlogs:
639 processed revlogs:
640 - all-filelogs
640 - all-filelogs
641 - changelog
641 - changelog
642 - manifest
642 - manifest
643
643
644 $ ls -1 .hg/store/ | egrep '00(changelog|manifest)(\.n|-.*\.nd)'
644 $ ls -1 .hg/store/ | egrep '00(changelog|manifest)(\.n|-.*\.nd)'
645 00changelog-*.nd (glob)
645 00changelog-*.nd (glob)
646 00changelog.n
646 00changelog.n
647 00manifest-*.nd (glob)
647 00manifest-*.nd (glob)
648 00manifest.n
648 00manifest.n
649
649
650 $ hg debugnodemap --metadata
650 $ hg debugnodemap --metadata
651 uid: * (glob)
651 uid: * (glob)
652 tip-rev: 5005
652 tip-rev: 5005
653 tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe
653 tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe
654 data-length: 121088
654 data-length: 121088
655 data-unused: 0
655 data-unused: 0
656 data-unused: 0.000%
656 data-unused: 0.000%
657
657
658 Persistent nodemap and local/streaming clone
658 Persistent nodemap and local/streaming clone
659 ============================================
659 ============================================
660
660
661 $ cd ..
661 $ cd ..
662
662
663 standard clone
663 standard clone
664 --------------
664 --------------
665
665
666 The persistent nodemap should exist after a streaming clone
666 The persistent nodemap should exist after a streaming clone
667
667
668 $ hg clone --pull --quiet -U test-repo standard-clone
668 $ hg clone --pull --quiet -U test-repo standard-clone
669 $ ls -1 standard-clone/.hg/store/ | egrep '00(changelog|manifest)(\.n|-.*\.nd)'
669 $ ls -1 standard-clone/.hg/store/ | egrep '00(changelog|manifest)(\.n|-.*\.nd)'
670 00changelog-*.nd (glob)
670 00changelog-*.nd (glob)
671 00changelog.n
671 00changelog.n
672 00manifest-*.nd (glob)
672 00manifest-*.nd (glob)
673 00manifest.n
673 00manifest.n
674 $ hg -R standard-clone debugnodemap --metadata
674 $ hg -R standard-clone debugnodemap --metadata
675 uid: * (glob)
675 uid: * (glob)
676 tip-rev: 5005
676 tip-rev: 5005
677 tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe
677 tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe
678 data-length: 121088
678 data-length: 121088
679 data-unused: 0
679 data-unused: 0
680 data-unused: 0.000%
680 data-unused: 0.000%
681
681
682
682
683 local clone
683 local clone
684 ------------
684 ------------
685
685
686 The persistent nodemap should exist after a streaming clone
686 The persistent nodemap should exist after a streaming clone
687
687
688 $ hg clone -U test-repo local-clone
688 $ hg clone -U test-repo local-clone
689 $ ls -1 local-clone/.hg/store/ | egrep '00(changelog|manifest)(\.n|-.*\.nd)'
689 $ ls -1 local-clone/.hg/store/ | egrep '00(changelog|manifest)(\.n|-.*\.nd)'
690 00changelog-*.nd (glob)
690 00changelog-*.nd (glob)
691 00changelog.n
691 00changelog.n
692 00manifest-*.nd (glob)
692 00manifest-*.nd (glob)
693 00manifest.n
693 00manifest.n
694 $ hg -R local-clone debugnodemap --metadata
694 $ hg -R local-clone debugnodemap --metadata
695 uid: * (glob)
695 uid: * (glob)
696 tip-rev: 5005
696 tip-rev: 5005
697 tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe
697 tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe
698 data-length: 121088
698 data-length: 121088
699 data-unused: 0
699 data-unused: 0
700 data-unused: 0.000%
700 data-unused: 0.000%
701
701
702 stream clone
702 stream clone
703 ------------
703 ------------
704
704
705 The persistent nodemap should exist after a streaming clone
705 The persistent nodemap should exist after a streaming clone
706
706
707 $ hg clone -U --stream --config ui.ssh="\"$PYTHON\" \"$TESTDIR/dummyssh\"" ssh://user@dummy/test-repo stream-clone --debug | egrep '00(changelog|manifest)'
707 $ hg clone -U --stream --config ui.ssh="\"$PYTHON\" \"$TESTDIR/dummyssh\"" ssh://user@dummy/test-repo stream-clone --debug | egrep '00(changelog|manifest)'
708 adding [s] 00manifest.n (70 bytes)
708 adding [s] 00manifest.n (70 bytes)
709 adding [s] 00manifest.i (313 KB)
709 adding [s] 00manifest.i (313 KB)
710 adding [s] 00manifest.d (452 KB)
710 adding [s] 00manifest.d (452 KB)
711 adding [s] 00manifest-*.nd (118 KB) (glob)
711 adding [s] 00changelog.n (70 bytes)
712 adding [s] 00changelog.n (70 bytes)
712 adding [s] 00changelog.i (313 KB)
713 adding [s] 00changelog.i (313 KB)
713 adding [s] 00changelog.d (360 KB)
714 adding [s] 00changelog.d (360 KB)
715 adding [s] 00changelog-*.nd (118 KB) (glob)
714 $ ls -1 stream-clone/.hg/store/ | egrep '00(changelog|manifest)(\.n|-.*\.nd)'
716 $ ls -1 stream-clone/.hg/store/ | egrep '00(changelog|manifest)(\.n|-.*\.nd)'
715 00changelog-*.nd (glob)
717 00changelog-*.nd (glob)
716 00changelog.n
718 00changelog.n
717 00manifest-*.nd (glob)
719 00manifest-*.nd (glob)
718 00manifest.n
720 00manifest.n
719 $ hg -R stream-clone debugnodemap --metadata
721 $ hg -R stream-clone debugnodemap --metadata
720 uid: * (glob)
722 uid: * (glob)
721 tip-rev: 5005
723 tip-rev: 5005
722 tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe
724 tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe
723 data-length: 121088
725 data-length: 121088
724 data-unused: 0
726 data-unused: 0
725 data-unused: 0.000%
727 data-unused: 0.000%
General Comments 0
You need to be logged in to leave comments. Login now