diff options
author | Aleksey Midenkov <midenok@gmail.com> | 2020-05-15 17:13:35 +0300 |
---|---|---|
committer | Aleksey Midenkov <midenok@gmail.com> | 2020-05-15 17:13:35 +0300 |
commit | f2a944516ea8fd3de1d79d46da5aa1c8a32cd78d (patch) | |
tree | a58d318446f4ac7fc199e53efa7e0029023cc3c6 | |
parent | 3b251e24b6c8fe81bc5eeca086d9c1e57e6739d2 (diff) | |
parent | a4996f951d731322acc63033646d950ddbb0f60c (diff) | |
download | mariadb-git-f2a944516ea8fd3de1d79d46da5aa1c8a32cd78d.tar.gz |
Merge 10.4 into 10.5
-rw-r--r-- | mysql-test/main/alter_table.result | 41 | ||||
-rw-r--r-- | mysql-test/main/alter_table.test | 42 | ||||
-rw-r--r-- | mysql-test/suite/galera/r/galera_bf_kill.result | 72 | ||||
-rw-r--r-- | mysql-test/suite/galera/r/galera_bf_lock_wait.result | 4 | ||||
-rw-r--r-- | mysql-test/suite/galera/t/galera_bf_kill.cnf | 7 | ||||
-rw-r--r-- | mysql-test/suite/galera/t/galera_bf_kill.test | 143 | ||||
-rw-r--r-- | mysql-test/suite/galera/t/galera_bf_lock_wait.cnf | 7 | ||||
-rw-r--r-- | mysql-test/suite/galera/t/galera_bf_lock_wait.test | 8 | ||||
-rw-r--r-- | sql/field.cc | 2 | ||||
-rw-r--r-- | sql/item.h | 5 | ||||
-rw-r--r-- | sql/opt_range.cc | 2 | ||||
-rw-r--r-- | sql/service_wsrep.cc | 10 | ||||
-rw-r--r-- | storage/innobase/handler/ha_innodb.cc | 139 | ||||
-rw-r--r-- | storage/innobase/include/ha_prototypes.h | 4 | ||||
-rw-r--r-- | storage/innobase/include/trx0trx.h | 46 | ||||
-rw-r--r-- | storage/innobase/lock/lock0lock.cc | 2 | ||||
-rw-r--r-- | storage/innobase/trx/trx0roll.cc | 3 | ||||
-rw-r--r-- | storage/innobase/trx/trx0trx.cc | 13 |
18 files changed, 453 insertions, 97 deletions
diff --git a/mysql-test/main/alter_table.result b/mysql-test/main/alter_table.result index b012fdde54b..5999f2c43c3 100644 --- a/mysql-test/main/alter_table.result +++ b/mysql-test/main/alter_table.result @@ -2564,6 +2564,44 @@ drop view v1; # End of 10.3 tests # # +# MDEV-22563 Segfault on duplicate free of Item_func_in::array +# +create or replace table person_principal ( +person_id bigint not null, +insurant_id varchar(10) not null, +principal_id bigint not null, +principal_officer_id bigint not null, +nursing_degree tinyint null, +nursing_degree_valid_from date not null default cast(current_timestamp(6) as date), +carma_user_id bigint not null, +current_date_time timestamp(6) not null default current_timestamp(6) on update current_timestamp(6), +constraint pk_person_principal primary key (person_id asc), +constraint ck_person_principal_nursing_degree check (nursing_degree in (1,2,3,4,5))); +Warnings: +Warning 1280 Name 'pk_person_principal' ignored for PRIMARY key. +create or replace table person_principal_hist ( +person_id bigint not null, +insurant_id varchar(10) not null, +principal_id bigint not null, +principal_officer_id bigint not null, +nursing_degree tinyint null, +nursing_degree_valid_from date not null default cast(now() as date), +carma_user_id bigint not null, +orig_date_time datetime(6) not null, +constraint pk_person_principal_hist primary key (person_id asc, orig_date_time asc), +constraint ck_person_principal_hist_nursing_degree check (nursing_degree in (1,2,3,4,5))); +Warnings: +Warning 1280 Name 'pk_person_principal_hist' ignored for PRIMARY key. +insert into person_principal (person_id, insurant_id, principal_id, principal_officer_id, nursing_degree, nursing_degree_valid_from, carma_user_id) +values (1, 'A123456789', 5, 1, 1, '2018-05-06', 1); +alter table person_principal add column if not exists date_mask tinyint null; +update person_principal set date_mask = 0; +alter table person_principal modify column date_mask tinyint not null; +drop tables person_principal_hist, person_principal; +# +# End of 10.4 tests +# +# # MDEV-16290 ALTER TABLE ... RENAME COLUMN syntax # SET @save_default_engine= @@DEFAULT_STORAGE_ENGINE; @@ -3250,9 +3288,6 @@ i2 b PRIMARY a drop table t1; # -# End of 10.5 tests -# -# # ALTER TABLE IF EXISTS # create table t1 (a int); diff --git a/mysql-test/main/alter_table.test b/mysql-test/main/alter_table.test index 01ab0f99d45..8b794fcfc3e 100644 --- a/mysql-test/main/alter_table.test +++ b/mysql-test/main/alter_table.test @@ -2078,6 +2078,44 @@ drop view v1; --echo # --echo # +--echo # MDEV-22563 Segfault on duplicate free of Item_func_in::array +--echo # +create or replace table person_principal ( + person_id bigint not null, + insurant_id varchar(10) not null, + principal_id bigint not null, + principal_officer_id bigint not null, + nursing_degree tinyint null, + nursing_degree_valid_from date not null default cast(current_timestamp(6) as date), + carma_user_id bigint not null, + current_date_time timestamp(6) not null default current_timestamp(6) on update current_timestamp(6), + constraint pk_person_principal primary key (person_id asc), + constraint ck_person_principal_nursing_degree check (nursing_degree in (1,2,3,4,5))); + +create or replace table person_principal_hist ( + person_id bigint not null, + insurant_id varchar(10) not null, + principal_id bigint not null, + principal_officer_id bigint not null, + nursing_degree tinyint null, + nursing_degree_valid_from date not null default cast(now() as date), + carma_user_id bigint not null, + orig_date_time datetime(6) not null, + constraint pk_person_principal_hist primary key (person_id asc, orig_date_time asc), + constraint ck_person_principal_hist_nursing_degree check (nursing_degree in (1,2,3,4,5))); + +insert into person_principal (person_id, insurant_id, principal_id, principal_officer_id, nursing_degree, nursing_degree_valid_from, carma_user_id) +values (1, 'A123456789', 5, 1, 1, '2018-05-06', 1); +alter table person_principal add column if not exists date_mask tinyint null; +update person_principal set date_mask = 0; +alter table person_principal modify column date_mask tinyint not null; +drop tables person_principal_hist, person_principal; + +--echo # +--echo # End of 10.4 tests +--echo # + +--echo # --echo # MDEV-16290 ALTER TABLE ... RENAME COLUMN syntax --echo # SET @save_default_engine= @@DEFAULT_STORAGE_ENGINE; @@ -2458,10 +2496,6 @@ order by k, c; drop table t1; --echo # ---echo # End of 10.5 tests ---echo # - ---echo # --echo # ALTER TABLE IF EXISTS --echo # diff --git a/mysql-test/suite/galera/r/galera_bf_kill.result b/mysql-test/suite/galera/r/galera_bf_kill.result new file mode 100644 index 00000000000..8b620323e35 --- /dev/null +++ b/mysql-test/suite/galera/r/galera_bf_kill.result @@ -0,0 +1,72 @@ +connection node_2; +connection node_1; +connection node_2; +CREATE TABLE t1(a int not null primary key auto_increment,b int) engine=InnoDB; +insert into t1 values (NULL,1); +connect node_2a, 127.0.0.1, root, , test, $NODE_MYPORT_2; +connection node_2a; +begin; +update t1 set a = 5; +connection node_2; +select * from t1; +a b +2 1 +disconnect node_2a; +connect node_2a, 127.0.0.1, root, , test, $NODE_MYPORT_2; +connection node_2a; +begin; +update t1 set a =5; +connection node_2; +select * from t1; +a b +2 1 +disconnect node_2a; +connect node_2a, 127.0.0.1, root, , test, $NODE_MYPORT_2; +connection node_2a; +begin; +update t1 set a =5, b=2; +connection node_2; +ALTER TABLE t1 ADD UNIQUE KEY b1(b); +ALTER TABLE t1 DROP KEY b1; +select * from t1; +a b +2 1 +disconnect node_2a; +connect node_2a, 127.0.0.1, root, , test, $NODE_MYPORT_2; +connection node_2a; +begin; +update t1 set a =5, b=2; +connect node_2b, 127.0.0.1, root, , test, $NODE_MYPORT_2; +connection node_2b; +begin; +update t1 set a =6, b=7; +connection node_2; +ALTER TABLE t1 ADD UNIQUE KEY b2(b); +ALTER TABLE t1 DROP KEY b2; +select * from t1; +a b +2 1 +disconnect node_2a; +disconnect node_2b; +connect node_2a, 127.0.0.1, root, , test, $NODE_MYPORT_2; +connection node_2a; +SET SESSION wsrep_on=OFF; +begin; +update t1 set a =5, b=2; +connection node_2; +ALTER TABLE t1 ADD UNIQUE KEY b3(b); +select * from t1; +a b +2 1 +disconnect node_2a; +connect node_2a, 127.0.0.1, root, , test, $NODE_MYPORT_2; +connection node_2a; +SET SESSION wsrep_on=OFF; +begin; +update t1 set a =5, b=2; +connection node_2; +select * from t1; +a b +2 1 +disconnect node_2a; +drop table t1; diff --git a/mysql-test/suite/galera/r/galera_bf_lock_wait.result b/mysql-test/suite/galera/r/galera_bf_lock_wait.result index f893848a72d..71627d11a4e 100644 --- a/mysql-test/suite/galera/r/galera_bf_lock_wait.result +++ b/mysql-test/suite/galera/r/galera_bf_lock_wait.result @@ -1,5 +1,7 @@ connection node_2; connection node_1; +connection node_1; +call mtr.add_suppression("WSREP: Trying to continue unpaused monitor"); CREATE TABLE t1 ENGINE=InnoDB select 1 as a, 1 as b union select 2, 2; ALTER TABLE t1 add primary key(a); CREATE PROCEDURE p1() @@ -19,7 +21,7 @@ connect node_2_p1, 127.0.0.1, root, , test, $NODE_MYPORT_2; call p1; connect node_2_p2, 127.0.0.1, root, , test, $NODE_MYPORT_2; call p1; -connection default; +connection node_1; checking error log for 'BF lock wait long' message for 10 times every 10 seconds ... drop table t1; drop procedure p1; diff --git a/mysql-test/suite/galera/t/galera_bf_kill.cnf b/mysql-test/suite/galera/t/galera_bf_kill.cnf new file mode 100644 index 00000000000..e68f891792c --- /dev/null +++ b/mysql-test/suite/galera/t/galera_bf_kill.cnf @@ -0,0 +1,7 @@ +!include ../galera_2nodes.cnf + +[mysqld.1] +wsrep-debug=SERVER + +[mysqld.2] +wsrep-debug=SERVER diff --git a/mysql-test/suite/galera/t/galera_bf_kill.test b/mysql-test/suite/galera/t/galera_bf_kill.test new file mode 100644 index 00000000000..0748b732ead --- /dev/null +++ b/mysql-test/suite/galera/t/galera_bf_kill.test @@ -0,0 +1,143 @@ +--source include/galera_cluster.inc + +# +# Test case 1: Start a transaction on node_2a and kill it +# from other connection on same node +# + +--connection node_2 +CREATE TABLE t1(a int not null primary key auto_increment,b int) engine=InnoDB; +insert into t1 values (NULL,1); + +--connect node_2a, 127.0.0.1, root, , test, $NODE_MYPORT_2 +--connection node_2a +begin; +update t1 set a = 5; + +--connection node_2 + +--let $wait_condition = SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE USER = 'root' AND COMMAND = 'Sleep' LIMIT 1 +--source include/wait_condition.inc + +--let $k_thread = `SELECT ID FROM INFORMATION_SCHEMA.PROCESSLIST WHERE USER = 'root' AND COMMAND = 'Sleep' LIMIT 1` + +--disable_query_log +--eval KILL $k_thread +--enable_query_log + +select * from t1; +--disconnect node_2a + +# +# Test case 2: Start a transaction on node_2a and use +# kill query from other connection on same node +# + +--connect node_2a, 127.0.0.1, root, , test, $NODE_MYPORT_2 +--connection node_2a +begin; +update t1 set a =5; + +--connection node_2 +--let $wait_condition = SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE USER = 'root' AND COMMAND = 'Sleep' LIMIT 1 +--source include/wait_condition.inc + +--let $k_thread = `SELECT ID FROM INFORMATION_SCHEMA.PROCESSLIST WHERE USER = 'root' AND COMMAND = 'Sleep' LIMIT 1` + +--disable_query_log +--eval KILL QUERY $k_thread +--enable_query_log + +select * from t1; +--disconnect node_2a +# +# Test case 3: Start a transaction on node_2a and start a DDL on other transaction +# that will then abort node_2a transaction +# +--connect node_2a, 127.0.0.1, root, , test, $NODE_MYPORT_2 +--connection node_2a +begin; +update t1 set a =5, b=2; + +--connection node_2 +ALTER TABLE t1 ADD UNIQUE KEY b1(b); +ALTER TABLE t1 DROP KEY b1; + +select * from t1; + +--disconnect node_2a + +# +# Test case 4: Start a transaction on node_2a and conflicting transaction on node_2b +# and start a DDL on other transaction that will then abort node_2a and node_2b +# transactions +# + +--connect node_2a, 127.0.0.1, root, , test, $NODE_MYPORT_2 +--connection node_2a +begin; +update t1 set a =5, b=2; + +--connect node_2b, 127.0.0.1, root, , test, $NODE_MYPORT_2 +--connection node_2b +begin; +send update t1 set a =6, b=7; + +--connection node_2 +ALTER TABLE t1 ADD UNIQUE KEY b2(b); +ALTER TABLE t1 DROP KEY b2; + +select * from t1; + +--disconnect node_2a +--disconnect node_2b + +# +# Test case 5: Start a transaction on node_2a with wsrep disabled +# and start a DDL on other transaction that will then abort node_2a +# transactions +# + +--connect node_2a, 127.0.0.1, root, , test, $NODE_MYPORT_2 +--connection node_2a +SET SESSION wsrep_on=OFF; +begin; +update t1 set a =5, b=2; + +--connection node_2 +ALTER TABLE t1 ADD UNIQUE KEY b3(b); + +select * from t1; + +--disconnect node_2a + +# +# Test case 6: Start a transaction on node_2a with wsrep disabled +# and kill it from other connection on same node +# + +--connect node_2a, 127.0.0.1, root, , test, $NODE_MYPORT_2 +--connection node_2a +SET SESSION wsrep_on=OFF; +begin; +update t1 set a =5, b=2; + +--connection node_2 +--let $wait_condition = SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE USER = 'root' AND COMMAND = 'Sleep' LIMIT 1 +--source include/wait_condition.inc + +--let $k_thread = `SELECT ID FROM INFORMATION_SCHEMA.PROCESSLIST WHERE USER = 'root' AND COMMAND = 'Sleep' LIMIT 1` + +--disable_query_log +--eval KILL $k_thread +--enable_query_log + + +select * from t1; + +--disconnect node_2a + +drop table t1; + + + diff --git a/mysql-test/suite/galera/t/galera_bf_lock_wait.cnf b/mysql-test/suite/galera/t/galera_bf_lock_wait.cnf new file mode 100644 index 00000000000..e68f891792c --- /dev/null +++ b/mysql-test/suite/galera/t/galera_bf_lock_wait.cnf @@ -0,0 +1,7 @@ +!include ../galera_2nodes.cnf + +[mysqld.1] +wsrep-debug=SERVER + +[mysqld.2] +wsrep-debug=SERVER diff --git a/mysql-test/suite/galera/t/galera_bf_lock_wait.test b/mysql-test/suite/galera/t/galera_bf_lock_wait.test index e3a9077a888..a3903fd10c0 100644 --- a/mysql-test/suite/galera/t/galera_bf_lock_wait.test +++ b/mysql-test/suite/galera/t/galera_bf_lock_wait.test @@ -1,6 +1,10 @@ --source include/galera_cluster.inc --source include/big_test.inc - + +--connection node_1 + +call mtr.add_suppression("WSREP: Trying to continue unpaused monitor"); + CREATE TABLE t1 ENGINE=InnoDB select 1 as a, 1 as b union select 2, 2; ALTER TABLE t1 add primary key(a); @@ -28,7 +32,7 @@ send call p1; --connect node_2_p2, 127.0.0.1, root, , test, $NODE_MYPORT_2 send call p1; -connection default; +connection node_1; let $counter=10; let $sleep_period=10; diff --git a/sql/field.cc b/sql/field.cc index 04c45dfb546..6234de43ec8 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -11086,7 +11086,7 @@ Virtual_column_info* Virtual_column_info::clone(THD *thd) return NULL; if (expr) { - dst->expr= expr->get_copy(thd); + dst->expr= expr->build_clone(thd); if (!dst->expr) return NULL; } diff --git a/sql/item.h b/sql/item.h index 3073a4d240d..c5fd5d074f6 100644 --- a/sql/item.h +++ b/sql/item.h @@ -1602,6 +1602,7 @@ public: virtual bool is_order_clause_position() const { return false; } /* cloning of constant items (0 if it is not const) */ virtual Item *clone_item(THD *thd) { return 0; } + /* deep copy item */ virtual Item* build_clone(THD *thd) { return get_copy(thd); } virtual cond_result eq_cmp_result() const { return COND_OK; } inline uint float_length(uint decimals_par) const @@ -2094,6 +2095,10 @@ public: */ virtual bool find_not_null_fields(table_map allowed) { return false; } + /* + Does not guarantee deep copy (depends on copy ctor). + See build_clone() for deep copy. + */ virtual Item *get_copy(THD *thd)=0; bool cache_const_expr_analyzer(uchar **arg); diff --git a/sql/opt_range.cc b/sql/opt_range.cc index be907a0c4b3..ab0040c9f7e 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -2730,6 +2730,7 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use, param.imerge_cost_buff_size= 0; param.using_real_indexes= TRUE; param.remove_jump_scans= TRUE; + param.max_key_parts= 0; param.remove_false_where_parts= remove_false_parts_of_where; param.force_default_mrr= ordered_output; param.possible_keys.clear_all(); @@ -3451,6 +3452,7 @@ bool calculate_cond_selectivity_for_table(THD *thd, TABLE *table, Item **cond) param.using_real_indexes= FALSE; param.real_keynr[0]= 0; param.alloced_sel_args= 0; + param.max_key_parts= 0; thd->no_errors=1; diff --git a/sql/service_wsrep.cc b/sql/service_wsrep.cc index 013ec65d3f5..ce18410d9af 100644 --- a/sql/service_wsrep.cc +++ b/sql/service_wsrep.cc @@ -206,7 +206,15 @@ extern "C" my_bool wsrep_thd_bf_abort(THD *bf_thd, THD *victim_thd, as RSU has paused the provider. */ if ((ret || !wsrep_on(victim_thd)) && signal) - victim_thd->awake(KILL_QUERY); + { + mysql_mutex_assert_not_owner(&victim_thd->LOCK_thd_data); + mysql_mutex_assert_not_owner(&victim_thd->LOCK_thd_kill); + mysql_mutex_lock(&victim_thd->LOCK_thd_data); + mysql_mutex_lock(&victim_thd->LOCK_thd_kill); + victim_thd->awake_no_mutex(KILL_QUERY); + mysql_mutex_unlock(&victim_thd->LOCK_thd_kill); + mysql_mutex_unlock(&victim_thd->LOCK_thd_data); + } return ret; } diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 8448d9291ff..98ea873a9d6 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -18907,86 +18907,129 @@ wsrep_abort_slave_trx( (long long)bf_seqno, (long long)victim_seqno); abort(); } + /*******************************************************************//** This function is used to kill one transaction in BF. */ + +/** This function is used to kill one transaction. + +This transaction was open on this node (not-yet-committed), and a +conflicting writeset from some other node that was being applied +caused a locking conflict. First committed (from other node) +wins, thus open transaction is rolled back. BF stands for +brute-force: any transaction can get aborted by galera any time +it is necessary. + +This conflict can happen only when the replicated writeset (from +other node) is being applied, not when it’s waiting in the queue. +If our local transaction reached its COMMIT and this conflicting +writeset was in the queue, then it should fail the local +certification test instead. + +A brute force abort is only triggered by a locking conflict +between a writeset being applied by an applier thread (slave thread) +and an open transaction on the node, not by a Galera writeset +comparison as in the local certification failure. + +@param[in] bf_thd Brute force (BF) thread +@param[in,out] victim_trx Vimtim trx to be killed +@param[in] signal Should victim be signaled */ +UNIV_INTERN int -wsrep_innobase_kill_one_trx(THD *bf_thd_ptr, const trx_t *bf_trx, - trx_t *victim_trx, bool signal) +wsrep_innobase_kill_one_trx(THD* bf_thd, trx_t *victim_trx, + bool signal) { - ut_ad(lock_mutex_own()); - ut_ad(trx_mutex_own(victim_trx)); - ut_ad(bf_thd_ptr); - ut_ad(victim_trx); + ut_ad(bf_thd); + ut_ad(victim_trx); + ut_ad(lock_mutex_own()); + ut_ad(trx_mutex_own(victim_trx)); DBUG_ENTER("wsrep_innobase_kill_one_trx"); - THD *bf_thd = bf_thd_ptr ? (THD*) bf_thd_ptr : NULL; - THD *thd = (THD *) victim_trx->mysql_thd; - int64_t bf_seqno = (bf_thd) ? wsrep_thd_trx_seqno(bf_thd) : 0; - if (!thd) { - DBUG_PRINT("wsrep", ("no thd for conflicting lock")); - WSREP_WARN("no THD for trx: " TRX_ID_FMT, victim_trx->id); - DBUG_RETURN(1); - } + THD *thd= (THD *) victim_trx->mysql_thd; + ut_ad(thd); + /* Note that bf_trx might not exist here e.g. on MDL conflict + case (test: galera_concurrent_ctas). Similarly, BF thread + could be also acquiring MDL-lock causing victim to be + aborted. However, we have not yet called innobase_trx_init() + for BF transaction (test: galera_many_columns)*/ + trx_t* bf_trx= thd_to_trx(bf_thd); + DBUG_ASSERT(wsrep_on(bf_thd)); - if (!bf_thd) { - DBUG_PRINT("wsrep", ("no BF thd for conflicting lock")); - WSREP_WARN("no BF THD for trx: " TRX_ID_FMT, - bf_trx ? bf_trx->id : 0); - DBUG_RETURN(1); - } - WSREP_LOG_CONFLICT(bf_thd, thd, TRUE); wsrep_thd_LOCK(thd); - WSREP_DEBUG("BF kill (" ULINTPF ", seqno: " INT64PF - "), victim: (%lu) trx: " TRX_ID_FMT, - signal, bf_seqno, - thd_get_thread_id(thd), - victim_trx->id); - - WSREP_DEBUG("Aborting query: %s conf %s trx: %lld", - (thd && wsrep_thd_query(thd)) ? wsrep_thd_query(thd) : "void", - wsrep_thd_transaction_state_str(thd), - wsrep_thd_transaction_id(thd)); - - /* - * we mark with was_chosen_as_deadlock_victim transaction, - * which is already marked as BF victim - * lock_sys is held until this vicitm has aborted - */ - victim_trx->lock.was_chosen_as_wsrep_victim = TRUE; + WSREP_LOG_CONFLICT(bf_thd, thd, TRUE); + + WSREP_DEBUG("Aborter %s trx_id: " TRX_ID_FMT " thread: %ld " + "seqno: %lld client_state: %s client_mode: %s transaction_mode: %s " + "query: %s", + wsrep_thd_is_BF(bf_thd, false) ? "BF" : "normal", + bf_trx ? bf_trx->id : TRX_ID_MAX, + thd_get_thread_id(bf_thd), + wsrep_thd_trx_seqno(bf_thd), + wsrep_thd_client_state_str(bf_thd), + wsrep_thd_client_mode_str(bf_thd), + wsrep_thd_transaction_state_str(bf_thd), + wsrep_thd_query(bf_thd)); + + WSREP_DEBUG("Victim %s trx_id: " TRX_ID_FMT " thread: %ld " + "seqno: %lld client_state: %s client_mode: %s transaction_mode: %s " + "query: %s", + wsrep_thd_is_BF(thd, false) ? "BF" : "normal", + victim_trx->id, + thd_get_thread_id(thd), + wsrep_thd_trx_seqno(thd), + wsrep_thd_client_state_str(thd), + wsrep_thd_client_mode_str(thd), + wsrep_thd_transaction_state_str(thd), + wsrep_thd_query(thd)); + + /* Mark transaction as a victim for Galera abort */ + victim_trx->lock.was_chosen_as_wsrep_victim= true; + + /* Note that we need to release this as it will be acquired + below in wsrep-lib */ wsrep_thd_UNLOCK(thd); + if (wsrep_thd_bf_abort(bf_thd, thd, signal)) { - if (victim_trx->lock.wait_lock) { + lock_t* wait_lock = victim_trx->lock.wait_lock; + if (wait_lock) { + DBUG_ASSERT(victim_trx->is_wsrep()); WSREP_DEBUG("victim has wait flag: %lu", thd_get_thread_id(thd)); - lock_t* wait_lock = victim_trx->lock.wait_lock; - if (wait_lock) { - WSREP_DEBUG("canceling wait lock"); - victim_trx->lock.was_chosen_as_deadlock_victim= TRUE; - lock_cancel_waiting_and_release(wait_lock); - } + WSREP_DEBUG("canceling wait lock"); + victim_trx->lock.was_chosen_as_deadlock_victim= TRUE; + lock_cancel_waiting_and_release(wait_lock); } } DBUG_RETURN(0); } +/** This function forces the victim transaction to abort. Aborting the + transaction does NOT end it, it still has to be rolled back. + + @param bf_thd brute force THD asking for the abort + @param victim_thd victim THD to be aborted + + @return 0 victim was aborted + @return -1 victim thread was aborted (no transaction) +*/ static int wsrep_abort_transaction( -/*====================*/ handlerton*, THD *bf_thd, THD *victim_thd, my_bool signal) { DBUG_ENTER("wsrep_innobase_abort_thd"); + ut_ad(bf_thd); + ut_ad(victim_thd); trx_t* victim_trx = thd_to_trx(victim_thd); - trx_t* bf_trx = (bf_thd) ? thd_to_trx(bf_thd) : NULL; WSREP_DEBUG("abort transaction: BF: %s victim: %s victim conf: %s", wsrep_thd_query(bf_thd), @@ -18996,7 +19039,7 @@ wsrep_abort_transaction( if (victim_trx) { lock_mutex_enter(); trx_mutex_enter(victim_trx); - int rcode= wsrep_innobase_kill_one_trx(bf_thd, bf_trx, + int rcode= wsrep_innobase_kill_one_trx(bf_thd, victim_trx, signal); trx_mutex_exit(victim_trx); lock_mutex_exit(); diff --git a/storage/innobase/include/ha_prototypes.h b/storage/innobase/include/ha_prototypes.h index f84540cacc8..ef1174c95dd 100644 --- a/storage/innobase/include/ha_prototypes.h +++ b/storage/innobase/include/ha_prototypes.h @@ -230,8 +230,8 @@ innobase_casedn_str( #ifdef WITH_WSREP int -wsrep_innobase_kill_one_trx(THD *bf_thd, const trx_t *bf_trx, - trx_t *victim_trx, bool signal); +wsrep_innobase_kill_one_trx(THD *bf_thd, trx_t *victim_trx, + bool signal); ulint wsrep_innobase_mysql_sort(int mysql_type, uint charset_number, unsigned char* str, ulint str_length, unsigned int buf_length); diff --git a/storage/innobase/include/trx0trx.h b/storage/innobase/include/trx0trx.h index be4504f71d8..294670a6f43 100644 --- a/storage/innobase/include/trx0trx.h +++ b/storage/innobase/include/trx0trx.h @@ -435,32 +435,6 @@ Check transaction state */ ut_error; \ } while (0) -/** Check if transaction is free so that it can be re-initialized. -@param t transaction handle */ -#define assert_trx_is_free(t) do { \ - ut_ad(trx_state_eq((t), TRX_STATE_NOT_STARTED)); \ - ut_ad(!(t)->id); \ - ut_ad(!(t)->has_logged()); \ - ut_ad(!(t)->is_referenced()); \ - ut_ad(!(t)->is_wsrep()); \ - ut_ad(!(t)->read_view.is_open()); \ - ut_ad((t)->lock.wait_thr == NULL); \ - ut_ad(UT_LIST_GET_LEN((t)->lock.trx_locks) == 0); \ - ut_ad((t)->lock.table_locks.empty()); \ - ut_ad(!(t)->autoinc_locks \ - || ib_vector_is_empty((t)->autoinc_locks)); \ - ut_ad(UT_LIST_GET_LEN((t)->lock.evicted_tables) == 0); \ - ut_ad((t)->dict_operation == TRX_DICT_OP_NONE); \ -} while(0) - -/** Check if transaction is in-active so that it can be freed and put back to -transaction pool. -@param t transaction handle */ -#define assert_trx_is_inactive(t) do { \ - assert_trx_is_free((t)); \ - ut_ad((t)->dict_operation_lock_mode == 0); \ -} while(0) - #ifdef UNIV_DEBUG /*******************************************************************//** Assert that an autocommit non-locking select cannot be in the @@ -1150,6 +1124,26 @@ public: } + void assert_freed() const + { + ut_ad(state == TRX_STATE_NOT_STARTED); + ut_ad(!id); + ut_ad(!has_logged()); + ut_ad(!is_referenced()); + ut_ad(!is_wsrep()); +#ifdef WITH_WSREP + ut_ad(!lock.was_chosen_as_wsrep_victim); +#endif + ut_ad(!read_view.is_open()); + ut_ad(!lock.wait_thr); + ut_ad(UT_LIST_GET_LEN(lock.trx_locks) == 0); + ut_ad(lock.table_locks.empty()); + ut_ad(!autoinc_locks || ib_vector_is_empty(autoinc_locks)); + ut_ad(UT_LIST_GET_LEN(lock.evicted_tables) == 0); + ut_ad(dict_operation == TRX_DICT_OP_NONE); + } + + private: /** Assign a rollback segment for modifying temporary tables. @return the assigned rollback segment */ diff --git a/storage/innobase/lock/lock0lock.cc b/storage/innobase/lock/lock0lock.cc index 938df53ec49..61052b15431 100644 --- a/storage/innobase/lock/lock0lock.cc +++ b/storage/innobase/lock/lock0lock.cc @@ -1120,7 +1120,7 @@ wsrep_kill_victim( } wsrep_innobase_kill_one_trx(trx->mysql_thd, - trx, lock->trx, TRUE); + lock->trx, true); } } } diff --git a/storage/innobase/trx/trx0roll.cc b/storage/innobase/trx/trx0roll.cc index c20cf4842a0..202a5c2e009 100644 --- a/storage/innobase/trx/trx0roll.cc +++ b/storage/innobase/trx/trx0roll.cc @@ -209,7 +209,8 @@ dberr_t trx_rollback_for_mysql(trx_t* trx) trx->will_lock = 0; ut_ad(trx->mysql_thd); #ifdef WITH_WSREP - trx->wsrep = false; + trx->wsrep= false; + trx->lock.was_chosen_as_wsrep_victim= false; #endif return(DB_SUCCESS); diff --git a/storage/innobase/trx/trx0trx.cc b/storage/innobase/trx/trx0trx.cc index f9c8ede1f1b..47cd014a1c3 100644 --- a/storage/innobase/trx/trx0trx.cc +++ b/storage/innobase/trx/trx0trx.cc @@ -351,14 +351,13 @@ trx_t *trx_create() { trx_t* trx = trx_pools->get(); - assert_trx_is_free(trx); + trx->assert_freed(); mem_heap_t* heap; ib_alloc_t* alloc; /* We just got trx from pool, it should be non locking */ ut_ad(trx->will_lock == 0); - ut_ad(trx->state == TRX_STATE_NOT_STARTED); ut_ad(!trx->rw_trx_hash_pins); DBUG_LOG("trx", "Create: " << trx); @@ -381,7 +380,7 @@ trx_t *trx_create() ut_ad(UT_LIST_GET_LEN(trx->lock.evicted_tables) == 0); #ifdef WITH_WSREP - trx->wsrep_event = NULL; + trx->wsrep_event= NULL; #endif /* WITH_WSREP */ trx_sys.register_trx(trx); @@ -430,11 +429,11 @@ void trx_free(trx_t*& trx) } trx->dict_operation = TRX_DICT_OP_NONE; - assert_trx_is_inactive(trx); + ut_ad(!trx->dict_operation_lock_mode); trx_sys.deregister_trx(trx); - assert_trx_is_free(trx); + trx->assert_freed(); trx_sys.rw_trx_hash.put_pins(trx); trx->mysql_thd = 0; @@ -1481,7 +1480,6 @@ inline void trx_t::commit_in_memory(const mtr_t *mtr) trx_mutex_enter(this); dict_operation= TRX_DICT_OP_NONE; - lock.was_chosen_as_deadlock_victim= false; DBUG_LOG("trx", "Commit in memory: " << this); state= TRX_STATE_NOT_STARTED; @@ -1495,9 +1493,10 @@ inline void trx_t::commit_in_memory(const mtr_t *mtr) wsrep= false; wsrep_commit_ordered(mysql_thd); } + lock.was_chosen_as_wsrep_victim= false; #endif /* WITH_WSREP */ - assert_trx_is_free(this); + assert_freed(); trx_init(this); trx_mutex_exit(this); |