summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--mysql-test/extra/binlog_tests/mix_innodb_myisam_binlog.test4
-rw-r--r--mysql-test/extra/rpl_tests/create_recursive_construct.inc17
-rw-r--r--mysql-test/extra/rpl_tests/rpl_deadlock.test2
-rw-r--r--mysql-test/include/binlog_start_pos.inc8
-rw-r--r--mysql-test/include/show_binlog_events.inc2
-rw-r--r--mysql-test/include/show_binlog_events2.inc2
-rw-r--r--mysql-test/include/show_events.inc29
-rw-r--r--mysql-test/r/mysqlbinlog_row.result2
-rw-r--r--mysql-test/r/mysqlbinlog_row_innodb.result8
-rw-r--r--mysql-test/r/mysqlbinlog_row_myisam.result8
-rw-r--r--mysql-test/r/mysqlbinlog_row_trans.result2
-rw-r--r--mysql-test/r/mysqldump-max.result10
-rw-r--r--mysql-test/r/xa_binlog.result2
-rw-r--r--mysql-test/suite/binlog/r/binlog_ioerr.result1
-rw-r--r--mysql-test/suite/binlog/r/binlog_row_annotate.result13
-rw-r--r--mysql-test/suite/binlog/r/binlog_row_binlog.result1
-rw-r--r--mysql-test/suite/binlog/r/binlog_row_mysqlbinlog_options.result4
-rw-r--r--mysql-test/suite/binlog/r/binlog_server_id.result3
-rw-r--r--mysql-test/suite/binlog/r/binlog_stm_binlog.result1
-rw-r--r--mysql-test/suite/binlog/r/binlog_stm_blackhole.result1
-rw-r--r--mysql-test/suite/binlog/r/binlog_xa_recover.result175
-rw-r--r--mysql-test/suite/binlog/t/binlog_killed.test12
-rw-r--r--mysql-test/suite/binlog/t/binlog_killed_simulate.test4
-rw-r--r--mysql-test/suite/binlog/t/binlog_xa_recover-master.opt1
-rw-r--r--mysql-test/suite/binlog/t/binlog_xa_recover.test174
-rw-r--r--mysql-test/suite/innodb/r/binlog_consistent.result69
-rw-r--r--mysql-test/suite/innodb/r/group_commit_binlog_pos.result2
-rw-r--r--mysql-test/suite/innodb/r/group_commit_binlog_pos_no_optimize_thread.result2
-rw-r--r--mysql-test/suite/innodb/r/group_commit_crash.result10
-rw-r--r--mysql-test/suite/innodb/r/group_commit_crash_no_optimize_thread.result10
-rw-r--r--mysql-test/suite/innodb/t/group_commit_crash.test2
-rw-r--r--mysql-test/suite/innodb/t/group_commit_crash_no_optimize_thread.test2
-rw-r--r--mysql-test/suite/maria/maria-connect.result1
-rw-r--r--mysql-test/suite/perfschema/r/all_instances.result2
-rw-r--r--mysql-test/suite/perfschema/r/relaylog.result8
-rw-r--r--mysql-test/suite/rpl/r/rpl_checksum.result2
-rw-r--r--mysql-test/suite/rpl/r/rpl_mariadb_slave_capability.result2
-rw-r--r--mysql-test/suite/rpl/r/rpl_row_annotate_do.result1
-rw-r--r--mysql-test/suite/rpl/r/rpl_row_annotate_dont.result1
-rw-r--r--mysql-test/suite/rpl/r/rpl_row_show_relaylog_events.result5
-rw-r--r--mysql-test/suite/rpl/r/rpl_stm_mix_show_relaylog_events.result5
-rw-r--r--mysql-test/suite/rpl/t/rpl_mariadb_slave_capability.test2
-rw-r--r--mysql-test/t/mysqlbinlog2.test38
-rw-r--r--mysql-test/t/mysqldump-max.test2
-rw-r--r--mysql-test/t/xa_binlog.test2
-rw-r--r--sql/handler.cc1
-rw-r--r--sql/log.cc526
-rw-r--r--sql/log.h53
-rw-r--r--sql/log_event.cc88
-rw-r--r--sql/log_event.h35
-rw-r--r--sql/mysqld.cc8
-rw-r--r--sql/mysqld.h4
-rw-r--r--sql/sql_repl.cc24
53 files changed, 1173 insertions, 220 deletions
diff --git a/mysql-test/extra/binlog_tests/mix_innodb_myisam_binlog.test b/mysql-test/extra/binlog_tests/mix_innodb_myisam_binlog.test
index b41bfeaba74..4ce001cfdd7 100644
--- a/mysql-test/extra/binlog_tests/mix_innodb_myisam_binlog.test
+++ b/mysql-test/extra/binlog_tests/mix_innodb_myisam_binlog.test
@@ -318,8 +318,8 @@ connection con4;
select get_lock("a",10); # wait for rollback to finish
if (`select @@binlog_format = 'STATEMENT' || @@binlog_format = 'MIXED'`)
{
- --let $binlog_rollback= query_get_value(SHOW BINLOG EVENTS, Pos, 7)
- --let $binlog_query= query_get_value(SHOW BINLOG EVENTS, Info, 7)
+ --let $binlog_rollback= query_get_value(SHOW BINLOG EVENTS, Pos, 8)
+ --let $binlog_query= query_get_value(SHOW BINLOG EVENTS, Info, 8)
if ($binlog_query != ROLLBACK) {
--echo Wrong query from SHOW BINLOG EVENTS. Expected ROLLBACK, got '$binlog_query'
--source include/show_rpl_debug_info.inc
diff --git a/mysql-test/extra/rpl_tests/create_recursive_construct.inc b/mysql-test/extra/rpl_tests/create_recursive_construct.inc
index 6e130a8154f..e790a1db41f 100644
--- a/mysql-test/extra/rpl_tests/create_recursive_construct.inc
+++ b/mysql-test/extra/rpl_tests/create_recursive_construct.inc
@@ -325,7 +325,8 @@ if ($CRC_RET_stmt_sidef) {
SHOW BINLOG EVENTS;
--die Wrong number of warnings.
}
- --let $binlog_event= query_get_value(SHOW BINLOG EVENTS, Event_type, 2)
+ # There should be no events after format description and binlog checkpoint.
+ --let $binlog_event= query_get_value(SHOW BINLOG EVENTS, Event_type, 3)
if ($binlog_event != No such row) {
--enable_query_log
--echo ******** Failure! Something was written to the binlog despite SQL_LOG_BIN=0 ********
@@ -345,23 +346,23 @@ if ($CRC_RET_stmt_sidef) {
SHOW BINLOG EVENTS;
--die Warnings printed
}
- --let $event_type= query_get_value(SHOW BINLOG EVENTS, Event_type, 3)
- # The first event is format_description, the second is
- # Query_event('BEGIN'), and the third should be our Query
+ --let $event_type= query_get_value(SHOW BINLOG EVENTS, Event_type, 4)
+ # The first event is format_description, the second is Binlog_checkpoint,
+ # the third Query_event('BEGIN'), and the fourth should be our Query
# for 'INSERT DELAYED' unsafe_type 3, which is safe after
# the fix of bug#54579.
if (`SELECT $unsafe_type = 3 AND '$event_type' != 'Query'`) {
--enable_query_log
- --echo ******** Failure! Event number 3 was a '$event_type', not a 'Query'. ********
+ --echo ******** Failure! Event number 4 was a '$event_type', not a 'Query'. ********
SHOW BINLOG EVENTS;
--die Wrong events in binlog.
}
- # The first event is format_description, the second is
- # Query_event('BEGIN'), and the third should be our Table_map
+ # The first event is format_description, the second is Binlog_checkpoint,
+ # the third is Query_event('BEGIN'), and the fourth should be our Table_map
# for unsafe statement.
if (`SELECT $unsafe_type != 3 AND '$event_type' != 'Table_map'`) {
--enable_query_log
- --echo ******** Failure! Event number 3 was a '$event_type', not a 'Table_map'. ********
+ --echo ******** Failure! Event number 4 was a '$event_type', not a 'Table_map'. ********
SHOW BINLOG EVENTS;
--die Wrong events in binlog.
}
diff --git a/mysql-test/extra/rpl_tests/rpl_deadlock.test b/mysql-test/extra/rpl_tests/rpl_deadlock.test
index 0e862e041e6..56ff4683df8 100644
--- a/mysql-test/extra/rpl_tests/rpl_deadlock.test
+++ b/mysql-test/extra/rpl_tests/rpl_deadlock.test
@@ -34,7 +34,7 @@ INSERT INTO t3 VALUES (3);
COMMIT;
save_master_pos;
# Save BEGIN event into variable
-let $master_pos_begin= query_get_value(SHOW BINLOG EVENTS, Pos, 5);
+let $master_pos_begin= query_get_value(SHOW BINLOG EVENTS, Pos, 6);
--echo
# 1) Test deadlock
diff --git a/mysql-test/include/binlog_start_pos.inc b/mysql-test/include/binlog_start_pos.inc
index add5a42a426..5237e357b28 100644
--- a/mysql-test/include/binlog_start_pos.inc
+++ b/mysql-test/include/binlog_start_pos.inc
@@ -15,14 +15,14 @@
# 1 /* Checksum algorithm */ +
# 4 /* CRC32 length */
#
-# With current number of events = 160,
+# With current number of events = 161,
#
-# binlog_start_pos = 4 + 19 + 57 + 160 + 1 + 4 = 245.
+# binlog_start_pos = 4 + 19 + 57 + 161 + 1 + 4 = 246.
#
##############################################################################
-let $binlog_start_pos=245;
+let $binlog_start_pos=246;
--disable_query_log
-SET @binlog_start_pos=245;
+SET @binlog_start_pos=246;
--enable_query_log
diff --git a/mysql-test/include/show_binlog_events.inc b/mysql-test/include/show_binlog_events.inc
index e5670c054fa..5ab837f0e6b 100644
--- a/mysql-test/include/show_binlog_events.inc
+++ b/mysql-test/include/show_binlog_events.inc
@@ -9,7 +9,7 @@
#
# It shows the first binary log file if $binlog_file is not given.
#
-# It shows events from the end position of the description event if
+# It shows events from the end position of the binlog checkpoint event if
# $binlog_start is not given.
#
# It shows all of the events if $binlog_limit is not given.
diff --git a/mysql-test/include/show_binlog_events2.inc b/mysql-test/include/show_binlog_events2.inc
index c32d12537fd..1fd9ce96d53 100644
--- a/mysql-test/include/show_binlog_events2.inc
+++ b/mysql-test/include/show_binlog_events2.inc
@@ -1,4 +1,4 @@
---let $binlog_start=245
+--let $binlog_start=246
--replace_result $binlog_start <binlog_start>
--replace_column 2 # 5 #
--replace_regex /\/\* xid=.* \*\//\/* XID *\// /table_id: [0-9]+/table_id: #/
diff --git a/mysql-test/include/show_events.inc b/mysql-test/include/show_events.inc
index ff5a7105c24..878773d2b5b 100644
--- a/mysql-test/include/show_events.inc
+++ b/mysql-test/include/show_events.inc
@@ -3,13 +3,28 @@
# It is only called by show_binlog_events.inc and show_relaylog_events.inc.
##############################################################################
+# Do not modify $binlog_start - if we did, it could wrongly persist until a
+# later call of show_events.inc.
+if ($binlog_start)
+{
+ --let $_binlog_start= $binlog_start
+}
if (!$binlog_start)
{
- # If $binlog_start is not set, we will set it as the second event's
- # position. The first event(Description Event) is always ignored. For
- # description event's length might be changed because of adding new events,
- # 'SHOW BINLOG EVENTS LIMIT 1' is used to get the right value.
- --let $binlog_start= query_get_value(SHOW BINLOG EVENTS LIMIT 1, End_log_pos, 1)
+ # If $binlog_start is not set, we will set it as the third event's
+ # position (second in relay log which has not Binlog Checkpoing event).
+ # The first two events (Description Event and Binlog Checkpoint
+ # event) are always ignored. For description event's length might be changed
+ # because of adding new events, 'SHOW BINLOG EVENTS LIMIT 2' is used to get
+ # the right value.
+ if ($is_relay_log)
+ {
+ --let $_binlog_start= query_get_value(SHOW BINLOG EVENTS LIMIT 1, End_log_pos, 1)
+ }
+ if (!$is_relay_log)
+ {
+ --let $_binlog_start= query_get_value(SHOW BINLOG EVENTS LIMIT 2, End_log_pos, 2)
+ }
}
--let $_statement=show binlog events
@@ -23,7 +38,7 @@ if ($binlog_file)
--let $_statement= $_statement in '$binlog_file'
}
---let $_statement= $_statement from $binlog_start
+--let $_statement= $_statement from $_binlog_start
# Cannot use if($binlog_limit) since the variable may begin with a 0
@@ -32,7 +47,7 @@ if (`SELECT '$binlog_limit' <> ''`)
--let $_statement= $_statement limit $binlog_limit
}
---replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR $binlog_start <binlog_start>
+--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR $_binlog_start <binlog_start>
--replace_column 2 # 4 # 5 #
--replace_regex /\/\* xid=.* \*\//\/* XID *\// /table_id: [0-9]+/table_id: #/ /file_id=[0-9]+/file_id=#/ /block_len=[0-9]+/block_len=#/ /Server ver:.*$/SERVER_VERSION, BINLOG_VERSION/
--eval $_statement
diff --git a/mysql-test/r/mysqlbinlog_row.result b/mysql-test/r/mysqlbinlog_row.result
index ce46b7ea898..6361cdadb32 100644
--- a/mysql-test/r/mysqlbinlog_row.result
+++ b/mysql-test/r/mysqlbinlog_row.result
@@ -335,6 +335,8 @@ DELIMITER /*!*/;
#010909 4:46:40 server id 1 end_log_pos # Start: binlog v 4, server v #.##.## created 010909 4:46:40 at startup
ROLLBACK/*!*/;
# at #
+#010909 4:46:40 server id 1 end_log_pos # Binlog checkpoint master-bin.000001
+# at #
#010909 4:46:40 server id 1 end_log_pos # Query thread_id=# exec_time=# error_code=0
use `test`/*!*/;
SET TIMESTAMP=1000000000/*!*/;
diff --git a/mysql-test/r/mysqlbinlog_row_innodb.result b/mysql-test/r/mysqlbinlog_row_innodb.result
index 63b64489a37..4be266d586c 100644
--- a/mysql-test/r/mysqlbinlog_row_innodb.result
+++ b/mysql-test/r/mysqlbinlog_row_innodb.result
@@ -2252,6 +2252,8 @@ DELIMITER /*!*/;
#010909 4:46:40 server id 1 end_log_pos # Start: binlog v 4, server v #.##.## created 010909 4:46:40 at startup
ROLLBACK/*!*/;
# at #
+#010909 4:46:40 server id 1 end_log_pos # Binlog checkpoint master-bin.000001
+# at #
#010909 4:46:40 server id 1 end_log_pos # Query thread_id=# exec_time=# error_code=0
use `test`/*!*/;
SET TIMESTAMP=1000000000/*!*/;
@@ -3875,6 +3877,8 @@ DELIMITER /*!*/;
#010909 4:46:40 server id 1 end_log_pos # Start: binlog v 4, server v #.##.## created 010909 4:46:40 at startup
ROLLBACK/*!*/;
# at #
+#010909 4:46:40 server id 1 end_log_pos # Binlog checkpoint master-bin.000001
+# at #
#010909 4:46:40 server id 1 end_log_pos # Query thread_id=# exec_time=# error_code=0
use `test`/*!*/;
SET TIMESTAMP=1000000000/*!*/;
@@ -4242,6 +4246,8 @@ DELIMITER /*!*/;
#010909 4:46:40 server id 1 end_log_pos # Start: binlog v 4, server v #.##.## created 010909 4:46:40 at startup
ROLLBACK/*!*/;
# at #
+#010909 4:46:40 server id 1 end_log_pos # Binlog checkpoint master-bin.000001
+# at #
#010909 4:46:40 server id 1 end_log_pos # Query thread_id=# exec_time=# error_code=0
use `test`/*!*/;
SET TIMESTAMP=1000000000/*!*/;
@@ -4803,6 +4809,8 @@ DELIMITER /*!*/;
#010909 4:46:40 server id 1 end_log_pos # Start: binlog v 4, server v #.##.## created 010909 4:46:40 at startup
ROLLBACK/*!*/;
# at #
+#010909 4:46:40 server id 1 end_log_pos # Binlog checkpoint master-bin.000001
+# at #
#010909 4:46:40 server id 1 end_log_pos # Query thread_id=# exec_time=# error_code=0
use `test`/*!*/;
SET TIMESTAMP=1000000000/*!*/;
diff --git a/mysql-test/r/mysqlbinlog_row_myisam.result b/mysql-test/r/mysqlbinlog_row_myisam.result
index 6e8c7cd64f9..d4062565320 100644
--- a/mysql-test/r/mysqlbinlog_row_myisam.result
+++ b/mysql-test/r/mysqlbinlog_row_myisam.result
@@ -2252,6 +2252,8 @@ DELIMITER /*!*/;
#010909 4:46:40 server id 1 end_log_pos # Start: binlog v 4, server v #.##.## created 010909 4:46:40 at startup
ROLLBACK/*!*/;
# at #
+#010909 4:46:40 server id 1 end_log_pos # Binlog checkpoint master-bin.000001
+# at #
#010909 4:46:40 server id 1 end_log_pos # Query thread_id=# exec_time=# error_code=0
use `test`/*!*/;
SET TIMESTAMP=1000000000/*!*/;
@@ -3897,6 +3899,8 @@ DELIMITER /*!*/;
#010909 4:46:40 server id 1 end_log_pos # Start: binlog v 4, server v #.##.## created 010909 4:46:40 at startup
ROLLBACK/*!*/;
# at #
+#010909 4:46:40 server id 1 end_log_pos # Binlog checkpoint master-bin.000001
+# at #
#010909 4:46:40 server id 1 end_log_pos # Query thread_id=# exec_time=# error_code=0
use `test`/*!*/;
SET TIMESTAMP=1000000000/*!*/;
@@ -4270,6 +4274,8 @@ DELIMITER /*!*/;
#010909 4:46:40 server id 1 end_log_pos # Start: binlog v 4, server v #.##.## created 010909 4:46:40 at startup
ROLLBACK/*!*/;
# at #
+#010909 4:46:40 server id 1 end_log_pos # Binlog checkpoint master-bin.000001
+# at #
#010909 4:46:40 server id 1 end_log_pos # Query thread_id=# exec_time=# error_code=0
use `test`/*!*/;
SET TIMESTAMP=1000000000/*!*/;
@@ -4841,6 +4847,8 @@ DELIMITER /*!*/;
#010909 4:46:40 server id 1 end_log_pos # Start: binlog v 4, server v #.##.## created 010909 4:46:40 at startup
ROLLBACK/*!*/;
# at #
+#010909 4:46:40 server id 1 end_log_pos # Binlog checkpoint master-bin.000001
+# at #
#010909 4:46:40 server id 1 end_log_pos # Query thread_id=# exec_time=# error_code=0
use `test`/*!*/;
SET TIMESTAMP=1000000000/*!*/;
diff --git a/mysql-test/r/mysqlbinlog_row_trans.result b/mysql-test/r/mysqlbinlog_row_trans.result
index 33c997d76a7..85106ab9684 100644
--- a/mysql-test/r/mysqlbinlog_row_trans.result
+++ b/mysql-test/r/mysqlbinlog_row_trans.result
@@ -131,6 +131,8 @@ DELIMITER /*!*/;
#010909 4:46:40 server id 1 end_log_pos # Start: binlog v 4, server v #.##.## created 010909 4:46:40 at startup
ROLLBACK/*!*/;
# at #
+#010909 4:46:40 server id 1 end_log_pos # Binlog checkpoint master-bin.000001
+# at #
#010909 4:46:40 server id 1 end_log_pos # Query thread_id=# exec_time=# error_code=0
use `test`/*!*/;
SET TIMESTAMP=1000000000/*!*/;
diff --git a/mysql-test/r/mysqldump-max.result b/mysql-test/r/mysqldump-max.result
index 6722f308358..fb0be20c119 100644
--- a/mysql-test/r/mysqldump-max.result
+++ b/mysql-test/r/mysqldump-max.result
@@ -332,12 +332,12 @@ a b
2 1
DROP TABLE t1;
DROP TABLE t2;
-SHOW BINLOG EVENTS LIMIT 6,3;
+SHOW BINLOG EVENTS LIMIT 7,3;
Log_name Pos Event_type Server_id End_log_pos Info
-master-bin.000001 663 Query 1 731 BEGIN
-master-bin.000001 731 Query 1 828 use `test`; INSERT INTO t2 VALUES (1,0), (2,0)
-master-bin.000001 828 Xid 1 855 COMMIT /* XID */
--- CHANGE MASTER TO MASTER_LOG_FILE='master-bin.000001', MASTER_LOG_POS=855;
+master-bin.000001 704 Query 1 772 BEGIN
+master-bin.000001 772 Query 1 869 use `test`; INSERT INTO t2 VALUES (1,0), (2,0)
+master-bin.000001 869 Xid 1 896 COMMIT /* XID */
+-- CHANGE MASTER TO MASTER_LOG_FILE='master-bin.000001', MASTER_LOG_POS=896;
SELECT * FROM t1 ORDER BY a;
a
1
diff --git a/mysql-test/r/xa_binlog.result b/mysql-test/r/xa_binlog.result
index 3ce64953902..395f0dc62a4 100644
--- a/mysql-test/r/xa_binlog.result
+++ b/mysql-test/r/xa_binlog.result
@@ -18,7 +18,7 @@ a
1
2
3
-SHOW BINLOG EVENTS LIMIT 1,9;
+SHOW BINLOG EVENTS LIMIT 2,9;
Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000001 # Query 1 # BEGIN
master-bin.000001 # Query 1 # use `test`; INSERT INTO t1 VALUES (1)
diff --git a/mysql-test/suite/binlog/r/binlog_ioerr.result b/mysql-test/suite/binlog/r/binlog_ioerr.result
index f8e2d189f57..68ff5264aa3 100644
--- a/mysql-test/suite/binlog/r/binlog_ioerr.result
+++ b/mysql-test/suite/binlog/r/binlog_ioerr.result
@@ -16,6 +16,7 @@ a
SHOW BINLOG EVENTS;
Log_name Pos Event_type Server_id End_log_pos Info
BINLOG POS Format_desc 1 ENDPOS Server ver: #, Binlog ver: #
+BINLOG POS Binlog_checkpoint 1 ENDPOS master-bin.000001
BINLOG POS Query 1 ENDPOS use `test`; CREATE TABLE t1 (a INT PRIMARY KEY) ENGINE=innodb
BINLOG POS Query 1 ENDPOS BEGIN
BINLOG POS Query 1 ENDPOS use `test`; INSERT INTO t1 VALUES(0)
diff --git a/mysql-test/suite/binlog/r/binlog_row_annotate.result b/mysql-test/suite/binlog/r/binlog_row_annotate.result
index 0c008661784..58cac276c95 100644
--- a/mysql-test/suite/binlog/r/binlog_row_annotate.result
+++ b/mysql-test/suite/binlog/r/binlog_row_annotate.result
@@ -8,6 +8,7 @@
#####################################################################################
show binlog events in 'master-bin.000001' from <start_pos>;
Log_name Pos Event_type Server_id End_log_pos Info
+master-bin.000001 # Binlog_checkpoint 1 # master-bin.000001
master-bin.000001 # Query 1 # DROP DATABASE IF EXISTS test1
master-bin.000001 # Query 1 # DROP DATABASE IF EXISTS test2
master-bin.000001 # Query 1 # DROP DATABASE IF EXISTS test3
@@ -67,6 +68,8 @@ DELIMITER /*!*/;
#010909 4:46:40 server id # end_log_pos # Start: binlog v 4, server v #.##.## created 010909 4:46:40 at startup
ROLLBACK/*!*/;
# at #
+#010909 4:46:40 server id # end_log_pos # Binlog checkpoint master-bin.000001
+# at #
#010909 4:46:40 server id # end_log_pos # Query thread_id=# exec_time=# error_code=0
SET TIMESTAMP=1000000000/*!*/;
SET @@session.pseudo_thread_id=#/*!*/;
@@ -293,6 +296,8 @@ DELIMITER /*!*/;
#010909 4:46:40 server id # end_log_pos # Start: binlog v 4, server v #.##.## created 010909 4:46:40 at startup
ROLLBACK/*!*/;
# at #
+#010909 4:46:40 server id # end_log_pos # Binlog checkpoint master-bin.000001
+# at #
#010909 4:46:40 server id # end_log_pos # Query thread_id=# exec_time=# error_code=0
SET TIMESTAMP=1000000000/*!*/;
SET @@session.pseudo_thread_id=#/*!*/;
@@ -437,6 +442,8 @@ DELIMITER /*!*/;
#010909 4:46:40 server id # end_log_pos # Start: binlog v 4, server v #.##.## created 010909 4:46:40 at startup
ROLLBACK/*!*/;
# at #
+#010909 4:46:40 server id # end_log_pos # Binlog checkpoint master-bin.000001
+# at #
#010909 4:46:40 server id # end_log_pos # Query thread_id=# exec_time=# error_code=0
SET TIMESTAMP=1000000000/*!*/;
SET @@session.pseudo_thread_id=#/*!*/;
@@ -653,6 +660,8 @@ DELIMITER /*!*/;
#010909 4:46:40 server id # end_log_pos # Start: binlog v 4, server v #.##.## created 010909 4:46:40 at startup
ROLLBACK/*!*/;
# at #
+#010909 4:46:40 server id # end_log_pos # Binlog checkpoint master-bin.000001
+# at #
#010909 4:46:40 server id # end_log_pos # Query thread_id=# exec_time=# error_code=0
SET TIMESTAMP=1000000000/*!*/;
SET @@session.pseudo_thread_id=#/*!*/;
@@ -879,6 +888,8 @@ DELIMITER /*!*/;
#010909 4:46:40 server id # end_log_pos # Start: binlog v 4, server v #.##.## created 010909 4:46:40 at startup
ROLLBACK/*!*/;
# at #
+#010909 4:46:40 server id # end_log_pos # Binlog checkpoint master-bin.000001
+# at #
#010909 4:46:40 server id # end_log_pos # Query thread_id=# exec_time=# error_code=0
SET TIMESTAMP=1000000000/*!*/;
SET @@session.pseudo_thread_id=#/*!*/;
@@ -1023,6 +1034,8 @@ DELIMITER /*!*/;
#010909 4:46:40 server id # end_log_pos # Start: binlog v 4, server v #.##.## created 010909 4:46:40 at startup
ROLLBACK/*!*/;
# at #
+#010909 4:46:40 server id # end_log_pos # Binlog checkpoint master-bin.000001
+# at #
#010909 4:46:40 server id # end_log_pos # Query thread_id=# exec_time=# error_code=0
SET TIMESTAMP=1000000000/*!*/;
SET @@session.pseudo_thread_id=#/*!*/;
diff --git a/mysql-test/suite/binlog/r/binlog_row_binlog.result b/mysql-test/suite/binlog/r/binlog_row_binlog.result
index 95477d13b50..26710178cd8 100644
--- a/mysql-test/suite/binlog/r/binlog_row_binlog.result
+++ b/mysql-test/suite/binlog/r/binlog_row_binlog.result
@@ -728,6 +728,7 @@ BINLOG '
SHOW BINLOG EVENTS;
Log_name Pos Event_type Server_id End_log_pos Info
# # Format_desc 1 # Server ver: #, Binlog ver: #
+# # Binlog_checkpoint 1 # master-bin.000001
# # Query 1 # use `test`; CREATE TABLE t1 (a INT PRIMARY KEY)
# # Query 1 # BEGIN
# # Table_map 1 # table_id: # (test.t1)
diff --git a/mysql-test/suite/binlog/r/binlog_row_mysqlbinlog_options.result b/mysql-test/suite/binlog/r/binlog_row_mysqlbinlog_options.result
index 9c780390ca8..ae732ffcc08 100644
--- a/mysql-test/suite/binlog/r/binlog_row_mysqlbinlog_options.result
+++ b/mysql-test/suite/binlog/r/binlog_row_mysqlbinlog_options.result
@@ -34,6 +34,8 @@ DELIMITER /*!*/;
# at #
#010909 4:46:40 server id # end_log_pos # Start: binlog v 4, server v #.##.## created 010909 4:46:40 at startup
ROLLBACK/*!*/;
+#010909 4:46:40 server id # end_log_pos # Binlog checkpoint master-bin.000001
+# at #
# at #
use `new_test1`/*!*/;
#010909 4:46:40 server id # end_log_pos # Query thread_id=# exec_time=# error_code=0
@@ -228,6 +230,8 @@ DELIMITER /*!*/;
# at #
#010909 4:46:40 server id # end_log_pos # Start: binlog v 4, server v #.##.## created 010909 4:46:40 at startup
ROLLBACK/*!*/;
+#010909 4:46:40 server id # end_log_pos # Binlog checkpoint master-bin.000001
+# at #
# at #
use `new_test1`/*!*/;
#010909 4:46:40 server id # end_log_pos # Query thread_id=# exec_time=# error_code=0
diff --git a/mysql-test/suite/binlog/r/binlog_server_id.result b/mysql-test/suite/binlog/r/binlog_server_id.result
index f7d778a288b..991fd6e476b 100644
--- a/mysql-test/suite/binlog/r/binlog_server_id.result
+++ b/mysql-test/suite/binlog/r/binlog_server_id.result
@@ -7,6 +7,7 @@ select @@server_id;
1
show binlog events from <binlog_start>;
Log_name Pos Event_type Server_id End_log_pos Info
+master-bin.000001 # Binlog_checkpoint 1 # master-bin.000001
master-bin.000001 # Query 1 # use `test`; DROP TABLE IF EXISTS `t1`,`t2`,`t3` /* generated by server */
master-bin.000001 # Query 1 # use `test`; create table t1 (a int)
set global server_id=2;
@@ -16,6 +17,7 @@ select @@server_id;
2
show binlog events from <binlog_start>;
Log_name Pos Event_type Server_id End_log_pos Info
+master-bin.000001 # Binlog_checkpoint 1 # master-bin.000001
master-bin.000001 # Query 1 # use `test`; DROP TABLE IF EXISTS `t1`,`t2`,`t3` /* generated by server */
master-bin.000001 # Query 1 # use `test`; create table t1 (a int)
master-bin.000001 # Query 2 # use `test`; create table t2 (b int)
@@ -26,6 +28,7 @@ select @@server_id;
3
show binlog events from <binlog_start>;
Log_name Pos Event_type Server_id End_log_pos Info
+master-bin.000001 # Binlog_checkpoint 1 # master-bin.000001
master-bin.000001 # Query 1 # use `test`; DROP TABLE IF EXISTS `t1`,`t2`,`t3` /* generated by server */
master-bin.000001 # Query 1 # use `test`; create table t1 (a int)
master-bin.000001 # Query 2 # use `test`; create table t2 (b int)
diff --git a/mysql-test/suite/binlog/r/binlog_stm_binlog.result b/mysql-test/suite/binlog/r/binlog_stm_binlog.result
index 062f4f4e906..f9d9fa1d18d 100644
--- a/mysql-test/suite/binlog/r/binlog_stm_binlog.result
+++ b/mysql-test/suite/binlog/r/binlog_stm_binlog.result
@@ -521,6 +521,7 @@ BINLOG '
SHOW BINLOG EVENTS;
Log_name Pos Event_type Server_id End_log_pos Info
# # Format_desc 1 # Server ver: #, Binlog ver: #
+# # Binlog_checkpoint 1 # master-bin.000001
# # Query 1 # use `test`; CREATE TABLE t1 (a INT PRIMARY KEY)
# # Query 1 # BEGIN
# # Query 1 # use `test`; INSERT INTO t1 VALUES (1)
diff --git a/mysql-test/suite/binlog/r/binlog_stm_blackhole.result b/mysql-test/suite/binlog/r/binlog_stm_blackhole.result
index e76f6b494f9..2b5bd76a338 100644
--- a/mysql-test/suite/binlog/r/binlog_stm_blackhole.result
+++ b/mysql-test/suite/binlog/r/binlog_stm_blackhole.result
@@ -175,6 +175,7 @@ set insert_id= 5;
insert into t1 values (55), (NULL);
show binlog events from <binlog_start>;
Log_name Pos Event_type Server_id End_log_pos Info
+master-bin.000001 # Binlog_checkpoint 1 # master-bin.000001
master-bin.000001 # Query 1 # use `test`; create table t1 (a int auto_increment, primary key (a)) engine=blackhole
master-bin.000001 # Query 1 # BEGIN
master-bin.000001 # Intvar 1 # INSERT_ID=1
diff --git a/mysql-test/suite/binlog/r/binlog_xa_recover.result b/mysql-test/suite/binlog/r/binlog_xa_recover.result
new file mode 100644
index 00000000000..41df149a928
--- /dev/null
+++ b/mysql-test/suite/binlog/r/binlog_xa_recover.result
@@ -0,0 +1,175 @@
+SET GLOBAL max_binlog_size= 4096;
+CREATE TABLE t1 (a INT PRIMARY KEY, b MEDIUMTEXT) ENGINE=Innodb;
+CREATE TABLE t2 (a INT PRIMARY KEY, b MEDIUMTEXT) ENGINE=Myisam;
+SET @@global.debug_dbug='+d,skip_commit_ordered';
+INSERT INTO t1 VALUES (0, REPEAT("x", 4100));
+SET DEBUG_SYNC= "ha_commit_trans_after_log_and_order SIGNAL con1_ready WAIT_FOR _ever";
+INSERT INTO t1 VALUES (1, REPEAT("x", 4100));
+SET DEBUG_SYNC= "now WAIT_FOR con1_ready";
+INSERT INTO t2 VALUES (1, "force binlog rotation");
+SET DEBUG_SYNC= "ha_commit_trans_after_log_and_order SIGNAL con2_ready WAIT_FOR _ever";
+INSERT INTO t1 VALUES (2, NULL);
+SET DEBUG_SYNC= "now WAIT_FOR con2_ready";
+SET DEBUG_SYNC= "ha_commit_trans_after_log_and_order SIGNAL con3_ready WAIT_FOR _ever";
+INSERT INTO t1 VALUES (3, REPEAT("x", 4100));
+SET DEBUG_SYNC= "now WAIT_FOR con3_ready";
+INSERT INTO t2 VALUES (2, "force binlog rotation");
+FLUSH TABLES t2;
+show binary logs;
+Log_name File_size
+master-bin.000001 #
+master-bin.000002 #
+master-bin.000003 #
+master-bin.000004 #
+show binlog events in 'master-bin.000001' from <binlog_start>;
+Log_name Pos Event_type Server_id End_log_pos Info
+master-bin.000001 # Format_desc # # SERVER_VERSION, BINLOG_VERSION
+master-bin.000001 # Binlog_checkpoint # # master-bin.000001
+master-bin.000001 # Query # # use `test`; CREATE TABLE t1 (a INT PRIMARY KEY, b MEDIUMTEXT) ENGINE=Innodb
+master-bin.000001 # Query # # use `test`; CREATE TABLE t2 (a INT PRIMARY KEY, b MEDIUMTEXT) ENGINE=Myisam
+master-bin.000001 # Query # # BEGIN
+master-bin.000001 # Table_map # # table_id: # (test.t1)
+master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F
+master-bin.000001 # Xid # # COMMIT /* XID */
+master-bin.000001 # Rotate # # master-bin.000002;pos=<binlog_start>
+show binlog events in 'master-bin.000002' from <binlog_start>;
+Log_name Pos Event_type Server_id End_log_pos Info
+master-bin.000002 # Format_desc # # SERVER_VERSION, BINLOG_VERSION
+master-bin.000002 # Binlog_checkpoint # # master-bin.000002
+master-bin.000002 # Query # # BEGIN
+master-bin.000002 # Table_map # # table_id: # (test.t1)
+master-bin.000002 # Write_rows # # table_id: # flags: STMT_END_F
+master-bin.000002 # Xid # # COMMIT /* XID */
+master-bin.000002 # Query # # BEGIN
+master-bin.000002 # Table_map # # table_id: # (test.t2)
+master-bin.000002 # Write_rows # # table_id: # flags: STMT_END_F
+master-bin.000002 # Query # # COMMIT
+master-bin.000002 # Rotate # # master-bin.000003;pos=<binlog_start>
+show binlog events in 'master-bin.000003' from <binlog_start>;
+Log_name Pos Event_type Server_id End_log_pos Info
+master-bin.000003 # Format_desc # # SERVER_VERSION, BINLOG_VERSION
+master-bin.000003 # Binlog_checkpoint # # master-bin.000002
+master-bin.000003 # Query # # BEGIN
+master-bin.000003 # Table_map # # table_id: # (test.t1)
+master-bin.000003 # Write_rows # # table_id: # flags: STMT_END_F
+master-bin.000003 # Xid # # COMMIT /* XID */
+master-bin.000003 # Query # # BEGIN
+master-bin.000003 # Table_map # # table_id: # (test.t1)
+master-bin.000003 # Write_rows # # table_id: # flags: STMT_END_F
+master-bin.000003 # Xid # # COMMIT /* XID */
+master-bin.000003 # Query # # BEGIN
+master-bin.000003 # Table_map # # table_id: # (test.t2)
+master-bin.000003 # Write_rows # # table_id: # flags: STMT_END_F
+master-bin.000003 # Query # # COMMIT
+master-bin.000003 # Rotate # # master-bin.00000<binlog_start>;pos=<binlog_start>
+show binlog events in 'master-bin.00000<binlog_start>' from <binlog_start>;
+Log_name Pos Event_type Server_id End_log_pos Info
+master-bin.00000<binlog_start> # Format_desc # # SERVER_VERSION, BINLOG_VERSION
+master-bin.00000<binlog_start> # Binlog_checkpoint # # master-bin.000002
+master-bin.00000<binlog_start> # Query # # use `test`; FLUSH TABLES t2
+We should see only one entry here, a=0:
+SELECT a FROM t1 ORDER BY a;
+a
+0
+PURGE BINARY LOGS TO "master-bin.000004";
+show binary logs;
+Log_name File_size
+master-bin.000002 #
+master-bin.000003 #
+master-bin.000004 #
+SET SESSION debug_dbug="+d,crash_commit_after_log";
+INSERT INTO t1 VALUES (4, NULL);
+Got one of the listed errors
+SELECT a FROM t1 ORDER BY a;
+a
+0
+1
+2
+3
+4
+*** Test that RESET MASTER waits for pending XIDs to be unlogged.
+SET @old_max_binlog_size= @@global.max_binlog_size;
+SET GLOBAL max_binlog_size= 4096;
+SET DEBUG_SYNC= "ha_commit_trans_after_log_and_order SIGNAL con10_ready WAIT_FOR con10_go";
+INSERT INTO t1 VALUES (10, NULL);
+SET DEBUG_SYNC= "now WAIT_FOR con10_ready";
+INSERT INTO t2 VALUES (10, REPEAT("x", 4100));
+INSERT INTO t2 VALUES (11, REPEAT("x", 4100));
+show binary logs;
+Log_name File_size
+master-bin.000002 #
+master-bin.000003 #
+master-bin.000004 #
+master-bin.000005 #
+master-bin.000006 #
+master-bin.000007 #
+SET DEBUG_SYNC= "execute_command_after_close_tables SIGNAL reset_master_done";
+RESET MASTER;
+This will timeout, as RESET MASTER is blocked
+SET DEBUG_SYNC= "now WAIT_FOR reset_master_done TIMEOUT 1";
+Warnings:
+Warning 1639 debug sync point wait timed out
+SET DEBUG_SYNC= "now SIGNAL con10_go";
+show binary logs;
+Log_name File_size
+master-bin.000001 #
+*** Test that binlog N is active, and last pending trx in (N-1) is
+unlogged while there is still a pending trx in (N-2).
+SET DEBUG_SYNC= "ha_commit_trans_after_log_and_order SIGNAL con10_ready WAIT_FOR con10_continue";
+INSERT INTO t1 VALUES (20, REPEAT("x", 4100));
+SET DEBUG_SYNC= "now WAIT_FOR con10_ready";
+INSERT INTO t2 VALUES (3, "force binlog rotation");
+SET DEBUG_SYNC= "ha_commit_trans_after_log_and_order SIGNAL con11_ready WAIT_FOR con11_continue";
+INSERT INTO t1 VALUES (21, REPEAT("x", 4100));
+SET DEBUG_SYNC= "now WAIT_FOR con11_ready";
+INSERT INTO t2 VALUES (4, "force binlog rotation");
+show binary logs;
+Log_name File_size
+master-bin.000001 #
+master-bin.000002 #
+master-bin.000003 #
+show binlog events in 'master-bin.000001' from <binlog_start>;
+Log_name Pos Event_type Server_id End_log_pos Info
+master-bin.000001 # Format_desc # # SERVER_VERSION, BINLOG_VERSION
+master-bin.000001 # Binlog_checkpoint # # master-bin.000001
+master-bin.000001 # Query # # BEGIN
+master-bin.000001 # Table_map # # table_id: # (test.t1)
+master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F
+master-bin.000001 # Xid # # COMMIT /* XID */
+master-bin.000001 # Query # # BEGIN
+master-bin.000001 # Table_map # # table_id: # (test.t2)
+master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F
+master-bin.000001 # Query # # COMMIT
+master-bin.000001 # Rotate # # master-bin.000002;pos=<binlog_start>
+show binlog events in 'master-bin.000002' from <binlog_start>;
+Log_name Pos Event_type Server_id End_log_pos Info
+master-bin.000002 # Format_desc # # SERVER_VERSION, BINLOG_VERSION
+master-bin.000002 # Binlog_checkpoint # # master-bin.000001
+master-bin.000002 # Query # # BEGIN
+master-bin.000002 # Table_map # # table_id: # (test.t1)
+master-bin.000002 # Write_rows # # table_id: # flags: STMT_END_F
+master-bin.000002 # Xid # # COMMIT /* XID */
+master-bin.000002 # Query # # BEGIN
+master-bin.000002 # Table_map # # table_id: # (test.t2)
+master-bin.000002 # Write_rows # # table_id: # flags: STMT_END_F
+master-bin.000002 # Query # # COMMIT
+master-bin.000002 # Rotate # # master-bin.000003;pos=<binlog_start>
+show binlog events in 'master-bin.000003' from <binlog_start>;
+Log_name Pos Event_type Server_id End_log_pos Info
+master-bin.000003 # Format_desc # # SERVER_VERSION, BINLOG_VERSION
+master-bin.000003 # Binlog_checkpoint # # master-bin.000001
+SET DEBUG_SYNC= "now SIGNAL con11_continue";
+con10 is still pending, no new binlog checkpoint should have been logged.
+show binlog events in 'master-bin.000003' from <binlog_start>;
+Log_name Pos Event_type Server_id End_log_pos Info
+master-bin.000003 # Format_desc # # SERVER_VERSION, BINLOG_VERSION
+master-bin.000003 # Binlog_checkpoint # # master-bin.000001
+SET DEBUG_SYNC= "now SIGNAL con10_continue";
+No XIDs are pending, a new binlog checkpoint should have been logged.
+show binlog events in 'master-bin.000003' from <binlog_start>;
+Log_name Pos Event_type Server_id End_log_pos Info
+master-bin.000003 # Format_desc # # SERVER_VERSION, BINLOG_VERSION
+master-bin.000003 # Binlog_checkpoint # # master-bin.000001
+master-bin.000003 # Binlog_checkpoint # # master-bin.000003
+DROP TABLE t1, t2;
+SET GLOBAL max_binlog_size= @old_max_binlog_size;
diff --git a/mysql-test/suite/binlog/t/binlog_killed.test b/mysql-test/suite/binlog/t/binlog_killed.test
index 9b6420df4b4..ff558ee2948 100644
--- a/mysql-test/suite/binlog/t/binlog_killed.test
+++ b/mysql-test/suite/binlog/t/binlog_killed.test
@@ -59,8 +59,8 @@ reap;
let $rows= `select count(*) from t2 /* must be 2 or 0 */`;
let $MYSQLD_DATADIR= `select @@datadir`;
---let $binlog_killed_pos=query_get_value(SHOW BINLOG EVENTS, Pos, 4)
---let $binlog_killed_end_log_pos=query_get_value(SHOW BINLOG EVENTS, End_log_pos, 4)
+--let $binlog_killed_pos=query_get_value(SHOW BINLOG EVENTS, Pos, 5)
+--let $binlog_killed_end_log_pos=query_get_value(SHOW BINLOG EVENTS, End_log_pos, 5)
--exec $MYSQL_BINLOG --force-if-open --start-position=$binlog_killed_pos --stop-position=$binlog_killed_end_log_pos $MYSQLD_DATADIR/master-bin.000001 > $MYSQLTEST_VARDIR/tmp/kill_query_calling_sp.binlog
--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
--disable_result_log
@@ -270,8 +270,8 @@ select * from t4 order by b /* must be (1,1), (1,2) */;
select @b /* must be 1 at the end of a stmt calling bug27563() */;
--echo must have the update query event on the 4th line
source include/show_binlog_events.inc;
---let $binlog_killed_pos= query_get_value(SHOW BINLOG EVENTS, Pos, 4)
---let $binlog_killed_end_log_pos= query_get_value(SHOW BINLOG EVENTS, End_log_pos, 4)
+--let $binlog_killed_pos= query_get_value(SHOW BINLOG EVENTS, Pos, 5)
+--let $binlog_killed_end_log_pos= query_get_value(SHOW BINLOG EVENTS, End_log_pos, 5)
--echo *** a proof the query is binlogged with an error ***
@@ -318,8 +318,8 @@ select count(*) from t4 /* must be 1 */;
select @b /* must be 1 at the end of a stmt calling bug27563() */;
--echo must have the delete query event on the 4th line
source include/show_binlog_events.inc;
---let $binlog_killed_pos= query_get_value(SHOW BINLOG EVENTS, Pos, 4)
---let $binlog_killed_end_log_pos= query_get_value(SHOW BINLOG EVENTS, End_log_pos, 4)
+--let $binlog_killed_pos= query_get_value(SHOW BINLOG EVENTS, Pos, 5)
+--let $binlog_killed_end_log_pos= query_get_value(SHOW BINLOG EVENTS, End_log_pos, 5)
# a proof the query is binlogged with an error
diff --git a/mysql-test/suite/binlog/t/binlog_killed_simulate.test b/mysql-test/suite/binlog/t/binlog_killed_simulate.test
index ba111fd0145..33037710379 100644
--- a/mysql-test/suite/binlog/t/binlog_killed_simulate.test
+++ b/mysql-test/suite/binlog/t/binlog_killed_simulate.test
@@ -50,8 +50,8 @@ load data infile '../../std_data/rpl_loaddata.dat' into table t2 /* will be "kil
# a proof the query is binlogged with an error
---let $binlog_load_data= query_get_value(SHOW BINLOG EVENTS, Pos, 3)
---let $binlog_end= query_get_value(SHOW BINLOG EVENTS, Pos, 4)
+--let $binlog_load_data= query_get_value(SHOW BINLOG EVENTS, Pos, 4)
+--let $binlog_end= query_get_value(SHOW BINLOG EVENTS, Pos, 5)
source include/show_binlog_events.inc;
--exec $MYSQL_BINLOG --force-if-open --start-position=$binlog_load_data --stop-position=$binlog_end $MYSQLD_DATADIR/master-bin.000001 > $MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog
diff --git a/mysql-test/suite/binlog/t/binlog_xa_recover-master.opt b/mysql-test/suite/binlog/t/binlog_xa_recover-master.opt
new file mode 100644
index 00000000000..425fda95086
--- /dev/null
+++ b/mysql-test/suite/binlog/t/binlog_xa_recover-master.opt
@@ -0,0 +1 @@
+--skip-stack-trace --skip-core-file
diff --git a/mysql-test/suite/binlog/t/binlog_xa_recover.test b/mysql-test/suite/binlog/t/binlog_xa_recover.test
new file mode 100644
index 00000000000..7a4cc17112e
--- /dev/null
+++ b/mysql-test/suite/binlog/t/binlog_xa_recover.test
@@ -0,0 +1,174 @@
+--source include/have_innodb.inc
+--source include/have_debug.inc
+--source include/have_debug_sync.inc
+--source include/have_binlog_format_row.inc
+# Valgrind does not work well with test that crashes the server
+--source include/not_valgrind.inc
+
+SET GLOBAL max_binlog_size= 4096;
+
+CREATE TABLE t1 (a INT PRIMARY KEY, b MEDIUMTEXT) ENGINE=Innodb;
+CREATE TABLE t2 (a INT PRIMARY KEY, b MEDIUMTEXT) ENGINE=Myisam;
+
+# Transactions are not guaranteed stored durably on disk in the engine until
+# they are fsync()ed, which normally happens during commit(). But there is no
+# guarantee that they will _not_ be durable, in particular loosing results
+# of a write(2) system call normally requires a kernel crash (as opposed to
+# just mysqld crash), which is inconvenient to do in a test suite.
+# So instead we do an error insert to prevent commit_ordered() from being
+# called in the engine - so nothing will be written to disk at all, and crash
+# recovery is sure to be needed.
+SET @@global.debug_dbug='+d,skip_commit_ordered';
+
+INSERT INTO t1 VALUES (0, REPEAT("x", 4100));
+
+# Now start a bunch of transactions that span multiple binlog
+# files. Leave then in the state prepared-but-not-committed in the engine
+# and crash the server. Check that crash recovery is able to recover all
+# of them.
+
+connect(con1,localhost,root,,);
+SET DEBUG_SYNC= "ha_commit_trans_after_log_and_order SIGNAL con1_ready WAIT_FOR _ever";
+send INSERT INTO t1 VALUES (1, REPEAT("x", 4100));
+
+connection default;
+SET DEBUG_SYNC= "now WAIT_FOR con1_ready";
+INSERT INTO t2 VALUES (1, "force binlog rotation");
+
+connect(con2,localhost,root,,);
+SET DEBUG_SYNC= "ha_commit_trans_after_log_and_order SIGNAL con2_ready WAIT_FOR _ever";
+send INSERT INTO t1 VALUES (2, NULL);
+
+connection default;
+SET DEBUG_SYNC= "now WAIT_FOR con2_ready";
+
+connect(con3,localhost,root,,);
+SET DEBUG_SYNC= "ha_commit_trans_after_log_and_order SIGNAL con3_ready WAIT_FOR _ever";
+send INSERT INTO t1 VALUES (3, REPEAT("x", 4100));
+connection default;
+SET DEBUG_SYNC= "now WAIT_FOR con3_ready";
+INSERT INTO t2 VALUES (2, "force binlog rotation");
+# So we won't get warnings about t2 being crashed.
+FLUSH TABLES t2;
+
+# Check that everything is committed in binary log.
+--source include/show_binary_logs.inc
+--let $binlog_file= master-bin.000001
+--let $binlog_start= 4
+--source include/show_binlog_events.inc
+--let $binlog_file= master-bin.000002
+--source include/show_binlog_events.inc
+--let $binlog_file= master-bin.000003
+--source include/show_binlog_events.inc
+--let $binlog_file= master-bin.000004
+--source include/show_binlog_events.inc
+
+# Check that transactions really are not yet committed in engine.
+# (This works because of debug_dbug='+d,skip_commit_ordered').
+--echo We should see only one entry here, a=0:
+SELECT a FROM t1 ORDER BY a;
+
+
+# Check that server will not purge too much.
+PURGE BINARY LOGS TO "master-bin.000004";
+--source include/show_binary_logs.inc
+
+# Now crash the server with one more transaction in prepared state.
+system echo wait-binlog_xa_recover.test >> $MYSQLTEST_VARDIR/tmp/mysqld.1.expect;
+SET SESSION debug_dbug="+d,crash_commit_after_log";
+--error 2006,2013
+INSERT INTO t1 VALUES (4, NULL);
+
+system echo restart-group_commit_binlog_pos.test >> $MYSQLTEST_VARDIR/tmp/mysqld.1.expect;
+
+connection default;
+--enable_reconnect
+--source include/wait_until_connected_again.inc
+
+# Check that all transactions are recovered.
+SELECT a FROM t1 ORDER BY a;
+
+
+--echo *** Test that RESET MASTER waits for pending XIDs to be unlogged.
+
+SET @old_max_binlog_size= @@global.max_binlog_size;
+SET GLOBAL max_binlog_size= 4096;
+# con10 will hang with a pending XID, blocking RESET MASTER.
+connect(con10,localhost,root,,);
+SET DEBUG_SYNC= "ha_commit_trans_after_log_and_order SIGNAL con10_ready WAIT_FOR con10_go";
+send INSERT INTO t1 VALUES (10, NULL);
+
+connection default;
+SET DEBUG_SYNC= "now WAIT_FOR con10_ready";
+# Let's add a few binlog rotations just for good measure.
+INSERT INTO t2 VALUES (10, REPEAT("x", 4100));
+INSERT INTO t2 VALUES (11, REPEAT("x", 4100));
+--source include/show_binary_logs.inc
+SET DEBUG_SYNC= "execute_command_after_close_tables SIGNAL reset_master_done";
+send RESET MASTER;
+
+connect(con11,localhost,root,,);
+--echo This will timeout, as RESET MASTER is blocked
+SET DEBUG_SYNC= "now WAIT_FOR reset_master_done TIMEOUT 1";
+# Wake up transaction to allow RESET MASTER to complete.
+SET DEBUG_SYNC= "now SIGNAL con10_go";
+
+connection con10;
+reap;
+
+connection default;
+reap;
+--source include/show_binary_logs.inc
+
+
+--echo *** Test that binlog N is active, and last pending trx in (N-1) is
+--echo unlogged while there is still a pending trx in (N-2).
+
+connection con10;
+SET DEBUG_SYNC= "ha_commit_trans_after_log_and_order SIGNAL con10_ready WAIT_FOR con10_continue";
+send INSERT INTO t1 VALUES (20, REPEAT("x", 4100));
+
+connection default;
+SET DEBUG_SYNC= "now WAIT_FOR con10_ready";
+INSERT INTO t2 VALUES (3, "force binlog rotation");
+
+connection con11;
+SET DEBUG_SYNC= "ha_commit_trans_after_log_and_order SIGNAL con11_ready WAIT_FOR con11_continue";
+send INSERT INTO t1 VALUES (21, REPEAT("x", 4100));
+
+connection default;
+SET DEBUG_SYNC= "now WAIT_FOR con11_ready";
+INSERT INTO t2 VALUES (4, "force binlog rotation");
+--source include/show_binary_logs.inc
+--let $binlog_file= master-bin.000001
+--source include/show_binlog_events.inc
+--let $binlog_file= master-bin.000002
+--source include/show_binlog_events.inc
+--let $binlog_file= master-bin.000003
+--source include/show_binlog_events.inc
+
+SET DEBUG_SYNC= "now SIGNAL con11_continue";
+
+connection con11;
+reap;
+
+connection default;
+--echo con10 is still pending, no new binlog checkpoint should have been logged.
+--let $binlog_file= master-bin.000003
+--source include/show_binlog_events.inc
+
+SET DEBUG_SYNC= "now SIGNAL con10_continue";
+
+connection con10;
+reap;
+
+connection default;
+--echo No XIDs are pending, a new binlog checkpoint should have been logged.
+--let $binlog_file= master-bin.000003
+--source include/show_binlog_events.inc
+
+
+# Cleanup
+connection default;
+DROP TABLE t1, t2;
+SET GLOBAL max_binlog_size= @old_max_binlog_size;
diff --git a/mysql-test/suite/innodb/r/binlog_consistent.result b/mysql-test/suite/innodb/r/binlog_consistent.result
index 2e523c40a5b..68838e8d52b 100644
--- a/mysql-test/suite/innodb/r/binlog_consistent.result
+++ b/mysql-test/suite/innodb/r/binlog_consistent.result
@@ -3,11 +3,11 @@ RESET MASTER;
CREATE TABLE t1 (a INT, b VARCHAR(100), PRIMARY KEY (a,b)) ENGINE=innodb;
SHOW MASTER STATUS;
File Position Binlog_Do_DB Binlog_Ignore_DB
-master-bin.000001 380
+master-bin.000001 421
SHOW STATUS LIKE 'binlog_snapshot_%';
Variable_name Value
binlog_snapshot_file master-bin.000001
-binlog_snapshot_position 380
+binlog_snapshot_position 421
BEGIN;
INSERT INTO t1 VALUES (0, "");
# Connection con1
@@ -38,10 +38,10 @@ a b
SHOW STATUS LIKE 'binlog_snapshot_%';
Variable_name Value
binlog_snapshot_file master-bin.000001
-binlog_snapshot_position 904
+binlog_snapshot_position 945
SHOW MASTER STATUS;
File Position Binlog_Do_DB Binlog_Ignore_DB
-master-bin.000001 1316
+master-bin.000001 1357
SELECT * FROM t2 ORDER BY a;
a
2
@@ -60,44 +60,45 @@ a b
SHOW STATUS LIKE 'binlog_snapshot_%';
Variable_name Value
binlog_snapshot_file master-bin.000001
-binlog_snapshot_position 904
+binlog_snapshot_position 945
SHOW MASTER STATUS;
File Position Binlog_Do_DB Binlog_Ignore_DB
-master-bin.000002 245
+master-bin.000002 286
COMMIT;
SHOW STATUS LIKE 'binlog_snapshot_%';
Variable_name Value
binlog_snapshot_file master-bin.000002
-binlog_snapshot_position 245
+binlog_snapshot_position 286
SHOW MASTER STATUS;
File Position Binlog_Do_DB Binlog_Ignore_DB
-master-bin.000002 245
+master-bin.000002 286
SHOW BINLOG EVENTS;
Log_name Pos Event_type Server_id End_log_pos Info
-master-bin.000001 4 Format_desc 1 245 Server ver: #, Binlog ver: #
-master-bin.000001 245 Query 1 380 use `test`; CREATE TABLE t1 (a INT, b VARCHAR(100), PRIMARY KEY (a,b)) ENGINE=innodb
-master-bin.000001 380 Query 1 492 use `test`; CREATE TABLE t2 (a INT PRIMARY KEY) ENGINE=myisam
-master-bin.000001 492 Query 1 560 BEGIN
-master-bin.000001 560 Query 1 648 use `test`; INSERT INTO t2 VALUES (2)
-master-bin.000001 648 Query 1 717 COMMIT
-master-bin.000001 717 Query 1 785 BEGIN
-master-bin.000001 785 Query 1 877 use `test`; INSERT INTO t1 VALUES (0, "")
-master-bin.000001 877 Xid 1 904 COMMIT /* XID */
-master-bin.000001 904 Query 1 972 BEGIN
-master-bin.000001 972 Query 1 1060 use `test`; INSERT INTO t2 VALUES (3)
-master-bin.000001 1060 Query 1 1129 COMMIT
-master-bin.000001 1129 Query 1 1197 BEGIN
-master-bin.000001 1197 Query 1 1289 use `test`; INSERT INTO t1 VALUES (4, "")
-master-bin.000001 1289 Xid 1 1316 COMMIT /* XID */
-master-bin.000001 1316 Query 1 1384 BEGIN
-master-bin.000001 1384 Query 1 1476 use `test`; INSERT INTO t1 VALUES (1, "")
-master-bin.000001 1476 Xid 1 1503 COMMIT /* XID */
-master-bin.000001 1503 Query 1 1571 BEGIN
-master-bin.000001 1571 Query 1 1668 use `test`; INSERT INTO t1 VALUES (2, "first")
-master-bin.000001 1668 Query 1 1766 use `test`; INSERT INTO t1 VALUES (2, "second")
-master-bin.000001 1766 Xid 1 1793 COMMIT /* XID */
-master-bin.000001 1793 Query 1 1861 BEGIN
-master-bin.000001 1861 Query 1 1953 use `test`; INSERT INTO t1 VALUES (3, "")
-master-bin.000001 1953 Xid 1 1980 COMMIT /* XID */
-master-bin.000001 1980 Rotate 1 2024 master-bin.000002;pos=4
+master-bin.000001 4 Format_desc 1 246 Server ver: #, Binlog ver: #
+master-bin.000001 246 Binlog_checkpoint 1 286 master-bin.000001
+master-bin.000001 286 Query 1 421 use `test`; CREATE TABLE t1 (a INT, b VARCHAR(100), PRIMARY KEY (a,b)) ENGINE=innodb
+master-bin.000001 421 Query 1 533 use `test`; CREATE TABLE t2 (a INT PRIMARY KEY) ENGINE=myisam
+master-bin.000001 533 Query 1 601 BEGIN
+master-bin.000001 601 Query 1 689 use `test`; INSERT INTO t2 VALUES (2)
+master-bin.000001 689 Query 1 758 COMMIT
+master-bin.000001 758 Query 1 826 BEGIN
+master-bin.000001 826 Query 1 918 use `test`; INSERT INTO t1 VALUES (0, "")
+master-bin.000001 918 Xid 1 945 COMMIT /* XID */
+master-bin.000001 945 Query 1 1013 BEGIN
+master-bin.000001 1013 Query 1 1101 use `test`; INSERT INTO t2 VALUES (3)
+master-bin.000001 1101 Query 1 1170 COMMIT
+master-bin.000001 1170 Query 1 1238 BEGIN
+master-bin.000001 1238 Query 1 1330 use `test`; INSERT INTO t1 VALUES (4, "")
+master-bin.000001 1330 Xid 1 1357 COMMIT /* XID */
+master-bin.000001 1357 Query 1 1425 BEGIN
+master-bin.000001 1425 Query 1 1517 use `test`; INSERT INTO t1 VALUES (1, "")
+master-bin.000001 1517 Xid 1 1544 COMMIT /* XID */
+master-bin.000001 1544 Query 1 1612 BEGIN
+master-bin.000001 1612 Query 1 1709 use `test`; INSERT INTO t1 VALUES (2, "first")
+master-bin.000001 1709 Query 1 1807 use `test`; INSERT INTO t1 VALUES (2, "second")
+master-bin.000001 1807 Xid 1 1834 COMMIT /* XID */
+master-bin.000001 1834 Query 1 1902 BEGIN
+master-bin.000001 1902 Query 1 1994 use `test`; INSERT INTO t1 VALUES (3, "")
+master-bin.000001 1994 Xid 1 2021 COMMIT /* XID */
+master-bin.000001 2021 Rotate 1 2065 master-bin.000002;pos=4
DROP TABLE t1,t2;
diff --git a/mysql-test/suite/innodb/r/group_commit_binlog_pos.result b/mysql-test/suite/innodb/r/group_commit_binlog_pos.result
index d28ad1fd70e..29aa765c1b4 100644
--- a/mysql-test/suite/innodb/r/group_commit_binlog_pos.result
+++ b/mysql-test/suite/innodb/r/group_commit_binlog_pos.result
@@ -30,6 +30,6 @@ a
1
2
3
-InnoDB: Last MySQL binlog file position 0 906, file name ./master-bin.000001
+InnoDB: Last MySQL binlog file position 0 947, file name ./master-bin.000001
SET DEBUG_SYNC= 'RESET';
DROP TABLE t1;
diff --git a/mysql-test/suite/innodb/r/group_commit_binlog_pos_no_optimize_thread.result b/mysql-test/suite/innodb/r/group_commit_binlog_pos_no_optimize_thread.result
index da8cff142b8..3c3b0709331 100644
--- a/mysql-test/suite/innodb/r/group_commit_binlog_pos_no_optimize_thread.result
+++ b/mysql-test/suite/innodb/r/group_commit_binlog_pos_no_optimize_thread.result
@@ -31,6 +31,6 @@ a
1
2
3
-InnoDB: Last MySQL binlog file position 0 906, file name ./master-bin.000001
+InnoDB: Last MySQL binlog file position 0 947, file name ./master-bin.000001
SET DEBUG_SYNC= 'RESET';
DROP TABLE t1;
diff --git a/mysql-test/suite/innodb/r/group_commit_crash.result b/mysql-test/suite/innodb/r/group_commit_crash.result
index cd47ba62ff2..c084f854e79 100644
--- a/mysql-test/suite/innodb/r/group_commit_crash.result
+++ b/mysql-test/suite/innodb/r/group_commit_crash.result
@@ -36,7 +36,7 @@ COMMIT;
Got one of the listed errors
SELECT * FROM t1 ORDER BY id;
a b c d id
-SHOW BINLOG EVENTS LIMIT 2,1;
+SHOW BINLOG EVENTS LIMIT 3,1;
Log_name Pos Event_type Server_id End_log_pos Info
delete from t1;
SET binlog_format= mixed;
@@ -58,7 +58,7 @@ a b c d 7
a b c d 8
a b c d 9
a b c d 10
-SHOW BINLOG EVENTS LIMIT 2,1;
+SHOW BINLOG EVENTS LIMIT 3,1;
Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000001 # Query 1 # use `test`; insert into t1 select * from t2
delete from t1;
@@ -81,7 +81,7 @@ a b c d 7
a b c d 8
a b c d 9
a b c d 10
-SHOW BINLOG EVENTS LIMIT 2,1;
+SHOW BINLOG EVENTS LIMIT 3,1;
Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000001 # Query 1 # use `test`; insert into t1 select * from t2
delete from t1;
@@ -104,7 +104,7 @@ a b c d 7
a b c d 8
a b c d 9
a b c d 10
-SHOW BINLOG EVENTS LIMIT 2,1;
+SHOW BINLOG EVENTS LIMIT 3,1;
Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000001 # Query 1 # use `test`; insert into t1 select * from t2
delete from t1;
@@ -117,7 +117,7 @@ COMMIT;
Got one of the listed errors
SELECT * FROM t1 ORDER BY id;
a b c d id
-SHOW BINLOG EVENTS LIMIT 2,1;
+SHOW BINLOG EVENTS LIMIT 3,1;
Log_name Pos Event_type Server_id End_log_pos Info
delete from t1;
DROP TABLE t1;
diff --git a/mysql-test/suite/innodb/r/group_commit_crash_no_optimize_thread.result b/mysql-test/suite/innodb/r/group_commit_crash_no_optimize_thread.result
index c1ae510d45b..40c270a76d3 100644
--- a/mysql-test/suite/innodb/r/group_commit_crash_no_optimize_thread.result
+++ b/mysql-test/suite/innodb/r/group_commit_crash_no_optimize_thread.result
@@ -36,7 +36,7 @@ COMMIT;
Got one of the listed errors
SELECT * FROM t1 ORDER BY id;
a b c d id
-SHOW BINLOG EVENTS LIMIT 2,1;
+SHOW BINLOG EVENTS LIMIT 3,1;
Log_name Pos Event_type Server_id End_log_pos Info
delete from t1;
SET binlog_format= mixed;
@@ -58,7 +58,7 @@ a b c d 7
a b c d 8
a b c d 9
a b c d 10
-SHOW BINLOG EVENTS LIMIT 2,1;
+SHOW BINLOG EVENTS LIMIT 3,1;
Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000001 # Query 1 # use `test`; insert into t1 select * from t2
delete from t1;
@@ -81,7 +81,7 @@ a b c d 7
a b c d 8
a b c d 9
a b c d 10
-SHOW BINLOG EVENTS LIMIT 2,1;
+SHOW BINLOG EVENTS LIMIT 3,1;
Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000001 # Query 1 # use `test`; insert into t1 select * from t2
delete from t1;
@@ -104,7 +104,7 @@ a b c d 7
a b c d 8
a b c d 9
a b c d 10
-SHOW BINLOG EVENTS LIMIT 2,1;
+SHOW BINLOG EVENTS LIMIT 3,1;
Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000001 # Query 1 # use `test`; insert into t1 select * from t2
delete from t1;
@@ -117,7 +117,7 @@ COMMIT;
Got one of the listed errors
SELECT * FROM t1 ORDER BY id;
a b c d id
-SHOW BINLOG EVENTS LIMIT 2,1;
+SHOW BINLOG EVENTS LIMIT 3,1;
Log_name Pos Event_type Server_id End_log_pos Info
delete from t1;
DROP TABLE t1;
diff --git a/mysql-test/suite/innodb/t/group_commit_crash.test b/mysql-test/suite/innodb/t/group_commit_crash.test
index 12c92d19244..0a297e3c570 100644
--- a/mysql-test/suite/innodb/t/group_commit_crash.test
+++ b/mysql-test/suite/innodb/t/group_commit_crash.test
@@ -66,7 +66,7 @@ while ($numtests)
# table and binlog should be in sync.
SELECT * FROM t1 ORDER BY id;
--replace_column 2 # 5 #
- SHOW BINLOG EVENTS LIMIT 2,1;
+ SHOW BINLOG EVENTS LIMIT 3,1;
delete from t1;
diff --git a/mysql-test/suite/innodb/t/group_commit_crash_no_optimize_thread.test b/mysql-test/suite/innodb/t/group_commit_crash_no_optimize_thread.test
index 2de09d6b0b6..4214c2a6b03 100644
--- a/mysql-test/suite/innodb/t/group_commit_crash_no_optimize_thread.test
+++ b/mysql-test/suite/innodb/t/group_commit_crash_no_optimize_thread.test
@@ -66,7 +66,7 @@ while ($numtests)
# table and binlog should be in sync.
SELECT * FROM t1 ORDER BY id;
--replace_column 2 # 5 #
- SHOW BINLOG EVENTS LIMIT 2,1;
+ SHOW BINLOG EVENTS LIMIT 3,1;
delete from t1;
diff --git a/mysql-test/suite/maria/maria-connect.result b/mysql-test/suite/maria/maria-connect.result
index ed626a003f5..d79ebbdb86c 100644
--- a/mysql-test/suite/maria/maria-connect.result
+++ b/mysql-test/suite/maria/maria-connect.result
@@ -16,6 +16,7 @@ a
4
SHOW BINLOG EVENTS FROM <start_pos>;
Log_name Pos Event_type Server_id End_log_pos Info
+master-bin.000001 # Binlog_checkpoint 1 # master-bin.000001
master-bin.000001 # Query 1 # use `test`; CREATE TABLE t1 (a int primary key)
master-bin.000001 # Query 1 # BEGIN
master-bin.000001 # Query 1 # use `test`; insert t1 values (1),(2),(3)
diff --git a/mysql-test/suite/perfschema/r/all_instances.result b/mysql-test/suite/perfschema/r/all_instances.result
index caf4f49034f..7d3484fc887 100644
--- a/mysql-test/suite/perfschema/r/all_instances.result
+++ b/mysql-test/suite/perfschema/r/all_instances.result
@@ -77,6 +77,7 @@ wait/synch/mutex/sql/Master_info::sleep_lock
wait/synch/mutex/sql/MDL_map::mutex
wait/synch/mutex/sql/MDL_wait::LOCK_wait_status
wait/synch/mutex/sql/MYSQL_BIN_LOG::LOCK_index
+wait/synch/mutex/sql/MYSQL_BIN_LOG::LOCK_xid_list
wait/synch/mutex/sql/MYSQL_RELAY_LOG::LOCK_index
wait/synch/mutex/sql/Query_cache::structure_guard_mutex
wait/synch/mutex/sql/Relay_log_info::data_lock
@@ -129,6 +130,7 @@ wait/synch/cond/sql/Master_info::start_cond
wait/synch/cond/sql/Master_info::stop_cond
wait/synch/cond/sql/MDL_context::COND_wait_status
wait/synch/cond/sql/MYSQL_BIN_LOG::COND_queue_busy
+wait/synch/cond/sql/MYSQL_BIN_LOG::COND_xid_list
wait/synch/cond/sql/MYSQL_BIN_LOG::update_cond
wait/synch/cond/sql/MYSQL_RELAY_LOG::COND_queue_busy
wait/synch/cond/sql/MYSQL_RELAY_LOG::update_cond
diff --git a/mysql-test/suite/perfschema/r/relaylog.result b/mysql-test/suite/perfschema/r/relaylog.result
index a1d10265f4d..f8ff902245c 100644
--- a/mysql-test/suite/perfschema/r/relaylog.result
+++ b/mysql-test/suite/perfschema/r/relaylog.result
@@ -56,10 +56,10 @@ where event_name like "%MYSQL_BIN_LOG%"
and event_name not like "%MYSQL_BIN_LOG::update_cond"
order by event_name;
EVENT_NAME COUNT_STAR
-wait/synch/cond/sql/MYSQL_BIN_LOG::COND_prep_xids NONE
wait/synch/cond/sql/MYSQL_BIN_LOG::COND_queue_busy NONE
+wait/synch/cond/sql/MYSQL_BIN_LOG::COND_xid_list NONE
wait/synch/mutex/sql/MYSQL_BIN_LOG::LOCK_index MANY
-wait/synch/mutex/sql/MYSQL_BIN_LOG::LOCK_prep_xids NONE
+wait/synch/mutex/sql/MYSQL_BIN_LOG::LOCK_xid_list MANY
"Expect no slave relay log"
select * from performance_schema.file_summary_by_instance
where event_name like "%relaylog%" order by file_name;
@@ -131,10 +131,10 @@ where event_name like "%MYSQL_BIN_LOG%"
and event_name not like "%MYSQL_BIN_LOG::update_cond"
order by event_name;
EVENT_NAME COUNT_STAR
-wait/synch/cond/sql/MYSQL_BIN_LOG::COND_prep_xids NONE
wait/synch/cond/sql/MYSQL_BIN_LOG::COND_queue_busy NONE
+wait/synch/cond/sql/MYSQL_BIN_LOG::COND_xid_list NONE
wait/synch/mutex/sql/MYSQL_BIN_LOG::LOCK_index MANY
-wait/synch/mutex/sql/MYSQL_BIN_LOG::LOCK_prep_xids NONE
+wait/synch/mutex/sql/MYSQL_BIN_LOG::LOCK_xid_list MANY
"Expect a slave relay log"
select
substring(file_name, locate("slave-", file_name)) as FILE_NAME,
diff --git a/mysql-test/suite/rpl/r/rpl_checksum.result b/mysql-test/suite/rpl/r/rpl_checksum.result
index ba5cb1b1b2b..9e561908a7b 100644
--- a/mysql-test/suite/rpl/r/rpl_checksum.result
+++ b/mysql-test/suite/rpl/r/rpl_checksum.result
@@ -71,7 +71,7 @@ insert into t1 values (1) /* will not be applied on slave due to simulation */;
set @@global.debug_dbug='d,simulate_slave_unaware_checksum';
start slave;
include/wait_for_slave_io_error.inc [errno=1236]
-Last_IO_Error = 'Got fatal error 1236 from master when reading data from binary log: 'Slave can not handle replication events with the checksum that master is configured to log; the first event 'master-bin.000009' at 245, the last event read from 'master-bin.000010' at 245, the last byte read from 'master-bin.000010' at 245.''
+Last_IO_Error = 'Got fatal error 1236 from master when reading data from binary log: 'Slave can not handle replication events with the checksum that master is configured to log; the first event 'master-bin.000009' at 286, the last event read from 'master-bin.000010' at 246, the last byte read from 'master-bin.000010' at 246.''
select count(*) as zero from t1;
zero
0
diff --git a/mysql-test/suite/rpl/r/rpl_mariadb_slave_capability.result b/mysql-test/suite/rpl/r/rpl_mariadb_slave_capability.result
index 5eae28441c2..9af3d4bbfd2 100644
--- a/mysql-test/suite/rpl/r/rpl_mariadb_slave_capability.result
+++ b/mysql-test/suite/rpl/r/rpl_mariadb_slave_capability.result
@@ -54,7 +54,7 @@ master-bin.000002 # Query # # COMMIT
SELECT * FROM t1;
a
2
-show relaylog events in 'slave-relay-bin.000005' from <binlog_start> limit 3,5;
+show relaylog events in 'slave-relay-bin.000005' from <binlog_start> limit 4,5;
Log_name Pos Event_type Server_id End_log_pos Info
slave-relay-bin.000005 # Query # # BEGIN
slave-relay-bin.000005 # Query # # # Dummy ev
diff --git a/mysql-test/suite/rpl/r/rpl_row_annotate_do.result b/mysql-test/suite/rpl/r/rpl_row_annotate_do.result
index a7dc2a569a1..cb1aab28603 100644
--- a/mysql-test/suite/rpl/r/rpl_row_annotate_do.result
+++ b/mysql-test/suite/rpl/r/rpl_row_annotate_do.result
@@ -55,6 +55,7 @@ a b
FLUSH LOGS;
show binlog events in 'slave-bin.000001' from <start_pos>;
Log_name Pos Event_type Server_id End_log_pos Info
+slave-bin.000001 # Binlog_checkpoint 2 # slave-bin.000001
slave-bin.000001 # Query 1 # DROP DATABASE IF EXISTS test1
slave-bin.000001 # Query 1 # CREATE DATABASE test1
slave-bin.000001 # Query 1 # use `test1`; CREATE TABLE t1(a int primary key, b int)
diff --git a/mysql-test/suite/rpl/r/rpl_row_annotate_dont.result b/mysql-test/suite/rpl/r/rpl_row_annotate_dont.result
index 2a3b5b1870e..b7648fd8592 100644
--- a/mysql-test/suite/rpl/r/rpl_row_annotate_dont.result
+++ b/mysql-test/suite/rpl/r/rpl_row_annotate_dont.result
@@ -47,6 +47,7 @@ a b
FLUSH LOGS;
show binlog events in 'slave-bin.000001' from <start_pos>;
Log_name Pos Event_type Server_id End_log_pos Info
+slave-bin.000001 # Binlog_checkpoint 2 # slave-bin.000001
slave-bin.000001 # Query 1 # DROP DATABASE IF EXISTS test1
slave-bin.000001 # Query 1 # CREATE DATABASE test1
slave-bin.000001 # Query 1 # use `test1`; CREATE TABLE t1(a int primary key, b int)
diff --git a/mysql-test/suite/rpl/r/rpl_row_show_relaylog_events.result b/mysql-test/suite/rpl/r/rpl_row_show_relaylog_events.result
index 7c55e44ed59..8534bf00711 100644
--- a/mysql-test/suite/rpl/r/rpl_row_show_relaylog_events.result
+++ b/mysql-test/suite/rpl/r/rpl_row_show_relaylog_events.result
@@ -94,6 +94,7 @@ show relaylog events in 'slave-relay-bin.000003' from <binlog_start>;
Log_name Pos Event_type Server_id End_log_pos Info
slave-relay-bin.000003 # Rotate # # master-bin.000001;pos=4
slave-relay-bin.000003 # Format_desc # # SERVER_VERSION, BINLOG_VERSION
+slave-relay-bin.000003 # Binlog_checkpoint # # master-bin.000001
slave-relay-bin.000003 # Query # # use `test`; CREATE TABLE t1 (a INT)
slave-relay-bin.000003 # Query # # BEGIN
slave-relay-bin.000003 # Table_map # # table_id: # (test.t1)
@@ -115,8 +116,8 @@ slave-relay-bin.000003 # Rotate # # master-bin.000001;pos=4
show relaylog events in 'slave-relay-bin.000003' from <binlog_start> limit 1,3;
Log_name Pos Event_type Server_id End_log_pos Info
slave-relay-bin.000003 # Format_desc # # SERVER_VERSION, BINLOG_VERSION
+slave-relay-bin.000003 # Binlog_checkpoint # # master-bin.000001
slave-relay-bin.000003 # Query # # use `test`; CREATE TABLE t1 (a INT)
-slave-relay-bin.000003 # Query # # BEGIN
******** [slave] SHOW RELAYLOG EVENTS ********
show relaylog events from <binlog_start>;
Log_name Pos Event_type Server_id End_log_pos Info
@@ -185,6 +186,7 @@ show relaylog events in 'slave-relay-bin.000006' from <binlog_start>;
Log_name Pos Event_type Server_id End_log_pos Info
slave-relay-bin.000006 # Rotate # # master-bin.000002;pos=4
slave-relay-bin.000006 # Format_desc # # SERVER_VERSION, BINLOG_VERSION
+slave-relay-bin.000006 # Binlog_checkpoint # # master-bin.000002
slave-relay-bin.000006 # Query # # use `test`; DROP TABLE `t1` /* generated by server */
******** [slave] SHOW RELAYLOG EVENTS IN <FILE> LIMIT 1 ********
show relaylog events in 'slave-relay-bin.000006' from <binlog_start> limit 1;
@@ -194,6 +196,7 @@ slave-relay-bin.000006 # Rotate # # master-bin.000002;pos=4
show relaylog events in 'slave-relay-bin.000006' from <binlog_start> limit 1,3;
Log_name Pos Event_type Server_id End_log_pos Info
slave-relay-bin.000006 # Format_desc # # SERVER_VERSION, BINLOG_VERSION
+slave-relay-bin.000006 # Binlog_checkpoint # # master-bin.000002
slave-relay-bin.000006 # Query # # use `test`; DROP TABLE `t1` /* generated by server */
******** [slave] SHOW RELAYLOG EVENTS ********
show relaylog events from <binlog_start>;
diff --git a/mysql-test/suite/rpl/r/rpl_stm_mix_show_relaylog_events.result b/mysql-test/suite/rpl/r/rpl_stm_mix_show_relaylog_events.result
index f706fa0fe75..a978c3c900c 100644
--- a/mysql-test/suite/rpl/r/rpl_stm_mix_show_relaylog_events.result
+++ b/mysql-test/suite/rpl/r/rpl_stm_mix_show_relaylog_events.result
@@ -82,6 +82,7 @@ show relaylog events in 'slave-relay-bin.000003' from <binlog_start>;
Log_name Pos Event_type Server_id End_log_pos Info
slave-relay-bin.000003 # Rotate # # master-bin.000001;pos=4
slave-relay-bin.000003 # Format_desc # # SERVER_VERSION, BINLOG_VERSION
+slave-relay-bin.000003 # Binlog_checkpoint # # master-bin.000001
slave-relay-bin.000003 # Query # # use `test`; CREATE TABLE t1 (a INT)
slave-relay-bin.000003 # Query # # BEGIN
slave-relay-bin.000003 # Query # # use `test`; INSERT INTO t1 VALUES (1)
@@ -100,8 +101,8 @@ slave-relay-bin.000003 # Rotate # # master-bin.000001;pos=4
show relaylog events in 'slave-relay-bin.000003' from <binlog_start> limit 1,3;
Log_name Pos Event_type Server_id End_log_pos Info
slave-relay-bin.000003 # Format_desc # # SERVER_VERSION, BINLOG_VERSION
+slave-relay-bin.000003 # Binlog_checkpoint # # master-bin.000001
slave-relay-bin.000003 # Query # # use `test`; CREATE TABLE t1 (a INT)
-slave-relay-bin.000003 # Query # # BEGIN
******** [slave] SHOW RELAYLOG EVENTS ********
show relaylog events from <binlog_start>;
Log_name Pos Event_type Server_id End_log_pos Info
@@ -164,6 +165,7 @@ show relaylog events in 'slave-relay-bin.000006' from <binlog_start>;
Log_name Pos Event_type Server_id End_log_pos Info
slave-relay-bin.000006 # Rotate # # master-bin.000002;pos=4
slave-relay-bin.000006 # Format_desc # # SERVER_VERSION, BINLOG_VERSION
+slave-relay-bin.000006 # Binlog_checkpoint # # master-bin.000002
slave-relay-bin.000006 # Query # # use `test`; DROP TABLE `t1` /* generated by server */
******** [slave] SHOW RELAYLOG EVENTS IN <FILE> LIMIT 1 ********
show relaylog events in 'slave-relay-bin.000006' from <binlog_start> limit 1;
@@ -173,6 +175,7 @@ slave-relay-bin.000006 # Rotate # # master-bin.000002;pos=4
show relaylog events in 'slave-relay-bin.000006' from <binlog_start> limit 1,3;
Log_name Pos Event_type Server_id End_log_pos Info
slave-relay-bin.000006 # Format_desc # # SERVER_VERSION, BINLOG_VERSION
+slave-relay-bin.000006 # Binlog_checkpoint # # master-bin.000002
slave-relay-bin.000006 # Query # # use `test`; DROP TABLE `t1` /* generated by server */
******** [slave] SHOW RELAYLOG EVENTS ********
show relaylog events from <binlog_start>;
diff --git a/mysql-test/suite/rpl/t/rpl_mariadb_slave_capability.test b/mysql-test/suite/rpl/t/rpl_mariadb_slave_capability.test
index 77aa9341ff4..36f4defa252 100644
--- a/mysql-test/suite/rpl/t/rpl_mariadb_slave_capability.test
+++ b/mysql-test/suite/rpl/t/rpl_mariadb_slave_capability.test
@@ -61,7 +61,7 @@ connection slave;
SELECT * FROM t1;
let $binlog_file= query_get_value(SHOW SLAVE STATUS, Relay_Log_File, 1);
let $binlog_start= 0;
-let $binlog_limit=3,5;
+let $binlog_limit=4,5;
--source include/show_relaylog_events.inc
--echo # Test that slave which cannot tolerate holes in binlog stream but
diff --git a/mysql-test/t/mysqlbinlog2.test b/mysql-test/t/mysqlbinlog2.test
index 740c4078f20..986e180db13 100644
--- a/mysql-test/t/mysqlbinlog2.test
+++ b/mysql-test/t/mysqlbinlog2.test
@@ -23,7 +23,7 @@ insert into t1 values(null, "b");
set timestamp=@a+2;
--let $binlog_pos_760=query_get_value(SHOW MASTER STATUS, Position, 1)
insert into t1 values(null, "c");
---let $binlog_pos_951=query_get_value(SHOW BINLOG EVENTS in 'master-bin.000001' from $binlog_pos_760, Pos, 4)
+--let $binlog_pos_951=query_get_value(SHOW BINLOG EVENTS in 'master-bin.000001' from $binlog_pos_760, Pos, 5)
set timestamp=@a+4;
insert into t1 values(null, "d");
insert into t1 values(null, "e");
@@ -31,8 +31,8 @@ insert into t1 values(null, "e");
flush logs;
set timestamp=@a+1; # this could happen on a slave
insert into t1 values(null, "f");
---let $binlog_pos_135=query_get_value(SHOW BINLOG EVENTS in 'master-bin.000002', Pos, 3)
---let $binlog_pos_203=query_get_value(SHOW BINLOG EVENTS in 'master-bin.000002', Pos, 4)
+--let $binlog_pos_135=query_get_value(SHOW BINLOG EVENTS in 'master-bin.000002', Pos, 4)
+--let $binlog_pos_203=query_get_value(SHOW BINLOG EVENTS in 'master-bin.000002', Pos, 5)
# delimiters are for easier debugging in future
@@ -50,22 +50,22 @@ let $MYSQLD_DATADIR= `select @@datadir`;
--disable_query_log
select "--- offset --" as "";
--enable_query_log
---exec $MYSQL_BINLOG --short-form --offset=2 $MYSQLD_DATADIR/master-bin.000001
+--exec $MYSQL_BINLOG --short-form --offset=3 $MYSQLD_DATADIR/master-bin.000001
--disable_query_log
select "--- start-position --" as "";
--enable_query_log
-let $start_pos= `select @binlog_start_pos + 653`;
+let $start_pos= `select @binlog_start_pos + 693`;
--exec $MYSQL_BINLOG --short-form --start-position=$start_pos $MYSQLD_DATADIR/master-bin.000001
--disable_query_log
select "--- stop-position --" as "";
--enable_query_log
-let $stop_pos= `select @binlog_start_pos + 653`;
+let $stop_pos= `select @binlog_start_pos + 693`;
--exec $MYSQL_BINLOG --short-form --stop-position=$stop_pos $MYSQLD_DATADIR/master-bin.000001
--disable_query_log
select "--- start and stop positions ---" as "";
--enable_query_log
-let $start_pos= `select @binlog_start_pos + 653`;
-let $stop_pos= `select @binlog_start_pos + 770`;
+let $start_pos= `select @binlog_start_pos + 693`;
+let $stop_pos= `select @binlog_start_pos + 810`;
--exec $MYSQL_BINLOG --short-form --start-position=$start_pos --stop-position=$stop_pos $MYSQLD_DATADIR/master-bin.000001
--disable_query_log
select "--- start-datetime --" as "";
@@ -88,16 +88,16 @@ flush logs;
--disable_query_log
select "--- offset --" as "";
--enable_query_log
---exec $MYSQL_BINLOG --short-form --offset=2 $MYSQLD_DATADIR/master-bin.000001 $MYSQLD_DATADIR/master-bin.000002
+--exec $MYSQL_BINLOG --short-form --offset=3 $MYSQLD_DATADIR/master-bin.000001 $MYSQLD_DATADIR/master-bin.000002
--disable_query_log
select "--- start-position --" as "";
--enable_query_log
-let $start_pos= `select @binlog_start_pos + 653`;
+let $start_pos= `select @binlog_start_pos + 693`;
--exec $MYSQL_BINLOG --short-form --start-position=$start_pos $MYSQLD_DATADIR/master-bin.000001 $MYSQLD_DATADIR/master-bin.000002
--disable_query_log
select "--- stop-position --" as "";
--enable_query_log
-let $stop_pos= `select @binlog_start_pos + 69`;
+let $stop_pos= `select @binlog_start_pos + 109`;
--exec $MYSQL_BINLOG --short-form --stop-position=$stop_pos $MYSQLD_DATADIR/master-bin.000001 $MYSQLD_DATADIR/master-bin.000002
--disable_query_log
select "--- start-datetime --" as "";
@@ -117,22 +117,22 @@ select "--- Remote --" as "";
--disable_query_log
select "--- offset --" as "";
--enable_query_log
---exec $MYSQL_BINLOG --short-form --offset=2 --read-from-remote-server --user=root --host=127.0.0.1 --port=$MASTER_MYPORT master-bin.000001
+--exec $MYSQL_BINLOG --short-form --offset=3 --read-from-remote-server --user=root --host=127.0.0.1 --port=$MASTER_MYPORT master-bin.000001
--disable_query_log
select "--- start-position --" as "";
--enable_query_log
-let $start_pos= `select @binlog_start_pos + 653`;
+let $start_pos= `select @binlog_start_pos + 693`;
--exec $MYSQL_BINLOG --short-form --start-position=$start_pos --read-from-remote-server --user=root --host=127.0.0.1 --port=$MASTER_MYPORT master-bin.000001
--disable_query_log
select "--- stop-position --" as "";
--enable_query_log
-let $stop_pos= `select @binlog_start_pos + 653`;
+let $stop_pos= `select @binlog_start_pos + 693`;
--exec $MYSQL_BINLOG --short-form --stop-position=$stop_pos --read-from-remote-server --user=root --host=127.0.0.1 --port=$MASTER_MYPORT master-bin.000001
--disable_query_log
select "--- start and stop positions ---" as "";
--enable_query_log
-let $start_pos= `select @binlog_start_pos + 653`;
-let $stop_pos= `select @binlog_start_pos + 770`;
+let $start_pos= `select @binlog_start_pos + 693`;
+let $stop_pos= `select @binlog_start_pos + 810`;
--exec $MYSQL_BINLOG --short-form --start-position=$start_pos --stop-position $stop_pos --read-from-remote-server --user=root --host=127.0.0.1 --port=$MASTER_MYPORT master-bin.000001
--disable_query_log
select "--- start-datetime --" as "";
@@ -152,16 +152,16 @@ select "--- Remote with 2 binlogs on command line --" as "";
--disable_query_log
select "--- offset --" as "";
--enable_query_log
---exec $MYSQL_BINLOG --short-form --offset=2 --read-from-remote-server --user=root --host=127.0.0.1 --port=$MASTER_MYPORT master-bin.000001 master-bin.000002
+--exec $MYSQL_BINLOG --short-form --offset=3 --read-from-remote-server --user=root --host=127.0.0.1 --port=$MASTER_MYPORT master-bin.000001 master-bin.000002
--disable_query_log
select "--- start-position --" as "";
--enable_query_log
-let $start_pos= `select @binlog_start_pos + 653`;
+let $start_pos= `select @binlog_start_pos + 693`;
--exec $MYSQL_BINLOG --short-form --start-position=$start_pos --read-from-remote-server --user=root --host=127.0.0.1 --port=$MASTER_MYPORT master-bin.000001 master-bin.000002
--disable_query_log
select "--- stop-position --" as "";
--enable_query_log
-let $stop_pos= `select @binlog_start_pos + 28`;
+let $stop_pos= `select @binlog_start_pos + 68`;
--exec $MYSQL_BINLOG --short-form --stop-position=$stop_pos --read-from-remote-server --user=root --host=127.0.0.1 --port=$MASTER_MYPORT master-bin.000001 master-bin.000002
--disable_query_log
select "--- start-datetime --" as "";
diff --git a/mysql-test/t/mysqldump-max.test b/mysql-test/t/mysqldump-max.test
index 27c1a3ce20c..d0a4870ba31 100644
--- a/mysql-test/t/mysqldump-max.test
+++ b/mysql-test/t/mysqldump-max.test
@@ -1194,7 +1194,7 @@ DROP TABLE t2;
--exec $MYSQL test < $MYSQLTEST_VARDIR/tmp/mwl136.sql
--replace_regex /\/\* xid=.* \*\//\/* XID *\// /Server ver: .*, Binlog ver: .*/Server ver: #, Binlog ver: #/ /table_id: [0-9]+/table_id: #/
-SHOW BINLOG EVENTS LIMIT 6,3;
+SHOW BINLOG EVENTS LIMIT 7,3;
--perl
my $f= "$ENV{MYSQLTEST_VARDIR}/tmp/mwl136.sql";
open F, '<', $f or die "Failed to open $f: $!\n";
diff --git a/mysql-test/t/xa_binlog.test b/mysql-test/t/xa_binlog.test
index 48f1dc6dfaa..430d45ab86a 100644
--- a/mysql-test/t/xa_binlog.test
+++ b/mysql-test/t/xa_binlog.test
@@ -27,6 +27,6 @@ SELECT * FROM t1 ORDER BY a;
--replace_column 2 # 5 #
--replace_regex /xid=[0-9]+/xid=XX/
-SHOW BINLOG EVENTS LIMIT 1,9;
+SHOW BINLOG EVENTS LIMIT 2,9;
DROP TABLE t1;
diff --git a/sql/handler.cc b/sql/handler.cc
index 58d37532796..e7eddef55ed 100644
--- a/sql/handler.cc
+++ b/sql/handler.cc
@@ -1286,6 +1286,7 @@ int ha_commit_trans(THD *thd, bool all)
if (!cookie)
goto err;
+ DEBUG_SYNC(thd, "ha_commit_trans_after_log_and_order");
DBUG_EXECUTE_IF("crash_commit_after_log", DBUG_SUICIDE(););
error= commit_one_phase_2(thd, all, trans, is_real_trans) ? 2 : 0;
diff --git a/sql/log.cc b/sql/log.cc
index 56c07f81c9e..430f0a0bf60 100644
--- a/sql/log.cc
+++ b/sql/log.cc
@@ -479,6 +479,7 @@ public:
*/
bool using_xa;
my_xid xa_xid;
+ ulong cookie;
private:
@@ -1665,6 +1666,21 @@ binlog_flush_cache(THD *thd, binlog_cache_mngr *cache_mngr,
end_ev, all,
using_stmt, using_trx);
}
+ else
+ {
+ /*
+ This can happen in row-format binlog with something like
+ BEGIN; INSERT INTO nontrans_table; INSERT IGNORE INTO trans_table;
+ The nontrans_table is written directly into the binlog before commit,
+ and if the trans_table is ignored there will be no rows to write when
+ we get here.
+
+ So there is no work to do. Therefore, we will not increment any XID
+ count, so we must not decrement any XID count in unlog().
+ */
+ if (cache_mngr->using_xa && cache_mngr->xa_xid)
+ cache_mngr->cookie= BINLOG_COOKIE_DUMMY;
+ }
cache_mngr->reset(using_stmt, using_trx);
DBUG_ASSERT((!using_stmt || cache_mngr->stmt_cache.empty()) &&
@@ -2888,7 +2904,8 @@ const char *MYSQL_LOG::generate_name(const char *log_name,
MYSQL_BIN_LOG::MYSQL_BIN_LOG(uint *sync_period)
- :bytes_written(0), prepared_xids(0), file_id(1), open_count(1),
+ :current_binlog_id(BINLOG_COOKIE_START), reset_master_pending(false),
+ bytes_written(0), file_id(1), open_count(1),
need_start_event(TRUE),
group_commit_queue(0), group_commit_queue_busy(FALSE),
num_commits(0), num_group_commits(0),
@@ -2916,13 +2933,30 @@ void MYSQL_BIN_LOG::cleanup()
DBUG_ENTER("cleanup");
if (inited)
{
+ xid_count_per_binlog *b;
+
inited= 0;
close(LOG_CLOSE_INDEX|LOG_CLOSE_STOP_EVENT);
delete description_event_for_queue;
delete description_event_for_exec;
+
+ while ((b= binlog_xid_count_list.get()))
+ {
+ /*
+ There should be no pending XIDs at shutdown, and only one entry (for
+ the active binlog file) in the list.
+ */
+ DBUG_ASSERT(b->xid_count == 0);
+ DBUG_ASSERT(!binlog_xid_count_list.head());
+ my_free(b);
+ }
+
mysql_mutex_destroy(&LOCK_log);
mysql_mutex_destroy(&LOCK_index);
+ mysql_mutex_destroy(&LOCK_xid_list);
mysql_cond_destroy(&update_cond);
+ mysql_cond_destroy(&COND_queue_busy);
+ mysql_cond_destroy(&COND_xid_list);
}
DBUG_VOID_RETURN;
}
@@ -2944,8 +2978,11 @@ void MYSQL_BIN_LOG::init_pthread_objects()
MYSQL_LOG::init_pthread_objects();
mysql_mutex_init(m_key_LOCK_index, &LOCK_index, MY_MUTEX_INIT_SLOW);
mysql_mutex_setflags(&LOCK_index, MYF_NO_DEADLOCK_DETECTION);
+ mysql_mutex_init(key_BINLOG_LOCK_xid_list,
+ &LOCK_xid_list, MY_MUTEX_INIT_FAST);
mysql_cond_init(m_key_update_cond, &update_cond, 0);
mysql_cond_init(m_key_COND_queue_busy, &COND_queue_busy, 0);
+ mysql_cond_init(key_BINLOG_COND_xid_list, &COND_xid_list, 0);
}
@@ -3149,6 +3186,51 @@ bool MYSQL_BIN_LOG::open(const char *log_name,
if (s.write(&log_file))
goto err;
bytes_written+= s.data_written;
+
+ if (!is_relay_log)
+ {
+ char buf[FN_REFLEN];
+ /*
+ Put this one into the list of active binlogs.
+ Write the current binlog checkpoint into the log, so XA recovery will
+ know from where to start recovery.
+ */
+ uint off= dirname_length(log_file_name);
+ uint len= strlen(log_file_name) - off;
+ char *entry_mem, *name_mem;
+ xid_count_per_binlog *b, *b2;
+ if (!(b = (xid_count_per_binlog *)
+ my_multi_malloc(MYF(MY_WME),
+ &entry_mem, sizeof(xid_count_per_binlog),
+ &name_mem, len,
+ NULL)))
+ goto err;
+ memcpy(name_mem, log_file_name+off, len);
+ b->binlog_name= name_mem;
+ b->binlog_name_len= len;
+ b->xid_count= 0;
+
+ mysql_mutex_lock(&LOCK_xid_list);
+ b->binlog_id= ++current_binlog_id;
+
+ /*
+ Remove any initial entries with no pending XIDs.
+ Normally this will be done in unlog(), but if there are no
+ transactions with an XA-capable engine at all in a given binlog
+ file, unlog() will never be used and we will remove the entry here.
+ */
+ while ((b2= binlog_xid_count_list.head()) && b2->xid_count == 0)
+ my_free(binlog_xid_count_list.get());
+
+ binlog_xid_count_list.push_back(b);
+ b2= binlog_xid_count_list.head();
+ strmake(buf, b2->binlog_name, b2->binlog_name_len);
+ mysql_mutex_unlock(&LOCK_xid_list);
+ Binlog_checkpoint_log_event ev(buf, len);
+ if (ev.write(&log_file))
+ goto err;
+ bytes_written+= ev.data_written;
+ }
}
if (description_event_for_queue &&
description_event_for_queue->binlog_version>=4)
@@ -3514,6 +3596,42 @@ bool MYSQL_BIN_LOG::reset_logs(THD* thd)
mysql_mutex_lock(&LOCK_log);
mysql_mutex_lock(&LOCK_index);
+ if (!is_relay_log)
+ {
+ /*
+ We are going to nuke all binary log files.
+ So first wait until all pending binlog checkpoints have completed.
+ */
+ mysql_mutex_lock(&LOCK_xid_list);
+ xid_count_per_binlog *b;
+ reset_master_pending= true;
+ for (;;)
+ {
+ I_List_iterator<xid_count_per_binlog> it(binlog_xid_count_list);
+ while ((b= it++))
+ {
+ if (b->xid_count > 0)
+ break;
+ }
+ if (!b)
+ break; /* No more pending XIDs */
+ /*
+ Wait until signalled that one more binlog dropped to zero, then check
+ again.
+ */
+ mysql_cond_wait(&COND_xid_list, &LOCK_xid_list);
+ }
+
+ /*
+ Now all XIDs are fully flushed to disk, and we are holding LOCK_log so
+ no new ones will be written. So we can proceed to delete the logs.
+ */
+ while ((b= binlog_xid_count_list.get()))
+ my_free(b);
+ reset_master_pending= false;
+ mysql_mutex_unlock(&LOCK_xid_list);
+ }
+
/*
The following mutex is needed to ensure that no threads call
'delete thd' as we would then risk missing a 'rollback' from this
@@ -3824,8 +3942,7 @@ int MYSQL_BIN_LOG::purge_logs(const char *to_log,
if ((error=find_log_pos(&log_info, NullS, 0 /*no mutex*/)))
goto err;
while ((strcmp(to_log,log_info.log_file_name) || (exit_loop=included)) &&
- !is_active(log_info.log_file_name) &&
- !log_in_use(log_info.log_file_name))
+ can_purge_log(log_info.log_file_name))
{
if ((error= register_purge_index_entry(log_info.log_file_name)))
{
@@ -4175,8 +4292,7 @@ int MYSQL_BIN_LOG::purge_logs_before_date(time_t purge_time)
goto err;
while (strcmp(log_file_name, log_info.log_file_name) &&
- !is_active(log_info.log_file_name) &&
- !log_in_use(log_info.log_file_name))
+ can_purge_log(log_info.log_file_name))
{
if (!mysql_file_stat(m_key_file_log,
log_info.log_file_name, &stat_area, MYF(0)))
@@ -4231,6 +4347,28 @@ err:
mysql_mutex_unlock(&LOCK_index);
DBUG_RETURN(error);
}
+
+
+bool
+MYSQL_BIN_LOG::can_purge_log(const char *log_file_name)
+{
+ xid_count_per_binlog *b;
+
+ if (is_active(log_file_name))
+ return false;
+ mysql_mutex_lock(&LOCK_xid_list);
+ {
+ I_List_iterator<xid_count_per_binlog> it(binlog_xid_count_list);
+ while ((b= it++) &&
+ 0 != strncmp(log_file_name+dirname_length(log_file_name),
+ b->binlog_name, b->binlog_name_len))
+ ;
+ }
+ mysql_mutex_unlock(&LOCK_xid_list);
+ if (b)
+ return false;
+ return !log_in_use(log_file_name);
+}
#endif /* HAVE_REPLICATION */
@@ -4324,26 +4462,6 @@ int MYSQL_BIN_LOG::new_file_impl(bool need_lock)
mysql_mutex_assert_owner(&LOCK_log);
mysql_mutex_assert_owner(&LOCK_index);
- /*
- if binlog is used as tc log, be sure all xids are "unlogged",
- so that on recover we only need to scan one - latest - binlog file
- for prepared xids. As this is expected to be a rare event,
- simple wait strategy is enough. We're locking LOCK_log to be sure no
- new Xid_log_event's are added to the log (and prepared_xids is not
- increased), and waiting on COND_prep_xids for late threads to
- catch up.
- */
- if (prepared_xids)
- {
- tc_log_page_waits++;
- mysql_mutex_lock(&LOCK_prep_xids);
- while (prepared_xids) {
- DBUG_PRINT("info", ("prepared_xids=%lu", prepared_xids));
- mysql_cond_wait(&COND_prep_xids, &LOCK_prep_xids);
- }
- mysql_mutex_unlock(&LOCK_prep_xids);
- }
-
/* Reuse old name if not binlog and not update log */
new_name_ptr= name;
@@ -5792,6 +5910,37 @@ bool MYSQL_BIN_LOG::write_incident(THD *thd)
DBUG_RETURN(error);
}
+void
+MYSQL_BIN_LOG::write_binlog_checkpoint_event_already_locked(const char *name,
+ uint len)
+{
+ Binlog_checkpoint_log_event ev(name, len);
+ /*
+ Note that we must sync the binlog checkpoint to disk.
+ Otherwise a subsequent log purge could delete binlogs that XA recovery
+ thinks are needed (even though they are not really).
+ */
+ if (!ev.write(&log_file) && !flush_and_sync(0))
+ {
+ bool check_purge= false;
+ signal_update();
+ rotate(false, &check_purge);
+ if (check_purge)
+ purge();
+ return;
+ }
+
+ /*
+ If we fail to write the checkpoint event, something is probably really
+ bad with the binlog. We complain in the error log.
+ Note that failure to write binlog checkpoint does not compromise the
+ ability to do crash recovery - crash recovery will just have to scan a
+ bit more of the binlog than strictly necessary.
+ */
+ sql_print_error("Failed to write binlog checkpoint event to binary log\n");
+}
+
+
/**
Write a cached log entry to the binary log.
- To support transaction over replication, we wrap the transaction
@@ -5951,7 +6100,7 @@ MYSQL_BIN_LOG::write_transaction_to_binlog_events(group_commit_entry *entry)
for a transaction if log_xid() fails).
*/
if (entry->cache_mngr->using_xa && entry->cache_mngr->xa_xid)
- mark_xid_done();
+ mark_xid_done(entry->cache_mngr->cookie);
return 1;
}
@@ -5972,7 +6121,6 @@ MYSQL_BIN_LOG::trx_group_commit_leader(group_commit_entry *leader)
uint xid_count= 0;
my_off_t UNINIT_VAR(commit_offset);
group_commit_entry *current;
- group_commit_entry *last_in_queue;
group_commit_entry *queue= NULL;
bool check_purge= false;
DBUG_ENTER("MYSQL_BIN_LOG::trx_group_commit_leader");
@@ -5993,7 +6141,6 @@ MYSQL_BIN_LOG::trx_group_commit_leader(group_commit_entry *leader)
mysql_mutex_unlock(&LOCK_prepare_ordered);
/* As the queue is in reverse order of entering, reverse it. */
- last_in_queue= current;
while (current)
{
group_commit_entry *next= current->next;
@@ -6032,7 +6179,10 @@ MYSQL_BIN_LOG::trx_group_commit_leader(group_commit_entry *leader)
commit_offset= my_b_write_tell(&log_file);
cache_mngr->last_commit_pos_offset= commit_offset;
if (cache_mngr->using_xa && cache_mngr->xa_xid)
+ {
xid_count++;
+ cache_mngr->cookie= current_binlog_id;
+ }
}
bool synced= 0;
@@ -6075,16 +6225,14 @@ MYSQL_BIN_LOG::trx_group_commit_leader(group_commit_entry *leader)
}
/*
- if any commit_events are Xid_log_event, increase the number of
- prepared_xids (it's decreased in ::unlog()). Binlog cannot be rotated
- if there're prepared xids in it - see the comment in new_file() for
- an explanation.
- If no Xid_log_events (then it's all Query_log_event) rotate binlog,
- if necessary.
+ If any commit_events are Xid_log_event, increase the number of pending
+ XIDs in current binlog (it's decreased in ::unlog()). When the count in
+ a (not active) binlog file reaches zero, we know that it is no longer
+ needed in XA recovery, and we can log a new binlog checkpoint event.
*/
if (xid_count > 0)
{
- mark_xids_active(xid_count);
+ mark_xids_active(current_binlog_id, xid_count);
}
else
{
@@ -6092,11 +6240,11 @@ MYSQL_BIN_LOG::trx_group_commit_leader(group_commit_entry *leader)
{
/*
If we fail to rotate, which thread should get the error?
- We give the error to the *last* transaction thread; that seems to
- make the most sense, as it was the last to write to the log.
+ We give the error to the leader, as any my_error() thrown inside
+ rotate() will have been registered for the leader THD.
*/
- last_in_queue->error= ER_ERROR_ON_WRITE;
- last_in_queue->commit_errno= errno;
+ leader->error= ER_ERROR_ON_WRITE;
+ leader->commit_errno= errno;
check_purge= false;
}
}
@@ -6113,9 +6261,6 @@ MYSQL_BIN_LOG::trx_group_commit_leader(group_commit_entry *leader)
*/
mysql_mutex_unlock(&LOCK_log);
- if (check_purge)
- purge();
-
DEBUG_SYNC(leader->thd, "commit_after_release_LOCK_log");
++num_group_commits;
@@ -6148,7 +6293,8 @@ MYSQL_BIN_LOG::trx_group_commit_leader(group_commit_entry *leader)
DEBUG_SYNC(leader->thd, "commit_loop_entry_commit_ordered");
++num_commits;
- if (current->cache_mngr->using_xa && !current->error)
+ if (current->cache_mngr->using_xa && !current->error &&
+ DBUG_EVALUATE_IF("skip_commit_ordered", 0, 1))
run_commit_ordered(current->thd, current->all);
/*
@@ -6163,6 +6309,9 @@ MYSQL_BIN_LOG::trx_group_commit_leader(group_commit_entry *leader)
DEBUG_SYNC(leader->thd, "commit_after_group_run_commit_ordered");
mysql_mutex_unlock(&LOCK_commit_ordered);
+ if (check_purge)
+ purge();
+
DBUG_VOID_RETURN;
}
@@ -7351,14 +7500,6 @@ int TC_LOG::using_heuristic_recover()
/****** transaction coordinator log for 2pc - binlog() based solution ******/
#define TC_LOG_BINLOG MYSQL_BIN_LOG
-/**
- @todo
- keep in-memory list of prepared transactions
- (add to list in log(), remove on unlog())
- and copy it to the new binlog if rotated
- but let's check the behaviour of tc_log_page_waits first!
-*/
-
int TC_LOG_BINLOG::open(const char *opt_name)
{
LOG_INFO log_info;
@@ -7367,10 +7508,6 @@ int TC_LOG_BINLOG::open(const char *opt_name)
DBUG_ASSERT(total_ha_2pc > 1);
DBUG_ASSERT(opt_name && opt_name[0]);
- mysql_mutex_init(key_BINLOG_LOCK_prep_xids,
- &LOCK_prep_xids, MY_MUTEX_INIT_FAST);
- mysql_cond_init(key_BINLOG_COND_prep_xids, &COND_prep_xids, 0);
-
if (!my_b_inited(&index_file))
{
/* There was a failure to open the index file, can't open the binlog */
@@ -7429,7 +7566,8 @@ int TC_LOG_BINLOG::open(const char *opt_name)
ev->flags & LOG_EVENT_BINLOG_IN_USE_F)
{
sql_print_information("Recovering after a crash using %s", opt_name);
- error= recover(&log, (Format_description_log_event *)ev);
+ error= recover(&log_info, log_name, &log,
+ (Format_description_log_event *)ev);
}
else
error=0;
@@ -7449,9 +7587,6 @@ err:
/** This is called on shutdown, after ha_panic. */
void TC_LOG_BINLOG::close()
{
- DBUG_ASSERT(prepared_xids==0);
- mysql_mutex_destroy(&LOCK_prep_xids);
- mysql_cond_destroy(&COND_prep_xids);
}
/*
@@ -7471,11 +7606,23 @@ TC_LOG_BINLOG::log_and_order(THD *thd, my_xid xid, bool all,
cache_mngr->using_xa= TRUE;
cache_mngr->xa_xid= xid;
+#ifndef DBUG_OFF
+ cache_mngr->cookie= 0;
+#endif
err= binlog_commit_flush_xid_caches(thd, cache_mngr, all, xid);
DEBUG_SYNC(thd, "binlog_after_log_and_order");
- DBUG_RETURN(!err);
+ if (err)
+ DBUG_RETURN(0);
+ /*
+ If using explicit user XA, we will not have XID. We must still return a
+ non-zero cookie (as zero cookie signals error).
+ */
+ if (!xid)
+ DBUG_RETURN(BINLOG_COOKIE_DUMMY);
+ DBUG_ASSERT(cache_mngr->cookie != 0);
+ DBUG_RETURN(cache_mngr->cookie);
}
/*
@@ -7490,40 +7637,134 @@ TC_LOG_BINLOG::log_and_order(THD *thd, my_xid xid, bool all,
binary log.
*/
void
-TC_LOG_BINLOG::mark_xids_active(uint xid_count)
+TC_LOG_BINLOG::mark_xids_active(ulong cookie, uint xid_count)
{
+ xid_count_per_binlog *b;
+
DBUG_ENTER("TC_LOG_BINLOG::mark_xids_active");
- DBUG_PRINT("info", ("xid_count=%u", xid_count));
- mysql_mutex_lock(&LOCK_prep_xids);
- prepared_xids+= xid_count;
- mysql_mutex_unlock(&LOCK_prep_xids);
+ DBUG_PRINT("info", ("cookie=%lu xid_count=%u", cookie, xid_count));
+ DBUG_ASSERT(cookie != 0 && cookie != BINLOG_COOKIE_DUMMY);
+
+ mysql_mutex_lock(&LOCK_xid_list);
+ I_List_iterator<xid_count_per_binlog> it(binlog_xid_count_list);
+ while ((b= it++))
+ {
+ if (b->binlog_id == cookie)
+ {
+ b->xid_count += xid_count;
+ break;
+ }
+ }
+ /*
+ As we do not delete elements until count reach zero, elements should always
+ be found.
+ */
+ DBUG_ASSERT(b);
+ mysql_mutex_unlock(&LOCK_xid_list);
DBUG_VOID_RETURN;
}
/*
- Once an XID is committed, it is safe to rotate the binary log, as it can no
- longer be needed during crash recovery.
+ Once an XID is committed, it can no longer be needed during crash recovery,
+ as it has been durably recorded on disk as "committed".
This function is called to mark an XID this way. It needs to decrease the
- count of pending XIDs, and signal the log rotator thread when it reaches zero.
+ count of pending XIDs in the corresponding binlog. When the count reaches
+ zero (for an "old" binlog that is not the active one), that binlog file no
+ longer need to be scanned during crash recovery, so we can log a new binlog
+ checkpoint.
*/
void
-TC_LOG_BINLOG::mark_xid_done()
+TC_LOG_BINLOG::mark_xid_done(ulong cookie)
{
- my_bool send_signal;
+ xid_count_per_binlog *b;
+ bool first;
+ ulong current;
DBUG_ENTER("TC_LOG_BINLOG::mark_xid_done");
- mysql_mutex_lock(&LOCK_prep_xids);
- // prepared_xids can be 0 if the transaction had ignorable errors.
- DBUG_ASSERT(prepared_xids >= 0);
- if (prepared_xids > 0)
- prepared_xids--;
- send_signal= (prepared_xids == 0);
- mysql_mutex_unlock(&LOCK_prep_xids);
- if (send_signal) {
- DBUG_PRINT("info", ("prepared_xids=%lu", prepared_xids));
- mysql_cond_signal(&COND_prep_xids);
+ if (cookie == BINLOG_COOKIE_DUMMY)
+ DBUG_VOID_RETURN; /* Nothing to do. */
+
+ mysql_mutex_lock(&LOCK_xid_list);
+ current= current_binlog_id;
+ I_List_iterator<xid_count_per_binlog> it(binlog_xid_count_list);
+ first= true;
+ while ((b= it++))
+ {
+ if (b->binlog_id == cookie)
+ {
+ --b->xid_count;
+ break;
+ }
+ first= false;
+ }
+ /* Binlog is always found, as we do not remove until count reaches 0 */
+ DBUG_ASSERT(b);
+ if (likely(cookie == current && !reset_master_pending) ||
+ b->xid_count != 0 || !first)
+ {
+ /* No new binlog checkpoint reached yet. */
+ mysql_mutex_unlock(&LOCK_xid_list);
+ DBUG_VOID_RETURN;
+ }
+
+ /*
+ Now log a binlog checkpoint for the first binlog file with a non-zero count.
+
+ Note that it is possible (though perhaps unlikely) that when count of
+ binlog (N-2) drops to zero, binlog (N-1) is already at zero. So we may
+ need to skip several entries before we find the one to log in the binlog
+ checkpoint event.
+
+ We chain the locking of LOCK_xid_list and LOCK_log, so that we ensure that
+ Binlog_checkpoint_events are logged in order. This simplifies recovery a
+ bit, as it can just take the last binlog checkpoint in the log, rather
+ than compare all found against each other to find the one pointing to the
+ most recent binlog.
+
+ Note also that we need to first release LOCK_xid_list, then aquire
+ LOCK_log, then re-aquire LOCK_xid_list. If we were to take LOCK_log while
+ holding LOCK_xid_list, we might deadlock with other threads that take the
+ locks in the opposite order.
+
+ If a RESET MASTER is pending, we are about to remove all log files, and
+ the RESET MASTER thread is waiting for all pending unlog() calls to
+ complete while holding LOCK_log. In this case we should not log a binlog
+ checkpoint event (it would be deleted immediately anywat and we would
+ deadlock on LOCK_log) but just signal the thread.
+ */
+ if (!reset_master_pending)
+ {
+ mysql_mutex_unlock(&LOCK_xid_list);
+ mysql_mutex_lock(&LOCK_log);
+ mysql_mutex_lock(&LOCK_xid_list);
+ }
+ for (;;)
+ {
+ /* Remove initial element(s) with zero count. */
+ b= binlog_xid_count_list.head();
+ /*
+ Normally, we must not remove all elements in the list.
+ Only if a RESET MASTER is in progress may we delete everything - RESET
+ MASTER has LOCK_log held, and will create a new initial element before
+ releasing the lock.
+ */
+ DBUG_ASSERT(b || reset_master_pending);
+ if (unlikely(!b) || b->binlog_id == current || b->xid_count > 0)
+ break;
+ my_free(binlog_xid_count_list.get());
}
+ if (reset_master_pending)
+ {
+ mysql_cond_signal(&COND_xid_list);
+ mysql_mutex_unlock(&LOCK_xid_list);
+ DBUG_VOID_RETURN;
+ }
+
+ mysql_mutex_unlock(&LOCK_xid_list);
+ write_binlog_checkpoint_event_already_locked(b->binlog_name,
+ b->binlog_name_len);
+ mysql_mutex_unlock(&LOCK_log);
DBUG_VOID_RETURN;
}
@@ -7531,16 +7772,24 @@ int TC_LOG_BINLOG::unlog(ulong cookie, my_xid xid)
{
DBUG_ENTER("TC_LOG_BINLOG::unlog");
if (xid)
- mark_xid_done();
+ mark_xid_done(cookie);
/* As ::write_transaction_to_binlog() did not rotate, do it here. */
DBUG_RETURN(rotate_and_purge(0));
}
-int TC_LOG_BINLOG::recover(IO_CACHE *log, Format_description_log_event *fdle)
+int TC_LOG_BINLOG::recover(LOG_INFO *linfo, const char *last_log_name,
+ IO_CACHE *first_log,
+ Format_description_log_event *fdle)
{
Log_event *ev;
HASH xids;
MEM_ROOT mem_root;
+ char binlog_checkpoint_name[FN_REFLEN];
+ bool binlog_checkpoint_found;
+ bool first_round;
+ IO_CACHE log;
+ File file= -1;
+ const char *errmsg;
if (! fdle->is_valid() ||
my_hash_init(&xids, &my_charset_bin, TC_LOG_PAGE_SIZE/3, 0,
@@ -7551,19 +7800,109 @@ int TC_LOG_BINLOG::recover(IO_CACHE *log, Format_description_log_event *fdle)
fdle->flags&= ~LOG_EVENT_BINLOG_IN_USE_F; // abort on the first error
- while ((ev= Log_event::read_log_event(log, 0, fdle,
- opt_master_verify_checksum))
- && ev->is_valid())
+ /*
+ Scan the binlog for XIDs that need to be committed if still in the
+ prepared stage.
+
+ Start with the latest binlog file, then continue with any other binlog
+ files if the last found binlog checkpoint indicates it is needed.
+ */
+
+ binlog_checkpoint_found= false;
+ first_round= true;
+ for (;;)
{
- if (ev->get_type_code() == XID_EVENT)
+ while ((ev= Log_event::read_log_event(first_round ? first_log : &log,
+ 0, fdle, opt_master_verify_checksum))
+ && ev->is_valid())
+ {
+ switch (ev->get_type_code())
+ {
+ case XID_EVENT:
+ {
+ Xid_log_event *xev=(Xid_log_event *)ev;
+ uchar *x= (uchar *) memdup_root(&mem_root, (uchar*) &xev->xid,
+ sizeof(xev->xid));
+ if (!x || my_hash_insert(&xids, x))
+ {
+ delete ev;
+ goto err2;
+ }
+ break;
+ }
+ case BINLOG_CHECKPOINT_EVENT:
+ if (first_round)
+ {
+ uint dir_len;
+ Binlog_checkpoint_log_event *cev= (Binlog_checkpoint_log_event *)ev;
+ if (cev->binlog_file_len >= FN_REFLEN)
+ sql_print_warning("Incorrect binlog checkpoint event with too "
+ "long file name found.");
+ else
+ {
+ /*
+ Note that we cannot use make_log_name() here, as we have not yet
+ initialised MYSQL_BIN_LOG::log_file_name.
+ */
+ dir_len= dirname_length(last_log_name);
+ strmake(strnmov(binlog_checkpoint_name, last_log_name, dir_len),
+ cev->binlog_file_name, FN_REFLEN - 1 - dir_len);
+ binlog_checkpoint_found= true;
+ }
+ break;
+ }
+ default:
+ /* Nothing. */
+ break;
+ }
+ delete ev;
+ }
+
+ /*
+ If the last binlog checkpoint event points to an older log, we have to
+ scan all logs from there also, to get all possible XIDs to recover.
+
+ If there was no binlog checkpoint event at all, this means the log was
+ written by an older version of MariaDB (or MySQL) - these always have an
+ (implicit) binlog checkpoint event at the start of the last binlog file.
+ */
+ if (first_round)
{
- Xid_log_event *xev=(Xid_log_event *)ev;
- uchar *x= (uchar *) memdup_root(&mem_root, (uchar*) &xev->xid,
- sizeof(xev->xid));
- if (!x || my_hash_insert(&xids, x))
+ if (!binlog_checkpoint_found)
+ break;
+ first_round= false;
+ if (find_log_pos(linfo, binlog_checkpoint_name, 1))
+ {
+ sql_print_error("Binlog file '%s' not found in binlog index, needed "
+ "for recovery. Aborting.", binlog_checkpoint_name);
goto err2;
+ }
+ }
+ else
+ {
+ end_io_cache(&log);
+ mysql_file_close(file, MYF(MY_WME));
+ file= -1;
+ }
+
+ if (0 == strcmp(linfo->log_file_name, last_log_name))
+ break; // No more files to do
+ if ((file= open_binlog(&log, linfo->log_file_name, &errmsg)) < 0)
+ {
+ sql_print_error("%s", errmsg);
+ goto err2;
+ }
+ /*
+ We do not need to read the Format_description_log_event of other binlog
+ files. It is not possible for a binlog checkpoint to span multiple
+ binlog files written by different versions of the server. So we can use
+ the first one read for reading from all binlog files.
+ */
+ if (find_next_log(linfo, 1))
+ {
+ sql_print_error("Error reading binlog files during recovery. Aborting.");
+ goto err2;
}
- delete ev;
}
if (ha_recover(&xids))
@@ -7574,6 +7913,11 @@ int TC_LOG_BINLOG::recover(IO_CACHE *log, Format_description_log_event *fdle)
return 0;
err2:
+ if (file >= 0)
+ {
+ end_io_cache(&log);
+ mysql_file_close(file, MYF(MY_WME));
+ }
free_root(&mem_root, MYF(0));
my_hash_free(&xids);
err1:
diff --git a/sql/log.h b/sql/log.h
index 9b9bed1262a..179d302d2cc 100644
--- a/sql/log.h
+++ b/sql/log.h
@@ -354,6 +354,15 @@ private:
time_t last_time;
};
+/*
+ We assign each binlog file an internal ID, used to identify them for unlog().
+ Ids start from BINLOG_COOKIE_START; the value BINLOG_COOKIE_DUMMY is special
+ meaning "no binlog" (we cannot use zero as that is reserved for error return
+ from log_and_order).
+*/
+#define BINLOG_COOKIE_DUMMY 1
+#define BINLOG_COOKIE_START 2
+
class binlog_cache_mngr;
class MYSQL_BIN_LOG: public TC_LOG, private MYSQL_LOG
{
@@ -394,10 +403,40 @@ class MYSQL_BIN_LOG: public TC_LOG, private MYSQL_LOG
bool all;
};
+ /*
+ A list of struct xid_count_per_binlog is used to keep track of how many
+ XIDs are in prepared, but not committed, state in each binlog.
+
+ When count drops to zero in a binlog after rotation, it means that there
+ are no more XIDs in prepared state, so that binlog is no longer needed
+ for XA crash recovery, and we can log a new binlog checkpoint event.
+
+ The list is protected against simultaneous access from multiple
+ threads by LOCK_xid_list.
+ */
+ struct xid_count_per_binlog : public ilink {
+ char *binlog_name;
+ uint binlog_name_len;
+ ulong binlog_id;
+ long xid_count;
+ xid_count_per_binlog(); /* Give link error if constructor used. */
+ };
+ ulong current_binlog_id;
+ I_List<xid_count_per_binlog> binlog_xid_count_list;
+ /*
+ When this is set, a RESET MASTER is in progress.
+
+ Then we should not write any binlog checkpoints into the binlog (that
+ could result in deadlock on LOCK_log, and we will delete all binlog files
+ anyway). Instead we should signal COND_xid_list whenever a new binlog
+ checkpoint arrives - when all have arrived, RESET MASTER will complete.
+ */
+ bool reset_master_pending;
+
/* LOCK_log and LOCK_index are inited by init_pthread_objects() */
mysql_mutex_t LOCK_index;
- mysql_mutex_t LOCK_prep_xids;
- mysql_cond_t COND_prep_xids;
+ mysql_mutex_t LOCK_xid_list;
+ mysql_cond_t COND_xid_list;
mysql_cond_t update_cond;
ulonglong bytes_written;
IO_CACHE index_file;
@@ -421,7 +460,6 @@ class MYSQL_BIN_LOG: public TC_LOG, private MYSQL_LOG
fix_max_relay_log_size).
*/
ulong max_size;
- long prepared_xids; /* for tc log - number of xids to remember */
// current file sequence number for load data infile binary logging
uint file_id;
uint open_count; // For replication
@@ -473,8 +511,8 @@ class MYSQL_BIN_LOG: public TC_LOG, private MYSQL_LOG
int write_transaction_or_stmt(group_commit_entry *entry);
bool write_transaction_to_binlog_events(group_commit_entry *entry);
void trx_group_commit_leader(group_commit_entry *leader);
- void mark_xid_done();
- void mark_xids_active(uint xid_count);
+ void mark_xid_done(ulong cookie);
+ void mark_xids_active(ulong cookie, uint xid_count);
public:
using MYSQL_LOG::generate_name;
@@ -562,7 +600,8 @@ public:
int log_and_order(THD *thd, my_xid xid, bool all,
bool need_prepare_ordered, bool need_commit_ordered);
int unlog(ulong cookie, my_xid xid);
- int recover(IO_CACHE *log, Format_description_log_event *fdle);
+ int recover(LOG_INFO *linfo, const char *last_log_name, IO_CACHE *first_log,
+ Format_description_log_event *fdle);
#if !defined(MYSQL_CLIENT)
int flush_and_set_pending_rows_event(THD *thd, Rows_log_event* event,
@@ -614,6 +653,7 @@ public:
bool write_incident_already_locked(THD *thd);
bool write_incident(THD *thd);
+ void write_binlog_checkpoint_event_already_locked(const char *name, uint len);
int write_cache(THD *thd, IO_CACHE *cache);
void set_write_error(THD *thd, bool is_transactional);
bool check_write_error(THD *thd);
@@ -631,6 +671,7 @@ public:
void make_log_name(char* buf, const char* log_ident);
bool is_active(const char* log_file_name);
+ bool can_purge_log(const char *log_file_name);
int update_log_index(LOG_INFO* linfo, bool need_update_threads);
int rotate(bool force_rotate, bool* check_purge);
void purge();
diff --git a/sql/log_event.cc b/sql/log_event.cc
index f9849fa0ff5..6cefdb4fa59 100644
--- a/sql/log_event.cc
+++ b/sql/log_event.cc
@@ -731,6 +731,7 @@ const char* Log_event::get_type_str(Log_event_type type)
case EXECUTE_LOAD_QUERY_EVENT: return "Execute_load_query";
case INCIDENT_EVENT: return "Incident";
case ANNOTATE_ROWS_EVENT: return "Annotate_rows";
+ case BINLOG_CHECKPOINT_EVENT: return "Binlog_checkpoint";
default: return "Unknown"; /* impossible */
}
}
@@ -1387,7 +1388,7 @@ err:
DBUG_ASSERT(error != 0);
sql_print_error("Error in Log_event::read_log_event(): "
"'%s', data_len: %d, event_type: %d",
- error,data_len,head[EVENT_TYPE_OFFSET]);
+ error,data_len,(uchar)(head[EVENT_TYPE_OFFSET]));
my_free(buf);
/*
The SQL slave thread will check if file->error<0 to know
@@ -1536,6 +1537,9 @@ Log_event* Log_event::read_log_event(const char* buf, uint event_len,
case ROTATE_EVENT:
ev = new Rotate_log_event(buf, event_len, description_event);
break;
+ case BINLOG_CHECKPOINT_EVENT:
+ ev = new Binlog_checkpoint_log_event(buf, event_len, description_event);
+ break;
#ifdef HAVE_REPLICATION
case SLAVE_EVENT: /* can never happen (unused event) */
ev = new Slave_log_event(buf, event_len, description_event);
@@ -4405,6 +4409,8 @@ Format_description_log_event(uint8 binlog_ver, const char* server_ver)
// Set header lengths of Maria events
post_header_len[ANNOTATE_ROWS_EVENT-1]= ANNOTATE_ROWS_HEADER_LEN;
+ post_header_len[BINLOG_CHECKPOINT_EVENT-1]=
+ BINLOG_CHECKPOINT_HEADER_LEN;
// Sanity-check that all post header lengths are initialized.
int i;
@@ -5864,6 +5870,86 @@ Rotate_log_event::do_shall_skip(Relay_log_info *rli)
/**************************************************************************
+ Binlog_checkpoint_log_event methods
+**************************************************************************/
+
+#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
+void Binlog_checkpoint_log_event::pack_info(Protocol *protocol)
+{
+ protocol->store(binlog_file_name, binlog_file_len, &my_charset_bin);
+}
+#endif
+
+
+#ifdef MYSQL_CLIENT
+void Binlog_checkpoint_log_event::print(FILE *file,
+ PRINT_EVENT_INFO *print_event_info)
+{
+ Write_on_release_cache cache(&print_event_info->head_cache, file,
+ Write_on_release_cache::FLUSH_F);
+
+ if (print_event_info->short_form)
+ return;
+ print_header(&cache, print_event_info, FALSE);
+ my_b_printf(&cache, "\tBinlog checkpoint ");
+ my_b_write(&cache, (uchar*)binlog_file_name, binlog_file_len);
+ my_b_printf(&cache, "\n");
+}
+#endif /* MYSQL_CLIENT */
+
+
+#ifdef MYSQL_SERVER
+Binlog_checkpoint_log_event::Binlog_checkpoint_log_event(
+ const char *binlog_file_name_arg,
+ uint binlog_file_len_arg)
+ :Log_event(),
+ binlog_file_name(my_strndup(binlog_file_name_arg, binlog_file_len_arg,
+ MYF(MY_WME))),
+ binlog_file_len(binlog_file_len_arg)
+{
+ cache_type= EVENT_NO_CACHE;
+}
+#endif /* MYSQL_SERVER */
+
+
+Binlog_checkpoint_log_event::Binlog_checkpoint_log_event(
+ const char *buf, uint event_len,
+ const Format_description_log_event *description_event)
+ :Log_event(buf, description_event), binlog_file_name(0)
+{
+ uint8 header_size= description_event->common_header_len;
+ uint8 post_header_len=
+ description_event->post_header_len[BINLOG_CHECKPOINT_EVENT-1];
+ if (event_len < header_size + post_header_len ||
+ post_header_len < BINLOG_CHECKPOINT_HEADER_LEN)
+ return;
+ buf+= header_size;
+ /* See uint4korr and int4store below */
+ compile_time_assert(BINLOG_CHECKPOINT_HEADER_LEN == 4);
+ binlog_file_len= uint4korr(buf);
+ if (event_len - (header_size + post_header_len) < binlog_file_len)
+ return;
+ binlog_file_name= my_strndup(buf + post_header_len, binlog_file_len,
+ MYF(MY_WME));
+ return;
+}
+
+
+#ifndef MYSQL_CLIENT
+bool Binlog_checkpoint_log_event::write(IO_CACHE *file)
+{
+ uchar buf[BINLOG_CHECKPOINT_HEADER_LEN];
+ int4store(buf, binlog_file_len);
+ return write_header(file, BINLOG_CHECKPOINT_HEADER_LEN + binlog_file_len) ||
+ wrapper_my_b_safe_write(file, buf, BINLOG_CHECKPOINT_HEADER_LEN) ||
+ wrapper_my_b_safe_write(file, (const uchar *)binlog_file_name,
+ binlog_file_len) ||
+ write_footer(file);
+}
+#endif /* MYSQL_CLIENT */
+
+
+/**************************************************************************
Intvar_log_event methods
**************************************************************************/
diff --git a/sql/log_event.h b/sql/log_event.h
index 12d5e1417f4..c76e538618b 100644
--- a/sql/log_event.h
+++ b/sql/log_event.h
@@ -259,6 +259,7 @@ struct sql_ex_info
#define INCIDENT_HEADER_LEN 2
#define HEARTBEAT_HEADER_LEN 0
#define ANNOTATE_ROWS_HEADER_LEN 0
+#define BINLOG_CHECKPOINT_HEADER_LEN 4
/*
Max number of possible extra bytes in a replication event compared to a
@@ -685,6 +686,14 @@ enum Log_event_type
MARIA_EVENTS_BEGIN= 160,
/* New Maria event numbers start from here */
ANNOTATE_ROWS_EVENT= 160,
+ /*
+ Binlog checkpoint event. Used for XA crash recovery on the master, not used
+ in replication.
+ A binlog checkpoint event specifies a binlog file such that XA crash
+ recovery can start from that file - and it is guaranteed to find all XIDs
+ that are prepared in storage engines but not yet committed.
+ */
+ BINLOG_CHECKPOINT_EVENT= 161,
/* Add new MariaDB events here - right above this comment! */
@@ -2892,6 +2901,32 @@ private:
};
+class Binlog_checkpoint_log_event: public Log_event
+{
+public:
+ char *binlog_file_name;
+ uint binlog_file_len;
+
+#ifdef MYSQL_SERVER
+ Binlog_checkpoint_log_event(const char *binlog_file_name_arg,
+ uint binlog_file_len_arg);
+#ifdef HAVE_REPLICATION
+ void pack_info(Protocol *protocol);
+#endif
+#else
+ void print(FILE *file, PRINT_EVENT_INFO *print_event_info);
+#endif
+ Binlog_checkpoint_log_event(const char *buf, uint event_len,
+ const Format_description_log_event *description_event);
+ ~Binlog_checkpoint_log_event() { my_free(binlog_file_name); }
+ Log_event_type get_type_code() { return BINLOG_CHECKPOINT_EVENT;}
+ int get_data_size() { return binlog_file_len + BINLOG_CHECKPOINT_HEADER_LEN;}
+ bool is_valid() const { return binlog_file_name != 0; }
+#ifdef MYSQL_SERVER
+ bool write(IO_CACHE* file);
+#endif
+};
+
/* the classes below are for the new LOAD DATA INFILE logging */
/**
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index 91bc2bfe226..3c0f209235a 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -722,7 +722,7 @@ PSI_mutex_key key_PAGE_lock, key_LOCK_sync, key_LOCK_active, key_LOCK_pool;
PSI_mutex_key key_LOCK_des_key_file;
#endif /* HAVE_OPENSSL */
-PSI_mutex_key key_BINLOG_LOCK_index, key_BINLOG_LOCK_prep_xids,
+PSI_mutex_key key_BINLOG_LOCK_index, key_BINLOG_LOCK_xid_list,
key_delayed_insert_mutex, key_hash_filo_lock, key_LOCK_active_mi,
key_LOCK_connection_count, key_LOCK_crypt, key_LOCK_delayed_create,
key_LOCK_delayed_insert, key_LOCK_delayed_status, key_LOCK_error_log,
@@ -763,7 +763,7 @@ static PSI_mutex_info all_server_mutexes[]=
#endif /* HAVE_OPENSSL */
{ &key_BINLOG_LOCK_index, "MYSQL_BIN_LOG::LOCK_index", 0},
- { &key_BINLOG_LOCK_prep_xids, "MYSQL_BIN_LOG::LOCK_prep_xids", 0},
+ { &key_BINLOG_LOCK_xid_list, "MYSQL_BIN_LOG::LOCK_xid_list", 0},
{ &key_RELAYLOG_LOCK_index, "MYSQL_RELAY_LOG::LOCK_index", 0},
{ &key_delayed_insert_mutex, "Delayed_insert::mutex", 0},
{ &key_hash_filo_lock, "hash_filo::lock", 0},
@@ -831,7 +831,7 @@ static PSI_rwlock_info all_server_rwlocks[]=
PSI_cond_key key_PAGE_cond, key_COND_active, key_COND_pool;
#endif /* HAVE_MMAP */
-PSI_cond_key key_BINLOG_COND_prep_xids, key_BINLOG_update_cond,
+PSI_cond_key key_BINLOG_COND_xid_list, key_BINLOG_update_cond,
key_COND_cache_status_changed, key_COND_manager,
key_COND_rpl_status, key_COND_server_started,
key_delayed_insert_cond, key_delayed_insert_cond_client,
@@ -859,7 +859,7 @@ static PSI_cond_info all_server_conds[]=
{ &key_COND_pool, "TC_LOG_MMAP::COND_pool", 0},
{ &key_TC_LOG_MMAP_COND_queue_busy, "TC_LOG_MMAP::COND_queue_busy", 0},
#endif /* HAVE_MMAP */
- { &key_BINLOG_COND_prep_xids, "MYSQL_BIN_LOG::COND_prep_xids", 0},
+ { &key_BINLOG_COND_xid_list, "MYSQL_BIN_LOG::COND_xid_list", 0},
{ &key_BINLOG_update_cond, "MYSQL_BIN_LOG::update_cond", 0},
{ &key_BINLOG_COND_queue_busy, "MYSQL_BIN_LOG::COND_queue_busy", 0},
{ &key_RELAYLOG_update_cond, "MYSQL_RELAY_LOG::update_cond", 0},
diff --git a/sql/mysqld.h b/sql/mysqld.h
index 56419acdcd4..28c4d771a48 100644
--- a/sql/mysqld.h
+++ b/sql/mysqld.h
@@ -225,7 +225,7 @@ extern PSI_mutex_key key_PAGE_lock, key_LOCK_sync, key_LOCK_active,
extern PSI_mutex_key key_LOCK_des_key_file;
#endif
-extern PSI_mutex_key key_BINLOG_LOCK_index, key_BINLOG_LOCK_prep_xids,
+extern PSI_mutex_key key_BINLOG_LOCK_index, key_BINLOG_LOCK_xid_list,
key_delayed_insert_mutex, key_hash_filo_lock, key_LOCK_active_mi,
key_LOCK_connection_count, key_LOCK_crypt, key_LOCK_delayed_create,
key_LOCK_delayed_insert, key_LOCK_delayed_status, key_LOCK_error_log,
@@ -256,7 +256,7 @@ extern PSI_rwlock_key key_rwlock_LOCK_grant, key_rwlock_LOCK_logger,
extern PSI_cond_key key_PAGE_cond, key_COND_active, key_COND_pool;
#endif /* HAVE_MMAP */
-extern PSI_cond_key key_BINLOG_COND_prep_xids, key_BINLOG_update_cond,
+extern PSI_cond_key key_BINLOG_COND_xid_list, key_BINLOG_update_cond,
key_COND_cache_status_changed, key_COND_manager,
key_COND_rpl_status, key_COND_server_started,
key_delayed_insert_cond, key_delayed_insert_cond_client,
diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc
index d7308eddb7f..079aab27101 100644
--- a/sql/sql_repl.cc
+++ b/sql/sql_repl.cc
@@ -624,6 +624,30 @@ send_event_to_slave(THD *thd, NET *net, String* const packet, ushort flags,
}
/*
+ Do not send binlog checkpoint events to a slave that does not understand it.
+ */
+ if (unlikely(event_type == BINLOG_CHECKPOINT_EVENT) &&
+ mariadb_slave_capability < MARIA_SLAVE_CAPABILITY_BINLOG_CHECKPOINT)
+ {
+ if (mariadb_slave_capability >= MARIA_SLAVE_CAPABILITY_TOLERATE_HOLES)
+ {
+ /* This slave can tolerate events omitted from the binlog stream. */
+ return NULL;
+ }
+ else
+ {
+ /*
+ The slave does not understand BINLOG_CHECKPOINT_EVENT. Send a dummy
+ event instead, with same length so slave does not get confused about
+ binlog positions.
+ */
+ if (Query_log_event::dummy_event(packet, ev_offset, current_checksum_alg))
+ return "Failed to replace binlog checkpoint event with dummy: "
+ "too small event.";
+ }
+ }
+
+ /*
Skip events with the @@skip_replication flag set, if slave requested
skipping of such events.
*/