Skip to content

Commit c1401ad

Browse files
author
Pedro Figueiredo
committed
WL#11300 Crash-safe XA + binary log
# Executive Summary The goal of this worklog is to improve the interaction between externally coordinated transactions (XA) and the server internal transaction coordination w.r.t order of execution, logging and recovery in both single and multi-server topologies. More specifically: 1. Propagate the XA transaction state to the topology at the expected moment so that nodes don't diverge. 2. Keep the XA transaction state consistent throughout the topology while performing work in the given transaction. 3. Keep the XA transaction state consistent throughout the topology after any server in the topology crashes, recovers and re-joins the topology. # User stories - As a MySQL user and while on a multi-server topology (classical replication or GR), I wish for externally coordinated transaction's state to be propagated at the proper moment throughout the topology, making every server state consistent with each other. - As a MySQL user and while on a single-server or multi-server topology (classical replication or GR), I wish to safely use externally coordinated transactions (XA) and be able to recover any server in the topology to a consistent state in case of a crash. Reviewed-By: Harini T. S. <harini.t.s@oracle.com> Reviewed-By: Pedro Gomes <pedro.gomes@oracle.com> Reviewed-By: Pedro Ribeiro <pedro.a.ribeiro@oracle.com> Reviewed-By: Sven Sandberg <sven.sandberg@oracle.com>
1 parent c8e58b4 commit c1401ad

File tree

307 files changed

+24178
-2271
lines changed

Some content is hidden

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

307 files changed

+24178
-2271
lines changed

libbinlogevents/include/control_events.h

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* Copyright (c) 2014, 2021, Oracle and/or its affiliates.
1+
/* Copyright (c) 2014, 2022, Oracle and/or its affiliates.
22
33
This program is free software; you can redistribute it and/or modify
44
it under the terms of the GNU General Public License, version 2.0,
@@ -583,6 +583,7 @@ class XA_prepare_event : public Binary_log_event {
583583
*/
584584
static const int MY_XIDDATASIZE = 128;
585585

586+
public:
586587
struct MY_XID {
587588
long formatID;
588589
long gtrid_length;
@@ -624,6 +625,19 @@ class XA_prepare_event : public Binary_log_event {
624625
void print_event_info(std::ostream &) override {}
625626
void print_long_info(std::ostream &) override {}
626627
#endif
628+
/**
629+
Whether or not this `XA_prepare_event` represents an `XA COMMIT ONE
630+
PHASE`.
631+
632+
@return true if it's an `XA COMMIT ONE PHASE`, false otherwise.
633+
*/
634+
bool is_one_phase() const;
635+
/**
636+
Retrieves the content of `my_xid` member variable.
637+
638+
@return The const-reference to the `my_xid` member variable.
639+
*/
640+
MY_XID const &get_xid() const;
627641
};
628642

629643
/**

libbinlogevents/src/control_events.cpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* Copyright (c) 2014, 2021, Oracle and/or its affiliates.
1+
/* Copyright (c) 2014, 2022, Oracle and/or its affiliates.
22
33
This program is free software; you can redistribute it and/or modify
44
it under the terms of the GNU General Public License, version 2.0,
@@ -348,6 +348,12 @@ XA_prepare_event::XA_prepare_event(const char *buf,
348348
BAPI_VOID_RETURN;
349349
}
350350

351+
bool XA_prepare_event::is_one_phase() const { return this->one_phase; }
352+
353+
XA_prepare_event::MY_XID const &XA_prepare_event::get_xid() const {
354+
return this->my_xid;
355+
}
356+
351357
Transaction_payload_event::Transaction_payload_event(const char *payload,
352358
uint64_t payload_size,
353359
uint16_t compression_type,
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
# ==== Purpose ====
2+
#
3+
# Used by test `binlog_gtid.binlog_gtid_recovery_errors`, it cleans up
4+
# after a binlog recovery error scenario, by:
5+
# 1. Reinstating the correct binary log file.
6+
# 2. Starting the crashed server.
7+
# 3. Cleaning up server context.
8+
#
9+
# ==== Parameters ====
10+
#
11+
# $recovery_scenario
12+
# The recovery scenario being executed.
13+
#
14+
# $end_scenario_stmt
15+
# The statement to execute after restarting the server and before
16+
# cleaning the sever context.
17+
#
18+
# $target_binlog_file
19+
# The active binlog file name, as instantiated in
20+
# `extra/binlog_tests/recovery/kill_copy_malformed_restart.inc`.
21+
#
22+
# $target_binlog_file_bak
23+
# Backup of the binlog file before overwriting with a corrupted one, as
24+
# instantiated in
25+
# `extra/binlog_tests/recovery/kill_copy_malformed_restart.inc`.
26+
#
27+
# ==== References ====
28+
#
29+
# WL#11300: Crash-safe XA + binary log
30+
#
31+
# Related tests;
32+
# see extra/xa_crash_safe_tests/setup.inc
33+
#
34+
if ($recovery_scenario == '') {
35+
--die ERROR: 'recovery_scenario' parameter needed by 'setup_scenario.inc'
36+
}
37+
38+
--echo extra/binlog_tests/recovery/end_scenario.inc [$recovery_scenario]
39+
40+
--move_file $target_binlog_file_bak $target_binlog_file
41+
42+
--let $expect_crash_on_start =
43+
--let $restart_parameters =
44+
--source include/start_mysqld.inc
45+
46+
if ($end_scenario_stmt != '') {
47+
--eval $end_scenario_stmt
48+
--let $end_scenario_stmt =
49+
}
50+
51+
DELETE FROM t1;
52+
RESET MASTER;
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
# ==== Purpose ====
2+
#
3+
# Used by test `binlog_gtid.binlog_gtid_recovery_errors`, it sets up the
4+
# scenario for a malformed binary log file to be read during recovery, by:
5+
# 1. Getting the current binary log file name.
6+
# 2. Crashing the server.
7+
# 3. Replacing the current binlog file with a malformed binary log file,
8+
# tampered to trigger the given error scenario,
9+
# 4. Restarting the server.
10+
#
11+
# ==== Parameters ====
12+
#
13+
# $recovery_scenario
14+
# The recovery scenario being executed.
15+
#
16+
# ==== References ====
17+
#
18+
# WL#11300: Crash-safe XA + binary log
19+
#
20+
# Related tests;
21+
# see extra/xa_crash_safe_tests/setup.inc
22+
#
23+
if ($recovery_scenario == '') {
24+
--die ERROR: 'recovery_scenario' parameter needed by 'setup_scenario.inc'
25+
}
26+
27+
--echo extra/binlog_tests/recovery/kill_copy_malformed_restart.inc [$recovery_scenario]
28+
29+
--let $datadir = `SELECT @@GLOBAL.datadir`
30+
--let $last_binlog_file = query_get_value(SHOW MASTER STATUS, File, 1)
31+
--let $target_binlog_file = $datadir$last_binlog_file
32+
--let $target_binlog_file_bak = $target_binlog_file.bak
33+
34+
--source include/kill_mysqld.inc
35+
36+
--let $malformed_binlog_file = $MYSQL_TEST_DIR/std_data/binlog_recovery/$recovery_scenario.000001
37+
--copy_file $target_binlog_file $target_binlog_file_bak
38+
--remove_file $target_binlog_file
39+
--copy_file $malformed_binlog_file $target_binlog_file
40+
41+
--let $restart_parameters = restart: --debug=+d,eval_force_bin_log_recovery
42+
--let $expect_crash_on_start = 1
43+
--source include/start_mysqld.inc
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
# ==== Purpose ====
2+
#
3+
# Used by scripts testing XA crash recovery, it searches
4+
# `performance_schema.error_log` table for one occurrence of the given
5+
# message.
6+
#
7+
# ==== Parameters ====
8+
#
9+
# $assert_select
10+
# Sub-string to search for in the error log.
11+
#
12+
# ==== References ====
13+
#
14+
# WL#11300: Crash-safe XA + binary log
15+
#
16+
# Related tests;
17+
# see extra/xa_crash_safe_tests/setup.inc
18+
#
19+
20+
if ($assert_select == '') {
21+
--die ERROR IN TEST: You must set $assert_select before sourcing assert_recovery_message.inc
22+
}
23+
24+
let $_row_count_to_assert =
25+
`SELECT COUNT(1)
26+
FROM performance_schema.error_log
27+
WHERE
28+
(subsystem = 'Server' OR
29+
subsystem = 'InnoDB') AND
30+
prio = 'Note' AND
31+
REGEXP_LIKE(data, '.*$assert_select.*') = 1`;
32+
--let $assert_text = Found 1 log message(s) for "$assert_select"
33+
--let $assert_cond = $_row_count_to_assert = 1
34+
--source include/assert.inc
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# ==== Purpose ====
2+
#
3+
# Used by scripts testing XA crash recovery, it checks that the table used
4+
# in those tests has a record count equal to the parameter.
5+
#
6+
# ==== Parameters ====
7+
#
8+
# $expected_row_count
9+
# The expected record count in the table used in XA crash safe tests.
10+
#
11+
# For other parameters, see `include/assert.inc`
12+
#
13+
# ==== References ====
14+
#
15+
#
16+
# Related tests;
17+
# see extra/xa_crash_safe_tests/setup.inc
18+
#
19+
20+
--let $count = `SELECT COUNT(1) FROM t1;`
21+
--let $assert_text = Table 'test.t1' record count must be $expected_row_count
22+
--let $assert_cond = $count = $expected_row_count
23+
--source include/assert.inc
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
# ==== Purpose ====
2+
#
3+
# Used by scripts testing XA crash recovery, it searches
4+
# `performance_schema.error_log` table for one occurrence of the given
5+
# InnoDB message.
6+
#
7+
# ==== Parameters ====
8+
#
9+
# $assert_select
10+
# Sub-string to search for in the error log.
11+
#
12+
# ==== References ====
13+
#
14+
# WL#11300: Crash-safe XA + binary log
15+
#
16+
# Related tests;
17+
# see extra/xa_crash_safe_tests/setup.inc
18+
#
19+
20+
if ($assert_select == '') {
21+
--die ERROR IN TEST: You must set $assert_select before sourcing assert_recovery_message.inc
22+
}
23+
24+
let $_row_count_to_assert =
25+
`SELECT COUNT(1)
26+
FROM performance_schema.error_log
27+
WHERE
28+
subsystem = 'InnoDB' AND
29+
prio = 'Note' AND
30+
data LIKE '%$assert_select%'`;
31+
--let $assert_text = Found log message(s) for "$assert_select"
32+
--let $assert_cond = $_row_count_to_assert > 0
33+
--source include/assert.inc
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
# ==== Purpose ====
2+
#
3+
# Used by scripts testing XA crash recovery, it checks the line count
4+
# returnes by `XA RECOVER` against the given count parameter and, if
5+
# different from zero, tries to find the given XID in the list.
6+
#
7+
# ==== Parameters ====
8+
#
9+
# $expected_prepared_xa_count
10+
# The expected line count return by `XA RECOVER`
11+
#
12+
# $xid_data
13+
# The XID raw data, to find in the `XA RECOVER` returned list. If
14+
# `$expected_prepared_xa_count` is non-zero, will try to assert that the
15+
# provided XID exists in the `XA RECOVER` outputted list. Support for
16+
# more than one XID to test isn't provided.
17+
#
18+
# ==== References ====
19+
#
20+
# Related tests:
21+
# see extra/xa_crash_safe_tests/setup.inc
22+
#
23+
24+
--let $statement = XA RECOVER
25+
--let $column = data
26+
--source include/get_row_count.inc
27+
28+
if ($expected_prepared_xa_count == 0) {
29+
--let $assert_text = No XA transactions in PREPARED state
30+
}
31+
if ($expected_prepared_xa_count != 0) {
32+
--let $assert_text = $expected_prepared_xa_count XA transaction(s) in PREPARED state
33+
}
34+
# Test `XA RECOVER` returned line count
35+
--let $assert_cond = "$row_count" = "$expected_prepared_xa_count"
36+
--source include/assert.inc
37+
38+
if ($expected_prepared_xa_count != 0) {
39+
if ($xid_data != '') {
40+
# For each line returned from `XA RECOVER`, try to find the given XID
41+
--let $row_number = $row_count
42+
while($row_number != 0) {
43+
--let $pending_xa = query_get_value(XA RECOVER, data, $row_number)
44+
if ($pending_xa != $xid_data) {
45+
--let $pending_xa =
46+
--dec $row_number
47+
}
48+
if ($pending_xa == $xid_data) {
49+
# If found, exit loop
50+
--let $row_number = 0
51+
}
52+
}
53+
--let $assert_text = XA transaction $xid is in PREPARED state
54+
--let $assert_cond = "$pending_xa" = "$xid_data"
55+
--source include/assert.inc
56+
}
57+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# ==== Purpose ====
2+
#
3+
# Used by scripts testing XA crash recovery, it cleans up temporary files
4+
# created by `extra/xa_crash_safe_tests/utility_functions.inc`.
5+
#
6+
# ==== References ====
7+
#
8+
# WL#11300: Crash-safe XA + binary log
9+
#
10+
# Related tests;
11+
# see extra/xa_crash_safe_tests/setup.inc
12+
#
13+
--remove_file $exec_xa_transaction_body
14+
--remove_file $clean_up_xa_transactions
15+
--remove_file $error_on_recovery_for_normal_transaction
16+
--remove_file $error_on_recovery_for_xa_transaction

0 commit comments

Comments
 (0)