[PATCH 3 of 6] dirstate: read from `.pending` file under HG_PENDING mode
FUJIWARA Katsunori
foozy at lares.dti.ne.jp
Tue May 19 11:42:03 CDT 2015
# HG changeset patch
# User FUJIWARA Katsunori <foozy at lares.dti.ne.jp>
# Date 1432051569 -32400
# Wed May 20 01:06:09 2015 +0900
# Node ID e830ef506b9aaa01c5406d100a385961c4c0dff0
# Parent 2d2eff9ee053025e8e0267b8d6c6d07326f607ee
dirstate: read from `.pending` file under HG_PENDING mode
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
For review-ability, this patch focuses only on reading `.pending` file
in. Then, `dirstate.write()` can write changes out even under
HG_PENDING mode. But it is still safe enough, because there is no code
path writing `.pending` file out yet (= `_pendingmode` never be True).
`_trypending()` is defined as a normal function to factor similar code
path (in bookmarks and phases) out in the future easily.
diff --git a/mercurial/dirstate.py b/mercurial/dirstate.py
--- a/mercurial/dirstate.py
+++ b/mercurial/dirstate.py
@@ -26,6 +26,22 @@
def join(self, obj, fname):
return obj._join(fname)
+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, inst:
+ if inst.errno != errno.ENOENT:
+ raise
+ return (vfs(filename), False)
+
class dirstate(object):
def __init__(self, opener, ui, root, validate):
@@ -49,6 +65,9 @@
self._parentwriters = 0
self._filename = 'dirstate'
+ # 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,
@@ -122,7 +141,7 @@
@propertycache
def _pl(self):
try:
- fp = self._opener(self._filename)
+ fp = self._opendirstatefile()
st = fp.read(40)
fp.close()
l = len(st)
@@ -316,11 +335,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 util.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:
More information about the Mercurial-devel
mailing list