Submitter | Katsunori FUJIWARA |
---|---|
Date | May 2, 2015, 3:59 p.m. |
Message ID | <ea0832f5425148072ca0.1430582377@feefifofum> |
Download | mbox | patch |
Permalink | /patch/8853/ |
State | Superseded |
Headers | show |
Comments
On Sun, 03 May 2015 00:59:37 +0900, FUJIWARA Katsunori wrote: > # HG changeset patch > # User FUJIWARA Katsunori <foozy@lares.dti.ne.jp> > # Date 1430582197 -32400 > # Sun May 03 00:56:37 2015 +0900 > # Node ID ea0832f5425148072ca048997fb322615e90e805 > # Parent fac0b879377d014c4081940040d092469635447a > localrepo: use changelog.rev instead of self.__contains__ > > Before this patch, releasing store lock implies actions below, when > transaction is aborted: > > 1. "commithook()" scheduled in "localrepository.commit()" is invoked > 2. "changectx.__init__()" is invoked via "self.__contains__()" > 3. specified ID is examined against "repo.dirstate.p1()" > 4. validation function is invoked in "dirstate.p1()" > > In subsequent patches, "dirstate.invalidate()" invocations for > discarding changes are replaced with "dirstateguard", but discarding > changes by "dirstateguard" is executed after releasing sotre lock: > resouces are acquired in "wlock => dirstateguard => store lock" order, > and are released in reversed order. > > This may cause that "dirstate.p1()" still refers the changeset to be > rollback-ed at (4) above: pushing multiple patches by "hg qpush" is > typical case. > > At releasing store lock, such changesets are: > > - not contained in "repo.changelog", if it is reloaded from > ".hg/00changelog.i" already truncated by "transaction.abort()" > > - still contained in it, otherwise > (this "dirty read" problem is discussed in "Transaction Plan" > http://mercurial.selenic.com/wiki/TransactionPlan) > > Validation function shows "unknown working parent" warning in the > former case, but reloading "repo.changelog" depends on the timestamp > of ".hg/00changelog.i". It prevents tests from running stably. > > In the case of scheduled "commithook()", it just wants to examine > whether "node ID" of committed changeset is still valid or not. Other > examinations implied in "changectx.__init__()" are meaningless. > > To avoid showing "unknown working parent" warning irregularly, this > patch uses "changelog.rev()" instead of "node in self" to examine > existence of committed changeset. > > diff --git a/mercurial/localrepo.py b/mercurial/localrepo.py > --- a/mercurial/localrepo.py > +++ b/mercurial/localrepo.py > @@ -1521,9 +1521,12 @@ > def commithook(node=hex(ret), parent1=hookp1, parent2=hookp2): > # hack for command that use a temporary commit (eg: histedit) > # temporary commit got stripped before hook release > - if node in self: > + try: > + self.changelog.rev(ret) # check existence > self.hook("commit", node=node, parent1=parent1, > parent2=parent2) > + except error.LookupError: > + pass # changeset is already rollback-ed Nit pick: perhaps changelog.hasnode() can be used here.
At Sun, 3 May 2015 19:17:40 +0900, Yuya Nishihara wrote: > > On Sun, 03 May 2015 00:59:37 +0900, FUJIWARA Katsunori wrote: > > # HG changeset patch > > # User FUJIWARA Katsunori <foozy@lares.dti.ne.jp> > > # Date 1430582197 -32400 > > # Sun May 03 00:56:37 2015 +0900 > > # Node ID ea0832f5425148072ca048997fb322615e90e805 > > # Parent fac0b879377d014c4081940040d092469635447a > > localrepo: use changelog.rev instead of self.__contains__ > > > > Before this patch, releasing store lock implies actions below, when > > transaction is aborted: > > > > 1. "commithook()" scheduled in "localrepository.commit()" is invoked > > 2. "changectx.__init__()" is invoked via "self.__contains__()" > > 3. specified ID is examined against "repo.dirstate.p1()" > > 4. validation function is invoked in "dirstate.p1()" > > > > In subsequent patches, "dirstate.invalidate()" invocations for > > discarding changes are replaced with "dirstateguard", but discarding > > changes by "dirstateguard" is executed after releasing sotre lock: > > resouces are acquired in "wlock => dirstateguard => store lock" order, > > and are released in reversed order. > > > > This may cause that "dirstate.p1()" still refers the changeset to be > > rollback-ed at (4) above: pushing multiple patches by "hg qpush" is > > typical case. > > > > At releasing store lock, such changesets are: > > > > - not contained in "repo.changelog", if it is reloaded from > > ".hg/00changelog.i" already truncated by "transaction.abort()" > > > > - still contained in it, otherwise > > (this "dirty read" problem is discussed in "Transaction Plan" > > http://mercurial.selenic.com/wiki/TransactionPlan) > > > > Validation function shows "unknown working parent" warning in the > > former case, but reloading "repo.changelog" depends on the timestamp > > of ".hg/00changelog.i". It prevents tests from running stably. > > > > In the case of scheduled "commithook()", it just wants to examine > > whether "node ID" of committed changeset is still valid or not. Other > > examinations implied in "changectx.__init__()" are meaningless. > > > > To avoid showing "unknown working parent" warning irregularly, this > > patch uses "changelog.rev()" instead of "node in self" to examine > > existence of committed changeset. > > > > diff --git a/mercurial/localrepo.py b/mercurial/localrepo.py > > --- a/mercurial/localrepo.py > > +++ b/mercurial/localrepo.py > > @@ -1521,9 +1521,12 @@ > > def commithook(node=hex(ret), parent1=hookp1, parent2=hookp2): > > # hack for command that use a temporary commit (eg: histedit) > > # temporary commit got stripped before hook release > > - if node in self: > > + try: > > + self.changelog.rev(ret) # check existence > > self.hook("commit", node=node, parent1=parent1, > > parent2=parent2) > > + except error.LookupError: > > + pass # changeset is already rollback-ed > > Nit pick: perhaps changelog.hasnode() can be used here. I'll use "changelog.hasnode()" in revised series, thank you. ---------------------------------------------------------------------- [FUJIWARA Katsunori] foozy@lares.dti.ne.jp
Patch
diff --git a/mercurial/localrepo.py b/mercurial/localrepo.py --- a/mercurial/localrepo.py +++ b/mercurial/localrepo.py @@ -1521,9 +1521,12 @@ def commithook(node=hex(ret), parent1=hookp1, parent2=hookp2): # hack for command that use a temporary commit (eg: histedit) # temporary commit got stripped before hook release - if node in self: + try: + self.changelog.rev(ret) # check existence self.hook("commit", node=node, parent1=parent1, parent2=parent2) + except error.LookupError: + pass # changeset is already rollback-ed self._afterlock(commithook) return ret diff --git a/tests/test-mq-qpush-fail.t b/tests/test-mq-qpush-fail.t --- a/tests/test-mq-qpush-fail.t +++ b/tests/test-mq-qpush-fail.t @@ -34,7 +34,23 @@ $ $PYTHON -c 'print "\xe9"' > message $ cat .hg/patches/bad-patch >> message $ mv message .hg/patches/bad-patch - $ hg qpush -a && echo 'qpush succeeded?!' + $ cat > $TESTTMP/wrapplayback.py <<EOF + > import os + > from mercurial import extensions, transaction + > def wrapplayback(orig, + > journal, report, opener, vfsmap, entries, backupentries, + > unlink=True): + > orig(journal, report, opener, vfsmap, entries, backupentries, unlink) + > # Touching files truncated at "transaction.abort" causes + > # forcible re-loading invalidated filecache properties + > # (including repo.changelog) + > for f, o, _ignore in entries: + > if o or not unlink: + > os.utime(opener.join(f), (0.0, 0.0)) + > def extsetup(ui): + > extensions.wrapfunction(transaction, '_playback', wrapplayback) + > EOF + $ hg qpush -a --config extensions.wrapplayback=$TESTTMP/wrapplayback.py && echo 'qpush succeeded?!' applying patch1 applying patch2 applying bad-patch