##// END OF EJS Templates
persistent-nodemap: catch the right exception on python...
marmoute -
r47039:d32e7ed8 default
parent child Browse files
Show More
@@ -1,636 +1,636 b''
1 # nodemap.py - nodemap related code and utilities
1 # nodemap.py - nodemap related code and utilities
2 #
2 #
3 # Copyright 2019 Pierre-Yves David <pierre-yves.david@octobus.net>
3 # Copyright 2019 Pierre-Yves David <pierre-yves.david@octobus.net>
4 # Copyright 2019 George Racinet <georges.racinet@octobus.net>
4 # Copyright 2019 George Racinet <georges.racinet@octobus.net>
5 #
5 #
6 # This software may be used and distributed according to the terms of the
6 # This software may be used and distributed according to the terms of the
7 # GNU General Public License version 2 or any later version.
7 # GNU General Public License version 2 or any later version.
8
8
9 from __future__ import absolute_import
9 from __future__ import absolute_import
10
10
11 import errno
11 import errno
12 import os
12 import os
13 import re
13 import re
14 import struct
14 import struct
15
15
16 from ..node import hex
16 from ..node import hex
17
17
18 from .. import (
18 from .. import (
19 error,
19 error,
20 util,
20 util,
21 )
21 )
22
22
23
23
24 class NodeMap(dict):
24 class NodeMap(dict):
25 def __missing__(self, x):
25 def __missing__(self, x):
26 raise error.RevlogError(b'unknown node: %s' % x)
26 raise error.RevlogError(b'unknown node: %s' % x)
27
27
28
28
29 def persisted_data(revlog):
29 def persisted_data(revlog):
30 """read the nodemap for a revlog from disk"""
30 """read the nodemap for a revlog from disk"""
31 if revlog.nodemap_file is None:
31 if revlog.nodemap_file is None:
32 return None
32 return None
33 pdata = revlog.opener.tryread(revlog.nodemap_file)
33 pdata = revlog.opener.tryread(revlog.nodemap_file)
34 if not pdata:
34 if not pdata:
35 return None
35 return None
36 offset = 0
36 offset = 0
37 (version,) = S_VERSION.unpack(pdata[offset : offset + S_VERSION.size])
37 (version,) = S_VERSION.unpack(pdata[offset : offset + S_VERSION.size])
38 if version != ONDISK_VERSION:
38 if version != ONDISK_VERSION:
39 return None
39 return None
40 offset += S_VERSION.size
40 offset += S_VERSION.size
41 headers = S_HEADER.unpack(pdata[offset : offset + S_HEADER.size])
41 headers = S_HEADER.unpack(pdata[offset : offset + S_HEADER.size])
42 uid_size, tip_rev, data_length, data_unused, tip_node_size = headers
42 uid_size, tip_rev, data_length, data_unused, tip_node_size = headers
43 offset += S_HEADER.size
43 offset += S_HEADER.size
44 docket = NodeMapDocket(pdata[offset : offset + uid_size])
44 docket = NodeMapDocket(pdata[offset : offset + uid_size])
45 offset += uid_size
45 offset += uid_size
46 docket.tip_rev = tip_rev
46 docket.tip_rev = tip_rev
47 docket.tip_node = pdata[offset : offset + tip_node_size]
47 docket.tip_node = pdata[offset : offset + tip_node_size]
48 docket.data_length = data_length
48 docket.data_length = data_length
49 docket.data_unused = data_unused
49 docket.data_unused = data_unused
50
50
51 filename = _rawdata_filepath(revlog, docket)
51 filename = _rawdata_filepath(revlog, docket)
52 use_mmap = revlog.opener.options.get(b"persistent-nodemap.mmap")
52 use_mmap = revlog.opener.options.get(b"persistent-nodemap.mmap")
53 try:
53 try:
54 with revlog.opener(filename) as fd:
54 with revlog.opener(filename) as fd:
55 if use_mmap:
55 if use_mmap:
56 data = util.buffer(util.mmapread(fd, data_length))
56 data = util.buffer(util.mmapread(fd, data_length))
57 else:
57 else:
58 data = fd.read(data_length)
58 data = fd.read(data_length)
59 except OSError as e:
59 except (IOError, OSError) as e:
60 if e.errno == errno.ENOENT:
60 if e.errno == errno.ENOENT:
61 return None
61 return None
62 else:
62 else:
63 raise
63 raise
64 if len(data) < data_length:
64 if len(data) < data_length:
65 return None
65 return None
66 return docket, data
66 return docket, data
67
67
68
68
69 def setup_persistent_nodemap(tr, revlog):
69 def setup_persistent_nodemap(tr, revlog):
70 """Install whatever is needed transaction side to persist a nodemap on disk
70 """Install whatever is needed transaction side to persist a nodemap on disk
71
71
72 (only actually persist the nodemap if this is relevant for this revlog)
72 (only actually persist the nodemap if this is relevant for this revlog)
73 """
73 """
74 if revlog._inline:
74 if revlog._inline:
75 return # inlined revlog are too small for this to be relevant
75 return # inlined revlog are too small for this to be relevant
76 if revlog.nodemap_file is None:
76 if revlog.nodemap_file is None:
77 return # we do not use persistent_nodemap on this revlog
77 return # we do not use persistent_nodemap on this revlog
78
78
79 # we need to happen after the changelog finalization, in that use "cl-"
79 # we need to happen after the changelog finalization, in that use "cl-"
80 callback_id = b"nm-revlog-persistent-nodemap-%s" % revlog.nodemap_file
80 callback_id = b"nm-revlog-persistent-nodemap-%s" % revlog.nodemap_file
81 if tr.hasfinalize(callback_id):
81 if tr.hasfinalize(callback_id):
82 return # no need to register again
82 return # no need to register again
83 tr.addpending(
83 tr.addpending(
84 callback_id, lambda tr: _persist_nodemap(tr, revlog, pending=True)
84 callback_id, lambda tr: _persist_nodemap(tr, revlog, pending=True)
85 )
85 )
86 tr.addfinalize(callback_id, lambda tr: _persist_nodemap(tr, revlog))
86 tr.addfinalize(callback_id, lambda tr: _persist_nodemap(tr, revlog))
87
87
88
88
89 class _NoTransaction(object):
89 class _NoTransaction(object):
90 """transaction like object to update the nodemap outside a transaction"""
90 """transaction like object to update the nodemap outside a transaction"""
91
91
92 def __init__(self):
92 def __init__(self):
93 self._postclose = {}
93 self._postclose = {}
94
94
95 def addpostclose(self, callback_id, callback_func):
95 def addpostclose(self, callback_id, callback_func):
96 self._postclose[callback_id] = callback_func
96 self._postclose[callback_id] = callback_func
97
97
98 def registertmp(self, *args, **kwargs):
98 def registertmp(self, *args, **kwargs):
99 pass
99 pass
100
100
101 def addbackup(self, *args, **kwargs):
101 def addbackup(self, *args, **kwargs):
102 pass
102 pass
103
103
104 def add(self, *args, **kwargs):
104 def add(self, *args, **kwargs):
105 pass
105 pass
106
106
107 def addabort(self, *args, **kwargs):
107 def addabort(self, *args, **kwargs):
108 pass
108 pass
109
109
110 def _report(self, *args):
110 def _report(self, *args):
111 pass
111 pass
112
112
113
113
114 def update_persistent_nodemap(revlog):
114 def update_persistent_nodemap(revlog):
115 """update the persistent nodemap right now
115 """update the persistent nodemap right now
116
116
117 To be used for updating the nodemap on disk outside of a normal transaction
117 To be used for updating the nodemap on disk outside of a normal transaction
118 setup (eg, `debugupdatecache`).
118 setup (eg, `debugupdatecache`).
119 """
119 """
120 if revlog._inline:
120 if revlog._inline:
121 return # inlined revlog are too small for this to be relevant
121 return # inlined revlog are too small for this to be relevant
122 if revlog.nodemap_file is None:
122 if revlog.nodemap_file is None:
123 return # we do not use persistent_nodemap on this revlog
123 return # we do not use persistent_nodemap on this revlog
124
124
125 notr = _NoTransaction()
125 notr = _NoTransaction()
126 _persist_nodemap(notr, revlog)
126 _persist_nodemap(notr, revlog)
127 for k in sorted(notr._postclose):
127 for k in sorted(notr._postclose):
128 notr._postclose[k](None)
128 notr._postclose[k](None)
129
129
130
130
131 def _persist_nodemap(tr, revlog, pending=False):
131 def _persist_nodemap(tr, revlog, pending=False):
132 """Write nodemap data on disk for a given revlog"""
132 """Write nodemap data on disk for a given revlog"""
133 if getattr(revlog, 'filteredrevs', ()):
133 if getattr(revlog, 'filteredrevs', ()):
134 raise error.ProgrammingError(
134 raise error.ProgrammingError(
135 "cannot persist nodemap of a filtered changelog"
135 "cannot persist nodemap of a filtered changelog"
136 )
136 )
137 if revlog.nodemap_file is None:
137 if revlog.nodemap_file is None:
138 msg = "calling persist nodemap on a revlog without the feature enableb"
138 msg = "calling persist nodemap on a revlog without the feature enableb"
139 raise error.ProgrammingError(msg)
139 raise error.ProgrammingError(msg)
140
140
141 can_incremental = util.safehasattr(revlog.index, "nodemap_data_incremental")
141 can_incremental = util.safehasattr(revlog.index, "nodemap_data_incremental")
142 ondisk_docket = revlog._nodemap_docket
142 ondisk_docket = revlog._nodemap_docket
143 feed_data = util.safehasattr(revlog.index, "update_nodemap_data")
143 feed_data = util.safehasattr(revlog.index, "update_nodemap_data")
144 use_mmap = revlog.opener.options.get(b"persistent-nodemap.mmap")
144 use_mmap = revlog.opener.options.get(b"persistent-nodemap.mmap")
145
145
146 data = None
146 data = None
147 # first attemp an incremental update of the data
147 # first attemp an incremental update of the data
148 if can_incremental and ondisk_docket is not None:
148 if can_incremental and ondisk_docket is not None:
149 target_docket = revlog._nodemap_docket.copy()
149 target_docket = revlog._nodemap_docket.copy()
150 (
150 (
151 src_docket,
151 src_docket,
152 data_changed_count,
152 data_changed_count,
153 data,
153 data,
154 ) = revlog.index.nodemap_data_incremental()
154 ) = revlog.index.nodemap_data_incremental()
155 new_length = target_docket.data_length + len(data)
155 new_length = target_docket.data_length + len(data)
156 new_unused = target_docket.data_unused + data_changed_count
156 new_unused = target_docket.data_unused + data_changed_count
157 if src_docket != target_docket:
157 if src_docket != target_docket:
158 data = None
158 data = None
159 elif new_length <= (new_unused * 10): # under 10% of unused data
159 elif new_length <= (new_unused * 10): # under 10% of unused data
160 data = None
160 data = None
161 else:
161 else:
162 datafile = _rawdata_filepath(revlog, target_docket)
162 datafile = _rawdata_filepath(revlog, target_docket)
163 # EXP-TODO: if this is a cache, this should use a cache vfs, not a
163 # EXP-TODO: if this is a cache, this should use a cache vfs, not a
164 # store vfs
164 # store vfs
165 tr.add(datafile, target_docket.data_length)
165 tr.add(datafile, target_docket.data_length)
166 with revlog.opener(datafile, b'r+') as fd:
166 with revlog.opener(datafile, b'r+') as fd:
167 fd.seek(target_docket.data_length)
167 fd.seek(target_docket.data_length)
168 fd.write(data)
168 fd.write(data)
169 if feed_data:
169 if feed_data:
170 if use_mmap:
170 if use_mmap:
171 fd.seek(0)
171 fd.seek(0)
172 new_data = fd.read(new_length)
172 new_data = fd.read(new_length)
173 else:
173 else:
174 fd.flush()
174 fd.flush()
175 new_data = util.buffer(util.mmapread(fd, new_length))
175 new_data = util.buffer(util.mmapread(fd, new_length))
176 target_docket.data_length = new_length
176 target_docket.data_length = new_length
177 target_docket.data_unused = new_unused
177 target_docket.data_unused = new_unused
178
178
179 if data is None:
179 if data is None:
180 # otherwise fallback to a full new export
180 # otherwise fallback to a full new export
181 target_docket = NodeMapDocket()
181 target_docket = NodeMapDocket()
182 datafile = _rawdata_filepath(revlog, target_docket)
182 datafile = _rawdata_filepath(revlog, target_docket)
183 if util.safehasattr(revlog.index, "nodemap_data_all"):
183 if util.safehasattr(revlog.index, "nodemap_data_all"):
184 data = revlog.index.nodemap_data_all()
184 data = revlog.index.nodemap_data_all()
185 else:
185 else:
186 data = persistent_data(revlog.index)
186 data = persistent_data(revlog.index)
187 # EXP-TODO: if this is a cache, this should use a cache vfs, not a
187 # EXP-TODO: if this is a cache, this should use a cache vfs, not a
188 # store vfs
188 # store vfs
189
189
190 tryunlink = revlog.opener.tryunlink
190 tryunlink = revlog.opener.tryunlink
191
191
192 def abortck(tr):
192 def abortck(tr):
193 tryunlink(datafile)
193 tryunlink(datafile)
194
194
195 callback_id = b"delete-%s" % datafile
195 callback_id = b"delete-%s" % datafile
196
196
197 # some flavor of the transaction abort does not cleanup new file, it
197 # some flavor of the transaction abort does not cleanup new file, it
198 # simply empty them.
198 # simply empty them.
199 tr.addabort(callback_id, abortck)
199 tr.addabort(callback_id, abortck)
200 with revlog.opener(datafile, b'w+') as fd:
200 with revlog.opener(datafile, b'w+') as fd:
201 fd.write(data)
201 fd.write(data)
202 if feed_data:
202 if feed_data:
203 if use_mmap:
203 if use_mmap:
204 new_data = data
204 new_data = data
205 else:
205 else:
206 fd.flush()
206 fd.flush()
207 new_data = util.buffer(util.mmapread(fd, len(data)))
207 new_data = util.buffer(util.mmapread(fd, len(data)))
208 target_docket.data_length = len(data)
208 target_docket.data_length = len(data)
209 target_docket.tip_rev = revlog.tiprev()
209 target_docket.tip_rev = revlog.tiprev()
210 target_docket.tip_node = revlog.node(target_docket.tip_rev)
210 target_docket.tip_node = revlog.node(target_docket.tip_rev)
211 # EXP-TODO: if this is a cache, this should use a cache vfs, not a
211 # EXP-TODO: if this is a cache, this should use a cache vfs, not a
212 # store vfs
212 # store vfs
213 file_path = revlog.nodemap_file
213 file_path = revlog.nodemap_file
214 if pending:
214 if pending:
215 file_path += b'.a'
215 file_path += b'.a'
216 tr.registertmp(file_path)
216 tr.registertmp(file_path)
217 else:
217 else:
218 tr.addbackup(file_path)
218 tr.addbackup(file_path)
219
219
220 with revlog.opener(file_path, b'w', atomictemp=True) as fp:
220 with revlog.opener(file_path, b'w', atomictemp=True) as fp:
221 fp.write(target_docket.serialize())
221 fp.write(target_docket.serialize())
222 revlog._nodemap_docket = target_docket
222 revlog._nodemap_docket = target_docket
223 if feed_data:
223 if feed_data:
224 revlog.index.update_nodemap_data(target_docket, new_data)
224 revlog.index.update_nodemap_data(target_docket, new_data)
225
225
226 # search for old index file in all cases, some older process might have
226 # search for old index file in all cases, some older process might have
227 # left one behind.
227 # left one behind.
228 olds = _other_rawdata_filepath(revlog, target_docket)
228 olds = _other_rawdata_filepath(revlog, target_docket)
229 if olds:
229 if olds:
230 realvfs = getattr(revlog, '_realopener', revlog.opener)
230 realvfs = getattr(revlog, '_realopener', revlog.opener)
231
231
232 def cleanup(tr):
232 def cleanup(tr):
233 for oldfile in olds:
233 for oldfile in olds:
234 realvfs.tryunlink(oldfile)
234 realvfs.tryunlink(oldfile)
235
235
236 callback_id = b"revlog-cleanup-nodemap-%s" % revlog.nodemap_file
236 callback_id = b"revlog-cleanup-nodemap-%s" % revlog.nodemap_file
237 tr.addpostclose(callback_id, cleanup)
237 tr.addpostclose(callback_id, cleanup)
238
238
239
239
240 ### Nodemap docket file
240 ### Nodemap docket file
241 #
241 #
242 # The nodemap data are stored on disk using 2 files:
242 # The nodemap data are stored on disk using 2 files:
243 #
243 #
244 # * a raw data files containing a persistent nodemap
244 # * a raw data files containing a persistent nodemap
245 # (see `Nodemap Trie` section)
245 # (see `Nodemap Trie` section)
246 #
246 #
247 # * a small "docket" file containing medatadata
247 # * a small "docket" file containing medatadata
248 #
248 #
249 # While the nodemap data can be multiple tens of megabytes, the "docket" is
249 # While the nodemap data can be multiple tens of megabytes, the "docket" is
250 # small, it is easy to update it automatically or to duplicated its content
250 # small, it is easy to update it automatically or to duplicated its content
251 # during a transaction.
251 # during a transaction.
252 #
252 #
253 # Multiple raw data can exist at the same time (The currently valid one and a
253 # Multiple raw data can exist at the same time (The currently valid one and a
254 # new one beind used by an in progress transaction). To accomodate this, the
254 # new one beind used by an in progress transaction). To accomodate this, the
255 # filename hosting the raw data has a variable parts. The exact filename is
255 # filename hosting the raw data has a variable parts. The exact filename is
256 # specified inside the "docket" file.
256 # specified inside the "docket" file.
257 #
257 #
258 # The docket file contains information to find, qualify and validate the raw
258 # The docket file contains information to find, qualify and validate the raw
259 # data. Its content is currently very light, but it will expand as the on disk
259 # data. Its content is currently very light, but it will expand as the on disk
260 # nodemap gains the necessary features to be used in production.
260 # nodemap gains the necessary features to be used in production.
261
261
262 ONDISK_VERSION = 1
262 ONDISK_VERSION = 1
263 S_VERSION = struct.Struct(">B")
263 S_VERSION = struct.Struct(">B")
264 S_HEADER = struct.Struct(">BQQQQ")
264 S_HEADER = struct.Struct(">BQQQQ")
265
265
266 ID_SIZE = 8
266 ID_SIZE = 8
267
267
268
268
269 def _make_uid():
269 def _make_uid():
270 """return a new unique identifier.
270 """return a new unique identifier.
271
271
272 The identifier is random and composed of ascii characters."""
272 The identifier is random and composed of ascii characters."""
273 return hex(os.urandom(ID_SIZE))
273 return hex(os.urandom(ID_SIZE))
274
274
275
275
276 class NodeMapDocket(object):
276 class NodeMapDocket(object):
277 """metadata associated with persistent nodemap data
277 """metadata associated with persistent nodemap data
278
278
279 The persistent data may come from disk or be on their way to disk.
279 The persistent data may come from disk or be on their way to disk.
280 """
280 """
281
281
282 def __init__(self, uid=None):
282 def __init__(self, uid=None):
283 if uid is None:
283 if uid is None:
284 uid = _make_uid()
284 uid = _make_uid()
285 # a unique identifier for the data file:
285 # a unique identifier for the data file:
286 # - When new data are appended, it is preserved.
286 # - When new data are appended, it is preserved.
287 # - When a new data file is created, a new identifier is generated.
287 # - When a new data file is created, a new identifier is generated.
288 self.uid = uid
288 self.uid = uid
289 # the tipmost revision stored in the data file. This revision and all
289 # the tipmost revision stored in the data file. This revision and all
290 # revision before it are expected to be encoded in the data file.
290 # revision before it are expected to be encoded in the data file.
291 self.tip_rev = None
291 self.tip_rev = None
292 # the node of that tipmost revision, if it mismatch the current index
292 # the node of that tipmost revision, if it mismatch the current index
293 # data the docket is not valid for the current index and should be
293 # data the docket is not valid for the current index and should be
294 # discarded.
294 # discarded.
295 #
295 #
296 # note: this method is not perfect as some destructive operation could
296 # note: this method is not perfect as some destructive operation could
297 # preserve the same tip_rev + tip_node while altering lower revision.
297 # preserve the same tip_rev + tip_node while altering lower revision.
298 # However this multiple other caches have the same vulnerability (eg:
298 # However this multiple other caches have the same vulnerability (eg:
299 # brancmap cache).
299 # brancmap cache).
300 self.tip_node = None
300 self.tip_node = None
301 # the size (in bytes) of the persisted data to encode the nodemap valid
301 # the size (in bytes) of the persisted data to encode the nodemap valid
302 # for `tip_rev`.
302 # for `tip_rev`.
303 # - data file shorter than this are corrupted,
303 # - data file shorter than this are corrupted,
304 # - any extra data should be ignored.
304 # - any extra data should be ignored.
305 self.data_length = None
305 self.data_length = None
306 # the amount (in bytes) of "dead" data, still in the data file but no
306 # the amount (in bytes) of "dead" data, still in the data file but no
307 # longer used for the nodemap.
307 # longer used for the nodemap.
308 self.data_unused = 0
308 self.data_unused = 0
309
309
310 def copy(self):
310 def copy(self):
311 new = NodeMapDocket(uid=self.uid)
311 new = NodeMapDocket(uid=self.uid)
312 new.tip_rev = self.tip_rev
312 new.tip_rev = self.tip_rev
313 new.tip_node = self.tip_node
313 new.tip_node = self.tip_node
314 new.data_length = self.data_length
314 new.data_length = self.data_length
315 new.data_unused = self.data_unused
315 new.data_unused = self.data_unused
316 return new
316 return new
317
317
318 def __cmp__(self, other):
318 def __cmp__(self, other):
319 if self.uid < other.uid:
319 if self.uid < other.uid:
320 return -1
320 return -1
321 if self.uid > other.uid:
321 if self.uid > other.uid:
322 return 1
322 return 1
323 elif self.data_length < other.data_length:
323 elif self.data_length < other.data_length:
324 return -1
324 return -1
325 elif self.data_length > other.data_length:
325 elif self.data_length > other.data_length:
326 return 1
326 return 1
327 return 0
327 return 0
328
328
329 def __eq__(self, other):
329 def __eq__(self, other):
330 return self.uid == other.uid and self.data_length == other.data_length
330 return self.uid == other.uid and self.data_length == other.data_length
331
331
332 def serialize(self):
332 def serialize(self):
333 """return serialized bytes for a docket using the passed uid"""
333 """return serialized bytes for a docket using the passed uid"""
334 data = []
334 data = []
335 data.append(S_VERSION.pack(ONDISK_VERSION))
335 data.append(S_VERSION.pack(ONDISK_VERSION))
336 headers = (
336 headers = (
337 len(self.uid),
337 len(self.uid),
338 self.tip_rev,
338 self.tip_rev,
339 self.data_length,
339 self.data_length,
340 self.data_unused,
340 self.data_unused,
341 len(self.tip_node),
341 len(self.tip_node),
342 )
342 )
343 data.append(S_HEADER.pack(*headers))
343 data.append(S_HEADER.pack(*headers))
344 data.append(self.uid)
344 data.append(self.uid)
345 data.append(self.tip_node)
345 data.append(self.tip_node)
346 return b''.join(data)
346 return b''.join(data)
347
347
348
348
349 def _rawdata_filepath(revlog, docket):
349 def _rawdata_filepath(revlog, docket):
350 """The (vfs relative) nodemap's rawdata file for a given uid"""
350 """The (vfs relative) nodemap's rawdata file for a given uid"""
351 if revlog.nodemap_file.endswith(b'.n.a'):
351 if revlog.nodemap_file.endswith(b'.n.a'):
352 prefix = revlog.nodemap_file[:-4]
352 prefix = revlog.nodemap_file[:-4]
353 else:
353 else:
354 prefix = revlog.nodemap_file[:-2]
354 prefix = revlog.nodemap_file[:-2]
355 return b"%s-%s.nd" % (prefix, docket.uid)
355 return b"%s-%s.nd" % (prefix, docket.uid)
356
356
357
357
358 def _other_rawdata_filepath(revlog, docket):
358 def _other_rawdata_filepath(revlog, docket):
359 prefix = revlog.nodemap_file[:-2]
359 prefix = revlog.nodemap_file[:-2]
360 pattern = re.compile(br"(^|/)%s-[0-9a-f]+\.nd$" % prefix)
360 pattern = re.compile(br"(^|/)%s-[0-9a-f]+\.nd$" % prefix)
361 new_file_path = _rawdata_filepath(revlog, docket)
361 new_file_path = _rawdata_filepath(revlog, docket)
362 new_file_name = revlog.opener.basename(new_file_path)
362 new_file_name = revlog.opener.basename(new_file_path)
363 dirpath = revlog.opener.dirname(new_file_path)
363 dirpath = revlog.opener.dirname(new_file_path)
364 others = []
364 others = []
365 for f in revlog.opener.listdir(dirpath):
365 for f in revlog.opener.listdir(dirpath):
366 if pattern.match(f) and f != new_file_name:
366 if pattern.match(f) and f != new_file_name:
367 others.append(f)
367 others.append(f)
368 return others
368 return others
369
369
370
370
371 ### Nodemap Trie
371 ### Nodemap Trie
372 #
372 #
373 # This is a simple reference implementation to compute and persist a nodemap
373 # This is a simple reference implementation to compute and persist a nodemap
374 # trie. This reference implementation is write only. The python version of this
374 # trie. This reference implementation is write only. The python version of this
375 # is not expected to be actually used, since it wont provide performance
375 # is not expected to be actually used, since it wont provide performance
376 # improvement over existing non-persistent C implementation.
376 # improvement over existing non-persistent C implementation.
377 #
377 #
378 # The nodemap is persisted as Trie using 4bits-address/16-entries block. each
378 # The nodemap is persisted as Trie using 4bits-address/16-entries block. each
379 # revision can be adressed using its node shortest prefix.
379 # revision can be adressed using its node shortest prefix.
380 #
380 #
381 # The trie is stored as a sequence of block. Each block contains 16 entries
381 # The trie is stored as a sequence of block. Each block contains 16 entries
382 # (signed 64bit integer, big endian). Each entry can be one of the following:
382 # (signed 64bit integer, big endian). Each entry can be one of the following:
383 #
383 #
384 # * value >= 0 -> index of sub-block
384 # * value >= 0 -> index of sub-block
385 # * value == -1 -> no value
385 # * value == -1 -> no value
386 # * value < -1 -> encoded revision: rev = -(value+2)
386 # * value < -1 -> encoded revision: rev = -(value+2)
387 #
387 #
388 # See REV_OFFSET and _transform_rev below.
388 # See REV_OFFSET and _transform_rev below.
389 #
389 #
390 # The implementation focus on simplicity, not on performance. A Rust
390 # The implementation focus on simplicity, not on performance. A Rust
391 # implementation should provide a efficient version of the same binary
391 # implementation should provide a efficient version of the same binary
392 # persistence. This reference python implementation is never meant to be
392 # persistence. This reference python implementation is never meant to be
393 # extensively use in production.
393 # extensively use in production.
394
394
395
395
396 def persistent_data(index):
396 def persistent_data(index):
397 """return the persistent binary form for a nodemap for a given index"""
397 """return the persistent binary form for a nodemap for a given index"""
398 trie = _build_trie(index)
398 trie = _build_trie(index)
399 return _persist_trie(trie)
399 return _persist_trie(trie)
400
400
401
401
402 def update_persistent_data(index, root, max_idx, last_rev):
402 def update_persistent_data(index, root, max_idx, last_rev):
403 """return the incremental update for persistent nodemap from a given index"""
403 """return the incremental update for persistent nodemap from a given index"""
404 changed_block, trie = _update_trie(index, root, last_rev)
404 changed_block, trie = _update_trie(index, root, last_rev)
405 return (
405 return (
406 changed_block * S_BLOCK.size,
406 changed_block * S_BLOCK.size,
407 _persist_trie(trie, existing_idx=max_idx),
407 _persist_trie(trie, existing_idx=max_idx),
408 )
408 )
409
409
410
410
411 S_BLOCK = struct.Struct(">" + ("l" * 16))
411 S_BLOCK = struct.Struct(">" + ("l" * 16))
412
412
413 NO_ENTRY = -1
413 NO_ENTRY = -1
414 # rev 0 need to be -2 because 0 is used by block, -1 is a special value.
414 # rev 0 need to be -2 because 0 is used by block, -1 is a special value.
415 REV_OFFSET = 2
415 REV_OFFSET = 2
416
416
417
417
418 def _transform_rev(rev):
418 def _transform_rev(rev):
419 """Return the number used to represent the rev in the tree.
419 """Return the number used to represent the rev in the tree.
420
420
421 (or retrieve a rev number from such representation)
421 (or retrieve a rev number from such representation)
422
422
423 Note that this is an involution, a function equal to its inverse (i.e.
423 Note that this is an involution, a function equal to its inverse (i.e.
424 which gives the identity when applied to itself).
424 which gives the identity when applied to itself).
425 """
425 """
426 return -(rev + REV_OFFSET)
426 return -(rev + REV_OFFSET)
427
427
428
428
429 def _to_int(hex_digit):
429 def _to_int(hex_digit):
430 """turn an hexadecimal digit into a proper integer"""
430 """turn an hexadecimal digit into a proper integer"""
431 return int(hex_digit, 16)
431 return int(hex_digit, 16)
432
432
433
433
434 class Block(dict):
434 class Block(dict):
435 """represent a block of the Trie
435 """represent a block of the Trie
436
436
437 contains up to 16 entry indexed from 0 to 15"""
437 contains up to 16 entry indexed from 0 to 15"""
438
438
439 def __init__(self):
439 def __init__(self):
440 super(Block, self).__init__()
440 super(Block, self).__init__()
441 # If this block exist on disk, here is its ID
441 # If this block exist on disk, here is its ID
442 self.ondisk_id = None
442 self.ondisk_id = None
443
443
444 def __iter__(self):
444 def __iter__(self):
445 return iter(self.get(i) for i in range(16))
445 return iter(self.get(i) for i in range(16))
446
446
447
447
448 def _build_trie(index):
448 def _build_trie(index):
449 """build a nodemap trie
449 """build a nodemap trie
450
450
451 The nodemap stores revision number for each unique prefix.
451 The nodemap stores revision number for each unique prefix.
452
452
453 Each block is a dictionary with keys in `[0, 15]`. Values are either
453 Each block is a dictionary with keys in `[0, 15]`. Values are either
454 another block or a revision number.
454 another block or a revision number.
455 """
455 """
456 root = Block()
456 root = Block()
457 for rev in range(len(index)):
457 for rev in range(len(index)):
458 current_hex = hex(index[rev][7])
458 current_hex = hex(index[rev][7])
459 _insert_into_block(index, 0, root, rev, current_hex)
459 _insert_into_block(index, 0, root, rev, current_hex)
460 return root
460 return root
461
461
462
462
463 def _update_trie(index, root, last_rev):
463 def _update_trie(index, root, last_rev):
464 """consume"""
464 """consume"""
465 changed = 0
465 changed = 0
466 for rev in range(last_rev + 1, len(index)):
466 for rev in range(last_rev + 1, len(index)):
467 current_hex = hex(index[rev][7])
467 current_hex = hex(index[rev][7])
468 changed += _insert_into_block(index, 0, root, rev, current_hex)
468 changed += _insert_into_block(index, 0, root, rev, current_hex)
469 return changed, root
469 return changed, root
470
470
471
471
472 def _insert_into_block(index, level, block, current_rev, current_hex):
472 def _insert_into_block(index, level, block, current_rev, current_hex):
473 """insert a new revision in a block
473 """insert a new revision in a block
474
474
475 index: the index we are adding revision for
475 index: the index we are adding revision for
476 level: the depth of the current block in the trie
476 level: the depth of the current block in the trie
477 block: the block currently being considered
477 block: the block currently being considered
478 current_rev: the revision number we are adding
478 current_rev: the revision number we are adding
479 current_hex: the hexadecimal representation of the of that revision
479 current_hex: the hexadecimal representation of the of that revision
480 """
480 """
481 changed = 1
481 changed = 1
482 if block.ondisk_id is not None:
482 if block.ondisk_id is not None:
483 block.ondisk_id = None
483 block.ondisk_id = None
484 hex_digit = _to_int(current_hex[level : level + 1])
484 hex_digit = _to_int(current_hex[level : level + 1])
485 entry = block.get(hex_digit)
485 entry = block.get(hex_digit)
486 if entry is None:
486 if entry is None:
487 # no entry, simply store the revision number
487 # no entry, simply store the revision number
488 block[hex_digit] = current_rev
488 block[hex_digit] = current_rev
489 elif isinstance(entry, dict):
489 elif isinstance(entry, dict):
490 # need to recurse to an underlying block
490 # need to recurse to an underlying block
491 changed += _insert_into_block(
491 changed += _insert_into_block(
492 index, level + 1, entry, current_rev, current_hex
492 index, level + 1, entry, current_rev, current_hex
493 )
493 )
494 else:
494 else:
495 # collision with a previously unique prefix, inserting new
495 # collision with a previously unique prefix, inserting new
496 # vertices to fit both entry.
496 # vertices to fit both entry.
497 other_hex = hex(index[entry][7])
497 other_hex = hex(index[entry][7])
498 other_rev = entry
498 other_rev = entry
499 new = Block()
499 new = Block()
500 block[hex_digit] = new
500 block[hex_digit] = new
501 _insert_into_block(index, level + 1, new, other_rev, other_hex)
501 _insert_into_block(index, level + 1, new, other_rev, other_hex)
502 _insert_into_block(index, level + 1, new, current_rev, current_hex)
502 _insert_into_block(index, level + 1, new, current_rev, current_hex)
503 return changed
503 return changed
504
504
505
505
506 def _persist_trie(root, existing_idx=None):
506 def _persist_trie(root, existing_idx=None):
507 """turn a nodemap trie into persistent binary data
507 """turn a nodemap trie into persistent binary data
508
508
509 See `_build_trie` for nodemap trie structure"""
509 See `_build_trie` for nodemap trie structure"""
510 block_map = {}
510 block_map = {}
511 if existing_idx is not None:
511 if existing_idx is not None:
512 base_idx = existing_idx + 1
512 base_idx = existing_idx + 1
513 else:
513 else:
514 base_idx = 0
514 base_idx = 0
515 chunks = []
515 chunks = []
516 for tn in _walk_trie(root):
516 for tn in _walk_trie(root):
517 if tn.ondisk_id is not None:
517 if tn.ondisk_id is not None:
518 block_map[id(tn)] = tn.ondisk_id
518 block_map[id(tn)] = tn.ondisk_id
519 else:
519 else:
520 block_map[id(tn)] = len(chunks) + base_idx
520 block_map[id(tn)] = len(chunks) + base_idx
521 chunks.append(_persist_block(tn, block_map))
521 chunks.append(_persist_block(tn, block_map))
522 return b''.join(chunks)
522 return b''.join(chunks)
523
523
524
524
525 def _walk_trie(block):
525 def _walk_trie(block):
526 """yield all the block in a trie
526 """yield all the block in a trie
527
527
528 Children blocks are always yield before their parent block.
528 Children blocks are always yield before their parent block.
529 """
529 """
530 for (__, item) in sorted(block.items()):
530 for (__, item) in sorted(block.items()):
531 if isinstance(item, dict):
531 if isinstance(item, dict):
532 for sub_block in _walk_trie(item):
532 for sub_block in _walk_trie(item):
533 yield sub_block
533 yield sub_block
534 yield block
534 yield block
535
535
536
536
537 def _persist_block(block_node, block_map):
537 def _persist_block(block_node, block_map):
538 """produce persistent binary data for a single block
538 """produce persistent binary data for a single block
539
539
540 Children block are assumed to be already persisted and present in
540 Children block are assumed to be already persisted and present in
541 block_map.
541 block_map.
542 """
542 """
543 data = tuple(_to_value(v, block_map) for v in block_node)
543 data = tuple(_to_value(v, block_map) for v in block_node)
544 return S_BLOCK.pack(*data)
544 return S_BLOCK.pack(*data)
545
545
546
546
547 def _to_value(item, block_map):
547 def _to_value(item, block_map):
548 """persist any value as an integer"""
548 """persist any value as an integer"""
549 if item is None:
549 if item is None:
550 return NO_ENTRY
550 return NO_ENTRY
551 elif isinstance(item, dict):
551 elif isinstance(item, dict):
552 return block_map[id(item)]
552 return block_map[id(item)]
553 else:
553 else:
554 return _transform_rev(item)
554 return _transform_rev(item)
555
555
556
556
557 def parse_data(data):
557 def parse_data(data):
558 """parse parse nodemap data into a nodemap Trie"""
558 """parse parse nodemap data into a nodemap Trie"""
559 if (len(data) % S_BLOCK.size) != 0:
559 if (len(data) % S_BLOCK.size) != 0:
560 msg = "nodemap data size is not a multiple of block size (%d): %d"
560 msg = "nodemap data size is not a multiple of block size (%d): %d"
561 raise error.Abort(msg % (S_BLOCK.size, len(data)))
561 raise error.Abort(msg % (S_BLOCK.size, len(data)))
562 if not data:
562 if not data:
563 return Block(), None
563 return Block(), None
564 block_map = {}
564 block_map = {}
565 new_blocks = []
565 new_blocks = []
566 for i in range(0, len(data), S_BLOCK.size):
566 for i in range(0, len(data), S_BLOCK.size):
567 block = Block()
567 block = Block()
568 block.ondisk_id = len(block_map)
568 block.ondisk_id = len(block_map)
569 block_map[block.ondisk_id] = block
569 block_map[block.ondisk_id] = block
570 block_data = data[i : i + S_BLOCK.size]
570 block_data = data[i : i + S_BLOCK.size]
571 values = S_BLOCK.unpack(block_data)
571 values = S_BLOCK.unpack(block_data)
572 new_blocks.append((block, values))
572 new_blocks.append((block, values))
573 for b, values in new_blocks:
573 for b, values in new_blocks:
574 for idx, v in enumerate(values):
574 for idx, v in enumerate(values):
575 if v == NO_ENTRY:
575 if v == NO_ENTRY:
576 continue
576 continue
577 elif v >= 0:
577 elif v >= 0:
578 b[idx] = block_map[v]
578 b[idx] = block_map[v]
579 else:
579 else:
580 b[idx] = _transform_rev(v)
580 b[idx] = _transform_rev(v)
581 return block, i // S_BLOCK.size
581 return block, i // S_BLOCK.size
582
582
583
583
584 # debug utility
584 # debug utility
585
585
586
586
587 def check_data(ui, index, data):
587 def check_data(ui, index, data):
588 """verify that the provided nodemap data are valid for the given idex"""
588 """verify that the provided nodemap data are valid for the given idex"""
589 ret = 0
589 ret = 0
590 ui.status((b"revision in index: %d\n") % len(index))
590 ui.status((b"revision in index: %d\n") % len(index))
591 root, __ = parse_data(data)
591 root, __ = parse_data(data)
592 all_revs = set(_all_revisions(root))
592 all_revs = set(_all_revisions(root))
593 ui.status((b"revision in nodemap: %d\n") % len(all_revs))
593 ui.status((b"revision in nodemap: %d\n") % len(all_revs))
594 for r in range(len(index)):
594 for r in range(len(index)):
595 if r not in all_revs:
595 if r not in all_revs:
596 msg = b" revision missing from nodemap: %d\n" % r
596 msg = b" revision missing from nodemap: %d\n" % r
597 ui.write_err(msg)
597 ui.write_err(msg)
598 ret = 1
598 ret = 1
599 else:
599 else:
600 all_revs.remove(r)
600 all_revs.remove(r)
601 nm_rev = _find_node(root, hex(index[r][7]))
601 nm_rev = _find_node(root, hex(index[r][7]))
602 if nm_rev is None:
602 if nm_rev is None:
603 msg = b" revision node does not match any entries: %d\n" % r
603 msg = b" revision node does not match any entries: %d\n" % r
604 ui.write_err(msg)
604 ui.write_err(msg)
605 ret = 1
605 ret = 1
606 elif nm_rev != r:
606 elif nm_rev != r:
607 msg = (
607 msg = (
608 b" revision node does not match the expected revision: "
608 b" revision node does not match the expected revision: "
609 b"%d != %d\n" % (r, nm_rev)
609 b"%d != %d\n" % (r, nm_rev)
610 )
610 )
611 ui.write_err(msg)
611 ui.write_err(msg)
612 ret = 1
612 ret = 1
613
613
614 if all_revs:
614 if all_revs:
615 for r in sorted(all_revs):
615 for r in sorted(all_revs):
616 msg = b" extra revision in nodemap: %d\n" % r
616 msg = b" extra revision in nodemap: %d\n" % r
617 ui.write_err(msg)
617 ui.write_err(msg)
618 ret = 1
618 ret = 1
619 return ret
619 return ret
620
620
621
621
622 def _all_revisions(root):
622 def _all_revisions(root):
623 """return all revisions stored in a Trie"""
623 """return all revisions stored in a Trie"""
624 for block in _walk_trie(root):
624 for block in _walk_trie(root):
625 for v in block:
625 for v in block:
626 if v is None or isinstance(v, Block):
626 if v is None or isinstance(v, Block):
627 continue
627 continue
628 yield v
628 yield v
629
629
630
630
631 def _find_node(block, node):
631 def _find_node(block, node):
632 """find the revision associated with a given node"""
632 """find the revision associated with a given node"""
633 entry = block.get(_to_int(node[0:1]))
633 entry = block.get(_to_int(node[0:1]))
634 if isinstance(entry, dict):
634 if isinstance(entry, dict):
635 return _find_node(entry, node[1:])
635 return _find_node(entry, node[1:])
636 return entry
636 return entry
@@ -1,693 +1,725 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
378 -----------------
379
380 $ UUID=`hg debugnodemap --metadata| grep 'uid:' | \
381 > sed 's/uid: //'`
382 $ FILE=.hg/store/00changelog-"${UUID}".nd
383 $ mv $FILE ../tmp-data-file
384 $ cp .hg/store/00changelog.n ../tmp-docket
385
386 mercurial don't crash
387
388 $ hg log -r .
389 changeset: 5002:b355ef8adce0
390 tag: tip
391 parent: 4998:d918ad6d18d3
392 user: test
393 date: Thu Jan 01 00:00:00 1970 +0000
394 summary: babar
395
396 $ hg debugnodemap --metadata
397
398 $ hg debugupdatecache
399 $ hg debugnodemap --metadata
400 uid: * (glob)
401 tip-rev: 5002
402 tip-node: b355ef8adce0949b8bdf6afc72ca853740d65944
403 data-length: 121088
404 data-unused: 0
405 data-unused: 0.000%
406 $ mv ../tmp-data-file $FILE
407 $ mv ../tmp-docket .hg/store/00changelog.n
408
377 Check transaction related property
409 Check transaction related property
378 ==================================
410 ==================================
379
411
380 An up to date nodemap should be available to shell hooks,
412 An up to date nodemap should be available to shell hooks,
381
413
382 $ echo dsljfl > a
414 $ echo dsljfl > a
383 $ hg add a
415 $ hg add a
384 $ hg ci -m a
416 $ hg ci -m a
385 $ hg debugnodemap --metadata
417 $ hg debugnodemap --metadata
386 uid: ???????????????? (glob)
418 uid: ???????????????? (glob)
387 tip-rev: 5003
419 tip-rev: 5003
388 tip-node: a52c5079765b5865d97b993b303a18740113bbb2
420 tip-node: a52c5079765b5865d97b993b303a18740113bbb2
389 data-length: 121088
421 data-length: 121088
390 data-unused: 0
422 data-unused: 0
391 data-unused: 0.000%
423 data-unused: 0.000%
392 $ echo babar2 > babar
424 $ echo babar2 > babar
393 $ 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"
394 uid: ???????????????? (glob)
426 uid: ???????????????? (glob)
395 tip-rev: 5004
427 tip-rev: 5004
396 tip-node: 2f5fb1c06a16834c5679d672e90da7c5f3b1a984
428 tip-node: 2f5fb1c06a16834c5679d672e90da7c5f3b1a984
397 data-length: 121280 (pure !)
429 data-length: 121280 (pure !)
398 data-length: 121280 (rust !)
430 data-length: 121280 (rust !)
399 data-length: 121088 (no-pure no-rust !)
431 data-length: 121088 (no-pure no-rust !)
400 data-unused: 192 (pure !)
432 data-unused: 192 (pure !)
401 data-unused: 192 (rust !)
433 data-unused: 192 (rust !)
402 data-unused: 0 (no-pure no-rust !)
434 data-unused: 0 (no-pure no-rust !)
403 data-unused: 0.158% (pure !)
435 data-unused: 0.158% (pure !)
404 data-unused: 0.158% (rust !)
436 data-unused: 0.158% (rust !)
405 data-unused: 0.000% (no-pure no-rust !)
437 data-unused: 0.000% (no-pure no-rust !)
406 $ hg debugnodemap --metadata
438 $ hg debugnodemap --metadata
407 uid: ???????????????? (glob)
439 uid: ???????????????? (glob)
408 tip-rev: 5004
440 tip-rev: 5004
409 tip-node: 2f5fb1c06a16834c5679d672e90da7c5f3b1a984
441 tip-node: 2f5fb1c06a16834c5679d672e90da7c5f3b1a984
410 data-length: 121280 (pure !)
442 data-length: 121280 (pure !)
411 data-length: 121280 (rust !)
443 data-length: 121280 (rust !)
412 data-length: 121088 (no-pure no-rust !)
444 data-length: 121088 (no-pure no-rust !)
413 data-unused: 192 (pure !)
445 data-unused: 192 (pure !)
414 data-unused: 192 (rust !)
446 data-unused: 192 (rust !)
415 data-unused: 0 (no-pure no-rust !)
447 data-unused: 0 (no-pure no-rust !)
416 data-unused: 0.158% (pure !)
448 data-unused: 0.158% (pure !)
417 data-unused: 0.158% (rust !)
449 data-unused: 0.158% (rust !)
418 data-unused: 0.000% (no-pure no-rust !)
450 data-unused: 0.000% (no-pure no-rust !)
419
451
420 Another process does not see the pending nodemap content during run.
452 Another process does not see the pending nodemap content during run.
421
453
422 $ PATH=$RUNTESTDIR/testlib/:$PATH
454 $ PATH=$RUNTESTDIR/testlib/:$PATH
423 $ echo qpoasp > a
455 $ echo qpoasp > a
424 $ hg ci -m a2 \
456 $ hg ci -m a2 \
425 > --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" \
426 > --config "hooks.txnclose=touch sync-txn-close" > output.txt 2>&1 &
458 > --config "hooks.txnclose=touch sync-txn-close" > output.txt 2>&1 &
427
459
428 (read the repository while the commit transaction is pending)
460 (read the repository while the commit transaction is pending)
429
461
430 $ wait-on-file 20 sync-txn-pending && \
462 $ wait-on-file 20 sync-txn-pending && \
431 > hg debugnodemap --metadata && \
463 > hg debugnodemap --metadata && \
432 > wait-on-file 20 sync-txn-close sync-repo-read
464 > wait-on-file 20 sync-txn-close sync-repo-read
433 uid: ???????????????? (glob)
465 uid: ???????????????? (glob)
434 tip-rev: 5004
466 tip-rev: 5004
435 tip-node: 2f5fb1c06a16834c5679d672e90da7c5f3b1a984
467 tip-node: 2f5fb1c06a16834c5679d672e90da7c5f3b1a984
436 data-length: 121280 (pure !)
468 data-length: 121280 (pure !)
437 data-length: 121280 (rust !)
469 data-length: 121280 (rust !)
438 data-length: 121088 (no-pure no-rust !)
470 data-length: 121088 (no-pure no-rust !)
439 data-unused: 192 (pure !)
471 data-unused: 192 (pure !)
440 data-unused: 192 (rust !)
472 data-unused: 192 (rust !)
441 data-unused: 0 (no-pure no-rust !)
473 data-unused: 0 (no-pure no-rust !)
442 data-unused: 0.158% (pure !)
474 data-unused: 0.158% (pure !)
443 data-unused: 0.158% (rust !)
475 data-unused: 0.158% (rust !)
444 data-unused: 0.000% (no-pure no-rust !)
476 data-unused: 0.000% (no-pure no-rust !)
445 $ hg debugnodemap --metadata
477 $ hg debugnodemap --metadata
446 uid: ???????????????? (glob)
478 uid: ???????????????? (glob)
447 tip-rev: 5005
479 tip-rev: 5005
448 tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe
480 tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe
449 data-length: 121536 (pure !)
481 data-length: 121536 (pure !)
450 data-length: 121536 (rust !)
482 data-length: 121536 (rust !)
451 data-length: 121088 (no-pure no-rust !)
483 data-length: 121088 (no-pure no-rust !)
452 data-unused: 448 (pure !)
484 data-unused: 448 (pure !)
453 data-unused: 448 (rust !)
485 data-unused: 448 (rust !)
454 data-unused: 0 (no-pure no-rust !)
486 data-unused: 0 (no-pure no-rust !)
455 data-unused: 0.369% (pure !)
487 data-unused: 0.369% (pure !)
456 data-unused: 0.369% (rust !)
488 data-unused: 0.369% (rust !)
457 data-unused: 0.000% (no-pure no-rust !)
489 data-unused: 0.000% (no-pure no-rust !)
458
490
459 $ cat output.txt
491 $ cat output.txt
460
492
461 Check that a failing transaction will properly revert the data
493 Check that a failing transaction will properly revert the data
462
494
463 $ echo plakfe > a
495 $ echo plakfe > a
464 $ f --size --sha256 .hg/store/00changelog-*.nd
496 $ f --size --sha256 .hg/store/00changelog-*.nd
465 .hg/store/00changelog-????????????????.nd: size=121536, sha256=bb414468d225cf52d69132e1237afba34d4346ee2eb81b505027e6197b107f03 (glob) (pure !)
497 .hg/store/00changelog-????????????????.nd: size=121536, sha256=bb414468d225cf52d69132e1237afba34d4346ee2eb81b505027e6197b107f03 (glob) (pure !)
466 .hg/store/00changelog-????????????????.nd: size=121536, sha256=909ac727bc4d1c0fda5f7bff3c620c98bd4a2967c143405a1503439e33b377da (glob) (rust !)
498 .hg/store/00changelog-????????????????.nd: size=121536, sha256=909ac727bc4d1c0fda5f7bff3c620c98bd4a2967c143405a1503439e33b377da (glob) (rust !)
467 .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 !)
468 $ 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"
469 transaction abort!
501 transaction abort!
470 rollback completed
502 rollback completed
471 abort: This is a late abort
503 abort: This is a late abort
472 [255]
504 [255]
473 $ hg debugnodemap --metadata
505 $ hg debugnodemap --metadata
474 uid: ???????????????? (glob)
506 uid: ???????????????? (glob)
475 tip-rev: 5005
507 tip-rev: 5005
476 tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe
508 tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe
477 data-length: 121536 (pure !)
509 data-length: 121536 (pure !)
478 data-length: 121536 (rust !)
510 data-length: 121536 (rust !)
479 data-length: 121088 (no-pure no-rust !)
511 data-length: 121088 (no-pure no-rust !)
480 data-unused: 448 (pure !)
512 data-unused: 448 (pure !)
481 data-unused: 448 (rust !)
513 data-unused: 448 (rust !)
482 data-unused: 0 (no-pure no-rust !)
514 data-unused: 0 (no-pure no-rust !)
483 data-unused: 0.369% (pure !)
515 data-unused: 0.369% (pure !)
484 data-unused: 0.369% (rust !)
516 data-unused: 0.369% (rust !)
485 data-unused: 0.000% (no-pure no-rust !)
517 data-unused: 0.000% (no-pure no-rust !)
486 $ f --size --sha256 .hg/store/00changelog-*.nd
518 $ f --size --sha256 .hg/store/00changelog-*.nd
487 .hg/store/00changelog-????????????????.nd: size=121536, sha256=bb414468d225cf52d69132e1237afba34d4346ee2eb81b505027e6197b107f03 (glob) (pure !)
519 .hg/store/00changelog-????????????????.nd: size=121536, sha256=bb414468d225cf52d69132e1237afba34d4346ee2eb81b505027e6197b107f03 (glob) (pure !)
488 .hg/store/00changelog-????????????????.nd: size=121536, sha256=909ac727bc4d1c0fda5f7bff3c620c98bd4a2967c143405a1503439e33b377da (glob) (rust !)
520 .hg/store/00changelog-????????????????.nd: size=121536, sha256=909ac727bc4d1c0fda5f7bff3c620c98bd4a2967c143405a1503439e33b377da (glob) (rust !)
489 .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 !)
490
522
491 Check that removing content does not confuse the nodemap
523 Check that removing content does not confuse the nodemap
492 --------------------------------------------------------
524 --------------------------------------------------------
493
525
494 removing data with rollback
526 removing data with rollback
495
527
496 $ echo aso > a
528 $ echo aso > a
497 $ hg ci -m a4
529 $ hg ci -m a4
498 $ hg rollback
530 $ hg rollback
499 repository tip rolled back to revision 5005 (undo commit)
531 repository tip rolled back to revision 5005 (undo commit)
500 working directory now based on revision 5005
532 working directory now based on revision 5005
501 $ hg id -r .
533 $ hg id -r .
502 90d5d3ba2fc4 tip
534 90d5d3ba2fc4 tip
503
535
504 roming data with strip
536 roming data with strip
505
537
506 $ echo aso > a
538 $ echo aso > a
507 $ hg ci -m a4
539 $ hg ci -m a4
508 $ hg --config extensions.strip= strip -r . --no-backup
540 $ hg --config extensions.strip= strip -r . --no-backup
509 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
510 $ hg id -r . --traceback
542 $ hg id -r . --traceback
511 90d5d3ba2fc4 tip
543 90d5d3ba2fc4 tip
512
544
513 Test upgrade / downgrade
545 Test upgrade / downgrade
514 ========================
546 ========================
515
547
516 downgrading
548 downgrading
517
549
518 $ cat << EOF >> .hg/hgrc
550 $ cat << EOF >> .hg/hgrc
519 > [format]
551 > [format]
520 > use-persistent-nodemap=no
552 > use-persistent-nodemap=no
521 > EOF
553 > EOF
522 $ hg debugformat -v
554 $ hg debugformat -v
523 format-variant repo config default
555 format-variant repo config default
524 fncache: yes yes yes
556 fncache: yes yes yes
525 dotencode: yes yes yes
557 dotencode: yes yes yes
526 generaldelta: yes yes yes
558 generaldelta: yes yes yes
527 exp-sharesafe: no no no
559 exp-sharesafe: no no no
528 sparserevlog: yes yes yes
560 sparserevlog: yes yes yes
529 sidedata: no no no
561 sidedata: no no no
530 persistent-nodemap: yes no no
562 persistent-nodemap: yes no no
531 copies-sdc: no no no
563 copies-sdc: no no no
532 plain-cl-delta: yes yes yes
564 plain-cl-delta: yes yes yes
533 compression: zlib zlib zlib
565 compression: zlib zlib zlib
534 compression-level: default default default
566 compression-level: default default default
535 $ hg debugupgraderepo --run --no-backup --quiet
567 $ hg debugupgraderepo --run --no-backup --quiet
536 upgrade will perform the following actions:
568 upgrade will perform the following actions:
537
569
538 requirements
570 requirements
539 preserved: dotencode, fncache, generaldelta, revlogv1, sparserevlog, store
571 preserved: dotencode, fncache, generaldelta, revlogv1, sparserevlog, store
540 removed: persistent-nodemap
572 removed: persistent-nodemap
541
573
542 processed revlogs:
574 processed revlogs:
543 - all-filelogs
575 - all-filelogs
544 - changelog
576 - changelog
545 - manifest
577 - manifest
546
578
547 $ ls -1 .hg/store/ | egrep '00(changelog|manifest)(\.n|-.*\.nd)'
579 $ ls -1 .hg/store/ | egrep '00(changelog|manifest)(\.n|-.*\.nd)'
548 [1]
580 [1]
549 $ hg debugnodemap --metadata
581 $ hg debugnodemap --metadata
550
582
551
583
552 upgrading
584 upgrading
553
585
554 $ cat << EOF >> .hg/hgrc
586 $ cat << EOF >> .hg/hgrc
555 > [format]
587 > [format]
556 > use-persistent-nodemap=yes
588 > use-persistent-nodemap=yes
557 > EOF
589 > EOF
558 $ hg debugformat -v
590 $ hg debugformat -v
559 format-variant repo config default
591 format-variant repo config default
560 fncache: yes yes yes
592 fncache: yes yes yes
561 dotencode: yes yes yes
593 dotencode: yes yes yes
562 generaldelta: yes yes yes
594 generaldelta: yes yes yes
563 exp-sharesafe: no no no
595 exp-sharesafe: no no no
564 sparserevlog: yes yes yes
596 sparserevlog: yes yes yes
565 sidedata: no no no
597 sidedata: no no no
566 persistent-nodemap: no yes no
598 persistent-nodemap: no yes no
567 copies-sdc: no no no
599 copies-sdc: no no no
568 plain-cl-delta: yes yes yes
600 plain-cl-delta: yes yes yes
569 compression: zlib zlib zlib
601 compression: zlib zlib zlib
570 compression-level: default default default
602 compression-level: default default default
571 $ hg debugupgraderepo --run --no-backup --quiet
603 $ hg debugupgraderepo --run --no-backup --quiet
572 upgrade will perform the following actions:
604 upgrade will perform the following actions:
573
605
574 requirements
606 requirements
575 preserved: dotencode, fncache, generaldelta, revlogv1, sparserevlog, store
607 preserved: dotencode, fncache, generaldelta, revlogv1, sparserevlog, store
576 added: persistent-nodemap
608 added: persistent-nodemap
577
609
578 processed revlogs:
610 processed revlogs:
579 - all-filelogs
611 - all-filelogs
580 - changelog
612 - changelog
581 - manifest
613 - manifest
582
614
583 $ ls -1 .hg/store/ | egrep '00(changelog|manifest)(\.n|-.*\.nd)'
615 $ ls -1 .hg/store/ | egrep '00(changelog|manifest)(\.n|-.*\.nd)'
584 00changelog-*.nd (glob)
616 00changelog-*.nd (glob)
585 00changelog.n
617 00changelog.n
586 00manifest-*.nd (glob)
618 00manifest-*.nd (glob)
587 00manifest.n
619 00manifest.n
588
620
589 $ hg debugnodemap --metadata
621 $ hg debugnodemap --metadata
590 uid: * (glob)
622 uid: * (glob)
591 tip-rev: 5005
623 tip-rev: 5005
592 tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe
624 tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe
593 data-length: 121088
625 data-length: 121088
594 data-unused: 0
626 data-unused: 0
595 data-unused: 0.000%
627 data-unused: 0.000%
596
628
597 Running unrelated upgrade
629 Running unrelated upgrade
598
630
599 $ hg debugupgraderepo --run --no-backup --quiet --optimize re-delta-all
631 $ hg debugupgraderepo --run --no-backup --quiet --optimize re-delta-all
600 upgrade will perform the following actions:
632 upgrade will perform the following actions:
601
633
602 requirements
634 requirements
603 preserved: dotencode, fncache, generaldelta, persistent-nodemap, revlogv1, sparserevlog, store
635 preserved: dotencode, fncache, generaldelta, persistent-nodemap, revlogv1, sparserevlog, store
604
636
605 optimisations: re-delta-all
637 optimisations: re-delta-all
606
638
607 processed revlogs:
639 processed revlogs:
608 - all-filelogs
640 - all-filelogs
609 - changelog
641 - changelog
610 - manifest
642 - manifest
611
643
612 $ ls -1 .hg/store/ | egrep '00(changelog|manifest)(\.n|-.*\.nd)'
644 $ ls -1 .hg/store/ | egrep '00(changelog|manifest)(\.n|-.*\.nd)'
613 00changelog-*.nd (glob)
645 00changelog-*.nd (glob)
614 00changelog.n
646 00changelog.n
615 00manifest-*.nd (glob)
647 00manifest-*.nd (glob)
616 00manifest.n
648 00manifest.n
617
649
618 $ hg debugnodemap --metadata
650 $ hg debugnodemap --metadata
619 uid: * (glob)
651 uid: * (glob)
620 tip-rev: 5005
652 tip-rev: 5005
621 tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe
653 tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe
622 data-length: 121088
654 data-length: 121088
623 data-unused: 0
655 data-unused: 0
624 data-unused: 0.000%
656 data-unused: 0.000%
625
657
626 Persistent nodemap and local/streaming clone
658 Persistent nodemap and local/streaming clone
627 ============================================
659 ============================================
628
660
629 $ cd ..
661 $ cd ..
630
662
631 standard clone
663 standard clone
632 --------------
664 --------------
633
665
634 The persistent nodemap should exist after a streaming clone
666 The persistent nodemap should exist after a streaming clone
635
667
636 $ hg clone --pull --quiet -U test-repo standard-clone
668 $ hg clone --pull --quiet -U test-repo standard-clone
637 $ 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)'
638 00changelog-*.nd (glob)
670 00changelog-*.nd (glob)
639 00changelog.n
671 00changelog.n
640 00manifest-*.nd (glob)
672 00manifest-*.nd (glob)
641 00manifest.n
673 00manifest.n
642 $ hg -R standard-clone debugnodemap --metadata
674 $ hg -R standard-clone debugnodemap --metadata
643 uid: * (glob)
675 uid: * (glob)
644 tip-rev: 5005
676 tip-rev: 5005
645 tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe
677 tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe
646 data-length: 121088
678 data-length: 121088
647 data-unused: 0
679 data-unused: 0
648 data-unused: 0.000%
680 data-unused: 0.000%
649
681
650
682
651 local clone
683 local clone
652 ------------
684 ------------
653
685
654 The persistent nodemap should exist after a streaming clone
686 The persistent nodemap should exist after a streaming clone
655
687
656 $ hg clone -U test-repo local-clone
688 $ hg clone -U test-repo local-clone
657 $ 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)'
658 00changelog-*.nd (glob)
690 00changelog-*.nd (glob)
659 00changelog.n
691 00changelog.n
660 00manifest-*.nd (glob)
692 00manifest-*.nd (glob)
661 00manifest.n
693 00manifest.n
662 $ hg -R local-clone debugnodemap --metadata
694 $ hg -R local-clone debugnodemap --metadata
663 uid: * (glob)
695 uid: * (glob)
664 tip-rev: 5005
696 tip-rev: 5005
665 tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe
697 tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe
666 data-length: 121088
698 data-length: 121088
667 data-unused: 0
699 data-unused: 0
668 data-unused: 0.000%
700 data-unused: 0.000%
669
701
670 stream clone
702 stream clone
671 ------------
703 ------------
672
704
673 The persistent nodemap should exist after a streaming clone
705 The persistent nodemap should exist after a streaming clone
674
706
675 $ 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)'
676 adding [s] 00manifest.n (70 bytes)
708 adding [s] 00manifest.n (70 bytes)
677 adding [s] 00manifest.i (313 KB)
709 adding [s] 00manifest.i (313 KB)
678 adding [s] 00manifest.d (452 KB)
710 adding [s] 00manifest.d (452 KB)
679 adding [s] 00changelog.n (70 bytes)
711 adding [s] 00changelog.n (70 bytes)
680 adding [s] 00changelog.i (313 KB)
712 adding [s] 00changelog.i (313 KB)
681 adding [s] 00changelog.d (360 KB)
713 adding [s] 00changelog.d (360 KB)
682 $ ls -1 stream-clone/.hg/store/ | egrep '00(changelog|manifest)(\.n|-.*\.nd)'
714 $ ls -1 stream-clone/.hg/store/ | egrep '00(changelog|manifest)(\.n|-.*\.nd)'
683 00changelog-*.nd (glob)
715 00changelog-*.nd (glob)
684 00changelog.n
716 00changelog.n
685 00manifest-*.nd (glob)
717 00manifest-*.nd (glob)
686 00manifest.n
718 00manifest.n
687 $ hg -R stream-clone debugnodemap --metadata
719 $ hg -R stream-clone debugnodemap --metadata
688 uid: * (glob)
720 uid: * (glob)
689 tip-rev: 5005
721 tip-rev: 5005
690 tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe
722 tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe
691 data-length: 121088
723 data-length: 121088
692 data-unused: 0
724 data-unused: 0
693 data-unused: 0.000%
725 data-unused: 0.000%
General Comments 0
You need to be logged in to leave comments. Login now