diff options
author | Vladislav Vaintroub <wlad@mariadb.com> | 2017-09-11 16:45:36 +0000 |
---|---|---|
committer | Vladislav Vaintroub <wlad@mariadb.com> | 2017-09-12 05:57:05 +0000 |
commit | 31774f0ede81d77d889061324930d3d0066c653a (patch) | |
tree | b9131beffe7791a39a21434dcdfe492543a9f3a7 | |
parent | 6b5c0effe43d5cfd19d3aff0fdb5fb6f1b6d41d3 (diff) | |
download | mariadb-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.cc | 94 | ||||
-rw-r--r-- | extra/mariabackup/xtrabackup.cc | 22 | ||||
-rw-r--r-- | extra/mariabackup/xtrabackup.h | 4 | ||||
-rw-r--r-- | mysql-test/suite/mariabackup/lock_ddl_per_table.result | 4 | ||||
-rw-r--r-- | mysql-test/suite/mariabackup/lock_ddl_per_table.test | 12 | ||||
-rw-r--r-- | mysql-test/suite/mariabackup/suite.opt | 2 |
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 |