Merge lp:~laurynas-biveinis/percona-server/bug1012715-5.1 into lp:percona-server/5.1

Proposed by Laurynas Biveinis
Status: Superseded
Proposed branch: lp:~laurynas-biveinis/percona-server/bug1012715-5.1
Merge into: lp:percona-server/5.1
Diff against target: 878 lines (+527/-170)
7 files modified
Percona-Server/mysql-test/suite/rpl/r/rpl_percona_crash_resistant_rpl.result (+54/-0)
Percona-Server/mysql-test/suite/rpl/t/rpl_percona_crash_resistant_rpl-slave.opt (+1/-0)
Percona-Server/mysql-test/suite/rpl/t/rpl_percona_crash_resistant_rpl.test (+117/-0)
Percona-Server/storage/innodb_plugin/handler/ha_innodb.cc (+225/-113)
Percona-Server/storage/innodb_plugin/include/trx0sys.h (+15/-1)
Percona-Server/storage/innodb_plugin/trx/trx0sys.c (+96/-54)
Percona-Server/storage/innodb_plugin/trx/trx0trx.c (+19/-2)
To merge this branch: bzr merge lp:~laurynas-biveinis/percona-server/bug1012715-5.1
Reviewer Review Type Date Requested Status
Alexey Kopytov (community) Needs Fixing
Percona core Pending
Laurynas Biveinis Pending
Review via email: mp+115485@code.launchpad.net

This proposal supersedes a proposal from 2012-06-29.

This proposal has been superseded by a proposal from 2012-08-17.

Description of the change

Issue 22478.

Fix bug 1012715. See the revision commit message for the changes.

Jenkins: http://jenkins.percona.com/job/percona-server-5.1-param/345/

Some of the refactoring might seem excessive for this bug fix. However, I introduced the new functions in order to avoid copy-pasting the same code, and new file-scope log variables in ha_innodb.cc to preserve my sanity.

The functional difference from the previous MP is that both transaction commit and rollback are tested.

To post a comment you must log in.
Revision history for this message
Laurynas Biveinis (laurynas-biveinis) wrote : Posted in a previous version of this proposal

Found one issue myself.

The testcase has one sync bug: lines 88--91 do not sync slave with master first, thus might result in slave shutdown while slave SQL thread is still executing.

review: Needs Fixing
Revision history for this message
Alexey Kopytov (akopytov) wrote : Posted in a previous version of this proposal

Laurynas,

The assumption this patch is based on looks wrong to me, i.e.:

> + XA COMMIT. In contrast to that, the slave position is an
> + actual part of the changes made by this transaction and thus
> + must be updated in the XA PREPARE stage. */

A prepared transaction may either be committed or rolled back (see xarecover_handlerton()) depending on whether the corresponding record made it to the binary log (and if the binary log is used at all).

The correct solution would be to update slave coordinates when commiting the corresponding XA transaction on recovery, rather than moving the code storing slave coordinates to persistent storage from COMMIT to PREPARE stage. The problem is that slave coordinates are not available at the point, i.e. when committing prepared transactions on recovery.

I wonder if we can fix this by introducing another set of slave coordinates in the trx header. The we can only update those fields on PREPARE, and update the regular TRX_SYS_MYSQL_RELAY_LOG_INFO fields on COMMIT. On recovery, we could copy the "prepare" fields to "committed" ones and overwrite the relay log info file, *if* the PREPAREd transaction is being committed, e.g. in innobase_commit_by_xid(). What do you think?

Minor comments on the test case:
- do we really need the "rpl_" prefix in rpl_percona_crash_resistant_rpl.*?
- please use

SET GLOBAL debug="+d,keyword"

instead of

SET GLOBAL debug="d,keyword"

The latter breaks ./mtr --debug.

review: Needs Fixing
Revision history for this message
Laurynas Biveinis (laurynas-biveinis) wrote : Posted in a previous version of this proposal
Download full text (3.3 KiB)

Alexey -

Thanks. Could you please expand on your comment on why you think this assumption is wrong -

> The assumption this patch is based on looks wrong to me, i.e.:
>
> > + XA COMMIT. In contrast to that, the slave position is an
> > + actual part of the changes made by this transaction and thus
> > + must be updated in the XA PREPARE stage. */

because the following explanation matches my assumptions precisely:

> A prepared transaction may either be committed or rolled back (see
> xarecover_handlerton()) depending on whether the corresponding record made it
> to the binary log (and if the binary log is used at all).

Namely, why is the assumption "slave position update is a part of actual transaction changes" wrong in the light of this? If a prepared transaction is rolled back, the old slave position is restored from an undo seg. If it is 2pc-committed, the new slave position becomes permanent.

Maybe you view this fix as incomplete or working by chance because of the following (which is the actual action sequence that happens in this bug): on crash recovery the relay status log overwrite will happen before the XA rollback, thus the slave position will point to as if the transaction was fully committed. Then the transaction will be rolled back, (which would require overwriting relay status log with the old position) and replayed from the binlog, (which would require overwriting the relay status log position again, but binlog does not have the required info for that). This results in correct positions, although with a shortcut taken. The assumption here that all replicated InnoDB XA prepared transactions will be eventually committed. It is not perfect but IMHO "slave position is a part of transaction itself" is a step to the right direction.

> The correct solution would be to update slave coordinates when commiting the
> corresponding XA transaction on recovery, rather than moving the code storing
> slave coordinates to persistent storage from COMMIT to PREPARE stage. The
> problem is that slave coordinates are not available at the point, i.e. when
> committing prepared transactions on recovery.

Fully agreed modulus that ATM I think it's "one of the possible correct solutions."

> I wonder if we can fix this by introducing another set of slave coordinates in
> the trx header. The we can only update those fields on PREPARE, and update the
> regular TRX_SYS_MYSQL_RELAY_LOG_INFO fields on COMMIT. On recovery, we could
> copy the "prepare" fields to "committed" ones and overwrite the relay log info
> file, *if* the PREPAREd transaction is being committed, e.g. in
> innobase_commit_by_xid(). What do you think?

Upon the first thought it seems workable, however I would like to postpone further discussion until we agree on the previous point, because there are other bugs in crash-resistant replication bug too, fixing which might require implementing "transactional system table for slave relay log," and if we have to do that, then we should discuss such fixes as a whole.

> Minor comments on the test case:
> - do we really need the "rpl_" prefix in rpl_percona_crash_resistant_rpl.*?

Looks funny to me too...

Read more...

Revision history for this message
Alexey Kopytov (akopytov) wrote : Posted in a previous version of this proposal

On 07/03/2012 08:35 PM, Laurynas Biveinis wrote:
=> Namely, why is the assumption "slave position update is a part of
actual transaction changes" wrong in the light of this? If a prepared
transaction is rolled back, the old slave position is restored from an
undo seg. If it is 2pc-committed, the new slave position becomes permanent.
>

Right, it didn't occur to me that updates of the trx header fields are
done as a part of the current transaction. If they are rolled back when
a prepared transaction is rolled back, then the fix is correct. Can we
have it covered by the test case?

Though it's not clear then what the difference with the binlog position
update is, i.e. what following means:

> + /* Update the replication position info inside InnoDB. This is
> + different from the binlog position update that happens during
> + XA COMMIT. In contrast to that, the slave position is an

> Maybe you view this fix as incomplete or working by chance because of the following (which is the actual action sequence that happens in this bug): on crash recovery the relay status log overwrite will happen before the XA rollback, thus the slave position will point to as if the transaction was fully committed. Then the transaction will be rolled back, (which would require overwriting relay status log with the old position) and replayed from the binlog, (which would require overwriting the relay status log position again, but binlog does not have the required info for that). This results in correct positions, although with a shortcut taken. The assumption here that all replicated InnoDB XA prepared transactions will be eventually committed. It is not perfect but IMHO "slave position is a part of transaction itself" is a step to the right direction.
>

I don't understand this. When and how a replay from binlog of a rolled
back XA transaction occurs? If I'm not mistaken, a roll back happens
when the corresponding event is _not_ in the binary log (or binlog not
used at all).

Revision history for this message
Laurynas Biveinis (laurynas-biveinis) wrote : Posted in a previous version of this proposal

> On 07/03/2012 08:35 PM, Laurynas Biveinis wrote:
> => Namely, why is the assumption "slave position update is a part of
> actual transaction changes" wrong in the light of this? If a prepared
> transaction is rolled back, the old slave position is restored from an
> undo seg. If it is 2pc-committed, the new slave position becomes permanent.
> >
>
> Right, it didn't occur to me that updates of the trx header fields are
> done as a part of the current transaction. If they are rolled back when
> a prepared transaction is rolled back, then the fix is correct. Can we
> have it covered by the test case?

Good idea, I will work on this if the points below are agreed upon. I will probably use the explicit XA syntax.

> Though it's not clear then what the difference with the binlog position
> update is, i.e. what following means:
>
> > + /* Update the replication position info inside InnoDB. This
> is
> > + different from the binlog position update that happens during
> > + XA COMMIT. In contrast to that, the slave position is an

My understanding is that binlog position record in InnoDB means "InnoDB transactions are committed (not prepared) up to this binlog position." Thus it cannot possibly go back and in contrast to the slave info log, it is not part of the transaction itself, but rather InnoDB/binlog metadata of sorts. I briefly experimented with moving this to PREPARE too and broke crash recovery even worse. I can research to provide more info if you want me to.

> > Maybe you view this fix as incomplete or working by chance because of the
> following (which is the actual action sequence that happens in this bug): on
> crash recovery the relay status log overwrite will happen before the XA
> rollback, thus the slave position will point to as if the transaction was
> fully committed. Then the transaction will be rolled back, (which would
> require overwriting relay status log with the old position) and replayed from
> the binlog, (which would require overwriting the relay status log position
> again, but binlog does not have the required info for that). This results in
> correct positions, although with a shortcut taken. The assumption here that
> all replicated InnoDB XA prepared transactions will be eventually committed.
> It is not perfect but IMHO "slave position is a part of transaction itself" is
> a step to the right direction.
> >
>
> I don't understand this. When and how a replay from binlog of a rolled
> back XA transaction occurs? If I'm not mistaken, a roll back happens
> when the corresponding event is _not_ in the binary log (or binlog not
> used at all).

Right, sorry, memory failed me. The transaction is never rolledback, it sits there in prepared state on crash recovery and is committed during the binlog crash recovery. The fix still works as designed.

Revision history for this message
Alexey Kopytov (akopytov) wrote : Posted in a previous version of this proposal

On 07/04/2012 05:50 PM, Laurynas Biveinis wrote:
>> On 07/03/2012 08:35 PM, Laurynas Biveinis wrote:
>> => Namely, why is the assumption "slave position update is a part of
>> actual transaction changes" wrong in the light of this? If a prepared
>> transaction is rolled back, the old slave position is restored from an
>> undo seg. If it is 2pc-committed, the new slave position becomes permanent.
>>>
>>
>> Right, it didn't occur to me that updates of the trx header fields are
>> done as a part of the current transaction. If they are rolled back when
>> a prepared transaction is rolled back, then the fix is correct. Can we
>> have it covered by the test case?
>
> Good idea, I will work on this if the points below are agreed upon. I will probably use the explicit XA syntax.
>

There are also existing injection sites that you may want to use, e.g.
crash_commit_after_prepare will crash the server after preparing a
transaction, but before writing a xid event to binlog, so that would
theoretically lead to a rollback on recovery.

>> Though it's not clear then what the difference with the binlog position
>> update is, i.e. what following means:
>>
>>> + /* Update the replication position info inside InnoDB. This
>> is
>>> + different from the binlog position update that happens during
>>> + XA COMMIT. In contrast to that, the slave position is an
>
> My understanding is that binlog position record in InnoDB means "InnoDB transactions are committed (not prepared) up to this binlog position." Thus it cannot possibly go back and in contrast to the slave info log, it is not part of the transaction itself, but rather InnoDB/binlog metadata of sorts. I briefly experimented with moving this to PREPARE too and broke crash recovery even worse. I can research to provide more info if you want me to.
>

OK, I see what you meant to say, no need for details. Thanks for
clarifications.

Revision history for this message
Alexey Kopytov (akopytov) wrote :

Laurynas,

   - many lines exceed the 80 line width limit
   - it is a good practice to end replication test cases with "--source
     include/rpl_end.inc"
   - Yoda notation in comparisons ("0 == ...")
   - variable declarations in the middle of a block is C99 (i.e. more
     Windows incompatibilities)
   - unnecessary (char *) cast for the first argument in bzero()
   - I don't think we actually need IO_CACHE in
     innobase_do_overwrite_relay_log_info(). it's basically an enhanced
     version of fwrite() & friends, whereas we only want a single write
     of buff to the file.
   - no spaces around '=' sign in many places
   - no braces in single-statement if()s
   - in general, I would suggest to fix all of the above by leaving the
     (incorrectly formatted) code alone and not moving it into a
     separate function. That would save me about half an hour on reading
     and commenting on changes that are not really changes but rather
     moving the code around, and allow me to focus on what's really been
     changed.
   - same goes for fname -> info_fname renaming
   - otherwise the patch looks good, but in case you decide to follow my
     suggestion and revert unnecessary changes, I'd like to take another
     review round. It's too easy to miss important things with so much
     insignificant changes.

review: Needs Fixing
Revision history for this message
Laurynas Biveinis (laurynas-biveinis) wrote :

Alexey -

Thanks for the review

> - many lines exceed the 80 line width limit
> - it is a good practice to end replication test cases with "--source
> include/rpl_end.inc"
> - Yoda notation in comparisons ("0 == ...")

Noted.

> - variable declarations in the middle of a block is C99 (i.e. more
> Windows incompatibilities)

Isn't ha_innodb.cc C++? But I will fix them in any case.

> - unnecessary (char *) cast for the first argument in bzero()
> - I don't think we actually need IO_CACHE in
> innobase_do_overwrite_relay_log_info(). it's basically an enhanced
> version of fwrite() & friends, whereas we only want a single write
> of buff to the file.
> - no spaces around '=' sign in many places
> - no braces in single-statement if()s

Noted.

> - in general, I would suggest to fix all of the above by leaving the
> (incorrectly formatted) code alone and not moving it into a
> separate function. That would save me about half an hour on reading
> and commenting on changes that are not really changes but rather
> moving the code around, and allow me to focus on what's really been
> changed.
> - same goes for fname -> info_fname renaming

There are two places where I extracted new functions from existing code: in ha_innodb.cc and in trx0sys.c. Which one of them, or both, are you referring to? The trx0sys.c one I can revert, but IMHO it is easy to review too. Re. ha_innodb.cc changes, I have extracted innobase_do_overwrite_relay_log_info() because I needed to call it from another function as well and I don't see a good alternative to making a new function: if I copy pasted the code, I'd still need to adjust it heavily due to different local var context and the end result would be very close to innobase_do_overwrite_relay_log_info() anyway then. And I did the fname/pos variable rename & split, because these variables being repurposed five times is way beyond my pain threshold and extracted from innobase_setup() they stop working anyway.

Is there any way I can make the review easier with separate function? A separate MP with no functional changes perhaps?

Revision history for this message
Alexey Kopytov (akopytov) wrote :

On 09.08.12 6:30, Laurynas Biveinis wrote:
>
> Isn't ha_innodb.cc C++? But I will fix them in any case.
>

Right, it's C++, sorry.

>> - in general, I would suggest to fix all of the above by leaving the
>> (incorrectly formatted) code alone and not moving it into a
>> separate function. That would save me about half an hour on reading
>> and commenting on changes that are not really changes but rather
>> moving the code around, and allow me to focus on what's really been
>> changed.
>> - same goes for fname -> info_fname renaming
>
> There are two places where I extracted new functions from existing code: in ha_innodb.cc and in trx0sys.c. Which one of them, or both, are you referring to? The trx0sys.c one I can revert, but IMHO it is easy to review too. Re. ha_innodb.cc changes, I have extracted innobase_do_overwrite_relay_log_info() because I needed to call it from another function as well and I don't see a good alternative to making a new function: if I copy pasted the code, I'd still need to adjust it heavily due to different local var context and the end result would be very close to innobase_do_overwrite_relay_log_info() anyway then. And I did the fname/pos variable rename & split, because these variables being repurposed five times is way beyond my pain threshold and extracted from innobase_setup() they stop working anyway.
>

I was referring to innobase_do_overwrite_relay_log_info().

The second call of the function looked like a part of the comment to me
when I grepped:

+ /* On rollback of a prepared transaction revert the
+ current slave positions to the ones recorded by the
+ last COMMITTed transaction. This has an effect of
+ undoing the position change caused by the transaction
+ being rolled back. Assumes single-threaded slave SQL
+ thread. If the server has non-master write traffic
+ with XA rollbacks, this will cause additional spurious
+ slave info log overwrites, which should be harmless. */
+ trx_sys_print_committed_mysql_master_log_pos();
+ innobase_do_overwrite_relay_log_info();

In the InnoDB code multi-line comments are usually separated from code
with blank lines. That is easier to read.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added file 'Percona-Server/mysql-test/suite/rpl/r/rpl_percona_crash_resistant_rpl.result'
2--- Percona-Server/mysql-test/suite/rpl/r/rpl_percona_crash_resistant_rpl.result 1970-01-01 00:00:00 +0000
3+++ Percona-Server/mysql-test/suite/rpl/r/rpl_percona_crash_resistant_rpl.result 2012-08-16 13:46:15 +0000
4@@ -0,0 +1,54 @@
5+include/master-slave.inc
6+[connection master]
7+DROP TABLE IF EXISTS t1;
8+CREATE TABLE t1 (id INT(11) NOT NULL AUTO_INCREMENT, PRIMARY KEY(id)) ENGINE=InnoDB;
9+INSERT INTO t1 VALUES ();
10+SELECT COUNT(*) FROM t1;
11+COUNT(*)
12+1
13+include/rpl_restart_server.inc [server_number=2]
14+include/start_slave.inc
15+SELECT COUNT(*) FROM t1;
16+COUNT(*)
17+1
18+STOP SLAVE;
19+include/wait_for_slave_to_stop.inc
20+INSERT INTO t1 VALUES();
21+SELECT COUNT(*) FROM t1;
22+COUNT(*)
23+2
24+SET GLOBAL debug="+d,crash_commit_before";
25+START SLAVE;
26+include/rpl_start_server.inc [server_number=2]
27+include/start_slave.inc
28+SELECT COUNT(*) FROM t1;
29+COUNT(*)
30+2
31+STOP SLAVE;
32+include/wait_for_slave_to_stop.inc
33+INSERT INTO t1 VALUES();
34+SELECT COUNT(*) FROM t1;
35+COUNT(*)
36+3
37+SET GLOBAL debug="+d,crash_innodb_after_prepare";
38+START SLAVE;
39+include/rpl_start_server.inc [server_number=2]
40+include/start_slave.inc
41+SELECT COUNT(*) FROM t1;
42+COUNT(*)
43+3
44+STOP SLAVE;
45+include/wait_for_slave_to_stop.inc
46+INSERT INTO t1 VALUES();
47+SELECT COUNT(*) FROM t1;
48+COUNT(*)
49+4
50+SET GLOBAL debug="+d,crash_innodb_before_commit";
51+START SLAVE;
52+include/rpl_start_server.inc [server_number=2]
53+include/start_slave.inc
54+SELECT COUNT(*) FROM t1;
55+COUNT(*)
56+4
57+DROP TABLE t1;
58+include/rpl_end.inc
59
60=== added file 'Percona-Server/mysql-test/suite/rpl/t/rpl_percona_crash_resistant_rpl-slave.opt'
61--- Percona-Server/mysql-test/suite/rpl/t/rpl_percona_crash_resistant_rpl-slave.opt 1970-01-01 00:00:00 +0000
62+++ Percona-Server/mysql-test/suite/rpl/t/rpl_percona_crash_resistant_rpl-slave.opt 2012-08-16 13:46:15 +0000
63@@ -0,0 +1,1 @@
64+--innodb-overwrite-relay-log-info=TRUE --skip-core-file --skip-stack-trace
65
66=== added file 'Percona-Server/mysql-test/suite/rpl/t/rpl_percona_crash_resistant_rpl.test'
67--- Percona-Server/mysql-test/suite/rpl/t/rpl_percona_crash_resistant_rpl.test 1970-01-01 00:00:00 +0000
68+++ Percona-Server/mysql-test/suite/rpl/t/rpl_percona_crash_resistant_rpl.test 2012-08-16 13:46:15 +0000
69@@ -0,0 +1,117 @@
70+# Tests for Percona crash-resistant replication feature
71+--source include/have_innodb_plugin.inc
72+--source include/master-slave.inc
73+--source include/not_valgrind.inc
74+--source include/not_crashrep.inc
75+--source include/have_debug.inc
76+
77+#
78+# Setup
79+#
80+
81+--disable_query_log
82+call mtr.add_suppression("InnoDB: Warning: innodb_overwrite_relay_log_info is enabled.");
83+--enable_query_log
84+
85+connection master;
86+
87+--disable_warnings
88+DROP TABLE IF EXISTS t1;
89+--enable_warnings
90+
91+CREATE TABLE t1 (id INT(11) NOT NULL AUTO_INCREMENT, PRIMARY KEY(id)) ENGINE=InnoDB;
92+
93+#
94+# Test the non-crashing case
95+#
96+
97+INSERT INTO t1 VALUES ();
98+SELECT COUNT(*) FROM t1;
99+
100+sync_slave_with_master;
101+--let $rpl_server_number= 2
102+--source include/rpl_restart_server.inc
103+--source include/start_slave.inc
104+SELECT COUNT(*) FROM t1;
105+
106+#
107+# Test the crashing case where relay-log.info needs not to be overwritten
108+#
109+
110+STOP SLAVE;
111+--source include/wait_for_slave_to_stop.inc
112+
113+connection master;
114+INSERT INTO t1 VALUES();
115+SELECT COUNT(*) FROM t1;
116+
117+connection slave;
118+SET GLOBAL debug="+d,crash_commit_before";
119+--exec echo "restart" > $MYSQLTEST_VARDIR/tmp/mysqld.2.expect
120+--error 0,2013
121+START SLAVE;
122+--source include/wait_until_disconnected.inc
123+--enable_reconnect
124+
125+--let $rpl_server_number= 2
126+--source include/rpl_start_server.inc
127+--source include/start_slave.inc
128+connection master;
129+sync_slave_with_master;
130+SELECT COUNT(*) FROM t1;
131+
132+#
133+# Test the rollback of slave position stored in the InnoDB trx header.
134+#
135+STOP SLAVE;
136+--source include/wait_for_slave_to_stop.inc
137+
138+connection master;
139+INSERT INTO t1 VALUES();
140+SELECT COUNT(*) FROM t1;
141+
142+connection slave;
143+SET GLOBAL debug="+d,crash_innodb_after_prepare";
144+--exec echo "restart" > $MYSQLTEST_VARDIR/tmp/mysqld.2.expect
145+--error 0,2013
146+START SLAVE;
147+--source include/wait_until_disconnected.inc
148+--enable_reconnect
149+
150+--let $rpl_server_number= 2
151+--source include/rpl_start_server.inc
152+--source include/start_slave.inc
153+connection master;
154+sync_slave_with_master;
155+SELECT COUNT(*) FROM t1;
156+
157+#
158+# Test crash with XA transaction recovery (bug 1012715)
159+#
160+STOP SLAVE;
161+--source include/wait_for_slave_to_stop.inc
162+connection master;
163+INSERT INTO t1 VALUES();
164+SELECT COUNT(*) FROM t1;
165+
166+connection slave;
167+SET GLOBAL debug="+d,crash_innodb_before_commit";
168+--exec echo "restart" > $MYSQLTEST_VARDIR/tmp/mysqld.2.expect
169+--error 0,2013
170+START SLAVE;
171+--source include/wait_until_disconnected.inc
172+--enable_reconnect
173+
174+--let $rpl_server_number= 2
175+--source include/rpl_start_server.inc
176+--source include/start_slave.inc
177+SELECT COUNT(*) FROM t1;
178+
179+#
180+# Cleanup
181+#
182+
183+connection master;
184+DROP TABLE t1;
185+
186+--source include/rpl_end.inc
187
188=== modified file 'Percona-Server/storage/innodb_plugin/handler/ha_innodb.cc'
189--- Percona-Server/storage/innodb_plugin/handler/ha_innodb.cc 2012-07-02 02:04:45 +0000
190+++ Percona-Server/storage/innodb_plugin/handler/ha_innodb.cc 2012-08-16 13:46:15 +0000
191@@ -2093,6 +2093,118 @@
192 reset_template(prebuilt);
193 }
194
195+/* The last read master log coordinates in the slave info file */
196+static char master_log_fname[TRX_SYS_MYSQL_MASTER_LOG_NAME_LEN] = "";
197+static int master_log_pos;
198+/* The slave relay log coordinates in the slave info file after startup */
199+static char original_relay_log_fname[TRX_SYS_MYSQL_MASTER_LOG_NAME_LEN] = "";
200+static int original_relay_log_pos;
201+/* The master log coordinates in the slave info file after startup */
202+static char original_master_log_fname[TRX_SYS_MYSQL_MASTER_LOG_NAME_LEN] = "";
203+static int original_master_log_pos;
204+
205+/*****************************************************************//**
206+Overwrites the MySQL relay log info file with the current master and relay log
207+coordinates from InnoDB. Skips overwrite if the master log position did not
208+change from the last overwrite. If the InnoDB master log position is equal
209+to position that was read from the info file on startup before any overwrites,
210+restores the original positions. */
211+static
212+void
213+innobase_do_overwrite_relay_log_info(void)
214+/*======================================*/
215+{
216+ char info_fname[FN_REFLEN];
217+ File info_fd = -1;
218+ int error = 0;
219+ char buff[FN_REFLEN*2+22*2+4];
220+ char *relay_info_log_pos;
221+ size_t buf_len;
222+
223+ if (master_log_fname[0] == '\0') {
224+ fprintf(stderr,
225+ "InnoDB: something wrong with relay-log.info. "
226+ "InnoDB will not overwrite it.\n");
227+ return;
228+ }
229+
230+ if (strcmp(master_log_fname, trx_sys_mysql_master_log_name) == 0
231+ && master_log_pos == trx_sys_mysql_master_log_pos) {
232+ fprintf(stderr,
233+ "InnoDB: InnoDB and relay-log.info are synchronized. "
234+ "InnoDB will not overwrite it.\n");
235+ return;
236+ }
237+
238+ /* If we overwrite the file back to the original master log position,
239+ restore the original relay log position too. This is required because
240+ we might have rolled back a prepared transaction and restored the
241+ original master log position from the InnoDB trx sys header, but the
242+ corresponding relay log position points to an already-purged file. */
243+ if (strcmp(original_master_log_fname, trx_sys_mysql_master_log_name)
244+ == 0
245+ && (original_master_log_pos == trx_sys_mysql_master_log_pos)) {
246+
247+ strncpy(trx_sys_mysql_relay_log_name, original_relay_log_fname,
248+ TRX_SYS_MYSQL_MASTER_LOG_NAME_LEN);
249+ trx_sys_mysql_relay_log_pos = original_relay_log_pos;
250+ }
251+
252+ fn_format(info_fname, relay_log_info_file, mysql_data_home, "",
253+ MY_UNPACK_FILENAME | MY_RETURN_REAL_PATH);
254+
255+ if (access(info_fname, F_OK)) {
256+ /* File does not exist */
257+ error = 1;
258+ goto skip_overwrite;
259+ }
260+
261+ /* File exists */
262+ info_fd = my_open(info_fname, O_RDWR|O_BINARY, MYF(MY_WME));
263+ if (info_fd < 0) {
264+ error = 1;
265+ goto skip_overwrite;
266+ }
267+
268+ relay_info_log_pos = strmov(buff, trx_sys_mysql_relay_log_name);
269+ *relay_info_log_pos ++= '\n';
270+ relay_info_log_pos = longlong2str(trx_sys_mysql_relay_log_pos,
271+ relay_info_log_pos, 10);
272+ *relay_info_log_pos ++= '\n';
273+ relay_info_log_pos = strmov(relay_info_log_pos,
274+ trx_sys_mysql_master_log_name);
275+ *relay_info_log_pos ++= '\n';
276+ relay_info_log_pos = longlong2str(trx_sys_mysql_master_log_pos,
277+ relay_info_log_pos, 10);
278+ *relay_info_log_pos = '\n';
279+
280+ buf_len = (relay_info_log_pos - buff) + 1;
281+ if (my_write(info_fd, (uchar *)buff, buf_len, MY_WME) != buf_len) {
282+ error = 1;
283+ } else if (my_sync(info_fd, MY_WME)) {
284+ error = 1;
285+ }
286+
287+ if (info_fd >= 0) {
288+ my_close(info_fd, MYF(0));
289+ }
290+
291+ strncpy(master_log_fname, trx_sys_mysql_relay_log_name,
292+ TRX_SYS_MYSQL_MASTER_LOG_NAME_LEN);
293+ master_log_pos = trx_sys_mysql_master_log_pos;
294+
295+skip_overwrite:
296+ if (error) {
297+ fprintf(stderr,
298+ "InnoDB: ERROR: error occured during overwriting "
299+ "relay-log.info.\n");
300+ } else {
301+ fprintf(stderr,
302+ "InnoDB: relay-log.info was overwritten.\n");
303+ }
304+}
305+
306+
307 /*********************************************************************//**
308 Opens an InnoDB database.
309 @return 0 on success, error code on failure */
310@@ -2221,12 +2333,13 @@
311 #ifdef HAVE_REPLICATION
312 #ifdef MYSQL_SERVER
313 /* read master log position from relay-log.info if exists */
314- char fname[FN_REFLEN+128];
315- int pos;
316+ char info_fname[FN_REFLEN];
317+ char relay_log_fname[TRX_SYS_MYSQL_MASTER_LOG_NAME_LEN];
318+ int relay_log_pos;
319 int info_fd;
320 IO_CACHE info_file;
321
322- fname[0] = '\0';
323+ info_fname[0] = '\0';
324
325 if(innobase_overwrite_relay_log_info) {
326
327@@ -2235,13 +2348,14 @@
328 " Updates in other storage engines may have problem with consistency.\n");
329
330 bzero((char*) &info_file, sizeof(info_file));
331- fn_format(fname, relay_log_info_file, mysql_data_home, "", 4+32);
332+ fn_format(info_fname, relay_log_info_file, mysql_data_home, "", 4+32);
333
334 int error=0;
335
336- if (!access(fname,F_OK)) {
337+ if (!access(info_fname,F_OK)) {
338 /* exist */
339- if ((info_fd = my_open(fname, O_RDWR|O_BINARY, MYF(MY_WME))) < 0) {
340+ if ((info_fd = my_open(info_fname, O_RDWR | O_BINARY,
341+ MYF(MY_WME))) < 0) {
342 error=1;
343 } else if (init_io_cache(&info_file, info_fd, IO_SIZE*2,
344 READ_CACHE, 0L, 0, MYF(MY_WME))) {
345@@ -2252,16 +2366,18 @@
346 relay_info_error:
347 if (info_fd >= 0)
348 my_close(info_fd, MYF(0));
349- fname[0] = '\0';
350+ master_log_fname[0] = '\0';
351 goto skip_relay;
352 }
353 } else {
354- fname[0] = '\0';
355+ master_log_fname[0] = '\0';
356 goto skip_relay;
357 }
358
359- if (init_strvar_from_file(fname, sizeof(fname), &info_file, "") || /* dummy (it is relay-log) */
360- init_intvar_from_file(&pos, &info_file, BIN_LOG_HEADER_SIZE)) {
361+ if (init_strvar_from_file(relay_log_fname, sizeof(relay_log_fname),
362+ &info_file, "")
363+ || /* dummy (it is relay-log) */ init_intvar_from_file(
364+ &relay_log_pos, &info_file, BIN_LOG_HEADER_SIZE)) {
365 end_io_cache(&info_file);
366 error=1;
367 goto relay_info_error;
368@@ -2270,13 +2386,19 @@
369 fprintf(stderr,
370 "InnoDB: relay-log.info is detected.\n"
371 "InnoDB: relay log: position %u, file name %s\n",
372- pos, fname);
373-
374- strncpy(trx_sys_mysql_relay_log_name, fname, TRX_SYS_MYSQL_MASTER_LOG_NAME_LEN);
375- trx_sys_mysql_relay_log_pos = (ib_int64_t) pos;
376-
377- if (init_strvar_from_file(fname, sizeof(fname), &info_file, "") ||
378- init_intvar_from_file(&pos, &info_file, 0)) {
379+ relay_log_pos, relay_log_fname);
380+
381+ strncpy(trx_sys_mysql_relay_log_name, relay_log_fname,
382+ TRX_SYS_MYSQL_MASTER_LOG_NAME_LEN);
383+ trx_sys_mysql_relay_log_pos = (ib_int64_t) relay_log_pos;
384+
385+ strncpy(original_relay_log_fname, relay_log_fname,
386+ TRX_SYS_MYSQL_MASTER_LOG_NAME_LEN);
387+ original_relay_log_pos = relay_log_pos;
388+
389+ if (init_strvar_from_file(master_log_fname, sizeof(master_log_fname),
390+ &info_file, "")
391+ || init_intvar_from_file(&master_log_pos, &info_file, 0)) {
392 end_io_cache(&info_file);
393 error=1;
394 goto relay_info_error;
395@@ -2284,10 +2406,15 @@
396
397 fprintf(stderr,
398 "InnoDB: master log: position %u, file name %s\n",
399- pos, fname);
400-
401- strncpy(trx_sys_mysql_master_log_name, fname, TRX_SYS_MYSQL_MASTER_LOG_NAME_LEN);
402- trx_sys_mysql_master_log_pos = (ib_int64_t) pos;
403+ master_log_pos, master_log_fname);
404+
405+ strncpy(trx_sys_mysql_master_log_name, master_log_fname,
406+ TRX_SYS_MYSQL_MASTER_LOG_NAME_LEN);
407+ trx_sys_mysql_master_log_pos = (ib_int64_t) master_log_pos;
408+
409+ strncpy(original_master_log_fname, master_log_fname,
410+ TRX_SYS_MYSQL_MASTER_LOG_NAME_LEN);
411+ original_master_log_pos = master_log_pos;
412
413 end_io_cache(&info_file);
414 if (info_fd >= 0)
415@@ -2587,75 +2714,9 @@
416 goto mem_free_and_error;
417 }
418
419-#ifdef HAVE_REPLICATION
420-#ifdef MYSQL_SERVER
421 if(innobase_overwrite_relay_log_info) {
422- /* If InnoDB progressed from relay-log.info, overwrite it */
423- if (fname[0] == '\0') {
424- fprintf(stderr,
425- "InnoDB: something wrong with relay-info.log. InnoDB will not overwrite it.\n");
426- } else if (0 != strcmp(fname, trx_sys_mysql_master_log_name)
427- || pos != trx_sys_mysql_master_log_pos) {
428- /* Overwrite relay-log.info */
429- bzero((char*) &info_file, sizeof(info_file));
430- fn_format(fname, relay_log_info_file, mysql_data_home, "", 4+32);
431-
432- int error = 0;
433-
434- if (!access(fname,F_OK)) {
435- /* exist */
436- if ((info_fd = my_open(fname, O_RDWR|O_BINARY, MYF(MY_WME))) < 0) {
437- error = 1;
438- } else if (init_io_cache(&info_file, info_fd, IO_SIZE*2,
439- WRITE_CACHE, 0L, 0, MYF(MY_WME))) {
440- error = 1;
441- }
442-
443- if (error) {
444- if (info_fd >= 0)
445- my_close(info_fd, MYF(0));
446- goto skip_overwrite;
447- }
448- } else {
449- error = 1;
450- goto skip_overwrite;
451- }
452-
453- char buff[FN_REFLEN*2+22*2+4], *pos;
454-
455- my_b_seek(&info_file, 0L);
456- pos=strmov(buff, trx_sys_mysql_relay_log_name);
457- *pos++='\n';
458- pos=longlong2str(trx_sys_mysql_relay_log_pos, pos, 10);
459- *pos++='\n';
460- pos=strmov(pos, trx_sys_mysql_master_log_name);
461- *pos++='\n';
462- pos=longlong2str(trx_sys_mysql_master_log_pos, pos, 10);
463- *pos='\n';
464-
465- if (my_b_write(&info_file, (uchar*) buff, (size_t) (pos-buff)+1))
466- error = 1;
467- if (flush_io_cache(&info_file))
468- error = 1;
469-
470- end_io_cache(&info_file);
471- if (info_fd >= 0)
472- my_close(info_fd, MYF(0));
473-skip_overwrite:
474- if (error) {
475- fprintf(stderr,
476- "InnoDB: ERROR: error occured during overwriting relay-log.info.\n");
477- } else {
478- fprintf(stderr,
479- "InnoDB: relay-log.info was overwritten.\n");
480- }
481- } else {
482- fprintf(stderr,
483- "InnoDB: InnoDB and relay-log.info are synchronized. InnoDB will not overwrite it.\n");
484- }
485- }
486-#endif /* MYSQL_SERVER */
487-#endif /* HAVE_REPLICATION */
488+ innobase_do_overwrite_relay_log_info();
489+ }
490
491 innobase_open_tables = hash_create(200);
492 pthread_mutex_init(&innobase_share_mutex, MY_MUTEX_INIT_FAST);
493@@ -2757,38 +2818,50 @@
494 | HA_ONLINE_ADD_PK_INDEX_NO_WRITES);
495 }
496
497-/*****************************************************************//**
498-Commits a transaction in an InnoDB database. */
499+/****************************************************************//**
500+Copy the current replication position from MySQL to a transaction. */
501 static
502 void
503-innobase_commit_low(
504-/*================*/
505- trx_t* trx) /*!< in: transaction handle */
506+innobase_copy_repl_coords_to_trx(
507+/*=============================*/
508+ const THD* thd, /*!< in: thread handle */
509+ trx_t* trx) /*!< in/out: transaction */
510 {
511- if (trx->conc_state == TRX_NOT_STARTED) {
512-
513- return;
514- }
515-
516-#ifdef HAVE_REPLICATION
517-#ifdef MYSQL_SERVER
518- THD *thd=current_thd;
519-
520 if (thd && thd->slave_thread) {
521- /* Update the replication position info inside InnoDB */
522+ const Relay_log_info* rli = &active_mi->rli;
523+
524 trx->mysql_master_log_file_name
525- = active_mi->rli.group_master_log_name;
526+ = rli->group_master_log_name;
527 trx->mysql_master_log_pos
528- = ((ib_int64_t)active_mi->rli.group_master_log_pos +
529- ((ib_int64_t)active_mi->rli.future_event_relay_log_pos -
530- (ib_int64_t)active_mi->rli.group_relay_log_pos));
531+ = ((ib_int64_t)rli->group_master_log_pos
532+ + ((ib_int64_t)
533+ rli->future_event_relay_log_pos
534+ - (ib_int64_t)rli->group_relay_log_pos));
535 trx->mysql_relay_log_file_name
536- = active_mi->rli.group_relay_log_name;
537+ = rli->group_relay_log_name;
538 trx->mysql_relay_log_pos
539- = (ib_int64_t)active_mi->rli.future_event_relay_log_pos;
540- }
541-#endif /* MYSQL_SERVER */
542-#endif /* HAVE_REPLICATION */
543+ = (ib_int64_t)rli->future_event_relay_log_pos;
544+ }
545+}
546+
547+/*****************************************************************//**
548+Commits a transaction in an InnoDB database. */
549+static
550+void
551+innobase_commit_low(
552+/*================*/
553+ trx_t* trx) /*!< in: transaction handle */
554+{
555+ if (trx->conc_state == TRX_NOT_STARTED) {
556+
557+ return;
558+ }
559+
560+ /* Save the current replication position for write to trx sys header
561+ for undo purposes, see the comment at corresponding call at
562+ innobase_xa_prepare(). */
563+
564+ innobase_copy_repl_coords_to_trx(current_thd, trx);
565
566 trx_commit_for_mysql(trx);
567 }
568@@ -2898,6 +2971,9 @@
569 if (all
570 || (!thd_test_options(thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))) {
571
572+ DBUG_EXECUTE_IF("crash_innodb_before_commit",
573+ DBUG_SUICIDE(););
574+
575 /* We were instructed to commit the whole transaction, or
576 this is an SQL statement end and autocommit is on */
577
578@@ -10657,7 +10733,27 @@
579
580 ut_ad(trx->active_trans);
581
582+ /* Update the replication position info in current trx. This
583+ is different from the binlog position update that happens
584+ during XA COMMIT. In contrast to that, the slave position is
585+ an actual part of the changes made by this transaction and thus
586+ must be updated in the XA PREPARE stage. Since the trx sys
587+ header page changes are not undo-logged, again store this
588+ position in a different field in the XA COMMIT stage, so that
589+ it might be used in case of rollbacks. */
590+
591+ /* Since currently there might be only one slave SQL thread, we
592+ don't need to take any precautions (e.g. prepare_commit_mutex)
593+ to ensure position ordering. Revisit this in 5.6 which has
594+ both the multi-threaded replication to cause us problems and
595+ the group commit to solve them. */
596+
597+ innobase_copy_repl_coords_to_trx(thd, trx);
598+
599 error = (int) trx_prepare_for_mysql(trx);
600+
601+ DBUG_EXECUTE_IF("crash_innodb_after_prepare",
602+ DBUG_SUICIDE(););
603 } else {
604 /* We just mark the SQL statement ended and do not do a
605 transaction prepare */
606@@ -10780,6 +10876,22 @@
607 if (trx) {
608 int ret = innobase_rollback_trx(trx);
609 trx_free_for_background(trx);
610+
611+ if (innobase_overwrite_relay_log_info) {
612+
613+ /* On rollback of a prepared transaction revert the
614+ current slave positions to the ones recorded by the
615+ last COMMITTed transaction. This has an effect of
616+ undoing the position change caused by the transaction
617+ being rolled back. Assumes single-threaded slave SQL
618+ thread. If the server has non-master write traffic
619+ with XA rollbacks, this will cause additional spurious
620+ slave info log overwrites, which should be harmless. */
621+
622+ trx_sys_print_committed_mysql_master_log_pos();
623+ innobase_do_overwrite_relay_log_info();
624+ }
625+
626 return(ret);
627 } else {
628 return(XAER_NOTA);
629
630=== modified file 'Percona-Server/storage/innodb_plugin/include/trx0sys.h'
631--- Percona-Server/storage/innodb_plugin/include/trx0sys.h 2012-04-02 02:09:15 +0000
632+++ Percona-Server/storage/innodb_plugin/include/trx0sys.h 2012-08-16 13:46:15 +0000
633@@ -357,6 +357,14 @@
634 trx_sys_print_mysql_binlog_offset(void);
635 /*===================================*/
636 /*****************************************************************//**
637+Prints to stderr the MySQL master log offset info in the trx system header
638+COMMIT set of fields if the magic number shows it valid and stores it
639+in global variables. */
640+UNIV_INTERN
641+void
642+trx_sys_print_committed_mysql_master_log_pos(void);
643+/*==============================================*/
644+/*****************************************************************//**
645 Prints to stderr the MySQL master log offset info in the trx system header if
646 the magic number shows it valid. */
647 UNIV_INTERN
648@@ -536,10 +544,16 @@
649 //# error "UNIV_PAGE_SIZE < 4096"
650 //#endif
651 /** The offset of the MySQL replication info in the trx system header;
652-this contains the same fields as TRX_SYS_MYSQL_LOG_INFO below */
653+this contains the same fields as TRX_SYS_MYSQL_LOG_INFO below. These are
654+written at prepare time and are the main copy. */
655 #define TRX_SYS_MYSQL_MASTER_LOG_INFO (UNIV_PAGE_SIZE - 2000)
656 #define TRX_SYS_MYSQL_RELAY_LOG_INFO (UNIV_PAGE_SIZE - 1500)
657
658+/** The copy of the above which is made at transaction COMMIT time. If binlog
659+crash recovery rollbacks a PREPAREd transaction, they are copied back. */
660+#define TRX_SYS_COMMIT_MASTER_LOG_INFO (UNIV_PAGE_SIZE - 3000)
661+#define TRX_SYS_COMMIT_RELAY_LOG_INFO (UNIV_PAGE_SIZE - 2500)
662+
663 /** The offset of the MySQL binlog offset info in the trx system header */
664 #define TRX_SYS_MYSQL_LOG_INFO (UNIV_PAGE_SIZE - 1000)
665 #define TRX_SYS_MYSQL_LOG_MAGIC_N_FLD 0 /*!< magic number which is
666
667=== modified file 'Percona-Server/storage/innodb_plugin/trx/trx0sys.c'
668--- Percona-Server/storage/innodb_plugin/trx/trx0sys.c 2012-04-02 02:09:15 +0000
669+++ Percona-Server/storage/innodb_plugin/trx/trx0sys.c 2012-08-16 13:46:15 +0000
670@@ -947,8 +947,31 @@
671 }
672
673 /*****************************************************************//**
674-Prints to stderr the MySQL master log offset info in the trx system header if
675-the magic number shows it valid. */
676+Reads the log coordinates at the given offset in the trx sys header. */
677+static
678+void
679+trx_sys_read_log_pos(
680+/*=================*/
681+ const trx_sysf_t* sys_header, /*!< in: the trx sys header */
682+ uint header_offset, /*!< in: coord offset in the
683+ header */
684+ char* log_fn, /*!< out: the log file name */
685+ ib_int64_t* log_pos) /*!< out: the log poistion */
686+{
687+ ut_memcpy(log_fn, sys_header + header_offset + TRX_SYS_MYSQL_LOG_NAME,
688+ TRX_SYS_MYSQL_MASTER_LOG_NAME_LEN);
689+
690+ *log_pos =
691+ (((ib_int64_t)mach_read_from_4(sys_header + header_offset
692+ + TRX_SYS_MYSQL_LOG_OFFSET_HIGH)) << 32)
693+ + mach_read_from_4(sys_header + header_offset
694+ + TRX_SYS_MYSQL_LOG_OFFSET_LOW);
695+}
696+
697+/*****************************************************************//**
698+Prints to stderr the MySQL master log offset info in the trx system header
699+PREPARE set of fields if the magic number shows it valid and stores it
700+in global variables. */
701 UNIV_INTERN
702 void
703 trx_sys_print_mysql_master_log_pos(void)
704@@ -970,60 +993,79 @@
705 return;
706 }
707
708- fprintf(stderr,
709- "InnoDB: In a MySQL replication slave the last"
710- " master binlog file\n"
711- "InnoDB: position %lu %lu, file name %s\n",
712- (ulong) mach_read_from_4(sys_header
713- + TRX_SYS_MYSQL_MASTER_LOG_INFO
714- + TRX_SYS_MYSQL_LOG_OFFSET_HIGH),
715- (ulong) mach_read_from_4(sys_header
716- + TRX_SYS_MYSQL_MASTER_LOG_INFO
717- + TRX_SYS_MYSQL_LOG_OFFSET_LOW),
718- sys_header + TRX_SYS_MYSQL_MASTER_LOG_INFO
719- + TRX_SYS_MYSQL_LOG_NAME);
720-
721- fprintf(stderr,
722- "InnoDB: and relay log file\n"
723- "InnoDB: position %lu %lu, file name %s\n",
724- (ulong) mach_read_from_4(sys_header
725- + TRX_SYS_MYSQL_RELAY_LOG_INFO
726- + TRX_SYS_MYSQL_LOG_OFFSET_HIGH),
727- (ulong) mach_read_from_4(sys_header
728- + TRX_SYS_MYSQL_RELAY_LOG_INFO
729- + TRX_SYS_MYSQL_LOG_OFFSET_LOW),
730- sys_header + TRX_SYS_MYSQL_RELAY_LOG_INFO
731- + TRX_SYS_MYSQL_LOG_NAME);
732-
733 /* Copy the master log position info to global variables we can
734 use in ha_innobase.cc to initialize glob_mi to right values */
735-
736- ut_memcpy(trx_sys_mysql_master_log_name,
737- sys_header + TRX_SYS_MYSQL_MASTER_LOG_INFO
738- + TRX_SYS_MYSQL_LOG_NAME,
739- TRX_SYS_MYSQL_MASTER_LOG_NAME_LEN);
740-
741- trx_sys_mysql_master_log_pos
742- = (((ib_int64_t) mach_read_from_4(
743- sys_header + TRX_SYS_MYSQL_MASTER_LOG_INFO
744- + TRX_SYS_MYSQL_LOG_OFFSET_HIGH)) << 32)
745- + ((ib_int64_t) mach_read_from_4(
746- sys_header + TRX_SYS_MYSQL_MASTER_LOG_INFO
747- + TRX_SYS_MYSQL_LOG_OFFSET_LOW));
748-
749- ut_memcpy(trx_sys_mysql_relay_log_name,
750- sys_header + TRX_SYS_MYSQL_RELAY_LOG_INFO
751- + TRX_SYS_MYSQL_LOG_NAME,
752- TRX_SYS_MYSQL_MASTER_LOG_NAME_LEN);
753-
754- trx_sys_mysql_relay_log_pos
755- = (((ib_int64_t) mach_read_from_4(
756- sys_header + TRX_SYS_MYSQL_RELAY_LOG_INFO
757- + TRX_SYS_MYSQL_LOG_OFFSET_HIGH)) << 32)
758- + ((ib_int64_t) mach_read_from_4(
759- sys_header + TRX_SYS_MYSQL_RELAY_LOG_INFO
760- + TRX_SYS_MYSQL_LOG_OFFSET_LOW));
761- mtr_commit(&mtr);
762+ trx_sys_read_log_pos(sys_header, TRX_SYS_MYSQL_MASTER_LOG_INFO,
763+ trx_sys_mysql_master_log_name,
764+ &trx_sys_mysql_master_log_pos);
765+
766+ trx_sys_read_log_pos(sys_header, TRX_SYS_MYSQL_RELAY_LOG_INFO,
767+ trx_sys_mysql_relay_log_name,
768+ &trx_sys_mysql_relay_log_pos);
769+
770+ mtr_commit(&mtr);
771+
772+ fprintf(stderr,
773+ "InnoDB: In a MySQL replication slave the last"
774+ " master binlog file\n"
775+ "InnoDB: position %llu, file name %s\n",
776+ trx_sys_mysql_master_log_pos,
777+ trx_sys_mysql_master_log_name);
778+
779+ fprintf(stderr,
780+ "InnoDB: and relay log file\n"
781+ "InnoDB: position %llu, file name %s\n",
782+ trx_sys_mysql_relay_log_pos,
783+ trx_sys_mysql_relay_log_name);
784+}
785+
786+/*****************************************************************//**
787+Prints to stderr the MySQL master log offset info in the trx system header
788+COMMIT set of fields if the magic number shows it valid and stores it
789+in global variables. */
790+UNIV_INTERN
791+void
792+trx_sys_print_committed_mysql_master_log_pos(void)
793+/*==============================================*/
794+{
795+ trx_sysf_t* sys_header;
796+ mtr_t mtr;
797+
798+ mtr_start(&mtr);
799+
800+ sys_header = trx_sysf_get(&mtr);
801+
802+ if (mach_read_from_4(sys_header + TRX_SYS_COMMIT_MASTER_LOG_INFO
803+ + TRX_SYS_MYSQL_LOG_MAGIC_N_FLD)
804+ != TRX_SYS_MYSQL_LOG_MAGIC_N) {
805+
806+ mtr_commit(&mtr);
807+
808+ return;
809+ }
810+
811+ /* Copy the master log position info to global variables we can
812+ use in ha_innobase.cc to initialize glob_mi to right values */
813+ trx_sys_read_log_pos(sys_header, TRX_SYS_COMMIT_MASTER_LOG_INFO,
814+ trx_sys_mysql_master_log_name,
815+ &trx_sys_mysql_master_log_pos);
816+
817+ trx_sys_read_log_pos(sys_header, TRX_SYS_COMMIT_RELAY_LOG_INFO,
818+ trx_sys_mysql_relay_log_name,
819+ &trx_sys_mysql_relay_log_pos);
820+
821+ mtr_commit(&mtr);
822+
823+ fprintf(stderr,
824+ "InnoDB: In a MySQL replication slave the last"
825+ " master binlog file\n"
826+ "InnoDB: position %llu, file name %s\n",
827+ trx_sys_mysql_master_log_pos, trx_sys_mysql_master_log_name);
828+
829+ fprintf(stderr,
830+ "InnoDB: and relay log file\n"
831+ "InnoDB: position %llu, file name %s\n",
832+ trx_sys_mysql_relay_log_pos, trx_sys_mysql_relay_log_name);
833 }
834
835 /****************************************************************//**
836
837=== modified file 'Percona-Server/storage/innodb_plugin/trx/trx0trx.c'
838--- Percona-Server/storage/innodb_plugin/trx/trx0trx.c 2012-04-02 02:09:15 +0000
839+++ Percona-Server/storage/innodb_plugin/trx/trx0trx.c 2012-08-16 13:46:15 +0000
840@@ -904,12 +904,12 @@
841 sys_header,
842 trx->mysql_relay_log_file_name,
843 trx->mysql_relay_log_pos,
844- TRX_SYS_MYSQL_RELAY_LOG_INFO, &mtr);
845+ TRX_SYS_COMMIT_RELAY_LOG_INFO, &mtr);
846 trx_sys_update_mysql_binlog_offset(
847 sys_header,
848 trx->mysql_master_log_file_name,
849 trx->mysql_master_log_pos,
850- TRX_SYS_MYSQL_MASTER_LOG_INFO, &mtr);
851+ TRX_SYS_COMMIT_MASTER_LOG_INFO, &mtr);
852 trx->mysql_master_log_file_name = "";
853 }
854
855@@ -2002,6 +2002,23 @@
856
857 mutex_exit(&(rseg->mutex));
858
859+ if (trx->mysql_master_log_file_name[0] != '\0') {
860+ /* This database server is a MySQL replication slave */
861+ trx_sysf_t* sys_header = trx_sysf_get(&mtr);
862+
863+ trx_sys_update_mysql_binlog_offset(
864+ sys_header,
865+ trx->mysql_relay_log_file_name,
866+ trx->mysql_relay_log_pos,
867+ TRX_SYS_MYSQL_RELAY_LOG_INFO, &mtr);
868+ trx_sys_update_mysql_binlog_offset(
869+ sys_header,
870+ trx->mysql_master_log_file_name,
871+ trx->mysql_master_log_pos,
872+ TRX_SYS_MYSQL_MASTER_LOG_INFO, &mtr);
873+ trx->mysql_master_log_file_name = "";
874+ }
875+
876 /*--------------*/
877 mtr_commit(&mtr); /* This mtr commit makes the
878 transaction prepared in the file-based

Subscribers

People subscribed via source and target branches