summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVladislav Vaintroub <wlad@mariadb.com>2017-09-11 16:45:36 +0000
committerVladislav Vaintroub <wlad@mariadb.com>2017-09-12 05:57:05 +0000
commit31774f0ede81d77d889061324930d3d0066c653a (patch)
treeb9131beffe7791a39a21434dcdfe492543a9f3a7
parent6b5c0effe43d5cfd19d3aff0fdb5fb6f1b6d41d3 (diff)
downloadmariadb-git-31774f0ede81d77d889061324930d3d0066c653a.tar.gz
MDEV-13563 lock DDL for mariabackup in 10.2
Implement lock-ddl-per-table option that locks tables before it is copied to backup, and helds the lock until backup finished The "DDL-lock" itself is implemented as "SELECT * from <table> LIMIT 0", inside a transaction, and "COMMIT" of this transaction is the DDL-unlock.
-rw-r--r--extra/mariabackup/backup_mysql.cc94
-rw-r--r--extra/mariabackup/xtrabackup.cc22
-rw-r--r--extra/mariabackup/xtrabackup.h4
-rw-r--r--mysql-test/suite/mariabackup/lock_ddl_per_table.result4
-rw-r--r--mysql-test/suite/mariabackup/lock_ddl_per_table.test12
-rw-r--r--mysql-test/suite/mariabackup/suite.opt2
6 files changed, 136 insertions, 2 deletions
diff --git a/extra/mariabackup/backup_mysql.cc b/extra/mariabackup/backup_mysql.cc
index edd369e6ea9..60985dbb519 100644
--- a/extra/mariabackup/backup_mysql.cc
+++ b/extra/mariabackup/backup_mysql.cc
@@ -117,6 +117,7 @@ xb_mysql_connect()
mysql_options(connection, MYSQL_PLUGIN_DIR, xb_plugin_dir);
}
mysql_options(connection, MYSQL_OPT_PROTOCOL, &opt_protocol);
+ mysql_options(connection,MYSQL_SET_CHARSET_NAME, "utf8");
msg_ts("Connecting to MySQL server host: %s, user: %s, password: %s, "
"port: %s, socket: %s\n", opt_host ? opt_host : "localhost",
@@ -1629,3 +1630,96 @@ backup_cleanup()
mysql_close(mysql_connection);
}
}
+
+
+static pthread_mutex_t mdl_lock_con_mutex;
+static MYSQL *mdl_con = NULL;
+
+void
+mdl_lock_init()
+{
+ pthread_mutex_init(&mdl_lock_con_mutex, NULL);
+ mdl_con = xb_mysql_connect();
+ if (mdl_con)
+ {
+ xb_mysql_query(mdl_con, "BEGIN", false, true);
+ }
+}
+
+#ifndef DBUF_OFF
+/* Test that table is really locked, if lock_ddl_per_table is set.
+ The test is executed in DBUG_EXECUTE_IF block inside mdl_lock_table().
+*/
+static void check_mdl_lock_works(const char *table_name)
+{
+ MYSQL *test_con= xb_mysql_connect();
+ char *query;
+ xb_a(asprintf(&query,
+ "SET STATEMENT max_statement_time=1 FOR ALTER TABLE %s"
+ " ADD COLUMN mdl_lock_column int", table_name));
+ int err = mysql_query(test_con, query);
+ DBUG_ASSERT(err);
+ int err_no = mysql_errno(test_con);
+ DBUG_ASSERT(err_no == ER_STATEMENT_TIMEOUT);
+ mysql_close(test_con);
+}
+#endif
+
+extern void
+dict_fs2utf8(const char*, char*, size_t, char*, size_t);
+
+void
+mdl_lock_table(ulint space_id)
+{
+ char *query;
+
+ pthread_mutex_lock(&mdl_lock_con_mutex);
+
+ xb_a(asprintf(&query,
+ "SELECT NAME FROM INFORMATION_SCHEMA.INNODB_SYS_TABLES "
+ "WHERE SPACE = %llu AND NAME LIKE '%%/%%'", (ulonglong)space_id));
+
+ xb_mysql_query(mdl_con, query, true, true);
+
+ MYSQL_RES *mysql_result = xb_mysql_query(mdl_con, query, true);
+
+ MYSQL_ROW row;
+ while ((row = mysql_fetch_row(mysql_result))) {
+ char full_table_name[2*FN_REFLEN +2];
+ char db_utf8[FN_REFLEN];
+ char table_utf8[FN_REFLEN];
+
+ dict_fs2utf8(row[0], db_utf8, sizeof(db_utf8),table_utf8,sizeof(table_utf8));
+ snprintf(full_table_name,sizeof(full_table_name),"`%s`.`%s`",db_utf8,table_utf8);
+
+ char *lock_query;
+
+ msg_ts("Locking MDL for %s\n", full_table_name);
+
+ xb_a(asprintf(&lock_query,
+ "SELECT * FROM %s LIMIT 0",
+ full_table_name));
+
+ xb_mysql_query(mdl_con, lock_query, false, false);
+
+ free(lock_query);
+
+ DBUG_EXECUTE_IF("check_mdl_lock_works",
+ check_mdl_lock_works(full_table_name););
+ }
+
+ mysql_free_result(mysql_result);
+ free(query);
+ pthread_mutex_unlock(&mdl_lock_con_mutex);
+}
+
+
+void
+mdl_unlock_all()
+{
+ msg_ts("Unlocking MDL for all tables");
+ xb_mysql_query(mdl_con, "COMMIT", false, true);
+ mysql_close(mdl_con);
+ pthread_mutex_destroy(&mdl_lock_con_mutex);
+}
+
diff --git a/extra/mariabackup/xtrabackup.cc b/extra/mariabackup/xtrabackup.cc
index 65aa913cc29..5d8bc7eaaf3 100644
--- a/extra/mariabackup/xtrabackup.cc
+++ b/extra/mariabackup/xtrabackup.cc
@@ -296,6 +296,8 @@ my_bool opt_noversioncheck = FALSE;
my_bool opt_no_backup_locks = FALSE;
my_bool opt_decompress = FALSE;
+my_bool opt_lock_ddl_per_table = FALSE;
+
static const char *binlog_info_values[] = {"off", "lockless", "on", "auto",
NullS};
static TYPELIB binlog_info_typelib = {array_elements(binlog_info_values)-1, "",
@@ -537,7 +539,8 @@ enum options_xtrabackup
OPT_XTRA_TABLES_EXCLUDE,
OPT_XTRA_DATABASES_EXCLUDE,
- OPT_PROTOCOL
+ OPT_PROTOCOL,
+ OPT_LOCK_DDL_PER_TABLE
};
struct my_option xb_client_options[] =
@@ -1072,6 +1075,11 @@ struct my_option xb_server_options[] =
(G_PTR*) &xb_open_files_limit, (G_PTR*) &xb_open_files_limit, 0, GET_ULONG,
REQUIRED_ARG, 0, 0, UINT_MAX, 0, 1, 0},
+ {"lock-ddl-per-table", OPT_LOCK_DDL_PER_TABLE, "Lock DDL for each table "
+ "before xtrabackup starts to copy it and until the backup is completed.",
+ (uchar*) &opt_lock_ddl_per_table, (uchar*) &opt_lock_ddl_per_table, 0,
+ GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
+
{ 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
};
@@ -2205,6 +2213,10 @@ xtrabackup_copy_datafile(fil_node_t* node, uint thread_n)
return(FALSE);
}
+ if (opt_lock_ddl_per_table) {
+ mdl_lock_table(node->space->id);
+ }
+
if (!changed_page_bitmap) {
read_filter = &rf_pass_through;
}
@@ -3552,6 +3564,10 @@ xtrabackup_backup_func()
"or RENAME TABLE during the backup, inconsistent backup will be "
"produced.\n");
+ if (opt_lock_ddl_per_table) {
+ mdl_lock_init();
+ }
+
/* initialize components */
if(innodb_init_param()) {
fail:
@@ -3930,6 +3946,10 @@ reread_log_header:
goto fail;
}
+ if (opt_lock_ddl_per_table) {
+ mdl_unlock_all();
+ }
+
xtrabackup_destroy_datasinks();
msg("xtrabackup: Redo log (from LSN " LSN_PF " to " LSN_PF
diff --git a/extra/mariabackup/xtrabackup.h b/extra/mariabackup/xtrabackup.h
index b226a9d1d83..a24626c48bc 100644
--- a/extra/mariabackup/xtrabackup.h
+++ b/extra/mariabackup/xtrabackup.h
@@ -193,4 +193,8 @@ xb_get_one_option(int optid,
const char*
xb_get_copy_action(const char *dflt = "Copying");
+void mdl_lock_init();
+void mdl_lock_table(ulint space_id);
+void mdl_unlock_all();
+
#endif /* XB_XTRABACKUP_H */
diff --git a/mysql-test/suite/mariabackup/lock_ddl_per_table.result b/mysql-test/suite/mariabackup/lock_ddl_per_table.result
new file mode 100644
index 00000000000..d0137a1e072
--- /dev/null
+++ b/mysql-test/suite/mariabackup/lock_ddl_per_table.result
@@ -0,0 +1,4 @@
+CREATE TABLE t(i INT) ENGINE INNODB;
+INSERT INTO t VALUES(1);
+# xtrabackup backup
+DROP TABLE t;
diff --git a/mysql-test/suite/mariabackup/lock_ddl_per_table.test b/mysql-test/suite/mariabackup/lock_ddl_per_table.test
new file mode 100644
index 00000000000..5b45aa7c61b
--- /dev/null
+++ b/mysql-test/suite/mariabackup/lock_ddl_per_table.test
@@ -0,0 +1,12 @@
+--source include/have_debug.inc
+
+CREATE TABLE t(i INT) ENGINE INNODB;
+INSERT INTO t VALUES(1);
+echo # xtrabackup backup;
+let $targetdir=$MYSQLTEST_VARDIR/tmp/backup;
+
+--disable_result_log
+exec $XTRABACKUP --defaults-file=$MYSQLTEST_VARDIR/my.cnf --backup --target-dir=$targetdir --lock-ddl-per-table=1 --dbug=+d,check_mdl_lock_works;
+--enable_result_log
+DROP TABLE t;
+rmdir $targetdir; \ No newline at end of file
diff --git a/mysql-test/suite/mariabackup/suite.opt b/mysql-test/suite/mariabackup/suite.opt
index ba78b2d8957..defba074293 100644
--- a/mysql-test/suite/mariabackup/suite.opt
+++ b/mysql-test/suite/mariabackup/suite.opt
@@ -1 +1 @@
---innodb --loose-changed_page_bitmaps --innodb-file-format=Barracuda \ No newline at end of file
+--innodb --loose-changed_page_bitmaps --innodb-file-format=Barracuda --innodb-sys-tables \ No newline at end of file