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