Hi!
On Jun 19, Paul McCullagh wrote:
> Hi Sergei and Wei,
>
> >>Later, in ha_commit_one_phase(), the code never reverse binlog
> >>changes if the transaction failed committing. How do we handle the
> >>failure here?
> >
> >We don't. Two-phase commit protocol works in the assumption that
> >commit phase cannot fail if prepare phase succeeded. That is by
> >returning a success code from prepare(), storage engine promises to
> >be able to commit - if there could've been an error, it must've been
> >returned from prepare(). And it someone breaks the protocol,
> >succeeding in prepare, but failing in commit - you'll have
> >inconsistent data. Commit cannot be undone, by definition.
> >
> This is a good question and something that I have been wondering about.
>
> Although it is very unlikely, this situation can actually occur.
>
> You see, even if an engine returns OK on the prepare(), it probably
> still relies on the fact that at least one disk write operation must
> work in order to do the commit().
You're right. Even better example - a federated storage engine (not
necessarily _our_ federated, but conceptually similar, with remote
storage). It may experience network failure anytime, also between
prepare and commit.
> What this means is that the engine can actually not guarantee that the
> commit() will work. It can only guarantee that if it does not work,
> then the commit will be completed on recovery.
XA standard allows both. xa_commit() has many dirrefent return values, I
quote two most relevant here:
[XA_RETRY]
The resource manager is not able to commit the transaction branch at
this time. This value may be returned when a blocking condition
exists and TMNOWAIT was set. Note, however, that this value may also
be returned even when TMNOWAIT is not set (for example, if the
necessary stable storage is currently unavailable). This value cannot
be returned if TMONEPHASE is set in flags . All resources held on
behalf of xid remain in a prepared state until commitment is
possible. The transaction manager should reissue xa_commit() at a
later time.
[XAER_RMERR]
An error occurred in committing the work performed on behalf of the
transaction branch and the branch's work has been rolled back. Note
that returning this error signals a catastrophic event to a
transaction manager since other resource managers may successfully
commit their work on behalf of this branch. This error should be
returned only when a resource manager concludes that it can never
commit the branch and that it cannot hold the branch's resources in a
prepared state. Otherwise, [XA_RETRY] should be returned.
> So my question is: since recovery is only done on startup, if a
> commit() call fails, doesn't this mean that the data server should
> actually shutdown immediately and automatically restart (or some
> equivalent operation)?
According to the XA standard - no, it only means MySQL should keep
retrying the commit as long as it is getting XA_RETRY back.
But I don't think it is a practical solution. There must be some
timeouts or whatever limits to prevent MySQL from retrying forever.
Also, XA standard does not specify when recovery happens. And if I'd be
given a choice whether to crash MySQL when commit fails, or add a support
for recovery not only at startup - I'd rather fix recovery :)
Anyway, XA_RETRY is not supported at the moment. Though it'll be
straightforward to add, when it'll be necessary.
Regards,
Sergei
--
__ ___ ___ ____ __
/ |/ /_ __/ __/ __ \/ / Sergei Golubchik <serg@stripped>
/ /|_/ / // /\ \/ /_/ / /__ MySQL AB, Senior Software Developer
/_/ /_/\_, /___/\___\_\___/ Kerpen, Germany
<___/ www.mysql.com