comparison mercurial/dirstatemap.py @ 48223:b4f83c9e7905

dirstate-v2: Add support when Rust is not enabled This wires into `dirstatemap` the parser and serializer added in previous changesets. The memory representation is still the same, with a flat `dict` for `DirstateItem`s and another one for copy sources. Serialization always creates a new dirstate-v2 data file and does not support (when Rust is not enabled) appending to an existing one, since we don’t keep track of which tree nodes are new or modified. Instead the tree is reconstructed during serialization. Differential Revision: https://phab.mercurial-scm.org/D11520
author Simon Sapin <simon.sapin@octobus.net>
date Fri, 16 Jul 2021 18:42:20 +0200
parents a32a96079e2d
children 269ff8978086
comparison
equal deleted inserted replaced
48222:7e78c72ee3ea 48223:b4f83c9e7905
330 330
331 - `dirfoldmap` is a dict mapping normalized directory names to the 331 - `dirfoldmap` is a dict mapping normalized directory names to the
332 denormalized form that they appear as in the dirstate. 332 denormalized form that they appear as in the dirstate.
333 """ 333 """
334 334
335 def __init__(self, ui, opener, root, nodeconstants, use_dirstate_v2):
336 super(dirstatemap, self).__init__(
337 ui, opener, root, nodeconstants, use_dirstate_v2
338 )
339 if self._use_dirstate_v2:
340 msg = "Dirstate V2 not supportedi"
341 msg += "(should have detected unsupported requirement)"
342 raise error.ProgrammingError(msg)
343
344 ### Core data storage and access 335 ### Core data storage and access
345 336
346 @propertycache 337 @propertycache
347 def _map(self): 338 def _map(self):
348 self._map = {} 339 self._map = {}
404 # ignore HG_PENDING because identity is used only for writing 395 # ignore HG_PENDING because identity is used only for writing
405 self.identity = util.filestat.frompath( 396 self.identity = util.filestat.frompath(
406 self._opener.join(self._filename) 397 self._opener.join(self._filename)
407 ) 398 )
408 399
409 try: 400 if self._use_dirstate_v2:
410 fp = self._opendirstatefile() 401 if not self.docket.uuid:
411 try: 402 return
412 st = fp.read() 403 st = self._opener.read(self.docket.data_filename())
413 finally: 404 else:
414 fp.close() 405 st = self._readdirstatefile()
415 except IOError as err: 406
416 if err.errno != errno.ENOENT:
417 raise
418 return
419 if not st: 407 if not st:
420 return 408 return
421 409
410 # TODO: adjust this estimate for dirstate-v2
422 if util.safehasattr(parsers, b'dict_new_presized'): 411 if util.safehasattr(parsers, b'dict_new_presized'):
423 # Make an estimate of the number of files in the dirstate based on 412 # Make an estimate of the number of files in the dirstate based on
424 # its size. This trades wasting some memory for avoiding costly 413 # its size. This trades wasting some memory for avoiding costly
425 # resizes. Each entry have a prefix of 17 bytes followed by one or 414 # resizes. Each entry have a prefix of 17 bytes followed by one or
426 # two path names. Studies on various large-scale real-world repositories 415 # two path names. Studies on various large-scale real-world repositories
438 # Depending on when in the process's lifetime the dirstate is parsed, 427 # Depending on when in the process's lifetime the dirstate is parsed,
439 # this can get very expensive. As a workaround, disable GC while 428 # this can get very expensive. As a workaround, disable GC while
440 # parsing the dirstate. 429 # parsing the dirstate.
441 # 430 #
442 # (we cannot decorate the function directly since it is in a C module) 431 # (we cannot decorate the function directly since it is in a C module)
443 parse_dirstate = util.nogc(parsers.parse_dirstate) 432 if self._use_dirstate_v2:
444 p = parse_dirstate(self._map, self.copymap, st) 433 p = self.docket.parents
434 meta = self.docket.tree_metadata
435 parse_dirstate = util.nogc(v2.parse_dirstate)
436 parse_dirstate(self._map, self.copymap, st, meta)
437 else:
438 parse_dirstate = util.nogc(parsers.parse_dirstate)
439 p = parse_dirstate(self._map, self.copymap, st)
445 if not self._dirtyparents: 440 if not self._dirtyparents:
446 self.setparents(*p) 441 self.setparents(*p)
447 442
448 # Avoid excess attribute lookups by fast pathing certain checks 443 # Avoid excess attribute lookups by fast pathing certain checks
449 self.__contains__ = self._map.__contains__ 444 self.__contains__ = self._map.__contains__
450 self.__getitem__ = self._map.__getitem__ 445 self.__getitem__ = self._map.__getitem__
451 self.get = self._map.get 446 self.get = self._map.get
452 447
453 def write(self, _tr, st, now): 448 def write(self, tr, st, now):
454 d = parsers.pack_dirstate(self._map, self.copymap, self.parents(), now) 449 if self._use_dirstate_v2:
455 st.write(d) 450 packed, meta = v2.pack_dirstate(self._map, self.copymap, now)
456 st.close() 451 self.write_v2_no_append(tr, st, meta, packed)
452 else:
453 packed = parsers.pack_dirstate(
454 self._map, self.copymap, self.parents(), now
455 )
456 st.write(packed)
457 st.close()
457 self._dirtyparents = False 458 self._dirtyparents = False
458 459
459 @propertycache 460 @propertycache
460 def identity(self): 461 def identity(self):
461 self._map 462 self._map