comparison mercurial/dirstate.py @ 34332:b36881c68569

dirstate: create new dirstatemap class This is part of a larger refactor to move the dirstate storage logic to a separate class, so it's easier to rewrite the dirstate storage layer without having to rewrite all the algorithms as well. Step one it to create the class, and replace dirstate._map with it. The abstraction bleeds through in a few places where the main dirstate class has to access self._map._map, but those will be cleaned up in future patches. Differential Revision: https://phab.mercurial-scm.org/D752
author Durham Goode <durham@fb.com>
date Tue, 26 Sep 2017 03:56:20 -0700
parents 1246acdad653
children 4ac04418ce66
comparison
equal deleted inserted replaced
34331:531332502568 34332:b36881c68569
55 vfs.unlink(tmpname) 55 vfs.unlink(tmpname)
56 56
57 def nonnormalentries(dmap): 57 def nonnormalentries(dmap):
58 '''Compute the nonnormal dirstate entries from the dmap''' 58 '''Compute the nonnormal dirstate entries from the dmap'''
59 try: 59 try:
60 return parsers.nonnormalotherparententries(dmap) 60 return parsers.nonnormalotherparententries(dmap._map)
61 except AttributeError: 61 except AttributeError:
62 nonnorm = set() 62 nonnorm = set()
63 otherparent = set() 63 otherparent = set()
64 for fname, e in dmap.iteritems(): 64 for fname, e in dmap.iteritems():
65 if e[0] != 'n' or e[3] == -1: 65 if e[0] != 'n' or e[3] == -1:
177 try: 177 try:
178 makefilefoldmap = parsers.make_file_foldmap 178 makefilefoldmap = parsers.make_file_foldmap
179 except AttributeError: 179 except AttributeError:
180 pass 180 pass
181 else: 181 else:
182 return makefilefoldmap(self._map, util.normcasespec, 182 return makefilefoldmap(self._map._map, util.normcasespec,
183 util.normcasefallback) 183 util.normcasefallback)
184 184
185 f = {} 185 f = {}
186 normcase = util.normcase 186 normcase = util.normcase
187 for name, s in self._map.iteritems(): 187 for name, s in self._map.iteritems():
236 raise 236 raise
237 return [nullid, nullid] 237 return [nullid, nullid]
238 238
239 @propertycache 239 @propertycache
240 def _dirs(self): 240 def _dirs(self):
241 return util.dirs(self._map, 'r') 241 return util.dirs(self._map._map, 'r')
242 242
243 def dirs(self): 243 def dirs(self):
244 return self._dirs 244 return self._dirs
245 245
246 @rootcache('.hgignore') 246 @rootcache('.hgignore')
442 'changed parallelly')) 442 'changed parallelly'))
443 self._pendingmode = mode 443 self._pendingmode = mode
444 return fp 444 return fp
445 445
446 def _read(self): 446 def _read(self):
447 self._map = {} 447 self._map = dirstatemap()
448
448 self._copymap = {} 449 self._copymap = {}
449 # ignore HG_PENDING because identity is used only for writing 450 # ignore HG_PENDING because identity is used only for writing
450 self._identity = util.filestat.frompath( 451 self._identity = util.filestat.frompath(
451 self._opener.join(self._filename)) 452 self._opener.join(self._filename))
452 try: 453 try:
471 # size. 472 # size.
472 # 473 #
473 # This heuristic is imperfect in many ways, so in a future dirstate 474 # This heuristic is imperfect in many ways, so in a future dirstate
474 # format update it makes sense to just record the number of entries 475 # format update it makes sense to just record the number of entries
475 # on write. 476 # on write.
476 self._map = parsers.dict_new_presized(len(st) / 71) 477 self._map._map = parsers.dict_new_presized(len(st) / 71)
477 478
478 # Python's garbage collector triggers a GC each time a certain number 479 # Python's garbage collector triggers a GC each time a certain number
479 # of container objects (the number being defined by 480 # of container objects (the number being defined by
480 # gc.get_threshold()) are allocated. parse_dirstate creates a tuple 481 # gc.get_threshold()) are allocated. parse_dirstate creates a tuple
481 # for each file in the dirstate. The C version then immediately marks 482 # for each file in the dirstate. The C version then immediately marks
486 # this can get very expensive. As a workaround, disable GC while 487 # this can get very expensive. As a workaround, disable GC while
487 # parsing the dirstate. 488 # parsing the dirstate.
488 # 489 #
489 # (we cannot decorate the function directly since it is in a C module) 490 # (we cannot decorate the function directly since it is in a C module)
490 parse_dirstate = util.nogc(parsers.parse_dirstate) 491 parse_dirstate = util.nogc(parsers.parse_dirstate)
491 p = parse_dirstate(self._map, self._copymap, st) 492 p = parse_dirstate(self._map._map, self._copymap, st)
492 if not self._dirtypl: 493 if not self._dirtypl:
493 self._pl = p 494 self._pl = p
494 495
495 def invalidate(self): 496 def invalidate(self):
496 '''Causes the next access to reread the dirstate. 497 '''Causes the next access to reread the dirstate.
729 if self._checkcase: 730 if self._checkcase:
730 return self._normalize(path, isknown, ignoremissing) 731 return self._normalize(path, isknown, ignoremissing)
731 return path 732 return path
732 733
733 def clear(self): 734 def clear(self):
734 self._map = {} 735 self._map = dirstatemap()
735 self._nonnormalset = set() 736 self._nonnormalset = set()
736 self._otherparentset = set() 737 self._otherparentset = set()
737 if "_dirs" in self.__dict__: 738 if "_dirs" in self.__dict__:
738 delattr(self, "_dirs") 739 delattr(self, "_dirs")
739 self._copymap = {} 740 self._copymap = {}
838 end = start + delaywrite 839 end = start + delaywrite
839 time.sleep(end - clock) 840 time.sleep(end - clock)
840 now = end # trust our estimate that the end is near now 841 now = end # trust our estimate that the end is near now
841 break 842 break
842 843
843 st.write(parsers.pack_dirstate(self._map, self._copymap, self._pl, now)) 844 st.write(parsers.pack_dirstate(self._map._map, self._copymap, self._pl,
845 now))
844 self._nonnormalset, self._otherparentset = nonnormalentries(self._map) 846 self._nonnormalset, self._otherparentset = nonnormalentries(self._map)
845 st.close() 847 st.close()
846 self._lastnormaltime = 0 848 self._lastnormaltime = 0
847 self._dirty = self._dirtypl = False 849 self._dirty = self._dirtypl = False
848 850
977 except OSError as inst: # nf not found on disk - it is dirstate only 979 except OSError as inst: # nf not found on disk - it is dirstate only
978 if nf in dmap: # does it exactly match a missing file? 980 if nf in dmap: # does it exactly match a missing file?
979 results[nf] = None 981 results[nf] = None
980 else: # does it match a missing directory? 982 else: # does it match a missing directory?
981 if alldirs is None: 983 if alldirs is None:
982 alldirs = util.dirs(dmap) 984 alldirs = util.dirs(dmap._map)
983 if nf in alldirs: 985 if nf in alldirs:
984 if matchedir: 986 if matchedir:
985 matchedir(nf) 987 matchedir(nf)
986 notfoundadd(nf) 988 notfoundadd(nf)
987 else: 989 else:
1337 self._opener.rename(backupname, filename, checkambig=True) 1339 self._opener.rename(backupname, filename, checkambig=True)
1338 1340
1339 def clearbackup(self, tr, backupname): 1341 def clearbackup(self, tr, backupname):
1340 '''Clear backup file''' 1342 '''Clear backup file'''
1341 self._opener.unlink(backupname) 1343 self._opener.unlink(backupname)
1344
1345 class dirstatemap(object):
1346 def __init__(self):
1347 self._map = {}
1348
1349 def iteritems(self):
1350 return self._map.iteritems()
1351
1352 def __iter__(self):
1353 return iter(self._map)
1354
1355 def get(self, key, default=None):
1356 return self._map.get(key, default)
1357
1358 def __contains__(self, key):
1359 return key in self._map
1360
1361 def __setitem__(self, key, value):
1362 self._map[key] = value
1363
1364 def __getitem__(self, key):
1365 return self._map[key]
1366
1367 def __delitem__(self, key):
1368 del self._map[key]
1369
1370 def keys(self):
1371 return self._map.keys()