Skip to content

Commit

Permalink
MDEV-13563 lock DDL for mariabackup in 10.2
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
vaintroub committed Sep 12, 2017
1 parent 6b5c0ef commit 31774f0
Show file tree
Hide file tree
Showing 6 changed files with 136 additions and 2 deletions.
94 changes: 94 additions & 0 deletions extra/mariabackup/backup_mysql.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down Expand Up @@ -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);
}

22 changes: 21 additions & 1 deletion extra/mariabackup/xtrabackup.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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, "",
Expand Down Expand Up @@ -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[] =
Expand Down Expand Up @@ -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}
};

Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -3930,6 +3946,10 @@ xtrabackup_backup_func()
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
Expand Down
4 changes: 4 additions & 0 deletions extra/mariabackup/xtrabackup.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
4 changes: 4 additions & 0 deletions mysql-test/suite/mariabackup/lock_ddl_per_table.result
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
CREATE TABLE t(i INT) ENGINE INNODB;
INSERT INTO t VALUES(1);
# xtrabackup backup
DROP TABLE t;
12 changes: 12 additions & 0 deletions mysql-test/suite/mariabackup/lock_ddl_per_table.test
Original file line number Diff line number Diff line change
@@ -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;
2 changes: 1 addition & 1 deletion mysql-test/suite/mariabackup/suite.opt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
--innodb --loose-changed_page_bitmaps --innodb-file-format=Barracuda
--innodb --loose-changed_page_bitmaps --innodb-file-format=Barracuda --innodb-sys-tables

0 comments on commit 31774f0

Please sign in to comment.