##// END OF EJS Templates
nodemap: deal with data mmap error...
marmoute -
r47733:a3720569 default
parent child Browse files
Show More
@@ -1,660 +1,664 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 try:
56 data = util.buffer(util.mmapread(fd, data_length))
57 data = util.buffer(util.mmapread(fd, data_length))
58 except ValueError:
59 # raised when the read file is too small
60 data = b''
57 else:
61 else:
58 data = fd.read(data_length)
62 data = fd.read(data_length)
59 except (IOError, OSError) as e:
63 except (IOError, OSError) as e:
60 if e.errno == errno.ENOENT:
64 if e.errno == errno.ENOENT:
61 return None
65 return None
62 else:
66 else:
63 raise
67 raise
64 if len(data) < data_length:
68 if len(data) < data_length:
65 return None
69 return None
66 return docket, data
70 return docket, data
67
71
68
72
69 def setup_persistent_nodemap(tr, revlog):
73 def setup_persistent_nodemap(tr, revlog):
70 """Install whatever is needed transaction side to persist a nodemap on disk
74 """Install whatever is needed transaction side to persist a nodemap on disk
71
75
72 (only actually persist the nodemap if this is relevant for this revlog)
76 (only actually persist the nodemap if this is relevant for this revlog)
73 """
77 """
74 if revlog._inline:
78 if revlog._inline:
75 return # inlined revlog are too small for this to be relevant
79 return # inlined revlog are too small for this to be relevant
76 if revlog.nodemap_file is None:
80 if revlog.nodemap_file is None:
77 return # we do not use persistent_nodemap on this revlog
81 return # we do not use persistent_nodemap on this revlog
78
82
79 # we need to happen after the changelog finalization, in that use "cl-"
83 # we need to happen after the changelog finalization, in that use "cl-"
80 callback_id = b"nm-revlog-persistent-nodemap-%s" % revlog.nodemap_file
84 callback_id = b"nm-revlog-persistent-nodemap-%s" % revlog.nodemap_file
81 if tr.hasfinalize(callback_id):
85 if tr.hasfinalize(callback_id):
82 return # no need to register again
86 return # no need to register again
83 tr.addpending(
87 tr.addpending(
84 callback_id, lambda tr: persist_nodemap(tr, revlog, pending=True)
88 callback_id, lambda tr: persist_nodemap(tr, revlog, pending=True)
85 )
89 )
86 tr.addfinalize(callback_id, lambda tr: persist_nodemap(tr, revlog))
90 tr.addfinalize(callback_id, lambda tr: persist_nodemap(tr, revlog))
87
91
88
92
89 class _NoTransaction(object):
93 class _NoTransaction(object):
90 """transaction like object to update the nodemap outside a transaction"""
94 """transaction like object to update the nodemap outside a transaction"""
91
95
92 def __init__(self):
96 def __init__(self):
93 self._postclose = {}
97 self._postclose = {}
94
98
95 def addpostclose(self, callback_id, callback_func):
99 def addpostclose(self, callback_id, callback_func):
96 self._postclose[callback_id] = callback_func
100 self._postclose[callback_id] = callback_func
97
101
98 def registertmp(self, *args, **kwargs):
102 def registertmp(self, *args, **kwargs):
99 pass
103 pass
100
104
101 def addbackup(self, *args, **kwargs):
105 def addbackup(self, *args, **kwargs):
102 pass
106 pass
103
107
104 def add(self, *args, **kwargs):
108 def add(self, *args, **kwargs):
105 pass
109 pass
106
110
107 def addabort(self, *args, **kwargs):
111 def addabort(self, *args, **kwargs):
108 pass
112 pass
109
113
110 def _report(self, *args):
114 def _report(self, *args):
111 pass
115 pass
112
116
113
117
114 def update_persistent_nodemap(revlog):
118 def update_persistent_nodemap(revlog):
115 """update the persistent nodemap right now
119 """update the persistent nodemap right now
116
120
117 To be used for updating the nodemap on disk outside of a normal transaction
121 To be used for updating the nodemap on disk outside of a normal transaction
118 setup (eg, `debugupdatecache`).
122 setup (eg, `debugupdatecache`).
119 """
123 """
120 if revlog._inline:
124 if revlog._inline:
121 return # inlined revlog are too small for this to be relevant
125 return # inlined revlog are too small for this to be relevant
122 if revlog.nodemap_file is None:
126 if revlog.nodemap_file is None:
123 return # we do not use persistent_nodemap on this revlog
127 return # we do not use persistent_nodemap on this revlog
124
128
125 notr = _NoTransaction()
129 notr = _NoTransaction()
126 persist_nodemap(notr, revlog)
130 persist_nodemap(notr, revlog)
127 for k in sorted(notr._postclose):
131 for k in sorted(notr._postclose):
128 notr._postclose[k](None)
132 notr._postclose[k](None)
129
133
130
134
131 def delete_nodemap(tr, repo, revlog):
135 def delete_nodemap(tr, repo, revlog):
132 """ Delete nodemap data on disk for a given revlog"""
136 """ Delete nodemap data on disk for a given revlog"""
133 if revlog.nodemap_file is None:
137 if revlog.nodemap_file is None:
134 msg = "calling persist nodemap on a revlog without the feature enabled"
138 msg = "calling persist nodemap on a revlog without the feature enabled"
135 raise error.ProgrammingError(msg)
139 raise error.ProgrammingError(msg)
136 repo.svfs.unlink(revlog.nodemap_file)
140 repo.svfs.unlink(revlog.nodemap_file)
137
141
138
142
139 def persist_nodemap(tr, revlog, pending=False, force=False):
143 def persist_nodemap(tr, revlog, pending=False, force=False):
140 """Write nodemap data on disk for a given revlog"""
144 """Write nodemap data on disk for a given revlog"""
141 if getattr(revlog, 'filteredrevs', ()):
145 if getattr(revlog, 'filteredrevs', ()):
142 raise error.ProgrammingError(
146 raise error.ProgrammingError(
143 "cannot persist nodemap of a filtered changelog"
147 "cannot persist nodemap of a filtered changelog"
144 )
148 )
145 if revlog.nodemap_file is None:
149 if revlog.nodemap_file is None:
146 if force:
150 if force:
147 revlog.nodemap_file = get_nodemap_file(
151 revlog.nodemap_file = get_nodemap_file(
148 revlog.opener, revlog.indexfile
152 revlog.opener, revlog.indexfile
149 )
153 )
150 else:
154 else:
151 msg = "calling persist nodemap on a revlog without the feature enabled"
155 msg = "calling persist nodemap on a revlog without the feature enabled"
152 raise error.ProgrammingError(msg)
156 raise error.ProgrammingError(msg)
153
157
154 can_incremental = util.safehasattr(revlog.index, "nodemap_data_incremental")
158 can_incremental = util.safehasattr(revlog.index, "nodemap_data_incremental")
155 ondisk_docket = revlog._nodemap_docket
159 ondisk_docket = revlog._nodemap_docket
156 feed_data = util.safehasattr(revlog.index, "update_nodemap_data")
160 feed_data = util.safehasattr(revlog.index, "update_nodemap_data")
157 use_mmap = revlog.opener.options.get(b"persistent-nodemap.mmap")
161 use_mmap = revlog.opener.options.get(b"persistent-nodemap.mmap")
158
162
159 data = None
163 data = None
160 # first attemp an incremental update of the data
164 # first attemp an incremental update of the data
161 if can_incremental and ondisk_docket is not None:
165 if can_incremental and ondisk_docket is not None:
162 target_docket = revlog._nodemap_docket.copy()
166 target_docket = revlog._nodemap_docket.copy()
163 (
167 (
164 src_docket,
168 src_docket,
165 data_changed_count,
169 data_changed_count,
166 data,
170 data,
167 ) = revlog.index.nodemap_data_incremental()
171 ) = revlog.index.nodemap_data_incremental()
168 new_length = target_docket.data_length + len(data)
172 new_length = target_docket.data_length + len(data)
169 new_unused = target_docket.data_unused + data_changed_count
173 new_unused = target_docket.data_unused + data_changed_count
170 if src_docket != target_docket:
174 if src_docket != target_docket:
171 data = None
175 data = None
172 elif new_length <= (new_unused * 10): # under 10% of unused data
176 elif new_length <= (new_unused * 10): # under 10% of unused data
173 data = None
177 data = None
174 else:
178 else:
175 datafile = _rawdata_filepath(revlog, target_docket)
179 datafile = _rawdata_filepath(revlog, target_docket)
176 # EXP-TODO: if this is a cache, this should use a cache vfs, not a
180 # EXP-TODO: if this is a cache, this should use a cache vfs, not a
177 # store vfs
181 # store vfs
178 tr.add(datafile, target_docket.data_length)
182 tr.add(datafile, target_docket.data_length)
179 with revlog.opener(datafile, b'r+') as fd:
183 with revlog.opener(datafile, b'r+') as fd:
180 fd.seek(target_docket.data_length)
184 fd.seek(target_docket.data_length)
181 fd.write(data)
185 fd.write(data)
182 if feed_data:
186 if feed_data:
183 if use_mmap:
187 if use_mmap:
184 fd.seek(0)
188 fd.seek(0)
185 new_data = fd.read(new_length)
189 new_data = fd.read(new_length)
186 else:
190 else:
187 fd.flush()
191 fd.flush()
188 new_data = util.buffer(util.mmapread(fd, new_length))
192 new_data = util.buffer(util.mmapread(fd, new_length))
189 target_docket.data_length = new_length
193 target_docket.data_length = new_length
190 target_docket.data_unused = new_unused
194 target_docket.data_unused = new_unused
191
195
192 if data is None:
196 if data is None:
193 # otherwise fallback to a full new export
197 # otherwise fallback to a full new export
194 target_docket = NodeMapDocket()
198 target_docket = NodeMapDocket()
195 datafile = _rawdata_filepath(revlog, target_docket)
199 datafile = _rawdata_filepath(revlog, target_docket)
196 if util.safehasattr(revlog.index, "nodemap_data_all"):
200 if util.safehasattr(revlog.index, "nodemap_data_all"):
197 data = revlog.index.nodemap_data_all()
201 data = revlog.index.nodemap_data_all()
198 else:
202 else:
199 data = persistent_data(revlog.index)
203 data = persistent_data(revlog.index)
200 # EXP-TODO: if this is a cache, this should use a cache vfs, not a
204 # EXP-TODO: if this is a cache, this should use a cache vfs, not a
201 # store vfs
205 # store vfs
202
206
203 tryunlink = revlog.opener.tryunlink
207 tryunlink = revlog.opener.tryunlink
204
208
205 def abortck(tr):
209 def abortck(tr):
206 tryunlink(datafile)
210 tryunlink(datafile)
207
211
208 callback_id = b"delete-%s" % datafile
212 callback_id = b"delete-%s" % datafile
209
213
210 # some flavor of the transaction abort does not cleanup new file, it
214 # some flavor of the transaction abort does not cleanup new file, it
211 # simply empty them.
215 # simply empty them.
212 tr.addabort(callback_id, abortck)
216 tr.addabort(callback_id, abortck)
213 with revlog.opener(datafile, b'w+') as fd:
217 with revlog.opener(datafile, b'w+') as fd:
214 fd.write(data)
218 fd.write(data)
215 if feed_data:
219 if feed_data:
216 if use_mmap:
220 if use_mmap:
217 new_data = data
221 new_data = data
218 else:
222 else:
219 fd.flush()
223 fd.flush()
220 new_data = util.buffer(util.mmapread(fd, len(data)))
224 new_data = util.buffer(util.mmapread(fd, len(data)))
221 target_docket.data_length = len(data)
225 target_docket.data_length = len(data)
222 target_docket.tip_rev = revlog.tiprev()
226 target_docket.tip_rev = revlog.tiprev()
223 target_docket.tip_node = revlog.node(target_docket.tip_rev)
227 target_docket.tip_node = revlog.node(target_docket.tip_rev)
224 # EXP-TODO: if this is a cache, this should use a cache vfs, not a
228 # EXP-TODO: if this is a cache, this should use a cache vfs, not a
225 # store vfs
229 # store vfs
226 file_path = revlog.nodemap_file
230 file_path = revlog.nodemap_file
227 if pending:
231 if pending:
228 file_path += b'.a'
232 file_path += b'.a'
229 tr.registertmp(file_path)
233 tr.registertmp(file_path)
230 else:
234 else:
231 tr.addbackup(file_path)
235 tr.addbackup(file_path)
232
236
233 with revlog.opener(file_path, b'w', atomictemp=True) as fp:
237 with revlog.opener(file_path, b'w', atomictemp=True) as fp:
234 fp.write(target_docket.serialize())
238 fp.write(target_docket.serialize())
235 revlog._nodemap_docket = target_docket
239 revlog._nodemap_docket = target_docket
236 if feed_data:
240 if feed_data:
237 revlog.index.update_nodemap_data(target_docket, new_data)
241 revlog.index.update_nodemap_data(target_docket, new_data)
238
242
239 # search for old index file in all cases, some older process might have
243 # search for old index file in all cases, some older process might have
240 # left one behind.
244 # left one behind.
241 olds = _other_rawdata_filepath(revlog, target_docket)
245 olds = _other_rawdata_filepath(revlog, target_docket)
242 if olds:
246 if olds:
243 realvfs = getattr(revlog, '_realopener', revlog.opener)
247 realvfs = getattr(revlog, '_realopener', revlog.opener)
244
248
245 def cleanup(tr):
249 def cleanup(tr):
246 for oldfile in olds:
250 for oldfile in olds:
247 realvfs.tryunlink(oldfile)
251 realvfs.tryunlink(oldfile)
248
252
249 callback_id = b"revlog-cleanup-nodemap-%s" % revlog.nodemap_file
253 callback_id = b"revlog-cleanup-nodemap-%s" % revlog.nodemap_file
250 tr.addpostclose(callback_id, cleanup)
254 tr.addpostclose(callback_id, cleanup)
251
255
252
256
253 ### Nodemap docket file
257 ### Nodemap docket file
254 #
258 #
255 # The nodemap data are stored on disk using 2 files:
259 # The nodemap data are stored on disk using 2 files:
256 #
260 #
257 # * a raw data files containing a persistent nodemap
261 # * a raw data files containing a persistent nodemap
258 # (see `Nodemap Trie` section)
262 # (see `Nodemap Trie` section)
259 #
263 #
260 # * a small "docket" file containing medatadata
264 # * a small "docket" file containing medatadata
261 #
265 #
262 # While the nodemap data can be multiple tens of megabytes, the "docket" is
266 # While the nodemap data can be multiple tens of megabytes, the "docket" is
263 # small, it is easy to update it automatically or to duplicated its content
267 # small, it is easy to update it automatically or to duplicated its content
264 # during a transaction.
268 # during a transaction.
265 #
269 #
266 # Multiple raw data can exist at the same time (The currently valid one and a
270 # Multiple raw data can exist at the same time (The currently valid one and a
267 # new one beind used by an in progress transaction). To accomodate this, the
271 # new one beind used by an in progress transaction). To accomodate this, the
268 # filename hosting the raw data has a variable parts. The exact filename is
272 # filename hosting the raw data has a variable parts. The exact filename is
269 # specified inside the "docket" file.
273 # specified inside the "docket" file.
270 #
274 #
271 # The docket file contains information to find, qualify and validate the raw
275 # The docket file contains information to find, qualify and validate the raw
272 # data. Its content is currently very light, but it will expand as the on disk
276 # data. Its content is currently very light, but it will expand as the on disk
273 # nodemap gains the necessary features to be used in production.
277 # nodemap gains the necessary features to be used in production.
274
278
275 ONDISK_VERSION = 1
279 ONDISK_VERSION = 1
276 S_VERSION = struct.Struct(">B")
280 S_VERSION = struct.Struct(">B")
277 S_HEADER = struct.Struct(">BQQQQ")
281 S_HEADER = struct.Struct(">BQQQQ")
278
282
279 ID_SIZE = 8
283 ID_SIZE = 8
280
284
281
285
282 def _make_uid():
286 def _make_uid():
283 """return a new unique identifier.
287 """return a new unique identifier.
284
288
285 The identifier is random and composed of ascii characters."""
289 The identifier is random and composed of ascii characters."""
286 return hex(os.urandom(ID_SIZE))
290 return hex(os.urandom(ID_SIZE))
287
291
288
292
289 class NodeMapDocket(object):
293 class NodeMapDocket(object):
290 """metadata associated with persistent nodemap data
294 """metadata associated with persistent nodemap data
291
295
292 The persistent data may come from disk or be on their way to disk.
296 The persistent data may come from disk or be on their way to disk.
293 """
297 """
294
298
295 def __init__(self, uid=None):
299 def __init__(self, uid=None):
296 if uid is None:
300 if uid is None:
297 uid = _make_uid()
301 uid = _make_uid()
298 # a unique identifier for the data file:
302 # a unique identifier for the data file:
299 # - When new data are appended, it is preserved.
303 # - When new data are appended, it is preserved.
300 # - When a new data file is created, a new identifier is generated.
304 # - When a new data file is created, a new identifier is generated.
301 self.uid = uid
305 self.uid = uid
302 # the tipmost revision stored in the data file. This revision and all
306 # the tipmost revision stored in the data file. This revision and all
303 # revision before it are expected to be encoded in the data file.
307 # revision before it are expected to be encoded in the data file.
304 self.tip_rev = None
308 self.tip_rev = None
305 # the node of that tipmost revision, if it mismatch the current index
309 # the node of that tipmost revision, if it mismatch the current index
306 # data the docket is not valid for the current index and should be
310 # data the docket is not valid for the current index and should be
307 # discarded.
311 # discarded.
308 #
312 #
309 # note: this method is not perfect as some destructive operation could
313 # note: this method is not perfect as some destructive operation could
310 # preserve the same tip_rev + tip_node while altering lower revision.
314 # preserve the same tip_rev + tip_node while altering lower revision.
311 # However this multiple other caches have the same vulnerability (eg:
315 # However this multiple other caches have the same vulnerability (eg:
312 # brancmap cache).
316 # brancmap cache).
313 self.tip_node = None
317 self.tip_node = None
314 # the size (in bytes) of the persisted data to encode the nodemap valid
318 # the size (in bytes) of the persisted data to encode the nodemap valid
315 # for `tip_rev`.
319 # for `tip_rev`.
316 # - data file shorter than this are corrupted,
320 # - data file shorter than this are corrupted,
317 # - any extra data should be ignored.
321 # - any extra data should be ignored.
318 self.data_length = None
322 self.data_length = None
319 # the amount (in bytes) of "dead" data, still in the data file but no
323 # the amount (in bytes) of "dead" data, still in the data file but no
320 # longer used for the nodemap.
324 # longer used for the nodemap.
321 self.data_unused = 0
325 self.data_unused = 0
322
326
323 def copy(self):
327 def copy(self):
324 new = NodeMapDocket(uid=self.uid)
328 new = NodeMapDocket(uid=self.uid)
325 new.tip_rev = self.tip_rev
329 new.tip_rev = self.tip_rev
326 new.tip_node = self.tip_node
330 new.tip_node = self.tip_node
327 new.data_length = self.data_length
331 new.data_length = self.data_length
328 new.data_unused = self.data_unused
332 new.data_unused = self.data_unused
329 return new
333 return new
330
334
331 def __cmp__(self, other):
335 def __cmp__(self, other):
332 if self.uid < other.uid:
336 if self.uid < other.uid:
333 return -1
337 return -1
334 if self.uid > other.uid:
338 if self.uid > other.uid:
335 return 1
339 return 1
336 elif self.data_length < other.data_length:
340 elif self.data_length < other.data_length:
337 return -1
341 return -1
338 elif self.data_length > other.data_length:
342 elif self.data_length > other.data_length:
339 return 1
343 return 1
340 return 0
344 return 0
341
345
342 def __eq__(self, other):
346 def __eq__(self, other):
343 return self.uid == other.uid and self.data_length == other.data_length
347 return self.uid == other.uid and self.data_length == other.data_length
344
348
345 def serialize(self):
349 def serialize(self):
346 """return serialized bytes for a docket using the passed uid"""
350 """return serialized bytes for a docket using the passed uid"""
347 data = []
351 data = []
348 data.append(S_VERSION.pack(ONDISK_VERSION))
352 data.append(S_VERSION.pack(ONDISK_VERSION))
349 headers = (
353 headers = (
350 len(self.uid),
354 len(self.uid),
351 self.tip_rev,
355 self.tip_rev,
352 self.data_length,
356 self.data_length,
353 self.data_unused,
357 self.data_unused,
354 len(self.tip_node),
358 len(self.tip_node),
355 )
359 )
356 data.append(S_HEADER.pack(*headers))
360 data.append(S_HEADER.pack(*headers))
357 data.append(self.uid)
361 data.append(self.uid)
358 data.append(self.tip_node)
362 data.append(self.tip_node)
359 return b''.join(data)
363 return b''.join(data)
360
364
361
365
362 def _rawdata_filepath(revlog, docket):
366 def _rawdata_filepath(revlog, docket):
363 """The (vfs relative) nodemap's rawdata file for a given uid"""
367 """The (vfs relative) nodemap's rawdata file for a given uid"""
364 if revlog.nodemap_file.endswith(b'.n.a'):
368 if revlog.nodemap_file.endswith(b'.n.a'):
365 prefix = revlog.nodemap_file[:-4]
369 prefix = revlog.nodemap_file[:-4]
366 else:
370 else:
367 prefix = revlog.nodemap_file[:-2]
371 prefix = revlog.nodemap_file[:-2]
368 return b"%s-%s.nd" % (prefix, docket.uid)
372 return b"%s-%s.nd" % (prefix, docket.uid)
369
373
370
374
371 def _other_rawdata_filepath(revlog, docket):
375 def _other_rawdata_filepath(revlog, docket):
372 prefix = revlog.nodemap_file[:-2]
376 prefix = revlog.nodemap_file[:-2]
373 pattern = re.compile(br"(^|/)%s-[0-9a-f]+\.nd$" % prefix)
377 pattern = re.compile(br"(^|/)%s-[0-9a-f]+\.nd$" % prefix)
374 new_file_path = _rawdata_filepath(revlog, docket)
378 new_file_path = _rawdata_filepath(revlog, docket)
375 new_file_name = revlog.opener.basename(new_file_path)
379 new_file_name = revlog.opener.basename(new_file_path)
376 dirpath = revlog.opener.dirname(new_file_path)
380 dirpath = revlog.opener.dirname(new_file_path)
377 others = []
381 others = []
378 for f in revlog.opener.listdir(dirpath):
382 for f in revlog.opener.listdir(dirpath):
379 if pattern.match(f) and f != new_file_name:
383 if pattern.match(f) and f != new_file_name:
380 others.append(f)
384 others.append(f)
381 return others
385 return others
382
386
383
387
384 ### Nodemap Trie
388 ### Nodemap Trie
385 #
389 #
386 # This is a simple reference implementation to compute and persist a nodemap
390 # This is a simple reference implementation to compute and persist a nodemap
387 # trie. This reference implementation is write only. The python version of this
391 # trie. This reference implementation is write only. The python version of this
388 # is not expected to be actually used, since it wont provide performance
392 # is not expected to be actually used, since it wont provide performance
389 # improvement over existing non-persistent C implementation.
393 # improvement over existing non-persistent C implementation.
390 #
394 #
391 # The nodemap is persisted as Trie using 4bits-address/16-entries block. each
395 # The nodemap is persisted as Trie using 4bits-address/16-entries block. each
392 # revision can be adressed using its node shortest prefix.
396 # revision can be adressed using its node shortest prefix.
393 #
397 #
394 # The trie is stored as a sequence of block. Each block contains 16 entries
398 # The trie is stored as a sequence of block. Each block contains 16 entries
395 # (signed 64bit integer, big endian). Each entry can be one of the following:
399 # (signed 64bit integer, big endian). Each entry can be one of the following:
396 #
400 #
397 # * value >= 0 -> index of sub-block
401 # * value >= 0 -> index of sub-block
398 # * value == -1 -> no value
402 # * value == -1 -> no value
399 # * value < -1 -> encoded revision: rev = -(value+2)
403 # * value < -1 -> encoded revision: rev = -(value+2)
400 #
404 #
401 # See REV_OFFSET and _transform_rev below.
405 # See REV_OFFSET and _transform_rev below.
402 #
406 #
403 # The implementation focus on simplicity, not on performance. A Rust
407 # The implementation focus on simplicity, not on performance. A Rust
404 # implementation should provide a efficient version of the same binary
408 # implementation should provide a efficient version of the same binary
405 # persistence. This reference python implementation is never meant to be
409 # persistence. This reference python implementation is never meant to be
406 # extensively use in production.
410 # extensively use in production.
407
411
408
412
409 def persistent_data(index):
413 def persistent_data(index):
410 """return the persistent binary form for a nodemap for a given index"""
414 """return the persistent binary form for a nodemap for a given index"""
411 trie = _build_trie(index)
415 trie = _build_trie(index)
412 return _persist_trie(trie)
416 return _persist_trie(trie)
413
417
414
418
415 def update_persistent_data(index, root, max_idx, last_rev):
419 def update_persistent_data(index, root, max_idx, last_rev):
416 """return the incremental update for persistent nodemap from a given index"""
420 """return the incremental update for persistent nodemap from a given index"""
417 changed_block, trie = _update_trie(index, root, last_rev)
421 changed_block, trie = _update_trie(index, root, last_rev)
418 return (
422 return (
419 changed_block * S_BLOCK.size,
423 changed_block * S_BLOCK.size,
420 _persist_trie(trie, existing_idx=max_idx),
424 _persist_trie(trie, existing_idx=max_idx),
421 )
425 )
422
426
423
427
424 S_BLOCK = struct.Struct(">" + ("l" * 16))
428 S_BLOCK = struct.Struct(">" + ("l" * 16))
425
429
426 NO_ENTRY = -1
430 NO_ENTRY = -1
427 # rev 0 need to be -2 because 0 is used by block, -1 is a special value.
431 # rev 0 need to be -2 because 0 is used by block, -1 is a special value.
428 REV_OFFSET = 2
432 REV_OFFSET = 2
429
433
430
434
431 def _transform_rev(rev):
435 def _transform_rev(rev):
432 """Return the number used to represent the rev in the tree.
436 """Return the number used to represent the rev in the tree.
433
437
434 (or retrieve a rev number from such representation)
438 (or retrieve a rev number from such representation)
435
439
436 Note that this is an involution, a function equal to its inverse (i.e.
440 Note that this is an involution, a function equal to its inverse (i.e.
437 which gives the identity when applied to itself).
441 which gives the identity when applied to itself).
438 """
442 """
439 return -(rev + REV_OFFSET)
443 return -(rev + REV_OFFSET)
440
444
441
445
442 def _to_int(hex_digit):
446 def _to_int(hex_digit):
443 """turn an hexadecimal digit into a proper integer"""
447 """turn an hexadecimal digit into a proper integer"""
444 return int(hex_digit, 16)
448 return int(hex_digit, 16)
445
449
446
450
447 class Block(dict):
451 class Block(dict):
448 """represent a block of the Trie
452 """represent a block of the Trie
449
453
450 contains up to 16 entry indexed from 0 to 15"""
454 contains up to 16 entry indexed from 0 to 15"""
451
455
452 def __init__(self):
456 def __init__(self):
453 super(Block, self).__init__()
457 super(Block, self).__init__()
454 # If this block exist on disk, here is its ID
458 # If this block exist on disk, here is its ID
455 self.ondisk_id = None
459 self.ondisk_id = None
456
460
457 def __iter__(self):
461 def __iter__(self):
458 return iter(self.get(i) for i in range(16))
462 return iter(self.get(i) for i in range(16))
459
463
460
464
461 def _build_trie(index):
465 def _build_trie(index):
462 """build a nodemap trie
466 """build a nodemap trie
463
467
464 The nodemap stores revision number for each unique prefix.
468 The nodemap stores revision number for each unique prefix.
465
469
466 Each block is a dictionary with keys in `[0, 15]`. Values are either
470 Each block is a dictionary with keys in `[0, 15]`. Values are either
467 another block or a revision number.
471 another block or a revision number.
468 """
472 """
469 root = Block()
473 root = Block()
470 for rev in range(len(index)):
474 for rev in range(len(index)):
471 current_hex = hex(index[rev][7])
475 current_hex = hex(index[rev][7])
472 _insert_into_block(index, 0, root, rev, current_hex)
476 _insert_into_block(index, 0, root, rev, current_hex)
473 return root
477 return root
474
478
475
479
476 def _update_trie(index, root, last_rev):
480 def _update_trie(index, root, last_rev):
477 """consume"""
481 """consume"""
478 changed = 0
482 changed = 0
479 for rev in range(last_rev + 1, len(index)):
483 for rev in range(last_rev + 1, len(index)):
480 current_hex = hex(index[rev][7])
484 current_hex = hex(index[rev][7])
481 changed += _insert_into_block(index, 0, root, rev, current_hex)
485 changed += _insert_into_block(index, 0, root, rev, current_hex)
482 return changed, root
486 return changed, root
483
487
484
488
485 def _insert_into_block(index, level, block, current_rev, current_hex):
489 def _insert_into_block(index, level, block, current_rev, current_hex):
486 """insert a new revision in a block
490 """insert a new revision in a block
487
491
488 index: the index we are adding revision for
492 index: the index we are adding revision for
489 level: the depth of the current block in the trie
493 level: the depth of the current block in the trie
490 block: the block currently being considered
494 block: the block currently being considered
491 current_rev: the revision number we are adding
495 current_rev: the revision number we are adding
492 current_hex: the hexadecimal representation of the of that revision
496 current_hex: the hexadecimal representation of the of that revision
493 """
497 """
494 changed = 1
498 changed = 1
495 if block.ondisk_id is not None:
499 if block.ondisk_id is not None:
496 block.ondisk_id = None
500 block.ondisk_id = None
497 hex_digit = _to_int(current_hex[level : level + 1])
501 hex_digit = _to_int(current_hex[level : level + 1])
498 entry = block.get(hex_digit)
502 entry = block.get(hex_digit)
499 if entry is None:
503 if entry is None:
500 # no entry, simply store the revision number
504 # no entry, simply store the revision number
501 block[hex_digit] = current_rev
505 block[hex_digit] = current_rev
502 elif isinstance(entry, dict):
506 elif isinstance(entry, dict):
503 # need to recurse to an underlying block
507 # need to recurse to an underlying block
504 changed += _insert_into_block(
508 changed += _insert_into_block(
505 index, level + 1, entry, current_rev, current_hex
509 index, level + 1, entry, current_rev, current_hex
506 )
510 )
507 else:
511 else:
508 # collision with a previously unique prefix, inserting new
512 # collision with a previously unique prefix, inserting new
509 # vertices to fit both entry.
513 # vertices to fit both entry.
510 other_hex = hex(index[entry][7])
514 other_hex = hex(index[entry][7])
511 other_rev = entry
515 other_rev = entry
512 new = Block()
516 new = Block()
513 block[hex_digit] = new
517 block[hex_digit] = new
514 _insert_into_block(index, level + 1, new, other_rev, other_hex)
518 _insert_into_block(index, level + 1, new, other_rev, other_hex)
515 _insert_into_block(index, level + 1, new, current_rev, current_hex)
519 _insert_into_block(index, level + 1, new, current_rev, current_hex)
516 return changed
520 return changed
517
521
518
522
519 def _persist_trie(root, existing_idx=None):
523 def _persist_trie(root, existing_idx=None):
520 """turn a nodemap trie into persistent binary data
524 """turn a nodemap trie into persistent binary data
521
525
522 See `_build_trie` for nodemap trie structure"""
526 See `_build_trie` for nodemap trie structure"""
523 block_map = {}
527 block_map = {}
524 if existing_idx is not None:
528 if existing_idx is not None:
525 base_idx = existing_idx + 1
529 base_idx = existing_idx + 1
526 else:
530 else:
527 base_idx = 0
531 base_idx = 0
528 chunks = []
532 chunks = []
529 for tn in _walk_trie(root):
533 for tn in _walk_trie(root):
530 if tn.ondisk_id is not None:
534 if tn.ondisk_id is not None:
531 block_map[id(tn)] = tn.ondisk_id
535 block_map[id(tn)] = tn.ondisk_id
532 else:
536 else:
533 block_map[id(tn)] = len(chunks) + base_idx
537 block_map[id(tn)] = len(chunks) + base_idx
534 chunks.append(_persist_block(tn, block_map))
538 chunks.append(_persist_block(tn, block_map))
535 return b''.join(chunks)
539 return b''.join(chunks)
536
540
537
541
538 def _walk_trie(block):
542 def _walk_trie(block):
539 """yield all the block in a trie
543 """yield all the block in a trie
540
544
541 Children blocks are always yield before their parent block.
545 Children blocks are always yield before their parent block.
542 """
546 """
543 for (__, item) in sorted(block.items()):
547 for (__, item) in sorted(block.items()):
544 if isinstance(item, dict):
548 if isinstance(item, dict):
545 for sub_block in _walk_trie(item):
549 for sub_block in _walk_trie(item):
546 yield sub_block
550 yield sub_block
547 yield block
551 yield block
548
552
549
553
550 def _persist_block(block_node, block_map):
554 def _persist_block(block_node, block_map):
551 """produce persistent binary data for a single block
555 """produce persistent binary data for a single block
552
556
553 Children block are assumed to be already persisted and present in
557 Children block are assumed to be already persisted and present in
554 block_map.
558 block_map.
555 """
559 """
556 data = tuple(_to_value(v, block_map) for v in block_node)
560 data = tuple(_to_value(v, block_map) for v in block_node)
557 return S_BLOCK.pack(*data)
561 return S_BLOCK.pack(*data)
558
562
559
563
560 def _to_value(item, block_map):
564 def _to_value(item, block_map):
561 """persist any value as an integer"""
565 """persist any value as an integer"""
562 if item is None:
566 if item is None:
563 return NO_ENTRY
567 return NO_ENTRY
564 elif isinstance(item, dict):
568 elif isinstance(item, dict):
565 return block_map[id(item)]
569 return block_map[id(item)]
566 else:
570 else:
567 return _transform_rev(item)
571 return _transform_rev(item)
568
572
569
573
570 def parse_data(data):
574 def parse_data(data):
571 """parse parse nodemap data into a nodemap Trie"""
575 """parse parse nodemap data into a nodemap Trie"""
572 if (len(data) % S_BLOCK.size) != 0:
576 if (len(data) % S_BLOCK.size) != 0:
573 msg = b"nodemap data size is not a multiple of block size (%d): %d"
577 msg = b"nodemap data size is not a multiple of block size (%d): %d"
574 raise error.Abort(msg % (S_BLOCK.size, len(data)))
578 raise error.Abort(msg % (S_BLOCK.size, len(data)))
575 if not data:
579 if not data:
576 return Block(), None
580 return Block(), None
577 block_map = {}
581 block_map = {}
578 new_blocks = []
582 new_blocks = []
579 for i in range(0, len(data), S_BLOCK.size):
583 for i in range(0, len(data), S_BLOCK.size):
580 block = Block()
584 block = Block()
581 block.ondisk_id = len(block_map)
585 block.ondisk_id = len(block_map)
582 block_map[block.ondisk_id] = block
586 block_map[block.ondisk_id] = block
583 block_data = data[i : i + S_BLOCK.size]
587 block_data = data[i : i + S_BLOCK.size]
584 values = S_BLOCK.unpack(block_data)
588 values = S_BLOCK.unpack(block_data)
585 new_blocks.append((block, values))
589 new_blocks.append((block, values))
586 for b, values in new_blocks:
590 for b, values in new_blocks:
587 for idx, v in enumerate(values):
591 for idx, v in enumerate(values):
588 if v == NO_ENTRY:
592 if v == NO_ENTRY:
589 continue
593 continue
590 elif v >= 0:
594 elif v >= 0:
591 b[idx] = block_map[v]
595 b[idx] = block_map[v]
592 else:
596 else:
593 b[idx] = _transform_rev(v)
597 b[idx] = _transform_rev(v)
594 return block, i // S_BLOCK.size
598 return block, i // S_BLOCK.size
595
599
596
600
597 # debug utility
601 # debug utility
598
602
599
603
600 def check_data(ui, index, data):
604 def check_data(ui, index, data):
601 """verify that the provided nodemap data are valid for the given idex"""
605 """verify that the provided nodemap data are valid for the given idex"""
602 ret = 0
606 ret = 0
603 ui.status((b"revision in index: %d\n") % len(index))
607 ui.status((b"revision in index: %d\n") % len(index))
604 root, __ = parse_data(data)
608 root, __ = parse_data(data)
605 all_revs = set(_all_revisions(root))
609 all_revs = set(_all_revisions(root))
606 ui.status((b"revision in nodemap: %d\n") % len(all_revs))
610 ui.status((b"revision in nodemap: %d\n") % len(all_revs))
607 for r in range(len(index)):
611 for r in range(len(index)):
608 if r not in all_revs:
612 if r not in all_revs:
609 msg = b" revision missing from nodemap: %d\n" % r
613 msg = b" revision missing from nodemap: %d\n" % r
610 ui.write_err(msg)
614 ui.write_err(msg)
611 ret = 1
615 ret = 1
612 else:
616 else:
613 all_revs.remove(r)
617 all_revs.remove(r)
614 nm_rev = _find_node(root, hex(index[r][7]))
618 nm_rev = _find_node(root, hex(index[r][7]))
615 if nm_rev is None:
619 if nm_rev is None:
616 msg = b" revision node does not match any entries: %d\n" % r
620 msg = b" revision node does not match any entries: %d\n" % r
617 ui.write_err(msg)
621 ui.write_err(msg)
618 ret = 1
622 ret = 1
619 elif nm_rev != r:
623 elif nm_rev != r:
620 msg = (
624 msg = (
621 b" revision node does not match the expected revision: "
625 b" revision node does not match the expected revision: "
622 b"%d != %d\n" % (r, nm_rev)
626 b"%d != %d\n" % (r, nm_rev)
623 )
627 )
624 ui.write_err(msg)
628 ui.write_err(msg)
625 ret = 1
629 ret = 1
626
630
627 if all_revs:
631 if all_revs:
628 for r in sorted(all_revs):
632 for r in sorted(all_revs):
629 msg = b" extra revision in nodemap: %d\n" % r
633 msg = b" extra revision in nodemap: %d\n" % r
630 ui.write_err(msg)
634 ui.write_err(msg)
631 ret = 1
635 ret = 1
632 return ret
636 return ret
633
637
634
638
635 def _all_revisions(root):
639 def _all_revisions(root):
636 """return all revisions stored in a Trie"""
640 """return all revisions stored in a Trie"""
637 for block in _walk_trie(root):
641 for block in _walk_trie(root):
638 for v in block:
642 for v in block:
639 if v is None or isinstance(v, Block):
643 if v is None or isinstance(v, Block):
640 continue
644 continue
641 yield v
645 yield v
642
646
643
647
644 def _find_node(block, node):
648 def _find_node(block, node):
645 """find the revision associated with a given node"""
649 """find the revision associated with a given node"""
646 entry = block.get(_to_int(node[0:1]))
650 entry = block.get(_to_int(node[0:1]))
647 if isinstance(entry, dict):
651 if isinstance(entry, dict):
648 return _find_node(entry, node[1:])
652 return _find_node(entry, node[1:])
649 return entry
653 return entry
650
654
651
655
652 def get_nodemap_file(opener, indexfile):
656 def get_nodemap_file(opener, indexfile):
653 if indexfile.endswith(b'.a'):
657 if indexfile.endswith(b'.a'):
654 pending_path = indexfile[:-4] + b".n.a"
658 pending_path = indexfile[:-4] + b".n.a"
655 if opener.exists(pending_path):
659 if opener.exists(pending_path):
656 return pending_path
660 return pending_path
657 else:
661 else:
658 return indexfile[:-4] + b".n"
662 return indexfile[:-4] + b".n"
659 else:
663 else:
660 return indexfile[:-2] + b".n"
664 return indexfile[:-2] + b".n"
@@ -1,834 +1,838 b''
1 ===================================
1 ===================================
2 Test the persistent on-disk nodemap
2 Test the persistent on-disk nodemap
3 ===================================
3 ===================================
4
4
5
5
6 #if no-rust
6 #if no-rust
7
7
8 $ cat << EOF >> $HGRCPATH
8 $ cat << EOF >> $HGRCPATH
9 > [format]
9 > [format]
10 > use-persistent-nodemap=yes
10 > use-persistent-nodemap=yes
11 > [devel]
11 > [devel]
12 > persistent-nodemap=yes
12 > persistent-nodemap=yes
13 > EOF
13 > EOF
14
14
15 #endif
15 #endif
16
16
17 $ hg init test-repo --config storage.revlog.persistent-nodemap.slow-path=allow
17 $ hg init test-repo --config storage.revlog.persistent-nodemap.slow-path=allow
18 $ cd test-repo
18 $ cd test-repo
19
19
20 Check handling of the default slow-path value
20 Check handling of the default slow-path value
21
21
22 #if no-pure no-rust
22 #if no-pure no-rust
23
23
24 $ hg id
24 $ hg id
25 abort: accessing `persistent-nodemap` repository without associated fast implementation.
25 abort: accessing `persistent-nodemap` repository without associated fast implementation.
26 (check `hg help config.format.use-persistent-nodemap` for details)
26 (check `hg help config.format.use-persistent-nodemap` for details)
27 [255]
27 [255]
28
28
29 Unlock further check (we are here to test the feature)
29 Unlock further check (we are here to test the feature)
30
30
31 $ cat << EOF >> $HGRCPATH
31 $ cat << EOF >> $HGRCPATH
32 > [storage]
32 > [storage]
33 > # to avoid spamming the test
33 > # to avoid spamming the test
34 > revlog.persistent-nodemap.slow-path=allow
34 > revlog.persistent-nodemap.slow-path=allow
35 > EOF
35 > EOF
36
36
37 #endif
37 #endif
38
38
39 #if rust
39 #if rust
40
40
41 Regression test for a previous bug in Rust/C FFI for the `Revlog_CAPI` capsule:
41 Regression test for a previous bug in Rust/C FFI for the `Revlog_CAPI` capsule:
42 in places where `mercurial/cext/revlog.c` function signatures use `Py_ssize_t`
42 in places where `mercurial/cext/revlog.c` function signatures use `Py_ssize_t`
43 (64 bits on Linux x86_64), corresponding declarations in `rust/hg-cpython/src/cindex.rs`
43 (64 bits on Linux x86_64), corresponding declarations in `rust/hg-cpython/src/cindex.rs`
44 incorrectly used `libc::c_int` (32 bits).
44 incorrectly used `libc::c_int` (32 bits).
45 As a result, -1 passed from Rust for the null revision became 4294967295 in C.
45 As a result, -1 passed from Rust for the null revision became 4294967295 in C.
46
46
47 $ hg log -r 00000000
47 $ hg log -r 00000000
48 changeset: -1:000000000000
48 changeset: -1:000000000000
49 tag: tip
49 tag: tip
50 user:
50 user:
51 date: Thu Jan 01 00:00:00 1970 +0000
51 date: Thu Jan 01 00:00:00 1970 +0000
52
52
53
53
54 #endif
54 #endif
55
55
56
56
57 $ hg debugformat
57 $ hg debugformat
58 format-variant repo
58 format-variant repo
59 fncache: yes
59 fncache: yes
60 dotencode: yes
60 dotencode: yes
61 generaldelta: yes
61 generaldelta: yes
62 share-safe: no
62 share-safe: no
63 sparserevlog: yes
63 sparserevlog: yes
64 persistent-nodemap: yes
64 persistent-nodemap: yes
65 copies-sdc: no
65 copies-sdc: no
66 revlog-v2: no
66 revlog-v2: no
67 plain-cl-delta: yes
67 plain-cl-delta: yes
68 compression: zlib (no-zstd !)
68 compression: zlib (no-zstd !)
69 compression: zstd (zstd !)
69 compression: zstd (zstd !)
70 compression-level: default
70 compression-level: default
71 $ hg debugbuilddag .+5000 --new-file
71 $ hg debugbuilddag .+5000 --new-file
72
72
73 $ hg debugnodemap --metadata
73 $ hg debugnodemap --metadata
74 uid: ???????????????? (glob)
74 uid: ???????????????? (glob)
75 tip-rev: 5000
75 tip-rev: 5000
76 tip-node: 6b02b8c7b96654c25e86ba69eda198d7e6ad8b3c
76 tip-node: 6b02b8c7b96654c25e86ba69eda198d7e6ad8b3c
77 data-length: 121088
77 data-length: 121088
78 data-unused: 0
78 data-unused: 0
79 data-unused: 0.000%
79 data-unused: 0.000%
80 $ f --size .hg/store/00changelog.n
80 $ f --size .hg/store/00changelog.n
81 .hg/store/00changelog.n: size=70
81 .hg/store/00changelog.n: size=70
82
82
83 Simple lookup works
83 Simple lookup works
84
84
85 $ ANYNODE=`hg log --template '{node|short}\n' --rev tip`
85 $ ANYNODE=`hg log --template '{node|short}\n' --rev tip`
86 $ hg log -r "$ANYNODE" --template '{rev}\n'
86 $ hg log -r "$ANYNODE" --template '{rev}\n'
87 5000
87 5000
88
88
89
89
90 #if rust
90 #if rust
91
91
92 $ f --sha256 .hg/store/00changelog-*.nd
92 $ f --sha256 .hg/store/00changelog-*.nd
93 .hg/store/00changelog-????????????????.nd: sha256=2e029d3200bd1a986b32784fc2ef1a3bd60dc331f025718bcf5ff44d93f026fd (glob)
93 .hg/store/00changelog-????????????????.nd: sha256=2e029d3200bd1a986b32784fc2ef1a3bd60dc331f025718bcf5ff44d93f026fd (glob)
94
94
95 $ f --sha256 .hg/store/00manifest-*.nd
95 $ f --sha256 .hg/store/00manifest-*.nd
96 .hg/store/00manifest-????????????????.nd: sha256=97117b1c064ea2f86664a124589e47db0e254e8d34739b5c5cc5bf31c9da2b51 (glob)
96 .hg/store/00manifest-????????????????.nd: sha256=97117b1c064ea2f86664a124589e47db0e254e8d34739b5c5cc5bf31c9da2b51 (glob)
97 $ hg debugnodemap --dump-new | f --sha256 --size
97 $ hg debugnodemap --dump-new | f --sha256 --size
98 size=121088, sha256=2e029d3200bd1a986b32784fc2ef1a3bd60dc331f025718bcf5ff44d93f026fd
98 size=121088, sha256=2e029d3200bd1a986b32784fc2ef1a3bd60dc331f025718bcf5ff44d93f026fd
99 $ hg debugnodemap --dump-disk | f --sha256 --bytes=256 --hexdump --size
99 $ hg debugnodemap --dump-disk | f --sha256 --bytes=256 --hexdump --size
100 size=121088, sha256=2e029d3200bd1a986b32784fc2ef1a3bd60dc331f025718bcf5ff44d93f026fd
100 size=121088, sha256=2e029d3200bd1a986b32784fc2ef1a3bd60dc331f025718bcf5ff44d93f026fd
101 0000: 00 00 00 91 00 00 00 20 00 00 00 bb 00 00 00 e7 |....... ........|
101 0000: 00 00 00 91 00 00 00 20 00 00 00 bb 00 00 00 e7 |....... ........|
102 0010: 00 00 00 66 00 00 00 a1 00 00 01 13 00 00 01 22 |...f..........."|
102 0010: 00 00 00 66 00 00 00 a1 00 00 01 13 00 00 01 22 |...f..........."|
103 0020: 00 00 00 23 00 00 00 fc 00 00 00 ba 00 00 00 5e |...#...........^|
103 0020: 00 00 00 23 00 00 00 fc 00 00 00 ba 00 00 00 5e |...#...........^|
104 0030: 00 00 00 df 00 00 01 4e 00 00 01 65 00 00 00 ab |.......N...e....|
104 0030: 00 00 00 df 00 00 01 4e 00 00 01 65 00 00 00 ab |.......N...e....|
105 0040: 00 00 00 a9 00 00 00 95 00 00 00 73 00 00 00 38 |...........s...8|
105 0040: 00 00 00 a9 00 00 00 95 00 00 00 73 00 00 00 38 |...........s...8|
106 0050: 00 00 00 cc 00 00 00 92 00 00 00 90 00 00 00 69 |...............i|
106 0050: 00 00 00 cc 00 00 00 92 00 00 00 90 00 00 00 69 |...............i|
107 0060: 00 00 00 ec 00 00 00 8d 00 00 01 4f 00 00 00 12 |...........O....|
107 0060: 00 00 00 ec 00 00 00 8d 00 00 01 4f 00 00 00 12 |...........O....|
108 0070: 00 00 02 0c 00 00 00 77 00 00 00 9c 00 00 00 8f |.......w........|
108 0070: 00 00 02 0c 00 00 00 77 00 00 00 9c 00 00 00 8f |.......w........|
109 0080: 00 00 00 d5 00 00 00 6b 00 00 00 48 00 00 00 b3 |.......k...H....|
109 0080: 00 00 00 d5 00 00 00 6b 00 00 00 48 00 00 00 b3 |.......k...H....|
110 0090: 00 00 00 e5 00 00 00 b5 00 00 00 8e 00 00 00 ad |................|
110 0090: 00 00 00 e5 00 00 00 b5 00 00 00 8e 00 00 00 ad |................|
111 00a0: 00 00 00 7b 00 00 00 7c 00 00 00 0b 00 00 00 2b |...{...|.......+|
111 00a0: 00 00 00 7b 00 00 00 7c 00 00 00 0b 00 00 00 2b |...{...|.......+|
112 00b0: 00 00 00 c6 00 00 00 1e 00 00 01 08 00 00 00 11 |................|
112 00b0: 00 00 00 c6 00 00 00 1e 00 00 01 08 00 00 00 11 |................|
113 00c0: 00 00 01 30 00 00 00 26 00 00 01 9c 00 00 00 35 |...0...&.......5|
113 00c0: 00 00 01 30 00 00 00 26 00 00 01 9c 00 00 00 35 |...0...&.......5|
114 00d0: 00 00 00 b8 00 00 01 31 00 00 00 2c 00 00 00 55 |.......1...,...U|
114 00d0: 00 00 00 b8 00 00 01 31 00 00 00 2c 00 00 00 55 |.......1...,...U|
115 00e0: 00 00 00 8a 00 00 00 9a 00 00 00 0c 00 00 01 1e |................|
115 00e0: 00 00 00 8a 00 00 00 9a 00 00 00 0c 00 00 01 1e |................|
116 00f0: 00 00 00 a4 00 00 00 83 00 00 00 c9 00 00 00 8c |................|
116 00f0: 00 00 00 a4 00 00 00 83 00 00 00 c9 00 00 00 8c |................|
117
117
118
118
119 #else
119 #else
120
120
121 $ f --sha256 .hg/store/00changelog-*.nd
121 $ f --sha256 .hg/store/00changelog-*.nd
122 .hg/store/00changelog-????????????????.nd: sha256=f544f5462ff46097432caf6d764091f6d8c46d6121be315ead8576d548c9dd79 (glob)
122 .hg/store/00changelog-????????????????.nd: sha256=f544f5462ff46097432caf6d764091f6d8c46d6121be315ead8576d548c9dd79 (glob)
123 $ hg debugnodemap --dump-new | f --sha256 --size
123 $ hg debugnodemap --dump-new | f --sha256 --size
124 size=121088, sha256=f544f5462ff46097432caf6d764091f6d8c46d6121be315ead8576d548c9dd79
124 size=121088, sha256=f544f5462ff46097432caf6d764091f6d8c46d6121be315ead8576d548c9dd79
125 $ hg debugnodemap --dump-disk | f --sha256 --bytes=256 --hexdump --size
125 $ hg debugnodemap --dump-disk | f --sha256 --bytes=256 --hexdump --size
126 size=121088, sha256=f544f5462ff46097432caf6d764091f6d8c46d6121be315ead8576d548c9dd79
126 size=121088, sha256=f544f5462ff46097432caf6d764091f6d8c46d6121be315ead8576d548c9dd79
127 0000: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
127 0000: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
128 0010: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
128 0010: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
129 0020: ff ff ff ff ff ff f5 06 ff ff ff ff ff ff f3 e7 |................|
129 0020: ff ff ff ff ff ff f5 06 ff ff ff ff ff ff f3 e7 |................|
130 0030: ff ff ef ca ff ff ff ff ff ff ff ff ff ff ff ff |................|
130 0030: ff ff ef ca ff ff ff ff ff ff ff ff ff ff ff ff |................|
131 0040: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
131 0040: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
132 0050: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ed 08 |................|
132 0050: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ed 08 |................|
133 0060: ff ff ed 66 ff ff ff ff ff ff ff ff ff ff ff ff |...f............|
133 0060: ff ff ed 66 ff ff ff ff ff ff ff ff ff ff ff ff |...f............|
134 0070: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
134 0070: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
135 0080: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
135 0080: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
136 0090: ff ff ff ff ff ff ff ff ff ff ff ff ff ff f6 ed |................|
136 0090: ff ff ff ff ff ff ff ff ff ff ff ff ff ff f6 ed |................|
137 00a0: ff ff ff ff ff ff fe 61 ff ff ff ff ff ff ff ff |.......a........|
137 00a0: ff ff ff ff ff ff fe 61 ff ff ff ff ff ff ff ff |.......a........|
138 00b0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
138 00b0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
139 00c0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
139 00c0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
140 00d0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
140 00d0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
141 00e0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff f1 02 |................|
141 00e0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff f1 02 |................|
142 00f0: ff ff ff ff ff ff ed 1b ff ff ff ff ff ff ff ff |................|
142 00f0: ff ff ff ff ff ff ed 1b ff ff ff ff ff ff ff ff |................|
143
143
144 #endif
144 #endif
145
145
146 $ hg debugnodemap --check
146 $ hg debugnodemap --check
147 revision in index: 5001
147 revision in index: 5001
148 revision in nodemap: 5001
148 revision in nodemap: 5001
149
149
150 add a new commit
150 add a new commit
151
151
152 $ hg up
152 $ hg up
153 5001 files updated, 0 files merged, 0 files removed, 0 files unresolved
153 5001 files updated, 0 files merged, 0 files removed, 0 files unresolved
154 $ echo foo > foo
154 $ echo foo > foo
155 $ hg add foo
155 $ hg add foo
156
156
157
157
158 Check slow-path config value handling
158 Check slow-path config value handling
159 -------------------------------------
159 -------------------------------------
160
160
161 #if no-pure no-rust
161 #if no-pure no-rust
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 abort: accessing `persistent-nodemap` repository without associated fast implementation.
166 abort: accessing `persistent-nodemap` repository without associated fast implementation.
167 (check `hg help config.format.use-persistent-nodemap` for details)
167 (check `hg help config.format.use-persistent-nodemap` for details)
168 [255]
168 [255]
169
169
170 $ hg log -r . --config "storage.revlog.persistent-nodemap.slow-path=warn"
170 $ hg log -r . --config "storage.revlog.persistent-nodemap.slow-path=warn"
171 warning: accessing `persistent-nodemap` repository without associated fast implementation.
171 warning: accessing `persistent-nodemap` repository without associated fast implementation.
172 (check `hg help config.format.use-persistent-nodemap` for details)
172 (check `hg help config.format.use-persistent-nodemap` for details)
173 changeset: 5000:6b02b8c7b966
173 changeset: 5000:6b02b8c7b966
174 tag: tip
174 tag: tip
175 user: debugbuilddag
175 user: debugbuilddag
176 date: Thu Jan 01 01:23:20 1970 +0000
176 date: Thu Jan 01 01:23:20 1970 +0000
177 summary: r5000
177 summary: r5000
178
178
179 $ hg ci -m 'foo' --config "storage.revlog.persistent-nodemap.slow-path=abort"
179 $ hg ci -m 'foo' --config "storage.revlog.persistent-nodemap.slow-path=abort"
180 abort: accessing `persistent-nodemap` repository without associated fast implementation.
180 abort: accessing `persistent-nodemap` repository without associated fast implementation.
181 (check `hg help config.format.use-persistent-nodemap` for details)
181 (check `hg help config.format.use-persistent-nodemap` for details)
182 [255]
182 [255]
183
183
184 #else
184 #else
185
185
186 $ hg id --config "storage.revlog.persistent-nodemap.slow-path=invalid-value"
186 $ hg id --config "storage.revlog.persistent-nodemap.slow-path=invalid-value"
187 unknown value for config "storage.revlog.persistent-nodemap.slow-path": "invalid-value"
187 unknown value for config "storage.revlog.persistent-nodemap.slow-path": "invalid-value"
188 falling back to default value: abort
188 falling back to default value: abort
189 6b02b8c7b966+ tip
189 6b02b8c7b966+ tip
190
190
191 #endif
191 #endif
192
192
193 $ hg ci -m 'foo'
193 $ hg ci -m 'foo'
194
194
195 #if no-pure no-rust
195 #if no-pure no-rust
196 $ hg debugnodemap --metadata
196 $ hg debugnodemap --metadata
197 uid: ???????????????? (glob)
197 uid: ???????????????? (glob)
198 tip-rev: 5001
198 tip-rev: 5001
199 tip-node: 16395c3cf7e231394735e6b1717823ada303fb0c
199 tip-node: 16395c3cf7e231394735e6b1717823ada303fb0c
200 data-length: 121088
200 data-length: 121088
201 data-unused: 0
201 data-unused: 0
202 data-unused: 0.000%
202 data-unused: 0.000%
203 #else
203 #else
204 $ hg debugnodemap --metadata
204 $ hg debugnodemap --metadata
205 uid: ???????????????? (glob)
205 uid: ???????????????? (glob)
206 tip-rev: 5001
206 tip-rev: 5001
207 tip-node: 16395c3cf7e231394735e6b1717823ada303fb0c
207 tip-node: 16395c3cf7e231394735e6b1717823ada303fb0c
208 data-length: 121344
208 data-length: 121344
209 data-unused: 256
209 data-unused: 256
210 data-unused: 0.211%
210 data-unused: 0.211%
211 #endif
211 #endif
212
212
213 $ f --size .hg/store/00changelog.n
213 $ f --size .hg/store/00changelog.n
214 .hg/store/00changelog.n: size=70
214 .hg/store/00changelog.n: size=70
215
215
216 (The pure code use the debug code that perform incremental update, the C code reencode from scratch)
216 (The pure code use the debug code that perform incremental update, the C code reencode from scratch)
217
217
218 #if pure
218 #if pure
219 $ f --sha256 .hg/store/00changelog-*.nd --size
219 $ f --sha256 .hg/store/00changelog-*.nd --size
220 .hg/store/00changelog-????????????????.nd: size=121344, sha256=cce54c5da5bde3ad72a4938673ed4064c86231b9c64376b082b163fdb20f8f66 (glob)
220 .hg/store/00changelog-????????????????.nd: size=121344, sha256=cce54c5da5bde3ad72a4938673ed4064c86231b9c64376b082b163fdb20f8f66 (glob)
221 #endif
221 #endif
222
222
223 #if rust
223 #if rust
224 $ f --sha256 .hg/store/00changelog-*.nd --size
224 $ f --sha256 .hg/store/00changelog-*.nd --size
225 .hg/store/00changelog-????????????????.nd: size=121344, sha256=952b042fcf614ceb37b542b1b723e04f18f83efe99bee4e0f5ccd232ef470e58 (glob)
225 .hg/store/00changelog-????????????????.nd: size=121344, sha256=952b042fcf614ceb37b542b1b723e04f18f83efe99bee4e0f5ccd232ef470e58 (glob)
226 #endif
226 #endif
227
227
228 #if no-pure no-rust
228 #if no-pure no-rust
229 $ f --sha256 .hg/store/00changelog-*.nd --size
229 $ f --sha256 .hg/store/00changelog-*.nd --size
230 .hg/store/00changelog-????????????????.nd: size=121088, sha256=df7c06a035b96cb28c7287d349d603baef43240be7736fe34eea419a49702e17 (glob)
230 .hg/store/00changelog-????????????????.nd: size=121088, sha256=df7c06a035b96cb28c7287d349d603baef43240be7736fe34eea419a49702e17 (glob)
231 #endif
231 #endif
232
232
233 $ hg debugnodemap --check
233 $ hg debugnodemap --check
234 revision in index: 5002
234 revision in index: 5002
235 revision in nodemap: 5002
235 revision in nodemap: 5002
236
236
237 Test code path without mmap
237 Test code path without mmap
238 ---------------------------
238 ---------------------------
239
239
240 $ echo bar > bar
240 $ echo bar > bar
241 $ hg add bar
241 $ hg add bar
242 $ hg ci -m 'bar' --config storage.revlog.persistent-nodemap.mmap=no
242 $ hg ci -m 'bar' --config storage.revlog.persistent-nodemap.mmap=no
243
243
244 $ hg debugnodemap --check --config storage.revlog.persistent-nodemap.mmap=yes
244 $ hg debugnodemap --check --config storage.revlog.persistent-nodemap.mmap=yes
245 revision in index: 5003
245 revision in index: 5003
246 revision in nodemap: 5003
246 revision in nodemap: 5003
247 $ hg debugnodemap --check --config storage.revlog.persistent-nodemap.mmap=no
247 $ hg debugnodemap --check --config storage.revlog.persistent-nodemap.mmap=no
248 revision in index: 5003
248 revision in index: 5003
249 revision in nodemap: 5003
249 revision in nodemap: 5003
250
250
251
251
252 #if pure
252 #if pure
253 $ hg debugnodemap --metadata
253 $ hg debugnodemap --metadata
254 uid: ???????????????? (glob)
254 uid: ???????????????? (glob)
255 tip-rev: 5002
255 tip-rev: 5002
256 tip-node: 880b18d239dfa9f632413a2071bfdbcc4806a4fd
256 tip-node: 880b18d239dfa9f632413a2071bfdbcc4806a4fd
257 data-length: 121600
257 data-length: 121600
258 data-unused: 512
258 data-unused: 512
259 data-unused: 0.421%
259 data-unused: 0.421%
260 $ f --sha256 .hg/store/00changelog-*.nd --size
260 $ f --sha256 .hg/store/00changelog-*.nd --size
261 .hg/store/00changelog-????????????????.nd: size=121600, sha256=def52503d049ccb823974af313a98a935319ba61f40f3aa06a8be4d35c215054 (glob)
261 .hg/store/00changelog-????????????????.nd: size=121600, sha256=def52503d049ccb823974af313a98a935319ba61f40f3aa06a8be4d35c215054 (glob)
262 #endif
262 #endif
263 #if rust
263 #if rust
264 $ hg debugnodemap --metadata
264 $ hg debugnodemap --metadata
265 uid: ???????????????? (glob)
265 uid: ???????????????? (glob)
266 tip-rev: 5002
266 tip-rev: 5002
267 tip-node: 880b18d239dfa9f632413a2071bfdbcc4806a4fd
267 tip-node: 880b18d239dfa9f632413a2071bfdbcc4806a4fd
268 data-length: 121600
268 data-length: 121600
269 data-unused: 512
269 data-unused: 512
270 data-unused: 0.421%
270 data-unused: 0.421%
271 $ f --sha256 .hg/store/00changelog-*.nd --size
271 $ f --sha256 .hg/store/00changelog-*.nd --size
272 .hg/store/00changelog-????????????????.nd: size=121600, sha256=dacf5b5f1d4585fee7527d0e67cad5b1ba0930e6a0928f650f779aefb04ce3fb (glob)
272 .hg/store/00changelog-????????????????.nd: size=121600, sha256=dacf5b5f1d4585fee7527d0e67cad5b1ba0930e6a0928f650f779aefb04ce3fb (glob)
273 #endif
273 #endif
274 #if no-pure no-rust
274 #if no-pure no-rust
275 $ hg debugnodemap --metadata
275 $ hg debugnodemap --metadata
276 uid: ???????????????? (glob)
276 uid: ???????????????? (glob)
277 tip-rev: 5002
277 tip-rev: 5002
278 tip-node: 880b18d239dfa9f632413a2071bfdbcc4806a4fd
278 tip-node: 880b18d239dfa9f632413a2071bfdbcc4806a4fd
279 data-length: 121088
279 data-length: 121088
280 data-unused: 0
280 data-unused: 0
281 data-unused: 0.000%
281 data-unused: 0.000%
282 $ f --sha256 .hg/store/00changelog-*.nd --size
282 $ f --sha256 .hg/store/00changelog-*.nd --size
283 .hg/store/00changelog-????????????????.nd: size=121088, sha256=59fcede3e3cc587755916ceed29e3c33748cd1aa7d2f91828ac83e7979d935e8 (glob)
283 .hg/store/00changelog-????????????????.nd: size=121088, sha256=59fcede3e3cc587755916ceed29e3c33748cd1aa7d2f91828ac83e7979d935e8 (glob)
284 #endif
284 #endif
285
285
286 Test force warming the cache
286 Test force warming the cache
287
287
288 $ rm .hg/store/00changelog.n
288 $ rm .hg/store/00changelog.n
289 $ hg debugnodemap --metadata
289 $ hg debugnodemap --metadata
290 $ hg debugupdatecache
290 $ hg debugupdatecache
291 #if pure
291 #if pure
292 $ hg debugnodemap --metadata
292 $ hg debugnodemap --metadata
293 uid: ???????????????? (glob)
293 uid: ???????????????? (glob)
294 tip-rev: 5002
294 tip-rev: 5002
295 tip-node: 880b18d239dfa9f632413a2071bfdbcc4806a4fd
295 tip-node: 880b18d239dfa9f632413a2071bfdbcc4806a4fd
296 data-length: 121088
296 data-length: 121088
297 data-unused: 0
297 data-unused: 0
298 data-unused: 0.000%
298 data-unused: 0.000%
299 #else
299 #else
300 $ hg debugnodemap --metadata
300 $ hg debugnodemap --metadata
301 uid: ???????????????? (glob)
301 uid: ???????????????? (glob)
302 tip-rev: 5002
302 tip-rev: 5002
303 tip-node: 880b18d239dfa9f632413a2071bfdbcc4806a4fd
303 tip-node: 880b18d239dfa9f632413a2071bfdbcc4806a4fd
304 data-length: 121088
304 data-length: 121088
305 data-unused: 0
305 data-unused: 0
306 data-unused: 0.000%
306 data-unused: 0.000%
307 #endif
307 #endif
308
308
309 Check out of sync nodemap
309 Check out of sync nodemap
310 =========================
310 =========================
311
311
312 First copy old data on the side.
312 First copy old data on the side.
313
313
314 $ mkdir ../tmp-copies
314 $ mkdir ../tmp-copies
315 $ cp .hg/store/00changelog-????????????????.nd .hg/store/00changelog.n ../tmp-copies
315 $ cp .hg/store/00changelog-????????????????.nd .hg/store/00changelog.n ../tmp-copies
316
316
317 Nodemap lagging behind
317 Nodemap lagging behind
318 ----------------------
318 ----------------------
319
319
320 make a new commit
320 make a new commit
321
321
322 $ echo bar2 > bar
322 $ echo bar2 > bar
323 $ hg ci -m 'bar2'
323 $ hg ci -m 'bar2'
324 $ NODE=`hg log -r tip -T '{node}\n'`
324 $ NODE=`hg log -r tip -T '{node}\n'`
325 $ hg log -r "$NODE" -T '{rev}\n'
325 $ hg log -r "$NODE" -T '{rev}\n'
326 5003
326 5003
327
327
328 If the nodemap is lagging behind, it can catch up fine
328 If the nodemap is lagging behind, it can catch up fine
329
329
330 $ hg debugnodemap --metadata
330 $ hg debugnodemap --metadata
331 uid: ???????????????? (glob)
331 uid: ???????????????? (glob)
332 tip-rev: 5003
332 tip-rev: 5003
333 tip-node: c9329770f979ade2d16912267c38ba5f82fd37b3
333 tip-node: c9329770f979ade2d16912267c38ba5f82fd37b3
334 data-length: 121344 (pure !)
334 data-length: 121344 (pure !)
335 data-length: 121344 (rust !)
335 data-length: 121344 (rust !)
336 data-length: 121152 (no-rust no-pure !)
336 data-length: 121152 (no-rust no-pure !)
337 data-unused: 192 (pure !)
337 data-unused: 192 (pure !)
338 data-unused: 192 (rust !)
338 data-unused: 192 (rust !)
339 data-unused: 0 (no-rust no-pure !)
339 data-unused: 0 (no-rust no-pure !)
340 data-unused: 0.158% (pure !)
340 data-unused: 0.158% (pure !)
341 data-unused: 0.158% (rust !)
341 data-unused: 0.158% (rust !)
342 data-unused: 0.000% (no-rust no-pure !)
342 data-unused: 0.000% (no-rust no-pure !)
343 $ cp -f ../tmp-copies/* .hg/store/
343 $ cp -f ../tmp-copies/* .hg/store/
344 $ hg debugnodemap --metadata
344 $ hg debugnodemap --metadata
345 uid: ???????????????? (glob)
345 uid: ???????????????? (glob)
346 tip-rev: 5002
346 tip-rev: 5002
347 tip-node: 880b18d239dfa9f632413a2071bfdbcc4806a4fd
347 tip-node: 880b18d239dfa9f632413a2071bfdbcc4806a4fd
348 data-length: 121088
348 data-length: 121088
349 data-unused: 0
349 data-unused: 0
350 data-unused: 0.000%
350 data-unused: 0.000%
351 $ hg log -r "$NODE" -T '{rev}\n'
351 $ hg log -r "$NODE" -T '{rev}\n'
352 5003
352 5003
353
353
354 changelog altered
354 changelog altered
355 -----------------
355 -----------------
356
356
357 If the nodemap is not gated behind a requirements, an unaware client can alter
357 If the nodemap is not gated behind a requirements, an unaware client can alter
358 the repository so the revlog used to generate the nodemap is not longer
358 the repository so the revlog used to generate the nodemap is not longer
359 compatible with the persistent nodemap. We need to detect that.
359 compatible with the persistent nodemap. We need to detect that.
360
360
361 $ hg up "$NODE~5"
361 $ hg up "$NODE~5"
362 0 files updated, 0 files merged, 4 files removed, 0 files unresolved
362 0 files updated, 0 files merged, 4 files removed, 0 files unresolved
363 $ echo bar > babar
363 $ echo bar > babar
364 $ hg add babar
364 $ hg add babar
365 $ hg ci -m 'babar'
365 $ hg ci -m 'babar'
366 created new head
366 created new head
367 $ OTHERNODE=`hg log -r tip -T '{node}\n'`
367 $ OTHERNODE=`hg log -r tip -T '{node}\n'`
368 $ hg log -r "$OTHERNODE" -T '{rev}\n'
368 $ hg log -r "$OTHERNODE" -T '{rev}\n'
369 5004
369 5004
370
370
371 $ hg --config extensions.strip= strip --rev "$NODE~1" --no-backup
371 $ hg --config extensions.strip= strip --rev "$NODE~1" --no-backup
372
372
373 the nodemap should detect the changelog have been tampered with and recover.
373 the nodemap should detect the changelog have been tampered with and recover.
374
374
375 $ hg debugnodemap --metadata
375 $ hg debugnodemap --metadata
376 uid: ???????????????? (glob)
376 uid: ???????????????? (glob)
377 tip-rev: 5002
377 tip-rev: 5002
378 tip-node: b355ef8adce0949b8bdf6afc72ca853740d65944
378 tip-node: b355ef8adce0949b8bdf6afc72ca853740d65944
379 data-length: 121536 (pure !)
379 data-length: 121536 (pure !)
380 data-length: 121088 (rust !)
380 data-length: 121088 (rust !)
381 data-length: 121088 (no-pure no-rust !)
381 data-length: 121088 (no-pure no-rust !)
382 data-unused: 448 (pure !)
382 data-unused: 448 (pure !)
383 data-unused: 0 (rust !)
383 data-unused: 0 (rust !)
384 data-unused: 0 (no-pure no-rust !)
384 data-unused: 0 (no-pure no-rust !)
385 data-unused: 0.000% (rust !)
385 data-unused: 0.000% (rust !)
386 data-unused: 0.369% (pure !)
386 data-unused: 0.369% (pure !)
387 data-unused: 0.000% (no-pure no-rust !)
387 data-unused: 0.000% (no-pure no-rust !)
388
388
389 $ cp -f ../tmp-copies/* .hg/store/
389 $ cp -f ../tmp-copies/* .hg/store/
390 $ hg debugnodemap --metadata
390 $ hg debugnodemap --metadata
391 uid: ???????????????? (glob)
391 uid: ???????????????? (glob)
392 tip-rev: 5002
392 tip-rev: 5002
393 tip-node: 880b18d239dfa9f632413a2071bfdbcc4806a4fd
393 tip-node: 880b18d239dfa9f632413a2071bfdbcc4806a4fd
394 data-length: 121088
394 data-length: 121088
395 data-unused: 0
395 data-unused: 0
396 data-unused: 0.000%
396 data-unused: 0.000%
397 $ hg log -r "$OTHERNODE" -T '{rev}\n'
397 $ hg log -r "$OTHERNODE" -T '{rev}\n'
398 5002
398 5002
399
399
400 missing data file
400 missing data file
401 -----------------
401 -----------------
402
402
403 $ UUID=`hg debugnodemap --metadata| grep 'uid:' | \
403 $ UUID=`hg debugnodemap --metadata| grep 'uid:' | \
404 > sed 's/uid: //'`
404 > sed 's/uid: //'`
405 $ FILE=.hg/store/00changelog-"${UUID}".nd
405 $ FILE=.hg/store/00changelog-"${UUID}".nd
406 $ mv $FILE ../tmp-data-file
406 $ mv $FILE ../tmp-data-file
407 $ cp .hg/store/00changelog.n ../tmp-docket
407 $ cp .hg/store/00changelog.n ../tmp-docket
408
408
409 mercurial don't crash
409 mercurial don't crash
410
410
411 $ hg log -r .
411 $ hg log -r .
412 changeset: 5002:b355ef8adce0
412 changeset: 5002:b355ef8adce0
413 tag: tip
413 tag: tip
414 parent: 4998:d918ad6d18d3
414 parent: 4998:d918ad6d18d3
415 user: test
415 user: test
416 date: Thu Jan 01 00:00:00 1970 +0000
416 date: Thu Jan 01 00:00:00 1970 +0000
417 summary: babar
417 summary: babar
418
418
419 $ hg debugnodemap --metadata
419 $ hg debugnodemap --metadata
420
420
421 $ hg debugupdatecache
421 $ hg debugupdatecache
422 $ hg debugnodemap --metadata
422 $ hg debugnodemap --metadata
423 uid: * (glob)
423 uid: * (glob)
424 tip-rev: 5002
424 tip-rev: 5002
425 tip-node: b355ef8adce0949b8bdf6afc72ca853740d65944
425 tip-node: b355ef8adce0949b8bdf6afc72ca853740d65944
426 data-length: 121088
426 data-length: 121088
427 data-unused: 0
427 data-unused: 0
428 data-unused: 0.000%
428 data-unused: 0.000%
429 $ mv ../tmp-data-file $FILE
429 $ mv ../tmp-data-file $FILE
430 $ mv ../tmp-docket .hg/store/00changelog.n
430 $ mv ../tmp-docket .hg/store/00changelog.n
431
431
432 Check transaction related property
432 Check transaction related property
433 ==================================
433 ==================================
434
434
435 An up to date nodemap should be available to shell hooks,
435 An up to date nodemap should be available to shell hooks,
436
436
437 $ echo dsljfl > a
437 $ echo dsljfl > a
438 $ hg add a
438 $ hg add a
439 $ hg ci -m a
439 $ hg ci -m a
440 $ hg debugnodemap --metadata
440 $ hg debugnodemap --metadata
441 uid: ???????????????? (glob)
441 uid: ???????????????? (glob)
442 tip-rev: 5003
442 tip-rev: 5003
443 tip-node: a52c5079765b5865d97b993b303a18740113bbb2
443 tip-node: a52c5079765b5865d97b993b303a18740113bbb2
444 data-length: 121088
444 data-length: 121088
445 data-unused: 0
445 data-unused: 0
446 data-unused: 0.000%
446 data-unused: 0.000%
447 $ echo babar2 > babar
447 $ echo babar2 > babar
448 $ hg ci -m 'babar2' --config "hooks.pretxnclose.nodemap-test=hg debugnodemap --metadata"
448 $ hg ci -m 'babar2' --config "hooks.pretxnclose.nodemap-test=hg debugnodemap --metadata"
449 uid: ???????????????? (glob)
449 uid: ???????????????? (glob)
450 tip-rev: 5004
450 tip-rev: 5004
451 tip-node: 2f5fb1c06a16834c5679d672e90da7c5f3b1a984
451 tip-node: 2f5fb1c06a16834c5679d672e90da7c5f3b1a984
452 data-length: 121280 (pure !)
452 data-length: 121280 (pure !)
453 data-length: 121280 (rust !)
453 data-length: 121280 (rust !)
454 data-length: 121088 (no-pure no-rust !)
454 data-length: 121088 (no-pure no-rust !)
455 data-unused: 192 (pure !)
455 data-unused: 192 (pure !)
456 data-unused: 192 (rust !)
456 data-unused: 192 (rust !)
457 data-unused: 0 (no-pure no-rust !)
457 data-unused: 0 (no-pure no-rust !)
458 data-unused: 0.158% (pure !)
458 data-unused: 0.158% (pure !)
459 data-unused: 0.158% (rust !)
459 data-unused: 0.158% (rust !)
460 data-unused: 0.000% (no-pure no-rust !)
460 data-unused: 0.000% (no-pure no-rust !)
461 $ hg debugnodemap --metadata
461 $ hg debugnodemap --metadata
462 uid: ???????????????? (glob)
462 uid: ???????????????? (glob)
463 tip-rev: 5004
463 tip-rev: 5004
464 tip-node: 2f5fb1c06a16834c5679d672e90da7c5f3b1a984
464 tip-node: 2f5fb1c06a16834c5679d672e90da7c5f3b1a984
465 data-length: 121280 (pure !)
465 data-length: 121280 (pure !)
466 data-length: 121280 (rust !)
466 data-length: 121280 (rust !)
467 data-length: 121088 (no-pure no-rust !)
467 data-length: 121088 (no-pure no-rust !)
468 data-unused: 192 (pure !)
468 data-unused: 192 (pure !)
469 data-unused: 192 (rust !)
469 data-unused: 192 (rust !)
470 data-unused: 0 (no-pure no-rust !)
470 data-unused: 0 (no-pure no-rust !)
471 data-unused: 0.158% (pure !)
471 data-unused: 0.158% (pure !)
472 data-unused: 0.158% (rust !)
472 data-unused: 0.158% (rust !)
473 data-unused: 0.000% (no-pure no-rust !)
473 data-unused: 0.000% (no-pure no-rust !)
474
474
475 Another process does not see the pending nodemap content during run.
475 Another process does not see the pending nodemap content during run.
476
476
477 $ PATH=$RUNTESTDIR/testlib/:$PATH
477 $ PATH=$RUNTESTDIR/testlib/:$PATH
478 $ echo qpoasp > a
478 $ echo qpoasp > a
479 $ hg ci -m a2 \
479 $ hg ci -m a2 \
480 > --config "hooks.pretxnclose=wait-on-file 20 sync-repo-read sync-txn-pending" \
480 > --config "hooks.pretxnclose=wait-on-file 20 sync-repo-read sync-txn-pending" \
481 > --config "hooks.txnclose=touch sync-txn-close" > output.txt 2>&1 &
481 > --config "hooks.txnclose=touch sync-txn-close" > output.txt 2>&1 &
482
482
483 (read the repository while the commit transaction is pending)
483 (read the repository while the commit transaction is pending)
484
484
485 $ wait-on-file 20 sync-txn-pending && \
485 $ wait-on-file 20 sync-txn-pending && \
486 > hg debugnodemap --metadata && \
486 > hg debugnodemap --metadata && \
487 > wait-on-file 20 sync-txn-close sync-repo-read
487 > wait-on-file 20 sync-txn-close sync-repo-read
488 uid: ???????????????? (glob)
488 uid: ???????????????? (glob)
489 tip-rev: 5004
489 tip-rev: 5004
490 tip-node: 2f5fb1c06a16834c5679d672e90da7c5f3b1a984
490 tip-node: 2f5fb1c06a16834c5679d672e90da7c5f3b1a984
491 data-length: 121280 (pure !)
491 data-length: 121280 (pure !)
492 data-length: 121280 (rust !)
492 data-length: 121280 (rust !)
493 data-length: 121088 (no-pure no-rust !)
493 data-length: 121088 (no-pure no-rust !)
494 data-unused: 192 (pure !)
494 data-unused: 192 (pure !)
495 data-unused: 192 (rust !)
495 data-unused: 192 (rust !)
496 data-unused: 0 (no-pure no-rust !)
496 data-unused: 0 (no-pure no-rust !)
497 data-unused: 0.158% (pure !)
497 data-unused: 0.158% (pure !)
498 data-unused: 0.158% (rust !)
498 data-unused: 0.158% (rust !)
499 data-unused: 0.000% (no-pure no-rust !)
499 data-unused: 0.000% (no-pure no-rust !)
500 $ hg debugnodemap --metadata
500 $ hg debugnodemap --metadata
501 uid: ???????????????? (glob)
501 uid: ???????????????? (glob)
502 tip-rev: 5005
502 tip-rev: 5005
503 tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe
503 tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe
504 data-length: 121536 (pure !)
504 data-length: 121536 (pure !)
505 data-length: 121536 (rust !)
505 data-length: 121536 (rust !)
506 data-length: 121088 (no-pure no-rust !)
506 data-length: 121088 (no-pure no-rust !)
507 data-unused: 448 (pure !)
507 data-unused: 448 (pure !)
508 data-unused: 448 (rust !)
508 data-unused: 448 (rust !)
509 data-unused: 0 (no-pure no-rust !)
509 data-unused: 0 (no-pure no-rust !)
510 data-unused: 0.369% (pure !)
510 data-unused: 0.369% (pure !)
511 data-unused: 0.369% (rust !)
511 data-unused: 0.369% (rust !)
512 data-unused: 0.000% (no-pure no-rust !)
512 data-unused: 0.000% (no-pure no-rust !)
513
513
514 $ cat output.txt
514 $ cat output.txt
515
515
516 Check that a failing transaction will properly revert the data
516 Check that a failing transaction will properly revert the data
517
517
518 $ echo plakfe > a
518 $ echo plakfe > a
519 $ f --size --sha256 .hg/store/00changelog-*.nd
519 $ f --size --sha256 .hg/store/00changelog-*.nd
520 .hg/store/00changelog-????????????????.nd: size=121536, sha256=bb414468d225cf52d69132e1237afba34d4346ee2eb81b505027e6197b107f03 (glob) (pure !)
520 .hg/store/00changelog-????????????????.nd: size=121536, sha256=bb414468d225cf52d69132e1237afba34d4346ee2eb81b505027e6197b107f03 (glob) (pure !)
521 .hg/store/00changelog-????????????????.nd: size=121536, sha256=909ac727bc4d1c0fda5f7bff3c620c98bd4a2967c143405a1503439e33b377da (glob) (rust !)
521 .hg/store/00changelog-????????????????.nd: size=121536, sha256=909ac727bc4d1c0fda5f7bff3c620c98bd4a2967c143405a1503439e33b377da (glob) (rust !)
522 .hg/store/00changelog-????????????????.nd: size=121088, sha256=342d36d30d86dde67d3cb6c002606c4a75bcad665595d941493845066d9c8ee0 (glob) (no-pure no-rust !)
522 .hg/store/00changelog-????????????????.nd: size=121088, sha256=342d36d30d86dde67d3cb6c002606c4a75bcad665595d941493845066d9c8ee0 (glob) (no-pure no-rust !)
523 $ hg ci -m a3 --config "extensions.abort=$RUNTESTDIR/testlib/crash_transaction_late.py"
523 $ hg ci -m a3 --config "extensions.abort=$RUNTESTDIR/testlib/crash_transaction_late.py"
524 transaction abort!
524 transaction abort!
525 rollback completed
525 rollback completed
526 abort: This is a late abort
526 abort: This is a late abort
527 [255]
527 [255]
528 $ hg debugnodemap --metadata
528 $ hg debugnodemap --metadata
529 uid: ???????????????? (glob)
529 uid: ???????????????? (glob)
530 tip-rev: 5005
530 tip-rev: 5005
531 tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe
531 tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe
532 data-length: 121536 (pure !)
532 data-length: 121536 (pure !)
533 data-length: 121536 (rust !)
533 data-length: 121536 (rust !)
534 data-length: 121088 (no-pure no-rust !)
534 data-length: 121088 (no-pure no-rust !)
535 data-unused: 448 (pure !)
535 data-unused: 448 (pure !)
536 data-unused: 448 (rust !)
536 data-unused: 448 (rust !)
537 data-unused: 0 (no-pure no-rust !)
537 data-unused: 0 (no-pure no-rust !)
538 data-unused: 0.369% (pure !)
538 data-unused: 0.369% (pure !)
539 data-unused: 0.369% (rust !)
539 data-unused: 0.369% (rust !)
540 data-unused: 0.000% (no-pure no-rust !)
540 data-unused: 0.000% (no-pure no-rust !)
541 $ f --size --sha256 .hg/store/00changelog-*.nd
541 $ f --size --sha256 .hg/store/00changelog-*.nd
542 .hg/store/00changelog-????????????????.nd: size=121536, sha256=bb414468d225cf52d69132e1237afba34d4346ee2eb81b505027e6197b107f03 (glob) (pure !)
542 .hg/store/00changelog-????????????????.nd: size=121536, sha256=bb414468d225cf52d69132e1237afba34d4346ee2eb81b505027e6197b107f03 (glob) (pure !)
543 .hg/store/00changelog-????????????????.nd: size=121536, sha256=909ac727bc4d1c0fda5f7bff3c620c98bd4a2967c143405a1503439e33b377da (glob) (rust !)
543 .hg/store/00changelog-????????????????.nd: size=121536, sha256=909ac727bc4d1c0fda5f7bff3c620c98bd4a2967c143405a1503439e33b377da (glob) (rust !)
544 .hg/store/00changelog-????????????????.nd: size=121088, sha256=342d36d30d86dde67d3cb6c002606c4a75bcad665595d941493845066d9c8ee0 (glob) (no-pure no-rust !)
544 .hg/store/00changelog-????????????????.nd: size=121088, sha256=342d36d30d86dde67d3cb6c002606c4a75bcad665595d941493845066d9c8ee0 (glob) (no-pure no-rust !)
545
545
546 Check that removing content does not confuse the nodemap
546 Check that removing content does not confuse the nodemap
547 --------------------------------------------------------
547 --------------------------------------------------------
548
548
549 removing data with rollback
549 removing data with rollback
550
550
551 $ echo aso > a
551 $ echo aso > a
552 $ hg ci -m a4
552 $ hg ci -m a4
553 $ hg rollback
553 $ hg rollback
554 repository tip rolled back to revision 5005 (undo commit)
554 repository tip rolled back to revision 5005 (undo commit)
555 working directory now based on revision 5005
555 working directory now based on revision 5005
556 $ hg id -r .
556 $ hg id -r .
557 90d5d3ba2fc4 tip
557 90d5d3ba2fc4 tip
558
558
559 roming data with strip
559 roming data with strip
560
560
561 $ echo aso > a
561 $ echo aso > a
562 $ hg ci -m a4
562 $ hg ci -m a4
563 $ hg --config extensions.strip= strip -r . --no-backup
563 $ hg --config extensions.strip= strip -r . --no-backup
564 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
564 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
565 $ hg id -r . --traceback
565 $ hg id -r . --traceback
566 90d5d3ba2fc4 tip
566 90d5d3ba2fc4 tip
567
567
568 Test upgrade / downgrade
568 Test upgrade / downgrade
569 ========================
569 ========================
570
570
571 downgrading
571 downgrading
572
572
573 $ cat << EOF >> .hg/hgrc
573 $ cat << EOF >> .hg/hgrc
574 > [format]
574 > [format]
575 > use-persistent-nodemap=no
575 > use-persistent-nodemap=no
576 > EOF
576 > EOF
577 $ hg debugformat -v
577 $ hg debugformat -v
578 format-variant repo config default
578 format-variant repo config default
579 fncache: yes yes yes
579 fncache: yes yes yes
580 dotencode: yes yes yes
580 dotencode: yes yes yes
581 generaldelta: yes yes yes
581 generaldelta: yes yes yes
582 share-safe: no no no
582 share-safe: no no no
583 sparserevlog: yes yes yes
583 sparserevlog: yes yes yes
584 persistent-nodemap: yes no no
584 persistent-nodemap: yes no no
585 copies-sdc: no no no
585 copies-sdc: no no no
586 revlog-v2: no no no
586 revlog-v2: no no no
587 plain-cl-delta: yes yes yes
587 plain-cl-delta: yes yes yes
588 compression: zlib zlib zlib (no-zstd !)
588 compression: zlib zlib zlib (no-zstd !)
589 compression: zstd zstd zstd (zstd !)
589 compression: zstd zstd zstd (zstd !)
590 compression-level: default default default
590 compression-level: default default default
591 $ hg debugupgraderepo --run --no-backup
591 $ hg debugupgraderepo --run --no-backup
592 upgrade will perform the following actions:
592 upgrade will perform the following actions:
593
593
594 requirements
594 requirements
595 preserved: dotencode, fncache, generaldelta, revlogv1, sparserevlog, store (no-zstd !)
595 preserved: dotencode, fncache, generaldelta, revlogv1, sparserevlog, store (no-zstd !)
596 preserved: dotencode, fncache, generaldelta, revlog-compression-zstd, revlogv1, sparserevlog, store (zstd !)
596 preserved: dotencode, fncache, generaldelta, revlog-compression-zstd, revlogv1, sparserevlog, store (zstd !)
597 removed: persistent-nodemap
597 removed: persistent-nodemap
598
598
599 processed revlogs:
599 processed revlogs:
600 - all-filelogs
600 - all-filelogs
601 - changelog
601 - changelog
602 - manifest
602 - manifest
603
603
604 beginning upgrade...
604 beginning upgrade...
605 repository locked and read-only
605 repository locked and read-only
606 creating temporary repository to stage upgraded data: $TESTTMP/test-repo/.hg/upgrade.* (glob)
606 creating temporary repository to stage upgraded data: $TESTTMP/test-repo/.hg/upgrade.* (glob)
607 (it is safe to interrupt this process any time before data migration completes)
607 (it is safe to interrupt this process any time before data migration completes)
608 downgrading repository to not use persistent nodemap feature
608 downgrading repository to not use persistent nodemap feature
609 removing temporary repository $TESTTMP/test-repo/.hg/upgrade.* (glob)
609 removing temporary repository $TESTTMP/test-repo/.hg/upgrade.* (glob)
610 $ ls -1 .hg/store/ | egrep '00(changelog|manifest)(\.n|-.*\.nd)'
610 $ ls -1 .hg/store/ | egrep '00(changelog|manifest)(\.n|-.*\.nd)'
611 00changelog-*.nd (glob)
611 00changelog-*.nd (glob)
612 00manifest-*.nd (glob)
612 00manifest-*.nd (glob)
613 undo.backup.00changelog.n
613 undo.backup.00changelog.n
614 undo.backup.00manifest.n
614 undo.backup.00manifest.n
615 $ hg debugnodemap --metadata
615 $ hg debugnodemap --metadata
616
616
617
617
618 upgrading
618 upgrading
619
619
620 $ cat << EOF >> .hg/hgrc
620 $ cat << EOF >> .hg/hgrc
621 > [format]
621 > [format]
622 > use-persistent-nodemap=yes
622 > use-persistent-nodemap=yes
623 > EOF
623 > EOF
624 $ hg debugformat -v
624 $ hg debugformat -v
625 format-variant repo config default
625 format-variant repo config default
626 fncache: yes yes yes
626 fncache: yes yes yes
627 dotencode: yes yes yes
627 dotencode: yes yes yes
628 generaldelta: yes yes yes
628 generaldelta: yes yes yes
629 share-safe: no no no
629 share-safe: no no no
630 sparserevlog: yes yes yes
630 sparserevlog: yes yes yes
631 persistent-nodemap: no yes no
631 persistent-nodemap: no yes no
632 copies-sdc: no no no
632 copies-sdc: no no no
633 revlog-v2: no no no
633 revlog-v2: no no no
634 plain-cl-delta: yes yes yes
634 plain-cl-delta: yes yes yes
635 compression: zlib zlib zlib (no-zstd !)
635 compression: zlib zlib zlib (no-zstd !)
636 compression: zstd zstd zstd (zstd !)
636 compression: zstd zstd zstd (zstd !)
637 compression-level: default default default
637 compression-level: default default default
638 $ hg debugupgraderepo --run --no-backup
638 $ hg debugupgraderepo --run --no-backup
639 upgrade will perform the following actions:
639 upgrade will perform the following actions:
640
640
641 requirements
641 requirements
642 preserved: dotencode, fncache, generaldelta, revlogv1, sparserevlog, store (no-zstd !)
642 preserved: dotencode, fncache, generaldelta, revlogv1, sparserevlog, store (no-zstd !)
643 preserved: dotencode, fncache, generaldelta, revlog-compression-zstd, revlogv1, sparserevlog, store (zstd !)
643 preserved: dotencode, fncache, generaldelta, revlog-compression-zstd, revlogv1, sparserevlog, store (zstd !)
644 added: persistent-nodemap
644 added: persistent-nodemap
645
645
646 persistent-nodemap
646 persistent-nodemap
647 Speedup revision lookup by node id.
647 Speedup revision lookup by node id.
648
648
649 processed revlogs:
649 processed revlogs:
650 - all-filelogs
650 - all-filelogs
651 - changelog
651 - changelog
652 - manifest
652 - manifest
653
653
654 beginning upgrade...
654 beginning upgrade...
655 repository locked and read-only
655 repository locked and read-only
656 creating temporary repository to stage upgraded data: $TESTTMP/test-repo/.hg/upgrade.* (glob)
656 creating temporary repository to stage upgraded data: $TESTTMP/test-repo/.hg/upgrade.* (glob)
657 (it is safe to interrupt this process any time before data migration completes)
657 (it is safe to interrupt this process any time before data migration completes)
658 upgrading repository to use persistent nodemap feature
658 upgrading repository to use persistent nodemap feature
659 removing temporary repository $TESTTMP/test-repo/.hg/upgrade.* (glob)
659 removing temporary repository $TESTTMP/test-repo/.hg/upgrade.* (glob)
660 $ ls -1 .hg/store/ | egrep '00(changelog|manifest)(\.n|-.*\.nd)'
660 $ ls -1 .hg/store/ | egrep '00(changelog|manifest)(\.n|-.*\.nd)'
661 00changelog-*.nd (glob)
661 00changelog-*.nd (glob)
662 00changelog.n
662 00changelog.n
663 00manifest-*.nd (glob)
663 00manifest-*.nd (glob)
664 00manifest.n
664 00manifest.n
665 undo.backup.00changelog.n
665 undo.backup.00changelog.n
666 undo.backup.00manifest.n
666 undo.backup.00manifest.n
667
667
668 $ hg debugnodemap --metadata
668 $ hg debugnodemap --metadata
669 uid: * (glob)
669 uid: * (glob)
670 tip-rev: 5005
670 tip-rev: 5005
671 tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe
671 tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe
672 data-length: 121088
672 data-length: 121088
673 data-unused: 0
673 data-unused: 0
674 data-unused: 0.000%
674 data-unused: 0.000%
675
675
676 Running unrelated upgrade
676 Running unrelated upgrade
677
677
678 $ hg debugupgraderepo --run --no-backup --quiet --optimize re-delta-all
678 $ hg debugupgraderepo --run --no-backup --quiet --optimize re-delta-all
679 upgrade will perform the following actions:
679 upgrade will perform the following actions:
680
680
681 requirements
681 requirements
682 preserved: dotencode, fncache, generaldelta, persistent-nodemap, revlogv1, sparserevlog, store (no-zstd !)
682 preserved: dotencode, fncache, generaldelta, persistent-nodemap, revlogv1, sparserevlog, store (no-zstd !)
683 preserved: dotencode, fncache, generaldelta, persistent-nodemap, revlog-compression-zstd, revlogv1, sparserevlog, store (zstd !)
683 preserved: dotencode, fncache, generaldelta, persistent-nodemap, revlog-compression-zstd, revlogv1, sparserevlog, store (zstd !)
684
684
685 optimisations: re-delta-all
685 optimisations: re-delta-all
686
686
687 processed revlogs:
687 processed revlogs:
688 - all-filelogs
688 - all-filelogs
689 - changelog
689 - changelog
690 - manifest
690 - manifest
691
691
692 $ ls -1 .hg/store/ | egrep '00(changelog|manifest)(\.n|-.*\.nd)'
692 $ ls -1 .hg/store/ | egrep '00(changelog|manifest)(\.n|-.*\.nd)'
693 00changelog-*.nd (glob)
693 00changelog-*.nd (glob)
694 00changelog.n
694 00changelog.n
695 00manifest-*.nd (glob)
695 00manifest-*.nd (glob)
696 00manifest.n
696 00manifest.n
697
697
698 $ hg debugnodemap --metadata
698 $ hg debugnodemap --metadata
699 uid: * (glob)
699 uid: * (glob)
700 tip-rev: 5005
700 tip-rev: 5005
701 tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe
701 tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe
702 data-length: 121088
702 data-length: 121088
703 data-unused: 0
703 data-unused: 0
704 data-unused: 0.000%
704 data-unused: 0.000%
705
705
706 Persistent nodemap and local/streaming clone
706 Persistent nodemap and local/streaming clone
707 ============================================
707 ============================================
708
708
709 $ cd ..
709 $ cd ..
710
710
711 standard clone
711 standard clone
712 --------------
712 --------------
713
713
714 The persistent nodemap should exist after a streaming clone
714 The persistent nodemap should exist after a streaming clone
715
715
716 $ hg clone --pull --quiet -U test-repo standard-clone
716 $ hg clone --pull --quiet -U test-repo standard-clone
717 $ ls -1 standard-clone/.hg/store/ | egrep '00(changelog|manifest)(\.n|-.*\.nd)'
717 $ ls -1 standard-clone/.hg/store/ | egrep '00(changelog|manifest)(\.n|-.*\.nd)'
718 00changelog-*.nd (glob)
718 00changelog-*.nd (glob)
719 00changelog.n
719 00changelog.n
720 00manifest-*.nd (glob)
720 00manifest-*.nd (glob)
721 00manifest.n
721 00manifest.n
722 $ hg -R standard-clone debugnodemap --metadata
722 $ hg -R standard-clone debugnodemap --metadata
723 uid: * (glob)
723 uid: * (glob)
724 tip-rev: 5005
724 tip-rev: 5005
725 tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe
725 tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe
726 data-length: 121088
726 data-length: 121088
727 data-unused: 0
727 data-unused: 0
728 data-unused: 0.000%
728 data-unused: 0.000%
729
729
730
730
731 local clone
731 local clone
732 ------------
732 ------------
733
733
734 The persistent nodemap should exist after a streaming clone
734 The persistent nodemap should exist after a streaming clone
735
735
736 $ hg clone -U test-repo local-clone
736 $ hg clone -U test-repo local-clone
737 $ ls -1 local-clone/.hg/store/ | egrep '00(changelog|manifest)(\.n|-.*\.nd)'
737 $ ls -1 local-clone/.hg/store/ | egrep '00(changelog|manifest)(\.n|-.*\.nd)'
738 00changelog-*.nd (glob)
738 00changelog-*.nd (glob)
739 00changelog.n
739 00changelog.n
740 00manifest-*.nd (glob)
740 00manifest-*.nd (glob)
741 00manifest.n
741 00manifest.n
742 $ hg -R local-clone debugnodemap --metadata
742 $ hg -R local-clone debugnodemap --metadata
743 uid: * (glob)
743 uid: * (glob)
744 tip-rev: 5005
744 tip-rev: 5005
745 tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe
745 tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe
746 data-length: 121088
746 data-length: 121088
747 data-unused: 0
747 data-unused: 0
748 data-unused: 0.000%
748 data-unused: 0.000%
749
749
750 Test various corruption case
750 Test various corruption case
751 ============================
751 ============================
752
752
753 Missing datafile
753 Missing datafile
754 ----------------
754 ----------------
755
755
756 Test behavior with a missing datafile
756 Test behavior with a missing datafile
757
757
758 $ hg clone --quiet --pull test-repo corruption-test-repo
758 $ hg clone --quiet --pull test-repo corruption-test-repo
759 $ ls -1 corruption-test-repo/.hg/store/00changelog*
759 $ ls -1 corruption-test-repo/.hg/store/00changelog*
760 corruption-test-repo/.hg/store/00changelog-*.nd (glob)
760 corruption-test-repo/.hg/store/00changelog-*.nd (glob)
761 corruption-test-repo/.hg/store/00changelog.d
761 corruption-test-repo/.hg/store/00changelog.d
762 corruption-test-repo/.hg/store/00changelog.i
762 corruption-test-repo/.hg/store/00changelog.i
763 corruption-test-repo/.hg/store/00changelog.n
763 corruption-test-repo/.hg/store/00changelog.n
764 $ rm corruption-test-repo/.hg/store/00changelog*.nd
764 $ rm corruption-test-repo/.hg/store/00changelog*.nd
765 $ hg log -R corruption-test-repo -r .
765 $ hg log -R corruption-test-repo -r .
766 changeset: 5005:90d5d3ba2fc4
766 changeset: 5005:90d5d3ba2fc4
767 tag: tip
767 tag: tip
768 user: test
768 user: test
769 date: Thu Jan 01 00:00:00 1970 +0000
769 date: Thu Jan 01 00:00:00 1970 +0000
770 summary: a2
770 summary: a2
771
771
772 $ ls -1 corruption-test-repo/.hg/store/00changelog*
772 $ ls -1 corruption-test-repo/.hg/store/00changelog*
773 corruption-test-repo/.hg/store/00changelog.d
773 corruption-test-repo/.hg/store/00changelog.d
774 corruption-test-repo/.hg/store/00changelog.i
774 corruption-test-repo/.hg/store/00changelog.i
775 corruption-test-repo/.hg/store/00changelog.n
775 corruption-test-repo/.hg/store/00changelog.n
776
776
777 Truncated data file
777 Truncated data file
778 -------------------
778 -------------------
779
779
780 Test behavior with a too short datafile
780 Test behavior with a too short datafile
781
781
782 rebuild the missing data
782 rebuild the missing data
783 $ hg -R corruption-test-repo debugupdatecache
783 $ hg -R corruption-test-repo debugupdatecache
784 $ ls -1 corruption-test-repo/.hg/store/00changelog*
784 $ ls -1 corruption-test-repo/.hg/store/00changelog*
785 corruption-test-repo/.hg/store/00changelog-*.nd (glob)
785 corruption-test-repo/.hg/store/00changelog-*.nd (glob)
786 corruption-test-repo/.hg/store/00changelog.d
786 corruption-test-repo/.hg/store/00changelog.d
787 corruption-test-repo/.hg/store/00changelog.i
787 corruption-test-repo/.hg/store/00changelog.i
788 corruption-test-repo/.hg/store/00changelog.n
788 corruption-test-repo/.hg/store/00changelog.n
789
789
790 truncate the file
790 truncate the file
791
791
792 $ datafilepath=`ls corruption-test-repo/.hg/store/00changelog*.nd`
792 $ datafilepath=`ls corruption-test-repo/.hg/store/00changelog*.nd`
793 $ f -s $datafilepath
793 $ f -s $datafilepath
794 corruption-test-repo/.hg/store/00changelog-*.nd: size=121088 (glob)
794 corruption-test-repo/.hg/store/00changelog-*.nd: size=121088 (glob)
795 $ dd if=$datafilepath bs=1000 count=10 of=$datafilepath-tmp status=none
795 $ dd if=$datafilepath bs=1000 count=10 of=$datafilepath-tmp status=none
796 $ mv $datafilepath-tmp $datafilepath
796 $ mv $datafilepath-tmp $datafilepath
797 $ f -s $datafilepath
797 $ f -s $datafilepath
798 corruption-test-repo/.hg/store/00changelog-*.nd: size=10000 (glob)
798 corruption-test-repo/.hg/store/00changelog-*.nd: size=10000 (glob)
799
799
800 Check that Mercurial reaction to this event
800 Check that Mercurial reaction to this event
801
801
802 $ hg -R corruption-test-repo log -r .
802 $ hg -R corruption-test-repo log -r . --traceback
803 abort: index 00changelog.i is corrupted
803 changeset: 5005:90d5d3ba2fc4
804 [50]
804 tag: tip
805 user: test
806 date: Thu Jan 01 00:00:00 1970 +0000
807 summary: a2
808
805
809
806
810
807 stream clone
811 stream clone
808 ------------
812 ------------
809
813
810 The persistent nodemap should exist after a streaming clone
814 The persistent nodemap should exist after a streaming clone
811
815
812 $ hg clone -U --stream --config ui.ssh="\"$PYTHON\" \"$TESTDIR/dummyssh\"" ssh://user@dummy/test-repo stream-clone --debug | egrep '00(changelog|manifest)'
816 $ hg clone -U --stream --config ui.ssh="\"$PYTHON\" \"$TESTDIR/dummyssh\"" ssh://user@dummy/test-repo stream-clone --debug | egrep '00(changelog|manifest)'
813 adding [s] 00manifest.n (70 bytes)
817 adding [s] 00manifest.n (70 bytes)
814 adding [s] 00manifest.d (452 KB) (no-zstd !)
818 adding [s] 00manifest.d (452 KB) (no-zstd !)
815 adding [s] 00manifest.d (491 KB) (zstd !)
819 adding [s] 00manifest.d (491 KB) (zstd !)
816 adding [s] 00manifest-*.nd (118 KB) (glob)
820 adding [s] 00manifest-*.nd (118 KB) (glob)
817 adding [s] 00changelog.n (70 bytes)
821 adding [s] 00changelog.n (70 bytes)
818 adding [s] 00changelog.d (360 KB) (no-zstd !)
822 adding [s] 00changelog.d (360 KB) (no-zstd !)
819 adding [s] 00changelog.d (368 KB) (zstd !)
823 adding [s] 00changelog.d (368 KB) (zstd !)
820 adding [s] 00changelog-*.nd (118 KB) (glob)
824 adding [s] 00changelog-*.nd (118 KB) (glob)
821 adding [s] 00manifest.i (313 KB)
825 adding [s] 00manifest.i (313 KB)
822 adding [s] 00changelog.i (313 KB)
826 adding [s] 00changelog.i (313 KB)
823 $ ls -1 stream-clone/.hg/store/ | egrep '00(changelog|manifest)(\.n|-.*\.nd)'
827 $ ls -1 stream-clone/.hg/store/ | egrep '00(changelog|manifest)(\.n|-.*\.nd)'
824 00changelog-*.nd (glob)
828 00changelog-*.nd (glob)
825 00changelog.n
829 00changelog.n
826 00manifest-*.nd (glob)
830 00manifest-*.nd (glob)
827 00manifest.n
831 00manifest.n
828 $ hg -R stream-clone debugnodemap --metadata
832 $ hg -R stream-clone debugnodemap --metadata
829 uid: * (glob)
833 uid: * (glob)
830 tip-rev: 5005
834 tip-rev: 5005
831 tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe
835 tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe
832 data-length: 121088
836 data-length: 121088
833 data-unused: 0
837 data-unused: 0
834 data-unused: 0.000%
838 data-unused: 0.000%
General Comments 0
You need to be logged in to leave comments. Login now