Sergei Golubchik <serg@askmonty.org> writes:
Right. In fact, I think perhaps I am doing it in a single statement already:
mysql_reset_thd_for_next_command(thd, 0); open_and_lock_tables(thd, &tlist, FALSE, 0); table->file->ha_write_row(table->record[0]); table->file->ha_rnd_pos_by_record(table->record[0])); table->file->ha_delete_row(table->record[0]); ha_commit_trans(thd, FALSE); close_thread_tables(thd); if (!in_transaction) ha_commit_trans(thd, TRUE);
Yes, that is all there is to it. A transaction starts automatically on the first "transaction-initiating statement" (according to the standard).
You don't need to set autocommit. If you do - you won't need the second ha_commit_trans(thd, TRUE). You current code, as far as I understand, will work correctly, whether autocommit is on or off.
Aha, I see. Ok, thanks a lot for clarifying that!
In that case, though, your changes may be part of the already running transaction - do you want that?
Indeed, the whole point of this is to be part of the running transaction. So that slave state becomes crash-safe, unlike now where we first commit and then write to the file relay-log.info - and a crash in the middle makes us inconsistent, etc. So the intention with record_gtid() is to add an extra statement to the transaction being replicated - which updates the slave state. If we crash, we either recover or rollback the whole transaction, which includes both the replicated changes and the update of slave status. So we are crash safe (assuming transactional support in all involved engines, of course).
Oh, hmm, a problem. If you're in the middle of the already running transaction, you probably shouldn't commit it after your changes, but wait till the end - arbitrary adding commits in the middle of a transaction is no good.
So this is what I try to address with this code:
ha_commit_trans(thd, FALSE); close_thread_tables(thd); if (!in_transaction) ha_commit_trans(thd, TRUE);
My intension was - first commit the "statement" (all=FALSE). Then, if I am part of a larger transaction, do not commit the transaction, postpone that to later. But if not part of a transaction, I have to commit it here. But maybe I misunderstood? I thought a call of ha_commit_trans with all=FALSE was done/needed after every statement. Suppose we run this on the master: UPDATE t1 SET b=1 WHERE a=1; This gets written to binlog as two statement events and one XID event: Statement: "BEGIN" Statement: "UPDATE t1 SET b=1 WHERE a=1" Xid-event (meaning commit) So my thought was that the UPDATE does a ha_commit_trans(thd, FALSE). In the Xid-event I inject a call to record_gtid, which updates the mysql.rpl_slave_state table, and I therefore also need ha_commit_trans(thd, FALSE). Then finally Xid-event does ha_commit_trans(thd, TRUE). But maybe this is incorrect? I'm not sure ... maybe ha_commit_trans() is only called at the end of the transaction? - Kristian.