diff options
author | Sergei Golubchik <serg@mariadb.org> | 2015-12-22 10:32:33 +0100 |
---|---|---|
committer | Sergei Golubchik <serg@mariadb.org> | 2015-12-22 10:32:33 +0100 |
commit | 7697bf0bd7e5b50c1071742ac90539be71f6eabe (patch) | |
tree | 9c4f650d6961467da0bbda23e3697571c984832d | |
parent | 0686c34d22a5cbf93015012eaf77a4a977b63afb (diff) | |
parent | 080da551ea171f8a43633ab27b56875938643dd0 (diff) | |
download | mariadb-git-7697bf0bd7e5b50c1071742ac90539be71f6eabe.tar.gz |
Merge branch 'github/10.0-galera' into 10.1
Note: some tests fail, just as they failed before the merge!
26 files changed, 382 insertions, 141 deletions
diff --git a/include/mysql/service_wsrep.h b/include/mysql/service_wsrep.h index 93567c1927d..6b332f89958 100644 --- a/include/mysql/service_wsrep.h +++ b/include/mysql/service_wsrep.h @@ -104,6 +104,7 @@ extern struct wsrep_service_st { const char * (*wsrep_thd_query_state_str_func)(THD *thd); int (*wsrep_thd_retry_counter_func)(THD *thd); void (*wsrep_thd_set_conflict_state_func)(THD *thd, enum wsrep_conflict_state state); + bool (*wsrep_thd_skip_append_keys_func)(THD *thd); long long (*wsrep_thd_trx_seqno_func)(THD *thd); struct wsrep_ws_handle * (*wsrep_thd_ws_handle_func)(THD *thd); int (*wsrep_trx_is_aborting_func)(MYSQL_THD thd); @@ -144,6 +145,7 @@ extern struct wsrep_service_st { #define wsrep_thd_query_state_str(T) wsrep_service->wsrep_thd_query_state_str_func(T) #define wsrep_thd_retry_counter(T) wsrep_service->wsrep_thd_retry_counter_func(T) #define wsrep_thd_set_conflict_state(T,S) wsrep_service->wsrep_thd_set_conflict_state_func(T,S) +#define wsrep_thd_skip_append_keys(T) wsrep_service->wsrep_thd_skip_append_keys_func(T) #define wsrep_thd_trx_seqno(T) wsrep_service->wsrep_thd_trx_seqno_func(T) #define wsrep_thd_ws_handle(T) wsrep_service->wsrep_thd_ws_handle_func(T) #define wsrep_trx_is_aborting(T) wsrep_service->wsrep_trx_is_aborting_func(T) @@ -204,6 +206,7 @@ void wsrep_thd_LOCK(THD *thd); void wsrep_thd_UNLOCK(THD *thd); void wsrep_thd_awake(THD *thd, my_bool signal); void wsrep_thd_set_conflict_state(THD *thd, enum wsrep_conflict_state state); +bool wsrep_thd_skip_append_keys(THD *thd); void wsrep_unlock_rollback(); #endif diff --git a/include/service_versions.h b/include/service_versions.h index 58d5f41c4a3..0f0990d43b3 100644 --- a/include/service_versions.h +++ b/include/service_versions.h @@ -30,7 +30,7 @@ #define VERSION_thd_timezone 0x0100 #define VERSION_my_sha1 0x0101 #define VERSION_my_md5 0x0100 -#define VERSION_wsrep 0x0200 +#define VERSION_wsrep 0x0201 #define VERSION_logger 0x0100 #define VERSION_thd_autoinc 0x0100 #define VERSION_thd_error_context 0x0100 diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index 2db4fc71544..01ac06f6fc9 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -354,7 +354,7 @@ my $opt_max_save_datadir= env_or_val(MTR_MAX_SAVE_DATADIR => 20); my $opt_max_test_fail= env_or_val(MTR_MAX_TEST_FAIL => 10); my $opt_parallel= $ENV{MTR_PARALLEL} || 1; -my $opt_port_group_size = $ENV{MTR_PORT_GROUP_SIZE} || 10; +my $opt_port_group_size = $ENV{MTR_PORT_GROUP_SIZE} || 20; # lock file to stop tests my $opt_stop_file= $ENV{MTR_STOP_FILE}; diff --git a/mysql-test/suite/galera/galera_3nodes_as_slave.cnf b/mysql-test/suite/galera/galera_3nodes_as_slave.cnf index 4f3fdb02045..aed33ba365b 100644 --- a/mysql-test/suite/galera/galera_3nodes_as_slave.cnf +++ b/mysql-test/suite/galera/galera_3nodes_as_slave.cnf @@ -1,73 +1,79 @@ # -# This .cnf file creates a setup with 1 standard MySQL server, followed by a 2-node Galera cluster +# This .cnf file creates a setup with 1 standard MariaDB server, followed by a 3-node Galera cluster # # Use default setting for mysqld processes !include include/default_mysqld.cnf [mysqld] -log-slave-updates -log-bin=mysqld-bin +log-bin binlog-format=row [mysqld.1] server-id=1 [mysqld.2] -server-id=2 - -wsrep_provider=@ENV.WSREP_PROVIDER -wsrep_cluster_address='gcomm://' -wsrep_provider_options='base_port=@mysqld.2.#galera_port;evs.install_timeout = PT15S; evs.max_install_timeouts=1;' +#galera_port=@OPT.port +#ist_port=@OPT.port +#sst_port=@OPT.port -# enforce read-committed characteristics across the cluster -wsrep_causal_reads=ON -wsrep_sync_wait = 7 +log-slave-updates +innodb-autoinc-lock-mode=2 +default-storage-engine=innodb +wsrep-provider=@ENV.WSREP_PROVIDER wsrep_node_address=127.0.0.1 -wsrep_sst_receive_address=127.0.0.2:@mysqld.2.#sst_port +wsrep-cluster-address=gcomm:// +wsrep_provider_options='base_port=@mysqld.2.#galera_port;evs.install_timeout = PT15S;evs.max_install_timeouts=1;gcache.size=10M' wsrep_node_incoming_address=127.0.0.1:@mysqld.2.port +wsrep_sst_receive_address='127.0.0.1:@mysqld.2.#sst_port' -# Required for Galera -innodb_autoinc_lock_mode=2 - -innodb_flush_log_at_trx_commit=2 +# enforce read-committed characteristics across the cluster +wsrep-causal-reads=ON +wsrep-sync-wait=7 +server-id=2 [mysqld.3] -wsrep_provider=@ENV.WSREP_PROVIDER -wsrep_cluster_address='gcomm://127.0.0.1:@mysqld.2.#galera_port' -wsrep_provider_options='base_port=@mysqld.3.#galera_port;evs.install_timeout = PT15S; evs.max_install_timeouts = 1;' +#galera_port=@OPT.port +#ist_port=@OPT.port +#sst_port=@OPT.port -# enforce read-committed characteristics across the cluster -wsrep_causal_reads=ON -wsrep_sync_wait = 7 +log-slave-updates +innodb-autoinc-lock-mode=2 +default-storage-engine=innodb +wsrep-provider=@ENV.WSREP_PROVIDER wsrep_node_address=127.0.0.1 -wsrep_sst_receive_address=127.0.0.2:@mysqld.3.#sst_port +wsrep_cluster_address='gcomm://127.0.0.1:@mysqld.2.#galera_port' +wsrep_provider_options='base_port=@mysqld.3.#galera_port;evs.install_timeout=PT15S;evs.max_install_timeouts=1;gcache.size=10M' wsrep_node_incoming_address=127.0.0.1:@mysqld.3.port +wsrep_sst_receive_address='127.0.0.1:@mysqld.3.#sst_port' -# Required for Galera -innodb_autoinc_lock_mode=2 - -innodb_flush_log_at_trx_commit=2 +# enforce read-committed characteristics across the cluster +wsrep-causal-reads=ON +wsrep-sync-wait=7 +server-id=3 [mysqld.4] -wsrep_provider=@ENV.WSREP_PROVIDER -wsrep_cluster_address='gcomm://127.0.0.1:@mysqld.2.#galera_port' -wsrep_provider_options='base_port=@mysqld.4.#galera_port;evs.install_timeout = PT15S; evs.max_install_timeouts = 1;' +#galera_port=@OPT.port +#ist_port=@OPT.port +#sst_port=@OPT.port -# enforce read-committed characteristics across the cluster -wsrep_causal_reads=ON -wsrep_sync_wait = 7 +log-slave-updates +innodb-autoinc-lock-mode=2 +default-storage-engine=innodb +wsrep-provider=@ENV.WSREP_PROVIDER wsrep_node_address=127.0.0.1 -wsrep_sst_receive_address=127.0.0.2:@mysqld.4.#sst_port +wsrep_cluster_address='gcomm://127.0.0.1:@mysqld.2.#galera_port' +wsrep_provider_options='base_port=@mysqld.4.#galera_port;evs.install_timeout=PT15S;evs.max_install_timeouts=1;gcache.size=10M' wsrep_node_incoming_address=127.0.0.1:@mysqld.4.port +wsrep_sst_receive_address='127.0.0.1:@mysqld.4.#sst_port' -# Required for Galera -innodb_autoinc_lock_mode=2 - -innodb_flush_log_at_trx_commit=2 +# enforce read-committed characteristics across the cluster +wsrep-causal-reads=ON +wsrep-sync-wait=7 +server-id=4 [ENV] NODE_MYPORT_1= @mysqld.1.port @@ -79,8 +85,8 @@ NODE_MYSOCK_2= @mysqld.2.socket NODE_MYPORT_3= @mysqld.3.port NODE_MYSOCK_3= @mysqld.3.socket -NODE_MYPORT_3= @mysqld.4.port -NODE_MYSOCK_3= @mysqld.4.socket +NODE_MYPORT_4= @mysqld.4.port +NODE_MYSOCK_4= @mysqld.4.socket NODE_GALERAPORT_2= @mysqld.2.#galera_port NODE_GALERAPORT_3= @mysqld.3.#galera_port diff --git a/mysql-test/suite/galera/r/galera_as_slave_nonprim.result b/mysql-test/suite/galera/r/galera_as_slave_nonprim.result index ded3caecf89..fd20f8db2f9 100644 --- a/mysql-test/suite/galera/r/galera_as_slave_nonprim.result +++ b/mysql-test/suite/galera/r/galera_as_slave_nonprim.result @@ -1,6 +1,4 @@ -START SLAVE USER='root'; -Warnings: -Note 1759 Sending passwords in plain text without SSL/TLS is extremely insecure. +START SLAVE; SET SESSION wsrep_sync_wait = 0; CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB; SET GLOBAL wsrep_provider_options = 'gmcast.isolate=1'; diff --git a/mysql-test/suite/galera/r/mdev_9290.result b/mysql-test/suite/galera/r/mdev_9290.result new file mode 100644 index 00000000000..cb2f0813333 --- /dev/null +++ b/mysql-test/suite/galera/r/mdev_9290.result @@ -0,0 +1,14 @@ +# +# MDEV-9290 : InnoDB: Assertion failure in file trx0sys.cc line 353 +# InnoDB: Failing assertion: xid_seqno > trx_sys_cur_xid_seqno +# +CREATE TABLE t1 (i INT) ENGINE=InnoDB; +START TRANSACTION; +INSERT INTO t1 VALUES (1); +INSERT INTO t1 VALUES (2); +COMMIT; +SELECT * FROM t1; +i +1 +2 +DROP TABLE t1; diff --git a/mysql-test/suite/galera/t/galera_as_slave_nonprim.test b/mysql-test/suite/galera/t/galera_as_slave_nonprim.test index 5c53ff79cc1..b7b656383fd 100644 --- a/mysql-test/suite/galera/t/galera_as_slave_nonprim.test +++ b/mysql-test/suite/galera/t/galera_as_slave_nonprim.test @@ -6,7 +6,6 @@ # --source include/have_innodb.inc ---source include/have_log_bin.inc --source include/big_test.inc # Step #1. Establish replication @@ -18,9 +17,9 @@ --connection node_2 --disable_query_log ---eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=$NODE_MYPORT_1; +--eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=$NODE_MYPORT_1, MASTER_USER='root'; --enable_query_log -START SLAVE USER='root'; +START SLAVE; SET SESSION wsrep_sync_wait = 0; --connection node_1 @@ -64,7 +63,7 @@ SET GLOBAL wsrep_provider_options = 'gmcast.isolate=0'; --source include/wait_condition.inc --connection node_2 ---source include/galera_wait_ready.inc +--source include/wait_until_ready.inc --source include/wait_until_connected_again.inc START SLAVE; diff --git a/mysql-test/suite/galera/t/galera_var_dirty_reads.test b/mysql-test/suite/galera/t/galera_var_dirty_reads.test index 855f4abdbf0..9eea8efdaf3 100644 --- a/mysql-test/suite/galera/t/galera_var_dirty_reads.test +++ b/mysql-test/suite/galera/t/galera_var_dirty_reads.test @@ -5,6 +5,14 @@ --source include/galera_cluster.inc --source include/have_innodb.inc +--disable_query_log +# Save original auto_increment_offset values. +--connection node_1 +let $auto_increment_offset_node_1 = `SELECT @@global.auto_increment_offset`; +--connection node_2 +let $auto_increment_offset_node_2 = `SELECT @@global.auto_increment_offset`; +--enable_query_log + --connection node_2 --let $wsrep_cluster_address_saved = `SELECT @@global.wsrep_cluster_address` @@ -41,6 +49,14 @@ SELECT * FROM t1; # Cleanup DROP TABLE t1; +--disable_query_log +# Restore original auto_increment_offset values. +--connection node_1 +--eval SET @@global.auto_increment_offset = $auto_increment_offset_node_1; +--connection node_2 +--eval SET @@global.auto_increment_offset = $auto_increment_offset_node_2; +--enable_query_log + --source include/galera_end.inc --echo # End of test diff --git a/mysql-test/suite/galera/t/mdev_9290.test b/mysql-test/suite/galera/t/mdev_9290.test new file mode 100644 index 00000000000..39e02011a09 --- /dev/null +++ b/mysql-test/suite/galera/t/mdev_9290.test @@ -0,0 +1,24 @@ +--source include/galera_cluster.inc +--source include/have_innodb.inc + +--echo # +--echo # MDEV-9290 : InnoDB: Assertion failure in file trx0sys.cc line 353 +--echo # InnoDB: Failing assertion: xid_seqno > trx_sys_cur_xid_seqno +--echo # + +--connection node_1 +CREATE TABLE t1 (i INT) ENGINE=InnoDB; + +--connection node_2 +# Note: a multi-statement transaction should always be the "first" one to execute +# on this node. +START TRANSACTION; +INSERT INTO t1 VALUES (1); +INSERT INTO t1 VALUES (2); +COMMIT; + +--connection node_1 +SELECT * FROM t1; +DROP TABLE t1; + +--source include/galera_end.inc diff --git a/scripts/wsrep_sst_mysqldump.sh b/scripts/wsrep_sst_mysqldump.sh index 21c4bf62130..5f25c2c9d13 100644 --- a/scripts/wsrep_sst_mysqldump.sh +++ b/scripts/wsrep_sst_mysqldump.sh @@ -76,17 +76,6 @@ fi # word, it is arguably more secure than passing password on the command line. [ -n "$WSREP_SST_OPT_PSWD" ] && export MYSQL_PWD="$WSREP_SST_OPT_PSWD" -# Refs https://github.com/codership/mysql-wsrep/issues/141 -# Passing password in MYSQL_PWD environment variable is considered -# "extremely insecure" by MySQL Guidelines for Password Security -# (https://dev.mysql.com/doc/refman/5.6/en/password-security-user.html) -# that is even less secure than passing it on a command line! It is doubtful: -# the whole command line is easily observable by any unprivileged user via ps, -# whereas (at least on Linux) unprivileged user can't see process environment -# that he does not own. So while it may be not secure in the NSA sense of the -# word, it is arguably more secure than passing password on the command line. -[ -n "$WSREP_SST_OPT_PSWD" ] && export MYSQL_PWD="$WSREP_SST_OPT_PSWD" - STOP_WSREP="SET wsrep_on=OFF;" # mysqldump cannot restore CSV tables, fix this issue diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 566d0ff9e04..121d3432758 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -5230,10 +5230,20 @@ static int init_server_components() THD *current_thd_saved= current_thd; set_current_thd(tmp); + /* + Also save/restore server_status and variables.option_bits and they + get altered during init_for_queries(). + */ + unsigned int server_status_saved= tmp->server_status; + ulonglong option_bits_saved= tmp->variables.option_bits; + tmp->init_for_queries(); /* Restore current_thd. */ set_current_thd(current_thd_saved); + + tmp->server_status= server_status_saved; + tmp->variables.option_bits= option_bits_saved; } } mysql_mutex_unlock(&LOCK_thread_count); diff --git a/sql/rpl_gtid.cc b/sql/rpl_gtid.cc index 90d750c38ad..47c0f4e3fb7 100644 --- a/sql/rpl_gtid.cc +++ b/sql/rpl_gtid.cc @@ -562,6 +562,14 @@ rpl_slave_state::record_gtid(THD *thd, const rpl_gtid *gtid, uint64 sub_id, if ((err= gtid_check_rpl_slave_state_table(table))) goto end; +#ifdef WITH_WSREP + /* + Updates in slave state table should not be appended to galera transaction + writeset. + */ + thd->wsrep_skip_append_keys= true; +#endif + if (!in_transaction) { DBUG_PRINT("info", ("resetting OPTION_BEGIN")); @@ -676,6 +684,10 @@ IF_DBUG(dbug_break:, ) end: +#ifdef WITH_WSREP + thd->wsrep_skip_append_keys= false; +#endif + if (table_opened) { if (err || (err= ha_commit_trans(thd, FALSE))) diff --git a/sql/sql_class.cc b/sql/sql_class.cc index e95e32a5e0b..729b23cf993 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -901,7 +901,8 @@ THD::THD(bool is_wsrep_applier) wsrep_apply_toi(false), wsrep_po_handle(WSREP_PO_INITIALIZER), wsrep_po_cnt(0), - wsrep_apply_format(0) + wsrep_apply_format(0), + wsrep_skip_append_keys(false) #endif { ulong tmp; diff --git a/sql/sql_class.h b/sql/sql_class.h index aee6d560bfb..27837e4f60a 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -3989,6 +3989,7 @@ public: #endif /* GTID_SUPPORT */ void *wsrep_apply_format; char wsrep_info[128]; /* string for dynamic proc info */ + bool wsrep_skip_append_keys; #endif /* WITH_WSREP */ /* Handling of timeouts for commands */ diff --git a/sql/sql_plugin_services.ic b/sql/sql_plugin_services.ic index 0570e2fcdd9..da0cc17250b 100644 --- a/sql/sql_plugin_services.ic +++ b/sql/sql_plugin_services.ic @@ -133,6 +133,7 @@ static struct wsrep_service_st wsrep_handler = { wsrep_thd_query_state_str, wsrep_thd_retry_counter, wsrep_thd_set_conflict_state, + wsrep_thd_skip_append_keys, wsrep_thd_trx_seqno, wsrep_thd_ws_handle, wsrep_trx_is_aborting, diff --git a/sql/wsrep_dummy.cc b/sql/wsrep_dummy.cc index 5cbf6821e7c..603cd8ec5ea 100644 --- a/sql/wsrep_dummy.cc +++ b/sql/wsrep_dummy.cc @@ -116,6 +116,9 @@ int wsrep_thd_retry_counter(THD *) void wsrep_thd_set_conflict_state(THD *, enum wsrep_conflict_state) { } +bool wsrep_thd_skip_append_keys(THD *) +{ return 0; } + longlong wsrep_thd_trx_seqno(THD *) { return -1; } diff --git a/sql/wsrep_mysqld.cc b/sql/wsrep_mysqld.cc index 90b1c132ae9..b922d2b2857 100644 --- a/sql/wsrep_mysqld.cc +++ b/sql/wsrep_mysqld.cc @@ -1877,7 +1877,7 @@ error: WSREP_ERROR("Failed to create/initialize system thread"); /* Abort if its the first applier/rollbacker thread. */ - if (wsrep_creating_startup_threads < 2) + if (wsrep_creating_startup_threads == 1) unireg_abort(1); else return NULL; @@ -2381,6 +2381,12 @@ int wsrep_thd_retry_counter(THD *thd) } +extern "C" bool wsrep_thd_skip_append_keys(THD *thd) +{ + return thd->wsrep_skip_append_keys; +} + + extern int wsrep_trx_order_before(THD *thd1, THD *thd2) { diff --git a/sql/wsrep_mysqld.h b/sql/wsrep_mysqld.h index 3c36e88eb6d..26d3484b3b4 100644 --- a/sql/wsrep_mysqld.h +++ b/sql/wsrep_mysqld.h @@ -151,7 +151,6 @@ extern "C" query_id_t wsrep_thd_query_id(THD *thd); extern "C" query_id_t wsrep_thd_wsrep_last_query_id(THD *thd); extern "C" void wsrep_thd_set_wsrep_last_query_id(THD *thd, query_id_t id); - extern void wsrep_close_client_connections(my_bool wait_to_end); extern int wsrep_wait_committing_connections_close(int wait_time); extern void wsrep_close_applier(THD *thd); @@ -165,7 +164,6 @@ extern bool wsrep_start_replication(); extern bool wsrep_sync_wait(THD* thd, uint mask = WSREP_SYNC_WAIT_BEFORE_READ); extern int wsrep_check_opts(); extern void wsrep_prepend_PATH (const char* path); -/* some inline functions are defined in wsrep_mysqld_inl.h */ /* Other global variables */ extern wsrep_seqno_t wsrep_locked_seqno; diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 359805ff95d..527c5beb47c 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -4598,7 +4598,6 @@ innobase_kill_query( enum thd_kill_levels level) /*!< in: kill level */ { trx_t* trx; - bool took_lock_sys = false; DBUG_ENTER("innobase_kill_query"); DBUG_ASSERT(hton == innodb_hton_ptr); @@ -4619,30 +4618,47 @@ innobase_kill_query( #endif /* WITH_WSREP */ trx = thd_to_trx(thd); - if (trx) { - THD *cur = current_thd; - THD *owner = trx->current_lock_mutex_owner; - - if (!owner || owner != cur) { + if (trx && trx->lock.wait_lock) { + /* In wsrep BF we have already took lock_sys and trx + mutex either on wsrep_abort_transaction() or + before wsrep_kill_victim(). In replication we + could own lock_sys mutex taken in + lock_deadlock_check_and_resolve(). */ + + WSREP_DEBUG("Killing victim trx %p BF %d trx BF %d trx_id " TRX_ID_FMT " ABORT %d thd %p" + " current_thd %p BF %d wait_lock_modes: %s\n", + trx, wsrep_thd_is_BF(trx->mysql_thd, FALSE), + wsrep_thd_is_BF(thd, FALSE), + trx->id, trx->abort_type, + trx->mysql_thd, + current_thd, + wsrep_thd_is_BF(current_thd, FALSE), + lock_get_info(trx->lock.wait_lock).c_str()); + + if (!wsrep_thd_is_BF(trx->mysql_thd, FALSE) && + trx->abort_type == TRX_SERVER_ABORT) { ut_ad(!lock_mutex_own()); lock_mutex_enter(); - took_lock_sys = true; } - ut_ad(!trx_mutex_own(trx)); - trx_mutex_enter(trx); + if (trx->abort_type != TRX_WSREP_ABORT) { + trx_mutex_enter(trx); + } + + ut_ad(lock_mutex_own()); + ut_ad(trx_mutex_own(trx)); /* Cancel a pending lock request. */ if (trx->lock.wait_lock) { lock_cancel_waiting_and_release(trx->lock.wait_lock); } - ut_ad(lock_mutex_own()); - ut_ad(trx_mutex_own(trx)); - - trx_mutex_exit(trx); + if (trx->abort_type != TRX_WSREP_ABORT) { + trx_mutex_exit(trx); + } - if (took_lock_sys) { + if (!wsrep_thd_is_BF(trx->mysql_thd, FALSE) && + trx->abort_type == TRX_SERVER_ABORT) { lock_mutex_exit(); } } @@ -8088,7 +8104,8 @@ report_error: if (!error_result && wsrep_thd_exec_mode(user_thd) == LOCAL_STATE && wsrep_on(user_thd) && - !wsrep_consistency_check(user_thd)) + !wsrep_consistency_check(user_thd) && + !wsrep_thd_skip_append_keys(user_thd)) { if (wsrep_append_keys(user_thd, false, record, NULL)) { @@ -8607,10 +8624,11 @@ func_exit: innobase_active_small(); #ifdef WITH_WSREP - if (error == DB_SUCCESS && + if (error == DB_SUCCESS && wsrep_thd_exec_mode(user_thd) == LOCAL_STATE && - wsrep_on(user_thd)) { - + wsrep_on(user_thd) && + !wsrep_thd_skip_append_keys(user_thd)) + { DBUG_PRINT("wsrep", ("update row key")); if (wsrep_append_keys(user_thd, false, old_row, new_row)) { @@ -8673,9 +8691,10 @@ ha_innobase::delete_row( #ifdef WITH_WSREP if (error == DB_SUCCESS && - wsrep_thd_exec_mode(user_thd) == LOCAL_STATE && - wsrep_on(user_thd)) { - + wsrep_thd_exec_mode(user_thd) == LOCAL_STATE && + wsrep_on(user_thd) && + !wsrep_thd_skip_append_keys(user_thd)) + { if (wsrep_append_keys(user_thd, false, record, NULL)) { DBUG_PRINT("wsrep", ("delete fail")); error = (dberr_t) HA_ERR_INTERNAL_ERROR; @@ -18304,13 +18323,13 @@ wsrep_abort_transaction( if (victim_trx) { lock_mutex_enter(); - victim_trx->current_lock_mutex_owner = victim_thd; trx_mutex_enter(victim_trx); + victim_trx->abort_type = TRX_WSREP_ABORT; int rcode = wsrep_innobase_kill_one_trx(bf_thd, bf_trx, victim_trx, signal); trx_mutex_exit(victim_trx); - victim_trx->current_lock_mutex_owner = NULL; lock_mutex_exit(); + victim_trx->abort_type = TRX_SERVER_ABORT; wsrep_srv_conc_cancel_wait(victim_trx); DBUG_RETURN(rcode); } else { diff --git a/storage/innobase/include/lock0lock.h b/storage/innobase/include/lock0lock.h index d96fdfa9d89..acfb8ef19c6 100644 --- a/storage/innobase/include/lock0lock.h +++ b/storage/innobase/include/lock0lock.h @@ -664,6 +664,16 @@ lock_get_type( const lock_t* lock); /*!< in: lock */ /*******************************************************************//** +Gets the trx of the lock. Non-inline version for using outside of the +lock module. +@return trx_t* */ +UNIV_INTERN +trx_t* +lock_get_trx( +/*=========*/ + const lock_t* lock); /*!< in: lock */ + +/*******************************************************************//** Gets the id of the transaction owning a lock. @return transaction id */ UNIV_INTERN @@ -991,6 +1001,14 @@ void lock_cancel_waiting_and_release( /*============================*/ lock_t* lock); /*!< in/out: waiting lock request */ + +/*******************************************************************//** +Get lock mode and table/index name +@return string containing lock info */ +std::string +lock_get_info( + const lock_t*); + #endif /* WITH_WSREP */ #ifndef UNIV_NONINL #include "lock0lock.ic" diff --git a/storage/innobase/include/trx0trx.h b/storage/innobase/include/trx0trx.h index 6cb082edc67..4f0fac4c899 100644 --- a/storage/innobase/include/trx0trx.h +++ b/storage/innobase/include/trx0trx.h @@ -673,6 +673,12 @@ lock_rec_convert_impl_to_expl()) will access transactions associated to other connections. The locks of transactions are protected by lock_sys->mutex and sometimes by trx->mutex. */ +typedef enum { + TRX_SERVER_ABORT = 0, + TRX_WSREP_ABORT = 1, + TRX_REPLICATION_ABORT = 2 +} trx_abort_t; + struct trx_t{ ulint magic_n; @@ -848,6 +854,8 @@ struct trx_t{ /*------------------------------*/ THD* mysql_thd; /*!< MySQL thread handle corresponding to this trx, or NULL */ + trx_abort_t abort_type; /*!< Transaction abort type*/ + const char* mysql_log_file_name; /*!< if MySQL binlog is used, this field contains a pointer to the latest file @@ -992,11 +1000,6 @@ struct trx_t{ count of tables being flushed. */ /*------------------------------*/ - THD* current_lock_mutex_owner; - /*!< If this is equal to current_thd, - then in innobase_kill_query() we know we - already hold the lock_sys->mutex. */ - /*------------------------------*/ #ifdef UNIV_DEBUG ulint start_line; /*!< Track where it was started from */ const char* start_file; /*!< Filename where it was started */ diff --git a/storage/innobase/lock/lock0lock.cc b/storage/innobase/lock/lock0lock.cc index 36570a2a2b7..184b1a375ce 100644 --- a/storage/innobase/lock/lock0lock.cc +++ b/storage/innobase/lock/lock0lock.cc @@ -54,6 +54,9 @@ Created 5/7/1996 Heikki Tuuri #include <mysql/service_wsrep.h> +#include <string> +#include <sstream> + /* Restricts the length of search we will do in the waits-for graph of transactions */ #define LOCK_MAX_N_STEPS_IN_DEADLOCK_CHECK 1000000 @@ -1726,8 +1729,10 @@ wsrep_kill_victim( } } + lock->trx->abort_type = TRX_WSREP_ABORT; wsrep_innobase_kill_one_trx(trx->mysql_thd, (const trx_t*) trx, lock->trx, TRUE); + lock->trx->abort_type = TRX_SERVER_ABORT; } } } @@ -4441,9 +4446,9 @@ lock_report_waiters_to_mysql( innobase_kill_query. We mark this by setting current_lock_mutex_owner, so we can avoid trying to recursively take lock_sys->mutex. */ - w_trx->current_lock_mutex_owner = mysql_thd; + w_trx->abort_type = TRX_REPLICATION_ABORT; thd_report_wait_for(mysql_thd, w_trx->mysql_thd); - w_trx->current_lock_mutex_owner = NULL; + w_trx->abort_type = TRX_SERVER_ABORT; } ++i; } @@ -6813,7 +6818,7 @@ lock_clust_rec_modify_check_and_lock( lock_mutex_enter(); trx_t* trx = thr_get_trx(thr); - trx->current_lock_mutex_owner = trx->mysql_thd; + ut_ad(lock_table_has(trx, index->table, LOCK_IX)); err = lock_rec_lock(TRUE, LOCK_X | LOCK_REC_NOT_GAP, @@ -6821,7 +6826,6 @@ lock_clust_rec_modify_check_and_lock( MONITOR_INC(MONITOR_NUM_RECLOCK_REQ); - trx->current_lock_mutex_owner = NULL; lock_mutex_exit(); ut_ad(lock_rec_queue_validate(FALSE, block, rec, index, offsets)); @@ -6875,7 +6879,6 @@ lock_sec_rec_modify_check_and_lock( trx_t* trx = thr_get_trx(thr); lock_mutex_enter(); - trx->current_lock_mutex_owner = trx->mysql_thd; ut_ad(lock_table_has(trx, index->table, LOCK_IX)); @@ -6884,7 +6887,6 @@ lock_sec_rec_modify_check_and_lock( MONITOR_INC(MONITOR_NUM_RECLOCK_REQ); - trx->current_lock_mutex_owner = NULL; lock_mutex_exit(); #ifdef UNIV_DEBUG @@ -6977,7 +6979,6 @@ lock_sec_rec_read_check_and_lock( trx_t* trx = thr_get_trx(thr); lock_mutex_enter(); - trx->current_lock_mutex_owner = trx->mysql_thd; ut_ad(mode != LOCK_X || lock_table_has(trx, index->table, LOCK_IX)); @@ -6989,7 +6990,6 @@ lock_sec_rec_read_check_and_lock( MONITOR_INC(MONITOR_NUM_RECLOCK_REQ); - trx->current_lock_mutex_owner = NULL; lock_mutex_exit(); ut_ad(lock_rec_queue_validate(FALSE, block, rec, index, offsets)); @@ -7052,7 +7052,6 @@ lock_clust_rec_read_check_and_lock( lock_mutex_enter(); trx_t* trx = thr_get_trx(thr); - trx->current_lock_mutex_owner = trx->mysql_thd; ut_ad(mode != LOCK_X || lock_table_has(trx, index->table, LOCK_IX)); @@ -7064,7 +7063,6 @@ lock_clust_rec_read_check_and_lock( MONITOR_INC(MONITOR_NUM_RECLOCK_REQ); - trx->current_lock_mutex_owner = NULL; lock_mutex_exit(); ut_ad(lock_rec_queue_validate(FALSE, block, rec, index, offsets)); @@ -7211,6 +7209,19 @@ lock_get_type( } /*******************************************************************//** +Gets the trx of the lock. Non-inline version for using outside of the +lock module. +@return trx_t* */ +UNIV_INTERN +trx_t* +lock_get_trx( +/*=========*/ + const lock_t* lock) /*!< in: lock */ +{ + return (lock->trx); +} + +/*******************************************************************//** Gets the id of the transaction owning a lock. @return transaction id */ UNIV_INTERN @@ -7779,3 +7790,32 @@ lock_trx_has_rec_x_lock( return(true); } #endif /* UNIV_DEBUG */ + +/*******************************************************************//** +Get lock mode and table/index name +@return string containing lock info */ +std::string +lock_get_info( + const lock_t* lock) +{ + std::string info; + std::string mode("mode "); + std::string index("index "); + std::string table("table "); + std::string n_uniq(" n_uniq"); + std::string n_user(" n_user"); + std::string lock_mode((lock_get_mode_str(lock))); + std::string iname(lock->index->name); + std::string tname(lock->index->table_name); + +#define SSTR( x ) reinterpret_cast< std::ostringstream & >( \ + ( std::ostringstream() << std::dec << x ) ).str() + + info = mode + lock_mode + + index + iname + + table + tname + + n_uniq + SSTR(lock->index->n_uniq) + + n_user + SSTR(lock->index->n_user_defined_cols); + + return info; +} diff --git a/storage/xtradb/handler/ha_innodb.cc b/storage/xtradb/handler/ha_innodb.cc index a28c296181e..2f989a47d86 100644 --- a/storage/xtradb/handler/ha_innodb.cc +++ b/storage/xtradb/handler/ha_innodb.cc @@ -5165,7 +5165,6 @@ innobase_kill_connection( thd_kill_levels) { trx_t* trx; - bool took_lock_sys = false; DBUG_ENTER("innobase_kill_connection"); DBUG_ASSERT(hton == innodb_hton_ptr); @@ -5186,30 +5185,46 @@ innobase_kill_connection( #endif /* WITH_WSREP */ trx = thd_to_trx(thd); - if (trx) { - THD *cur = current_thd; - THD *owner = trx->current_lock_mutex_owner; - - if (!owner || owner != cur) { + if (trx && trx->lock.wait_lock) { + /* In wsrep BF we have already took lock_sys and trx + mutex either on wsrep_abort_transaction() or + before wsrep_kill_victim(). In replication we + could own lock_sys mutex taken in + lock_deadlock_check_and_resolve().*/ + + WSREP_DEBUG("Killing victim trx %p BF %d trx BF %d trx_id " TRX_ID_FMT " ABORT %d thd %p" + " current_thd %p BF %d wait_lock_modes: %s\n", + trx, wsrep_thd_is_BF(trx->mysql_thd, FALSE), + wsrep_thd_is_BF(thd, FALSE), + trx->id, trx->abort_type, + trx->mysql_thd, + current_thd, + wsrep_thd_is_BF(current_thd, FALSE), + lock_get_info(trx->lock.wait_lock).c_str()); + + if (!wsrep_thd_is_BF(trx->mysql_thd, FALSE) && + trx->abort_type == TRX_SERVER_ABORT) { ut_ad(!lock_mutex_own()); lock_mutex_enter(); - took_lock_sys = true; } - ut_ad(!trx_mutex_own(trx)); - trx_mutex_enter(trx); - - /* Cancel a pending lock request. */ - if (trx->lock.wait_lock) { - lock_cancel_waiting_and_release(trx->lock.wait_lock); + if (trx->abort_type != TRX_WSREP_ABORT) { + trx_mutex_enter(trx); } ut_ad(lock_mutex_own()); ut_ad(trx_mutex_own(trx)); - trx_mutex_exit(trx); + if (trx->lock.wait_lock) { + lock_cancel_waiting_and_release(trx->lock.wait_lock); + } - if (took_lock_sys) { + if (trx->abort_type != TRX_WSREP_ABORT) { + trx_mutex_exit(trx); + } + + if (!wsrep_thd_is_BF(trx->mysql_thd, FALSE) && + trx->abort_type == TRX_SERVER_ABORT) { lock_mutex_exit(); } } @@ -8635,7 +8650,8 @@ report_error: if (!error_result && wsrep_thd_exec_mode(user_thd) == LOCAL_STATE && wsrep_on(user_thd) && - !wsrep_consistency_check(user_thd)) + !wsrep_consistency_check(user_thd) && + !wsrep_thd_skip_append_keys(user_thd)) { if (wsrep_append_keys(user_thd, false, record, NULL)) { @@ -9166,10 +9182,11 @@ func_exit: innobase_active_small(); #ifdef WITH_WSREP - if (error == DB_SUCCESS && + if (error == DB_SUCCESS && wsrep_thd_exec_mode(user_thd) == LOCAL_STATE && - wsrep_on(user_thd)) { - + wsrep_on(user_thd) && + !wsrep_thd_skip_append_keys(user_thd)) + { DBUG_PRINT("wsrep", ("update row key")); if (wsrep_append_keys(user_thd, false, old_row, new_row)) { @@ -9246,9 +9263,10 @@ ha_innobase::delete_row( #ifdef WITH_WSREP if (error == DB_SUCCESS && - wsrep_thd_exec_mode(user_thd) == LOCAL_STATE && - wsrep_on(user_thd)) { - + wsrep_thd_exec_mode(user_thd) == LOCAL_STATE && + wsrep_on(user_thd) && + !wsrep_thd_skip_append_keys(user_thd)) + { if (wsrep_append_keys(user_thd, false, record, NULL)) { DBUG_PRINT("wsrep", ("delete fail")); error = (dberr_t) HA_ERR_INTERNAL_ERROR; @@ -19359,13 +19377,13 @@ wsrep_abort_transaction(handlerton* hton, THD *bf_thd, THD *victim_thd, if (victim_trx) { lock_mutex_enter(); - victim_trx->current_lock_mutex_owner = victim_thd; trx_mutex_enter(victim_trx); + victim_trx->abort_type = TRX_WSREP_ABORT; int rcode = wsrep_innobase_kill_one_trx(bf_thd, bf_trx, victim_trx, signal); trx_mutex_exit(victim_trx); - victim_trx->current_lock_mutex_owner = NULL; lock_mutex_exit(); + victim_trx->abort_type = TRX_SERVER_ABORT; wsrep_srv_conc_cancel_wait(victim_trx); DBUG_RETURN(rcode); } else { diff --git a/storage/xtradb/include/lock0lock.h b/storage/xtradb/include/lock0lock.h index 235b2373c25..7858e5de2db 100644 --- a/storage/xtradb/include/lock0lock.h +++ b/storage/xtradb/include/lock0lock.h @@ -39,6 +39,8 @@ Created 5/7/1996 Heikki Tuuri #include "srv0srv.h" #include "ut0vec.h" +#include <string> + #ifdef UNIV_DEBUG extern ibool lock_print_waits; #endif /* UNIV_DEBUG */ @@ -676,6 +678,16 @@ lock_get_type( const lock_t* lock); /*!< in: lock */ /*******************************************************************//** +Gets the trx of the lock. Non-inline version for using outside of the +lock module. +@return trx_t* */ +UNIV_INTERN +trx_t* +lock_get_trx( +/*=========*/ + const lock_t* lock); /*!< in: lock */ + +/*******************************************************************//** Gets the id of the transaction owning a lock. @return transaction id */ UNIV_INTERN @@ -995,6 +1007,13 @@ extern lock_sys_t* lock_sys; mutex_exit(&lock_sys->wait_mutex); \ } while (0) +/*******************************************************************//** +Get lock mode and table/index name +@return string containing lock info */ +std::string +lock_get_info( + const lock_t*); + #ifndef UNIV_NONINL #include "lock0lock.ic" #endif diff --git a/storage/xtradb/include/trx0trx.h b/storage/xtradb/include/trx0trx.h index ad47eb0b0d2..d3b1b89e706 100644 --- a/storage/xtradb/include/trx0trx.h +++ b/storage/xtradb/include/trx0trx.h @@ -705,6 +705,12 @@ lock_rec_convert_impl_to_expl()) will access transactions associated to other connections. The locks of transactions are protected by lock_sys->mutex and sometimes by trx->mutex. */ +typedef enum { + TRX_SERVER_ABORT = 0, + TRX_WSREP_ABORT = 1, + TRX_REPLICATION_ABORT = 2 +} trx_abort_t; + struct trx_t{ ulint magic_n; @@ -881,6 +887,8 @@ struct trx_t{ /*------------------------------*/ THD* mysql_thd; /*!< MySQL thread handle corresponding to this trx, or NULL */ + trx_abort_t abort_type; /*!< Transaction abort type */ + const char* mysql_log_file_name; /*!< if MySQL binlog is used, this field contains a pointer to the latest file @@ -1031,11 +1039,6 @@ struct trx_t{ count of tables being flushed. */ /*------------------------------*/ - THD* current_lock_mutex_owner; - /*!< If this is equal to current_thd, - then in innobase_kill_query() we know we - already hold the lock_sys->mutex. */ - /*------------------------------*/ #ifdef UNIV_DEBUG ulint start_line; /*!< Track where it was started from */ const char* start_file; /*!< Filename where it was started */ diff --git a/storage/xtradb/lock/lock0lock.cc b/storage/xtradb/lock/lock0lock.cc index 549b9d1e2f3..c3044daafad 100644 --- a/storage/xtradb/lock/lock0lock.cc +++ b/storage/xtradb/lock/lock0lock.cc @@ -54,6 +54,9 @@ Created 5/7/1996 Heikki Tuuri #include <mysql/service_wsrep.h> +#include <string> +#include <sstream> + /* Restricts the length of search we will do in the waits-for graph of transactions */ #define LOCK_MAX_N_STEPS_IN_DEADLOCK_CHECK 1000000 @@ -1726,8 +1729,10 @@ wsrep_kill_victim( } } + lock->trx->abort_type = TRX_WSREP_ABORT; wsrep_innobase_kill_one_trx(trx->mysql_thd, (const trx_t*) trx, lock->trx, TRUE); + lock->trx->abort_type = TRX_SERVER_ABORT; } } } @@ -4469,9 +4474,9 @@ lock_report_waiters_to_mysql( innobase_kill_query. We mark this by setting current_lock_mutex_owner, so we can avoid trying to recursively take lock_sys->mutex. */ - w_trx->current_lock_mutex_owner = mysql_thd; + w_trx->abort_type = TRX_REPLICATION_ABORT; thd_report_wait_for(mysql_thd, w_trx->mysql_thd); - w_trx->current_lock_mutex_owner = NULL; + w_trx->abort_type = TRX_SERVER_ABORT; } ++i; } @@ -6886,7 +6891,7 @@ lock_clust_rec_modify_check_and_lock( lock_mutex_enter(); trx_t* trx = thr_get_trx(thr); - trx->current_lock_mutex_owner = trx->mysql_thd; + ut_ad(lock_table_has(trx, index->table, LOCK_IX)); err = lock_rec_lock(TRUE, LOCK_X | LOCK_REC_NOT_GAP, @@ -6894,7 +6899,6 @@ lock_clust_rec_modify_check_and_lock( MONITOR_INC(MONITOR_NUM_RECLOCK_REQ); - trx->current_lock_mutex_owner = NULL; lock_mutex_exit(); ut_ad(lock_rec_queue_validate(FALSE, block, rec, index, offsets)); @@ -6952,7 +6956,6 @@ lock_sec_rec_modify_check_and_lock( trx_t* trx = thr_get_trx(thr); lock_mutex_enter(); - trx->current_lock_mutex_owner = trx->mysql_thd; ut_ad(lock_table_has(trx, index->table, LOCK_IX)); @@ -6961,7 +6964,6 @@ lock_sec_rec_modify_check_and_lock( MONITOR_INC(MONITOR_NUM_RECLOCK_REQ); - trx->current_lock_mutex_owner = NULL; lock_mutex_exit(); #ifdef UNIV_DEBUG @@ -7063,7 +7065,6 @@ lock_sec_rec_read_check_and_lock( trx_t* trx = thr_get_trx(thr); lock_mutex_enter(); - trx->current_lock_mutex_owner = trx->mysql_thd; ut_ad(mode != LOCK_X || lock_table_has(trx, index->table, LOCK_IX)); @@ -7075,7 +7076,6 @@ lock_sec_rec_read_check_and_lock( MONITOR_INC(MONITOR_NUM_RECLOCK_REQ); - trx->current_lock_mutex_owner = NULL; lock_mutex_exit(); ut_ad(lock_rec_queue_validate(FALSE, block, rec, index, offsets)); @@ -7147,7 +7147,6 @@ lock_clust_rec_read_check_and_lock( lock_mutex_enter(); trx_t* trx = thr_get_trx(thr); - trx->current_lock_mutex_owner = trx->mysql_thd; ut_ad(mode != LOCK_X || lock_table_has(trx, index->table, LOCK_IX)); @@ -7159,7 +7158,6 @@ lock_clust_rec_read_check_and_lock( MONITOR_INC(MONITOR_NUM_RECLOCK_REQ); - trx->current_lock_mutex_owner = NULL; lock_mutex_exit(); ut_ad(lock_rec_queue_validate(FALSE, block, rec, index, offsets)); @@ -7306,6 +7304,19 @@ lock_get_type( } /*******************************************************************//** +Gets the trx of the lock. Non-inline version for using outside of the +lock module. +@return trx_t* */ +UNIV_INTERN +trx_t* +lock_get_trx( +/*=========*/ + const lock_t* lock) /*!< in: lock */ +{ + return (lock->trx); +} + +/*******************************************************************//** Gets the id of the transaction owning a lock. @return transaction id */ UNIV_INTERN @@ -7896,3 +7907,32 @@ lock_trx_has_rec_x_lock( return(true); } #endif /* UNIV_DEBUG */ + +/*******************************************************************//** +Get lock mode and table/index name +@return string containing lock info */ +std::string +lock_get_info( + const lock_t* lock) +{ + std::string info; + std::string mode("mode "); + std::string index("index "); + std::string table("table "); + std::string n_uniq(" n_uniq"); + std::string n_user(" n_user"); + std::string lock_mode((lock_get_mode_str(lock))); + std::string iname(lock->index->name); + std::string tname(lock->index->table_name); + +#define SSTR( x ) reinterpret_cast< std::ostringstream & >( \ + ( std::ostringstream() << std::dec << x ) ).str() + + info = mode + lock_mode + + index + iname + + table + tname + + n_uniq + SSTR(lock->index->n_uniq) + + n_user + SSTR(lock->index->n_user_defined_cols); + + return info; +} |