Merge lp:~laurynas-biveinis/percona-server/bug1012715-5.1 into lp:percona-server/5.1
- bug1012715-5.1
- Merge into 5.1
Status: | Merged |
---|---|
Approved by: | Alexey Kopytov |
Approved revision: | no longer in the source branch. |
Merged at revision: | 496 |
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 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Alexey Kopytov (community) | Approve | ||
Laurynas Biveinis | Pending | ||
Percona core | Pending | ||
Review via email: mp+120042@code.launchpad.net |
This proposal supersedes a proposal from 2012-07-18.
Commit message
Description of the change
Issue 22478.
Fix bug 1012715. See the revision commit message for the changes.
Changes from the previous MP: review comments implemented and addressed, a testcase instability issue fixed (typo in expectation file name).
Jenkins: http://
Laurynas Biveinis (laurynas-biveinis) wrote : Posted in a previous version of this proposal | # |
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_
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_
Minor comments on the test case:
- do we really need the "rpl_" prefix in rpl_percona_
- please use
SET GLOBAL debug="+d,keyword"
instead of
SET GLOBAL debug="d,keyword"
The latter breaks ./mtr --debug.
Laurynas Biveinis (laurynas-biveinis) wrote : Posted in a previous version of this proposal | # |
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_
> 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_
> 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_
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_
Looks funny to me too...
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).
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.
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_
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.
Alexey Kopytov (akopytov) wrote : Posted in a previous version of this proposal | # |
Laurynas,
- many lines exceed the 80 line width limit
- it is a good practice to end replication test cases with "--source
include/
- 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_
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.
Laurynas Biveinis (laurynas-biveinis) wrote : Posted in a previous version of this proposal | # |
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/
> - 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_
> 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_
Is there any way I can make the review easier with separate function? A separate MP with no functional changes perhaps?
Alexey Kopytov (akopytov) wrote : Posted in a previous version of this proposal | # |
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_
>
I was referring to innobase_
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_
+ innobase_
In the InnoDB code multi-line comments are usually separated from code
with blank lines. That is easier to read.
Laurynas Biveinis (laurynas-biveinis) wrote : | # |
Please ping me if you are about to review this.
Alexey Kopytov (akopytov) : | # |
Preview Diff
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-17 02:51:27 +0000 | |||
4 | @@ -0,0 +1,54 @@ | |||
5 | 1 | include/master-slave.inc | ||
6 | 2 | [connection master] | ||
7 | 3 | DROP TABLE IF EXISTS t1; | ||
8 | 4 | CREATE TABLE t1 (id INT(11) NOT NULL AUTO_INCREMENT, PRIMARY KEY(id)) ENGINE=InnoDB; | ||
9 | 5 | INSERT INTO t1 VALUES (); | ||
10 | 6 | SELECT COUNT(*) FROM t1; | ||
11 | 7 | COUNT(*) | ||
12 | 8 | 1 | ||
13 | 9 | include/rpl_restart_server.inc [server_number=2] | ||
14 | 10 | include/start_slave.inc | ||
15 | 11 | SELECT COUNT(*) FROM t1; | ||
16 | 12 | COUNT(*) | ||
17 | 13 | 1 | ||
18 | 14 | STOP SLAVE; | ||
19 | 15 | include/wait_for_slave_to_stop.inc | ||
20 | 16 | INSERT INTO t1 VALUES(); | ||
21 | 17 | SELECT COUNT(*) FROM t1; | ||
22 | 18 | COUNT(*) | ||
23 | 19 | 2 | ||
24 | 20 | SET GLOBAL debug="+d,crash_commit_before"; | ||
25 | 21 | START SLAVE; | ||
26 | 22 | include/rpl_start_server.inc [server_number=2] | ||
27 | 23 | include/start_slave.inc | ||
28 | 24 | SELECT COUNT(*) FROM t1; | ||
29 | 25 | COUNT(*) | ||
30 | 26 | 2 | ||
31 | 27 | STOP SLAVE; | ||
32 | 28 | include/wait_for_slave_to_stop.inc | ||
33 | 29 | INSERT INTO t1 VALUES(); | ||
34 | 30 | SELECT COUNT(*) FROM t1; | ||
35 | 31 | COUNT(*) | ||
36 | 32 | 3 | ||
37 | 33 | SET GLOBAL debug="+d,crash_innodb_after_prepare"; | ||
38 | 34 | START SLAVE; | ||
39 | 35 | include/rpl_start_server.inc [server_number=2] | ||
40 | 36 | include/start_slave.inc | ||
41 | 37 | SELECT COUNT(*) FROM t1; | ||
42 | 38 | COUNT(*) | ||
43 | 39 | 3 | ||
44 | 40 | STOP SLAVE; | ||
45 | 41 | include/wait_for_slave_to_stop.inc | ||
46 | 42 | INSERT INTO t1 VALUES(); | ||
47 | 43 | SELECT COUNT(*) FROM t1; | ||
48 | 44 | COUNT(*) | ||
49 | 45 | 4 | ||
50 | 46 | SET GLOBAL debug="+d,crash_innodb_before_commit"; | ||
51 | 47 | START SLAVE; | ||
52 | 48 | include/rpl_start_server.inc [server_number=2] | ||
53 | 49 | include/start_slave.inc | ||
54 | 50 | SELECT COUNT(*) FROM t1; | ||
55 | 51 | COUNT(*) | ||
56 | 52 | 4 | ||
57 | 53 | DROP TABLE t1; | ||
58 | 54 | include/rpl_end.inc | ||
59 | 0 | 55 | ||
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-17 02:51:27 +0000 | |||
63 | @@ -0,0 +1,1 @@ | |||
64 | 1 | --innodb-overwrite-relay-log-info=TRUE --skip-core-file --skip-stack-trace | ||
65 | 0 | 2 | ||
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-17 02:51:27 +0000 | |||
69 | @@ -0,0 +1,117 @@ | |||
70 | 1 | # Tests for Percona crash-resistant replication feature | ||
71 | 2 | --source include/have_innodb_plugin.inc | ||
72 | 3 | --source include/master-slave.inc | ||
73 | 4 | --source include/not_valgrind.inc | ||
74 | 5 | --source include/not_crashrep.inc | ||
75 | 6 | --source include/have_debug.inc | ||
76 | 7 | |||
77 | 8 | # | ||
78 | 9 | # Setup | ||
79 | 10 | # | ||
80 | 11 | |||
81 | 12 | --disable_query_log | ||
82 | 13 | call mtr.add_suppression("InnoDB: Warning: innodb_overwrite_relay_log_info is enabled."); | ||
83 | 14 | --enable_query_log | ||
84 | 15 | |||
85 | 16 | connection master; | ||
86 | 17 | |||
87 | 18 | --disable_warnings | ||
88 | 19 | DROP TABLE IF EXISTS t1; | ||
89 | 20 | --enable_warnings | ||
90 | 21 | |||
91 | 22 | CREATE TABLE t1 (id INT(11) NOT NULL AUTO_INCREMENT, PRIMARY KEY(id)) ENGINE=InnoDB; | ||
92 | 23 | |||
93 | 24 | # | ||
94 | 25 | # Test the non-crashing case | ||
95 | 26 | # | ||
96 | 27 | |||
97 | 28 | INSERT INTO t1 VALUES (); | ||
98 | 29 | SELECT COUNT(*) FROM t1; | ||
99 | 30 | |||
100 | 31 | sync_slave_with_master; | ||
101 | 32 | --let $rpl_server_number= 2 | ||
102 | 33 | --source include/rpl_restart_server.inc | ||
103 | 34 | --source include/start_slave.inc | ||
104 | 35 | SELECT COUNT(*) FROM t1; | ||
105 | 36 | |||
106 | 37 | # | ||
107 | 38 | # Test the crashing case where relay-log.info needs not to be overwritten | ||
108 | 39 | # | ||
109 | 40 | |||
110 | 41 | STOP SLAVE; | ||
111 | 42 | --source include/wait_for_slave_to_stop.inc | ||
112 | 43 | |||
113 | 44 | connection master; | ||
114 | 45 | INSERT INTO t1 VALUES(); | ||
115 | 46 | SELECT COUNT(*) FROM t1; | ||
116 | 47 | |||
117 | 48 | connection slave; | ||
118 | 49 | SET GLOBAL debug="+d,crash_commit_before"; | ||
119 | 50 | --exec echo "restart" > $MYSQLTEST_VARDIR/tmp/mysqld.2.expect | ||
120 | 51 | --error 0,2013 | ||
121 | 52 | START SLAVE; | ||
122 | 53 | --source include/wait_until_disconnected.inc | ||
123 | 54 | --enable_reconnect | ||
124 | 55 | |||
125 | 56 | --let $rpl_server_number= 2 | ||
126 | 57 | --source include/rpl_start_server.inc | ||
127 | 58 | --source include/start_slave.inc | ||
128 | 59 | connection master; | ||
129 | 60 | sync_slave_with_master; | ||
130 | 61 | SELECT COUNT(*) FROM t1; | ||
131 | 62 | |||
132 | 63 | # | ||
133 | 64 | # Test the rollback of slave position stored in the InnoDB trx header. | ||
134 | 65 | # | ||
135 | 66 | STOP SLAVE; | ||
136 | 67 | --source include/wait_for_slave_to_stop.inc | ||
137 | 68 | |||
138 | 69 | connection master; | ||
139 | 70 | INSERT INTO t1 VALUES(); | ||
140 | 71 | SELECT COUNT(*) FROM t1; | ||
141 | 72 | |||
142 | 73 | connection slave; | ||
143 | 74 | SET GLOBAL debug="+d,crash_innodb_after_prepare"; | ||
144 | 75 | --exec echo "restart" > $MYSQLTEST_VARDIR/tmp/mysqld.2.expect | ||
145 | 76 | --error 0,2013 | ||
146 | 77 | START SLAVE; | ||
147 | 78 | --source include/wait_until_disconnected.inc | ||
148 | 79 | --enable_reconnect | ||
149 | 80 | |||
150 | 81 | --let $rpl_server_number= 2 | ||
151 | 82 | --source include/rpl_start_server.inc | ||
152 | 83 | --source include/start_slave.inc | ||
153 | 84 | connection master; | ||
154 | 85 | sync_slave_with_master; | ||
155 | 86 | SELECT COUNT(*) FROM t1; | ||
156 | 87 | |||
157 | 88 | # | ||
158 | 89 | # Test crash with XA transaction recovery (bug 1012715) | ||
159 | 90 | # | ||
160 | 91 | STOP SLAVE; | ||
161 | 92 | --source include/wait_for_slave_to_stop.inc | ||
162 | 93 | connection master; | ||
163 | 94 | INSERT INTO t1 VALUES(); | ||
164 | 95 | SELECT COUNT(*) FROM t1; | ||
165 | 96 | |||
166 | 97 | connection slave; | ||
167 | 98 | SET GLOBAL debug="+d,crash_innodb_before_commit"; | ||
168 | 99 | --exec echo "restart" > $MYSQLTEST_VARDIR/tmp/mysqld.2.expect | ||
169 | 100 | --error 0,2013 | ||
170 | 101 | START SLAVE; | ||
171 | 102 | --source include/wait_until_disconnected.inc | ||
172 | 103 | --enable_reconnect | ||
173 | 104 | |||
174 | 105 | --let $rpl_server_number= 2 | ||
175 | 106 | --source include/rpl_start_server.inc | ||
176 | 107 | --source include/start_slave.inc | ||
177 | 108 | SELECT COUNT(*) FROM t1; | ||
178 | 109 | |||
179 | 110 | # | ||
180 | 111 | # Cleanup | ||
181 | 112 | # | ||
182 | 113 | |||
183 | 114 | connection master; | ||
184 | 115 | DROP TABLE t1; | ||
185 | 116 | |||
186 | 117 | --source include/rpl_end.inc | ||
187 | 0 | 118 | ||
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-17 02:51:27 +0000 | |||
191 | @@ -2093,6 +2093,118 @@ | |||
192 | 2093 | reset_template(prebuilt); | 2093 | reset_template(prebuilt); |
193 | 2094 | } | 2094 | } |
194 | 2095 | 2095 | ||
195 | 2096 | /* The last read master log coordinates in the slave info file */ | ||
196 | 2097 | static char master_log_fname[TRX_SYS_MYSQL_MASTER_LOG_NAME_LEN] = ""; | ||
197 | 2098 | static int master_log_pos; | ||
198 | 2099 | /* The slave relay log coordinates in the slave info file after startup */ | ||
199 | 2100 | static char original_relay_log_fname[TRX_SYS_MYSQL_MASTER_LOG_NAME_LEN] = ""; | ||
200 | 2101 | static int original_relay_log_pos; | ||
201 | 2102 | /* The master log coordinates in the slave info file after startup */ | ||
202 | 2103 | static char original_master_log_fname[TRX_SYS_MYSQL_MASTER_LOG_NAME_LEN] = ""; | ||
203 | 2104 | static int original_master_log_pos; | ||
204 | 2105 | |||
205 | 2106 | /*****************************************************************//** | ||
206 | 2107 | Overwrites the MySQL relay log info file with the current master and relay log | ||
207 | 2108 | coordinates from InnoDB. Skips overwrite if the master log position did not | ||
208 | 2109 | change from the last overwrite. If the InnoDB master log position is equal | ||
209 | 2110 | to position that was read from the info file on startup before any overwrites, | ||
210 | 2111 | restores the original positions. */ | ||
211 | 2112 | static | ||
212 | 2113 | void | ||
213 | 2114 | innobase_do_overwrite_relay_log_info(void) | ||
214 | 2115 | /*======================================*/ | ||
215 | 2116 | { | ||
216 | 2117 | char info_fname[FN_REFLEN]; | ||
217 | 2118 | File info_fd = -1; | ||
218 | 2119 | int error = 0; | ||
219 | 2120 | char buff[FN_REFLEN*2+22*2+4]; | ||
220 | 2121 | char *relay_info_log_pos; | ||
221 | 2122 | size_t buf_len; | ||
222 | 2123 | |||
223 | 2124 | if (master_log_fname[0] == '\0') { | ||
224 | 2125 | fprintf(stderr, | ||
225 | 2126 | "InnoDB: something wrong with relay-log.info. " | ||
226 | 2127 | "InnoDB will not overwrite it.\n"); | ||
227 | 2128 | return; | ||
228 | 2129 | } | ||
229 | 2130 | |||
230 | 2131 | if (strcmp(master_log_fname, trx_sys_mysql_master_log_name) == 0 | ||
231 | 2132 | && master_log_pos == trx_sys_mysql_master_log_pos) { | ||
232 | 2133 | fprintf(stderr, | ||
233 | 2134 | "InnoDB: InnoDB and relay-log.info are synchronized. " | ||
234 | 2135 | "InnoDB will not overwrite it.\n"); | ||
235 | 2136 | return; | ||
236 | 2137 | } | ||
237 | 2138 | |||
238 | 2139 | /* If we overwrite the file back to the original master log position, | ||
239 | 2140 | restore the original relay log position too. This is required because | ||
240 | 2141 | we might have rolled back a prepared transaction and restored the | ||
241 | 2142 | original master log position from the InnoDB trx sys header, but the | ||
242 | 2143 | corresponding relay log position points to an already-purged file. */ | ||
243 | 2144 | if (strcmp(original_master_log_fname, trx_sys_mysql_master_log_name) | ||
244 | 2145 | == 0 | ||
245 | 2146 | && (original_master_log_pos == trx_sys_mysql_master_log_pos)) { | ||
246 | 2147 | |||
247 | 2148 | strncpy(trx_sys_mysql_relay_log_name, original_relay_log_fname, | ||
248 | 2149 | TRX_SYS_MYSQL_MASTER_LOG_NAME_LEN); | ||
249 | 2150 | trx_sys_mysql_relay_log_pos = original_relay_log_pos; | ||
250 | 2151 | } | ||
251 | 2152 | |||
252 | 2153 | fn_format(info_fname, relay_log_info_file, mysql_data_home, "", | ||
253 | 2154 | MY_UNPACK_FILENAME | MY_RETURN_REAL_PATH); | ||
254 | 2155 | |||
255 | 2156 | if (access(info_fname, F_OK)) { | ||
256 | 2157 | /* File does not exist */ | ||
257 | 2158 | error = 1; | ||
258 | 2159 | goto skip_overwrite; | ||
259 | 2160 | } | ||
260 | 2161 | |||
261 | 2162 | /* File exists */ | ||
262 | 2163 | info_fd = my_open(info_fname, O_RDWR|O_BINARY, MYF(MY_WME)); | ||
263 | 2164 | if (info_fd < 0) { | ||
264 | 2165 | error = 1; | ||
265 | 2166 | goto skip_overwrite; | ||
266 | 2167 | } | ||
267 | 2168 | |||
268 | 2169 | relay_info_log_pos = strmov(buff, trx_sys_mysql_relay_log_name); | ||
269 | 2170 | *relay_info_log_pos ++= '\n'; | ||
270 | 2171 | relay_info_log_pos = longlong2str(trx_sys_mysql_relay_log_pos, | ||
271 | 2172 | relay_info_log_pos, 10); | ||
272 | 2173 | *relay_info_log_pos ++= '\n'; | ||
273 | 2174 | relay_info_log_pos = strmov(relay_info_log_pos, | ||
274 | 2175 | trx_sys_mysql_master_log_name); | ||
275 | 2176 | *relay_info_log_pos ++= '\n'; | ||
276 | 2177 | relay_info_log_pos = longlong2str(trx_sys_mysql_master_log_pos, | ||
277 | 2178 | relay_info_log_pos, 10); | ||
278 | 2179 | *relay_info_log_pos = '\n'; | ||
279 | 2180 | |||
280 | 2181 | buf_len = (relay_info_log_pos - buff) + 1; | ||
281 | 2182 | if (my_write(info_fd, (uchar *)buff, buf_len, MY_WME) != buf_len) { | ||
282 | 2183 | error = 1; | ||
283 | 2184 | } else if (my_sync(info_fd, MY_WME)) { | ||
284 | 2185 | error = 1; | ||
285 | 2186 | } | ||
286 | 2187 | |||
287 | 2188 | if (info_fd >= 0) { | ||
288 | 2189 | my_close(info_fd, MYF(0)); | ||
289 | 2190 | } | ||
290 | 2191 | |||
291 | 2192 | strncpy(master_log_fname, trx_sys_mysql_relay_log_name, | ||
292 | 2193 | TRX_SYS_MYSQL_MASTER_LOG_NAME_LEN); | ||
293 | 2194 | master_log_pos = trx_sys_mysql_master_log_pos; | ||
294 | 2195 | |||
295 | 2196 | skip_overwrite: | ||
296 | 2197 | if (error) { | ||
297 | 2198 | fprintf(stderr, | ||
298 | 2199 | "InnoDB: ERROR: error occured during overwriting " | ||
299 | 2200 | "relay-log.info.\n"); | ||
300 | 2201 | } else { | ||
301 | 2202 | fprintf(stderr, | ||
302 | 2203 | "InnoDB: relay-log.info was overwritten.\n"); | ||
303 | 2204 | } | ||
304 | 2205 | } | ||
305 | 2206 | |||
306 | 2207 | |||
307 | 2096 | /*********************************************************************//** | 2208 | /*********************************************************************//** |
308 | 2097 | Opens an InnoDB database. | 2209 | Opens an InnoDB database. |
309 | 2098 | @return 0 on success, error code on failure */ | 2210 | @return 0 on success, error code on failure */ |
310 | @@ -2221,12 +2333,13 @@ | |||
311 | 2221 | #ifdef HAVE_REPLICATION | 2333 | #ifdef HAVE_REPLICATION |
312 | 2222 | #ifdef MYSQL_SERVER | 2334 | #ifdef MYSQL_SERVER |
313 | 2223 | /* read master log position from relay-log.info if exists */ | 2335 | /* read master log position from relay-log.info if exists */ |
316 | 2224 | char fname[FN_REFLEN+128]; | 2336 | char info_fname[FN_REFLEN]; |
317 | 2225 | int pos; | 2337 | char relay_log_fname[TRX_SYS_MYSQL_MASTER_LOG_NAME_LEN]; |
318 | 2338 | int relay_log_pos; | ||
319 | 2226 | int info_fd; | 2339 | int info_fd; |
320 | 2227 | IO_CACHE info_file; | 2340 | IO_CACHE info_file; |
321 | 2228 | 2341 | ||
323 | 2229 | fname[0] = '\0'; | 2342 | info_fname[0] = '\0'; |
324 | 2230 | 2343 | ||
325 | 2231 | if(innobase_overwrite_relay_log_info) { | 2344 | if(innobase_overwrite_relay_log_info) { |
326 | 2232 | 2345 | ||
327 | @@ -2235,13 +2348,14 @@ | |||
328 | 2235 | " Updates in other storage engines may have problem with consistency.\n"); | 2348 | " Updates in other storage engines may have problem with consistency.\n"); |
329 | 2236 | 2349 | ||
330 | 2237 | bzero((char*) &info_file, sizeof(info_file)); | 2350 | bzero((char*) &info_file, sizeof(info_file)); |
332 | 2238 | fn_format(fname, relay_log_info_file, mysql_data_home, "", 4+32); | 2351 | fn_format(info_fname, relay_log_info_file, mysql_data_home, "", 4+32); |
333 | 2239 | 2352 | ||
334 | 2240 | int error=0; | 2353 | int error=0; |
335 | 2241 | 2354 | ||
337 | 2242 | if (!access(fname,F_OK)) { | 2355 | if (!access(info_fname,F_OK)) { |
338 | 2243 | /* exist */ | 2356 | /* exist */ |
340 | 2244 | if ((info_fd = my_open(fname, O_RDWR|O_BINARY, MYF(MY_WME))) < 0) { | 2357 | if ((info_fd = my_open(info_fname, O_RDWR | O_BINARY, |
341 | 2358 | MYF(MY_WME))) < 0) { | ||
342 | 2245 | error=1; | 2359 | error=1; |
343 | 2246 | } else if (init_io_cache(&info_file, info_fd, IO_SIZE*2, | 2360 | } else if (init_io_cache(&info_file, info_fd, IO_SIZE*2, |
344 | 2247 | READ_CACHE, 0L, 0, MYF(MY_WME))) { | 2361 | READ_CACHE, 0L, 0, MYF(MY_WME))) { |
345 | @@ -2252,16 +2366,18 @@ | |||
346 | 2252 | relay_info_error: | 2366 | relay_info_error: |
347 | 2253 | if (info_fd >= 0) | 2367 | if (info_fd >= 0) |
348 | 2254 | my_close(info_fd, MYF(0)); | 2368 | my_close(info_fd, MYF(0)); |
350 | 2255 | fname[0] = '\0'; | 2369 | master_log_fname[0] = '\0'; |
351 | 2256 | goto skip_relay; | 2370 | goto skip_relay; |
352 | 2257 | } | 2371 | } |
353 | 2258 | } else { | 2372 | } else { |
355 | 2259 | fname[0] = '\0'; | 2373 | master_log_fname[0] = '\0'; |
356 | 2260 | goto skip_relay; | 2374 | goto skip_relay; |
357 | 2261 | } | 2375 | } |
358 | 2262 | 2376 | ||
361 | 2263 | if (init_strvar_from_file(fname, sizeof(fname), &info_file, "") || /* dummy (it is relay-log) */ | 2377 | if (init_strvar_from_file(relay_log_fname, sizeof(relay_log_fname), |
362 | 2264 | init_intvar_from_file(&pos, &info_file, BIN_LOG_HEADER_SIZE)) { | 2378 | &info_file, "") |
363 | 2379 | || /* dummy (it is relay-log) */ init_intvar_from_file( | ||
364 | 2380 | &relay_log_pos, &info_file, BIN_LOG_HEADER_SIZE)) { | ||
365 | 2265 | end_io_cache(&info_file); | 2381 | end_io_cache(&info_file); |
366 | 2266 | error=1; | 2382 | error=1; |
367 | 2267 | goto relay_info_error; | 2383 | goto relay_info_error; |
368 | @@ -2270,13 +2386,19 @@ | |||
369 | 2270 | fprintf(stderr, | 2386 | fprintf(stderr, |
370 | 2271 | "InnoDB: relay-log.info is detected.\n" | 2387 | "InnoDB: relay-log.info is detected.\n" |
371 | 2272 | "InnoDB: relay log: position %u, file name %s\n", | 2388 | "InnoDB: relay log: position %u, file name %s\n", |
379 | 2273 | pos, fname); | 2389 | relay_log_pos, relay_log_fname); |
380 | 2274 | 2390 | ||
381 | 2275 | strncpy(trx_sys_mysql_relay_log_name, fname, TRX_SYS_MYSQL_MASTER_LOG_NAME_LEN); | 2391 | strncpy(trx_sys_mysql_relay_log_name, relay_log_fname, |
382 | 2276 | trx_sys_mysql_relay_log_pos = (ib_int64_t) pos; | 2392 | TRX_SYS_MYSQL_MASTER_LOG_NAME_LEN); |
383 | 2277 | 2393 | trx_sys_mysql_relay_log_pos = (ib_int64_t) relay_log_pos; | |
384 | 2278 | if (init_strvar_from_file(fname, sizeof(fname), &info_file, "") || | 2394 | |
385 | 2279 | init_intvar_from_file(&pos, &info_file, 0)) { | 2395 | strncpy(original_relay_log_fname, relay_log_fname, |
386 | 2396 | TRX_SYS_MYSQL_MASTER_LOG_NAME_LEN); | ||
387 | 2397 | original_relay_log_pos = relay_log_pos; | ||
388 | 2398 | |||
389 | 2399 | if (init_strvar_from_file(master_log_fname, sizeof(master_log_fname), | ||
390 | 2400 | &info_file, "") | ||
391 | 2401 | || init_intvar_from_file(&master_log_pos, &info_file, 0)) { | ||
392 | 2280 | end_io_cache(&info_file); | 2402 | end_io_cache(&info_file); |
393 | 2281 | error=1; | 2403 | error=1; |
394 | 2282 | goto relay_info_error; | 2404 | goto relay_info_error; |
395 | @@ -2284,10 +2406,15 @@ | |||
396 | 2284 | 2406 | ||
397 | 2285 | fprintf(stderr, | 2407 | fprintf(stderr, |
398 | 2286 | "InnoDB: master log: position %u, file name %s\n", | 2408 | "InnoDB: master log: position %u, file name %s\n", |
403 | 2287 | pos, fname); | 2409 | master_log_pos, master_log_fname); |
404 | 2288 | 2410 | ||
405 | 2289 | strncpy(trx_sys_mysql_master_log_name, fname, TRX_SYS_MYSQL_MASTER_LOG_NAME_LEN); | 2411 | strncpy(trx_sys_mysql_master_log_name, master_log_fname, |
406 | 2290 | trx_sys_mysql_master_log_pos = (ib_int64_t) pos; | 2412 | TRX_SYS_MYSQL_MASTER_LOG_NAME_LEN); |
407 | 2413 | trx_sys_mysql_master_log_pos = (ib_int64_t) master_log_pos; | ||
408 | 2414 | |||
409 | 2415 | strncpy(original_master_log_fname, master_log_fname, | ||
410 | 2416 | TRX_SYS_MYSQL_MASTER_LOG_NAME_LEN); | ||
411 | 2417 | original_master_log_pos = master_log_pos; | ||
412 | 2291 | 2418 | ||
413 | 2292 | end_io_cache(&info_file); | 2419 | end_io_cache(&info_file); |
414 | 2293 | if (info_fd >= 0) | 2420 | if (info_fd >= 0) |
415 | @@ -2587,75 +2714,9 @@ | |||
416 | 2587 | goto mem_free_and_error; | 2714 | goto mem_free_and_error; |
417 | 2588 | } | 2715 | } |
418 | 2589 | 2716 | ||
419 | 2590 | #ifdef HAVE_REPLICATION | ||
420 | 2591 | #ifdef MYSQL_SERVER | ||
421 | 2592 | if(innobase_overwrite_relay_log_info) { | 2717 | if(innobase_overwrite_relay_log_info) { |
488 | 2593 | /* If InnoDB progressed from relay-log.info, overwrite it */ | 2718 | innobase_do_overwrite_relay_log_info(); |
489 | 2594 | if (fname[0] == '\0') { | 2719 | } |
424 | 2595 | fprintf(stderr, | ||
425 | 2596 | "InnoDB: something wrong with relay-info.log. InnoDB will not overwrite it.\n"); | ||
426 | 2597 | } else if (0 != strcmp(fname, trx_sys_mysql_master_log_name) | ||
427 | 2598 | || pos != trx_sys_mysql_master_log_pos) { | ||
428 | 2599 | /* Overwrite relay-log.info */ | ||
429 | 2600 | bzero((char*) &info_file, sizeof(info_file)); | ||
430 | 2601 | fn_format(fname, relay_log_info_file, mysql_data_home, "", 4+32); | ||
431 | 2602 | |||
432 | 2603 | int error = 0; | ||
433 | 2604 | |||
434 | 2605 | if (!access(fname,F_OK)) { | ||
435 | 2606 | /* exist */ | ||
436 | 2607 | if ((info_fd = my_open(fname, O_RDWR|O_BINARY, MYF(MY_WME))) < 0) { | ||
437 | 2608 | error = 1; | ||
438 | 2609 | } else if (init_io_cache(&info_file, info_fd, IO_SIZE*2, | ||
439 | 2610 | WRITE_CACHE, 0L, 0, MYF(MY_WME))) { | ||
440 | 2611 | error = 1; | ||
441 | 2612 | } | ||
442 | 2613 | |||
443 | 2614 | if (error) { | ||
444 | 2615 | if (info_fd >= 0) | ||
445 | 2616 | my_close(info_fd, MYF(0)); | ||
446 | 2617 | goto skip_overwrite; | ||
447 | 2618 | } | ||
448 | 2619 | } else { | ||
449 | 2620 | error = 1; | ||
450 | 2621 | goto skip_overwrite; | ||
451 | 2622 | } | ||
452 | 2623 | |||
453 | 2624 | char buff[FN_REFLEN*2+22*2+4], *pos; | ||
454 | 2625 | |||
455 | 2626 | my_b_seek(&info_file, 0L); | ||
456 | 2627 | pos=strmov(buff, trx_sys_mysql_relay_log_name); | ||
457 | 2628 | *pos++='\n'; | ||
458 | 2629 | pos=longlong2str(trx_sys_mysql_relay_log_pos, pos, 10); | ||
459 | 2630 | *pos++='\n'; | ||
460 | 2631 | pos=strmov(pos, trx_sys_mysql_master_log_name); | ||
461 | 2632 | *pos++='\n'; | ||
462 | 2633 | pos=longlong2str(trx_sys_mysql_master_log_pos, pos, 10); | ||
463 | 2634 | *pos='\n'; | ||
464 | 2635 | |||
465 | 2636 | if (my_b_write(&info_file, (uchar*) buff, (size_t) (pos-buff)+1)) | ||
466 | 2637 | error = 1; | ||
467 | 2638 | if (flush_io_cache(&info_file)) | ||
468 | 2639 | error = 1; | ||
469 | 2640 | |||
470 | 2641 | end_io_cache(&info_file); | ||
471 | 2642 | if (info_fd >= 0) | ||
472 | 2643 | my_close(info_fd, MYF(0)); | ||
473 | 2644 | skip_overwrite: | ||
474 | 2645 | if (error) { | ||
475 | 2646 | fprintf(stderr, | ||
476 | 2647 | "InnoDB: ERROR: error occured during overwriting relay-log.info.\n"); | ||
477 | 2648 | } else { | ||
478 | 2649 | fprintf(stderr, | ||
479 | 2650 | "InnoDB: relay-log.info was overwritten.\n"); | ||
480 | 2651 | } | ||
481 | 2652 | } else { | ||
482 | 2653 | fprintf(stderr, | ||
483 | 2654 | "InnoDB: InnoDB and relay-log.info are synchronized. InnoDB will not overwrite it.\n"); | ||
484 | 2655 | } | ||
485 | 2656 | } | ||
486 | 2657 | #endif /* MYSQL_SERVER */ | ||
487 | 2658 | #endif /* HAVE_REPLICATION */ | ||
490 | 2659 | 2720 | ||
491 | 2660 | innobase_open_tables = hash_create(200); | 2721 | innobase_open_tables = hash_create(200); |
492 | 2661 | pthread_mutex_init(&innobase_share_mutex, MY_MUTEX_INIT_FAST); | 2722 | pthread_mutex_init(&innobase_share_mutex, MY_MUTEX_INIT_FAST); |
493 | @@ -2757,38 +2818,50 @@ | |||
494 | 2757 | | HA_ONLINE_ADD_PK_INDEX_NO_WRITES); | 2818 | | HA_ONLINE_ADD_PK_INDEX_NO_WRITES); |
495 | 2758 | } | 2819 | } |
496 | 2759 | 2820 | ||
499 | 2760 | /*****************************************************************//** | 2821 | /****************************************************************//** |
500 | 2761 | Commits a transaction in an InnoDB database. */ | 2822 | Copy the current replication position from MySQL to a transaction. */ |
501 | 2762 | static | 2823 | static |
502 | 2763 | void | 2824 | void |
506 | 2764 | innobase_commit_low( | 2825 | innobase_copy_repl_coords_to_trx( |
507 | 2765 | /*================*/ | 2826 | /*=============================*/ |
508 | 2766 | trx_t* trx) /*!< in: transaction handle */ | 2827 | const THD* thd, /*!< in: thread handle */ |
509 | 2828 | trx_t* trx) /*!< in/out: transaction */ | ||
510 | 2767 | { | 2829 | { |
511 | 2768 | if (trx->conc_state == TRX_NOT_STARTED) { | ||
512 | 2769 | |||
513 | 2770 | return; | ||
514 | 2771 | } | ||
515 | 2772 | |||
516 | 2773 | #ifdef HAVE_REPLICATION | ||
517 | 2774 | #ifdef MYSQL_SERVER | ||
518 | 2775 | THD *thd=current_thd; | ||
519 | 2776 | |||
520 | 2777 | if (thd && thd->slave_thread) { | 2830 | if (thd && thd->slave_thread) { |
522 | 2778 | /* Update the replication position info inside InnoDB */ | 2831 | const Relay_log_info* rli = &active_mi->rli; |
523 | 2832 | |||
524 | 2779 | trx->mysql_master_log_file_name | 2833 | trx->mysql_master_log_file_name |
526 | 2780 | = active_mi->rli.group_master_log_name; | 2834 | = rli->group_master_log_name; |
527 | 2781 | trx->mysql_master_log_pos | 2835 | trx->mysql_master_log_pos |
531 | 2782 | = ((ib_int64_t)active_mi->rli.group_master_log_pos + | 2836 | = ((ib_int64_t)rli->group_master_log_pos |
532 | 2783 | ((ib_int64_t)active_mi->rli.future_event_relay_log_pos - | 2837 | + ((ib_int64_t) |
533 | 2784 | (ib_int64_t)active_mi->rli.group_relay_log_pos)); | 2838 | rli->future_event_relay_log_pos |
534 | 2839 | - (ib_int64_t)rli->group_relay_log_pos)); | ||
535 | 2785 | trx->mysql_relay_log_file_name | 2840 | trx->mysql_relay_log_file_name |
537 | 2786 | = active_mi->rli.group_relay_log_name; | 2841 | = rli->group_relay_log_name; |
538 | 2787 | trx->mysql_relay_log_pos | 2842 | trx->mysql_relay_log_pos |
543 | 2788 | = (ib_int64_t)active_mi->rli.future_event_relay_log_pos; | 2843 | = (ib_int64_t)rli->future_event_relay_log_pos; |
544 | 2789 | } | 2844 | } |
545 | 2790 | #endif /* MYSQL_SERVER */ | 2845 | } |
546 | 2791 | #endif /* HAVE_REPLICATION */ | 2846 | |
547 | 2847 | /*****************************************************************//** | ||
548 | 2848 | Commits a transaction in an InnoDB database. */ | ||
549 | 2849 | static | ||
550 | 2850 | void | ||
551 | 2851 | innobase_commit_low( | ||
552 | 2852 | /*================*/ | ||
553 | 2853 | trx_t* trx) /*!< in: transaction handle */ | ||
554 | 2854 | { | ||
555 | 2855 | if (trx->conc_state == TRX_NOT_STARTED) { | ||
556 | 2856 | |||
557 | 2857 | return; | ||
558 | 2858 | } | ||
559 | 2859 | |||
560 | 2860 | /* Save the current replication position for write to trx sys header | ||
561 | 2861 | for undo purposes, see the comment at corresponding call at | ||
562 | 2862 | innobase_xa_prepare(). */ | ||
563 | 2863 | |||
564 | 2864 | innobase_copy_repl_coords_to_trx(current_thd, trx); | ||
565 | 2792 | 2865 | ||
566 | 2793 | trx_commit_for_mysql(trx); | 2866 | trx_commit_for_mysql(trx); |
567 | 2794 | } | 2867 | } |
568 | @@ -2898,6 +2971,9 @@ | |||
569 | 2898 | if (all | 2971 | if (all |
570 | 2899 | || (!thd_test_options(thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))) { | 2972 | || (!thd_test_options(thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))) { |
571 | 2900 | 2973 | ||
572 | 2974 | DBUG_EXECUTE_IF("crash_innodb_before_commit", | ||
573 | 2975 | DBUG_SUICIDE();); | ||
574 | 2976 | |||
575 | 2901 | /* We were instructed to commit the whole transaction, or | 2977 | /* We were instructed to commit the whole transaction, or |
576 | 2902 | this is an SQL statement end and autocommit is on */ | 2978 | this is an SQL statement end and autocommit is on */ |
577 | 2903 | 2979 | ||
578 | @@ -10657,7 +10733,27 @@ | |||
579 | 10657 | 10733 | ||
580 | 10658 | ut_ad(trx->active_trans); | 10734 | ut_ad(trx->active_trans); |
581 | 10659 | 10735 | ||
582 | 10736 | /* Update the replication position info in current trx. This | ||
583 | 10737 | is different from the binlog position update that happens | ||
584 | 10738 | during XA COMMIT. In contrast to that, the slave position is | ||
585 | 10739 | an actual part of the changes made by this transaction and thus | ||
586 | 10740 | must be updated in the XA PREPARE stage. Since the trx sys | ||
587 | 10741 | header page changes are not undo-logged, again store this | ||
588 | 10742 | position in a different field in the XA COMMIT stage, so that | ||
589 | 10743 | it might be used in case of rollbacks. */ | ||
590 | 10744 | |||
591 | 10745 | /* Since currently there might be only one slave SQL thread, we | ||
592 | 10746 | don't need to take any precautions (e.g. prepare_commit_mutex) | ||
593 | 10747 | to ensure position ordering. Revisit this in 5.6 which has | ||
594 | 10748 | both the multi-threaded replication to cause us problems and | ||
595 | 10749 | the group commit to solve them. */ | ||
596 | 10750 | |||
597 | 10751 | innobase_copy_repl_coords_to_trx(thd, trx); | ||
598 | 10752 | |||
599 | 10660 | error = (int) trx_prepare_for_mysql(trx); | 10753 | error = (int) trx_prepare_for_mysql(trx); |
600 | 10754 | |||
601 | 10755 | DBUG_EXECUTE_IF("crash_innodb_after_prepare", | ||
602 | 10756 | DBUG_SUICIDE();); | ||
603 | 10661 | } else { | 10757 | } else { |
604 | 10662 | /* We just mark the SQL statement ended and do not do a | 10758 | /* We just mark the SQL statement ended and do not do a |
605 | 10663 | transaction prepare */ | 10759 | transaction prepare */ |
606 | @@ -10780,6 +10876,22 @@ | |||
607 | 10780 | if (trx) { | 10876 | if (trx) { |
608 | 10781 | int ret = innobase_rollback_trx(trx); | 10877 | int ret = innobase_rollback_trx(trx); |
609 | 10782 | trx_free_for_background(trx); | 10878 | trx_free_for_background(trx); |
610 | 10879 | |||
611 | 10880 | if (innobase_overwrite_relay_log_info) { | ||
612 | 10881 | |||
613 | 10882 | /* On rollback of a prepared transaction revert the | ||
614 | 10883 | current slave positions to the ones recorded by the | ||
615 | 10884 | last COMMITTed transaction. This has an effect of | ||
616 | 10885 | undoing the position change caused by the transaction | ||
617 | 10886 | being rolled back. Assumes single-threaded slave SQL | ||
618 | 10887 | thread. If the server has non-master write traffic | ||
619 | 10888 | with XA rollbacks, this will cause additional spurious | ||
620 | 10889 | slave info log overwrites, which should be harmless. */ | ||
621 | 10890 | |||
622 | 10891 | trx_sys_print_committed_mysql_master_log_pos(); | ||
623 | 10892 | innobase_do_overwrite_relay_log_info(); | ||
624 | 10893 | } | ||
625 | 10894 | |||
626 | 10783 | return(ret); | 10895 | return(ret); |
627 | 10784 | } else { | 10896 | } else { |
628 | 10785 | return(XAER_NOTA); | 10897 | return(XAER_NOTA); |
629 | 10786 | 10898 | ||
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-17 02:51:27 +0000 | |||
633 | @@ -357,6 +357,14 @@ | |||
634 | 357 | trx_sys_print_mysql_binlog_offset(void); | 357 | trx_sys_print_mysql_binlog_offset(void); |
635 | 358 | /*===================================*/ | 358 | /*===================================*/ |
636 | 359 | /*****************************************************************//** | 359 | /*****************************************************************//** |
637 | 360 | Prints to stderr the MySQL master log offset info in the trx system header | ||
638 | 361 | COMMIT set of fields if the magic number shows it valid and stores it | ||
639 | 362 | in global variables. */ | ||
640 | 363 | UNIV_INTERN | ||
641 | 364 | void | ||
642 | 365 | trx_sys_print_committed_mysql_master_log_pos(void); | ||
643 | 366 | /*==============================================*/ | ||
644 | 367 | /*****************************************************************//** | ||
645 | 360 | Prints to stderr the MySQL master log offset info in the trx system header if | 368 | Prints to stderr the MySQL master log offset info in the trx system header if |
646 | 361 | the magic number shows it valid. */ | 369 | the magic number shows it valid. */ |
647 | 362 | UNIV_INTERN | 370 | UNIV_INTERN |
648 | @@ -536,10 +544,16 @@ | |||
649 | 536 | //# error "UNIV_PAGE_SIZE < 4096" | 544 | //# error "UNIV_PAGE_SIZE < 4096" |
650 | 537 | //#endif | 545 | //#endif |
651 | 538 | /** The offset of the MySQL replication info in the trx system header; | 546 | /** The offset of the MySQL replication info in the trx system header; |
653 | 539 | this contains the same fields as TRX_SYS_MYSQL_LOG_INFO below */ | 547 | this contains the same fields as TRX_SYS_MYSQL_LOG_INFO below. These are |
654 | 548 | written at prepare time and are the main copy. */ | ||
655 | 540 | #define TRX_SYS_MYSQL_MASTER_LOG_INFO (UNIV_PAGE_SIZE - 2000) | 549 | #define TRX_SYS_MYSQL_MASTER_LOG_INFO (UNIV_PAGE_SIZE - 2000) |
656 | 541 | #define TRX_SYS_MYSQL_RELAY_LOG_INFO (UNIV_PAGE_SIZE - 1500) | 550 | #define TRX_SYS_MYSQL_RELAY_LOG_INFO (UNIV_PAGE_SIZE - 1500) |
657 | 542 | 551 | ||
658 | 552 | /** The copy of the above which is made at transaction COMMIT time. If binlog | ||
659 | 553 | crash recovery rollbacks a PREPAREd transaction, they are copied back. */ | ||
660 | 554 | #define TRX_SYS_COMMIT_MASTER_LOG_INFO (UNIV_PAGE_SIZE - 3000) | ||
661 | 555 | #define TRX_SYS_COMMIT_RELAY_LOG_INFO (UNIV_PAGE_SIZE - 2500) | ||
662 | 556 | |||
663 | 543 | /** The offset of the MySQL binlog offset info in the trx system header */ | 557 | /** The offset of the MySQL binlog offset info in the trx system header */ |
664 | 544 | #define TRX_SYS_MYSQL_LOG_INFO (UNIV_PAGE_SIZE - 1000) | 558 | #define TRX_SYS_MYSQL_LOG_INFO (UNIV_PAGE_SIZE - 1000) |
665 | 545 | #define TRX_SYS_MYSQL_LOG_MAGIC_N_FLD 0 /*!< magic number which is | 559 | #define TRX_SYS_MYSQL_LOG_MAGIC_N_FLD 0 /*!< magic number which is |
666 | 546 | 560 | ||
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-17 02:51:27 +0000 | |||
670 | @@ -947,8 +947,31 @@ | |||
671 | 947 | } | 947 | } |
672 | 948 | 948 | ||
673 | 949 | /*****************************************************************//** | 949 | /*****************************************************************//** |
676 | 950 | Prints to stderr the MySQL master log offset info in the trx system header if | 950 | Reads the log coordinates at the given offset in the trx sys header. */ |
677 | 951 | the magic number shows it valid. */ | 951 | static |
678 | 952 | void | ||
679 | 953 | trx_sys_read_log_pos( | ||
680 | 954 | /*=================*/ | ||
681 | 955 | const trx_sysf_t* sys_header, /*!< in: the trx sys header */ | ||
682 | 956 | uint header_offset, /*!< in: coord offset in the | ||
683 | 957 | header */ | ||
684 | 958 | char* log_fn, /*!< out: the log file name */ | ||
685 | 959 | ib_int64_t* log_pos) /*!< out: the log poistion */ | ||
686 | 960 | { | ||
687 | 961 | ut_memcpy(log_fn, sys_header + header_offset + TRX_SYS_MYSQL_LOG_NAME, | ||
688 | 962 | TRX_SYS_MYSQL_MASTER_LOG_NAME_LEN); | ||
689 | 963 | |||
690 | 964 | *log_pos = | ||
691 | 965 | (((ib_int64_t)mach_read_from_4(sys_header + header_offset | ||
692 | 966 | + TRX_SYS_MYSQL_LOG_OFFSET_HIGH)) << 32) | ||
693 | 967 | + mach_read_from_4(sys_header + header_offset | ||
694 | 968 | + TRX_SYS_MYSQL_LOG_OFFSET_LOW); | ||
695 | 969 | } | ||
696 | 970 | |||
697 | 971 | /*****************************************************************//** | ||
698 | 972 | Prints to stderr the MySQL master log offset info in the trx system header | ||
699 | 973 | PREPARE set of fields if the magic number shows it valid and stores it | ||
700 | 974 | in global variables. */ | ||
701 | 952 | UNIV_INTERN | 975 | UNIV_INTERN |
702 | 953 | void | 976 | void |
703 | 954 | trx_sys_print_mysql_master_log_pos(void) | 977 | trx_sys_print_mysql_master_log_pos(void) |
704 | @@ -970,60 +993,79 @@ | |||
705 | 970 | return; | 993 | return; |
706 | 971 | } | 994 | } |
707 | 972 | 995 | ||
708 | 973 | fprintf(stderr, | ||
709 | 974 | "InnoDB: In a MySQL replication slave the last" | ||
710 | 975 | " master binlog file\n" | ||
711 | 976 | "InnoDB: position %lu %lu, file name %s\n", | ||
712 | 977 | (ulong) mach_read_from_4(sys_header | ||
713 | 978 | + TRX_SYS_MYSQL_MASTER_LOG_INFO | ||
714 | 979 | + TRX_SYS_MYSQL_LOG_OFFSET_HIGH), | ||
715 | 980 | (ulong) mach_read_from_4(sys_header | ||
716 | 981 | + TRX_SYS_MYSQL_MASTER_LOG_INFO | ||
717 | 982 | + TRX_SYS_MYSQL_LOG_OFFSET_LOW), | ||
718 | 983 | sys_header + TRX_SYS_MYSQL_MASTER_LOG_INFO | ||
719 | 984 | + TRX_SYS_MYSQL_LOG_NAME); | ||
720 | 985 | |||
721 | 986 | fprintf(stderr, | ||
722 | 987 | "InnoDB: and relay log file\n" | ||
723 | 988 | "InnoDB: position %lu %lu, file name %s\n", | ||
724 | 989 | (ulong) mach_read_from_4(sys_header | ||
725 | 990 | + TRX_SYS_MYSQL_RELAY_LOG_INFO | ||
726 | 991 | + TRX_SYS_MYSQL_LOG_OFFSET_HIGH), | ||
727 | 992 | (ulong) mach_read_from_4(sys_header | ||
728 | 993 | + TRX_SYS_MYSQL_RELAY_LOG_INFO | ||
729 | 994 | + TRX_SYS_MYSQL_LOG_OFFSET_LOW), | ||
730 | 995 | sys_header + TRX_SYS_MYSQL_RELAY_LOG_INFO | ||
731 | 996 | + TRX_SYS_MYSQL_LOG_NAME); | ||
732 | 997 | |||
733 | 998 | /* Copy the master log position info to global variables we can | 996 | /* Copy the master log position info to global variables we can |
734 | 999 | use in ha_innobase.cc to initialize glob_mi to right values */ | 997 | use in ha_innobase.cc to initialize glob_mi to right values */ |
762 | 1000 | 998 | trx_sys_read_log_pos(sys_header, TRX_SYS_MYSQL_MASTER_LOG_INFO, | |
763 | 1001 | ut_memcpy(trx_sys_mysql_master_log_name, | 999 | trx_sys_mysql_master_log_name, |
764 | 1002 | sys_header + TRX_SYS_MYSQL_MASTER_LOG_INFO | 1000 | &trx_sys_mysql_master_log_pos); |
765 | 1003 | + TRX_SYS_MYSQL_LOG_NAME, | 1001 | |
766 | 1004 | TRX_SYS_MYSQL_MASTER_LOG_NAME_LEN); | 1002 | trx_sys_read_log_pos(sys_header, TRX_SYS_MYSQL_RELAY_LOG_INFO, |
767 | 1005 | 1003 | trx_sys_mysql_relay_log_name, | |
768 | 1006 | trx_sys_mysql_master_log_pos | 1004 | &trx_sys_mysql_relay_log_pos); |
769 | 1007 | = (((ib_int64_t) mach_read_from_4( | 1005 | |
770 | 1008 | sys_header + TRX_SYS_MYSQL_MASTER_LOG_INFO | 1006 | mtr_commit(&mtr); |
771 | 1009 | + TRX_SYS_MYSQL_LOG_OFFSET_HIGH)) << 32) | 1007 | |
772 | 1010 | + ((ib_int64_t) mach_read_from_4( | 1008 | fprintf(stderr, |
773 | 1011 | sys_header + TRX_SYS_MYSQL_MASTER_LOG_INFO | 1009 | "InnoDB: In a MySQL replication slave the last" |
774 | 1012 | + TRX_SYS_MYSQL_LOG_OFFSET_LOW)); | 1010 | " master binlog file\n" |
775 | 1013 | 1011 | "InnoDB: position %llu, file name %s\n", | |
776 | 1014 | ut_memcpy(trx_sys_mysql_relay_log_name, | 1012 | trx_sys_mysql_master_log_pos, |
777 | 1015 | sys_header + TRX_SYS_MYSQL_RELAY_LOG_INFO | 1013 | trx_sys_mysql_master_log_name); |
778 | 1016 | + TRX_SYS_MYSQL_LOG_NAME, | 1014 | |
779 | 1017 | TRX_SYS_MYSQL_MASTER_LOG_NAME_LEN); | 1015 | fprintf(stderr, |
780 | 1018 | 1016 | "InnoDB: and relay log file\n" | |
781 | 1019 | trx_sys_mysql_relay_log_pos | 1017 | "InnoDB: position %llu, file name %s\n", |
782 | 1020 | = (((ib_int64_t) mach_read_from_4( | 1018 | trx_sys_mysql_relay_log_pos, |
783 | 1021 | sys_header + TRX_SYS_MYSQL_RELAY_LOG_INFO | 1019 | trx_sys_mysql_relay_log_name); |
784 | 1022 | + TRX_SYS_MYSQL_LOG_OFFSET_HIGH)) << 32) | 1020 | } |
785 | 1023 | + ((ib_int64_t) mach_read_from_4( | 1021 | |
786 | 1024 | sys_header + TRX_SYS_MYSQL_RELAY_LOG_INFO | 1022 | /*****************************************************************//** |
787 | 1025 | + TRX_SYS_MYSQL_LOG_OFFSET_LOW)); | 1023 | Prints to stderr the MySQL master log offset info in the trx system header |
788 | 1026 | mtr_commit(&mtr); | 1024 | COMMIT set of fields if the magic number shows it valid and stores it |
789 | 1025 | in global variables. */ | ||
790 | 1026 | UNIV_INTERN | ||
791 | 1027 | void | ||
792 | 1028 | trx_sys_print_committed_mysql_master_log_pos(void) | ||
793 | 1029 | /*==============================================*/ | ||
794 | 1030 | { | ||
795 | 1031 | trx_sysf_t* sys_header; | ||
796 | 1032 | mtr_t mtr; | ||
797 | 1033 | |||
798 | 1034 | mtr_start(&mtr); | ||
799 | 1035 | |||
800 | 1036 | sys_header = trx_sysf_get(&mtr); | ||
801 | 1037 | |||
802 | 1038 | if (mach_read_from_4(sys_header + TRX_SYS_COMMIT_MASTER_LOG_INFO | ||
803 | 1039 | + TRX_SYS_MYSQL_LOG_MAGIC_N_FLD) | ||
804 | 1040 | != TRX_SYS_MYSQL_LOG_MAGIC_N) { | ||
805 | 1041 | |||
806 | 1042 | mtr_commit(&mtr); | ||
807 | 1043 | |||
808 | 1044 | return; | ||
809 | 1045 | } | ||
810 | 1046 | |||
811 | 1047 | /* Copy the master log position info to global variables we can | ||
812 | 1048 | use in ha_innobase.cc to initialize glob_mi to right values */ | ||
813 | 1049 | trx_sys_read_log_pos(sys_header, TRX_SYS_COMMIT_MASTER_LOG_INFO, | ||
814 | 1050 | trx_sys_mysql_master_log_name, | ||
815 | 1051 | &trx_sys_mysql_master_log_pos); | ||
816 | 1052 | |||
817 | 1053 | trx_sys_read_log_pos(sys_header, TRX_SYS_COMMIT_RELAY_LOG_INFO, | ||
818 | 1054 | trx_sys_mysql_relay_log_name, | ||
819 | 1055 | &trx_sys_mysql_relay_log_pos); | ||
820 | 1056 | |||
821 | 1057 | mtr_commit(&mtr); | ||
822 | 1058 | |||
823 | 1059 | fprintf(stderr, | ||
824 | 1060 | "InnoDB: In a MySQL replication slave the last" | ||
825 | 1061 | " master binlog file\n" | ||
826 | 1062 | "InnoDB: position %llu, file name %s\n", | ||
827 | 1063 | trx_sys_mysql_master_log_pos, trx_sys_mysql_master_log_name); | ||
828 | 1064 | |||
829 | 1065 | fprintf(stderr, | ||
830 | 1066 | "InnoDB: and relay log file\n" | ||
831 | 1067 | "InnoDB: position %llu, file name %s\n", | ||
832 | 1068 | trx_sys_mysql_relay_log_pos, trx_sys_mysql_relay_log_name); | ||
833 | 1027 | } | 1069 | } |
834 | 1028 | 1070 | ||
835 | 1029 | /****************************************************************//** | 1071 | /****************************************************************//** |
836 | 1030 | 1072 | ||
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-17 02:51:27 +0000 | |||
840 | @@ -904,12 +904,12 @@ | |||
841 | 904 | sys_header, | 904 | sys_header, |
842 | 905 | trx->mysql_relay_log_file_name, | 905 | trx->mysql_relay_log_file_name, |
843 | 906 | trx->mysql_relay_log_pos, | 906 | trx->mysql_relay_log_pos, |
845 | 907 | TRX_SYS_MYSQL_RELAY_LOG_INFO, &mtr); | 907 | TRX_SYS_COMMIT_RELAY_LOG_INFO, &mtr); |
846 | 908 | trx_sys_update_mysql_binlog_offset( | 908 | trx_sys_update_mysql_binlog_offset( |
847 | 909 | sys_header, | 909 | sys_header, |
848 | 910 | trx->mysql_master_log_file_name, | 910 | trx->mysql_master_log_file_name, |
849 | 911 | trx->mysql_master_log_pos, | 911 | trx->mysql_master_log_pos, |
851 | 912 | TRX_SYS_MYSQL_MASTER_LOG_INFO, &mtr); | 912 | TRX_SYS_COMMIT_MASTER_LOG_INFO, &mtr); |
852 | 913 | trx->mysql_master_log_file_name = ""; | 913 | trx->mysql_master_log_file_name = ""; |
853 | 914 | } | 914 | } |
854 | 915 | 915 | ||
855 | @@ -2002,6 +2002,23 @@ | |||
856 | 2002 | 2002 | ||
857 | 2003 | mutex_exit(&(rseg->mutex)); | 2003 | mutex_exit(&(rseg->mutex)); |
858 | 2004 | 2004 | ||
859 | 2005 | if (trx->mysql_master_log_file_name[0] != '\0') { | ||
860 | 2006 | /* This database server is a MySQL replication slave */ | ||
861 | 2007 | trx_sysf_t* sys_header = trx_sysf_get(&mtr); | ||
862 | 2008 | |||
863 | 2009 | trx_sys_update_mysql_binlog_offset( | ||
864 | 2010 | sys_header, | ||
865 | 2011 | trx->mysql_relay_log_file_name, | ||
866 | 2012 | trx->mysql_relay_log_pos, | ||
867 | 2013 | TRX_SYS_MYSQL_RELAY_LOG_INFO, &mtr); | ||
868 | 2014 | trx_sys_update_mysql_binlog_offset( | ||
869 | 2015 | sys_header, | ||
870 | 2016 | trx->mysql_master_log_file_name, | ||
871 | 2017 | trx->mysql_master_log_pos, | ||
872 | 2018 | TRX_SYS_MYSQL_MASTER_LOG_INFO, &mtr); | ||
873 | 2019 | trx->mysql_master_log_file_name = ""; | ||
874 | 2020 | } | ||
875 | 2021 | |||
876 | 2005 | /*--------------*/ | 2022 | /*--------------*/ |
877 | 2006 | mtr_commit(&mtr); /* This mtr commit makes the | 2023 | mtr_commit(&mtr); /* This mtr commit makes the |
878 | 2007 | transaction prepared in the file-based | 2024 | transaction prepared in the file-based |
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.