# HG changeset patch # User FUJIWARA Katsunori # Date 1444758557 -32400 # Node ID 79d86ab65c9def3fdd65ec972bc5fa89688a19ff # Parent 09bb1ee7e73e057179964ae51c9217da4dc76e61 dirstate: read from pending file under HG_PENDING mode if it exists True/False value of '_pendingmode' means whether 'dirstate.pending' is used to initialize own '_map' and so on. When it is None, neither 'dirstate' nor 'dirstate.pending' is read in yet. This is used to keep consistent view between '_pl()' and '_read()'. Once '_pendingmode' is determined by reading one of 'dirstate' or 'dirstate.pending' in, '_pendingmode' is kept even if 'invalidate()' is invoked. This should be reasonable, because: - effective 'invalidate()' invocation should occur only in wlock scope, and - wlock can't be gotten under HG_PENDING mode '_trypending()' is defined as a normal function to factor similar code path (in bookmarks and phases) out in the future easily. diff -r 09bb1ee7e73e -r 79d86ab65c9d mercurial/dirstate.py --- a/mercurial/dirstate.py Wed Oct 14 02:49:17 2015 +0900 +++ b/mercurial/dirstate.py Wed Oct 14 02:49:17 2015 +0900 @@ -36,6 +36,22 @@ os.close(tmpfd) vfs.unlink(tmpname) +def _trypending(root, vfs, filename): + '''Open file to be read according to HG_PENDING environment variable + + This opens '.pending' of specified 'filename' only when HG_PENDING + is equal to 'root'. + + This returns '(fp, is_pending_opened)' tuple. + ''' + if root == os.environ.get('HG_PENDING'): + try: + return (vfs('%s.pending' % filename), True) + except IOError as inst: + if inst.errno != errno.ENOENT: + raise + return (vfs(filename), False) + class dirstate(object): def __init__(self, opener, ui, root, validate): @@ -64,6 +80,9 @@ self._filename = 'dirstate' self._pendingfilename = '%s.pending' % self._filename + # for consitent view between _pl() and _read() invocations + self._pendingmode = None + def beginparentchange(self): '''Marks the beginning of a set of changes that involve changing the dirstate parents. If there is an exception during this time, @@ -137,7 +156,7 @@ @propertycache def _pl(self): try: - fp = self._opener(self._filename) + fp = self._opendirstatefile() st = fp.read(40) fp.close() l = len(st) @@ -342,11 +361,20 @@ f.discard() raise + def _opendirstatefile(self): + fp, mode = _trypending(self._root, self._opener, self._filename) + if self._pendingmode is not None and self._pendingmode != mode: + fp.close() + raise error.Abort(_('working directory state may be ' + 'changed parallelly')) + self._pendingmode = mode + return fp + def _read(self): self._map = {} self._copymap = {} try: - fp = self._opener.open(self._filename) + fp = self._opendirstatefile() try: st = fp.read() finally: