summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--client/mysqldump.c119
-rw-r--r--mysql-test/r/mysqldump-max.result56
-rw-r--r--mysql-test/suite/binlog/r/binlog_consistent.result99
-rw-r--r--mysql-test/suite/binlog/t/binlog_consistent.test88
-rw-r--r--mysql-test/t/mysqldump-max.test81
-rw-r--r--sql/log.cc105
-rw-r--r--sql/log.h8
7 files changed, 511 insertions, 45 deletions
diff --git a/client/mysqldump.c b/client/mysqldump.c
index bb09af4a3c2..bc7f495eb98 100644
--- a/client/mysqldump.c
+++ b/client/mysqldump.c
@@ -77,6 +77,9 @@
#define IGNORE_DATA 0x01 /* don't dump data for this table */
#define IGNORE_INSERT_DELAYED 0x02 /* table doesn't support INSERT DELAYED */
+/* Chars needed to store LONGLONG, excluding trailing '\0'. */
+#define LONGLONG_LEN 20
+
static void add_load_option(DYNAMIC_STRING *str, const char *option,
const char *option_value);
static ulong find_set(TYPELIB *lib, const char *x, uint length,
@@ -344,9 +347,9 @@ static struct my_option my_long_options[] =
"This causes the binary log position and filename to be appended to the "
"output. If equal to 1, will print it as a CHANGE MASTER command; if equal"
" to 2, that command will be prefixed with a comment symbol. "
- "This option will turn --lock-all-tables on, unless "
- "--single-transaction is specified too (in which case a "
- "global read lock is only taken a short time at the beginning of the dump; "
+ "This option will turn --lock-all-tables on, unless --single-transaction "
+ "is specified too (on servers before MariaDB 5.3 this will still take a "
+ "global read lock for a short time at the beginning of the dump; "
"don't forget to read about --single-transaction below). In all cases, "
"any action on logs will happen at the exact moment of the dump. "
"Option automatically turns --lock-tables off.",
@@ -1109,6 +1112,44 @@ static int fetch_db_collation(const char *db_name,
}
+/*
+ Check if server supports non-blocking binlog position using the
+ binlog_trx_file and binlog_trx_position status variables. If it does,
+ also return the position obtained if output pointers are non-NULL.
+ Returns 1 if position available, 0 if not.
+*/
+static int
+check_consistent_binlog_pos(char *binlog_pos_file, char *binlog_pos_offset)
+{
+ MYSQL_RES *res;
+ MYSQL_ROW row;
+ int found;
+
+ if (mysql_query_with_error_report(mysql, &res,
+ "SHOW STATUS LIKE 'binlog_trx_%'"))
+ return 1;
+
+ found= 0;
+ while ((row= mysql_fetch_row(res)))
+ {
+ if (0 == strcmp(row[0], "binlog_trx_file"))
+ {
+ if (binlog_pos_file)
+ strmake(binlog_pos_file, row[1], FN_REFLEN-1);
+ found++;
+ }
+ else if (0 == strcmp(row[0], "binlog_trx_position"))
+ {
+ if (binlog_pos_offset)
+ strmake(binlog_pos_offset, row[1], LONGLONG_LEN);
+ found++;
+ }
+ }
+ mysql_free_result(res);
+
+ return (found == 2);
+}
+
static char *my_case_str(const char *str,
uint str_len,
const char *token,
@@ -4351,42 +4392,65 @@ static int dump_selected_tables(char *db, char **table_names, int tables)
} /* dump_selected_tables */
-static int do_show_master_status(MYSQL *mysql_con)
+static int do_show_master_status(MYSQL *mysql_con, int consistent_binlog_pos)
{
MYSQL_ROW row;
MYSQL_RES *master;
+ char binlog_pos_file[FN_REFLEN];
+ char binlog_pos_offset[LONGLONG_LEN+1];
+ char *file, *offset;
const char *comment_prefix=
(opt_master_data == MYSQL_OPT_MASTER_DATA_COMMENTED_SQL) ? "-- " : "";
- if (mysql_query_with_error_report(mysql_con, &master, "SHOW MASTER STATUS"))
+
+ if (consistent_binlog_pos)
{
- return 1;
+ if(!check_consistent_binlog_pos(binlog_pos_file, binlog_pos_offset))
+ return 1;
+ file= binlog_pos_file;
+ offset= binlog_pos_offset;
}
else
{
+ if (mysql_query_with_error_report(mysql_con, &master, "SHOW MASTER STATUS"))
+ return 1;
+
row= mysql_fetch_row(master);
if (row && row[0] && row[1])
{
- /* SHOW MASTER STATUS reports file and position */
- if (opt_comments)
- fprintf(md_result_file,
- "\n--\n-- Position to start replication or point-in-time "
- "recovery from\n--\n\n");
- fprintf(md_result_file,
- "%sCHANGE MASTER TO MASTER_LOG_FILE='%s', MASTER_LOG_POS=%s;\n",
- comment_prefix, row[0], row[1]);
- check_io(md_result_file);
+ file= row[0];
+ offset= row[1];
}
- else if (!ignore_errors)
+ else
{
- /* SHOW MASTER STATUS reports nothing and --force is not enabled */
- my_printf_error(0, "Error: Binlogging on server not active",
- MYF(0));
mysql_free_result(master);
- maybe_exit(EX_MYSQLERR);
- return 1;
+ if (!ignore_errors)
+ {
+ /* SHOW MASTER STATUS reports nothing and --force is not enabled */
+ my_printf_error(0, "Error: Binlogging on server not active",
+ MYF(0));
+ maybe_exit(EX_MYSQLERR);
+ return 1;
+ }
+ else
+ {
+ return 0;
+ }
}
- mysql_free_result(master);
}
+
+ /* SHOW MASTER STATUS reports file and position */
+ if (opt_comments)
+ fprintf(md_result_file,
+ "\n--\n-- Position to start replication or point-in-time "
+ "recovery from\n--\n\n");
+ fprintf(md_result_file,
+ "%sCHANGE MASTER TO MASTER_LOG_FILE='%s', MASTER_LOG_POS=%s;\n",
+ comment_prefix, file, offset);
+ check_io(md_result_file);
+
+ if (!consistent_binlog_pos)
+ mysql_free_result(master);
+
return 0;
}
@@ -5025,6 +5089,7 @@ int main(int argc, char **argv)
{
char bin_log_name[FN_REFLEN];
int exit_code;
+ int consistent_binlog_pos= 0;
MY_INIT("mysqldump");
compatible_mode_normal_str[0]= 0;
@@ -5055,7 +5120,13 @@ int main(int argc, char **argv)
if (!path)
write_header(md_result_file, *argv);
- if ((opt_lock_all_tables || opt_master_data) &&
+ if (opt_single_transaction && opt_master_data)
+ {
+ /* See if we can avoid FLUSH TABLES WITH READ LOCK (MariaDB 5.3+). */
+ consistent_binlog_pos= check_consistent_binlog_pos(NULL, NULL);
+ }
+
+ if ((opt_lock_all_tables || (opt_master_data && !consistent_binlog_pos)) &&
do_flush_tables_read_lock(mysql))
goto err;
if (opt_single_transaction && start_transaction(mysql))
@@ -5073,7 +5144,7 @@ int main(int argc, char **argv)
goto err;
flush_logs= 0; /* not anymore; that would not be sensible */
}
- if (opt_master_data && do_show_master_status(mysql))
+ if (opt_master_data && do_show_master_status(mysql, consistent_binlog_pos))
goto err;
if (opt_single_transaction && do_unlock_tables(mysql)) /* unlock but no commit! */
goto err;
diff --git a/mysql-test/r/mysqldump-max.result b/mysql-test/r/mysqldump-max.result
index c300f3d7996..57c9180691a 100644
--- a/mysql-test/r/mysqldump-max.result
+++ b/mysql-test/r/mysqldump-max.result
@@ -290,3 +290,59 @@ COUNT(*)
DROP VIEW v1;
DROP TABLE t1;
SET GLOBAL storage_engine=@old_engine;
+# Connection default
+RESET MASTER;
+CREATE TABLE t1 (a INT PRIMARY KEY) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (1),(2);
+CREATE TABLE t2 (a INT PRIMARY KEY, b INT) ENGINE=InnoDB;
+INSERT INTO t2 VALUES (1,0), (2,0);
+SELECT GET_LOCK("block_queries_1", 120);
+GET_LOCK("block_queries_1", 120)
+1
+# Connection c3
+SELECT GET_LOCK("block_queries_2", 120);
+GET_LOCK("block_queries_2", 120)
+1
+# Connection c1
+SET @c= 0;
+SELECT IF(@c<1, @c:=@c+1, GET_LOCK("block_queries_1", 120)) FROM t1 ORDER BY a;
+# Connection c2
+SET binlog_format="row";
+SET @d= 10;
+UPDATE t2 SET b=IF(@d<=10, @d:=@d+1, GET_LOCK("block_queries_2", 120)) ORDER BY a;
+# Connection default
+# Make sure other queries are running (and waiting).
+SELECT RELEASE_LOCK("block_queries_1");
+RELEASE_LOCK("block_queries_1")
+1
+# Connection c3
+SELECT RELEASE_LOCK("block_queries_2");
+RELEASE_LOCK("block_queries_2")
+1
+# Connection c1
+IF(@c<1, @c:=@c+1, GET_LOCK("block_queries_1", 120))
+1
+1
+# Connection c2
+# Connection default
+SELECT * FROM t2 ORDER BY a;
+a b
+1 11
+2 1
+DROP TABLE t1;
+DROP TABLE t2;
+SHOW BINLOG EVENTS LIMIT 6,3;
+Log_name Pos Event_type Server_id End_log_pos Info
+master-bin.000001 524 Query 1 592 BEGIN
+master-bin.000001 592 Query 1 689 use `test`; INSERT INTO t2 VALUES (1,0), (2,0)
+master-bin.000001 689 Xid 1 716 COMMIT /* XID */
+-- CHANGE MASTER TO MASTER_LOG_FILE='./master-bin.000001', MASTER_LOG_POS=716;
+SELECT * FROM t1 ORDER BY a;
+a
+1
+2
+SELECT * FROM t2 ORDER BY a;
+a b
+1 0
+2 0
+DROP TABLE t1,t2;
diff --git a/mysql-test/suite/binlog/r/binlog_consistent.result b/mysql-test/suite/binlog/r/binlog_consistent.result
new file mode 100644
index 00000000000..dc479ebe29c
--- /dev/null
+++ b/mysql-test/suite/binlog/r/binlog_consistent.result
@@ -0,0 +1,99 @@
+RESET MASTER;
+# Connection default
+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 241
+SHOW STATUS LIKE 'binlog_trx_%';
+Variable_name Value
+binlog_trx_file ./master-bin.000001
+binlog_trx_position 241
+BEGIN;
+INSERT INTO t1 VALUES (0, "");
+# Connection con1
+BEGIN;
+INSERT INTO t1 VALUES (1, "");
+# Connection con2
+CREATE TABLE t2 (a INT PRIMARY KEY) ENGINE=myisam;
+BEGIN;
+INSERT INTO t1 VALUES (2, "first");
+INSERT INTO t2 VALUES (2);
+INSERT INTO t1 VALUES (2, "second");
+# Connection default
+COMMIT;
+SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
+START TRANSACTION WITH CONSISTENT SNAPSHOT;
+# Connection con3
+BEGIN;
+INSERT INTO t1 VALUES (3, "");
+INSERT INTO t2 VALUES (3);
+# Connection con4
+BEGIN;
+INSERT INTO t1 VALUES (4, "");
+COMMIT;
+# Connection default
+SELECT * FROM t1 ORDER BY a,b;
+a b
+0
+SHOW STATUS LIKE 'binlog_trx_%';
+Variable_name Value
+binlog_trx_file ./master-bin.000001
+binlog_trx_position 540
+SHOW MASTER STATUS;
+File Position Binlog_Do_DB Binlog_Ignore_DB
+master-bin.000001 727
+SELECT * FROM t2 ORDER BY a;
+a
+2
+3
+# Connection con1
+COMMIT;
+# Connection con2
+COMMIT;
+# Connection con3
+COMMIT;
+FLUSH LOGS;
+# Connection default
+SELECT * FROM t1 ORDER BY a,b;
+a b
+0
+SHOW STATUS LIKE 'binlog_trx_%';
+Variable_name Value
+binlog_trx_file ./master-bin.000001
+binlog_trx_position 540
+SHOW MASTER STATUS;
+File Position Binlog_Do_DB Binlog_Ignore_DB
+master-bin.000002 106
+COMMIT;
+SHOW STATUS LIKE 'binlog_trx_%';
+Variable_name Value
+binlog_trx_file ./master-bin.000002
+binlog_trx_position 106
+SHOW MASTER STATUS;
+File Position Binlog_Do_DB Binlog_Ignore_DB
+master-bin.000002 106
+SHOW BINLOG EVENTS;
+Log_name Pos Event_type Server_id End_log_pos Info
+master-bin.000001 4 Format_desc 1 106 Server ver: #, Binlog ver: #
+master-bin.000001 106 Query 1 241 use `test`; CREATE TABLE t1 (a INT, b VARCHAR(100), PRIMARY KEY (a,b)) ENGINE=innodb
+master-bin.000001 241 Query 1 353 use `test`; CREATE TABLE t2 (a INT PRIMARY KEY) ENGINE=myisam
+master-bin.000001 353 Query 1 421 BEGIN
+master-bin.000001 421 Query 1 513 use `test`; INSERT INTO t1 VALUES (0, "")
+master-bin.000001 513 Xid 1 540 COMMIT /* XID */
+master-bin.000001 540 Query 1 608 BEGIN
+master-bin.000001 608 Query 1 700 use `test`; INSERT INTO t1 VALUES (4, "")
+master-bin.000001 700 Xid 1 727 COMMIT /* XID */
+master-bin.000001 727 Query 1 795 BEGIN
+master-bin.000001 795 Query 1 887 use `test`; INSERT INTO t1 VALUES (1, "")
+master-bin.000001 887 Xid 1 914 COMMIT /* XID */
+master-bin.000001 914 Query 1 982 BEGIN
+master-bin.000001 982 Query 1 1079 use `test`; INSERT INTO t1 VALUES (2, "first")
+master-bin.000001 1079 Query 1 1167 use `test`; INSERT INTO t2 VALUES (2)
+master-bin.000001 1167 Query 1 1265 use `test`; INSERT INTO t1 VALUES (2, "second")
+master-bin.000001 1265 Xid 1 1292 COMMIT /* XID */
+master-bin.000001 1292 Query 1 1360 BEGIN
+master-bin.000001 1360 Query 1 1452 use `test`; INSERT INTO t1 VALUES (3, "")
+master-bin.000001 1452 Query 1 1540 use `test`; INSERT INTO t2 VALUES (3)
+master-bin.000001 1540 Xid 1 1567 COMMIT /* XID */
+master-bin.000001 1567 Rotate 1 1611 master-bin.000002;pos=4
+DROP TABLE t1,t2;
diff --git a/mysql-test/suite/binlog/t/binlog_consistent.test b/mysql-test/suite/binlog/t/binlog_consistent.test
new file mode 100644
index 00000000000..b1df7e45678
--- /dev/null
+++ b/mysql-test/suite/binlog/t/binlog_consistent.test
@@ -0,0 +1,88 @@
+--source include/have_log_bin.inc
+--source include/have_binlog_format_mixed_or_statement.inc
+--source include/have_innodb.inc
+
+RESET MASTER;
+
+# Test that we get the correct binlog position from START TRANSACTION WITH
+# CONSISTENT SNAPSHOT even when other transactions are active.
+
+connect(con1,localhost,root,,);
+connect(con2,localhost,root,,);
+connect(con3,localhost,root,,);
+connect(con4,localhost,root,,);
+
+connection default;
+--echo # Connection default
+
+CREATE TABLE t1 (a INT, b VARCHAR(100), PRIMARY KEY (a,b)) ENGINE=innodb;
+SHOW MASTER STATUS;
+SHOW STATUS LIKE 'binlog_trx_%';
+BEGIN;
+INSERT INTO t1 VALUES (0, "");
+
+connection con1;
+--echo # Connection con1
+BEGIN;
+INSERT INTO t1 VALUES (1, "");
+
+connection con2;
+--echo # Connection con2
+CREATE TABLE t2 (a INT PRIMARY KEY) ENGINE=myisam;
+BEGIN;
+INSERT INTO t1 VALUES (2, "first");
+INSERT INTO t2 VALUES (2);
+INSERT INTO t1 VALUES (2, "second");
+
+connection default;
+--echo # Connection default
+COMMIT;
+
+SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
+START TRANSACTION WITH CONSISTENT SNAPSHOT;
+
+connection con3;
+--echo # Connection con3
+BEGIN;
+INSERT INTO t1 VALUES (3, "");
+INSERT INTO t2 VALUES (3);
+
+connection con4;
+--echo # Connection con4
+BEGIN;
+INSERT INTO t1 VALUES (4, "");
+COMMIT;
+
+connection default;
+--echo # Connection default
+SELECT * FROM t1 ORDER BY a,b;
+SHOW STATUS LIKE 'binlog_trx_%';
+SHOW MASTER STATUS;
+SELECT * FROM t2 ORDER BY a;
+
+connection con1;
+--echo # Connection con1
+COMMIT;
+
+connection con2;
+--echo # Connection con2
+COMMIT;
+
+connection con3;
+--echo # Connection con3
+COMMIT;
+FLUSH LOGS;
+
+connection default;
+--echo # Connection default
+SELECT * FROM t1 ORDER BY a,b;
+SHOW STATUS LIKE 'binlog_trx_%';
+SHOW MASTER STATUS;
+COMMIT;
+SHOW STATUS LIKE 'binlog_trx_%';
+SHOW MASTER STATUS;
+
+--replace_regex /\/\* xid=.* \*\//\/* XID *\// /Server ver: .*, Binlog ver: .*/Server ver: #, Binlog ver: #/ /table_id: [0-9]+/table_id: #/
+SHOW BINLOG EVENTS;
+
+DROP TABLE t1,t2;
diff --git a/mysql-test/t/mysqldump-max.test b/mysql-test/t/mysqldump-max.test
index 1e8b9647503..0a489b7eac7 100644
--- a/mysql-test/t/mysqldump-max.test
+++ b/mysql-test/t/mysqldump-max.test
@@ -2,6 +2,7 @@
--source include/not_embedded.inc
--source include/have_innodb.inc
--source include/have_archive.inc
+--source include/have_log_bin.inc
--disable_warnings
drop table if exists t1, t2, t3, t4, t5, t6;
@@ -1124,3 +1125,83 @@ DROP VIEW v1;
DROP TABLE t1;
SET GLOBAL storage_engine=@old_engine;
+
+# Test fully non-locking mysqldump with consistent binlog position (MWL#136).
+
+connect(c1,127.0.0.1,root,,test,$MASTER_MYPORT,);
+connect(c2,127.0.0.1,root,,test,$MASTER_MYPORT,);
+connect(c3,127.0.0.1,root,,test,$MASTER_MYPORT,);
+
+connection default;
+--echo # Connection default
+RESET MASTER;
+CREATE TABLE t1 (a INT PRIMARY KEY) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (1),(2);
+CREATE TABLE t2 (a INT PRIMARY KEY, b INT) ENGINE=InnoDB;
+INSERT INTO t2 VALUES (1,0), (2,0);
+SELECT GET_LOCK("block_queries_1", 120);
+
+connection c3;
+--echo # Connection c3
+SELECT GET_LOCK("block_queries_2", 120);
+
+# Start two queries that will be running on the tables during mysqldump
+connection c1;
+--echo # Connection c1
+SET @c= 0;
+send SELECT IF(@c<1, @c:=@c+1, GET_LOCK("block_queries_1", 120)) FROM t1 ORDER BY a;
+
+connection c2;
+--echo # Connection c2
+SET binlog_format="row";
+SET @d= 10;
+send UPDATE t2 SET b=IF(@d<=10, @d:=@d+1, GET_LOCK("block_queries_2", 120)) ORDER BY a;
+
+connection default;
+--echo # Connection default
+--echo # Make sure other queries are running (and waiting).
+let $wait_condition=
+ SELECT COUNT(*) FROM information_schema.processlist
+ WHERE state = "User lock" AND info LIKE 'SELECT%block_queries_1%';
+--source include/wait_condition.inc
+let $wait_condition=
+ SELECT COUNT(*) FROM information_schema.processlist
+ WHERE state = "User lock" AND info LIKE 'UPDATE%block_queries_2%';
+--source include/wait_condition.inc
+
+--exec $MYSQL_DUMP --master-data=2 --single-transaction test t1 t2 > $MYSQLTEST_VARDIR/tmp/mwl136.sql
+
+SELECT RELEASE_LOCK("block_queries_1");
+
+connection c3;
+--echo # Connection c3
+SELECT RELEASE_LOCK("block_queries_2");
+
+connection c1;
+--echo # Connection c1
+reap;
+
+connection c2;
+--echo # Connection c2
+reap;
+
+connection default;
+--echo # Connection default
+SELECT * FROM t2 ORDER BY a;
+DROP TABLE t1;
+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;
+--perl
+my $f= "$ENV{MYSQLTEST_VARDIR}/tmp/mwl136.sql";
+open F, '<', $f or die "Failed to open $f: $!\n";
+while (<F>) {
+ print if /CHANGE MASTER TO/;
+}
+EOF
+SELECT * FROM t1 ORDER BY a;
+SELECT * FROM t2 ORDER BY a;
+
+DROP TABLE t1,t2;
diff --git a/sql/log.cc b/sql/log.cc
index d18ded1f24e..5b3264986c1 100644
--- a/sql/log.cc
+++ b/sql/log.cc
@@ -62,6 +62,7 @@ static int binlog_savepoint_rollback(handlerton *hton, THD *thd, void *sv);
static int binlog_commit(handlerton *hton, THD *thd, bool all);
static int binlog_rollback(handlerton *hton, THD *thd, bool all);
static int binlog_prepare(handlerton *hton, THD *thd, bool all);
+static int binlog_start_consistent_snapshot(handlerton *hton, THD *thd);
/**
Silence all errors and warnings reported when performing a write
@@ -155,9 +156,10 @@ class binlog_trx_data {
public:
binlog_trx_data()
: at_least_one_stmt_committed(0), incident(FALSE), m_pending(0),
- before_stmt_pos(MY_OFF_T_UNDEF), commit_bin_log_file_pos(0), using_xa(0)
+ before_stmt_pos(MY_OFF_T_UNDEF), last_commit_pos_offset(0), using_xa(0)
{
trans_log.end_of_file= max_binlog_cache_size;
+ strcpy(last_commit_pos_file, "");
}
~binlog_trx_data()
@@ -215,7 +217,8 @@ public:
incident= FALSE;
trans_log.end_of_file= max_binlog_cache_size;
using_xa= FALSE;
- commit_bin_log_file_pos= 0;
+ strcpy(last_commit_pos_file, "");
+ last_commit_pos_offset= 0;
DBUG_ASSERT(empty());
}
@@ -261,10 +264,14 @@ public:
*/
my_off_t before_stmt_pos;
/*
- Binlog position after current commit, available to storage engines during
- commit_ordered() and commit().
+ Binlog position for current transaction.
+ For START TRANSACTION WITH CONSISTENT SNAPSHOT, this is the binlog
+ position corresponding to the snapshot taken. During (and after) commit,
+ this is set to the binlog position corresponding to just after the
+ commit (so storage engines can store it in their transaction log).
*/
- ulonglong commit_bin_log_file_pos;
+ char last_commit_pos_file[FN_REFLEN];
+ my_off_t last_commit_pos_offset;
/*
Flag set true if this transaction is committed with log_xid() as part of
@@ -1392,6 +1399,7 @@ int binlog_init(void *p)
binlog_hton->commit= binlog_commit;
binlog_hton->rollback= binlog_rollback;
binlog_hton->prepare= binlog_prepare;
+ binlog_hton->start_consistent_snapshot= binlog_start_consistent_snapshot;
binlog_hton->flags= HTON_NOT_USER_SELECTABLE | HTON_HIDDEN;
return 0;
}
@@ -2771,6 +2779,11 @@ bool MYSQL_BIN_LOG::open(const char *log_name,
if (flush_io_cache(&log_file) ||
my_sync(log_file.file, MYF(MY_WME)))
goto err;
+ pthread_mutex_lock(&LOCK_commit_ordered);
+ strmake(last_commit_pos_file, log_file_name,
+ sizeof(last_commit_pos_file)-1);
+ last_commit_pos_offset= my_b_tell(&log_file);
+ pthread_mutex_unlock(&LOCK_commit_ordered);
if (write_file_name_to_index_file)
{
@@ -4199,6 +4212,25 @@ void THD::binlog_set_stmt_begin() {
trx_data->before_stmt_pos= pos;
}
+static int
+binlog_start_consistent_snapshot(handlerton *hton, THD *thd)
+{
+ int err= 0;
+ binlog_trx_data *trx_data;
+ DBUG_ENTER("binlog_start_consistent_snapshot");
+
+ thd->binlog_setup_trx_data();
+ trx_data= (binlog_trx_data*) thd_get_ha_data(thd, binlog_hton);
+
+ /* Server layer calls us with LOCK_commit_ordered locked, so this is safe. */
+ strmake(trx_data->last_commit_pos_file, mysql_bin_log.last_commit_pos_file,
+ sizeof(trx_data->last_commit_pos_file)-1);
+ trx_data->last_commit_pos_offset= mysql_bin_log.last_commit_pos_offset;
+
+ trans_register_ha(thd, TRUE, hton);
+
+ DBUG_RETURN(err);
+}
/*
Write a table map to the binary log.
@@ -4337,6 +4369,9 @@ MYSQL_BIN_LOG::flush_and_set_pending_rows_event(THD *thd,
rotate_and_purge(RP_LOCK_LOG_IS_ALREADY_LOCKED);
}
+ pthread_mutex_lock(&LOCK_commit_ordered);
+ last_commit_pos_offset= my_b_tell(&log_file);
+ pthread_mutex_unlock(&LOCK_commit_ordered);
pthread_mutex_unlock(&LOCK_log);
}
@@ -4526,7 +4561,12 @@ bool MYSQL_BIN_LOG::write(Log_event *event_info)
err_unlock:
if (file == &log_file)
+ {
+ pthread_mutex_lock(&LOCK_commit_ordered);
+ last_commit_pos_offset= my_b_tell(&log_file);
+ pthread_mutex_unlock(&LOCK_commit_ordered);
pthread_mutex_unlock(&LOCK_log);
+ }
err:
if (error)
@@ -4827,6 +4867,9 @@ bool MYSQL_BIN_LOG::write_incident(THD *thd)
signal_update();
rotate_and_purge(RP_LOCK_LOG_IS_ALREADY_LOCKED);
}
+ pthread_mutex_lock(&LOCK_commit_ordered);
+ last_commit_pos_offset= my_b_tell(&log_file);
+ pthread_mutex_unlock(&LOCK_commit_ordered);
pthread_mutex_unlock(&LOCK_log);
DBUG_RETURN(error);
@@ -4972,9 +5015,11 @@ MYSQL_BIN_LOG::write_transaction_to_binlog_events(group_commit_entry *entry)
void
MYSQL_BIN_LOG::trx_group_commit_leader(group_commit_entry *leader)
{
- DBUG_ENTER("MYSQL_BIN_LOG::trx_group_commit_leader");
uint xid_count= 0;
uint write_count= 0;
+ my_off_t commit_offset;
+ DBUG_ENTER("MYSQL_BIN_LOG::trx_group_commit_leader");
+ LINT_INIT(commit_offset);
/*
Lock the LOCK_log(), and once we get it, collect any additional writes
@@ -5035,8 +5080,11 @@ MYSQL_BIN_LOG::trx_group_commit_leader(group_commit_entry *leader)
write_count++;
}
- trx_data->commit_bin_log_file_pos=
+ strmake(trx_data->last_commit_pos_file, log_file_name,
+ sizeof(trx_data->last_commit_pos_file)-1);
+ commit_offset=
log_file.pos_in_file + (log_file.write_pos - log_file.write_buffer);
+ trx_data->last_commit_pos_offset= commit_offset;
if (trx_data->using_xa)
xid_count++;
}
@@ -5078,6 +5126,7 @@ MYSQL_BIN_LOG::trx_group_commit_leader(group_commit_entry *leader)
DEBUG_SYNC(leader->thd, "commit_before_get_LOCK_commit_ordered");
pthread_mutex_lock(&LOCK_commit_ordered);
+ last_commit_pos_offset= commit_offset;
/*
We cannot unlock LOCK_log until we have locked LOCK_commit_ordered;
otherwise scheduling could allow the next group commit to run ahead of us,
@@ -6529,10 +6578,6 @@ ulonglong mysql_bin_log_file_pos(void)
Since it stores the position inside THD, it is safe to call without any
locking.
-
- Note that currently the binlog file name is not stored inside THD, but this
- is still safe as it can only change when the log is rotated, and we never
- rotate the binlog while commits are pending inside storage engines.
*/
void
mysql_bin_log_commit_pos(THD *thd, ulonglong *out_pos, const char **out_file)
@@ -6541,8 +6586,8 @@ mysql_bin_log_commit_pos(THD *thd, ulonglong *out_pos, const char **out_file)
(binlog_trx_data*) thd_get_ha_data(thd, binlog_hton);
if (trx_data)
{
- *out_pos= trx_data->commit_bin_log_file_pos;
- *out_file= mysql_bin_log.get_log_fname();
+ *out_file= trx_data->last_commit_pos_file;
+ *out_pos= (ulonglong)(trx_data->last_commit_pos_offset);
}
else
{
@@ -6555,6 +6600,8 @@ mysql_bin_log_commit_pos(THD *thd, ulonglong *out_pos, const char **out_file)
static ulonglong binlog_status_var_num_commits;
static ulonglong binlog_status_var_num_group_commits;
+static char binlog_trx_file[FN_REFLEN];
+static ulonglong binlog_trx_position;
static SHOW_VAR binlog_status_vars_detail[]=
{
@@ -6562,12 +6609,16 @@ static SHOW_VAR binlog_status_vars_detail[]=
(char *)&binlog_status_var_num_commits, SHOW_LONGLONG},
{"group_commits",
(char *)&binlog_status_var_num_group_commits, SHOW_LONGLONG},
+ {"trx_file",
+ (char *)&binlog_trx_file, SHOW_CHAR},
+ {"trx_position",
+ (char *)&binlog_trx_position, SHOW_LONGLONG},
{NullS, NullS, SHOW_LONG}
};
static int show_binlog_vars(THD *thd, SHOW_VAR *var, char *buff)
{
- mysql_bin_log.set_status_variables();
+ mysql_bin_log.set_status_variables(thd);
var->type= SHOW_ARRAY;
var->value= (char *)&binlog_status_vars_detail;
return 0;
@@ -6606,17 +6657,31 @@ static struct st_mysql_sys_var *binlog_sys_vars[]=
This is called only under LOCK_status, so we can fill in a static array.
*/
void
-TC_LOG_BINLOG::set_status_variables()
+TC_LOG_BINLOG::set_status_variables(THD *thd)
{
- ulonglong num_commits, num_group_commits;
+ binlog_trx_data *trx_data;
+
+ if (thd)
+ trx_data= (binlog_trx_data*) thd_get_ha_data(thd, binlog_hton);
+ else
+ trx_data= NULL;
pthread_mutex_lock(&LOCK_commit_ordered);
- num_commits= this->num_commits;
- num_group_commits= this->num_group_commits;
+ binlog_status_var_num_commits= this->num_commits;
+ binlog_status_var_num_group_commits= this->num_group_commits;
+ if (!trx_data || 0 == strcmp(trx_data->last_commit_pos_file, ""))
+ {
+ strmake(binlog_trx_file, last_commit_pos_file, sizeof(binlog_trx_file)-1);
+ binlog_trx_position= last_commit_pos_offset;
+ }
pthread_mutex_unlock(&LOCK_commit_ordered);
- binlog_status_var_num_commits= num_commits;
- binlog_status_var_num_group_commits= num_group_commits;
+ if (trx_data && 0 != strcmp(trx_data->last_commit_pos_file, ""))
+ {
+ strmake(binlog_trx_file, trx_data->last_commit_pos_file,
+ sizeof(binlog_trx_file)-1);
+ binlog_trx_position= trx_data->last_commit_pos_offset;
+ }
}
struct st_mysql_storage_engine binlog_storage_engine=
diff --git a/sql/log.h b/sql/log.h
index fcc9d5a711b..e2266114e81 100644
--- a/sql/log.h
+++ b/sql/log.h
@@ -406,6 +406,12 @@ public:
*/
Format_description_log_event *description_event_for_exec,
*description_event_for_queue;
+ /*
+ Binlog position of last commit (or non-transactional write) to the binlog.
+ Access to this is protected by LOCK_commit_ordered.
+ */
+ char last_commit_pos_file[FN_REFLEN];
+ my_off_t last_commit_pos_offset;
MYSQL_BIN_LOG();
/*
@@ -521,7 +527,7 @@ public:
inline void unlock_index() { pthread_mutex_unlock(&LOCK_index);}
inline IO_CACHE *get_index_file() { return &index_file;}
inline uint32 get_open_count() { return open_count; }
- void set_status_variables();
+ void set_status_variables(THD *thd);
};
class Log_event_handler