Skip to content

Commit f4c37f7

Browse files
author
Andrei Elkin
committed
WL#6860 Binlogging XA-prepared transaction
ChangeLog --------- Fri Mar 6 17:44:42 EET 2015 Resolving conflicts at merging to 5.7. Fri Mar 6 13:59:13 EET 2015 - fixing innodb transaction freeing that was missed out in a case of 1phase xa through mysqlbinlog applier. Restructuring an if to comply to innodb style, as earlier requested by Marko. Fixing an assert, not dealing directly with the WL per him as well. Thu Mar 5 08:50:38 EET 2015 - Compilation in innodb got broken on some platforms with the last patch. Fixed now. Wed Mar 4 19:13:52 EET 2015 - XA COMMIT ONE PHASE at replaying from binlog made binlog.binlog_xa_prepared_disconnect to cause failures in other tests masquerading to bug19502202. Yet the reason turned out to be missed re-attachment of storage engine trans context, that matches previous detachment. Fixed and the test is augmented to catch the failure alone. Small changes are done to innodb.cc and handler.cc. Tue Mar 3 21:35:28 EET 2015 - fixing more non-deterministic cases that PB2 reveals 1. main.xa: I left disconnect to run wo/ generally needed synchronisation with connection that runs XA recover. I did not like to contrain the test with P_S dependency. Added warnings and todo, if the warning will come true; 2. rpl_xa_survive_crash_debug: found a reason of result mismatch, fixed *it*, but the test fails sporadically. I suspect --error 2013; 3. sys_vars.innodb_support_xa_func: fixed - ending cleanup requested by Dmitry at today's review of xa.cc and sql_plugin.* changes. Hunks from the latter pair of files are relocated onto xa.*. - adding support and test for mysqlbinlog recovery for XA-COMMIT-ONE-PHASE; Tue Mar 3 16:59:14 EET 2015 - determinism in binlog_xa_prepared_disconnect (gtid on/off), and rpl_xa_survive_crash_debug (binlog format, synchronisation) - fixes to Bug20608551 (LiBing's contribution). Tue Mar 3 11:59:43 EET 2015 - Changes are done to support "mysqlbinlog | mysql | mysqld" recovery, making couple of log_event.cc static functions to turn to public into sql_plugin.cc,h and applier_reset_xa_trans() is defined in xa.cc. binlog_xa_prepared.test is extended to cover the case; - XA COMMIT/ROLLBACK vs GTID_NEXT testing is added; - Bug20616249 fixes are incorporated with the WL patch; - cleanup in done in xa.cc,h Fri Feb 27 18:30:28 EET 2015 - Incorrect ordering of rollback to binlog and SE is fixed. XA-rollback is written first now. That must be the most probable reason of bug20616249; - set @@gtid_next and following XA-commit,rollback worked incorrectly in few ways: a. mysql.gtid_executed on slave missed records b. set @@gtid_next could not be set to another "manual" value 'cos of uncleared status of previous assignment done to the first logging phase of XA START..PREPARE Tests are extend to cover b. - Crash simulation in the middle of XA-rollback is added to prove the existing policy of survival of the prepared XA is not gone, as well as to prove correct logging ordering (see above). Tue Feb 24 12:46:33 EET 2015 Updating few test result files: - XA basic framework main.xa complained about mismatch expectedly 'cos of having disconnect of a prepared transaction; - binlog_xa_prepared.test is slightly cleaned not to depend on preceeding tests that may contribute to binlog which is printed out to show new valid logging pattern. Fixing compilation on win; Todo: rpl_gtids_table_disable_binlog_on_slave seems to have caught mysql.gtid_executed updating by two-phased logged XA, under investigation. Mon Feb 23 21:24:48 EET 2015 Fixing failed tests on hundson. i_binlog.binlog_loose_XA_trans.test did not expect new XA-START query, corrected; binlog.binlog_xa_prepared_disconnect failed 'cos of a previous test, its correctness verification clause is refined to account that; rpl.rpl_gtids_table_disable_binlog_on_slave did not expect two-phase logging, GTID_NEXT handler did not let to change the value after XA-PREPARE which must be done each time a "manual" GTID_NEXT prepands XA-START. check_super_outside_prepared_trx_outside_sf() is introduced to refine a former GTID_NEXT check function. Also a minor bug in updating GTID_EXECUTED is fixed when XA COMMIT is invoked from another connection (through "recovery" interface). The test was extensively cleaned from all way using (incl copy-pasting) integer constants. compilation on embedded is fixed. Fri Feb 20 20:06:24 EET 2015 Addressing Shiv's final notes dealing with cleanup and undoing a result file. Fri Feb 20 13:22:11 EET 2015 Cleanup is do to - replacing xid methods with more appropriate, adding a new m_is_binlogged to the XID_STATE constructor initializer list; - dismantling st_replace_native_trx_args; - restoring help--no-win results. Thu Feb 19 19:05:49 EET 2015 --xa_survive_disconnect option is removed; changes around m_native_trx_ptr that is turned into THD::ha_data.ha_ptr_backup to provide one-to-many association THD to SE (multiple engines in on XA transaction) rather than 1-to-1; removing unneeded tests, renaming in remained; fixing rpl_trx_boundary_parser_warning (announced but slipped from yesterday patch); various consmetics: empty new lines for coding standard (announced but slipped from yesterday patch); renaming, few cosmentics Wed Feb 18 20:08:20 EET 2015 Cosmetics requested by Luis and Dmitry: renaming, adding empty line as separator throughout the patch, rpl_trx_boundary_parser_warning references to explicit log_pos are elminated 'cos the test started failing due to FD's grown one byte by the fixes. todo: sort out need of --xa_survive_disconnect option, raised by Luis. Upon that I'll take care of tests that are new-option sensitive. Wed Feb 18 09:43:15 EET 2015 A bug found out in that updating slave_relay_log_info table at XA_prepare handling ended up in locking the table for following transactions. It's fixed with refining flush_info() conditions to chose the file repo branch for the method invocation in this XA_prepare case. Fri Feb 13 20:25:36 EET 2015 Addressed - the final Marko's notes (tests related) - few notes from Dmitry - renaming a new transaction_ctx member - cleanup in trans_xa_prepare() as well as removed open questions to refer to new reported bug. In the bug report it's suggested to correct the error code and specify details of prepare failure. We won't automatically add XA ROLLBACK in this unlikely case. Thu Feb 12 14:36:29 EET 2015 xa_prepared_binlog_off is fixed in the assert part which could not run correctly due to log_bin is OFF in this test. Cosmetic changes in few tests, and picking up Marko's assert. Fri Feb 6 18:13:37 EET 2015 Refining the last commit's solution to syncronize the exiting connection's THD::cleanup with a follower connection through SELECTing from P_S.threads. That makes the test available wo/ DBUG, but requirs P_S. xa.h's start_recovery_xa() is made of two arguments. The new one carries m_is_binlogged value. Fri Feb 6 12:06:57 EET 2015 Changes in tests motivated by 1. It turned that there's no SQL way of learning by the killer or by an external connection that a prepared trx of one that is supposed to be gone is available. Methods based on `show processlist' or SELECT from I_S do *not* work! The exiting connect is not in the result list, but its THD may not have been passed through cleanup() method. I worked it around with dbug_sync. Here and in other place incl other tests. 2. gtid asserts added to main.xa_prepared_binlog_off and binlog.binlog_prepared_disconnect XID::m_is_binlogged flagging is fixed. In the previous vesion the member may be left uninitialized. Thu Feb 5 11:44:41 EET 2015 Fixing some tests (not full addressing yet) per Shiv's notes; making 2nd of two ser_buf_size declarations compilable everywhere, the issue was spotted by Dmitry. da todo: address the rest of sticking out notes, by Marko and Shiv, in the following commit. Wed Feb 4 22:22:26 EET 2015 opt_xa_prepared_rollback_at_disconnect is renamed to opt_xa_survive_disconnect; due to semantics got inverted, its value had to be inverted in sources; innodb cleanup is done; binlog_xa_prepared_do_and_restart.inc refactored to introduce another sourced include, extended; tests renaming is done per reviewers and the renaming above. Wed Feb 4 14:40:20 EET 2015 Asserting the new and old trx properties in innodb_replace_trx_in_thd. It's also revealed a flaw in arguments passing (fixed: see changes around get_slave_trx_orig()); fixed visibility in control_events.h per Dmitry's request, and compilation of static const XID_t::ser_buf_size; perfected binlog_xa_prepared_do_and_restart.inc to invoke a new extra/binlog_tests/binlog_xa_prepare_connection.inc to initiate connections with certain properties. Tue Feb 3 15:38:43 EET 2015 Fixing Marko's style complains, extending tests per his suggestion. An dbug-sync assert was found in innodb, explained and worked around. Potential non-determinism of XA RECOVER in tests like binlog_xa_prepared_disconnect is eliminated. Mon Feb 2 12:25:28 EET 2015 Cleanup, merge with trunk. Addressed remained notes by Marko. Futher extension to xa_prepared_binlog_off and binlog_xa_prepared_disconnect is done to disconnect prepared XA with the server shutdown. Thu Jan 29 15:01:48 EET 2015 Replaced --sleep 1 in binlog_xa_prepared and eliminated the same race in rpl_xa_old_logging; Found an issue and corrected XA COMMIT ONE PHASE. It's fixed with making XA_prepare_log_event to record the value of ONE_PHASE option. It case the new bool member is true the event commits the current group. Added tests for this case (rpl_xa_old,new_logging). Fixed compilation issue due to a incomplete renaming done in innodb; Extended rpl_xa_old,new_logging with random XID generation and made more XA transaction to disconnect. -- TODO: Self-review, and hand to reviewers to finish their work. Tue Jan 27 22:35:06 EET 2015 Addressing all Marko's notes. Adding up 2pc deregistration into the "read-only" XA prepared branch of innobase_close_connection() (Marko, plz assess); Extending testing base with adding more tests to extra/binlog_tests/binlog_xa_prepared.test, a common source for either --skip-log-bin and --log-bin top-level test files of xa_prepared_binlog_off and binlog_xa_prepared_disconnect. There're already notes from Dmitry who left me them on IM, to be addressed in tomorrow patch. TODO: 1. replace --sleep 1 made in binlog_xa_prepared.test to avoid race of connection close and XA COMMIT from another connection. 2. eliminate the same race in rpl_xa_old_logging 3. Address Dmitry's comments and get it fully reviewed. Tue Jan 27 10:10:44 EET 2015 After --skip-log-bin support opened by the previous patch an issue was revealed in that "read_only" prepared XA transation cleanup was not conducted properly to assert in innodb assert ( rw_trx_list.len >= n_prepared_trx). The "read-only" trx must've been rolled back and get to proper state. This patch corrects that issue. Few review notes (by Marko) are addressed as well. These include inlines and white space consmetics. Fri Jan 23 14:30:43 EET 2015 The final notes are cleared. Fri Jan 23 12:44:04 EET 2015 Addressed Neha's documentation and cleanup related comments. Thu Jan 22 12:51:15 EET 2015 Addressed all points by Neha (related to WL7440). Wed Jan 21 17:05:33 EET 2015 Merging with libbinlogevent is done (uint4korr() replaced). Wed Jan 22 This patch merges few WL:s pushed to the trunk as well addresses few notes made by reviewers. The external WL that caused changes are wl7440, wl7592, trx_boundary_parser. This patch does not fix two items present on RB:7755 atm: TODO/FIXME: trx_t::is_recovered life time to settle down. The WL6860 agenda ----------------- The WL addresses long time standing limitation of XA support in the server. When the server runs with replication (binary log) turn on prepared XA transaction had to be rolled back at disconnection Bug#11745231 (bugs.mysql.com/12161) contains the whole story of complains. This worklog adds support for XA-transactions to make them sustaining connection close or server restart without any harm to replication. For backward compatibility a new server option/global-read-only-var is introduced: --xa_prepared_rollback_at_disconnect to have the default value to comply with the rollback "old" behavior. The Worklog patch consists of - binary logging extension to write prepared XA and its Commit or Rollback decision as separate group of events into the binary log. That makes XA-binlogging possibly interleaving yet without any harm to data consistency after replaying on the slave. - slave applier extension to handle XA-prepared and its termination (Commit or Rollback) event - extension to XA recovery implementation in that connection closing leaves a prepared XA in the transaction cache as well as specially marked in Innodb. Such prepared XA can be discovered and terminated as the user wishes, as well as by the slave applier - extension to handlerton interface to add up interface allowing attach and detach a SE "internal" transaction from the server level transaction handle - augmentment to connection close logics in Innodb as well as changes to maintain disconnected transaction's state sane to survive the server restart. Conflicts: sql/xa.h
1 parent c527e60 commit f4c37f7

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

53 files changed

+5467
-186
lines changed

libbinlogevents/include/binlog_event.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -323,6 +323,8 @@ enum Log_event_type
323323

324324
VIEW_CHANGE_EVENT= 37,
325325

326+
/* Prepared XA transaction terminal event similar to Xid */
327+
XA_PREPARE_LOG_EVENT= 38,
326328
/**
327329
Add new events here - right above this comment!
328330
Existing events (except ENUM_END_EVENT) should never change their numbers
@@ -782,7 +784,8 @@ class Binary_log_event
782784
IGNORABLE_HEADER_LEN= 0,
783785
ROWS_HEADER_LEN_V2= 10,
784786
TRANSACTION_CONTEXT_HEADER_LEN= 18,
785-
VIEW_CHANGE_HEADER_LEN= 53
787+
VIEW_CHANGE_HEADER_LEN= 53,
788+
XA_PREPARE_HEADER_LEN= 0
786789
}; // end enum_post_header_length
787790
protected:
788791
/**

libbinlogevents/include/control_events.h

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -649,6 +649,106 @@ class Xid_event: public Binary_log_event
649649
#endif
650650
};
651651

652+
/**
653+
@class XA_prepare_event
654+
655+
An XA_prepare event is generated for a XA prepared transaction.
656+
Like Xid_event it contans XID of the *prepared* transaction.
657+
658+
@section XA_prepare_event_binary_format Binary Format
659+
660+
The Body has the following component:
661+
662+
<table>
663+
<caption>Body for XA_prepare_event</caption>
664+
665+
<tr>
666+
<th>Name</th>
667+
<th>Format</th>
668+
<th>Description</th>
669+
</tr>
670+
671+
<tr>
672+
<td>my_xid</td>
673+
<td>a struct similar to mysql/plugin.h containing three members.</td>
674+
<td>serialized XID representation of XA transaction.</td>
675+
</tr>
676+
677+
<tr>
678+
<td>xid</td>
679+
<td>a pointer to XID object.</td>
680+
<td>a reference to an object for mysql logger.</td>
681+
</tr>
682+
683+
<tr>
684+
<td>one_phase</td>
685+
<td>a bool</td>
686+
<td>the value specifies the current XA transaction commit method.</td>
687+
</tr>
688+
</table>
689+
The Post-Header and Body for this event type are empty; it only has
690+
the common header.
691+
*/
692+
693+
class XA_prepare_event: public Binary_log_event
694+
{
695+
/*
696+
Struct def is copied from $MYSQL/include/mysql/plugin.h,
697+
consult there about fine details.
698+
*/
699+
static const int MY_XIDDATASIZE= 128;
700+
701+
struct st_mysql_xid {
702+
long formatID;
703+
long gtrid_length;
704+
long bqual_length;
705+
char data[MY_XIDDATASIZE]; /* Not \0-terminated */
706+
};
707+
typedef struct st_mysql_xid MY_XID;
708+
709+
protected:
710+
/* size of serialization buffer is explained in $MYSQL/sql/xa.h. */
711+
static const uint16_t ser_buf_size=
712+
8 + 2 * MY_XIDDATASIZE + 4 * sizeof(long) + 1;
713+
MY_XID my_xid;
714+
void *xid; /* Master side only */
715+
bool one_phase;
716+
717+
public:
718+
/**
719+
The minimal constructor of XA_prepare_event, it initializes the
720+
instance variable xid and set the type_code as XID_EVENT in the
721+
header object in Binary_log_event
722+
*/
723+
XA_prepare_event(void *xid_arg, bool oph_arg)
724+
: Binary_log_event(XA_PREPARE_LOG_EVENT), xid(xid_arg), one_phase(oph_arg)
725+
{
726+
}
727+
728+
/**
729+
An XID event is generated for a commit of a transaction that modifies one or
730+
more tables of an XA-capable storage engine
731+
@param buf Contains the serialized event.
732+
@param fde An FDE event, used to get the following information
733+
-binlog_version
734+
-server_version
735+
-post_header_len
736+
-common_header_len
737+
The content of this object
738+
depends on the binlog-version currently in use.
739+
*/
740+
XA_prepare_event(const char *buf, const Format_description_event *fde);
741+
#ifndef HAVE_MYSYS
742+
/*
743+
todo: we need to find way how to exploit server's code of
744+
serialize_xid()
745+
*/
746+
void print_event_info(std::ostream& info) {};
747+
void print_long_info(std::ostream& info) {};
748+
#endif
749+
};
750+
751+
652752
/**
653753
@class Ignorable_event
654754

libbinlogevents/src/control_events.cpp

Lines changed: 59 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -156,8 +156,8 @@ Format_description_event::Format_description_event(uint8_t binlog_ver,
156156
Gtid_event::POST_HEADER_LENGTH, /*ANONYMOUS_GTID_EVENT*/
157157
IGNORABLE_HEADER_LEN,
158158
TRANSACTION_CONTEXT_HEADER_LEN,
159-
VIEW_CHANGE_HEADER_LEN
160-
159+
VIEW_CHANGE_HEADER_LEN,
160+
XA_PREPARE_HEADER_LEN
161161
};
162162
/*
163163
Allows us to sanity-check that all events initialized their
@@ -522,6 +522,36 @@ Incident_event::Incident_event(const char *buf, unsigned int event_len,
522522
return;
523523
}
524524

525+
/**
526+
We create an object of Ignorable_log_event for unrecognized sub-class, while
527+
decoding. So that we just update the position and continue.
528+
529+
@param buf Contains the serialized event.
530+
@param length Length of the serialized event.
531+
@param descr_event An FDE event, used to get the
532+
following information
533+
-binlog_version
534+
-server_version
535+
-post_header_len
536+
-common_header_len
537+
The content of this object
538+
depends on the binlog-version currently in use.
539+
*/
540+
541+
Ignorable_event::Ignorable_event(const char *buf,
542+
const Format_description_event *descr_event)
543+
: Binary_log_event(&buf, descr_event->binlog_version,
544+
descr_event->server_version)
545+
{}
546+
547+
/**
548+
Constructor for Xid_event at its decoding.
549+
550+
@param buf Contains the serialized event.
551+
@param description_event An FDE event (see comments for
552+
Ignorable_event for fine details).
553+
*/
554+
525555
Xid_event::
526556
Xid_event(const char* buf,
527557
const Format_description_event *description_event)
@@ -540,26 +570,37 @@ Xid_event(const char* buf,
540570
}
541571

542572
/**
543-
We create an object of Ignorable_log_event for unrecognized sub-class, while
544-
decoding. So that we just update the position and continue.
573+
Constructor for XA_prepare_event at its decoding.
545574
546575
@param buf Contains the serialized event.
547-
@param length Length of the serialized event.
548-
@param description_event An FDE event, used to get the
549-
following information
550-
-binlog_version
551-
-server_version
552-
-post_header_len
553-
-common_header_len
554-
The content of this object
555-
depends on the binlog-version currently in use.
576+
@param description_event An FDE event (see comments for
577+
Ignorable_event for fine details).
556578
*/
557-
Ignorable_event::Ignorable_event(const char *buf,
558-
const Format_description_event *descr_event)
559-
: Binary_log_event(&buf, descr_event->binlog_version,
560-
descr_event->server_version)
561-
{}
562579

580+
XA_prepare_event::
581+
XA_prepare_event(const char* buf,
582+
const Format_description_event *description_event)
583+
: Binary_log_event(&buf, description_event->binlog_version,
584+
description_event->server_version)
585+
{
586+
uint32_t temp= 0;
587+
uint8_t temp_byte;
588+
589+
buf+= description_event->post_header_len[XA_PREPARE_LOG_EVENT - 1];
590+
memcpy(&temp_byte, buf, 1);
591+
one_phase= (bool) temp_byte;
592+
buf += sizeof(temp_byte);
593+
memcpy(&temp, buf, sizeof(temp));
594+
my_xid.formatID= le32toh(temp);
595+
buf += sizeof(temp);
596+
memcpy(&temp, buf, sizeof(temp));
597+
my_xid.gtrid_length= le32toh(temp);
598+
buf += sizeof(temp);
599+
memcpy(&temp, buf, sizeof(temp));
600+
my_xid.bqual_length= le32toh(temp);
601+
buf += sizeof(temp);
602+
memcpy(my_xid.data, buf, my_xid.gtrid_length + my_xid.bqual_length);
603+
}
563604

564605
/**
565606
ctor to decode a Gtid_event
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
#
2+
# This file initiate connections to run XA transactions up to
3+
# their prepare.
4+
# Connection name, transaction name and its content depends on
5+
# supplied parameters.
6+
#
7+
# param $type type of transaction
8+
# param $index index identifies the connection with those of type $type
9+
# param $sql_init1 a query to execute once connection is established
10+
# param $sql_init2 a query to execute once connection is established
11+
# param $sql_doit a query to execute inside transaction
12+
# Note, the query may depend on tables created by caller
13+
#
14+
15+
--connect (conn$index$type, 127.0.0.1,root,,test,$MASTER_MYPORT,)
16+
if ($sql_init1)
17+
{
18+
--eval $sql_init1
19+
}
20+
if ($sql_init2)
21+
{
22+
--eval $sql_init2
23+
}
24+
25+
--eval XA START 'trx$index$type'
26+
if ($sql_doit)
27+
{
28+
--eval $sql_doit
29+
}
30+
--eval XA END 'trx$index$type'
31+
--eval XA PREPARE 'trx$index$type'
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
#
2+
# This file disconnects two connections. One actively and one through
3+
# kill. It is included by binlog_xa_prepared_do_and_restart.
4+
#
5+
# param $type type of transaction
6+
# param $terminate_with how to conclude actively disconnecte:
7+
# XA COMMIT or XA ROLLBACK
8+
# param $conn3_id connection id of the being killed.
9+
# param $num_trx_prepared number of transactions prepared so far
10+
#
11+
--connection default
12+
13+
--echo *** $num_trx_prepared prepared transactions must be in the list ***
14+
--replace_column 2 LEN1 3 LEN2 4 TRX_N
15+
XA RECOVER;
16+
17+
--connection conn1$type
18+
--let $conn1_id=`SELECT connection_id()`
19+
--disconnect conn1$type
20+
21+
--connection default
22+
--let $wait_condition= SELECT count(*) = 0 FROM v_processlist WHERE PROCESSLIST_ID = $conn1_id
23+
--source include/wait_condition.inc
24+
25+
# It will conclude now
26+
--eval $terminate_with 'trx1$type'
27+
28+
--replace_result $conn3_id CONN_ID
29+
--eval KILL connection $conn3_id
30+
31+
--let $wait_condition= SELECT count(*) = 0 FROM v_processlist WHERE PROCESSLIST_ID = $conn3_id
32+
--source include/wait_condition.inc
33+
34+
# It will conclude now
35+
--eval $terminate_with 'trx3$type'

0 commit comments

Comments
 (0)