diff --git a/client/mysqlimport.c b/client/mysqlimport.c index c1004a6869a..21a8655a249 100644 --- a/client/mysqlimport.c +++ b/client/mysqlimport.c @@ -657,7 +657,6 @@ error: pthread_cond_signal(&count_threshhold); pthread_mutex_unlock(&counter_mutex); mysql_thread_end(); - pthread_exit(0); return 0; } diff --git a/client/mysqltest.cc b/client/mysqltest.cc index c4bbb24e496..2d9d6f76a76 100644 --- a/client/mysqltest.cc +++ b/client/mysqltest.cc @@ -990,7 +990,6 @@ end_thread: cn->mysql= 0; cn->query_done= 1; mysql_thread_end(); - pthread_exit(0); DBUG_RETURN(0); } diff --git a/extra/mariabackup/xtrabackup.cc b/extra/mariabackup/xtrabackup.cc index aa731961df1..6623dce46bf 100644 --- a/extra/mariabackup/xtrabackup.cc +++ b/extra/mariabackup/xtrabackup.cc @@ -915,13 +915,15 @@ datafiles_iter_next(datafiles_iter_t *it) fil_system.space_list.begin() : std::next(it->space); - while (it->space != fil_system.space_list.end() && - (it->space->purpose != FIL_TYPE_TABLESPACE || - UT_LIST_GET_LEN(it->space->chain) == 0)) + while (it->space != fil_system.space_list.end() + && UT_LIST_GET_LEN(it->space->chain) == 0) ++it->space; if (it->space == fil_system.space_list.end()) goto end; + ut_ad(!it->space->is_temporary()); + ut_ad(!it->space->is_being_imported()); + it->node = UT_LIST_GET_FIRST(it->space->chain); end: @@ -1113,7 +1115,8 @@ static void backup_file_op(uint32_t space_id, int type, std::string space_name = filename_to_spacename(name, len); ddl_tracker.id_to_name[space_id] = space_name; ddl_tracker.delete_defer(space_id, space_name); - msg("DDL tracking : create %u \"%.*s\"", space_id, int(len), name); + msg("DDL tracking : create %" PRIu32 " \"%.*s\"", + space_id, int(len), name); } break; case FILE_MODIFY: @@ -1129,7 +1132,7 @@ static void backup_file_op(uint32_t space_id, int type, ddl_tracker.id_to_name[space_id] = new_space_name; ddl_tracker.rename_defer(space_id, old_space_name, new_space_name); - msg("DDL tracking : rename %u \"%.*s\",\"%.*s\"", + msg("DDL tracking : rename %" PRIu32 " \"%.*s\",\"%.*s\"", space_id, int(len), name, int(new_len), new_name); } break; @@ -1137,7 +1140,8 @@ static void backup_file_op(uint32_t space_id, int type, ddl_tracker.drops.insert(space_id); ddl_tracker.delete_defer( space_id, filename_to_spacename(name, len)); - msg("DDL tracking : delete %u \"%.*s\"", space_id, int(len), name); + msg("DDL tracking : delete %" PRIu32 " \"%.*s\"", + space_id, int(len), name); break; default: ut_ad(0); @@ -1188,13 +1192,14 @@ static void backup_file_op_fail(uint32_t space_id, int type, const std::string spacename{filename_to_spacename(name, len)}; switch (type) { case FILE_CREATE: - msg("DDL tracking : create %u \"%.*s\"", space_id, int(len), name); + msg("DDL tracking : create %" PRIu32 " \"%.*s\"", + space_id, int(len), name); fail = !check_if_skip_table(spacename.c_str()); break; case FILE_MODIFY: break; case FILE_RENAME: - msg("DDL tracking : rename %u \"%.*s\",\"%.*s\"", + msg("DDL tracking : rename %" PRIu32 " \"%.*s\",\"%.*s\"", space_id, int(len), name, int(new_len), new_name); fail = !check_if_skip_table(spacename.c_str()) || !check_if_skip_table( @@ -1203,7 +1208,8 @@ static void backup_file_op_fail(uint32_t space_id, int type, case FILE_DELETE: fail = !check_if_skip_table(spacename.c_str()) && !check_if_fts_table(spacename.c_str()); - msg("DDL tracking : delete %u \"%.*s\"", space_id, int(len), name); + msg("DDL tracking : delete %" PRIu32 " \"%.*s\"", + space_id, int(len), name); break; default: ut_ad(0); @@ -1224,7 +1230,7 @@ static void backup_undo_trunc(uint32_t space_id) /* Function to store the space id of page0 INIT_PAGE @param space_id space id which has page0 init page */ -static void backup_first_page_op(space_id_t space_id) +static void backup_first_page_op(uint32_t space_id) { first_page_init_ids.insert(space_id); } @@ -3934,8 +3940,8 @@ static void xb_load_single_table_tablespace(const char *dirname, if (err == DB_SUCCESS && file->space_id() != SRV_TMP_SPACE_ID) { mysql_mutex_lock(&fil_system.mutex); space = fil_space_t::create( - file->space_id(), file->flags(), - FIL_TYPE_TABLESPACE, nullptr/* TODO: crypt_data */, + uint32_t(file->space_id()), file->flags(), false, + nullptr/* TODO: crypt_data */, FIL_ENCRYPTION_DEFAULT, file->handle() != OS_FILE_CLOSED); ut_ad(space); @@ -5670,8 +5676,8 @@ void CorruptedPages::backup_fix_ddl(ds_ctxt *ds_data, ds_ctxt *ds_meta) iter != ddl_tracker.tables_in_backup.end(); iter++) { - const std::string name = iter->second; uint32_t id = iter->first; + const std::string &name = iter->second; if (ddl_tracker.drops.find(id) != ddl_tracker.drops.end()) { dropped_tables.insert(name); @@ -5698,7 +5704,7 @@ void CorruptedPages::backup_fix_ddl(ds_ctxt *ds_data, ds_ctxt *ds_meta) iter++) { uint32_t id = iter->first; - std::string name = iter->second; + const std::string &name = iter->second; if (ddl_tracker.tables_in_backup.find(id) != ddl_tracker.tables_in_backup.end()) { /* already processed above */ @@ -5995,8 +6001,8 @@ exit: char tmpname[FN_REFLEN]; - snprintf(tmpname, FN_REFLEN, "%s/xtrabackup_tmp_#%u", - dbname, fil_space->id); + snprintf(tmpname, FN_REFLEN, "%s/xtrabackup_tmp_#%" + PRIu32, dbname, fil_space->id); msg("mariabackup: Renaming %s to %s.ibd", fil_space->chain.start->name, tmpname); @@ -6051,8 +6057,8 @@ exit: ut_ad(fil_space_t::physical_size(flags) == info.page_size); mysql_mutex_lock(&fil_system.mutex); - fil_space_t* space = fil_space_t::create(info.space_id, flags, - FIL_TYPE_TABLESPACE, 0, + fil_space_t* space = fil_space_t::create(uint32_t(info.space_id), + flags, false, 0, FIL_ENCRYPTION_DEFAULT, true); mysql_mutex_unlock(&fil_system.mutex); if (space) { diff --git a/include/handler_ername.h b/include/handler_ername.h index e969daa7c77..32faa84b52d 100644 --- a/include/handler_ername.h +++ b/include/handler_ername.h @@ -78,5 +78,7 @@ { "HA_ERR_ABORTED_BY_USER", HA_ERR_ABORTED_BY_USER, "" }, { "HA_ERR_DISK_FULL", HA_ERR_DISK_FULL, "" }, { "HA_ERR_INCOMPATIBLE_DEFINITION", HA_ERR_INCOMPATIBLE_DEFINITION, "" }, -{ "HA_ERR_NO_ENCRYPTION", HA_ERR_NO_ENCRYPTION, "" }, { "HA_ERR_COMMIT_ERROR", HA_ERR_COMMIT_ERROR, "" }, +{ "HA_ERR_PARTITION_LIST", HA_ERR_PARTITION_LIST, ""}, +{ "HA_ERR_NO_ENCRYPTION", HA_ERR_NO_ENCRYPTION, ""}, +{ "HA_ERR_ROLLBACK", HA_ERR_ROLLBACK, "" }, diff --git a/include/my_base.h b/include/my_base.h index 3cbd4f7efe1..93fe1d1165a 100644 --- a/include/my_base.h +++ b/include/my_base.h @@ -535,7 +535,8 @@ enum ha_base_keytype { #define HA_ERR_COMMIT_ERROR 197 #define HA_ERR_PARTITION_LIST 198 #define HA_ERR_NO_ENCRYPTION 199 -#define HA_ERR_LAST 199 /* Copy of last error nr * */ +#define HA_ERR_ROLLBACK 200 /* Automatic rollback done */ +#define HA_ERR_LAST 200 /* Copy of last error nr * */ /* Number of different errors */ #define HA_ERR_ERRORS (HA_ERR_LAST - HA_ERR_FIRST + 1) diff --git a/include/my_handler_errors.h b/include/my_handler_errors.h index df414888907..4e96945e134 100644 --- a/include/my_handler_errors.h +++ b/include/my_handler_errors.h @@ -110,7 +110,8 @@ static const char *handler_error_messages[]= "Sequence values are conflicting", "Error during commit", "Cannot select partitions", - "Cannot initialize encryption. Check that all encryption parameters have been set" + "Cannot initialize encryption. Check that all encryption parameters have been set", + "Transaction was aborted", }; #endif /* MYSYS_MY_HANDLER_ERRORS_INCLUDED */ diff --git a/include/my_sys.h b/include/my_sys.h index 5b2f20f7b54..4a1518fc0f2 100644 --- a/include/my_sys.h +++ b/include/my_sys.h @@ -257,9 +257,9 @@ extern void (*my_sigtstp_cleanup)(void), /* Executed before jump to shell */ (*my_sigtstp_restart)(void); /* Executed when coming from shell */ -extern MYSQL_PLUGIN_IMPORT int my_umask; /* Default creation mask */ -extern int my_umask_dir, - my_recived_signals, /* Signals we have got */ +extern MYSQL_PLUGIN_IMPORT mode_t my_umask; /* Default creation mask */ +extern mode_t my_umask_dir; +extern int my_recived_signals, /* Signals we have got */ my_safe_to_handle_signal, /* Set when allowed to SIGTSTP */ my_dont_interrupt; /* call remember_intr when set */ #ifdef _WIN32 @@ -625,7 +625,7 @@ extern File my_open(const char *FileName,int Flags,myf MyFlags); extern File my_register_filename(File fd, const char *FileName, enum file_type type_of_file, uint error_message_number, myf MyFlags); -extern File my_create(const char *FileName,int CreateFlags, +extern File my_create(const char *FileName, mode_t CreateFlags, int AccessFlags, myf MyFlags); extern int my_close(File Filedes,myf MyFlags); extern int my_mkdir(const char *dir, int Flags, myf MyFlags); @@ -633,7 +633,7 @@ extern int my_readlink(char *to, const char *filename, myf MyFlags); extern int my_is_symlink(const char *filename); extern int my_realpath(char *to, const char *filename, myf MyFlags); extern File my_create_with_symlink(const char *linkname, const char *filename, - int createflags, int access_flags, + mode_t createflags, int access_flags, myf MyFlags); extern int my_rename_with_symlink(const char *from,const char *to,myf MyFlags); extern int my_symlink(const char *content, const char *linkname, myf MyFlags); diff --git a/mysql-test/include/innodb_rollback_on_timeout.inc b/mysql-test/include/innodb_rollback_on_timeout.inc index d41e1f1ec9f..5fbdaa1c62a 100644 --- a/mysql-test/include/innodb_rollback_on_timeout.inc +++ b/mysql-test/include/innodb_rollback_on_timeout.inc @@ -2,6 +2,10 @@ # Bug #24200: Provide backwards compatibility mode for 4.x "rollback on # transaction timeout" # +--disable_query_log +call mtr.add_suppression("InnoDB: Transaction was aborted due to "); +--enable_query_log + --disable_warnings drop table if exists t1; --enable_warnings diff --git a/mysql-test/main/bug39022.test b/mysql-test/main/bug39022.test index 211a40234b4..81dd6f14bed 100644 --- a/mysql-test/main/bug39022.test +++ b/mysql-test/main/bug39022.test @@ -2,6 +2,10 @@ -- source include/have_innodb.inc -- source include/not_binlog_format_row.inc +--disable_query_log +call mtr.add_suppression("InnoDB: Transaction was aborted due to "); +--enable_query_log + --echo # --echo # Bug #39022: Mysql randomly crashing in lock_sec_rec_cons_read_sees --echo # diff --git a/mysql-test/main/innodb_mysql_lock.test b/mysql-test/main/innodb_mysql_lock.test index 5ee688b1d6e..e61b2fde055 100644 --- a/mysql-test/main/innodb_mysql_lock.test +++ b/mysql-test/main/innodb_mysql_lock.test @@ -1,6 +1,10 @@ --source include/have_metadata_lock_info.inc -- source include/have_innodb.inc +--disable_query_log +call mtr.add_suppression("InnoDB: Transaction was aborted due to "); +--enable_query_log + # Save the initial number of concurrent sessions. --source include/count_sessions.inc diff --git a/mysql-test/main/log_slow.result b/mysql-test/main/log_slow.result index 4e4a4d71580..6c53debdf66 100644 --- a/mysql-test/main/log_slow.result +++ b/mysql-test/main/log_slow.result @@ -212,6 +212,23 @@ use `a b`; SET timestamp=1234567890; select count(*) from mysql.global_priv where length(priv)>2 +# +# MDEV-31366 Assertion `thd->start_time' failed in bool LOGGER::slow_log_print(THD*, const char*, size_t, ulonglong) +# +TRUNCATE mysql.slow_log; +SET global log_output='TABLE'; +SET timestamp=0.99; +SET long_query_time=0.00001; +SELECT SLEEP(0.1); +SLEEP(0.1) +0 +SELECT COUNT(*)>0 AS c1 FROM mysql.slow_log; +c1 +1 +SET global log_output=default; +SET timestamp=default; +SET long_query_time=default; +TRUNCATE mysql.slow_log; # End of 10.5 tests # # MDEV-34251 Conditional jump or move depends on uninitialised value in diff --git a/mysql-test/main/log_slow.test b/mysql-test/main/log_slow.test index 3b1281bb8ed..73a3369f826 100644 --- a/mysql-test/main/log_slow.test +++ b/mysql-test/main/log_slow.test @@ -225,6 +225,21 @@ let SEARCH_PATTERN= use \`a\n.*2; let SEARCH_OUTPUT=matches; source include/search_pattern_in_file.inc; +--echo # +--echo # MDEV-31366 Assertion `thd->start_time' failed in bool LOGGER::slow_log_print(THD*, const char*, size_t, ulonglong) +--echo # + +TRUNCATE mysql.slow_log; +SET global log_output='TABLE'; +SET timestamp=0.99; +SET long_query_time=0.00001; +SELECT SLEEP(0.1); +SELECT COUNT(*)>0 AS c1 FROM mysql.slow_log; +SET global log_output=default; +SET timestamp=default; +SET long_query_time=default; +TRUNCATE mysql.slow_log; + --echo # End of 10.5 tests --echo # diff --git a/mysql-test/main/long_unique_bugs.test b/mysql-test/main/long_unique_bugs.test index 973b8ff72a9..bf6ff598cd0 100644 --- a/mysql-test/main/long_unique_bugs.test +++ b/mysql-test/main/long_unique_bugs.test @@ -2,6 +2,10 @@ --source include/have_partition.inc --source include/have_sequence.inc +--disable_query_log +call mtr.add_suppression("InnoDB: Transaction was aborted due to "); +--enable_query_log + --echo # --echo # MDEV-18707 Server crash in my_hash_sort_bin, ASAN heap-use-after-free in Field::is_null, server hang, corrupted double-linked list --echo # diff --git a/mysql-test/main/partition_innodb_plugin.test b/mysql-test/main/partition_innodb_plugin.test index c24945152b3..2699ca2ca1a 100644 --- a/mysql-test/main/partition_innodb_plugin.test +++ b/mysql-test/main/partition_innodb_plugin.test @@ -5,6 +5,9 @@ let $MYSQLD_DATADIR= `SELECT @@datadir`; call mtr.add_suppression("InnoDB: Table .* does not exist in the InnoDB internal data dictionary .*"); call mtr.add_suppression("Deadlock found when trying to get lock; try restarting transaction"); +--disable_query_log +call mtr.add_suppression("InnoDB: Transaction was aborted due to "); +--enable_query_log --echo # --echo # Bug#11766879/Bug#60106: DIFF BETWEEN # OF INDEXES IN MYSQL VS INNODB, diff --git a/mysql-test/main/ps_ddl.result b/mysql-test/main/ps_ddl.result index dcbb6982702..35998c05dc9 100644 --- a/mysql-test/main/ps_ddl.result +++ b/mysql-test/main/ps_ddl.result @@ -2037,7 +2037,7 @@ SUCCESS execute stmt; Warnings: Note 1050 Table 't2' already exists -call p_verify_reprepare_count(1); +call p_verify_reprepare_count(0); SUCCESS select * from t2; diff --git a/mysql-test/main/ps_ddl.test b/mysql-test/main/ps_ddl.test index e12fb11d50f..7e6e9a67848 100644 --- a/mysql-test/main/ps_ddl.test +++ b/mysql-test/main/ps_ddl.test @@ -1686,7 +1686,7 @@ drop table t2; execute stmt; call p_verify_reprepare_count(0); execute stmt; -call p_verify_reprepare_count(1); +call p_verify_reprepare_count(0); select * from t2; execute stmt; call p_verify_reprepare_count(0); diff --git a/mysql-test/main/rowid_filter_innodb.test b/mysql-test/main/rowid_filter_innodb.test index d82dccd0551..6b3f9c783e6 100644 --- a/mysql-test/main/rowid_filter_innodb.test +++ b/mysql-test/main/rowid_filter_innodb.test @@ -4,6 +4,10 @@ --source include/have_sequence.inc --source include/innodb_stable_estimates.inc +--disable_query_log +call mtr.add_suppression("InnoDB: Transaction was aborted due to "); +--enable_query_log + SET SESSION DEFAULT_STORAGE_ENGINE='InnoDB'; SET @save_stats_persistent=@@GLOBAL.innodb_stats_persistent; diff --git a/mysql-test/main/xa.test b/mysql-test/main/xa.test index 77df6831355..a4c60ef316d 100644 --- a/mysql-test/main/xa.test +++ b/mysql-test/main/xa.test @@ -2,13 +2,16 @@ # WL#1756 # -- source include/have_innodb.inc - --source include/not_embedded.inc # Save the initial number of concurrent sessions --source include/count_sessions.inc call mtr.add_suppression("Deadlock found when trying to get lock; try restarting transaction"); +--disable_query_log +call mtr.add_suppression("InnoDB: Transaction was aborted due to "); +--enable_query_log + --disable_warnings drop table if exists t1, t2; diff --git a/mysql-test/suite/galera/disabled.def b/mysql-test/suite/galera/disabled.def index cbb42331792..5b92b282ece 100644 --- a/mysql-test/suite/galera/disabled.def +++ b/mysql-test/suite/galera/disabled.def @@ -10,6 +10,5 @@ # ############################################################################## -galera_sequences : MDEV-32561 WSREP FSM failure: no such a transition REPLICATING -> COMMITTED galera_as_slave_replay : MDEV-32780 galera_as_slave_replay: assertion in the wsrep::transaction::before_rollback() galera_slave_replay : MDEV-32780 galera_as_slave_replay: assertion in the wsrep::transaction::before_rollback() diff --git a/mysql-test/suite/galera/r/galera_bf_kill.result b/mysql-test/suite/galera/r/galera_bf_kill.result index 71b0366081b..e6ddf3fc3c5 100644 --- a/mysql-test/suite/galera/r/galera_bf_kill.result +++ b/mysql-test/suite/galera/r/galera_bf_kill.result @@ -1,10 +1,12 @@ connection node_2; connection node_1; connection node_2; +call mtr.add_suppression("InnoDB: Transaction was aborted due to "); 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; +call mtr.add_suppression("InnoDB: Transaction was aborted due to "); begin; update t1 set a = 5; connection node_2; 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 9e5cb2d9266..590fcea2997 100644 --- a/mysql-test/suite/galera/r/galera_bf_lock_wait.result +++ b/mysql-test/suite/galera/r/galera_bf_lock_wait.result @@ -1,8 +1,10 @@ connection node_2; connection node_1; connection node_2; +call mtr.add_suppression("InnoDB: Transaction was aborted due to "); call mtr.add_suppression("WSREP: Trying to continue unpaused monitor"); connection node_1; +call mtr.add_suppression("InnoDB: Transaction was aborted due to "); 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); diff --git a/mysql-test/suite/galera/r/galera_sequences.result b/mysql-test/suite/galera/r/galera_sequences.result index 1a5219c2d45..1f6b2bd6637 100644 --- a/mysql-test/suite/galera/r/galera_sequences.result +++ b/mysql-test/suite/galera/r/galera_sequences.result @@ -314,3 +314,14 @@ NEXTVAL(t) connection node_1; DROP TABLE t1; DROP SEQUENCE t; + +MDEV-33245 SIGSEGV in wsrep_check_sequence | Sql_cmd_alter_sequence::execute + +CREATE TABLE t (a INT) ENGINE=InnoDB; +INSERT INTO t VALUES (0); +CREATE TABLE t1 (c VARCHAR) ENGINE=InnoDB; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near ') ENGINE=InnoDB' at line 1 +ALTER SEQUENCE IF EXISTS t MINVALUE=1; +ERROR 42000: This version of MariaDB doesn't yet support 'CACHE without INCREMENT BY 0 in Galera cluster' +DROP TABLE t; +End of 10.5 tests diff --git a/mysql-test/suite/galera/t/galera_bf_kill.test b/mysql-test/suite/galera/t/galera_bf_kill.test index 1cb2e866cb4..4655a35fde5 100644 --- a/mysql-test/suite/galera/t/galera_bf_kill.test +++ b/mysql-test/suite/galera/t/galera_bf_kill.test @@ -7,11 +7,13 @@ # --connection node_2 +call mtr.add_suppression("InnoDB: Transaction was aborted due to "); 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 +call mtr.add_suppression("InnoDB: Transaction was aborted due to "); begin; update t1 set a = 5; 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 8ef2fee78ed..78a460eda09 100644 --- a/mysql-test/suite/galera/t/galera_bf_lock_wait.test +++ b/mysql-test/suite/galera/t/galera_bf_lock_wait.test @@ -3,9 +3,11 @@ --source include/big_test.inc --connection node_2 +call mtr.add_suppression("InnoDB: Transaction was aborted due to "); call mtr.add_suppression("WSREP: Trying to continue unpaused monitor"); --connection node_1 +call mtr.add_suppression("InnoDB: Transaction was aborted due to "); 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; diff --git a/mysql-test/suite/galera/t/galera_sequences.test b/mysql-test/suite/galera/t/galera_sequences.test index 53417055d7d..75a31b224b9 100644 --- a/mysql-test/suite/galera/t/galera_sequences.test +++ b/mysql-test/suite/galera/t/galera_sequences.test @@ -341,3 +341,18 @@ SELECT NEXTVAL(t); --connection node_1 DROP TABLE t1; DROP SEQUENCE t; + +--echo +--echo MDEV-33245 SIGSEGV in wsrep_check_sequence | Sql_cmd_alter_sequence::execute +--echo + +CREATE TABLE t (a INT) ENGINE=InnoDB; +INSERT INTO t VALUES (0); + +--error ER_PARSE_ERROR +CREATE TABLE t1 (c VARCHAR) ENGINE=InnoDB; +--error ER_NOT_SUPPORTED_YET +ALTER SEQUENCE IF EXISTS t MINVALUE=1; + +DROP TABLE t; +--echo End of 10.5 tests diff --git a/mysql-test/suite/innodb/r/innodb-wl5522-debug.result b/mysql-test/suite/innodb/r/innodb-wl5522-debug.result index 97da5374ca3..18819087e4a 100644 --- a/mysql-test/suite/innodb/r/innodb-wl5522-debug.result +++ b/mysql-test/suite/innodb/r/innodb-wl5522-debug.result @@ -456,7 +456,7 @@ restore: t1 .ibd and .cfg files SET SESSION debug_dbug=@saved_debug_dbug; SET SESSION debug_dbug="+d,ib_import_open_tablespace_failure"; ALTER TABLE t1 IMPORT TABLESPACE; -ERROR HY000: Got error 42 'Tablespace not found' from ./test/t1.ibd +ERROR HY000: Got error 41 'Tablespace not found' from ./test/t1.ibd SET SESSION debug_dbug=@saved_debug_dbug; restore: t1 .ibd and .cfg files SET SESSION debug_dbug="+d,ib_import_check_bitmap_failure"; diff --git a/mysql-test/suite/innodb/t/autoinc_debug.test b/mysql-test/suite/innodb/t/autoinc_debug.test index d38a70b3376..f62cfd8afce 100644 --- a/mysql-test/suite/innodb/t/autoinc_debug.test +++ b/mysql-test/suite/innodb/t/autoinc_debug.test @@ -3,6 +3,10 @@ --source include/have_debug_sync.inc --source include/not_embedded.inc +--disable_query_log +call mtr.add_suppression("InnoDB: Transaction was aborted due to "); +--enable_query_log + # Two parallel connection with autoinc column after restart. CREATE TABLE t1 (id INT AUTO_INCREMENT PRIMARY KEY)ENGINE=INNODB; diff --git a/mysql-test/suite/innodb/t/deadlock_detect.test b/mysql-test/suite/innodb/t/deadlock_detect.test index a84e6fc328f..39ea174a3ec 100644 --- a/mysql-test/suite/innodb/t/deadlock_detect.test +++ b/mysql-test/suite/innodb/t/deadlock_detect.test @@ -5,6 +5,10 @@ --source include/have_innodb.inc --source include/count_sessions.inc +--disable_query_log +call mtr.add_suppression("InnoDB: Transaction was aborted due to "); +--enable_query_log + let $have_deadlock=`select @@GLOBAL.innodb_deadlock_detect`; connection default; diff --git a/mysql-test/suite/innodb/t/deadlock_in_subqueries_join.test b/mysql-test/suite/innodb/t/deadlock_in_subqueries_join.test index b3adfb3b02d..beded05198e 100644 --- a/mysql-test/suite/innodb/t/deadlock_in_subqueries_join.test +++ b/mysql-test/suite/innodb/t/deadlock_in_subqueries_join.test @@ -1,6 +1,10 @@ --source include/have_innodb.inc --source include/count_sessions.inc +--disable_query_log +call mtr.add_suppression("InnoDB: Transaction was aborted due to "); +--enable_query_log + CREATE TABLE t1 ( pkey int NOT NULL PRIMARY KEY, c int diff --git a/mysql-test/suite/innodb/t/deadlock_victim_race.test b/mysql-test/suite/innodb/t/deadlock_victim_race.test index b9a442fc5b9..dac6be698fc 100644 --- a/mysql-test/suite/innodb/t/deadlock_victim_race.test +++ b/mysql-test/suite/innodb/t/deadlock_victim_race.test @@ -2,6 +2,10 @@ --source include/have_debug_sync.inc --source include/count_sessions.inc +--disable_query_log +call mtr.add_suppression("InnoDB: Transaction was aborted due to "); +--enable_query_log + --connect(cancel_purge,localhost,root,,) # Purge can cause deadlock in the test, requesting page's RW_X_LATCH for trx # ids reseting, after trx 2 acqured RW_S_LATCH and suspended in debug sync point diff --git a/mysql-test/suite/innodb/t/deadlock_wait_lock_race.test b/mysql-test/suite/innodb/t/deadlock_wait_lock_race.test index 79a62b098c9..27d02898b72 100644 --- a/mysql-test/suite/innodb/t/deadlock_wait_lock_race.test +++ b/mysql-test/suite/innodb/t/deadlock_wait_lock_race.test @@ -2,6 +2,10 @@ --source include/have_debug_sync.inc --source include/count_sessions.inc +--disable_query_log +call mtr.add_suppression("InnoDB: Transaction was aborted due to "); +--enable_query_log + # Purge can cause deadlock in the test, requesting page's RW_X_LATCH for trx # ids reseting, after trx 2 acqured RW_S_LATCH and suspended in debug sync point # lock_trx_handle_wait_enter, waiting for upd_cont signal, which must be diff --git a/mysql-test/suite/innodb/t/deadlock_wait_thr_race.test b/mysql-test/suite/innodb/t/deadlock_wait_thr_race.test index 42576f35baf..318db88a470 100644 --- a/mysql-test/suite/innodb/t/deadlock_wait_thr_race.test +++ b/mysql-test/suite/innodb/t/deadlock_wait_thr_race.test @@ -2,6 +2,10 @@ --source include/have_debug_sync.inc --source include/count_sessions.inc +--disable_query_log +call mtr.add_suppression("InnoDB: Transaction was aborted due to "); +--enable_query_log + # Purge can cause deadlock in the test, requesting page's RW_X_LATCH for trx # ids reseting, after trx 2 acqured RW_S_LATCH and suspended in debug sync point # lock_trx_handle_wait_enter, waiting for upd_cont signal, which must be diff --git a/mysql-test/suite/innodb/t/foreign_key.test b/mysql-test/suite/innodb/t/foreign_key.test index 8c6ce939bab..4b0dcc97e58 100644 --- a/mysql-test/suite/innodb/t/foreign_key.test +++ b/mysql-test/suite/innodb/t/foreign_key.test @@ -2,6 +2,10 @@ --source include/count_sessions.inc --source include/default_charset.inc +--disable_query_log +call mtr.add_suppression("InnoDB: Transaction was aborted due to "); +--enable_query_log + SET GLOBAL innodb_stats_persistent = 0; --echo # diff --git a/mysql-test/suite/innodb/t/innodb-lock.test b/mysql-test/suite/innodb/t/innodb-lock.test index fbbb1035481..394681702c0 100644 --- a/mysql-test/suite/innodb/t/innodb-lock.test +++ b/mysql-test/suite/innodb/t/innodb-lock.test @@ -1,6 +1,10 @@ --source include/have_innodb.inc --source include/have_partition.inc +--disable_query_log +call mtr.add_suppression("InnoDB: Transaction was aborted due to "); +--enable_query_log + # # Check and select innodb lock type # diff --git a/mysql-test/suite/innodb/t/innodb_bug42419.test b/mysql-test/suite/innodb/t/innodb_bug42419.test index ef350529604..2314a2b43ab 100644 --- a/mysql-test/suite/innodb/t/innodb_bug42419.test +++ b/mysql-test/suite/innodb/t/innodb_bug42419.test @@ -4,6 +4,10 @@ # Bug#42419 Server crash with "Pure virtual method called" on two concurrent connections # +--disable_query_log +call mtr.add_suppression("InnoDB: Transaction was aborted due to "); +--enable_query_log + --source include/not_embedded.inc let $innodb_lock_wait_timeout= query_get_value(SHOW VARIABLES LIKE 'innodb_lock_wait_timeout%', Value, 1); diff --git a/mysql-test/suite/innodb/t/innodb_mysql_rbk.test b/mysql-test/suite/innodb/t/innodb_mysql_rbk.test index 85a9769732f..ffdfaf48ea6 100644 --- a/mysql-test/suite/innodb/t/innodb_mysql_rbk.test +++ b/mysql-test/suite/innodb/t/innodb_mysql_rbk.test @@ -1,5 +1,9 @@ --source include/have_innodb.inc +--disable_query_log +call mtr.add_suppression("InnoDB: Transaction was aborted due to "); +--enable_query_log + # # Bug #41453: Assertion `m_status == DA_ERROR' failed in # Diagnostics_area::sql_errno diff --git a/mysql-test/suite/innodb/t/innodb_trx_weight.test b/mysql-test/suite/innodb/t/innodb_trx_weight.test index 819f05f331e..a8c29a1a8a8 100644 --- a/mysql-test/suite/innodb/t/innodb_trx_weight.test +++ b/mysql-test/suite/innodb/t/innodb_trx_weight.test @@ -6,6 +6,10 @@ # be heavier than ones that had not. # +--disable_query_log +call mtr.add_suppression("InnoDB: Transaction was aborted due to "); +--enable_query_log + -- source include/have_innodb.inc SET default_storage_engine=InnoDB; diff --git a/mysql-test/suite/innodb/t/insert-before-delete.test b/mysql-test/suite/innodb/t/insert-before-delete.test index 2547b94e5ea..1cadbf7c0c6 100644 --- a/mysql-test/suite/innodb/t/insert-before-delete.test +++ b/mysql-test/suite/innodb/t/insert-before-delete.test @@ -3,6 +3,10 @@ --source include/have_debug_sync.inc --source include/count_sessions.inc +--disable_query_log +call mtr.add_suppression("InnoDB: Transaction was aborted due to "); +--enable_query_log + --connect (pause_purge,localhost,root) START TRANSACTION WITH CONSISTENT SNAPSHOT; diff --git a/mysql-test/suite/innodb/t/lock_delete_updated.test b/mysql-test/suite/innodb/t/lock_delete_updated.test index 1f7b13144e4..8697ff595ab 100644 --- a/mysql-test/suite/innodb/t/lock_delete_updated.test +++ b/mysql-test/suite/innodb/t/lock_delete_updated.test @@ -3,6 +3,10 @@ --source include/have_debug.inc --source include/have_debug_sync.inc +--disable_query_log +call mtr.add_suppression("InnoDB: Transaction was aborted due to "); +--enable_query_log + CREATE TABLE t(a INT PRIMARY KEY) ENGINE=InnoDB; INSERT INTO t VALUES (3); diff --git a/mysql-test/suite/innodb/t/lock_isolation.test b/mysql-test/suite/innodb/t/lock_isolation.test index c9658c0a362..bac034a50e4 100644 --- a/mysql-test/suite/innodb/t/lock_isolation.test +++ b/mysql-test/suite/innodb/t/lock_isolation.test @@ -1,5 +1,9 @@ --source include/have_innodb.inc +--disable_query_log +call mtr.add_suppression("InnoDB: Transaction was aborted due to "); +--enable_query_log + --echo # --echo # MDEV-26642 Weird SELECT view when a record is --echo # modified to the same value by two transactions diff --git a/mysql-test/suite/innodb/t/lock_memory_debug.test b/mysql-test/suite/innodb/t/lock_memory_debug.test index 51e0e8fd57e..588356f7fa4 100644 --- a/mysql-test/suite/innodb/t/lock_memory_debug.test +++ b/mysql-test/suite/innodb/t/lock_memory_debug.test @@ -6,6 +6,9 @@ --echo # call mtr.add_suppression("\\[Warning\\] InnoDB: Over 67 percent of the buffer pool"); +--disable_query_log +call mtr.add_suppression("InnoDB: Transaction was aborted due to "); +--enable_query_log CREATE TABLE t1 (col1 INT) ENGINE=InnoDB; INSERT INTO t1 VALUES (1),(2),(3),(4),(5); diff --git a/mysql-test/suite/innodb/t/mdev-14846.test b/mysql-test/suite/innodb/t/mdev-14846.test index e9698cc0594..75b634a0908 100644 --- a/mysql-test/suite/innodb/t/mdev-14846.test +++ b/mysql-test/suite/innodb/t/mdev-14846.test @@ -4,6 +4,10 @@ --source include/innodb_stable_estimates.inc +--disable_query_log +call mtr.add_suppression("InnoDB: Transaction was aborted due to "); +--enable_query_log + CREATE TABLE t1 ( pk INT, f1 VARCHAR(10) NOT NULL, diff --git a/mysql-test/suite/innodb/t/row_lock.test b/mysql-test/suite/innodb/t/row_lock.test index 361bce461f7..2598189d0e2 100644 --- a/mysql-test/suite/innodb/t/row_lock.test +++ b/mysql-test/suite/innodb/t/row_lock.test @@ -4,6 +4,10 @@ # concurrent CREATE OR REPLACE and transactional UPDATE # +--disable_query_log +call mtr.add_suppression("InnoDB: Transaction was aborted due to "); +--enable_query_log + --source include/have_innodb.inc CREATE TABLE t1 (a INT, b INT) ENGINE=InnoDB; diff --git a/mysql-test/suite/innodb/t/stat_tables.test b/mysql-test/suite/innodb/t/stat_tables.test index 79bc107d0ea..d606ad27709 100644 --- a/mysql-test/suite/innodb/t/stat_tables.test +++ b/mysql-test/suite/innodb/t/stat_tables.test @@ -1,5 +1,9 @@ source include/have_innodb.inc; +--disable_query_log +call mtr.add_suppression("InnoDB: Transaction was aborted due to "); +--enable_query_log + # # MDEV-20354 All but last insert ignored in InnoDB tables when table locked # diff --git a/mysql-test/suite/innodb_fts/r/savepoint.result b/mysql-test/suite/innodb_fts/r/savepoint.result index 1abfc961d0a..b2d53c36fbe 100644 --- a/mysql-test/suite/innodb_fts/r/savepoint.result +++ b/mysql-test/suite/innodb_fts/r/savepoint.result @@ -249,9 +249,33 @@ id title 7 mysql TRUNCATE TABLE articles; INSERT INTO articles(id, title) VALUES(1, 'mysql'); +CREATE TABLE t(a INT PRIMARY KEY) ENGINE=InnoDB; BEGIN; +INSERT INTO t SET a=1; +SAVEPOINT t; +INSERT INTO articles(id, title) VALUES(2, 'mysql'); +SELECT * FROM articles WHERE MATCH(title) AGAINST('mysql'); +id title +1 mysql +ROLLBACK TO SAVEPOINT t; +SELECT * FROM articles WHERE MATCH(title) AGAINST('mysql'); +id title +1 mysql +SELECT * FROM t; +a +1 +COMMIT; +SELECT * FROM articles WHERE MATCH(title) AGAINST('mysql'); +id title +1 mysql +BEGIN; +INSERT INTO t SET a=2; INSERT INTO articles(id, title) VALUES(2, 'mysql'); ROLLBACK; +SELECT * FROM t; +a +1 +DROP TABLE t; INSERT INTO articles(id, title) VALUES(3, 'mysql'); SELECT * FROM articles WHERE MATCH(title) AGAINST('mysql'); id title diff --git a/mysql-test/suite/innodb_fts/t/savepoint.test b/mysql-test/suite/innodb_fts/t/savepoint.test index 09ccb383bb9..ae83c23d20c 100644 --- a/mysql-test/suite/innodb_fts/t/savepoint.test +++ b/mysql-test/suite/innodb_fts/t/savepoint.test @@ -366,12 +366,28 @@ TRUNCATE TABLE articles; INSERT INTO articles(id, title) VALUES(1, 'mysql'); +CREATE TABLE t(a INT PRIMARY KEY) ENGINE=InnoDB; BEGIN; +INSERT INTO t SET a=1; +SAVEPOINT t; +INSERT INTO articles(id, title) VALUES(2, 'mysql'); +SELECT * FROM articles WHERE MATCH(title) AGAINST('mysql'); +ROLLBACK TO SAVEPOINT t; +SELECT * FROM articles WHERE MATCH(title) AGAINST('mysql'); +SELECT * FROM t; +COMMIT; +SELECT * FROM articles WHERE MATCH(title) AGAINST('mysql'); + +BEGIN; +INSERT INTO t SET a=2; INSERT INTO articles(id, title) VALUES(2, 'mysql'); ROLLBACK; +SELECT * FROM t; +DROP TABLE t; + INSERT INTO articles(id, title) VALUES(3, 'mysql'); SELECT * FROM articles WHERE MATCH(title) AGAINST('mysql'); diff --git a/mysql-test/suite/innodb_zip/r/wl5522_debug_zip.result b/mysql-test/suite/innodb_zip/r/wl5522_debug_zip.result index 574ba0b6c2e..93c68fba74a 100644 --- a/mysql-test/suite/innodb_zip/r/wl5522_debug_zip.result +++ b/mysql-test/suite/innodb_zip/r/wl5522_debug_zip.result @@ -91,7 +91,7 @@ restore: t1 .ibd and .cfg files SET SESSION debug_dbug=@saved_debug_dbug; SET SESSION debug_dbug="+d,ib_import_open_tablespace_failure"; ALTER TABLE t1 IMPORT TABLESPACE; -ERROR HY000: Got error 42 'Tablespace not found' from ./test/t1.ibd +ERROR HY000: Got error 41 'Tablespace not found' from ./test/t1.ibd SET SESSION debug_dbug=@saved_debug_dbug; restore: t1 .ibd and .cfg files SET SESSION debug_dbug="+d,ib_import_check_bitmap_failure"; diff --git a/mysql-test/suite/multi_source/gtid_ignore_duplicates.test b/mysql-test/suite/multi_source/gtid_ignore_duplicates.test index cbc06920b41..634ff002cbc 100644 --- a/mysql-test/suite/multi_source/gtid_ignore_duplicates.test +++ b/mysql-test/suite/multi_source/gtid_ignore_duplicates.test @@ -2,6 +2,9 @@ --source include/have_innodb.inc --source include/have_debug.inc +--disable_query_log +call mtr.add_suppression("InnoDB: Transaction was aborted due to "); +--enable_query_log --echo *** Test all-to-all replication with --gtid-ignore-duplicates *** diff --git a/mysql-test/suite/plugins/r/server_audit_pwd_mask.result b/mysql-test/suite/plugins/r/server_audit_pwd_mask.result index ce90230f1ea..8068bbcf4d8 100644 --- a/mysql-test/suite/plugins/r/server_audit_pwd_mask.result +++ b/mysql-test/suite/plugins/r/server_audit_pwd_mask.result @@ -30,4 +30,13 @@ DROP USER u2; set global server_audit_logging=off; UNINSTALL PLUGIN ed25519; UNINSTALL PLUGIN server_audit; +# +# MDEV-35604: SIGSEGV in filter_query_type | log_statement_ex / auditing +# +INSTALL PLUGIN server_audit SONAME 'server_audit'; +SET GLOBAL server_audit_logging=ON; +SET STATEMENT max_error_count=1 SELECT 1; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'SELECT 1' at line 1 +SET GLOBAL server_audit_logging=OFF; +UNINSTALL SONAME 'server_audit'; # end of 10.5 tests diff --git a/mysql-test/suite/plugins/t/server_audit_pwd_mask.test b/mysql-test/suite/plugins/t/server_audit_pwd_mask.test index b393e22d11e..fe660795ab3 100644 --- a/mysql-test/suite/plugins/t/server_audit_pwd_mask.test +++ b/mysql-test/suite/plugins/t/server_audit_pwd_mask.test @@ -56,4 +56,20 @@ UNINSTALL PLUGIN ed25519; UNINSTALL PLUGIN server_audit; --enable_warnings +--echo # +--echo # MDEV-35604: SIGSEGV in filter_query_type | log_statement_ex / auditing +--echo # + +INSTALL PLUGIN server_audit SONAME 'server_audit'; +SET GLOBAL server_audit_logging=ON; + +--ERROR ER_PARSE_ERROR +SET STATEMENT max_error_count=1 SELECT 1; + +# Cleanup +SET GLOBAL server_audit_logging=OFF; +--disable_warnings +UNINSTALL SONAME 'server_audit'; +--enable_warnings + --echo # end of 10.5 tests diff --git a/mysql-test/suite/rpl/r/rpl_mark_optimize_tbl_ddl.result b/mysql-test/suite/rpl/r/rpl_mark_optimize_tbl_ddl.result index 09edd28827b..6296196104b 100644 --- a/mysql-test/suite/rpl/r/rpl_mark_optimize_tbl_ddl.result +++ b/mysql-test/suite/rpl/r/rpl_mark_optimize_tbl_ddl.result @@ -36,9 +36,9 @@ Table Op Msg_type Msg_text test.t1 analyze status Engine-independent statistics collected test.t1 analyze status OK FLUSH LOGS; -FOUND 1 /GTID 0-1-8 ddl/ in mysqlbinlog.out FOUND 1 /GTID 0-1-9 ddl/ in mysqlbinlog.out FOUND 1 /GTID 0-1-10 ddl/ in mysqlbinlog.out +FOUND 1 /GTID 0-1-11 ddl/ in mysqlbinlog.out # # Clean up # @@ -63,9 +63,9 @@ ALTER TABLE t1 REPAIR PARTITION p0; Table Op Msg_type Msg_text test.t1 repair status OK FLUSH LOGS; -FOUND 1 /GTID 0-1-14 ddl/ in mysqlbinlog.out FOUND 1 /GTID 0-1-15 ddl/ in mysqlbinlog.out FOUND 1 /GTID 0-1-16 ddl/ in mysqlbinlog.out +FOUND 1 /GTID 0-1-17 ddl/ in mysqlbinlog.out # # Clean up # diff --git a/mysql-test/suite/rpl/t/rpl_mark_optimize_tbl_ddl.test b/mysql-test/suite/rpl/t/rpl_mark_optimize_tbl_ddl.test index 6d66e3fd088..4c9b57e4bda 100644 --- a/mysql-test/suite/rpl/t/rpl_mark_optimize_tbl_ddl.test +++ b/mysql-test/suite/rpl/t/rpl_mark_optimize_tbl_ddl.test @@ -22,6 +22,10 @@ --let $rpl_topology=1->2 --source include/rpl_init.inc +--disable_query_log +call mtr.add_suppression("InnoDB: Transaction was aborted due to "); +--enable_query_log + --connection server_1 FLUSH TABLES; ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB; diff --git a/mysql-test/suite/rpl/t/rpl_parallel_deadlock_victim.test b/mysql-test/suite/rpl/t/rpl_parallel_deadlock_victim.test index ab634d2953e..c1876a43dca 100644 --- a/mysql-test/suite/rpl/t/rpl_parallel_deadlock_victim.test +++ b/mysql-test/suite/rpl/t/rpl_parallel_deadlock_victim.test @@ -2,6 +2,9 @@ --source include/have_debug.inc --source include/master-slave.inc +--disable_query_log +call mtr.add_suppression("InnoDB: Transaction was aborted due to "); +--enable_query_log --echo MDEV-31655: Parallel replication deadlock victim preference code erroneously removed # The problem was that InnoDB would choose the wrong deadlock victim. diff --git a/mysql-test/suite/rpl/t/rpl_parallel_deadlock_victim2.test b/mysql-test/suite/rpl/t/rpl_parallel_deadlock_victim2.test index 522cec18bbc..68d5ad6a481 100644 --- a/mysql-test/suite/rpl/t/rpl_parallel_deadlock_victim2.test +++ b/mysql-test/suite/rpl/t/rpl_parallel_deadlock_victim2.test @@ -3,6 +3,10 @@ --source include/have_debug.inc --source include/have_binlog_format_statement.inc +--disable_query_log +call mtr.add_suppression("InnoDB: Transaction was aborted due to "); +--enable_query_log + --connection master ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB; CREATE TABLE t1(a INT) ENGINE=INNODB; diff --git a/mysql-test/suite/rpl/t/rpl_parallel_innodb_lock_conflict.test b/mysql-test/suite/rpl/t/rpl_parallel_innodb_lock_conflict.test index 90304937445..532eb58571c 100644 --- a/mysql-test/suite/rpl/t/rpl_parallel_innodb_lock_conflict.test +++ b/mysql-test/suite/rpl/t/rpl_parallel_innodb_lock_conflict.test @@ -5,6 +5,10 @@ --source include/have_debug_sync.inc --source include/master-slave.inc +--disable_query_log +call mtr.add_suppression("InnoDB: Transaction was aborted due to "); +--enable_query_log + --connection server_2 SET sql_log_bin=0; CALL mtr.add_suppression("Commit failed due to failure of an earlier commit on which this one depends"); diff --git a/mysql-test/suite/rpl/t/rpl_parallel_optimistic.test b/mysql-test/suite/rpl/t/rpl_parallel_optimistic.test index 09da8c2df15..988221d4c18 100644 --- a/mysql-test/suite/rpl/t/rpl_parallel_optimistic.test +++ b/mysql-test/suite/rpl/t/rpl_parallel_optimistic.test @@ -7,6 +7,9 @@ call mtr.add_suppression("Deadlock found when trying to get lock; try restarting transaction"); call mtr.add_suppression("Can't find record in 't1'"); call mtr.add_suppression("Can't find record in 't2'"); +--disable_query_log +call mtr.add_suppression("InnoDB: Transaction was aborted due to "); +--enable_query_log --connection server_1 ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB; diff --git a/mysql-test/suite/rpl/t/rpl_parallel_optimistic_nobinlog.test b/mysql-test/suite/rpl/t/rpl_parallel_optimistic_nobinlog.test index ee0de499edf..0b7a76aa78b 100644 --- a/mysql-test/suite/rpl/t/rpl_parallel_optimistic_nobinlog.test +++ b/mysql-test/suite/rpl/t/rpl_parallel_optimistic_nobinlog.test @@ -3,6 +3,10 @@ --let $rpl_topology=1->2 --source include/rpl_init.inc +--disable_query_log +call mtr.add_suppression("InnoDB: Transaction was aborted due to "); +--enable_query_log + --connection server_1 ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB; CREATE TABLE t1 (a int PRIMARY KEY, b INT) ENGINE=InnoDB; diff --git a/mysql-test/suite/rpl/t/rpl_parallel_xa_same_xid.test b/mysql-test/suite/rpl/t/rpl_parallel_xa_same_xid.test index 888dd2f177b..17c404adef8 100644 --- a/mysql-test/suite/rpl/t/rpl_parallel_xa_same_xid.test +++ b/mysql-test/suite/rpl/t/rpl_parallel_xa_same_xid.test @@ -9,6 +9,10 @@ --source include/have_perfschema.inc --source include/master-slave.inc +--disable_query_log +call mtr.add_suppression("InnoDB: Transaction was aborted due to "); +--enable_query_log + --let $xid_num = 19 --let $repeat = 17 --let $workers = 7 diff --git a/mysql-test/suite/rpl/t/rpl_temporary_error2.test b/mysql-test/suite/rpl/t/rpl_temporary_error2.test index 3537499d562..23a84a02760 100644 --- a/mysql-test/suite/rpl/t/rpl_temporary_error2.test +++ b/mysql-test/suite/rpl/t/rpl_temporary_error2.test @@ -2,6 +2,9 @@ --source include/master-slave.inc call mtr.add_suppression("Deadlock found when trying to get lock; try restarting transaction"); +--disable_query_log +call mtr.add_suppression("InnoDB: Transaction was aborted due to "); +--enable_query_log --echo *** Provoke a deadlock on the slave, check that transaction retry succeeds. *** --connection master diff --git a/mysql-test/suite/versioning/t/update.test b/mysql-test/suite/versioning/t/update.test index e7a57b393ad..e3b07bfe47a 100644 --- a/mysql-test/suite/versioning/t/update.test +++ b/mysql-test/suite/versioning/t/update.test @@ -1,6 +1,10 @@ source suite/versioning/engines.inc; source suite/versioning/common.inc; +--disable_query_log +call mtr.add_suppression("InnoDB: Transaction was aborted due to "); +--enable_query_log + replace_result $sys_datatype_expl SYS_DATATYPE; eval create table t1( x int unsigned, diff --git a/mysys/array.c b/mysys/array.c index d1a95b45746..bef1ebf85c3 100644 --- a/mysys/array.c +++ b/mysys/array.c @@ -251,7 +251,7 @@ my_bool allocate_dynamic(DYNAMIC_ARRAY *array, size_t max_elements) if (!(new_ptr= (uchar *) my_malloc(array->m_psi_key, size * array->size_of_element, MYF(array->malloc_flags | MY_WME)))) - DBUG_RETURN(0); + DBUG_RETURN(TRUE); memcpy(new_ptr, array->buffer, array->elements * array->size_of_element); array->malloc_flags&= ~MY_INIT_BUFFER_USED; diff --git a/mysys/my_create.c b/mysys/my_create.c index 6fb817da8df..32cc73a53c4 100644 --- a/mysys/my_create.c +++ b/mysys/my_create.c @@ -33,12 +33,12 @@ */ -File my_create(const char *FileName, int CreateFlags, int access_flags, +File my_create(const char *FileName, mode_t CreateFlags, int access_flags, myf MyFlags) { int fd; DBUG_ENTER("my_create"); - DBUG_PRINT("my",("Name: '%s' CreateFlags: %d AccessFlags: %d MyFlags: %lu", + DBUG_PRINT("my",("Name: '%s' CreateFlags: %u AccessFlags: %d MyFlags: %lu", FileName, CreateFlags, access_flags, MyFlags)); #if defined(_WIN32) fd= my_win_open(FileName, access_flags | O_CREAT); diff --git a/mysys/my_init.c b/mysys/my_init.c index 04c36770289..5aa0c780131 100644 --- a/mysys/my_init.c +++ b/mysys/my_init.c @@ -54,7 +54,7 @@ size_t my_system_page_size= 8192; /* Default if no sysconf() */ ulonglong my_thread_stack_size= (sizeof(void*) <= 4)? 65536: ((256-16)*1024); -static ulong atoi_octal(const char *str) +static mode_t atoi_octal(const char *str) { long int tmp; while (*str && my_isspace(&my_charset_latin1, *str)) @@ -62,7 +62,7 @@ static ulong atoi_octal(const char *str) str2int(str, (*str == '0' ? 8 : 10), /* Octalt or decimalt */ 0, INT_MAX, &tmp); - return (ulong) tmp; + return (mode_t) tmp; } MYSQL_FILE *mysql_stdin= NULL; @@ -155,10 +155,10 @@ my_bool my_init(void) /* Default creation of new files */ if ((str= getenv("UMASK")) != 0) - my_umask= (int) (atoi_octal(str) | 0600); + my_umask= atoi_octal(str) | 0600; /* Default creation of new dir's */ if ((str= getenv("UMASK_DIR")) != 0) - my_umask_dir= (int) (atoi_octal(str) | 0700); + my_umask_dir= atoi_octal(str) | 0700; init_glob_errs(); diff --git a/mysys/my_open.c b/mysys/my_open.c index 4d26a7b250e..182bb149277 100644 --- a/mysys/my_open.c +++ b/mysys/my_open.c @@ -20,7 +20,7 @@ #include "my_atomic.h" CREATE_NOSYMLINK_FUNCTION( - open_nosymlinks(const char *pathname, int flags, int mode), + open_nosymlinks(const char *pathname, int flags, mode_t mode), openat(dfd, filename, O_NOFOLLOW | flags, mode), open(pathname, O_NOFOLLOW | flags, mode) ); diff --git a/mysys/my_static.c b/mysys/my_static.c index d0f20a5cc9c..74522d35829 100644 --- a/mysys/my_static.c +++ b/mysys/my_static.c @@ -64,7 +64,7 @@ char curr_dir[FN_REFLEN]= {0}, home_dir_buff[FN_REFLEN]= {0}; ulong my_stream_opened=0,my_tmp_file_created=0; ulong my_file_total_opened= 0; -int my_umask=0664, my_umask_dir=0777; +mode_t my_umask=0664, my_umask_dir=0777; #ifdef _WIN32 SECURITY_ATTRIBUTES my_dir_security_attributes= {sizeof(SECURITY_ATTRIBUTES),NULL,FALSE}; #endif diff --git a/mysys/my_symlink2.c b/mysys/my_symlink2.c index 0b580ecd32f..d9b31e3dfaf 100644 --- a/mysys/my_symlink2.c +++ b/mysys/my_symlink2.c @@ -26,7 +26,7 @@ #include File my_create_with_symlink(const char *linkname, const char *filename, - int createflags, int access_flags, myf MyFlags) + mode_t createflags, int access_flags, myf MyFlags) { File file; int tmp_errno; diff --git a/mysys/thr_alarm.c b/mysys/thr_alarm.c index 6333ac98fd5..7ebcfd2dac8 100644 --- a/mysys/thr_alarm.c +++ b/mysys/thr_alarm.c @@ -566,8 +566,7 @@ static void *alarm_handler(void *arg __attribute__((unused))) alarm_thread_running= 0; mysql_cond_signal(&COND_alarm); mysql_mutex_unlock(&LOCK_alarm); - pthread_exit(0); - return 0; /* Impossible */ + return 0; } #endif /* USE_ALARM_THREAD */ #endif diff --git a/mysys/thr_timer.c b/mysys/thr_timer.c index 00fc74cdf77..6e9e5a421e0 100644 --- a/mysys/thr_timer.c +++ b/mysys/thr_timer.c @@ -330,8 +330,7 @@ static void *timer_handler(void *arg __attribute__((unused))) } mysql_mutex_unlock(&LOCK_timer); my_thread_end(); - pthread_exit(0); - return 0; /* Impossible */ + return 0; } diff --git a/plugin/feedback/sender_thread.cc b/plugin/feedback/sender_thread.cc index 899157b0ae9..8020ae2a9e8 100644 --- a/plugin/feedback/sender_thread.cc +++ b/plugin/feedback/sender_thread.cc @@ -290,7 +290,6 @@ pthread_handler_t background_thread(void *arg __attribute__((unused))) } my_thread_end(); - pthread_exit(0); return 0; } diff --git a/plugin/handler_socket/CMakeLists.txt b/plugin/handler_socket/CMakeLists.txt index 5a1925b40e0..1510dc839a4 100644 --- a/plugin/handler_socket/CMakeLists.txt +++ b/plugin/handler_socket/CMakeLists.txt @@ -6,8 +6,6 @@ IF(WIN32 OR WITHOUT_SERVER) RETURN() ENDIF() -MY_CHECK_AND_SET_COMPILER_FLAG("-Wno-deprecated-declarations") - INCLUDE_DIRECTORIES(libhsclient) # Handlersocket client library. We do not distribute it, diff --git a/plugin/handler_socket/handlersocket/database.hpp b/plugin/handler_socket/handlersocket/database.hpp index ed5d00800d9..9e2aadf7380 100644 --- a/plugin/handler_socket/handlersocket/database.hpp +++ b/plugin/handler_socket/handlersocket/database.hpp @@ -9,6 +9,11 @@ #ifndef DENA_DATABASE_HPP #define DENA_DATABASE_HPP +#ifdef __GNUC__ +/* auto_ptr is deprecated */ +# pragma GCC diagnostic ignored "-Wdeprecated-declarations" +#endif + #include #include #include diff --git a/plugin/handler_socket/libhsclient/hstcpcli.hpp b/plugin/handler_socket/libhsclient/hstcpcli.hpp index fa0d4db1742..d078bdfd533 100644 --- a/plugin/handler_socket/libhsclient/hstcpcli.hpp +++ b/plugin/handler_socket/libhsclient/hstcpcli.hpp @@ -19,6 +19,11 @@ #include "string_ref.hpp" #include "string_buffer.hpp" +#ifdef __GNUC__ +/* auto_ptr is deprecated */ +# pragma GCC diagnostic ignored "-Wdeprecated-declarations" +#endif + namespace dena { struct hstcpcli_filter { diff --git a/plugin/server_audit/server_audit.c b/plugin/server_audit/server_audit.c index af4de984fe1..43249df744d 100644 --- a/plugin/server_audit/server_audit.c +++ b/plugin/server_audit/server_audit.c @@ -1782,6 +1782,8 @@ static int filter_query_type(const char *query, struct sa_keyword *kwd) char fword[MAX_KEYWORD + 1], nword[MAX_KEYWORD + 1]; int len, nlen= 0; const struct sa_keyword *l_keywords; + if (!query) + return SQLCOM_NOTHING; while (*query && (is_space(*query) || *query == '(' || *query == '/')) { diff --git a/scripts/wsrep_sst_common.sh b/scripts/wsrep_sst_common.sh index b4eace044be..efe321360a1 100644 --- a/scripts/wsrep_sst_common.sh +++ b/scripts/wsrep_sst_common.sh @@ -1117,7 +1117,7 @@ get_openssl() { # If the OPENSSL_BINARY variable is already defined, just return: if [ -n "${OPENSSL_BINARY+x}" ]; then - return + return 0 fi # Let's look for openssl: OPENSSL_BINARY=$(commandex 'openssl') @@ -1556,7 +1556,7 @@ cleanup_pid() fi done elif ps -p $pid >/dev/null 2>&1; then - wsrep_log_warning "Unable to kill PID=$pid ($pid_file)" + wsrep_log_warning "Unable to kill PID=$pid${pid_file:+ ($pid_file)}" return 1 fi fi @@ -1863,6 +1863,8 @@ create_dirs() cd "$OLD_PWD" [ $simplify -ne 0 -a "$ar_log_dir" = "$DATA_DIR" ] && ar_log_dir="" fi + + return 0 } wait_previous_sst() diff --git a/scripts/wsrep_sst_mariabackup.sh b/scripts/wsrep_sst_mariabackup.sh index e899337cb66..46d8db30506 100644 --- a/scripts/wsrep_sst_mariabackup.sh +++ b/scripts/wsrep_sst_mariabackup.sh @@ -439,17 +439,30 @@ get_transfer() get_footprint() { cd "$DATA_DIR" - local payload_data=$(find $findopt . \ - -regex '.*undo[0-9]+$\|.*\.ibd$\|.*\.MYI$\|.*\.MYD$\|.*ibdata1$' \ - -type f -print0 | du --files0-from=- --block-size=1 -c -s | \ - awk 'END { print $1 }') + local payload_data + if [ "$OS" = 'Linux' ]; then + payload_data=$(find $findopt . \ + -regex '.*undo[0-9]+$\|.*\.ibd$\|.*\.MYI$\|.*\.MYD$\|.*ibdata1$' \ + -type f -print0 | du --files0-from=- --bytes -c -s | \ + awk 'END { print $1 }') + else + payload_data=$(find $findopt . \ + -regex '.*undo[0-9]+$|.*\.ibd$|.*\.MYI$\.*\.MYD$|.*ibdata1$' \ + -type f -print0 | xargs -0 stat -f '%z' | \ + awk '{ sum += $1 } END { print sum }') + fi local payload_undo=0 if [ -n "$ib_undo_dir" -a "$ib_undo_dir" != '.' -a \ "$ib_undo_dir" != "$DATA_DIR" -a -d "$ib_undo_dir" ] then cd "$ib_undo_dir" - payload_undo=$(find . -regex '.*undo[0-9]+$' -type f -print0 | \ - du --files0-from=- --block-size=1 -c -s | awk 'END { print $1 }') + if [ "$OS" = 'Linux' ]; then + payload_undo=$(find . -regex '.*undo[0-9]+$' -type f -print0 | \ + du --files0-from=- --bytes -c -s | awk 'END { print $1 }') + else + payload_undo=$(find . -regex '.*undo[0-9]+$' -type f -print0 | \ + xargs -0 stat -f '%z' | awk '{ sum += $1 } END { print sum }') + fi fi cd "$OLD_PWD" @@ -676,24 +689,25 @@ cleanup_at_exit() [ "$(pwd)" != "$OLD_PWD" ] && cd "$OLD_PWD" - if [ $estatus -ne 0 ]; then - wsrep_log_error "Removing $MAGIC_FILE file due to signal" + if [ "$WSREP_SST_OPT_ROLE" = 'donor' -o $estatus -ne 0 ]; then + if [ $estatus -ne 0 ]; then + wsrep_log_error "Removing $MAGIC_FILE file due to signal" + fi [ -f "$MAGIC_FILE" ] && rm -f "$MAGIC_FILE" || : [ -f "$DONOR_MAGIC_FILE" ] && rm -f "$DONOR_MAGIC_FILE" || : + [ -f "$DATA/$IST_FILE" ] && rm -f "$DATA/$IST_FILE" || : fi if [ "$WSREP_SST_OPT_ROLE" = 'joiner' ]; then if [ -n "$BACKUP_PID" ]; then if ps -p $BACKUP_PID >/dev/null 2>&1; then wsrep_log_error \ - "mariadb-backup process is still running. Killing..." - cleanup_pid $CHECK_PID + "SST streaming process is still running. Killing..." + cleanup_pid $BACKUP_PID fi fi wsrep_log_info "Removing the sst_in_progress file" wsrep_cleanup_progress_file - else - [ -f "$DATA/$IST_FILE" ] && rm -f "$DATA/$IST_FILE" || : fi if [ -n "$progress" -a -p "$progress" ]; then @@ -1340,6 +1354,7 @@ else # joiner [ -f "$DATA/xtrabackup_checkpoints" ] && rm -f "$DATA/xtrabackup_checkpoints" [ -f "$DATA/xtrabackup_info" ] && rm -f "$DATA/xtrabackup_info" [ -f "$DATA/xtrabackup_slave_info" ] && rm -f "$DATA/xtrabackup_slave_info" + [ -f "$DATA/xtrabackup_binlog_info" ] && rm -f "$DATA/xtrabackup_binlog_info" [ -f "$DATA/xtrabackup_binlog_pos_innodb" ] && rm -f "$DATA/xtrabackup_binlog_pos_innodb" TDATA="$DATA" diff --git a/sql/handler.cc b/sql/handler.cc index 66ab473891a..82fec6142a6 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -4678,6 +4678,12 @@ void handler::print_error(int error, myf errflag) case HA_ERR_PARTITION_LIST: my_error(ER_VERS_NOT_ALLOWED, errflag, table->s->db.str, table->s->table_name.str); DBUG_VOID_RETURN; + case HA_ERR_ROLLBACK: + /* Crash if we run with --debug-assert-on-error */ + DBUG_ASSERT(!debug_assert_if_crashed_table); + SET_FATAL_ERROR; + textno= ER_ROLLBACK_ONLY; + break; default: { /* The error was "unknown" to this function. @@ -4712,7 +4718,7 @@ void handler::print_error(int error, myf errflag) /* Ensure this becomes a true error */ errflag&= ~(ME_WARNING | ME_NOTE); if ((debug_assert_if_crashed_table || - global_system_variables.log_warnings > 1)) + global_system_variables.log_warnings > 1)) { /* Log error to log before we crash or if extended warnings are requested diff --git a/sql/log.cc b/sql/log.cc index 3f6e658d89d..c5d5998f4df 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -1454,7 +1454,7 @@ bool LOGGER::slow_log_print(THD *thd, const char *query, size_t query_length, user_host_buff); DBUG_ASSERT(thd->start_utime); - DBUG_ASSERT(thd->start_time); + DBUG_ASSERT(thd->start_time || thd->start_time_sec_part); query_utime= (current_utime - thd->start_utime); lock_utime= (thd->utime_after_lock - thd->start_utime); my_hrtime_t current_time= { hrtime_from_time(thd->start_time) + diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 3ce27cb367a..a910602018b 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -3212,7 +3212,6 @@ pthread_handler_t signal_hand(void *) sigset_t set; int sig; my_thread_init(); // Init new thread - DBUG_ENTER("signal_hand"); signal_thread_in_use= 1; /* @@ -3278,7 +3277,6 @@ pthread_handler_t signal_hand(void *) /* switch to the old log message processing */ logger.set_handlers(global_system_variables.sql_log_slow ? LOG_FILE:LOG_NONE, opt_log ? LOG_FILE:LOG_NONE); - DBUG_PRINT("info",("Got signal: %d abort_loop: %d",sig,abort_loop)); break_connect_loop(); DBUG_ASSERT(abort_loop); @@ -3314,12 +3312,9 @@ pthread_handler_t signal_hand(void *) break; /* purecov: tested */ } } - DBUG_PRINT("quit", ("signal_handler: calling my_thread_end()")); my_thread_end(); - DBUG_LEAVE; // Must match DBUG_ENTER() signal_thread_in_use= 0; - pthread_exit(0); // Safety - return(0); /* purecov: deadcode */ + return nullptr; } static void check_data_home(const char *path) diff --git a/sql/signal_handler.cc b/sql/signal_handler.cc index 96020c68b2b..b1c570ade03 100644 --- a/sql/signal_handler.cc +++ b/sql/signal_handler.cc @@ -76,12 +76,32 @@ static inline void output_core_info() if ((fd= open("/proc/self/limits", O_RDONLY)) >= 0) #endif { - my_safe_printf_stderr("Resource Limits:\n"); - while ((len= read(fd, (uchar*)buff, sizeof(buff))) > 0) - { - my_write_stderr(buff, len); - } + char *endline= buff; + ssize_t remain_len= len= read(fd, buff, sizeof(buff)); close(fd); + my_safe_printf_stderr("Resource Limits (excludes unlimited resources):\n"); + /* first line, header */ + endline= (char *) memchr(buff, '\n', remain_len); + if (endline) + { + endline++; + remain_len= buff + len - endline; + my_safe_printf_stderr("%.*s", (int) (endline - buff), buff); + + while (remain_len > 27) + { + char *newendline= (char *) memchr(endline, '\n', remain_len); + if (!newendline) + break; + *newendline= '\0'; + newendline++; + if (endline[26] != 'u') /* skip unlimited limits */ + my_safe_printf_stderr("%s\n", endline); + + remain_len-= newendline - endline; + endline= newendline; + } + } } #ifdef __linux__ if ((fd= open("/proc/sys/kernel/core_pattern", O_RDONLY)) >= 0) @@ -144,7 +164,6 @@ extern "C" sig_handler handle_fatal_signal(int sig) We will try and print the query at the end of the signal handler, in case we're wrong. */ - bool print_invalid_query_pointer= false; #endif if (segfaulted) @@ -174,57 +193,19 @@ extern "C" sig_handler handle_fatal_signal(int sig) goto end; } - my_safe_printf_stderr("[ERROR] mysqld got " SIGNAL_FMT " ;\n",sig); + my_safe_printf_stderr("[ERROR] %s got " SIGNAL_FMT " ;\n", my_progname, sig); my_safe_printf_stderr("%s", "Sorry, we probably made a mistake, and this is a bug.\n\n" "Your assistance in bug reporting will enable us to fix this for the next release.\n" - "To report this bug, see https://mariadb.com/kb/en/reporting-bugs\n\n"); - - my_safe_printf_stderr("%s", - "We will try our best to scrape up some info that will hopefully help\n" - "diagnose the problem, but since we have already crashed, \n" - "something is definitely wrong and this may fail.\n\n"); + "To report this bug, see https://mariadb.com/kb/en/reporting-bugs about how to report\n" + "a bug on https://jira.mariadb.org/.\n\n" + "Please include the information from the server start above, to the end of the\n" + "information below.\n\n"); set_server_version(server_version, sizeof(server_version)); - my_safe_printf_stderr("Server version: %s source revision: %s\n", - server_version, SOURCE_REVISION); - - if (dflt_key_cache) - my_safe_printf_stderr("key_buffer_size=%zu\n", - dflt_key_cache->key_cache_mem_size); - - my_safe_printf_stderr("read_buffer_size=%lu\n", - global_system_variables.read_buff_size); - - my_safe_printf_stderr("max_used_connections=%lu\n", - max_used_connections); - - if (thread_scheduler) - my_safe_printf_stderr("max_threads=%lu\n", - thread_scheduler->max_threads + - extra_max_connections); - - my_safe_printf_stderr("thread_count=%u\n", THD_count::value()); - - if (dflt_key_cache && thread_scheduler) - { - size_t used_mem= - (dflt_key_cache->key_cache_mem_size + - (global_system_variables.read_buff_size + - (size_t) global_system_variables.sortbuff_size) * - (thread_scheduler->max_threads + extra_max_connections) + - (max_connections + extra_max_connections) * sizeof(THD)) / 1024; - - my_safe_printf_stderr("It is possible that mysqld could use up to \n" - "key_buffer_size + " - "(read_buffer_size + sort_buffer_size)*max_threads = " - "%zu K bytes of memory\n", used_mem); - - my_safe_printf_stderr("%s", - "Hope that's ok; if not, decrease some variables in " - "the equation.\n\n"); - } + my_safe_printf_stderr("Server version: %s source revision: %s\n\n", + server_version, SOURCE_REVISION); #ifdef WITH_WSREP Wsrep_server_state::handle_fatal_signal(); @@ -235,12 +216,14 @@ extern "C" sig_handler handle_fatal_signal(int sig) if (opt_stack_trace) { - my_safe_printf_stderr("Thread pointer: %p\n", thd); my_safe_printf_stderr("%s", - "Attempting backtrace. You can use the following " - "information to find out\n" - "where mysqld died. If you see no messages after this, something went\n" - "terribly wrong...\n"); + "The information page at " + "https://mariadb.com/kb/en/how-to-produce-a-full-stack-trace-for-mariadbd/\n" + "contains instructions to obtain a better version of the backtrace below.\n" + "Following these instructions will help MariaDB developers provide a fix quicker.\n\n" + "Attempting backtrace. Include this in the bug report.\n" + "(note: Retrieving this information may fail)\n\n"); + my_safe_printf_stderr("Thread pointer: %p\n", thd); my_print_stacktrace(thd ? (uchar*) thd->thread_stack : NULL, (ulong)my_thread_stack_size, 0); } @@ -288,20 +271,12 @@ extern "C" sig_handler handle_fatal_signal(int sig) kreason= "KILL_WAIT_TIMEOUT"; break; } - my_safe_printf_stderr("%s", "\n" - "Trying to get some variables.\n" - "Some pointers may be invalid and cause the dump to abort.\n"); - - my_safe_printf_stderr("Query (%p): ", thd->query()); - if (my_safe_print_str(thd->query(), MY_MIN(65536U, thd->query_length()))) - { - // Query was found invalid. We will try to print it at the end. - print_invalid_query_pointer= true; - } my_safe_printf_stderr("\nConnection ID (thread ID): %lu\n", (ulong) thd->thread_id); - my_safe_printf_stderr("Status: %s\n\n", kreason); + my_safe_printf_stderr("Status: %s\n", kreason); + my_safe_printf_stderr("Query (%p): ", thd->query()); + my_safe_print_str(thd->query(), MY_MIN(65536U, thd->query_length())); my_safe_printf_stderr("%s", "Optimizer switch: "); ulonglong optsw= thd->variables.optimizer_switch; for (uint i= 0; optimizer_switch_names[i+1]; i++, optsw >>= 1) @@ -313,52 +288,9 @@ extern "C" sig_handler handle_fatal_signal(int sig) } my_safe_printf_stderr("%s", "\n\n"); } - my_safe_printf_stderr("%s", - "The manual page at " - "https://mariadb.com/kb/en/how-to-produce-a-full-stack-trace-for-mariadbd/ contains\n" - "information that should help you find out what is causing the crash.\n"); #endif /* HAVE_STACKTRACE */ -#ifdef HAVE_INITGROUPS - if (calling_initgroups) - { - my_safe_printf_stderr("%s", "\n" - "This crash occurred while the server was calling initgroups(). This is\n" - "often due to the use of a mysqld that is statically linked against \n" - "glibc and configured to use LDAP in /etc/nsswitch.conf.\n" - "You will need to either upgrade to a version of glibc that does not\n" - "have this problem (2.3.4 or later when used with nscd),\n" - "disable LDAP in your nsswitch.conf, or use a " - "mysqld that is not statically linked.\n"); - } -#endif - - if (locked_in_memory) - { - my_safe_printf_stderr("%s", "\n" - "The \"--memlock\" argument, which was enabled, " - "uses system calls that are\n" - "unreliable and unstable on some operating systems and " - "operating-system versions (notably, some versions of Linux).\n" - "This crash could be due to use of those buggy OS calls.\n" - "You should consider whether you really need the " - "\"--memlock\" parameter and/or consult the OS distributer about " - "\"mlockall\" bugs.\n"); - } - -#ifdef HAVE_STACKTRACE - if (print_invalid_query_pointer) - { - my_safe_printf_stderr( - "\nWe think the query pointer is invalid, but we will try " - "to print it anyway. \n" - "Query: "); - my_write_stderr(thd->query(), MY_MIN(65536U, thd->query_length())); - my_safe_printf_stderr("\n\n"); - } -#endif - output_core_info(); #ifdef HAVE_WRITE_CORE if (test_flags & TEST_CORE_ON_SIGNAL) diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index def44656ac8..2abd0a529af 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -7227,6 +7227,7 @@ alter: { LEX *lex= Lex; lex->sql_command= SQLCOM_ALTER_SEQUENCE; + lex->create_info.init(); DBUG_ASSERT(!lex->m_sql_cmd); if (Lex->main_select_push()) MYSQL_YYABORT; diff --git a/sql/table.cc b/sql/table.cc index d7a0201379a..c74a6eaa81e 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -10102,7 +10102,14 @@ bool TABLE_LIST::is_the_same_definition(THD* thd, TABLE_SHARE *s) tabledef_version.length= 0; } else + { set_tabledef_version(s); + if (m_table_ref_type == TABLE_REF_NULL) + { + set_table_ref_id(s); + return TRUE; + } + } return FALSE; } diff --git a/storage/innobase/buf/buf0buf.cc b/storage/innobase/buf/buf0buf.cc index d706f2c21ec..73c9dcb65d0 100644 --- a/storage/innobase/buf/buf0buf.cc +++ b/storage/innobase/buf/buf0buf.cc @@ -1737,7 +1737,7 @@ struct find_interesting_trx { void operator()(const trx_t &trx) { - if (trx.state == TRX_STATE_NOT_STARTED) + if (!trx.is_started()) return; if (trx.mysql_thd == nullptr) return; @@ -1746,12 +1746,12 @@ struct find_interesting_trx if (!found) { - ib::warn() << "The following trx might hold " + sql_print_warning("InnoDB: The following trx might hold " "the blocks in buffer pool to " "be withdrawn. Buffer pool " "resizing can complete only " "after all the transactions " - "below release the blocks."; + "below release the blocks."); found= true; } @@ -3620,6 +3620,8 @@ retry: ut_ad(!bpage->is_io_fixed(state)); ut_ad(bpage->buf_fix_count(state)); } + else + state= bpage->state(); ut_ad(state >= buf_page_t::FREED); ut_ad(state < buf_page_t::READ_FIX); @@ -3941,8 +3943,7 @@ static dberr_t buf_page_check_corrupt(buf_page_t *bpage, const bool seems_encrypted = !node.space->full_crc32() && key_version && node.space->crypt_data && node.space->crypt_data->type != CRYPT_SCHEME_UNENCRYPTED; - ut_ad(node.space->purpose != FIL_TYPE_TEMPORARY || - node.space->full_crc32()); + ut_ad(!node.space->is_temporary() || node.space->full_crc32()); /* If traditional checksums match, we assume that page is not anymore encrypted. */ @@ -3950,7 +3951,7 @@ static dberr_t buf_page_check_corrupt(buf_page_t *bpage, && !buf_is_zeroes(span(dst_frame, node.space->physical_size())) && (key_version || node.space->is_compressed() - || node.space->purpose == FIL_TYPE_TEMPORARY)) { + || node.space->is_temporary())) { if (buf_page_full_crc32_is_corrupted( bpage->id().space(), dst_frame, node.space->is_compressed())) { diff --git a/storage/innobase/buf/buf0dblwr.cc b/storage/innobase/buf/buf0dblwr.cc index ff2e71b698f..ac48fef14cf 100644 --- a/storage/innobase/buf/buf0dblwr.cc +++ b/storage/innobase/buf/buf0dblwr.cc @@ -745,7 +745,8 @@ void buf_dblwr_t::add_to_batch(const IORequest &request, size_t size) ut_ad(request.bpage); ut_ad(request.bpage->in_file()); ut_ad(request.node); - ut_ad(request.node->space->purpose == FIL_TYPE_TABLESPACE); + ut_ad(!request.node->space->is_temporary()); + ut_ad(!request.node->space->is_being_imported()); ut_ad(request.node->space->id == request.bpage->id().space()); ut_ad(request.node->space->referenced()); ut_ad(!srv_read_only_mode); diff --git a/storage/innobase/buf/buf0flu.cc b/storage/innobase/buf/buf0flu.cc index cbff57c1157..0a0e6851eab 100644 --- a/storage/innobase/buf/buf0flu.cc +++ b/storage/innobase/buf/buf0flu.cc @@ -601,7 +601,7 @@ static byte *buf_page_encrypt(fil_space_t* space, buf_page_t* bpage, byte* s, fil_space_crypt_t *crypt_data= space->crypt_data; bool encrypted, page_compressed; - if (space->purpose == FIL_TYPE_TEMPORARY) + if (space->is_temporary()) { ut_ad(!crypt_data); encrypted= innodb_encrypt_temporary_tables; @@ -647,13 +647,13 @@ static byte *buf_page_encrypt(fil_space_t* space, buf_page_t* bpage, byte* s, if (!page_compressed) { not_compressed: - d= space->purpose == FIL_TYPE_TEMPORARY + d= space->is_temporary() ? buf_tmp_page_encrypt(page_no, s, d) : fil_space_encrypt(space, page_no, s, d); } else { - ut_ad(space->purpose != FIL_TYPE_TEMPORARY); + ut_ad(!space->is_temporary()); /* First we compress the page content */ buf_tmp_reserve_compression_buf(*slot); byte *tmp= (*slot)->comp_buf; @@ -730,8 +730,7 @@ bool buf_page_t::flush(fil_space_t *space) mysql_mutex_assert_not_owner(&buf_pool.flush_list_mutex); ut_ad(in_file()); ut_ad(in_LRU_list); - ut_ad((space->purpose == FIL_TYPE_TEMPORARY) == - (space == fil_system.temp_space)); + ut_ad((space->is_temporary()) == (space == fil_system.temp_space)); ut_ad(space->referenced()); const auto s= state(); @@ -741,12 +740,12 @@ bool buf_page_t::flush(fil_space_t *space) (FIL_PAGE_LSN + (zip.data ? zip.data : frame))); ut_ad(lsn ? lsn >= oldest_modification() || oldest_modification() == 2 - : space->purpose != FIL_TYPE_TABLESPACE); + : (space->is_temporary() || space->is_being_imported())); if (s < UNFIXED) { ut_a(s >= FREED); - if (UNIV_LIKELY(space->purpose == FIL_TYPE_TABLESPACE)) + if (!space->is_temporary() && !space->is_being_imported()) { freed: if (lsn > log_sys.get_flushed_lsn()) @@ -762,7 +761,8 @@ bool buf_page_t::flush(fil_space_t *space) if (UNIV_UNLIKELY(lsn < space->get_create_lsn())) { - ut_ad(space->purpose == FIL_TYPE_TABLESPACE); + ut_ad(!space->is_temporary()); + ut_ad(!space->is_being_imported()); goto freed; } @@ -846,7 +846,7 @@ bool buf_page_t::flush(fil_space_t *space) if ((s & LRU_MASK) == REINIT || !space->use_doublewrite()) { - if (UNIV_LIKELY(space->purpose == FIL_TYPE_TABLESPACE) && + if (!space->is_temporary() && !space->is_being_imported() && lsn > log_sys.get_flushed_lsn()) log_write_up_to(lsn, true); space->io(IORequest{type, this, slot}, physical_offset(), size, @@ -1697,7 +1697,7 @@ done: if (acquired) space->release(); - if (space->purpose == FIL_TYPE_IMPORT) + if (space->is_being_imported()) os_aio_wait_until_no_pending_writes(true); else buf_dblwr.flush_buffered_writes(); diff --git a/storage/innobase/dict/dict0load.cc b/storage/innobase/dict/dict0load.cc index 53a39a5e7e0..e35fd8124c4 100644 --- a/storage/innobase/dict/dict0load.cc +++ b/storage/innobase/dict/dict0load.cc @@ -970,8 +970,10 @@ void dict_check_tablespaces_and_store_max_id(const std::set *spaces) const bool not_dropped{!rec_get_deleted_flag(rec, 0)}; /* Check that the .ibd file exists. */ - if (fil_ibd_open(not_dropped, FIL_TYPE_TABLESPACE, - space_id, dict_tf_to_fsp_flags(flags), + if (fil_ibd_open(space_id, dict_tf_to_fsp_flags(flags), + not_dropped + ? fil_space_t::VALIDATE_NOTHING + : fil_space_t::MAYBE_MISSING, name, filepath)) { } else if (!not_dropped) { } else if (srv_operation == SRV_OPERATION_NORMAL @@ -2289,8 +2291,8 @@ dict_load_tablespace( } table->space = fil_ibd_open( - 2, FIL_TYPE_TABLESPACE, table->space_id, - dict_tf_to_fsp_flags(table->flags), + table->space_id, dict_tf_to_fsp_flags(table->flags), + fil_space_t::VALIDATE_SPACE_ID, {table->name.m_name, strlen(table->name.m_name)}, filepath); if (!table->space) { diff --git a/storage/innobase/dict/dict0mem.cc b/storage/innobase/dict/dict0mem.cc index b8b2d583c24..d47914cf888 100644 --- a/storage/innobase/dict/dict0mem.cc +++ b/storage/innobase/dict/dict0mem.cc @@ -136,9 +136,6 @@ dict_table_t *dict_table_t::create(const span &name, ulint n_cols, ulint n_v_cols, ulint flags, ulint flags2) { - ut_ad(!space || space->purpose == FIL_TYPE_TABLESPACE || - space->purpose == FIL_TYPE_TEMPORARY || - space->purpose == FIL_TYPE_IMPORT); ut_a(dict_tf2_is_valid(flags, flags2)); ut_a(!(flags2 & DICT_TF2_UNUSED_BIT_MASK)); diff --git a/storage/innobase/fil/fil0crypt.cc b/storage/innobase/fil/fil0crypt.cc index 0e03044feff..54ca21adba8 100644 --- a/storage/innobase/fil/fil0crypt.cc +++ b/storage/innobase/fil/fil0crypt.cc @@ -1068,7 +1068,8 @@ default_encrypt_list only when default encrypt */ static bool fil_crypt_must_remove(const fil_space_t &space) { - ut_ad(space.purpose == FIL_TYPE_TABLESPACE); + ut_ad(!space.is_temporary()); + ut_ad(!space.is_being_imported()); fil_space_crypt_t *crypt_data = space.crypt_data; mysql_mutex_assert_owner(&fil_system.mutex); const ulong encrypt_tables= srv_encrypt_tables; @@ -1104,7 +1105,8 @@ fil_crypt_space_needs_rotation( fil_space_t* space = &*state->space; ut_ad(space->referenced()); - ut_ad(space->purpose == FIL_TYPE_TABLESPACE); + ut_ad(!space->is_temporary()); + ut_ad(!space->is_being_imported()); fil_space_crypt_t *crypt_data = space->crypt_data; @@ -1456,7 +1458,7 @@ space_list_t::iterator fil_space_t::next(space_list_t::iterator space, for (; space != fil_system.space_list.end(); ++space) { - if (space->purpose != FIL_TYPE_TABLESPACE) + if (space->is_temporary() || space->is_being_imported()) continue; const uint32_t n= space->acquire_low(); if (UNIV_LIKELY(!(n & (STOPPING | CLOSING)))) @@ -2138,9 +2140,9 @@ static void fil_crypt_default_encrypt_tables_fill() mysql_mutex_assert_owner(&fil_system.mutex); for (fil_space_t& space : fil_system.space_list) { - if (space.purpose != FIL_TYPE_TABLESPACE - || space.is_in_default_encrypt + if (space.is_in_default_encrypt || UT_LIST_GET_LEN(space.chain) == 0 + || space.is_temporary() || space.is_being_imported() || !space.acquire_if_not_stopped()) { continue; } diff --git a/storage/innobase/fil/fil0fil.cc b/storage/innobase/fil/fil0fil.cc index a5663f4f756..6e5b16227d9 100644 --- a/storage/innobase/fil/fil0fil.cc +++ b/storage/innobase/fil/fil0fil.cc @@ -78,17 +78,11 @@ bool fil_space_t::try_to_close(fil_space_t *ignore_space, bool print_info) mysql_mutex_assert_owner(&fil_system.mutex); for (fil_space_t &space : fil_system.space_list) { - if (&space == ignore_space) + if (&space == ignore_space || space.is_being_imported() || + space.id == TRX_SYS_SPACE || space.id == SRV_TMP_SPACE_ID || + srv_is_undo_tablespace(space.id)) continue; - switch (space.purpose) { - case FIL_TYPE_TEMPORARY: - continue; - case FIL_TYPE_IMPORT: - break; - case FIL_TYPE_TABLESPACE: - if (space.id == TRX_SYS_SPACE || srv_is_undo_tablespace(space.id)) - continue; - } + ut_ad(!space.is_temporary()); /* We are using an approximation of LRU replacement policy. In fil_node_open_file_low(), newly opened files are moved to the end @@ -435,7 +429,7 @@ static bool fil_node_open_file(fil_node_t *node, const byte *page, bool no_lsn) srv_operation == SRV_OPERATION_BACKUP || srv_operation == SRV_OPERATION_RESTORE || srv_operation == SRV_OPERATION_RESTORE_DELTA); - ut_ad(node->space->purpose != FIL_TYPE_TEMPORARY); + ut_ad(!node->space->is_temporary()); ut_ad(node->space->referenced()); const auto old_time= fil_system.n_open_exceeded_time; @@ -496,7 +490,7 @@ void fil_node_t::prepare_to_close_or_detach() srv_operation == SRV_OPERATION_RESTORE_DELTA); ut_a(is_open()); ut_a(!being_extended); - ut_a(space->is_ready_to_close() || space->purpose == FIL_TYPE_TEMPORARY || + ut_a(space->is_ready_to_close() || space->is_temporary() || srv_fast_shutdown == 2 || !srv_was_started); ut_a(fil_system.n_open > 0); @@ -653,14 +647,13 @@ fil_space_extend_must_retry( mysql_mutex_lock(&fil_system.mutex); break; default: - ut_ad(space->purpose == FIL_TYPE_TABLESPACE - || space->purpose == FIL_TYPE_IMPORT); - if (space->purpose == FIL_TYPE_TABLESPACE) { + ut_ad(!space->is_temporary()); + if (!space->is_being_imported()) { goto do_flush; } break; case SRV_TMP_SPACE_ID: - ut_ad(space->purpose == FIL_TYPE_TEMPORARY); + ut_ad(space->is_temporary()); srv_tmp_space.set_last_file_size(pages_in_MiB); break; } @@ -674,8 +667,7 @@ ATTRIBUTE_COLD bool fil_space_t::prepare_acquired() ut_ad(referenced()); mysql_mutex_assert_owner(&fil_system.mutex); fil_node_t *node= UT_LIST_GET_LAST(chain); - ut_ad(!id || purpose == FIL_TYPE_TEMPORARY || - node == UT_LIST_GET_FIRST(chain)); + ut_ad(!id || is_temporary() || node == UT_LIST_GET_FIRST(chain)); const bool is_open= node && (node->is_open() || fil_node_open_file(node, nullptr, false)); @@ -737,7 +729,7 @@ ATTRIBUTE_COLD bool fil_space_t::acquire_and_prepare() @return whether the tablespace is at least as big as requested */ bool fil_space_extend(fil_space_t *space, uint32_t size) { - ut_ad(!srv_read_only_mode || space->purpose == FIL_TYPE_TEMPORARY); + ut_ad(!srv_read_only_mode || space->is_temporary()); bool success= false; const bool acquired= space->acquire(); mysql_mutex_lock(&fil_system.mutex); @@ -944,111 +936,85 @@ bool fil_space_free(uint32_t id, bool x_latched) return(space != NULL); } -/** Create a tablespace in fil_system. -@param name tablespace name -@param id tablespace identifier -@param flags tablespace flags -@param purpose tablespace purpose -@param crypt_data encryption information -@param mode encryption mode -@param opened true if space files are opened -@return pointer to created tablespace, to be filled in with add() -@retval nullptr on failure (such as when the same tablespace exists) */ -fil_space_t *fil_space_t::create(uint32_t id, uint32_t flags, - fil_type_t purpose, - fil_space_crypt_t *crypt_data, - fil_encryption_t mode, - bool opened) +fil_space_t::fil_space_t(uint32_t id, uint32_t flags, bool being_imported, + fil_space_crypt_t *crypt_data) noexcept : + id(id), crypt_data(crypt_data), being_imported(being_imported), flags(flags) { - fil_space_t* space; + UT_LIST_INIT(chain, &fil_node_t::chain); + memset((void*) &latch, 0, sizeof latch); + latch.SRW_LOCK_INIT(fil_space_latch_key); +} - mysql_mutex_assert_owner(&fil_system.mutex); - ut_ad(fil_system.is_initialised()); - ut_ad(fil_space_t::is_valid_flags(flags & ~FSP_FLAGS_MEM_MASK, id)); - ut_ad(srv_page_size == UNIV_PAGE_SIZE_ORIG || flags != 0); +fil_space_t *fil_space_t::create(uint32_t id, uint32_t flags, + bool being_imported, + fil_space_crypt_t *crypt_data, + fil_encryption_t mode, + bool opened) noexcept +{ + mysql_mutex_assert_owner(&fil_system.mutex); + ut_ad(fil_system.is_initialised()); + ut_ad(fil_space_t::is_valid_flags(flags & ~FSP_FLAGS_MEM_MASK, id)); + ut_ad(srv_page_size == UNIV_PAGE_SIZE_ORIG || flags != 0); - DBUG_EXECUTE_IF("fil_space_create_failure", return(NULL);); + DBUG_EXECUTE_IF("fil_space_create_failure", return nullptr;); - fil_space_t** after = reinterpret_cast( - &fil_system.spaces.cell_get(id)->node); - for (; *after; after = &(*after)->hash) { - ut_a((*after)->id != id); - } + fil_space_t** after= fil_system.spaces.cell_get(id)->search + (&fil_space_t::hash, [id](const fil_space_t *space) + { return !space || space->id == id; }); + ut_a(!*after); + fil_space_t *space= new (ut_malloc_nokey(sizeof(*space))) + fil_space_t(id, flags, being_imported, crypt_data); + *after= space; - /* FIXME: if calloc() is defined as an inline function that calls - memset() or bzero(), then GCC 6 -flifetime-dse can optimize it away */ - *after = space = new (ut_zalloc_nokey(sizeof(*space))) fil_space_t; + if (crypt_data) + DBUG_PRINT("crypt", ("Tablespace %" PRIu32 " encryption %d key id %" PRIu32 + ":%s %s", + id, crypt_data->encryption, crypt_data->key_id, + fil_crypt_get_mode(crypt_data), + fil_crypt_get_type(crypt_data))); - space->id = id; + if (opened) + fil_system.add_opened_last_to_space_list(space); + else + fil_system.space_list.push_back(*space); - UT_LIST_INIT(space->chain, &fil_node_t::chain); + switch (id) { + case 0: + ut_ad(!fil_system.sys_space); + fil_system.sys_space= space; + break; + case SRV_TMP_SPACE_ID: + ut_ad(!fil_system.temp_space); + fil_system.temp_space= space; + return space; + default: + if (UNIV_LIKELY(id <= fil_system.max_assigned_id)) + break; + if (UNIV_UNLIKELY(srv_operation == SRV_OPERATION_BACKUP)) + break; + if (!fil_system.space_id_reuse_warned) + sql_print_warning("InnoDB: Allocated tablespace ID %" PRIu32 + ", old maximum was %" PRIu32, + id, fil_system.max_assigned_id); + fil_system.max_assigned_id = id; + } - space->purpose = purpose; - space->flags = flags; + if ((mode == FIL_ENCRYPTION_ON || + (mode == FIL_ENCRYPTION_OFF || srv_encrypt_tables)) && + !space->is_being_imported() && fil_crypt_must_default_encrypt()) + { + fil_system.default_encrypt_tables.push_back(*space); + space->is_in_default_encrypt= true; - space->crypt_data = crypt_data; - space->n_pending.store(CLOSING, std::memory_order_relaxed); + if (srv_n_fil_crypt_threads_started) + { + mysql_mutex_unlock(&fil_system.mutex); + fil_crypt_threads_signal(); + mysql_mutex_lock(&fil_system.mutex); + } + } - DBUG_LOG("tablespace", "Created metadata for " << id); - if (crypt_data) { - DBUG_LOG("crypt", - "Tablespace " << id - << " encryption " << crypt_data->encryption - << " key id " << crypt_data->key_id - << ":" << fil_crypt_get_mode(crypt_data) - << " " << fil_crypt_get_type(crypt_data)); - } - - space->latch.SRW_LOCK_INIT(fil_space_latch_key); - - if (opened) - fil_system.add_opened_last_to_space_list(space); - else - fil_system.space_list.push_back(*space); - - switch (id) { - case 0: - ut_ad(!fil_system.sys_space); - fil_system.sys_space = space; - break; - case SRV_TMP_SPACE_ID: - ut_ad(!fil_system.temp_space); - fil_system.temp_space = space; - break; - default: - ut_ad(purpose != FIL_TYPE_TEMPORARY); - if (UNIV_LIKELY(id <= fil_system.max_assigned_id)) { - break; - } - if (UNIV_UNLIKELY(srv_operation == SRV_OPERATION_BACKUP)) { - break; - } - if (!fil_system.space_id_reuse_warned) { - ib::warn() << "Allocated tablespace ID " << id - << ", old maximum was " - << fil_system.max_assigned_id; - } - - fil_system.max_assigned_id = id; - } - - const bool rotate = purpose == FIL_TYPE_TABLESPACE - && (mode == FIL_ENCRYPTION_ON || mode == FIL_ENCRYPTION_OFF - || srv_encrypt_tables) - && fil_crypt_must_default_encrypt(); - - if (rotate) { - fil_system.default_encrypt_tables.push_back(*space); - space->is_in_default_encrypt = true; - - if (srv_n_fil_crypt_threads_started) { - mysql_mutex_unlock(&fil_system.mutex); - fil_crypt_threads_signal(); - mysql_mutex_lock(&fil_system.mutex); - } - } - - return(space); + return space; } /*******************************************************************//** @@ -1531,6 +1497,7 @@ static void fil_name_write(uint32_t space_id, const char *name, fil_space_t *fil_space_t::drop(uint32_t id, pfs_os_file_t *detached_handle) { ut_a(!is_system_tablespace(id)); + ut_ad(id != SRV_TMP_SPACE_ID); mysql_mutex_lock(&fil_system.mutex); fil_space_t *space= fil_space_get_by_id(id); @@ -1573,7 +1540,7 @@ fil_space_t *fil_space_t::drop(uint32_t id, pfs_os_file_t *detached_handle) if (space->crypt_data) fil_space_crypt_close_tablespace(space); - if (space->purpose == FIL_TYPE_TABLESPACE) + if (!space->is_being_imported()) { if (id >= srv_undo_space_id_start && id < srv_undo_space_id_start + srv_undo_tablespaces_open) @@ -1593,8 +1560,6 @@ fil_space_t *fil_space_t::drop(uint32_t id, pfs_os_file_t *detached_handle) os_file_delete(innodb_data_file_key, space->chain.start->name); } - else - ut_ad(space->purpose == FIL_TYPE_IMPORT); if (char *cfg_name= fil_make_filepath(space->chain.start->name, fil_space_t::name_type{}, CFG, false)) @@ -1894,7 +1859,7 @@ fil_ibd_create( uint32_t size, fil_encryption_t mode, uint32_t key_id, - dberr_t* err) + dberr_t* err) noexcept { pfs_os_file_t file; bool success; @@ -2017,8 +1982,8 @@ err_exit: log_make_checkpoint();); mysql_mutex_lock(&fil_system.mutex); - if (fil_space_t* space = fil_space_t::create(space_id, flags, - FIL_TYPE_TABLESPACE, + if (fil_space_t* space = fil_space_t::create(space_id, + flags, false, crypt_data, mode, true)) { fil_node_t* node = space->add(path, file, size, false, true); node->find_metadata(IF_WIN(,true)); @@ -2040,51 +2005,17 @@ err_exit: goto err_exit; } -/** Try to open a single-table tablespace and optionally check that the -space id in it is correct. If this does not succeed, print an error message -to the .err log. This function is used to open a tablespace when we start -mysqld after the dictionary has been booted, and also in IMPORT TABLESPACE. - -NOTE that we assume this operation is used either at the database startup -or under the protection of dict_sys.latch, so that two users cannot -race here. This operation does not leave the file associated with the -tablespace open, but closes it after we have looked at the space id in it. - -If the validate boolean is set, we read the first page of the file and -check that the space id in the file is what we expect. We assume that -this function runs much faster if no check is made, since accessing the -file inode probably is much faster (the OS caches them) than accessing -the first page of the file. This boolean may be initially false, but if -a remote tablespace is found it will be changed to true. - -If the fix_dict boolean is set, then it is safe to use an internal SQL -statement to update the dictionary tables if they are incorrect. - -@param[in] validate 0=maybe missing, 1=do not validate, 2=validate -@param[in] purpose FIL_TYPE_TABLESPACE or FIL_TYPE_TEMPORARY -@param[in] id tablespace ID -@param[in] flags expected FSP_SPACE_FLAGS -@param[in] name table name -If file-per-table, it is the table name in the databasename/tablename format -@param[in] path_in expected filepath, usually read from dictionary -@param[out] err DB_SUCCESS or error code -@return tablespace -@retval NULL if the tablespace could not be opened */ -fil_space_t* -fil_ibd_open( - unsigned validate, - fil_type_t purpose, - uint32_t id, - uint32_t flags, - fil_space_t::name_type name, - const char* path_in, - dberr_t* err) +fil_space_t *fil_ibd_open(uint32_t id, uint32_t flags, + fil_space_t::validate validate, + fil_space_t::name_type name, + const char *path_in, dberr_t *err) noexcept { mysql_mutex_lock(&fil_system.mutex); fil_space_t* space = fil_space_get_by_id(id); mysql_mutex_unlock(&fil_system.mutex); if (space) { - if (validate > 1 && !srv_read_only_mode) { + if (validate == fil_space_t::VALIDATE_SPACE_ID + && !srv_read_only_mode) { fsp_flags_try_adjust(space, flags & ~FSP_FLAGS_MEM_MASK); } @@ -2140,7 +2071,7 @@ func_exit: /* Dict path is not the default path. Always validate remote files. If default is opened, it was moved. */ must_validate = true; - } else if (validate > 1) { + } else if (validate >= fil_space_t::VALIDATE_SPACE_ID) { must_validate = true; } @@ -2157,7 +2088,8 @@ func_exit: the first server startup. The tables ought to be dropped by drop_garbage_tables_after_restore() a little later. */ - const bool strict = validate && !tablespaces_found + const bool strict = (validate != fil_space_t::MAYBE_MISSING) + && !tablespaces_found && operation_not_for_export && !(srv_operation == SRV_OPERATION_NORMAL && srv_start_after_restore @@ -2288,7 +2220,9 @@ skip_validate: : NULL; mysql_mutex_lock(&fil_system.mutex); - space = fil_space_t::create(id, flags, purpose, crypt_data); + space = fil_space_t::create(id, flags, + validate == fil_space_t::VALIDATE_IMPORT, + crypt_data); if (!space) { mysql_mutex_unlock(&fil_system.mutex); goto error; @@ -2306,7 +2240,7 @@ skip_validate: df_remote.close(); df_default.close(); if (space->acquire()) { - if (purpose != FIL_TYPE_IMPORT) { + if (validate < fil_space_t::VALIDATE_IMPORT) { fsp_flags_try_adjust(space, flags & ~FSP_FLAGS_MEM_MASK); } @@ -2591,8 +2525,8 @@ tablespace_check: mysql_mutex_lock(&fil_system.mutex); - space = fil_space_t::create( - space_id, flags, FIL_TYPE_TABLESPACE, crypt_data); + space = fil_space_t::create(uint32_t(space_id), flags, false, + crypt_data); if (space == NULL) { mysql_mutex_unlock(&fil_system.mutex); @@ -2620,16 +2554,14 @@ void fsp_flags_try_adjust(fil_space_t *space, uint32_t flags) { ut_ad(!srv_read_only_mode); ut_ad(fil_space_t::is_valid_flags(flags, space->id)); + ut_ad(!space->is_being_imported()); + ut_ad(!space->is_temporary()); if (space->full_crc32() || fil_space_t::full_crc32(flags)) { return; } - if (!space->size && (space->purpose != FIL_TYPE_TABLESPACE - || !space->get_size())) { + if (!space->size || !space->get_size()) { return; } - /* This code is executed during server startup while no - connections are allowed. We do not need to protect against - DROP TABLE by fil_space_acquire(). */ mtr_t mtr; mtr.start(); if (buf_block_t* b = buf_page_get( @@ -2720,7 +2652,7 @@ inline void fil_node_t::complete_write() { mysql_mutex_assert_not_owner(&fil_system.mutex); - if (space->purpose != FIL_TYPE_TEMPORARY && + if (!space->is_temporary() && srv_file_flush_method != SRV_O_DIRECT_NO_FSYNC && space->set_needs_flush()) { @@ -3034,8 +2966,8 @@ fil_space_validate_for_mtr_commit( { mysql_mutex_assert_not_owner(&fil_system.mutex); ut_ad(space != NULL); - ut_ad(space->purpose == FIL_TYPE_TABLESPACE); ut_ad(!is_predefined_tablespace(space->id)); + ut_ad(!space->is_being_imported()); /* We are serving mtr_commit(). While there is an active mini-transaction, we should have !space->is_stopping(). This is @@ -3218,7 +3150,7 @@ fil_space_t::name_type fil_space_t::name() const if (!UT_LIST_GET_FIRST(chain) || srv_is_undo_tablespace(id)) return name_type{}; - ut_ad(purpose != FIL_TYPE_TEMPORARY); + ut_ad(!is_temporary()); ut_ad(UT_LIST_GET_LEN(chain) == 1); const char *path= UT_LIST_GET_FIRST(chain)->name; diff --git a/storage/innobase/fsp/fsp0fsp.cc b/storage/innobase/fsp/fsp0fsp.cc index 4ed3ba5b34e..677e9b68662 100644 --- a/storage/innobase/fsp/fsp0fsp.cc +++ b/storage/innobase/fsp/fsp0fsp.cc @@ -350,7 +350,7 @@ xdes_get_descriptor_with_space_hdr( ut_ad(limit == space->free_limit || (space->free_limit == 0 && (init_space - || space->purpose == FIL_TYPE_TEMPORARY + || space->is_temporary() || (srv_startup_is_before_trx_rollback_phase && (space->id == TRX_SYS_SPACE || srv_is_undo_tablespace(space->id)))))); @@ -486,14 +486,15 @@ void fil_space_t::modify_check(const mtr_t& mtr) const case MTR_LOG_NONE: /* These modes are only allowed within a non-bitmap page when there is a higher-level redo log record written. */ - ut_ad(purpose == FIL_TYPE_TABLESPACE || purpose == FIL_TYPE_TEMPORARY); + ut_ad(!is_being_imported()); break; case MTR_LOG_NO_REDO: - ut_ad(purpose == FIL_TYPE_TEMPORARY || purpose == FIL_TYPE_IMPORT); + ut_ad(is_temporary() || is_being_imported()); break; default: /* We may only write redo log for a persistent tablespace. */ - ut_ad(purpose == FIL_TYPE_TABLESPACE); + ut_ad(!is_temporary()); + ut_ad(!is_being_imported()); ut_ad(mtr.is_named_space(id)); } } @@ -852,7 +853,7 @@ fsp_fill_free_list( FIL_PAGE_TYPE_XDES); } - if (space->purpose != FIL_TYPE_TEMPORARY) + if (!space->is_temporary()) { buf_block_t *f= buf_LRU_get_free_block(false); buf_block_t *block= diff --git a/storage/innobase/fsp/fsp0space.cc b/storage/innobase/fsp/fsp0space.cc index c2152b08590..6c00d26b9bb 100644 --- a/storage/innobase/fsp/fsp0space.cc +++ b/storage/innobase/fsp/fsp0space.cc @@ -132,10 +132,8 @@ Tablespace::open_or_create(bool is_temp) mysql_mutex_lock(&fil_system.mutex); space = fil_space_t::create( - m_space_id, fsp_flags, - is_temp - ? FIL_TYPE_TEMPORARY : FIL_TYPE_TABLESPACE, - NULL); + uint32_t(m_space_id), fsp_flags, + false, nullptr); if (!space) { mysql_mutex_unlock(&fil_system.mutex); return DB_ERROR; diff --git a/storage/innobase/fsp/fsp0sysspace.cc b/storage/innobase/fsp/fsp0sysspace.cc index 5771176ec2d..cdd1797d346 100644 --- a/storage/innobase/fsp/fsp0sysspace.cc +++ b/storage/innobase/fsp/fsp0sysspace.cc @@ -953,8 +953,7 @@ SysTablespace::open_or_create( } else if (is_temp) { ut_ad(space_id() == SRV_TMP_SPACE_ID); space = fil_space_t::create( - SRV_TMP_SPACE_ID, flags(), - FIL_TYPE_TEMPORARY, NULL); + SRV_TMP_SPACE_ID, flags(), false, nullptr); ut_ad(space == fil_system.temp_space); if (!space) { err = DB_ERROR; @@ -965,8 +964,7 @@ SysTablespace::open_or_create( } else { ut_ad(space_id() == TRX_SYS_SPACE); space = fil_space_t::create( - TRX_SYS_SPACE, it->flags(), - FIL_TYPE_TABLESPACE, NULL); + TRX_SYS_SPACE, it->flags(), false, nullptr); ut_ad(space == fil_system.sys_space); if (!space) { err = DB_ERROR; diff --git a/storage/innobase/fts/fts0fts.cc b/storage/innobase/fts/fts0fts.cc index 5c291b068ff..a00cd6ea9ae 100644 --- a/storage/innobase/fts/fts0fts.cc +++ b/storage/innobase/fts/fts0fts.cc @@ -2211,7 +2211,7 @@ fts_savepoint_t* fts_savepoint_create( /*=================*/ ib_vector_t* savepoints, /*!< out: InnoDB transaction */ - const char* name, /*!< in: savepoint name */ + const void* name, /*!< in: savepoint */ mem_heap_t* heap) /*!< in: heap */ { fts_savepoint_t* savepoint; @@ -2220,11 +2220,7 @@ fts_savepoint_create( ib_vector_push(savepoints, NULL)); memset(savepoint, 0x0, sizeof(*savepoint)); - - if (name) { - savepoint->name = mem_heap_strdup(heap, name); - } - + savepoint->name = name; static_assert(!offsetof(fts_trx_table_t, table), "ABI"); savepoint->tables = rbt_create(sizeof(fts_trx_table_t*), fts_ptr2_cmp); @@ -2243,7 +2239,6 @@ fts_trx_create( fts_trx_t* ftt; ib_alloc_t* heap_alloc; mem_heap_t* heap = mem_heap_create(1024); - trx_named_savept_t* savep; ut_a(trx->fts_trx == NULL); @@ -2263,14 +2258,6 @@ fts_trx_create( fts_savepoint_create(ftt->savepoints, NULL, NULL); fts_savepoint_create(ftt->last_stmt, NULL, NULL); - /* Copy savepoints that already set before. */ - for (savep = UT_LIST_GET_FIRST(trx->trx_savepoints); - savep != NULL; - savep = UT_LIST_GET_NEXT(trx_savepoints, savep)) { - - fts_savepoint_take(ftt, savep->name); - } - return(ftt); } @@ -5410,7 +5397,7 @@ void fts_savepoint_take( /*===============*/ fts_trx_t* fts_trx, /*!< in: fts transaction */ - const char* name) /*!< in: savepoint name */ + const void* name) /*!< in: savepoint */ { mem_heap_t* heap; fts_savepoint_t* savepoint; @@ -5433,31 +5420,21 @@ fts_savepoint_take( } /*********************************************************************//** -Lookup a savepoint instance by name. -@return ULINT_UNDEFINED if not found */ -UNIV_INLINE +Lookup a savepoint instance. +@return 0 if not found */ +static ulint fts_savepoint_lookup( /*==================*/ ib_vector_t* savepoints, /*!< in: savepoints */ - const char* name) /*!< in: savepoint name */ + const void* name) /*!< in: savepoint */ { - ulint i; - - ut_a(ib_vector_size(savepoints) > 0); - - for (i = 1; i < ib_vector_size(savepoints); ++i) { - fts_savepoint_t* savepoint; - - savepoint = static_cast( - ib_vector_get(savepoints, i)); - - if (strcmp(name, savepoint->name) == 0) { - return(i); - } - } - - return(ULINT_UNDEFINED); + ut_a(ib_vector_size(savepoints) > 0); + for (ulint i= 1; i < ib_vector_size(savepoints); ++i) + if (name == static_cast + (ib_vector_get(savepoints, i))->name) + return i; + return 0; } /*********************************************************************//** @@ -5468,7 +5445,7 @@ void fts_savepoint_release( /*==================*/ trx_t* trx, /*!< in: transaction */ - const char* name) /*!< in: savepoint name */ + const void* name) /*!< in: savepoint name */ { ut_a(name != NULL); @@ -5476,10 +5453,7 @@ fts_savepoint_release( ut_a(ib_vector_size(savepoints) > 0); - ulint i = fts_savepoint_lookup(savepoints, name); - if (i != ULINT_UNDEFINED) { - ut_a(i >= 1); - + if (ulint i = fts_savepoint_lookup(savepoints, name)) { fts_savepoint_t* savepoint; savepoint = static_cast( ib_vector_get(savepoints, i)); @@ -5634,9 +5608,8 @@ void fts_savepoint_rollback( /*===================*/ trx_t* trx, /*!< in: transaction */ - const char* name) /*!< in: savepoint name */ + const void* name) /*!< in: savepoint */ { - ulint i; ib_vector_t* savepoints; ut_a(name != NULL); @@ -5645,16 +5618,19 @@ fts_savepoint_rollback( /* We pop all savepoints from the the top of the stack up to and including the instance that was found. */ - i = fts_savepoint_lookup(savepoints, name); + ulint i = fts_savepoint_lookup(savepoints, name); - if (i != ULINT_UNDEFINED) { + if (i == 0) { + /* fts_trx_create() must have been invoked after + this savepoint had been created, and we must roll back + everything. */ + i = 1; + } + + { fts_savepoint_t* savepoint; - ut_a(i > 0); - while (ib_vector_size(savepoints) > i) { - fts_savepoint_t* savepoint; - savepoint = static_cast( ib_vector_pop(savepoints)); diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index dbb13057861..36c35af1a20 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -1091,17 +1091,6 @@ static SHOW_VAR innodb_status_variables[]= { {NullS, NullS, SHOW_LONG} }; -/*****************************************************************//** -Frees a possible InnoDB trx object associated with the current THD. -@return 0 or error number */ -static -int -innobase_close_connection( -/*======================*/ - handlerton* hton, /*!< in/out: InnoDB handlerton */ - THD* thd); /*!< in: MySQL thread handle for - which to close the connection */ - /** Cancel any pending lock request associated with the current THD. @sa THD::awake() @sa ha_kill_query() */ static void innobase_kill_query(handlerton*, THD* thd, enum thd_kill_levels); @@ -1166,33 +1155,6 @@ innobase_rollback_to_savepoint_can_release_mdl( the user whose XA transaction should be rolled back to savepoint */ -/*****************************************************************//** -Sets a transaction savepoint. -@return always 0, that is, always succeeds */ -static -int -innobase_savepoint( -/*===============*/ - handlerton* hton, /*!< in/out: InnoDB handlerton */ - THD* thd, /*!< in: handle to the MySQL thread of - the user's XA transaction for which - we need to take a savepoint */ - void* savepoint); /*!< in: savepoint data */ - -/*****************************************************************//** -Release transaction savepoint name. -@return 0 if success, HA_ERR_NO_SAVEPOINT if no savepoint with the -given name */ -static -int -innobase_release_savepoint( -/*=======================*/ - handlerton* hton, /*!< in/out: handlerton for InnoDB */ - THD* thd, /*!< in: handle to the MySQL thread - of the user whose transaction's - savepoint should be released */ - void* savepoint); /*!< in: savepoint data */ - /** Request notification of log writes */ static void innodb_log_flush_request(void *cookie); @@ -2108,6 +2070,25 @@ static int innodb_ddl_recovery_done(handlerton*) return 0; } +/** Report an aborted transaction or statement. +@param thd execution context +@param all true=transaction, false=statement +@param err InnoDB error code */ +static void innodb_transaction_abort(THD *thd, bool all, dberr_t err) noexcept +{ + if (!thd) + return; + if (!all); + else if (trx_t *trx = thd_to_trx(thd)) + { + ut_ad(trx->state == TRX_STATE_NOT_STARTED); + trx->state= TRX_STATE_ABORTED; + sql_print_error("InnoDB: Transaction was aborted due to %s", + ut_strerr(err)); + } + thd_mark_transaction_to_rollback(thd, all); +} + /********************************************************************//** Converts an InnoDB error code to a MySQL error code and also tells to MySQL about a possible transaction rollback inside InnoDB caused by a lock wait @@ -2170,14 +2151,9 @@ convert_error_code_to_mysql( case DB_DEADLOCK: case DB_RECORD_CHANGED: - /* Since we rolled back the whole transaction, we must - tell it also to MySQL so that MySQL knows to empty the - cached binlog for this transaction */ - - if (thd != NULL) { - thd_mark_transaction_to_rollback(thd, 1); - } - + /* Since we rolled back the whole transaction, the + cached binlog must be emptied. */ + innodb_transaction_abort(thd, true, error); return error == DB_DEADLOCK ? HA_ERR_LOCK_DEADLOCK : HA_ERR_RECORD_CHANGED; @@ -2186,11 +2162,8 @@ convert_error_code_to_mysql( latest SQL statement in a lock wait timeout. Previously, we rolled back the whole transaction. */ - if (thd) { - thd_mark_transaction_to_rollback( - thd, innobase_rollback_on_timeout); - } - + innodb_transaction_abort(thd, innobase_rollback_on_timeout, + error); return(HA_ERR_LOCK_WAIT_TIMEOUT); case DB_NO_REFERENCED_ROW: @@ -2269,9 +2242,6 @@ convert_error_code_to_mysql( (ulong) DICT_MAX_FIELD_LEN_BY_FORMAT_FLAG(flags)); return(HA_ERR_INDEX_COL_TOO_LONG); - case DB_NO_SAVEPOINT: - return(HA_ERR_NO_SAVEPOINT); - case DB_LOCK_TABLE_FULL: /* Since we rolled back the whole transaction, we must tell it also to MySQL so that MySQL knows to empty the @@ -2857,7 +2827,7 @@ Gets the InnoDB transaction handle for a MySQL handler object, creates an InnoDB transaction struct if the corresponding MySQL thread struct still lacks one. @return InnoDB transaction handle */ -static inline +static trx_t* check_trx_exists( /*=============*/ @@ -2915,6 +2885,137 @@ trx_deregister_from_2pc( trx->active_commit_ordered= false; } +/** + Set a transaction savepoint. + + @param thd server thread descriptor + @param savepoint transaction savepoint storage area + + @retval 0 on success + @retval HA_ERR_NO_SAVEPOINT if the transaction is in an inconsistent state +*/ +static int innobase_savepoint(handlerton*, THD *thd, void *savepoint) noexcept +{ + DBUG_ENTER("innobase_savepoint"); + + /* In the autocommit mode there is no sense to set a savepoint + (unless we are in sub-statement), so SQL layer ensures that + this method is never called in such situation. */ + trx_t *trx= check_trx_exists(thd); + + /* Cannot happen outside of transaction */ + DBUG_ASSERT(trx_is_registered_for_2pc(trx)); + + switch (UNIV_EXPECT(trx->state, TRX_STATE_ACTIVE)) { + default: + ut_ad("invalid state" == 0); + DBUG_RETURN(HA_ERR_NO_SAVEPOINT); + case TRX_STATE_NOT_STARTED: + trx_start_if_not_started_xa(trx, false); + /* fall through */ + case TRX_STATE_ACTIVE: + const undo_no_t savept{trx->undo_no}; + *static_cast(savepoint)= savept; + trx->last_stmt_start= savept; + trx->end_bulk_insert(); + + if (trx->fts_trx) + fts_savepoint_take(trx->fts_trx, savepoint); + + DBUG_RETURN(0); + } +} + +/** + Releases a transaction savepoint. + + @param thd server thread descriptor + @param savepoint transaction savepoint to be released + + @return 0 always +*/ +static int innobase_release_savepoint(handlerton*, THD *thd, void *savepoint) + noexcept +{ + DBUG_ENTER("innobase_release_savepoint"); + trx_t *trx= check_trx_exists(thd); + ut_ad(trx->mysql_thd == thd); + if (trx->fts_trx) + fts_savepoint_release(trx, savepoint); + DBUG_RETURN(0); +} + +/** + Frees a possible InnoDB trx object associated with the current THD. + + @param thd server thread descriptor, which resources should be free'd + + @return 0 always +*/ +static int innobase_close_connection(handlerton *, THD *thd) noexcept +{ + if (auto trx= thd_to_trx(thd)) + { + thd_set_ha_data(thd, innodb_hton_ptr, nullptr); + switch (trx->state) { + case TRX_STATE_ABORTED: + trx->state= TRX_STATE_NOT_STARTED; + /* fall through */ + case TRX_STATE_NOT_STARTED: + ut_ad(!trx->id); + trx->will_lock= false; + break; + default: + ut_ad("invalid state" == 0); + return 0; + case TRX_STATE_PREPARED: + if (trx->has_logged_persistent()) + { + trx_disconnect_prepared(trx); + return 0; + } + /* fall through */ + case TRX_STATE_ACTIVE: + /* If we had reserved the auto-inc lock for some table (if + we come here to roll back the latest SQL statement) we + release it now before a possibly lengthy rollback */ + lock_unlock_table_autoinc(trx); + trx_rollback_for_mysql(trx); + } + trx_deregister_from_2pc(trx); + trx->free(); + DEBUG_SYNC(thd, "innobase_connection_closed"); + } + return 0; +} + +/** + XA ROLLBACK after XA PREPARE + + @param xid X/Open XA transaction identification + + @retval 0 if the transaction was found and rolled back + @retval XAER_NOTA if no such transaction exists + @retval XAER_RMFAIL if InnoDB is in read-only mode +*/ +static int innobase_rollback_by_xid(handlerton*, XID *xid) noexcept +{ + DBUG_EXECUTE_IF("innobase_xa_fail", return XAER_RMFAIL;); + if (high_level_read_only) + return XAER_RMFAIL; + if (trx_t *trx= trx_get_trx_by_xid(xid)) + { + ut_ad(trx->xid.is_null()); /* should have been cleared by the lookup */ + trx_deregister_from_2pc(trx); + THD* thd= trx->mysql_thd; + dberr_t err= trx_rollback_for_mysql(trx); + ut_ad(!trx->will_lock); + trx->free(); + return convert_error_code_to_mysql(err, 0, thd); + } + return XAER_NOTA; +} + /*********************************************************************//** Copy table flags from MySQL's HA_CREATE_INFO into an InnoDB table object. Those flags are stored in .frm file and end up in the MySQL table object, @@ -4114,7 +4215,7 @@ static int innodb_init(void* p) innodb_hton_ptr = innobase_hton; innobase_hton->db_type = DB_TYPE_INNODB; - innobase_hton->savepoint_offset = sizeof(trx_named_savept_t); + innobase_hton->savepoint_offset = sizeof(undo_no_t); innobase_hton->close_connection = innobase_close_connection; innobase_hton->kill_query = innobase_kill_query; innobase_hton->savepoint_set = innobase_savepoint; @@ -4190,8 +4291,6 @@ static int innodb_init(void* p) test_filename)); #endif /* DBUG_OFF */ - os_file_set_umask(my_umask); - /* Setup the memory alloc/free tracing mechanisms before calling any functions that could possibly allocate memory. */ ut_new_boot(); @@ -4335,12 +4434,7 @@ innobase_commit_low( tmp = thd_proc_info(trx->mysql_thd, "innobase_commit_low()"); } #endif /* WITH_WSREP */ - if (trx_is_started(trx)) { - trx_commit_for_mysql(trx); - } else { - trx->will_lock = false; - } - + trx_commit_for_mysql(trx); #ifdef WITH_WSREP if (is_wsrep) { thd_proc_info(trx->mysql_thd, tmp); @@ -4371,7 +4465,7 @@ innobase_start_trx_and_assign_read_view( /* The transaction should not be active yet, start it */ - ut_ad(!trx_is_started(trx)); + ut_ad(!trx->is_started()); trx_start_if_not_started_xa(trx, false); @@ -4394,7 +4488,7 @@ innobase_start_trx_and_assign_read_view( /* Set the MySQL flag to mark that there is an active transaction */ - innobase_register_trx(hton, current_thd, trx); + innobase_register_trx(hton, thd, trx); DBUG_RETURN(0); } @@ -4472,7 +4566,7 @@ innobase_commit_ordered( trx = check_trx_exists(thd); - if (!trx_is_registered_for_2pc(trx) && trx_is_started(trx)) { + if (!trx_is_registered_for_2pc(trx) && trx->is_started()) { /* We cannot throw error here; instead we will catch this error again in innobase_commit() and report it from there. */ DBUG_VOID_RETURN; @@ -4492,19 +4586,36 @@ innobase_commit_ordered( /** Mark the end of a statement. @param trx transaction @return whether an error occurred */ -static bool end_of_statement(trx_t *trx) +static bool end_of_statement(trx_t *trx) noexcept { - trx_mark_sql_stat_end(trx); + ut_d(const trx_state_t trx_state{trx->state}); + ut_ad(trx_state == TRX_STATE_ACTIVE || trx_state == TRX_STATE_NOT_STARTED); + + if (trx->fts_trx) + fts_savepoint_laststmt_refresh(trx); + if (trx->is_bulk_insert()) + { + /* Allow a subsequent INSERT into an empty table + if !unique_checks && !foreign_key_checks. */ + + /* MDEV-25036 FIXME: we support buffered insert only for the first + insert statement */ + trx->error_state= trx->bulk_insert_apply(); + } + else + { + trx->last_stmt_start= trx->undo_no; + trx->end_bulk_insert(); + } + if (UNIV_LIKELY(trx->error_state == DB_SUCCESS)) return false; - trx_savept_t savept; - savept.least_undo_no= 0; + undo_no_t savept= 0; trx->rollback(&savept); /* MariaDB will roll back the entire transaction. */ trx->bulk_insert= false; - trx->last_sql_stat_start.least_undo_no= 0; - trx->savepoints_discard(); + trx->last_stmt_start= 0; return true; } @@ -4535,20 +4646,36 @@ innobase_commit( ut_ad(!trx->dict_operation_lock_mode); ut_ad(!trx->dict_operation); - /* Transaction is deregistered only in a commit or a rollback. If - it is deregistered we know there cannot be resources to be freed - and we could return immediately. For the time being, we play safe - and do the cleanup though there should be nothing to clean up. */ - - if (!trx_is_registered_for_2pc(trx) && trx_is_started(trx)) { - - sql_print_error("Transaction not registered for MariaDB 2PC," - " but transaction is active"); + switch (UNIV_EXPECT(trx->state, TRX_STATE_ACTIVE)) { + case TRX_STATE_ABORTED: + trx->state = TRX_STATE_NOT_STARTED; + /* fall through */ + case TRX_STATE_NOT_STARTED: + break; + default: + case TRX_STATE_COMMITTED_IN_MEMORY: + case TRX_STATE_PREPARED_RECOVERED: + ut_ad("invalid state" == 0); + /* fall through */ + case TRX_STATE_PREPARED: + ut_ad(commit_trx); + ut_ad(thd_test_options(thd, OPTION_NOT_AUTOCOMMIT + | OPTION_BEGIN)); + /* fall through */ + case TRX_STATE_ACTIVE: + /* Transaction is deregistered only in a commit or a + rollback. If it is deregistered we know there cannot + be resources to be freed and we could return + immediately. For the time being, we play safe and do + the cleanup though there should be nothing to clean + up. */ + if (!trx_is_registered_for_2pc(trx)) { + sql_print_error("Transaction not registered" + " for MariaDB 2PC," + " but transaction is active"); + } } - bool read_only = trx->read_only || trx->id == 0; - DBUG_PRINT("info", ("readonly: %d", read_only)); - if (commit_trx || (!thd_test_options(thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))) { @@ -4573,17 +4700,7 @@ innobase_commit( } else { /* We just mark the SQL statement ended and do not do a transaction commit */ - - /* If we had reserved the auto-inc lock for some - table in this SQL statement we release it now */ - - if (!read_only) { - lock_unlock_table_autoinc(trx); - } - - /* Store the current undo_no of the transaction so that we - know where to roll back if we have to roll back the next - SQL statement */ + lock_unlock_table_autoinc(trx); if (UNIV_UNLIKELY(end_of_statement(trx))) { DBUG_RETURN(1); } @@ -4605,7 +4722,7 @@ static int innobase_rollback( /*==============*/ - handlerton* hton, /*!< in: InnoDB handlerton */ + handlerton*, THD* thd, /*!< in: handle to the MySQL thread of the user whose transaction should be rolled back */ @@ -4613,74 +4730,79 @@ innobase_rollback( transaction FALSE - rollback the current statement only */ { - DBUG_ENTER("innobase_rollback"); - DBUG_ASSERT(hton == innodb_hton_ptr); - DBUG_PRINT("trans", ("aborting transaction")); + DBUG_ENTER("innobase_rollback"); + DBUG_PRINT("trans", ("aborting transaction")); - trx_t* trx = check_trx_exists(thd); + if (!rollback_trx) + rollback_trx= !thd_test_options(thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN); - ut_ad(!trx->dict_operation_lock_mode); - ut_ad(!trx->dict_operation); + trx_t *trx= check_trx_exists(thd); - /* Reset the number AUTO-INC rows required */ + ut_ad(trx->mysql_thd == thd); + ut_ad(!trx->is_recovered); + ut_ad(!trx->dict_operation_lock_mode); + ut_ad(!trx->dict_operation); - trx->n_autoinc_rows = 0; + /* Reset the number AUTO-INC rows required */ + trx->n_autoinc_rows= 0; + /* This is a statement level variable. */ + trx->fts_next_doc_id= 0; - /* If we had reserved the auto-inc lock for some table (if - we come here to roll back the latest SQL statement) we - release it now before a possibly lengthy rollback */ - lock_unlock_table_autoinc(trx); - - /* This is a statement level variable. */ - - trx->fts_next_doc_id = 0; - - dberr_t error; + const trx_state_t trx_state{trx->state}; + switch (UNIV_EXPECT(trx_state, TRX_STATE_ACTIVE)) { + case TRX_STATE_ABORTED: + if (rollback_trx) + trx->state= TRX_STATE_NOT_STARTED; + /* fall through */ + case TRX_STATE_NOT_STARTED: + ut_ad(!trx->id); + trx->will_lock= false; + if (rollback_trx) + trx_deregister_from_2pc(trx); + DBUG_RETURN(0); + default: + case TRX_STATE_COMMITTED_IN_MEMORY: + case TRX_STATE_PREPARED_RECOVERED: + ut_ad("invalid state" == 0); + /* fall through */ + case TRX_STATE_PREPARED: + ut_ad(rollback_trx); + /* fall through */ + case TRX_STATE_ACTIVE: + /* If we had reserved the auto-inc lock for some table (if + we come here to roll back the latest SQL statement) we + release it now before a possibly lengthy rollback */ + lock_unlock_table_autoinc(trx); #ifdef WITH_WSREP - /* If trx was assigned wsrep XID in prepare phase and the - trx is being rolled back due to BF abort, clear XID in order - to avoid writing it to rollback segment out of order. The XID - will be reassigned when the transaction is replayed. */ - if (trx->state != TRX_STATE_NOT_STARTED - && wsrep_is_wsrep_xid(&trx->xid)) { - trx->xid.null(); - } + /* If trx was assigned wsrep XID in prepare phase and the + trx is being rolled back due to BF abort, clear XID in order + to avoid writing it to rollback segment out of order. The XID + will be reassigned when the transaction is replayed. */ + if (rollback_trx || wsrep_is_wsrep_xid(&trx->xid)) + trx->xid.null(); #endif /* WITH_WSREP */ - if (rollback_trx - || !thd_test_options(thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) { - - error = trx_rollback_for_mysql(trx); - - trx_deregister_from_2pc(trx); - } else { - - error = trx_rollback_last_sql_stat_for_mysql(trx); - } - - DBUG_RETURN(convert_error_code_to_mysql(error, 0, trx->mysql_thd)); -} - -/*****************************************************************//** -Rolls back a transaction -@return 0 or error number */ -static -int -innobase_rollback_trx( -/*==================*/ - trx_t* trx) /*!< in: transaction */ -{ - DBUG_ENTER("innobase_rollback_trx"); - DBUG_PRINT("trans", ("aborting transaction")); - - /* If we had reserved the auto-inc lock for some table (if - we come here to roll back the latest SQL statement) we - release it now before a possibly lengthy rollback */ - lock_unlock_table_autoinc(trx); - trx_deregister_from_2pc(trx); - - DBUG_RETURN(convert_error_code_to_mysql(trx_rollback_for_mysql(trx), - 0, trx->mysql_thd)); + dberr_t error; + if (rollback_trx) + { + error= trx_rollback_for_mysql(trx); + trx_deregister_from_2pc(trx); + } + else + { + ut_a(trx_state == TRX_STATE_ACTIVE); + ut_ad(!trx->is_autocommit_non_locking() || trx->read_only); + error= trx->rollback(&trx->last_stmt_start); + if (trx->fts_trx) + { + fts_savepoint_rollback_last_stmt(trx); + fts_savepoint_laststmt_refresh(trx); + } + trx->last_stmt_start= trx->undo_no; + trx->end_bulk_insert(); + } + DBUG_RETURN(convert_error_code_to_mysql(error, 0, trx->mysql_thd)); + } } /** Invoke commit_checkpoint_notify_ha() on completed log flush requests. @@ -4817,34 +4939,43 @@ static int innobase_rollback_to_savepoint( /*===========================*/ - handlerton* hton, /*!< in: InnoDB handlerton */ + handlerton*, THD* thd, /*!< in: handle to the MySQL thread of the user whose transaction should be rolled back to savepoint */ void* savepoint) /*!< in: savepoint data */ { + DBUG_ENTER("innobase_rollback_to_savepoint"); + trx_t *trx= check_trx_exists(thd); - DBUG_ENTER("innobase_rollback_to_savepoint"); - DBUG_ASSERT(hton == innodb_hton_ptr); + /* We are reading trx->state without holding trx->mutex here, + because the savepoint rollback should be invoked for a running + active transaction that is associated with the current thread. */ + ut_ad(trx->mysql_thd); - trx_t* trx = check_trx_exists(thd); + if (UNIV_UNLIKELY(trx->state != TRX_STATE_ACTIVE)) + { + ut_ad("invalid state" == 0); + DBUG_RETURN(HA_ERR_NO_SAVEPOINT); + } - /* TODO: use provided savepoint data area to store savepoint data */ + const undo_no_t *savept= static_cast(savepoint); - char name[64]; + if (UNIV_UNLIKELY(*savept > trx->undo_no)) + /* row_mysql_handle_errors() should have invoked rollback during + a bulk insert into an empty table. */ + DBUG_RETURN(HA_ERR_NO_SAVEPOINT); - longlong2str(longlong(savepoint), name, 36); - - int64_t mysql_binlog_cache_pos; - - dberr_t error = trx_rollback_to_savepoint_for_mysql( - trx, name, &mysql_binlog_cache_pos); - - if (error == DB_SUCCESS && trx->fts_trx != NULL) { - fts_savepoint_rollback(trx, name); - } - - DBUG_RETURN(convert_error_code_to_mysql(error, 0, NULL)); + dberr_t error= trx->rollback(savept); + /* Store the position for rolling back the next SQL statement */ + if (trx->fts_trx) + { + fts_savepoint_laststmt_refresh(trx); + fts_savepoint_rollback(trx, savept); + } + trx->last_stmt_start= trx->undo_no; + trx->end_bulk_insert(); + DBUG_RETURN(convert_error_code_to_mysql(error, 0, nullptr)); } /*****************************************************************//** @@ -4877,106 +5008,6 @@ innobase_rollback_to_savepoint_can_release_mdl( DBUG_RETURN(false); } -/*****************************************************************//** -Release transaction savepoint name. -@return 0 if success, HA_ERR_NO_SAVEPOINT if no savepoint with the -given name */ -static -int -innobase_release_savepoint( -/*=======================*/ - handlerton* hton, /*!< in: handlerton for InnoDB */ - THD* thd, /*!< in: handle to the MySQL thread - of the user whose transaction's - savepoint should be released */ - void* savepoint) /*!< in: savepoint data */ -{ - dberr_t error; - trx_t* trx; - char name[64]; - - DBUG_ENTER("innobase_release_savepoint"); - DBUG_ASSERT(hton == innodb_hton_ptr); - - trx = check_trx_exists(thd); - - /* TODO: use provided savepoint data area to store savepoint data */ - - longlong2str(longlong(savepoint), name, 36); - - error = trx_release_savepoint_for_mysql(trx, name); - - if (error == DB_SUCCESS && trx->fts_trx != NULL) { - fts_savepoint_release(trx, name); - } - - DBUG_RETURN(convert_error_code_to_mysql(error, 0, NULL)); -} - -/*****************************************************************//** -Sets a transaction savepoint. -@return always 0, that is, always succeeds */ -static -int -innobase_savepoint( -/*===============*/ - handlerton* hton, /*!< in: handle to the InnoDB handlerton */ - THD* thd, /*!< in: handle to the MySQL thread */ - void* savepoint)/*!< in: savepoint data */ -{ - DBUG_ENTER("innobase_savepoint"); - DBUG_ASSERT(hton == innodb_hton_ptr); - - /* In the autocommit mode there is no sense to set a savepoint - (unless we are in sub-statement), so SQL layer ensures that - this method is never called in such situation. */ - - trx_t* trx = check_trx_exists(thd); - - /* Cannot happen outside of transaction */ - DBUG_ASSERT(trx_is_registered_for_2pc(trx)); - - /* TODO: use provided savepoint data area to store savepoint data */ - char name[64]; - - longlong2str(longlong(savepoint), name, 36); - - dberr_t error = trx_savepoint_for_mysql(trx, name, 0); - - if (error == DB_SUCCESS && trx->fts_trx != NULL) { - fts_savepoint_take(trx->fts_trx, name); - } - - DBUG_RETURN(convert_error_code_to_mysql(error, 0, NULL)); -} - - -/** - Frees a possible InnoDB trx object associated with the current THD. - - @param hton innobase handlerton - @param thd server thread descriptor, which resources should be free'd - - @return 0 always -*/ -static int innobase_close_connection(handlerton *hton, THD *thd) -{ - DBUG_ASSERT(hton == innodb_hton_ptr); - if (auto trx= thd_to_trx(thd)) - { - thd_set_ha_data(thd, innodb_hton_ptr, NULL); - if (trx->state == TRX_STATE_PREPARED && trx->has_logged_persistent()) - { - trx_disconnect_prepared(trx); - return 0; - } - innobase_rollback_trx(trx); - trx->free(); - DEBUG_SYNC(thd, "innobase_connection_closed"); - } - return 0; -} - /** Cancel any pending lock request associated with the current THD. @sa THD::awake() @sa ha_kill_query() */ static void innobase_kill_query(handlerton*, THD *thd, enum thd_kill_levels) @@ -7742,26 +7773,35 @@ ha_innobase::innobase_set_max_autoinc( return(error); } -/** @return whether the table is read-only */ -bool ha_innobase::is_read_only(bool altering_to_supported) const +int ha_innobase::is_valid_trx(bool altering_to_supported) const noexcept { ut_ad(m_prebuilt->trx == thd_to_trx(m_user_thd)); if (high_level_read_only) { ib_senderrf(m_user_thd, IB_LOG_LEVEL_WARN, ER_READ_ONLY_MODE); - return true; + return HA_ERR_TABLE_READONLY; } - if (altering_to_supported) - return false; + switch (UNIV_EXPECT(m_prebuilt->trx->state, TRX_STATE_ACTIVE)) { + default: + ut_ad("invalid state" == 0); + /* fall through */ + case TRX_STATE_ABORTED: + break; + case TRX_STATE_NOT_STARTED: + m_prebuilt->trx->will_lock= true; + /* fall through */ + case TRX_STATE_ACTIVE: + if (altering_to_supported || + !DICT_TF_GET_ZIP_SSIZE(m_prebuilt->table->flags) || + !innodb_read_only_compressed) + return 0; - if (!DICT_TF_GET_ZIP_SSIZE(m_prebuilt->table->flags) || - !innodb_read_only_compressed) - return false; - - ib_senderrf(m_user_thd, IB_LOG_LEVEL_WARN, ER_UNSUPPORTED_COMPRESSED_TABLE); - return true; + ib_senderrf(m_user_thd, IB_LOG_LEVEL_WARN, ER_UNSUPPORTED_COMPRESSED_TABLE); + return HA_ERR_TABLE_READONLY; + } + return HA_ERR_ROLLBACK; } /********************************************************************//** @@ -7787,12 +7827,8 @@ ha_innobase::write_row( trx_t* trx = thd_to_trx(m_user_thd); /* Validation checks before we commence write_row operation. */ - if (is_read_only()) { - DBUG_RETURN(HA_ERR_TABLE_READONLY); - } - - if (!trx_is_started(trx)) { - trx->will_lock = true; + if (int err = is_valid_trx()) { + DBUG_RETURN(err); } ins_mode_t vers_set_fields; @@ -8561,10 +8597,8 @@ ha_innobase::update_row( DBUG_ENTER("ha_innobase::update_row"); - if (is_read_only()) { - DBUG_RETURN(HA_ERR_TABLE_READONLY); - } else if (!trx_is_started(trx)) { - trx->will_lock = true; + if (int err = is_valid_trx()) { + DBUG_RETURN(err); } if (m_upd_buf == NULL) { @@ -8682,7 +8716,8 @@ func_exit: if (error == DB_SUCCESS && /* For sequences, InnoDB transaction may not have been started yet. Check THD-level wsrep state in that case. */ - (trx->is_wsrep() || (!trx_is_started(trx) && wsrep_on(m_user_thd))) + (trx->is_wsrep() + || (trx->state == TRX_STATE_NOT_STARTED && wsrep_on(m_user_thd))) && wsrep_thd_is_local(m_user_thd) && !wsrep_thd_ignore_table(m_user_thd) && (thd_sql_command(m_user_thd) != SQLCOM_CREATE_TABLE) @@ -8726,12 +8761,9 @@ ha_innobase::delete_row( DBUG_ENTER("ha_innobase::delete_row"); - if (is_read_only()) { - DBUG_RETURN(HA_ERR_TABLE_READONLY); - } else if (!trx_is_started(trx)) { - trx->will_lock = true; + if (int err = is_valid_trx()) { + DBUG_RETURN(err); } - if (!m_prebuilt->upd_node) { row_get_prebuilt_update_vector(m_prebuilt); } @@ -9008,10 +9040,15 @@ ha_innobase::index_read( DBUG_RETURN(HA_ERR_KEY_NOT_FOUND); } + const trx_state_t trx_state{m_prebuilt->trx->state}; + if (trx_state == TRX_STATE_ABORTED) { + DBUG_RETURN(HA_ERR_ROLLBACK); + } + /* For R-Tree index, we will always place the page lock to pages being searched */ if (index->is_spatial() && !m_prebuilt->trx->will_lock) { - if (trx_is_started(m_prebuilt->trx)) { + if (trx_state != TRX_STATE_NOT_STARTED) { DBUG_RETURN(HA_ERR_READ_ONLY_TRANSACTION); } else { m_prebuilt->trx->will_lock = true; @@ -9285,6 +9322,17 @@ ha_innobase::general_fetch( ut_ad(trx == thd_to_trx(m_user_thd)); + switch (UNIV_EXPECT(trx->state, TRX_STATE_ACTIVE)) { + default: + ut_ad("invalid state" == 0); + /* fall through */ + case TRX_STATE_ABORTED: + DBUG_RETURN(HA_ERR_ROLLBACK); + case TRX_STATE_ACTIVE: + case TRX_STATE_NOT_STARTED: + break; + } + if (m_prebuilt->table->is_readable()) { } else if (m_prebuilt->table->corrupted) { DBUG_RETURN(HA_ERR_CRASHED); @@ -9530,9 +9578,7 @@ ha_innobase::rnd_pos( Initialize FT index scan @return 0 or error number */ -int -ha_innobase::ft_init() -/*==================*/ +int ha_innobase::ft_init() { DBUG_ENTER("ft_init"); @@ -9542,9 +9588,14 @@ ha_innobase::ft_init() This is because the FTS implementation can acquire locks behind the scenes. This has not been verified but it is safer to treat them as regular read only transactions for now. */ - - if (!trx_is_started(trx)) { + switch (trx->state) { + default: + DBUG_RETURN(HA_ERR_ROLLBACK); + case TRX_STATE_ACTIVE: + break; + case TRX_STATE_NOT_STARTED: trx->will_lock = true; + break; } DBUG_RETURN(rnd_init(false)); @@ -9578,11 +9629,9 @@ ha_innobase::ft_init_ext( out.write(key->ptr(), key->length()); } - if (flags & FT_BOOL) { - ib::info() << "BOOL search"; - } else { - ib::info() << "NL search"; - } + sql_print_information((flags & FT_BOOL) + ? "InnoDB: BOOL search" + : "InnoDB: NL search"); } /* Multi byte character sets like utf32 and utf16 are not @@ -9607,8 +9656,17 @@ ha_innobase::ft_init_ext( the scenes. This has not been verified but it is safer to treat them as regular read only transactions for now. */ - if (!trx_is_started(trx)) { + switch (trx->state) { + default: + ut_ad("invalid state" == 0); + my_printf_error(HA_ERR_ROLLBACK, "Invalid tansaction state", + ME_ERROR_LOG); + return nullptr; + case TRX_STATE_ACTIVE: + break; + case TRX_STATE_NOT_STARTED: trx->will_lock = true; + break; } dict_table_t* ft_table = m_prebuilt->table; @@ -13292,12 +13350,8 @@ ha_innobase::discard_or_import_tablespace( DBUG_ENTER("ha_innobase::discard_or_import_tablespace"); - ut_a(m_prebuilt->trx != NULL); - ut_a(m_prebuilt->trx->magic_n == TRX_MAGIC_N); - ut_a(m_prebuilt->trx == thd_to_trx(ha_thd())); - - if (is_read_only()) { - DBUG_RETURN(HA_ERR_TABLE_READONLY); + if (int err = is_valid_trx()) { + DBUG_RETURN(err); } if (m_prebuilt->table->is_temporary()) { @@ -13845,8 +13899,8 @@ int ha_innobase::truncate() } #endif - if (is_read_only()) - DBUG_RETURN(HA_ERR_TABLE_READONLY); + if (int err= is_valid_trx()) + DBUG_RETURN(err); HA_CREATE_INFO info; dict_table_t *ib_table= m_prebuilt->table; @@ -15913,6 +15967,16 @@ ha_innobase::start_stmt( trx = m_prebuilt->trx; + switch (trx->state) { + default: + DBUG_RETURN(HA_ERR_ROLLBACK); + case TRX_STATE_ACTIVE: + break; + case TRX_STATE_NOT_STARTED: + trx->will_lock = true; + break; + } + /* Reset the AUTOINC statement level counter for multi-row INSERTs. */ trx->n_autoinc_rows = 0; @@ -15939,7 +16003,7 @@ ha_innobase::start_stmt( } trx->bulk_insert = false; - trx->last_sql_stat_start.least_undo_no = trx->undo_no; + trx->last_stmt_start = trx->undo_no; } m_prebuilt->sql_stat_start = TRUE; @@ -15997,10 +16061,6 @@ ha_innobase::start_stmt( innobase_register_trx(ht, thd, trx); - if (!trx_is_started(trx)) { - trx->will_lock = true; - } - DBUG_RETURN(0); } @@ -16052,6 +16112,28 @@ ha_innobase::external_lock( trx_t* trx = m_prebuilt->trx; ut_ad(m_prebuilt->table); + const bool not_autocommit = thd_test_options(thd, OPTION_NOT_AUTOCOMMIT + | OPTION_BEGIN); + bool not_started = false; + switch (trx->state) { + default: + case TRX_STATE_PREPARED: + ut_ad("invalid state" == 0); + DBUG_RETURN(HA_ERR_WRONG_COMMAND); + case TRX_STATE_ABORTED: + if (lock_type != F_UNLCK && not_autocommit) { + DBUG_RETURN(HA_ERR_WRONG_COMMAND); + } + /* Reset the state if the transaction had been aborted. */ + trx->state = TRX_STATE_NOT_STARTED; + /* fall through */ + case TRX_STATE_NOT_STARTED: + not_started = true; + break; + case TRX_STATE_ACTIVE: + break; + } + /* Statement based binlogging does not work in isolation level READ UNCOMMITTED and READ COMMITTED since the necessary locks cannot be taken. In this case, we print an @@ -16129,7 +16211,7 @@ ha_innobase::external_lock( break; } trx->bulk_insert = false; - trx->last_sql_stat_start.least_undo_no = trx->undo_no; + trx->last_stmt_start = trx->undo_no; } switch (m_prebuilt->table->quiesce) { @@ -16175,25 +16257,47 @@ ha_innobase::external_lock( break; } - if (lock_type == F_WRLCK) { + switch (lock_type) { + case F_UNLCK: + DEBUG_SYNC_C("ha_innobase_end_statement"); + m_mysql_has_locked = false; + if (--trx->n_mysql_tables_in_use) { + break; + } + + /* If the lock count drops to zero we know that the + current SQL statement has ended */ + trx->mysql_n_tables_locked = 0; + m_prebuilt->used_in_HANDLER = FALSE; + + if (!not_autocommit) { + if (!not_started) { + innobase_commit(ht, thd, TRUE); + } + } else if (trx->isolation_level <= TRX_ISO_READ_COMMITTED) { + trx->read_view.close(); + } + break; + case F_WRLCK: /* If this is a SELECT, then it is in UPDATE TABLE ... or SELECT ... FOR UPDATE */ m_prebuilt->select_lock_type = LOCK_X; m_prebuilt->stored_select_lock_type = LOCK_X; - } - - if (lock_type != F_UNLCK) { - /* MySQL is setting a new table lock */ - + goto set_lock; + case F_RDLCK: + /* Ensure that trx->lock.trx_locks is empty for read-only + autocommit transactions */ + ut_ad(not_autocommit || trx->n_mysql_tables_in_use + || UT_LIST_GET_LEN(trx->lock.trx_locks) == 0); +set_lock: *trx->detailed_error = 0; innobase_register_trx(ht, thd, trx); - if (trx->isolation_level == TRX_ISO_SERIALIZABLE - && m_prebuilt->select_lock_type == LOCK_NONE - && thd_test_options( - thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) { + if (not_autocommit + && trx->isolation_level == TRX_ISO_SERIALIZABLE + && m_prebuilt->select_lock_type == LOCK_NONE) { /* To get serializable execution, we let InnoDB conceptually add 'LOCK IN SHARE MODE' to all SELECTs @@ -16241,42 +16345,12 @@ ha_innobase::external_lock( trx->n_mysql_tables_in_use++; m_mysql_has_locked = true; - if (!trx_is_started(trx) + if (not_started && (m_prebuilt->select_lock_type != LOCK_NONE || m_prebuilt->stored_select_lock_type != LOCK_NONE)) { trx->will_lock = true; } - - DBUG_RETURN(0); - } - - DEBUG_SYNC_C("ha_innobase_end_statement"); - - /* MySQL is releasing a table lock */ - - trx->n_mysql_tables_in_use--; - m_mysql_has_locked = false; - - /* If the MySQL lock count drops to zero we know that the current SQL - statement has ended */ - - if (trx->n_mysql_tables_in_use == 0) { - - trx->mysql_n_tables_locked = 0; - m_prebuilt->used_in_HANDLER = FALSE; - - if (!thd_test_options( - thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) { - - if (trx_is_started(trx)) { - - innobase_commit(ht, thd, TRUE); - } - - } else if (trx->isolation_level <= TRX_ISO_READ_COMMITTED) { - trx->read_view.close(); - } } DBUG_RETURN(0); @@ -16617,14 +16691,6 @@ ha_innobase::store_lock( } m_prebuilt->skip_locked= (lock_type == TL_WRITE_SKIP_LOCKED || lock_type == TL_READ_SKIP_LOCKED); - - if (!trx_is_started(trx) - && (m_prebuilt->select_lock_type != LOCK_NONE - || m_prebuilt->stored_select_lock_type != LOCK_NONE)) { - - trx->will_lock = true; - } - return(to); } @@ -17099,7 +17165,7 @@ static int innobase_xa_prepare( /*================*/ - handlerton* hton, /*!< in: InnoDB handlerton */ + handlerton*, THD* thd, /*!< in: handle to the MySQL thread of the user whose XA transaction should be prepared */ @@ -17107,63 +17173,30 @@ innobase_xa_prepare( false - the current SQL statement ended */ { - trx_t* trx = check_trx_exists(thd); + trx_t *trx= check_trx_exists(thd); + ut_ad(trx_is_registered_for_2pc(trx)); + if (!prepare_trx) + prepare_trx= !thd_test_options(thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN); - DBUG_ASSERT(hton == innodb_hton_ptr); - - thd_get_xid(thd, &reinterpret_cast(trx->xid)); - - if (!trx_is_registered_for_2pc(trx) && trx_is_started(trx)) { - - sql_print_error("Transaction not registered for MariaDB 2PC," - " but transaction is active"); - } - - if (prepare_trx - || (!thd_test_options(thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))) { - - /* We were instructed to prepare the whole transaction, or - this is an SQL statement end and autocommit is on */ - - ut_ad(trx_is_registered_for_2pc(trx)); - - trx_prepare_for_mysql(trx); - } else { - /* We just mark the SQL statement ended and do not do a - transaction prepare */ - - /* If we had reserved the auto-inc lock for some - table in this SQL statement we release it now */ - - lock_unlock_table_autoinc(trx); - - /* Store the current undo_no of the transaction so that we - know where to roll back if we have to roll back the next - SQL statement */ - if (UNIV_UNLIKELY(end_of_statement(trx))) { - return 1; - } - } - - if (thd_sql_command(thd) != SQLCOM_XA_PREPARE - && (prepare_trx - || !thd_test_options( - thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))) { - - /* For mysqlbackup to work the order of transactions in binlog - and InnoDB must be the same. Consider the situation - - thread1> prepare; write to binlog; ... - - thread2> prepare; write to binlog; commit - thread1> ... commit - - The server guarantees that writes to the binary log - and commits are in the same order, so we do not have - to handle this case. */ - } - - return(0); + switch (UNIV_EXPECT(trx->state, TRX_STATE_ACTIVE)) { + default: + ut_ad("invalid state" == 0); + return HA_ERR_GENERIC; + case TRX_STATE_NOT_STARTED: + if (prepare_trx) + trx_start_if_not_started_xa(trx, false);; + /* fall through */ + case TRX_STATE_ACTIVE: + thd_get_xid(thd, &reinterpret_cast(trx->xid)); + if (prepare_trx) + trx_prepare_for_mysql(trx); + else + { + lock_unlock_table_autoinc(trx); + return end_of_statement(trx); + } + return 0; + } } /*******************************************************************//** @@ -17173,12 +17206,10 @@ static int innobase_xa_recover( /*================*/ - handlerton* hton, /*!< in: InnoDB handlerton */ + handlerton*, XID* xid_list,/*!< in/out: prepared transactions */ uint len) /*!< in: number of slots in xid_list */ { - DBUG_ASSERT(hton == innodb_hton_ptr); - if (len == 0 || xid_list == NULL) { return(0); @@ -17221,43 +17252,6 @@ innobase_commit_by_xid( } } -/** This function is used to rollback one X/Open XA distributed transaction -which is in the prepared state - -@param[in] hton InnoDB handlerton -@param[in] xid X/Open XA transaction identification - -@return 0 or error number */ -int innobase_rollback_by_xid(handlerton* hton, XID* xid) -{ - DBUG_ASSERT(hton == innodb_hton_ptr); - - DBUG_EXECUTE_IF("innobase_xa_fail", - return XAER_RMFAIL;); - - if (high_level_read_only) { - return(XAER_RMFAIL); - } - - if (trx_t* trx = trx_get_trx_by_xid(xid)) { -#ifdef WITH_WSREP - /* If a wsrep transaction is being rolled back during - the recovery, we must clear the xid in order to avoid - writing serialisation history for rolled back transaction. */ - if (wsrep_is_wsrep_xid(&trx->xid)) { - trx->xid.null(); - } -#endif /* WITH_WSREP */ - int ret = innobase_rollback_trx(trx); - ut_ad(!trx->will_lock); - trx->free(); - - return(ret); - } else { - return(XAER_NOTA); - } -} - bool ha_innobase::check_if_incompatible_data( /*====================================*/ diff --git a/storage/innobase/handler/ha_innodb.h b/storage/innobase/handler/ha_innodb.h index 671acc3b3ca..534936f8fae 100644 --- a/storage/innobase/handler/ha_innodb.h +++ b/storage/innobase/handler/ha_innodb.h @@ -465,8 +465,13 @@ protected: @see build_template() */ void reset_template(); - /** @return whether the table is read-only */ - bool is_read_only(bool altering_to_supported= false) const; + /** Check the transaction is valid. + @param altering_to_supported whether an ALTER TABLE is being run + to something else than ROW_FORMAT=COMPRESSED + @retval 0 if the transaction is valid for the current operation + @retval HA_ERR_TABLE_READONLY if the table is read-only + @retval HA_ERR_ROLLBACK if the transaction has been aborted */ + int is_valid_trx(bool altering_to_supported= false) const noexcept; inline void update_thd(THD* thd); void update_thd(); @@ -937,12 +942,3 @@ ib_push_frm_error( @return true if index column length exceeds limit */ MY_ATTRIBUTE((warn_unused_result)) bool too_big_key_part_length(size_t max_field_len, const KEY& key); - -/** This function is used to rollback one X/Open XA distributed transaction -which is in the prepared state - -@param[in] hton InnoDB handlerton -@param[in] xid X/Open XA transaction identification - -@return 0 or error number */ -int innobase_rollback_by_xid(handlerton* hton, XID* xid); diff --git a/storage/innobase/handler/handler0alter.cc b/storage/innobase/handler/handler0alter.cc index 61bb2020c9e..3d070ad5693 100644 --- a/storage/innobase/handler/handler0alter.cc +++ b/storage/innobase/handler/handler0alter.cc @@ -2248,7 +2248,7 @@ ha_innobase::check_if_supported_inplace_alter( table->s->table_name.str); } - if (is_read_only(!high_level_read_only + if (is_valid_trx(!high_level_read_only && (ha_alter_info->handler_flags & ALTER_OPTIONS) && ha_alter_info->create_info->key_block_size == 0 && ha_alter_info->create_info->row_type @@ -9170,7 +9170,7 @@ inline bool rollback_inplace_alter_table(Alter_inplace_info *ha_alter_info, /* If we have not started a transaction yet, (almost) nothing has been or needs to be done. */ dict_sys.lock(SRW_LOCK_CALL); - else if (ctx->trx->state == TRX_STATE_NOT_STARTED) + else if (!ctx->trx->is_started()) goto free_and_exit; else if (ctx->new_table) { @@ -11402,7 +11402,7 @@ lock_fail: to remove the newly created table or index from data dictionary and table cache in rollback_inplace_alter_table() */ - if (trx->state == TRX_STATE_NOT_STARTED) { + if (!trx->is_started()) { trx_start_for_ddl(trx); } @@ -11569,7 +11569,7 @@ err_index: purge_sys.resume_FTS(); } - if (trx->state == TRX_STATE_NOT_STARTED) { + if (!trx->is_started()) { /* Transaction may have been rolled back due to a lock wait timeout, deadlock, or a KILL statement. So restart the diff --git a/storage/innobase/handler/i_s.cc b/storage/innobase/handler/i_s.cc index 42d3bfa1fa4..0f00a0d39f9 100644 --- a/storage/innobase/handler/i_s.cc +++ b/storage/innobase/handler/i_s.cc @@ -6268,7 +6268,8 @@ static int i_s_sys_tablespaces_fill_table(THD *thd, TABLE_LIST *tables, Item*) for (fil_space_t &space : fil_system.space_list) { - if (space.purpose == FIL_TYPE_TABLESPACE && !space.is_stopping() && + if (!space.is_temporary() && !space.is_being_imported() && + !space.is_stopping() && space.chain.start) { space.reacquire(); @@ -6497,7 +6498,7 @@ i_s_tablespaces_encryption_fill_table( fil_system.freeze_space_list++; for (fil_space_t& space : fil_system.space_list) { - if (space.purpose == FIL_TYPE_TABLESPACE + if (!space.is_temporary() && !space.is_being_imported() && !space.is_stopping()) { space.reacquire(); mysql_mutex_unlock(&fil_system.mutex); diff --git a/storage/innobase/ibuf/ibuf0ibuf.cc b/storage/innobase/ibuf/ibuf0ibuf.cc index d138a18b272..d90527c0107 100644 --- a/storage/innobase/ibuf/ibuf0ibuf.cc +++ b/storage/innobase/ibuf/ibuf0ibuf.cc @@ -738,13 +738,15 @@ ibuf_set_free_bits_func( mtr.start(); const page_id_t id(block->page.id()); const fil_space_t *space= mtr.set_named_space_id(id.space()); + /* all callers of ibuf_update_free_bits_if_full() or ibuf_reset_free_bits() + check this */ + ut_ad(!space->is_temporary()); if (buf_block_t *bitmap_page= ibuf_bitmap_get_map_page(id, block->zip_size(), &mtr)) { - if (space->purpose != FIL_TYPE_TABLESPACE) + if (space->is_being_imported()) /* IndexPurge may invoke this */ mtr.set_log_mode(MTR_LOG_NO_REDO); - #ifdef UNIV_IBUF_DEBUG if (max_val != ULINT_UNDEFINED) { @@ -925,8 +927,7 @@ ibuf_page_low( return(false); } - compile_time_assert(IBUF_SPACE_ID == 0); - ut_ad(fil_system.sys_space->purpose == FIL_TYPE_TABLESPACE); + static_assert(IBUF_SPACE_ID == 0, "compatiblity"); #ifdef UNIV_DEBUG if (x_latch) { @@ -4505,7 +4506,7 @@ ibuf_print( dberr_t ibuf_check_bitmap_on_import(const trx_t* trx, fil_space_t* space) { ut_ad(trx->mysql_thd); - ut_ad(space->purpose == FIL_TYPE_IMPORT); + ut_ad(space->is_being_imported()); const unsigned zip_size = space->zip_size(); const unsigned physical_size = space->physical_size(); diff --git a/storage/innobase/include/db0err.h b/storage/innobase/include/db0err.h index 960ec3905eb..921cc977e2e 100644 --- a/storage/innobase/include/db0err.h +++ b/storage/innobase/include/db0err.h @@ -68,8 +68,6 @@ enum dberr_t { noticed */ DB_CANNOT_DROP_CONSTRAINT, /*!< dropping a foreign key constraint from a table failed */ - DB_NO_SAVEPOINT, /*!< no savepoint exists with the given - name */ DB_TABLESPACE_EXISTS, /*!< we cannot create a new single-table tablespace because a file of the same name already exists */ diff --git a/storage/innobase/include/fil0fil.h b/storage/innobase/include/fil0fil.h index 5b6312b1815..d9aea31736b 100644 --- a/storage/innobase/include/fil0fil.h +++ b/storage/innobase/include/fil0fil.h @@ -100,16 +100,6 @@ class page_id_t; /** Structure containing encryption specification */ struct fil_space_crypt_t; -/** File types */ -enum fil_type_t { - /** temporary tablespace (temporary undo log or tables) */ - FIL_TYPE_TEMPORARY, - /** a tablespace that is being imported (no logging until finished) */ - FIL_TYPE_IMPORT, - /** persistent tablespace (for system, undo log or tables) */ - FIL_TYPE_TABLESPACE, -}; - struct fil_node_t; /** Structure to store first and last value of range */ @@ -344,39 +334,43 @@ struct fil_space_t final { #ifndef UNIV_INNOCHECKSUM friend fil_node_t; + + /** Constructor; see @fil_space_t::create() */ + inline explicit fil_space_t(uint32_t id, uint32_t flags, bool being_imported, + fil_space_crypt_t *crypt_data) noexcept; + ~fil_space_t() { ut_ad(!latch_owner); latch.destroy(); } - /** fil_system.spaces chain node */ - fil_space_t *hash; - /** LSN of the most recent fil_names_write_if_was_clean(). - Reset to 0 by fil_names_clear(). Protected by exclusive log_sys.latch. - If and only if max_lsn is nonzero, this is in fil_system.named_spaces. */ - lsn_t max_lsn; /** tablespace identifier */ uint32_t id; - fil_type_t purpose;/*!< purpose */ - UT_LIST_BASE_NODE_T(fil_node_t) chain; - /*!< base node for the file chain */ - uint32_t size; /*!< tablespace file size in pages; - 0 if not known yet */ - uint32_t size_in_header; - /* FSP_SIZE in the tablespace header; - 0 if not known yet */ - uint32_t free_len; - /*!< length of the FSP_FREE list */ - uint32_t free_limit; - /*!< contents of FSP_FREE_LIMIT */ - uint32_t recv_size; - /*!< recovered tablespace size in pages; - 0 if no size change was read from the redo log, - or if the size change was implemented */ - uint32_t n_reserved_extents; - /*!< number of reserved free extents for - ongoing operations like B-tree page split */ + + /** fil_system.spaces chain node */ + fil_space_t *hash= nullptr; + /** log_sys.get_lsn() of the most recent fil_names_write_if_was_clean(). + Reset to 0 by fil_names_clear(). Protected by log_sys.mutex. + If and only if this is nonzero, the tablespace will be in named_spaces. */ + lsn_t max_lsn= 0; + /** base node for the chain of data files; multiple entries are + only possible for is_temporary() or id==0 */ + UT_LIST_BASE_NODE_T(fil_node_t) chain; + /** tablespace size in pages; 0 if not determined yet */ + uint32_t size= 0; + /** FSP_SIZE in the tablespace header; 0 if not determined yet */ + uint32_t size_in_header= 0; + /** length of the FSP_FREE list */ + uint32_t free_len= 0; + /** contents of FSP_FREE_LIMIT */ + uint32_t free_limit= 0; + /** recovered tablespace size in pages; 0 if no size change was read + from the redo log, or if the size change was applied */ + uint32_t recv_size= 0; + /** number of reserved free extents for ongoing operations like + B-tree page split */ + uint32_t n_reserved_extents= 0; private: #ifdef UNIV_DEBUG fil_space_t *next_in_space_list(); @@ -387,10 +381,10 @@ private: #endif /** the committed size of the tablespace in pages */ - Atomic_relaxed committed_size; + Atomic_relaxed committed_size{0}; /** Number of pending operations on the file. The tablespace cannot be freed while (n_pending & PENDING) != 0. */ - std::atomic n_pending; + std::atomic n_pending{CLOSING}; /** Flag in n_pending that indicates that the tablespace is about to be deleted, and no further operations should be performed */ static constexpr uint32_t STOPPING_READS= 1U << 31; @@ -412,20 +406,23 @@ private: /** latch protecting all page allocation bitmap pages */ IF_DBUG(srw_lock_debug, srw_lock) latch; /** the thread that holds the exclusive latch, or 0 */ - pthread_t latch_owner; + pthread_t latch_owner= 0; public: /** MariaDB encryption data */ - fil_space_crypt_t *crypt_data; + fil_space_crypt_t *crypt_data= nullptr; /** Whether needs_flush(), or this is in fil_system.unflushed_spaces */ - bool is_in_unflushed_spaces; + bool is_in_unflushed_spaces= false; /** Whether this in fil_system.default_encrypt_tables (needs key rotation) */ - bool is_in_default_encrypt; + bool is_in_default_encrypt= false; private: + /** Whether the tablespace is being imported */ + bool being_imported= false; + /** Whether any corrupton of this tablespace has been reported */ - mutable std::atomic_flag is_corrupted; + mutable std::atomic_flag is_corrupted{false}; public: /** mutex to protect freed_ranges and last_freed_lsn */ @@ -435,11 +432,18 @@ private: range_set freed_ranges; /** LSN of freeing last page; protected by freed_range_mutex */ - lsn_t last_freed_lsn; + lsn_t last_freed_lsn= 0; /** LSN of undo tablespace creation or 0; protected by latch */ - lsn_t create_lsn; + lsn_t create_lsn= 0; public: + /** @return whether this is the temporary tablespace */ + bool is_temporary() const noexcept + { return UNIV_UNLIKELY(id == SRV_TMP_SPACE_ID); } + /** @return whether this tablespace is being imported */ + bool is_being_imported() const noexcept + { return UNIV_UNLIKELY(being_imported); } + /** @return whether doublewrite buffering is needed */ inline bool use_doublewrite() const; @@ -509,7 +513,7 @@ public: MY_ATTRIBUTE((nonnull)); /** Note that the tablespace has been imported. - Initially, purpose=FIL_TYPE_IMPORT so that no redo log is + Initially, purpose=IMPORT so that no redo log is written while the space ID is being updated in each page. */ inline void set_imported(); @@ -886,18 +890,18 @@ public: #ifndef UNIV_INNOCHECKSUM MY_ATTRIBUTE((warn_unused_result)) /** Create a tablespace in fil_system. - @param id tablespace identifier - @param flags tablespace flags - @param purpose tablespace purpose - @param crypt_data encryption information - @param mode encryption mode - @param opened true if space files are opened + @param id tablespace identifier + @param flags tablespace flags + @param being_imported whether this is IMPORT TABLESPACE + @param crypt_data encryption information + @param mode encryption mode + @param opened whether the tablespace files are open @return pointer to created tablespace, to be filled in with add() @retval nullptr on failure (such as when the same tablespace exists) */ - static fil_space_t *create(uint32_t id, uint32_t flags, - fil_type_t purpose, fil_space_crypt_t *crypt_data, + static fil_space_t *create(uint32_t id, uint32_t flags, bool being_imported, + fil_space_crypt_t *crypt_data, fil_encryption_t mode= FIL_ENCRYPTION_DEFAULT, - bool opened= false); + bool opened= false) noexcept; MY_ATTRIBUTE((warn_unused_result)) /** Acquire a tablespace reference. @@ -1018,6 +1022,18 @@ public: /** @return the tablespace name (databasename/tablename) */ name_type name() const; + /** How to validate tablespace files that are being opened */ + enum validate { + /** the file may be missing */ + MAYBE_MISSING= 0, + /** do not validate */ + VALIDATE_NOTHING, + /** validate the tablespace ID */ + VALIDATE_SPACE_ID, + /** opening a file for ALTER TABLE...IMPORT TABLESPACE */ + VALIDATE_IMPORT + }; + private: /** @return whether the file is usable for io() */ ATTRIBUTE_COLD bool prepare_acquired(); @@ -1102,8 +1118,8 @@ inline bool fil_space_t::use_doublewrite() const inline void fil_space_t::set_imported() { - ut_ad(purpose == FIL_TYPE_IMPORT); - purpose= FIL_TYPE_TABLESPACE; + ut_ad(being_imported); + being_imported= false; UT_LIST_GET_FIRST(chain)->find_metadata(); } @@ -1415,7 +1431,8 @@ public: ulint n_open; /** last time we noted n_open exceeding the limit; protected by mutex */ time_t n_open_exceeded_time; - /** maximum persistent tablespace id that has ever been assigned */ + /** maximum space id in the existing tables; on InnoDB startup this is + initialized based on the data dictionary contents */ uint32_t max_assigned_id; /** nonzero if fil_node_open_file_low() should avoid moving the tablespace to the end of space_list, for FIFO policy of try_to_close() */ @@ -1518,7 +1535,7 @@ template inline void fil_space_t::flush() { mysql_mutex_assert_not_owner(&fil_system.mutex); ut_ad(!have_reference || (pending() & PENDING)); - ut_ad(purpose == FIL_TYPE_TABLESPACE || purpose == FIL_TYPE_IMPORT); + ut_ad(!is_temporary()); if (srv_file_flush_method == SRV_O_DIRECT_NO_FSYNC) { ut_ad(!is_in_unflushed_spaces); @@ -1641,7 +1658,7 @@ fil_ibd_create( uint32_t size, fil_encryption_t mode, uint32_t key_id, - dberr_t* err) + dberr_t* err) noexcept MY_ATTRIBUTE((nonnull, warn_unused_result)); /** Try to adjust FSP_SPACE_FLAGS if they differ from the expectations. @@ -1650,43 +1667,28 @@ fil_ibd_create( @param[in] flags desired tablespace flags */ void fsp_flags_try_adjust(fil_space_t *space, uint32_t flags); -/********************************************************************//** +/** Tries to open a single-table tablespace and optionally checks the space id is right in it. If does not succeed, prints an error message to the .err log. This function is used to open a tablespace when we start up mysqld, and also in IMPORT TABLESPACE. -NOTE that we assume this operation is used either at the database startup -or under the protection of dict_sys.latch, so that two users cannot -race here. This operation does not leave the file associated with the -tablespace open, but closes it after we have looked at the space id in it. -If the validate boolean is set, we read the first page of the file and -check that the space id in the file is what we expect. We assume that -this function runs much faster if no check is made, since accessing the -file inode probably is much faster (the OS caches them) than accessing -the first page of the file. This boolean may be initially false, but if -a remote tablespace is found it will be changed to true. +NOTE that we assume this operation is used either at the database +startup or under the protection of MDL, to prevent concurrent access +to the same tablespace. -@param[in] validate 0=maybe missing, 1=do not validate, 2=validate -@param[in] purpose FIL_TYPE_TABLESPACE or FIL_TYPE_TEMPORARY -@param[in] id tablespace ID -@param[in] flags expected FSP_SPACE_FLAGS -@param[in] name table name -If file-per-table, it is the table name in the databasename/tablename format -@param[in] path_in expected filepath, usually read from dictionary -@param[out] err DB_SUCCESS or error code +@param id tablespace identifier +@param flags expected FSP_SPACE_FLAGS +@param validate how to validate files +@param name the table name in databasename/tablename format +@param path_in expected filepath, usually read from dictionary +@param err DB_SUCCESS or error code @return tablespace -@retval NULL if the tablespace could not be opened */ -fil_space_t* -fil_ibd_open( - unsigned validate, - fil_type_t purpose, - uint32_t id, - uint32_t flags, - fil_space_t::name_type name, - const char* path_in, - dberr_t* err = NULL) - MY_ATTRIBUTE((warn_unused_result)); +@retval nullptr if the tablespace could not be opened */ +fil_space_t *fil_ibd_open(uint32_t id, uint32_t flags, + fil_space_t::validate validate, + fil_space_t::name_type name, + const char *path_in, dberr_t *err= nullptr) noexcept; enum fil_load_status { /** The tablespace file(s) were found and valid. */ diff --git a/storage/innobase/include/fts0fts.h b/storage/innobase/include/fts0fts.h index 1d2b409be01..810bfe6966b 100644 --- a/storage/innobase/include/fts0fts.h +++ b/storage/innobase/include/fts0fts.h @@ -201,9 +201,9 @@ struct fts_trx_t { /** Information required for transaction savepoint handling. */ struct fts_savepoint_t { - char* name; /*!< First entry is always NULL, the - default instance. Otherwise the name - of the savepoint */ + const void* name; /*!< First entry is always NULL, the + default instance. Otherwise the + savepoint */ ib_rbt_t* tables; /*!< Modified FTS tables */ }; @@ -666,7 +666,7 @@ void fts_savepoint_take( /*===============*/ fts_trx_t* fts_trx, /*!< in: fts transaction */ - const char* name); /*!< in: savepoint name */ + const void* name); /*!< in: savepoint */ /**********************************************************************//** Refresh last statement savepoint. */ @@ -681,7 +681,7 @@ void fts_savepoint_release( /*==================*/ trx_t* trx, /*!< in: transaction */ - const char* name); /*!< in: savepoint name */ + const void* name); /*!< in: savepoint */ /** Clear cache. @param[in,out] cache fts cache */ @@ -702,7 +702,7 @@ void fts_savepoint_rollback( /*===================*/ trx_t* trx, /*!< in: transaction */ - const char* name); /*!< in: savepoint name */ + const void* name); /*!< in: savepoint */ /*********************************************************************//** Rollback to and including savepoint indentified by name. */ diff --git a/storage/innobase/include/os0file.h b/storage/innobase/include/os0file.h index 62595be6438..11f3f8644f2 100644 --- a/storage/innobase/include/os0file.h +++ b/storage/innobase/include/os0file.h @@ -1052,11 +1052,6 @@ os_file_get_status( bool check_rw_perm, bool read_only); -/** Set the file create umask -@param[in] umask The umask to use for file creation. */ -void -os_file_set_umask(ulint umask); - #ifdef _WIN32 /** diff --git a/storage/innobase/include/row0mysql.h b/storage/innobase/include/row0mysql.h index 878d9c9f1a2..8cbeed7d297 100644 --- a/storage/innobase/include/row0mysql.h +++ b/storage/innobase/include/row0mysql.h @@ -172,7 +172,7 @@ row_mysql_handle_errors( during the function entry */ trx_t* trx, /*!< in: transaction */ que_thr_t* thr, /*!< in: query thread, or NULL */ - trx_savept_t* savept) /*!< in: savepoint, or NULL */ + const undo_no_t*savept) /*!< in: pointer to savepoint, or nullptr */ MY_ATTRIBUTE((nonnull(1,2))); /********************************************************************//** Create a prebuilt struct for a MySQL table handle. diff --git a/storage/innobase/include/trx0roll.h b/storage/innobase/include/trx0roll.h index 9ef9ebe93b2..dd21597b270 100644 --- a/storage/innobase/include/trx0roll.h +++ b/storage/innobase/include/trx0roll.h @@ -74,62 +74,6 @@ trx_rollback_for_mysql( /*===================*/ trx_t* trx) /*!< in/out: transaction */ MY_ATTRIBUTE((nonnull)); -/*******************************************************************//** -Rollback the latest SQL statement for MySQL. -@return error code or DB_SUCCESS */ -dberr_t -trx_rollback_last_sql_stat_for_mysql( -/*=================================*/ - trx_t* trx) /*!< in/out: transaction */ - MY_ATTRIBUTE((nonnull)); -/*******************************************************************//** -Rolls back a transaction back to a named savepoint. Modifications after the -savepoint are undone but InnoDB does NOT release the corresponding locks -which are stored in memory. If a lock is 'implicit', that is, a new inserted -row holds a lock where the lock information is carried by the trx id stored in -the row, these locks are naturally released in the rollback. Savepoints which -were set after this savepoint are deleted. -@return if no savepoint of the name found then DB_NO_SAVEPOINT, -otherwise DB_SUCCESS */ -dberr_t -trx_rollback_to_savepoint_for_mysql( -/*================================*/ - trx_t* trx, /*!< in: transaction handle */ - const char* savepoint_name, /*!< in: savepoint name */ - int64_t* mysql_binlog_cache_pos) /*!< out: the MySQL binlog cache - position corresponding to this - savepoint; MySQL needs this - information to remove the - binlog entries of the queries - executed after the savepoint */ - MY_ATTRIBUTE((nonnull, warn_unused_result)); -/*******************************************************************//** -Creates a named savepoint. If the transaction is not yet started, starts it. -If there is already a savepoint of the same name, this call erases that old -savepoint and replaces it with a new. Savepoints are deleted in a transaction -commit or rollback. -@return always DB_SUCCESS */ -dberr_t -trx_savepoint_for_mysql( -/*====================*/ - trx_t* trx, /*!< in: transaction handle */ - const char* savepoint_name, /*!< in: savepoint name */ - int64_t binlog_cache_pos) /*!< in: MySQL binlog cache - position corresponding to this - connection at the time of the - savepoint */ - MY_ATTRIBUTE((nonnull)); -/*******************************************************************//** -Releases a named savepoint. Savepoints which -were set after this savepoint are deleted. -@return if no savepoint of the name found then DB_NO_SAVEPOINT, -otherwise DB_SUCCESS */ -dberr_t -trx_release_savepoint_for_mysql( -/*============================*/ - trx_t* trx, /*!< in: transaction handle */ - const char* savepoint_name) /*!< in: savepoint name */ - MY_ATTRIBUTE((nonnull, warn_unused_result)); /** Rollback node states */ enum roll_node_state { @@ -144,25 +88,9 @@ enum roll_node_state { struct roll_node_t{ que_common_t common; /*!< node type: QUE_NODE_ROLLBACK */ enum roll_node_state state; /*!< node execution state */ - const trx_savept_t* savept; /*!< savepoint to which to - roll back, in the case of a - partial rollback */ + undo_no_t savept; /*!< savepoint to which to + roll back; 0=entire transaction */ que_thr_t* undo_thr;/*!< undo query graph */ }; -/** A savepoint set with SQL's "SAVEPOINT savepoint_id" command */ -struct trx_named_savept_t{ - char* name; /*!< savepoint name */ - trx_savept_t savept; /*!< the undo number corresponding to - the savepoint */ - int64_t mysql_binlog_cache_pos; - /*!< the MySQL binlog cache position - corresponding to this savepoint, not - defined if the MySQL binlogging is not - enabled */ - UT_LIST_NODE_T(trx_named_savept_t) - trx_savepoints; /*!< the list of savepoints of a - transaction */ -}; - #endif diff --git a/storage/innobase/include/trx0sys.h b/storage/innobase/include/trx0sys.h index 76688f8b396..604441ce030 100644 --- a/storage/innobase/include/trx0sys.h +++ b/storage/innobase/include/trx0sys.h @@ -495,19 +495,7 @@ class rw_trx_hash_t #ifdef UNIV_DEBUG - static void validate_element(trx_t *trx) - { - ut_ad(!trx->read_only || !trx->rsegs.m_redo.rseg); - ut_ad(!trx->is_autocommit_non_locking()); - /* trx->state can be anything except TRX_STATE_NOT_STARTED */ - ut_d(bool acquire_trx_mutex = !trx->mutex_is_owner()); - ut_d(if (acquire_trx_mutex) trx->mutex_lock()); - ut_ad(trx_state_eq(trx, TRX_STATE_ACTIVE) || - trx_state_eq(trx, TRX_STATE_COMMITTED_IN_MEMORY) || - trx_state_eq(trx, TRX_STATE_PREPARED_RECOVERED) || - trx_state_eq(trx, TRX_STATE_PREPARED)); - ut_d(if (acquire_trx_mutex) trx->mutex_unlock()); - } + static void validate_element(trx_t *trx); struct debug_iterator_arg @@ -985,18 +973,23 @@ public: Our IA-32 target is not "i386" but at least "i686", that is, at least Pentium MMX, which has a 64-bit data bus and 64-bit XMM registers. */ + bool hot= false; trx->mutex_lock(); trx_id_t &max_inactive_id= trx->max_inactive_id; - const bool hot{max_inactive_id < id && find_same_or_older(trx, id)}; + if (max_inactive_id >= id); + else if (!find_same_or_older_low(trx, id)) + max_inactive_id= id; + else + hot= true; #else Atomic_relaxed &max_inactive_id= trx->max_inactive_id_atomic; if (max_inactive_id >= id) return false; trx->mutex_lock(); - const bool hot{find_same_or_older(trx, id)}; -#endif - if (hot) + const bool hot{find_same_or_older_low(trx, id)}; + if (!hot) max_inactive_id= id; +#endif trx->mutex_unlock(); return hot; } diff --git a/storage/innobase/include/trx0trx.h b/storage/innobase/include/trx0trx.h index f014cd862e4..ff871478efd 100644 --- a/storage/innobase/include/trx0trx.h +++ b/storage/innobase/include/trx0trx.h @@ -150,19 +150,15 @@ void trx_start_for_ddl_low(trx_t *trx); ut_ad((t)->start_file == 0); \ (t)->start_line = __LINE__; \ (t)->start_file = __FILE__; \ + t->state= TRX_STATE_NOT_STARTED; \ trx_start_for_ddl_low(t); \ } while (0) #else # define trx_start_for_ddl(t) trx_start_for_ddl_low(t) #endif /* UNIV_DEBUG */ -/**********************************************************************//** -Does the transaction commit for MySQL. -@return DB_SUCCESS or error number */ -dberr_t -trx_commit_for_mysql( -/*=================*/ - trx_t* trx); /*!< in/out: transaction */ +/** Commit a transaction */ +void trx_commit_for_mysql(trx_t *trx) noexcept; /** XA PREPARE a transaction. @param[in,out] trx transaction to prepare */ void trx_prepare_for_mysql(trx_t* trx); @@ -185,12 +181,6 @@ trx_t* trx_get_trx_by_xid(const XID* xid); /** Durably write log until trx->commit_lsn (if trx_t::commit_in_memory() was invoked with flush_log_later=true). */ void trx_commit_complete_for_mysql(trx_t *trx); -/**********************************************************************//** -Marks the latest SQL statement ended. */ -void -trx_mark_sql_stat_end( -/*==================*/ - trx_t* trx); /*!< in: trx handle */ /****************************************************************//** Prepares a transaction for commit/rollback. */ void @@ -709,6 +699,7 @@ public: Possible states: TRX_STATE_NOT_STARTED + TRX_STATE_ABORTED TRX_STATE_ACTIVE TRX_STATE_PREPARED TRX_STATE_PREPARED_RECOVERED (special case of TRX_STATE_PREPARED) @@ -718,6 +709,8 @@ public: Regular transactions: * NOT_STARTED -> ACTIVE -> COMMITTED -> NOT_STARTED + * NOT_STARTED -> ABORTED (when thd_mark_transaction_to_rollback() is called) + * ABORTED -> NOT_STARTED (acknowledging the rollback of a transaction) Auto-commit non-locking read-only: * NOT_STARTED -> ACTIVE -> NOT_STARTED @@ -754,16 +747,18 @@ public: do we remove it from the read-only list and put it on the read-write list. During this switch we assign it a rollback segment. - When a transaction is NOT_STARTED, it can be in trx_list. It cannot be - in rw_trx_hash. + When a transaction is NOT_STARTED or ABORTED, it can be in trx_list. + It cannot be in rw_trx_hash. - ACTIVE->PREPARED->COMMITTED is only possible when trx is in rw_trx_hash. - The transition ACTIVE->PREPARED is protected by trx->mutex. + ACTIVE->PREPARED->COMMITTED and ACTIVE->COMMITTED is only possible when + trx is in rw_trx_hash. These transitions are protected by trx_t::mutex. - ACTIVE->COMMITTED is possible when the transaction is in - rw_trx_hash. + COMMITTED->NOT_STARTED is possible when trx_t::mutex is being held. + The transaction would already have been removed from rw_trx_hash by + trx_sys_t::deregister_rw() on the transition to COMMITTED. - Transitions to COMMITTED are protected by trx_t::mutex. */ + Transitions between NOT_STARTED and ABORTED can be performed at any time by + the thread that is associated with the transaction. */ Atomic_relaxed state; /** The locks of the transaction. Protected by lock_sys.latch @@ -779,6 +774,14 @@ public: bool is_wsrep() const { return false; } #endif /* WITH_WSREP */ + /** @return whether the transaction has been started */ + bool is_started() const noexcept + { + static_assert(TRX_STATE_NOT_STARTED == 0, ""); + static_assert(TRX_STATE_ABORTED == 1, ""); + return state > TRX_STATE_ABORTED; + } + /** Consistent read view of the transaction */ ReadView read_view; @@ -885,10 +888,6 @@ public: it is a stored procedure with a COMMIT WORK statement, for instance */ /*------------------------------*/ - UT_LIST_BASE_NODE_T(trx_named_savept_t) - trx_savepoints; /*!< savepoints set with SAVEPOINT ..., - oldest first */ - /*------------------------------*/ undo_no_t undo_no; /*!< next undo log record number to assign; since the undo log is private for a transaction, this @@ -896,7 +895,7 @@ public: with no gaps; thus it represents the number of modified/inserted rows in a transaction */ - trx_savept_t last_sql_stat_start; + undo_no_t last_stmt_start; /*!< undo_no when the last sql statement was started: in case of an error, trx is rolled back down to this number */ @@ -995,16 +994,17 @@ public: void evict_table(table_id_t table_id, bool reset_only= false); /** Initiate rollback. - @param savept savepoint to which to roll back + @param savept pointer to savepoint; nullptr=entire transaction @return error code or DB_SUCCESS */ - dberr_t rollback(trx_savept_t *savept= nullptr); + dberr_t rollback(const undo_no_t *savept= nullptr) noexcept; /** Roll back an active transaction. - @param savept savepoint to which to roll back */ - inline void rollback_low(trx_savept_t *savept= nullptr); + @param savept pointer to savepoint; nullptr=entire transaction + @return error code or DB_SUCCESS */ + dberr_t rollback_low(const undo_no_t *savept= nullptr) noexcept; /** Finish rollback. @return whether the rollback was completed normally @retval false if the rollback was aborted by shutdown */ - inline bool rollback_finish(); + bool rollback_finish() noexcept; private: /** Apply any changes to tables for which online DDL is in progress. */ ATTRIBUTE_COLD void apply_log(); @@ -1014,9 +1014,10 @@ private: @param mtr mini-transaction (if there are any persistent modifications) */ inline void commit_in_memory(const mtr_t *mtr); /** Write log for committing the transaction. */ - void commit_persist(); - /** Clean up the transaction after commit_in_memory() */ - void commit_cleanup(); + void commit_persist() noexcept; + /** Clean up the transaction after commit_in_memory() + @return false (always) */ + bool commit_cleanup() noexcept; /** Commit the transaction in a mini-transaction. @param mtr mini-transaction (if there are any persistent modifications) */ void commit_low(mtr_t *mtr= nullptr); @@ -1031,7 +1032,7 @@ private: inline void write_serialisation_history(mtr_t *mtr); public: /** Commit the transaction. */ - void commit(); + void commit() noexcept; /** Try to drop a persistent table. @param table persistent table @@ -1051,16 +1052,6 @@ public: void commit(std::vector &deleted); - /** Discard all savepoints */ - void savepoints_discard() - { savepoints_discard(UT_LIST_GET_FIRST(trx_savepoints)); } - - - /** Discard all savepoints starting from a particular savepoint. - @param savept first savepoint to discard */ - void savepoints_discard(trx_named_savept_t *savept); - - bool is_referenced() const { return (skip_lock_inheritance_and_n_ref & ~(1U << 31)) > 0; @@ -1201,15 +1192,6 @@ private: trx_rseg_t *assign_temp_rseg(); }; -/** -Check if transaction is started. -@param[in] trx Transaction whose state we need to check -@reutrn true if transaction is in state started */ -inline bool trx_is_started(const trx_t* trx) -{ - return trx->state != TRX_STATE_NOT_STARTED; -} - /* Transaction isolation levels (trx->isolation_level) */ #define TRX_ISO_READ_UNCOMMITTED 0 /* dirty read: non-locking SELECTs are performed so that diff --git a/storage/innobase/include/trx0trx.inl b/storage/innobase/include/trx0trx.inl index b063c920e2f..317f1f5cd0d 100644 --- a/storage/innobase/include/trx0trx.inl +++ b/storage/innobase/include/trx0trx.inl @@ -67,6 +67,8 @@ trx_state_eq( && thd_get_error_number(trx->mysql_thd))); return(true); + case TRX_STATE_ABORTED: + break; } ut_error; #endif /* UNIV_DEBUG */ diff --git a/storage/innobase/include/trx0types.h b/storage/innobase/include/trx0types.h index bfa2adc0115..ecb8ecc023b 100644 --- a/storage/innobase/include/trx0types.h +++ b/storage/innobase/include/trx0types.h @@ -52,6 +52,8 @@ constexpr uint innodb_purge_batch_size_MAX= 5000; /** Transaction states (trx_t::state) */ enum trx_state_t { TRX_STATE_NOT_STARTED, + /** The transaction was aborted (rolled back) due to an error */ + TRX_STATE_ABORTED, TRX_STATE_ACTIVE, /** XA PREPARE has been executed; only XA COMMIT or XA ROLLBACK @@ -59,6 +61,7 @@ enum trx_state_t { TRX_STATE_PREPARED, /** XA PREPARE transaction that was returned to ha_recover() */ TRX_STATE_PREPARED_RECOVERED, + /** The transaction has been committed (or completely rolled back) */ TRX_STATE_COMMITTED_IN_MEMORY }; @@ -76,8 +79,6 @@ struct trx_undo_t; struct roll_node_t; /** Commit command node in a query graph */ struct commit_node_t; -/** SAVEPOINT command node in a query graph */ -struct trx_named_savept_t; /* @} */ /** Row identifier (DB_ROW_ID, DATA_ROW_ID) */ @@ -89,11 +90,6 @@ typedef ib_id_t roll_ptr_t; /** Undo number */ typedef ib_id_t undo_no_t; -/** Transaction savepoint */ -struct trx_savept_t{ - undo_no_t least_undo_no; /*!< least undo number to undo */ -}; - /** File objects */ /* @{ */ /** Undo segment header */ diff --git a/storage/innobase/lock/lock0lock.cc b/storage/innobase/lock/lock0lock.cc index 2392d67bb04..1795852ec94 100644 --- a/storage/innobase/lock/lock0lock.cc +++ b/storage/innobase/lock/lock0lock.cc @@ -6692,23 +6692,19 @@ lock_unlock_table_autoinc( /*======================*/ trx_t* trx) /*!< in/out: transaction */ { - lock_sys.assert_unlocked(); - ut_ad(!trx->mutex_is_owner()); - ut_ad(!trx->lock.wait_lock); + /* This function is invoked for a running transaction by the thread + that is serving the transaction. Therefore it is not necessary to + hold trx->mutex here. */ - /* This can be invoked on NOT_STARTED, ACTIVE, PREPARED, - but not COMMITTED transactions. */ + lock_sys.assert_unlocked(); + ut_ad(!trx->mutex_is_owner()); + ut_ad(!trx->lock.wait_lock); + ut_d(trx_state_t trx_state{trx->state}); + ut_ad(trx_state == TRX_STATE_ACTIVE || trx_state == TRX_STATE_PREPARED || + trx_state == TRX_STATE_NOT_STARTED); - ut_ad(trx_state_eq(trx, TRX_STATE_NOT_STARTED) - || !trx_state_eq(trx, TRX_STATE_COMMITTED_IN_MEMORY)); - - /* This function is invoked for a running transaction by the - thread that is serving the transaction. Therefore it is not - necessary to hold trx->mutex here. */ - - if (lock_trx_holds_autoinc_locks(trx)) { - lock_release_autoinc_locks(trx); - } + if (lock_trx_holds_autoinc_locks(trx)) + lock_release_autoinc_locks(trx); } /** Handle a pending lock wait (DB_LOCK_WAIT) in a semi-consistent read diff --git a/storage/innobase/log/log0recv.cc b/storage/innobase/log/log0recv.cc index cef8317bb67..d581cd3d34c 100644 --- a/storage/innobase/log/log0recv.cc +++ b/storage/innobase/log/log0recv.cc @@ -810,8 +810,8 @@ processed: if (crypt_data && !fil_crypt_check(crypt_data, name.c_str())) return nullptr; mysql_mutex_lock(&fil_system.mutex); - fil_space_t *space= fil_space_t::create(it->first, flags, - FIL_TYPE_TABLESPACE, crypt_data); + fil_space_t *space= fil_space_t::create(it->first, flags, false, + crypt_data); ut_ad(space); const char *filename= name.c_str(); if (srv_operation == SRV_OPERATION_RESTORE) @@ -917,8 +917,8 @@ deferred_spaces; @param[in] new_name new file name (NULL if not rename) @param[in] new_len length of new_name, in bytes (0 if NULL) */ void (*log_file_op)(uint32_t space_id, int type, - const byte* name, ulint len, - const byte* new_name, ulint new_len); + const byte* name, size_t len, + const byte* new_name, size_t new_len); void (*undo_space_trunc)(uint32_t space_id); @@ -4331,7 +4331,7 @@ next: recv_spaces_t::iterator i = recv_spaces.find(space); ut_ad(i != recv_spaces.end()); - if (deferred_spaces.find(static_cast(space))) { + if (deferred_spaces.find(space)) { /* Skip redo logs belonging to incomplete tablespaces */ goto next; diff --git a/storage/innobase/mtr/mtr0mtr.cc b/storage/innobase/mtr/mtr0mtr.cc index 1b1877e0a86..d2ec3b1d8dc 100644 --- a/storage/innobase/mtr/mtr0mtr.cc +++ b/storage/innobase/mtr/mtr0mtr.cc @@ -834,8 +834,7 @@ fil_space_t *mtr_t::x_lock_space(uint32_t space_id) } else { space = fil_space_get(space_id); ut_ad(m_log_mode != MTR_LOG_NO_REDO - || space->purpose == FIL_TYPE_TEMPORARY - || space->purpose == FIL_TYPE_IMPORT); + || space->is_temporary() || space->is_being_imported()); } ut_ad(space); @@ -848,9 +847,6 @@ fil_space_t *mtr_t::x_lock_space(uint32_t space_id) @param space tablespace */ void mtr_t::x_lock_space(fil_space_t *space) { - ut_ad(space->purpose == FIL_TYPE_TEMPORARY || - space->purpose == FIL_TYPE_IMPORT || - space->purpose == FIL_TYPE_TABLESPACE); if (!memo_contains(*space)) { memo_push(space, MTR_MEMO_SPACE_X_LOCK); diff --git a/storage/innobase/os/os0file.cc b/storage/innobase/os/os0file.cc index f49c6ae7c04..34da710ee65 100644 --- a/storage/innobase/os/os0file.cc +++ b/storage/innobase/os/os0file.cc @@ -152,18 +152,6 @@ static io_slots *write_slots; /** Number of retries for partial I/O's */ constexpr ulint NUM_RETRIES_ON_PARTIAL_IO = 10; -/* This specifies the file permissions InnoDB uses when it creates files in -Unix; the value of os_innodb_umask is initialized in ha_innodb.cc to -my_umask */ - -#ifndef _WIN32 -/** Umask for creating files */ -static ulint os_innodb_umask = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP; -#else -/** Umask for creating files */ -static ulint os_innodb_umask = 0; -#endif /* _WIN32 */ - Atomic_counter os_n_file_reads; static ulint os_bytes_read_since_printout; Atomic_counter os_n_file_writes; @@ -1021,7 +1009,7 @@ os_file_create_simple_func( #endif do { - file = open(name, create_flag | direct_flag, os_innodb_umask); + file = open(name, create_flag | direct_flag, my_umask); if (file == -1) { #ifdef O_DIRECT @@ -1243,7 +1231,7 @@ skip_o_direct: os_file_t file; for (;;) { - file = open(name, create_flag | direct_flag, os_innodb_umask); + file = open(name, create_flag | direct_flag, my_umask); if (file == -1) { #ifdef O_DIRECT @@ -1365,7 +1353,7 @@ os_file_create_simple_no_error_handling_func( } } - file = open(name, create_flag, os_innodb_umask); + file = open(name, create_flag, my_umask); *success = (file != -1); @@ -3645,16 +3633,6 @@ os_aio_refresh_stats() os_last_printout = time(NULL); } - -/** -Set the file create umask -@param[in] umask The umask to use for file creation. */ -void -os_file_set_umask(ulint umask) -{ - os_innodb_umask = umask; -} - #ifdef _WIN32 /* Checks whether physical drive is on SSD.*/ @@ -3819,13 +3797,19 @@ void fil_node_t::find_metadata(IF_WIN(,bool create)) noexcept punch_hole= 2; else punch_hole= IF_WIN(, !create ||) os_is_sparse_file_supported(file); - if (space->purpose != FIL_TYPE_TABLESPACE) + /* For temporary tablespace or during IMPORT TABLESPACE, we + disable neighbour flushing and do not care about atomicity. */ + if (space->is_temporary()) { - /* For temporary tablespace or during IMPORT TABLESPACE, we - disable neighbour flushing and do not care about atomicity. */ on_ssd= true; atomic_write= true; - if (space->purpose == FIL_TYPE_TEMPORARY || !space->is_compressed()) + return; + } + if (space->is_being_imported()) + { + on_ssd= true; + atomic_write= true; + if (!space->is_compressed()) return; } #ifdef _WIN32 diff --git a/storage/innobase/que/que0que.cc b/storage/innobase/que/que0que.cc index 5e1e0686c97..81d93505d70 100644 --- a/storage/innobase/que/que0que.cc +++ b/storage/innobase/que/que0que.cc @@ -514,8 +514,7 @@ que_thr_step( for_step(thr); } else if (type == QUE_NODE_PROC) { if (thr->prev_node == que_node_get_parent(node)) { - trx->last_sql_stat_start.least_undo_no - = trx->undo_no; + trx->last_stmt_start = trx->undo_no; } proc_step(thr); diff --git a/storage/innobase/row/row0import.cc b/storage/innobase/row/row0import.cc index 72111ea3676..7035c33ccf4 100644 --- a/storage/innobase/row/row0import.cc +++ b/storage/innobase/row/row0import.cc @@ -4823,9 +4823,10 @@ import_error: we will not be writing any redo log for it before we have invoked fil_space_t::set_imported() to declare it a persistent tablespace. */ - table->space = fil_ibd_open( - 2, FIL_TYPE_IMPORT, table->space_id, - dict_tf_to_fsp_flags(table->flags), name, filepath, &err); + table->space = fil_ibd_open(table->space_id, + dict_tf_to_fsp_flags(table->flags), + fil_space_t::VALIDATE_IMPORT, + name, filepath, &err); ut_ad((table->space == NULL) == (err != DB_SUCCESS)); DBUG_EXECUTE_IF("ib_import_open_tablespace_failure", @@ -4927,8 +4928,6 @@ import_error: } ib::info() << "Phase IV - Flush complete"; - /* Set tablespace purpose as FIL_TYPE_TABLESPACE, - so that rollback can go ahead smoothly */ table->space->set_imported(); err = lock_sys_tables(trx); diff --git a/storage/innobase/row/row0merge.cc b/storage/innobase/row/row0merge.cc index b4f260c3ab0..944ca66aeb3 100644 --- a/storage/innobase/row/row0merge.cc +++ b/storage/innobase/row/row0merge.cc @@ -5374,8 +5374,7 @@ void trx_t::bulk_rollback_low() t.second.end_bulk_insert(); } } - trx_savept_t bulk_save{low_limit}; - rollback(&bulk_save); + rollback(&low_limit); } dberr_t trx_t::bulk_insert_apply_low() diff --git a/storage/innobase/row/row0mysql.cc b/storage/innobase/row/row0mysql.cc index 2702ab763b8..b51f3b54900 100644 --- a/storage/innobase/row/row0mysql.cc +++ b/storage/innobase/row/row0mysql.cc @@ -625,7 +625,7 @@ row_mysql_handle_errors( function */ trx_t* trx, /*!< in: transaction */ que_thr_t* thr, /*!< in: query thread, or NULL */ - trx_savept_t* savept) /*!< in: savepoint, or NULL */ + const undo_no_t*savept) /*!< in: pointer to savepoint, or nullptr */ { dberr_t err; @@ -681,8 +681,7 @@ handle_new_error: } /* MariaDB will roll back the entire transaction. */ trx->bulk_insert = false; - trx->last_sql_stat_start.least_undo_no = 0; - trx->savepoints_discard(); + trx->last_stmt_start = 0; break; case DB_LOCK_WAIT: err = lock_wait(thr); @@ -700,7 +699,6 @@ handle_new_error: rollback: /* Roll back the whole transaction; this resolution was added to version 3.23.43 */ - trx->rollback(); break; @@ -1137,7 +1135,7 @@ row_lock_table_autoinc_for_mysql( trx->error_state = err; } while (err != DB_SUCCESS - && row_mysql_handle_errors(&err, trx, thr, NULL)); + && row_mysql_handle_errors(&err, trx, thr, nullptr)); trx->op_info = ""; @@ -1179,7 +1177,7 @@ row_lock_table(row_prebuilt_t* prebuilt) prebuilt->select_lock_type), thr); trx->error_state = err; } while (err != DB_SUCCESS - && row_mysql_handle_errors(&err, trx, thr, NULL)); + && row_mysql_handle_errors(&err, trx, thr, nullptr)); trx->op_info = ""; @@ -1218,7 +1216,6 @@ row_insert_for_mysql( row_prebuilt_t* prebuilt, ins_mode_t ins_mode) { - trx_savept_t savept; que_thr_t* thr; dberr_t err; ibool was_lock_wait; @@ -1272,7 +1269,7 @@ row_insert_for_mysql( roll back to the start of the transaction. For correctness, it would suffice to roll back to the start of the first insert into this empty table, but we will keep it simple and efficient. */ - savept.least_undo_no = trx->bulk_insert ? 0 : trx->undo_no; + const undo_no_t savept{trx->bulk_insert ? 0 : trx->undo_no}; thr = que_fork_get_first_thr(prebuilt->ins_graph); @@ -1580,7 +1577,6 @@ init_fts_doc_id_for_ref( dberr_t row_update_for_mysql(row_prebuilt_t* prebuilt) { - trx_savept_t savept; dberr_t err; que_thr_t* thr; dict_index_t* clust_index; @@ -1637,7 +1633,7 @@ row_update_for_mysql(row_prebuilt_t* prebuilt) generated for the table: MySQL does not know anything about the row id used as the clustered index key */ - savept.least_undo_no = trx->undo_no; + undo_no_t savept = trx->undo_no; thr = que_fork_get_first_thr(prebuilt->upd_graph); diff --git a/storage/innobase/row/row0sel.cc b/storage/innobase/row/row0sel.cc index 5931dbef09d..3aed08698f0 100644 --- a/storage/innobase/row/row0sel.cc +++ b/storage/innobase/row/row0sel.cc @@ -1207,8 +1207,7 @@ re_scan: mtr->commit(); trx->error_state = err; thr->lock_state = QUE_THR_LOCK_ROW; - if (row_mysql_handle_errors( - &err, trx, thr, NULL)) { + if (row_mysql_handle_errors(&err, trx, thr, 0)) { thr->lock_state = QUE_THR_LOCK_NOLOCK; mtr->start(); @@ -5869,7 +5868,7 @@ lock_table_wait: trx->error_state = err; thr->lock_state = QUE_THR_LOCK_ROW; - if (row_mysql_handle_errors(&err, trx, thr, NULL)) { + if (row_mysql_handle_errors(&err, trx, thr, nullptr)) { /* It was a lock wait, and it ended */ thr->lock_state = QUE_THR_LOCK_NOLOCK; diff --git a/storage/innobase/srv/srv0start.cc b/storage/innobase/srv/srv0start.cc index 13d73e101d1..c63534d611f 100644 --- a/storage/innobase/srv/srv0start.cc +++ b/storage/innobase/srv/srv0start.cc @@ -714,8 +714,7 @@ err_exit: fil_set_max_space_id_if_bigger(space_id); mysql_mutex_lock(&fil_system.mutex); - fil_space_t *space= fil_space_t::create(space_id, fsp_flags, - FIL_TYPE_TABLESPACE, nullptr, + fil_space_t *space= fil_space_t::create(space_id, fsp_flags, false, nullptr, FIL_ENCRYPTION_DEFAULT, true); ut_ad(space); fil_node_t *file= space->add(name, fh, 0, false, true); diff --git a/storage/innobase/trx/trx0i_s.cc b/storage/innobase/trx/trx0i_s.cc index 4a661c51183..c1784b94bb1 100644 --- a/storage/innobase/trx/trx0i_s.cc +++ b/storage/innobase/trx/trx0i_s.cc @@ -1054,7 +1054,7 @@ static void fetch_data_into_cache(trx_i_s_cache_t *cache) &trx != (purge_sys.query ? purge_sys.query->trx : nullptr)) { trx.mutex_lock(); - if (trx.state != TRX_STATE_NOT_STARTED) + if (trx.is_started()) fetch_data_into_cache_low(cache, &trx); trx.mutex_unlock(); } diff --git a/storage/innobase/trx/trx0roll.cc b/storage/innobase/trx/trx0roll.cc index fd88caa84d0..87d8e0c187f 100644 --- a/storage/innobase/trx/trx0roll.cc +++ b/storage/innobase/trx/trx0roll.cc @@ -43,6 +43,7 @@ Created 3/26/1996 Heikki Tuuri #include "trx0sys.h" #include "trx0trx.h" #include "trx0undo.h" +#include "log.h" #ifdef UNIV_PFS_THREAD mysql_pfs_key_t trx_rollback_clean_thread_key; @@ -54,10 +55,7 @@ bool trx_rollback_is_active; /** In crash recovery, the current trx to be rolled back; NULL otherwise */ const trx_t* trx_roll_crash_recv_trx; -/** Finish transaction rollback. -@return whether the rollback was completed normally -@retval false if the rollback was aborted by shutdown */ -inline bool trx_t::rollback_finish() +bool trx_t::rollback_finish() noexcept { apply_online_log= false; if (UNIV_LIKELY(error_state == DB_SUCCESS)) @@ -84,34 +82,28 @@ inline bool trx_t::rollback_finish() undo= nullptr; } commit_low(); - commit_cleanup(); - return false; + return commit_cleanup(); } -/** Roll back an active transaction. */ -inline void trx_t::rollback_low(trx_savept_t *savept) +dberr_t trx_t::rollback_low(const undo_no_t *savept) noexcept { + op_info= "rollback"; mem_heap_t *heap= mem_heap_create(512); roll_node_t *roll_node= roll_node_create(heap); - roll_node->savept= savept; + + roll_node->savept= savept ? *savept : 0; ut_ad(!in_rollback); #ifdef UNIV_DEBUG + if (savept) { - const auto s= state; - ut_ad(s == TRX_STATE_ACTIVE || - s == TRX_STATE_PREPARED || - s == TRX_STATE_PREPARED_RECOVERED); - if (savept) - { - ut_ad(s == TRX_STATE_ACTIVE); - ut_ad(mysql_thd); - ut_ad(!is_recovered); - } + ut_ad(state == TRX_STATE_ACTIVE); + ut_ad(mysql_thd); + ut_ad(!is_recovered); } #endif - error_state = DB_SUCCESS; + error_state= DB_SUCCESS; if (has_logged()) { @@ -138,7 +130,7 @@ inline void trx_t::rollback_low(trx_savept_t *savept) victim. Galera transaction abort can be invoked during partial rollback. */ ut_ad(!(lock.was_chosen_as_deadlock_victim & 1)); ut_a(error_state == DB_SUCCESS); - const undo_no_t limit= savept->least_undo_no; + const undo_no_t limit{*savept}; apply_online_log= false; for (trx_mod_tables_t::iterator i= mod_tables.begin(); i != mod_tables.end(); ) @@ -157,49 +149,34 @@ inline void trx_t::rollback_low(trx_savept_t *savept) } mem_heap_free(heap); + op_info= ""; + return error_state; } -/** Initiate rollback. -@param savept savepoint -@return error code or DB_SUCCESS */ -dberr_t trx_t::rollback(trx_savept_t *savept) +dberr_t trx_t::rollback(const undo_no_t *savept) noexcept { ut_ad(!mutex_is_owner()); - if (state == TRX_STATE_NOT_STARTED) - { + switch (state) { + case TRX_STATE_ABORTED: + ut_ad(!savept); + state= TRX_STATE_NOT_STARTED; + /* fall through */ + case TRX_STATE_NOT_STARTED: error_state= DB_SUCCESS; return DB_SUCCESS; + case TRX_STATE_PREPARED: + case TRX_STATE_PREPARED_RECOVERED: + case TRX_STATE_COMMITTED_IN_MEMORY: + ut_ad("invalid state" == 0); + /* fall through */ + case TRX_STATE_ACTIVE: + break; } - ut_ad(state == TRX_STATE_ACTIVE); #ifdef WITH_WSREP if (!savept && is_wsrep() && wsrep_thd_is_SR(mysql_thd)) wsrep_handle_SR_rollback(nullptr, mysql_thd); #endif /* WITH_WSREP */ - rollback_low(savept); - return error_state; -} - -/*******************************************************************//** -Rollback a transaction used in MySQL. -@return error code or DB_SUCCESS */ -static -dberr_t -trx_rollback_for_mysql_low( -/*=======================*/ - trx_t* trx) /*!< in/out: transaction */ -{ - trx->op_info = "rollback"; - - /* If we are doing the XA recovery of prepared transactions, - then the transaction object does not have an InnoDB session - object, and we set a dummy session that we use for all MySQL - transactions. */ - - trx->rollback_low(); - - trx->op_info = ""; - - return(trx->error_state); + return rollback_low(savept); } /** Rollback a transaction used in MySQL @@ -213,6 +190,9 @@ dberr_t trx_rollback_for_mysql(trx_t* trx) that is associated with the current thread. */ switch (trx->state) { + case TRX_STATE_ABORTED: + trx->state = TRX_STATE_NOT_STARTED; + /* fall through */ case TRX_STATE_NOT_STARTED: trx->will_lock = false; ut_ad(trx->mysql_thd); @@ -224,13 +204,13 @@ dberr_t trx_rollback_for_mysql(trx_t* trx) ut_ad(!trx->is_wsrep()); trx->lock.was_chosen_as_deadlock_victim= false; #endif + ut_a(UT_LIST_GET_LEN(trx->lock.trx_locks) == 0); return(DB_SUCCESS); - case TRX_STATE_ACTIVE: ut_ad(trx->mysql_thd); ut_ad(!trx->is_recovered); ut_ad(!trx->is_autocommit_non_locking() || trx->read_only); - return(trx_rollback_for_mysql_low(trx)); + return trx->rollback_low(); case TRX_STATE_PREPARED: case TRX_STATE_PREPARED_RECOVERED: @@ -268,7 +248,7 @@ dberr_t trx_rollback_for_mysql(trx_t* trx) mtr.commit(); ut_ad(mtr.commit_lsn() > 0); } - return(trx_rollback_for_mysql_low(trx)); + return trx->rollback_low(); case TRX_STATE_COMMITTED_IN_MEMORY: ut_ad(!trx->is_autocommit_non_locking()); @@ -279,296 +259,6 @@ dberr_t trx_rollback_for_mysql(trx_t* trx) return(DB_CORRUPTION); } -/*******************************************************************//** -Rollback the latest SQL statement for MySQL. -@return error code or DB_SUCCESS */ -dberr_t -trx_rollback_last_sql_stat_for_mysql( -/*=================================*/ - trx_t* trx) /*!< in/out: transaction */ -{ - dberr_t err; - - /* We are reading trx->state without holding trx->mutex - here, because the statement rollback should be invoked for a - running active MySQL transaction that is associated with the - current thread. */ - ut_ad(trx->mysql_thd); - - switch (trx->state) { - case TRX_STATE_NOT_STARTED: - return(DB_SUCCESS); - - case TRX_STATE_ACTIVE: - ut_ad(trx->mysql_thd); - ut_ad(!trx->is_recovered); - ut_ad(!trx->is_autocommit_non_locking() || trx->read_only); - - trx->op_info = "rollback of SQL statement"; - - err = trx->rollback(&trx->last_sql_stat_start); - - if (trx->fts_trx != NULL) { - fts_savepoint_rollback_last_stmt(trx); - fts_savepoint_laststmt_refresh(trx); - } - - trx->last_sql_stat_start.least_undo_no = trx->undo_no; - trx->end_bulk_insert(); - - trx->op_info = ""; - - return(err); - - case TRX_STATE_PREPARED: - case TRX_STATE_PREPARED_RECOVERED: - case TRX_STATE_COMMITTED_IN_MEMORY: - /* The statement rollback is only allowed on an ACTIVE - transaction, not a PREPARED or COMMITTED one. */ - break; - } - - ut_error; - return(DB_CORRUPTION); -} - -/*******************************************************************//** -Search for a savepoint using name. -@return savepoint if found else NULL */ -static -trx_named_savept_t* -trx_savepoint_find( -/*===============*/ - trx_t* trx, /*!< in: transaction */ - const char* name) /*!< in: savepoint name */ -{ - trx_named_savept_t* savep; - - for (savep = UT_LIST_GET_FIRST(trx->trx_savepoints); - savep != NULL; - savep = UT_LIST_GET_NEXT(trx_savepoints, savep)) { - if (!strcmp(savep->name, name)) { - return(savep); - } - } - - return(NULL); -} - -/*******************************************************************//** -Frees a single savepoint struct. */ -static -void -trx_roll_savepoint_free( -/*=====================*/ - trx_t* trx, /*!< in: transaction handle */ - trx_named_savept_t* savep) /*!< in: savepoint to free */ -{ - UT_LIST_REMOVE(trx->trx_savepoints, savep); - - ut_free(savep->name); - ut_free(savep); -} - -/** Discard all savepoints starting from a particular savepoint. -@param savept first savepoint to discard */ -void trx_t::savepoints_discard(trx_named_savept_t *savept) -{ - while (savept) - { - auto next= UT_LIST_GET_NEXT(trx_savepoints, savept); - trx_roll_savepoint_free(this, savept); - savept= next; - } -} - -/*******************************************************************//** -Rolls back a transaction back to a named savepoint. Modifications after the -savepoint are undone but InnoDB does NOT release the corresponding locks -which are stored in memory. If a lock is 'implicit', that is, a new inserted -row holds a lock where the lock information is carried by the trx id stored in -the row, these locks are naturally released in the rollback. Savepoints which -were set after this savepoint are deleted. -@return if no savepoint of the name found then DB_NO_SAVEPOINT, -otherwise DB_SUCCESS */ -static MY_ATTRIBUTE((nonnull, warn_unused_result)) -dberr_t -trx_rollback_to_savepoint_for_mysql_low( -/*====================================*/ - trx_t* trx, /*!< in/out: transaction */ - trx_named_savept_t* savep, /*!< in/out: savepoint */ - int64_t* mysql_binlog_cache_pos) - /*!< out: the MySQL binlog - cache position corresponding - to this savepoint; MySQL needs - this information to remove the - binlog entries of the queries - executed after the savepoint */ -{ - dberr_t err; - - ut_ad(trx_state_eq(trx, TRX_STATE_ACTIVE)); - ut_ad(trx->mysql_thd); - - /* Free all savepoints strictly later than savep. */ - - trx->savepoints_discard(UT_LIST_GET_NEXT(trx_savepoints, savep)); - - *mysql_binlog_cache_pos = savep->mysql_binlog_cache_pos; - - trx->op_info = "rollback to a savepoint"; - - err = trx->rollback(&savep->savept); - - /* Store the current undo_no of the transaction so that - we know where to roll back if we have to roll back the - next SQL statement: */ - - trx_mark_sql_stat_end(trx); - - trx->op_info = ""; - return(err); -} - -/*******************************************************************//** -Rolls back a transaction back to a named savepoint. Modifications after the -savepoint are undone but InnoDB does NOT release the corresponding locks -which are stored in memory. If a lock is 'implicit', that is, a new inserted -row holds a lock where the lock information is carried by the trx id stored in -the row, these locks are naturally released in the rollback. Savepoints which -were set after this savepoint are deleted. -@return if no savepoint of the name found then DB_NO_SAVEPOINT, -otherwise DB_SUCCESS */ -dberr_t -trx_rollback_to_savepoint_for_mysql( -/*================================*/ - trx_t* trx, /*!< in: transaction handle */ - const char* savepoint_name, /*!< in: savepoint name */ - int64_t* mysql_binlog_cache_pos) /*!< out: the MySQL binlog cache - position corresponding to this - savepoint; MySQL needs this - information to remove the - binlog entries of the queries - executed after the savepoint */ -{ - trx_named_savept_t* savep; - - /* We are reading trx->state without holding trx->mutex - here, because the savepoint rollback should be invoked for a - running active MySQL transaction that is associated with the - current thread. */ - ut_ad(trx->mysql_thd); - - savep = trx_savepoint_find(trx, savepoint_name); - - if (savep == NULL) { - return(DB_NO_SAVEPOINT); - } - - switch (trx->state) { - case TRX_STATE_NOT_STARTED: - ib::error() << "Transaction has a savepoint " - << savep->name - << " though it is not started"; - return(DB_ERROR); - - case TRX_STATE_ACTIVE: - - return(trx_rollback_to_savepoint_for_mysql_low( - trx, savep, mysql_binlog_cache_pos)); - - case TRX_STATE_PREPARED: - case TRX_STATE_PREPARED_RECOVERED: - case TRX_STATE_COMMITTED_IN_MEMORY: - /* The savepoint rollback is only allowed on an ACTIVE - transaction, not a PREPARED or COMMITTED one. */ - break; - } - - ut_error; - return(DB_CORRUPTION); -} - -/*******************************************************************//** -Creates a named savepoint. If the transaction is not yet started, starts it. -If there is already a savepoint of the same name, this call erases that old -savepoint and replaces it with a new. Savepoints are deleted in a transaction -commit or rollback. -@return always DB_SUCCESS */ -dberr_t -trx_savepoint_for_mysql( -/*====================*/ - trx_t* trx, /*!< in: transaction handle */ - const char* savepoint_name, /*!< in: savepoint name */ - int64_t binlog_cache_pos) /*!< in: MySQL binlog cache - position corresponding to this - connection at the time of the - savepoint */ -{ - trx_named_savept_t* savep; - - trx_start_if_not_started_xa(trx, false); - - savep = trx_savepoint_find(trx, savepoint_name); - - if (savep) { - /* There is a savepoint with the same name: free that */ - - UT_LIST_REMOVE(trx->trx_savepoints, savep); - - ut_free(savep->name); - ut_free(savep); - } - - /* Create a new savepoint and add it as the last in the list */ - - savep = static_cast( - ut_malloc_nokey(sizeof(*savep))); - - savep->name = mem_strdup(savepoint_name); - - savep->savept.least_undo_no = trx->undo_no; - trx->last_sql_stat_start.least_undo_no = trx->undo_no; - - savep->mysql_binlog_cache_pos = binlog_cache_pos; - - UT_LIST_ADD_LAST(trx->trx_savepoints, savep); - - trx->end_bulk_insert(); - - return(DB_SUCCESS); -} - -/*******************************************************************//** -Releases only the named savepoint. Savepoints which were set after this -savepoint are left as is. -@return if no savepoint of the name found then DB_NO_SAVEPOINT, -otherwise DB_SUCCESS */ -dberr_t -trx_release_savepoint_for_mysql( -/*============================*/ - trx_t* trx, /*!< in: transaction handle */ - const char* savepoint_name) /*!< in: savepoint name */ -{ - trx_named_savept_t* savep; - - ut_ad(trx_state_eq(trx, TRX_STATE_ACTIVE, true) - || trx_state_eq(trx, TRX_STATE_PREPARED, true)); - ut_ad(trx->mysql_thd); - - savep = trx_savepoint_find(trx, savepoint_name); - - if (savep != NULL) { - trx_roll_savepoint_free(trx, savep); - return DB_SUCCESS; - } else if (trx->last_sql_stat_start.least_undo_no == 0) { - /* Bulk insert could have discarded savepoints */ - return DB_SUCCESS; - } - - return DB_NO_SAVEPOINT; -} - /*******************************************************************//** Roll back an active transaction. */ static @@ -620,7 +310,9 @@ trx_rollback_active( if (UNIV_UNLIKELY(!trx->rollback_finish())) { ut_ad(!dictionary_locked); } else { - ib::info() << "Rolled back recovered transaction " << trx_id; + sql_print_information( + "InnoDB: Rolled back recovered transaction " + TRX_ID_FMT, trx_id); } if (dictionary_locked) { @@ -906,7 +598,6 @@ trx_rollback_step( if (node->state == ROLL_NODE_SEND) { trx_t* trx; - ib_id_t roll_limit; trx = thr_get_trx(thr); @@ -914,13 +605,11 @@ trx_rollback_step( ut_a(node->undo_thr == NULL); - roll_limit = node->savept ? node->savept->least_undo_no : 0; - trx->mutex_lock(); trx_commit_or_rollback_prepare(trx); - node->undo_thr = trx_rollback_start(trx, roll_limit); + node->undo_thr = trx_rollback_start(trx, node->savept); trx->mutex_unlock(); } else { diff --git a/storage/innobase/trx/trx0sys.cc b/storage/innobase/trx/trx0sys.cc index eb2d7a9ce73..f0f95d15db5 100644 --- a/storage/innobase/trx/trx0sys.cc +++ b/storage/innobase/trx/trx0sys.cc @@ -47,6 +47,31 @@ trx_sys_t trx_sys; #ifdef UNIV_DEBUG /* Flag to control TRX_RSEG_N_SLOTS behavior debugging. */ uint trx_rseg_n_slots_debug = 0; + +void rw_trx_hash_t::validate_element(trx_t *trx) +{ + ut_ad(!trx->read_only || !trx->rsegs.m_redo.rseg); + ut_ad(!trx->is_autocommit_non_locking()); + ut_d(bool acquire_trx_mutex= !trx->mutex_is_owner()); + ut_d(if (acquire_trx_mutex) trx->mutex_lock()); + switch (trx->state) { + case TRX_STATE_NOT_STARTED: + case TRX_STATE_ABORTED: + ut_error; + case TRX_STATE_PREPARED: + case TRX_STATE_PREPARED_RECOVERED: + case TRX_STATE_COMMITTED_IN_MEMORY: + ut_ad(!trx->is_autocommit_non_locking()); + break; + case TRX_STATE_ACTIVE: + if (!trx->is_autocommit_non_locking()) + break; + ut_ad(!trx->is_recovered); + ut_ad(trx->read_only); + ut_ad(trx->mysql_thd); + } + ut_d(if (acquire_trx_mutex) trx->mutex_unlock()); +} #endif /** Display the MySQL binlog offset info if it is present in the trx @@ -238,7 +263,8 @@ static trx_rseg_t *trx_rseg_create(uint32_t space_id) if (fil_space_t *space= mtr.x_lock_space(space_id)) { - ut_ad(space->purpose == FIL_TYPE_TABLESPACE); + ut_ad(!space->is_temporary()); + ut_ad(!space->is_being_imported()); if (buf_block_t *sys_header= trx_sysf_get(&mtr)) { ulint rseg_id= trx_sys_rseg_find_free(sys_header); @@ -362,6 +388,7 @@ size_t trx_sys_t::any_active_transactions(size_t *prepared) trx_sys.trx_list.for_each([&](const trx_t &trx) { switch (trx.state) { case TRX_STATE_NOT_STARTED: + case TRX_STATE_ABORTED: break; case TRX_STATE_ACTIVE: if (!trx.id) diff --git a/storage/innobase/trx/trx0trx.cc b/storage/innobase/trx/trx0trx.cc index 99c01cf4e09..c60369ec082 100644 --- a/storage/innobase/trx/trx0trx.cc +++ b/storage/innobase/trx/trx0trx.cc @@ -144,7 +144,7 @@ trx_init( trx->magic_n = TRX_MAGIC_N; - trx->last_sql_stat_start.least_undo_no = 0; + trx->last_stmt_start = 0; ut_ad(!trx->read_view.is_open()); @@ -192,10 +192,6 @@ struct TrxFactory { UT_LIST_INIT(trx->lock.evicted_tables, &dict_table_t::table_LRU); - UT_LIST_INIT( - trx->trx_savepoints, - &trx_named_savept_t::trx_savepoints); - trx->mutex_init(); } @@ -437,9 +433,8 @@ void trx_t::free() MEM_NOACCESS(&error_info, sizeof error_info); MEM_NOACCESS(&error_key_num, sizeof error_key_num); MEM_NOACCESS(&graph, sizeof graph); - MEM_NOACCESS(&trx_savepoints, sizeof trx_savepoints); MEM_NOACCESS(&undo_no, sizeof undo_no); - MEM_NOACCESS(&last_sql_stat_start, sizeof last_sql_stat_start); + MEM_NOACCESS(&last_stmt_start, sizeof last_stmt_start); MEM_NOACCESS(&rsegs, sizeof rsegs); MEM_NOACCESS(&roll_limit, sizeof roll_limit); MEM_NOACCESS(&in_rollback, sizeof in_rollback); @@ -467,9 +462,10 @@ void trx_t::free() /** Transition to committed state, to release implicit locks. */ TRANSACTIONAL_INLINE inline void trx_t::commit_state() { - ut_ad(state == TRX_STATE_PREPARED - || state == TRX_STATE_PREPARED_RECOVERED - || state == TRX_STATE_ACTIVE); + ut_d(auto trx_state{state}); + ut_ad(trx_state == TRX_STATE_PREPARED || + trx_state == TRX_STATE_PREPARED_RECOVERED || + trx_state == TRX_STATE_ACTIVE); /* This makes the transaction committed in memory and makes its changes to data visible to other transactions. NOTE that there is a small discrepancy from the strict formal visibility rules here: a @@ -1495,8 +1491,6 @@ TRANSACTIONAL_INLINE inline void trx_t::commit_in_memory(const mtr_t *mtr) } } - savepoints_discard(); - if (fts_trx) trx_finalize_for_fts(this, undo_no != 0); @@ -1515,7 +1509,7 @@ TRANSACTIONAL_INLINE inline void trx_t::commit_in_memory(const mtr_t *mtr) lock.was_chosen_as_deadlock_victim= false; } -void trx_t::commit_cleanup() +bool trx_t::commit_cleanup() noexcept { ut_ad(!dict_operation); ut_ad(!was_dict_operation); @@ -1536,6 +1530,7 @@ void trx_t::commit_cleanup() mutex.wr_unlock(); ut_a(error_state == DB_SUCCESS); + return false; } /** Commit the transaction in a mini-transaction. @@ -1600,7 +1595,7 @@ TRANSACTIONAL_TARGET void trx_t::commit_low(mtr_t *mtr) } -void trx_t::commit_persist() +void trx_t::commit_persist() noexcept { mtr_t *mtr= nullptr; mtr_t local_mtr; @@ -1614,7 +1609,7 @@ void trx_t::commit_persist() } -void trx_t::commit() +void trx_t::commit() noexcept { ut_ad(!was_dict_operation); ut_d(was_dict_operation= dict_operation); @@ -1653,6 +1648,7 @@ trx_commit_or_rollback_prepare( return; case TRX_STATE_COMMITTED_IN_MEMORY: + case TRX_STATE_ABORTED: break; } @@ -1720,33 +1716,26 @@ trx_commit_step( return(thr); } -/**********************************************************************//** -Does the transaction commit for MySQL. -@return DB_SUCCESS or error number */ -dberr_t -trx_commit_for_mysql( -/*=================*/ - trx_t* trx) /*!< in/out: transaction */ +void trx_commit_for_mysql(trx_t *trx) noexcept { - /* Because we do not do the commit by sending an Innobase - sig to the transaction, we must here make sure that trx has been - started. */ - - switch (trx->state) { - case TRX_STATE_NOT_STARTED: - return DB_SUCCESS; - case TRX_STATE_ACTIVE: - case TRX_STATE_PREPARED: - case TRX_STATE_PREPARED_RECOVERED: - trx->op_info = "committing"; - trx->commit(); - trx->op_info = ""; - return(DB_SUCCESS); - case TRX_STATE_COMMITTED_IN_MEMORY: - break; - } - ut_error; - return(DB_CORRUPTION); + switch (trx->state) { + case TRX_STATE_ABORTED: + trx->state= TRX_STATE_NOT_STARTED; + /* fall through */ + case TRX_STATE_NOT_STARTED: + trx->will_lock= false; + break; + case TRX_STATE_ACTIVE: + case TRX_STATE_PREPARED: + case TRX_STATE_PREPARED_RECOVERED: + trx->op_info= "committing"; + trx->commit(); + trx->op_info= ""; + break; + case TRX_STATE_COMMITTED_IN_MEMORY: + ut_error; + break; + } } /** Durably write log until trx->commit_lsn @@ -1766,45 +1755,6 @@ void trx_commit_complete_for_mysql(trx_t *trx) trx_flush_log_if_needed(lsn, trx); } -/**********************************************************************//** -Marks the latest SQL statement ended. */ -void -trx_mark_sql_stat_end( -/*==================*/ - trx_t* trx) /*!< in: trx handle */ -{ - ut_a(trx); - - switch (trx->state) { - case TRX_STATE_PREPARED: - case TRX_STATE_PREPARED_RECOVERED: - case TRX_STATE_COMMITTED_IN_MEMORY: - break; - case TRX_STATE_NOT_STARTED: - trx->undo_no = 0; - /* fall through */ - case TRX_STATE_ACTIVE: - if (trx->fts_trx != NULL) { - fts_savepoint_laststmt_refresh(trx); - } - - if (trx->is_bulk_insert()) { - /* MDEV-25036 FIXME: we support buffered - insert only for the first insert statement */ - trx->error_state = trx->bulk_insert_apply(); - /* Allow a subsequent INSERT into an empty table - if !unique_checks && !foreign_key_checks. */ - return; - } - - trx->last_sql_stat_start.least_undo_no = trx->undo_no; - trx->end_bulk_insert(); - return; - } - - ut_error; -} - /**********************************************************************//** Prints info about a transaction. */ void @@ -1830,9 +1780,16 @@ trx_print_low( fprintf(f, "TRANSACTION (%p)", trx); } + THD* thd = trx->mysql_thd; + switch (trx->state) { case TRX_STATE_NOT_STARTED: fputs(", not started", f); + thd = nullptr; + goto state_ok; + case TRX_STATE_ABORTED: + fputs(", forced rollback done", f); + thd = nullptr; goto state_ok; case TRX_STATE_ACTIVE: fprintf(f, ", ACTIVE %lu sec", @@ -1898,9 +1855,8 @@ state_ok: putc('\n', f); } - if (trx->state != TRX_STATE_NOT_STARTED && trx->mysql_thd != NULL) { - innobase_mysql_print_thd( - f, trx->mysql_thd, static_cast(max_query_len)); + if (thd) { + innobase_mysql_print_thd(f, thd, uint(max_query_len)); } } @@ -2214,6 +2170,7 @@ trx_start_if_not_started_xa_low( bool read_write) /*!< in: true if read write transaction */ { switch (trx->state) { + case TRX_STATE_ABORTED: case TRX_STATE_NOT_STARTED: trx_start_low(trx, read_write); return; @@ -2257,6 +2214,7 @@ trx_start_if_not_started_low( } return; + case TRX_STATE_ABORTED: case TRX_STATE_PREPARED: case TRX_STATE_PREPARED_RECOVERED: case TRX_STATE_COMMITTED_IN_MEMORY: diff --git a/storage/innobase/unittest/innodb_sync-t.cc b/storage/innobase/unittest/innodb_sync-t.cc index 5ad726d8429..e12b5c25ba3 100644 --- a/storage/innobase/unittest/innodb_sync-t.cc +++ b/storage/innobase/unittest/innodb_sync-t.cc @@ -209,4 +209,7 @@ int main(int argc __attribute__((unused)), char **argv) ok(true, "sux_lock"); sux.free(); + + my_end(MY_CHECK_ERROR); + return exit_status(); } diff --git a/storage/innobase/ut/ut0ut.cc b/storage/innobase/ut/ut0ut.cc index 5b3bc185779..6bf28d7bdbd 100644 --- a/storage/innobase/ut/ut0ut.cc +++ b/storage/innobase/ut/ut0ut.cc @@ -340,8 +340,6 @@ ut_strerr( return("Data structure corruption"); case DB_CANNOT_DROP_CONSTRAINT: return("Cannot drop constraint"); - case DB_NO_SAVEPOINT: - return("No such savepoint"); case DB_TABLESPACE_EXISTS: return("Tablespace already exists"); case DB_TABLESPACE_DELETED: diff --git a/storage/mroonga/vendor/groonga/src/groonga_benchmark.c b/storage/mroonga/vendor/groonga/src/groonga_benchmark.c index 267bb278764..a4918137d4f 100644 --- a/storage/mroonga/vendor/groonga/src/groonga_benchmark.c +++ b/storage/mroonga/vendor/groonga/src/groonga_benchmark.c @@ -271,12 +271,7 @@ error_exit_in_thread(intptr_t code) CRITICAL_SECTION_ENTER(grntest_cs); grntest_stop_flag = 1; CRITICAL_SECTION_LEAVE(grntest_cs); -#ifdef WIN32 - _endthreadex(code); -#else - pthread_exit((void *)code); -#endif /* WIN32 */ - return 0; + return code; } diff --git a/tests/thread_test.c b/tests/thread_test.c index 8242811c744..1c9df416ea9 100644 --- a/tests/thread_test.c +++ b/tests/thread_test.c @@ -70,7 +70,6 @@ end: thread_count--; pthread_cond_signal(&COND_thread_count); /* Tell main we are ready */ pthread_mutex_unlock(&LOCK_thread_count); - pthread_exit(0); return 0; } diff --git a/unittest/mysys/dynstring-t.c b/unittest/mysys/dynstring-t.c index 194d435dfff..32a6b2a50e3 100644 --- a/unittest/mysys/dynstring-t.c +++ b/unittest/mysys/dynstring-t.c @@ -26,8 +26,10 @@ static void check(const char *res) str1.length= 0; } -int main(void) +int main(int argc, char** argv) { + MY_INIT(argv[0]); + plan(23); IF_WIN(skip_all("Test of POSIX shell escaping rules, not for CMD.EXE\n"), ); @@ -69,6 +71,7 @@ int main(void) dynstr_free(&str1); + my_end(MY_CHECK_ERROR); return exit_status(); } diff --git a/unittest/mysys/stack_allocation-t.c b/unittest/mysys/stack_allocation-t.c index 2b044c80f42..23b75a8f148 100644 --- a/unittest/mysys/stack_allocation-t.c +++ b/unittest/mysys/stack_allocation-t.c @@ -91,7 +91,6 @@ pthread_handler_t thread_stack_check(void *arg __attribute__((unused))) test_stack_detection(1, STACK_ALLOC_SMALL_BLOCK_SIZE-1); test_stack_detection(2, STACK_ALLOC_SMALL_BLOCK_SIZE+1); my_thread_end(); - pthread_exit(0); return 0; } diff --git a/unittest/sql/my_apc-t.cc b/unittest/sql/my_apc-t.cc index 83f894bedc5..09069ef5d40 100644 --- a/unittest/sql/my_apc-t.cc +++ b/unittest/sql/my_apc-t.cc @@ -108,7 +108,6 @@ void *test_apc_service_thread(void *ptr) apc_target.destroy(); mysql_mutex_destroy(&target_mutex); my_thread_end(); - pthread_exit(0); return NULL; } diff --git a/unittest/sql/my_json_writer-t.cc b/unittest/sql/my_json_writer-t.cc index 9363682d86d..8d8fda3f4c9 100644 --- a/unittest/sql/my_json_writer-t.cc +++ b/unittest/sql/my_json_writer-t.cc @@ -54,6 +54,8 @@ constexpr uint FAKE_SELECT_LEX_ID= UINT_MAX; int main(int args, char **argv) { + MY_INIT(argv[0]); + plan(NO_PLAN); diag("Testing Json_writer checks"); @@ -141,6 +143,7 @@ int main(int args, char **argv) diag("Done"); + my_end(MY_CHECK_ERROR); return exit_status(); }