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