diff options
38 files changed, 417 insertions, 318 deletions
diff --git a/client/mysqltest.cc b/client/mysqltest.cc index 316e52d95b4..425c5f98095 100644 --- a/client/mysqltest.cc +++ b/client/mysqltest.cc @@ -9091,10 +9091,6 @@ static void init_signal_handling(void) struct sigaction sa; DBUG_ENTER("init_signal_handling"); -#ifdef HAVE_STACKTRACE - my_init_stacktrace(); -#endif - sa.sa_flags = SA_RESETHAND | SA_NODEFER; sigemptyset(&sa.sa_mask); sigprocmask(SIG_SETMASK, &sa.sa_mask, NULL); diff --git a/extra/mariabackup/xtrabackup.cc b/extra/mariabackup/xtrabackup.cc index 277e8b67cf0..0529cb18f23 100644 --- a/extra/mariabackup/xtrabackup.cc +++ b/extra/mariabackup/xtrabackup.cc @@ -249,6 +249,12 @@ my_bool innobase_locks_unsafe_for_binlog; my_bool innobase_rollback_on_timeout; my_bool innobase_create_status_file; +/* The following counter is used to convey information to InnoDB +about server activity: in selects it is not sensible to call +srv_active_wake_master_thread after each fetch or search, we only do +it every INNOBASE_WAKE_INTERVAL'th step. */ + +#define INNOBASE_WAKE_INTERVAL 32 ulong innobase_active_counter = 0; #ifndef _WIN32 @@ -2006,10 +2012,6 @@ static bool innodb_init_param() srv_undo_dir = (char*) "."; } - log_checksum_algorithm_ptr = innodb_log_checksums || srv_encrypt_log - ? log_block_calc_checksum_crc32 - : log_block_calc_checksum_none; - #ifdef _WIN32 srv_use_native_aio = TRUE; #endif diff --git a/include/my_stacktrace.h b/include/my_stacktrace.h index 922a59c196a..015fa062752 100644 --- a/include/my_stacktrace.h +++ b/include/my_stacktrace.h @@ -41,7 +41,6 @@ C_MODE_START #if defined(HAVE_STACKTRACE) || defined(HAVE_BACKTRACE) -void my_init_stacktrace(); void my_print_stacktrace(uchar* stack_bottom, ulong thread_stack, my_bool silent); int my_safe_print_str(const char* val, size_t max_len); @@ -52,8 +51,6 @@ char *my_demangle(const char *mangled_name, int *status); #ifdef __WIN__ void my_set_exception_pointers(EXCEPTION_POINTERS *ep); #endif /* __WIN__ */ -#else -#define my_init_stacktrace() do { } while(0) #endif /* ! (defined(HAVE_STACKTRACE) || defined(HAVE_BACKTRACE)) */ #ifndef _WIN32 diff --git a/mysql-test/main/mysql_tzinfo_to_sql_symlink.result b/mysql-test/main/mysql_tzinfo_to_sql_symlink.result index 06e21beace1..f56a2df2012 100644 --- a/mysql-test/main/mysql_tzinfo_to_sql_symlink.result +++ b/mysql-test/main/mysql_tzinfo_to_sql_symlink.result @@ -15,6 +15,7 @@ TRUNCATE TABLE time_zone; TRUNCATE TABLE time_zone_name; TRUNCATE TABLE time_zone_transition; TRUNCATE TABLE time_zone_transition_type; +START TRANSACTION; INSERT INTO time_zone (Use_leap_seconds) VALUES ('N'); SET @time_zone_id= LAST_INSERT_ID(); INSERT INTO time_zone_name (Name, Time_zone_id) VALUES ('GMT', @time_zone_id); @@ -32,6 +33,7 @@ INSERT INTO time_zone_transition_type (Time_zone_id, Transition_type_id, Offset, Warning: Unable to load 'MYSQLTEST_VARDIR/zoneinfo/posix/garbage' as time zone. Skipping it. Warning: Unable to load 'MYSQLTEST_VARDIR/zoneinfo/posix/ignored.tab' as time zone. Skipping it. Warning: Skipping directory 'MYSQLTEST_VARDIR/zoneinfo/posix/posix': to avoid infinite symlink recursion. +COMMIT; ALTER TABLE time_zone_transition ORDER BY Time_zone_id, Transition_time; ALTER TABLE time_zone_transition_type ORDER BY Time_zone_id, Transition_type_id; \d | @@ -57,6 +59,7 @@ TRUNCATE TABLE time_zone; TRUNCATE TABLE time_zone_name; TRUNCATE TABLE time_zone_transition; TRUNCATE TABLE time_zone_transition_type; +START TRANSACTION; INSERT INTO time_zone (Use_leap_seconds) VALUES ('N'); SET @time_zone_id= LAST_INSERT_ID(); INSERT INTO time_zone_name (Name, Time_zone_id) VALUES ('GMT', @time_zone_id); @@ -71,6 +74,7 @@ INSERT INTO time_zone_transition_type (Time_zone_id, Transition_type_id, Offset, (@time_zone_id, 0, 0, 0, 'GMT') ; Warning: Unable to load 'MYSQLTEST_VARDIR/zoneinfo/posix/garbage' as time zone. Skipping it. +COMMIT; ALTER TABLE time_zone_transition ORDER BY Time_zone_id, Transition_time; ALTER TABLE time_zone_transition_type ORDER BY Time_zone_id, Transition_type_id; \d | @@ -160,6 +164,8 @@ TRUNCATE TABLE time_zone; TRUNCATE TABLE time_zone_name; TRUNCATE TABLE time_zone_transition; TRUNCATE TABLE time_zone_transition_type; +START TRANSACTION; +COMMIT; ALTER TABLE time_zone_transition ORDER BY Time_zone_id, Transition_time; ALTER TABLE time_zone_transition_type ORDER BY Time_zone_id, Transition_type_id; \d | diff --git a/mysql-test/suite/encryption/r/innodb_encrypt_log.result b/mysql-test/suite/encryption/r/innodb_encrypt_log.result index b999e8cb34a..cd37330f2b0 100644 --- a/mysql-test/suite/encryption/r/innodb_encrypt_log.result +++ b/mysql-test/suite/encryption/r/innodb_encrypt_log.result @@ -7,7 +7,7 @@ # SET GLOBAL innodb_log_checksums=0; Warnings: -Warning 138 innodb_encrypt_log implies innodb_log_checksums +Warning 138 innodb_log_checksums is deprecated and has no effect outside recovery SELECT @@global.innodb_log_checksums; @@global.innodb_log_checksums 1 diff --git a/mysql-test/suite/innodb/r/foreign_key.result b/mysql-test/suite/innodb/r/foreign_key.result index dffb718feb6..49206c7c723 100644 --- a/mysql-test/suite/innodb/r/foreign_key.result +++ b/mysql-test/suite/innodb/r/foreign_key.result @@ -658,6 +658,7 @@ SET GLOBAL innodb_purge_rseg_truncate_frequency = @saved_frequency; # MDEV-17187 table doesn't exist in engine after ALTER other tables # with CONSTRAINTs # +call mtr.add_suppression("\\[Warning\\] InnoDB: In ALTER TABLE `test`\\.`t2` has or is referenced in foreign key constraints which are not compatible with the new table definition."); set foreign_key_checks=on; create table t1 (id int not null primary key) engine=innodb; create table t2 (id int not null primary key, fid int not null, @@ -713,4 +714,30 @@ drop table t1,t2; ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails drop table t1,t2; ERROR 42S02: Unknown table 'test.t2' +# +# MDEV-22934 Table disappear after two alter table command +# +CREATE TABLE t1(f1 INT NOT NULL AUTO_INCREMENT, +f2 INT NOT NULL, +PRIMARY KEY (f1), INDEX (f2))ENGINE=InnoDB; +CREATE TABLE t2(f1 INT NOT NULL, +f2 INT NOT NULL, f3 INT NOT NULL, +PRIMARY KEY(f1, f2), UNIQUE KEY(f2), +CONSTRAINT `t2_ibfk_1` FOREIGN KEY (f2) REFERENCES t1(f2) ON DELETE CASCADE, +CONSTRAINT `t2_ibfk_2` FOREIGN KEY (f1) REFERENCES t1(f1) ON DELETE CASCADE +) ENGINE=InnoDB; +SET FOREIGN_KEY_CHECKS=0; +ALTER TABLE t2 DROP PRIMARY KEY, ADD PRIMARY KEY(f3), ALGORITHM=INPLACE; +ALTER TABLE t2 DROP INDEX `f2`, ALGORITHM=COPY; +SHOW CREATE TABLE t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `f1` int(11) NOT NULL, + `f2` int(11) NOT NULL, + `f3` int(11) NOT NULL, + PRIMARY KEY (`f3`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1 +CREATE TABLE t2 (f1 INT NOT NULL)ENGINE=InnoDB; +ERROR 42S01: Table 't2' already exists +DROP TABLE t2, t1; # End of 10.2 tests diff --git a/mysql-test/suite/innodb/r/innodb.result b/mysql-test/suite/innodb/r/innodb.result index 86f90c2bd79..233023e63c2 100644 --- a/mysql-test/suite/innodb/r/innodb.result +++ b/mysql-test/suite/innodb/r/innodb.result @@ -2543,7 +2543,6 @@ set foreign_key_checks=0; create table t2 (a varchar(10), foreign key (a) references t1(a)) engine = innodb; create table t1(a varchar(10) primary key) engine = innodb; alter table t1 modify column a int; -Got one of the listed errors set foreign_key_checks=1; drop table t2,t1; set foreign_key_checks=0; @@ -2552,6 +2551,7 @@ create table t1(a varchar(10) primary key) engine = innodb DEFAULT CHARSET=latin alter table t1 convert to character set utf8; set foreign_key_checks=1; drop table t2,t1; +call mtr.add_suppression("\\[Warning\\] InnoDB: In ALTER TABLE `test`.`t1` has or is referenced in foreign key constraints which are not compatible with the new table definition."); set foreign_key_checks=0; create table t2 (a varchar(10), foreign key (a) references t1(a)) engine = innodb DEFAULT CHARSET=latin1; create table t3(a varchar(10) primary key) engine = innodb DEFAULT CHARSET=utf8; diff --git a/mysql-test/suite/innodb/t/foreign_key.test b/mysql-test/suite/innodb/t/foreign_key.test index 27fa63f144e..40bc3a32a4f 100644 --- a/mysql-test/suite/innodb/t/foreign_key.test +++ b/mysql-test/suite/innodb/t/foreign_key.test @@ -657,6 +657,8 @@ SET GLOBAL innodb_purge_rseg_truncate_frequency = @saved_frequency; --echo # with CONSTRAINTs --echo # +call mtr.add_suppression("\\[Warning\\] InnoDB: In ALTER TABLE `test`\\.`t2` has or is referenced in foreign key constraints which are not compatible with the new table definition."); + set foreign_key_checks=on; create table t1 (id int not null primary key) engine=innodb; create table t2 (id int not null primary key, fid int not null, @@ -698,6 +700,27 @@ drop table t1,t2; --error ER_BAD_TABLE_ERROR drop table t1,t2; +--echo # +--echo # MDEV-22934 Table disappear after two alter table command +--echo # +CREATE TABLE t1(f1 INT NOT NULL AUTO_INCREMENT, + f2 INT NOT NULL, + PRIMARY KEY (f1), INDEX (f2))ENGINE=InnoDB; +CREATE TABLE t2(f1 INT NOT NULL, + f2 INT NOT NULL, f3 INT NOT NULL, + PRIMARY KEY(f1, f2), UNIQUE KEY(f2), +CONSTRAINT `t2_ibfk_1` FOREIGN KEY (f2) REFERENCES t1(f2) ON DELETE CASCADE, +CONSTRAINT `t2_ibfk_2` FOREIGN KEY (f1) REFERENCES t1(f1) ON DELETE CASCADE +) ENGINE=InnoDB; + +SET FOREIGN_KEY_CHECKS=0; +ALTER TABLE t2 DROP PRIMARY KEY, ADD PRIMARY KEY(f3), ALGORITHM=INPLACE; +ALTER TABLE t2 DROP INDEX `f2`, ALGORITHM=COPY; +SHOW CREATE TABLE t2; +--error ER_TABLE_EXISTS_ERROR +CREATE TABLE t2 (f1 INT NOT NULL)ENGINE=InnoDB; +DROP TABLE t2, t1; + --echo # End of 10.2 tests --source include/wait_until_count_sessions.inc diff --git a/mysql-test/suite/innodb/t/innodb.test b/mysql-test/suite/innodb/t/innodb.test index 2ea6d05d9eb..37708a4536d 100644 --- a/mysql-test/suite/innodb/t/innodb.test +++ b/mysql-test/suite/innodb/t/innodb.test @@ -1627,7 +1627,6 @@ drop table t1; set foreign_key_checks=0; create table t2 (a varchar(10), foreign key (a) references t1(a)) engine = innodb; create table t1(a varchar(10) primary key) engine = innodb; --- error 1025,1025 alter table t1 modify column a int; set foreign_key_checks=1; drop table t2,t1; @@ -1643,6 +1642,7 @@ drop table t2,t1; # test that RENAME does not allow invalid charsets when f_k_c is 0 +call mtr.add_suppression("\\[Warning\\] InnoDB: In ALTER TABLE `test`.`t1` has or is referenced in foreign key constraints which are not compatible with the new table definition."); set foreign_key_checks=0; create table t2 (a varchar(10), foreign key (a) references t1(a)) engine = innodb DEFAULT CHARSET=latin1; create table t3(a varchar(10) primary key) engine = innodb DEFAULT CHARSET=utf8; diff --git a/mysql-test/suite/sys_vars/r/innodb_log_checksums_basic.result b/mysql-test/suite/sys_vars/r/innodb_log_checksums_basic.result index 6679ca87249..7724ef9c2ee 100644 --- a/mysql-test/suite/sys_vars/r/innodb_log_checksums_basic.result +++ b/mysql-test/suite/sys_vars/r/innodb_log_checksums_basic.result @@ -28,9 +28,11 @@ SELECT @@global.innodb_log_checksums; @@global.innodb_log_checksums 1 SET GLOBAL innodb_log_checksums = OFF; +Warnings: +Warning 138 innodb_log_checksums is deprecated and has no effect outside recovery SELECT @@global.innodb_log_checksums; @@global.innodb_log_checksums -0 +1 SET GLOBAL innodb_log_checksums = default; SET GLOBAL innodb_log_checksums = ON; SELECT @@global.innodb_log_checksums; diff --git a/mysql-test/suite/sys_vars/r/sysvars_innodb.result b/mysql-test/suite/sys_vars/r/sysvars_innodb.result index c34c4748493..2bd2920ff9d 100644 --- a/mysql-test/suite/sys_vars/r/sysvars_innodb.result +++ b/mysql-test/suite/sys_vars/r/sysvars_innodb.result @@ -1250,7 +1250,7 @@ SESSION_VALUE NULL DEFAULT_VALUE ON VARIABLE_SCOPE GLOBAL VARIABLE_TYPE BOOLEAN -VARIABLE_COMMENT Whether to compute and require checksums for InnoDB redo log blocks +VARIABLE_COMMENT DEPRECATED. Whether to require checksums for InnoDB redo log blocks. NUMERIC_MIN_VALUE NULL NUMERIC_MAX_VALUE NULL NUMERIC_BLOCK_SIZE NULL diff --git a/mysql-test/suite/wsrep/r/mysql_tzinfo_to_sql_symlink.result b/mysql-test/suite/wsrep/r/mysql_tzinfo_to_sql_symlink.result index 51c2e204b78..bcd96b86516 100644 --- a/mysql-test/suite/wsrep/r/mysql_tzinfo_to_sql_symlink.result +++ b/mysql-test/suite/wsrep/r/mysql_tzinfo_to_sql_symlink.result @@ -15,6 +15,7 @@ TRUNCATE TABLE time_zone; TRUNCATE TABLE time_zone_name; TRUNCATE TABLE time_zone_transition; TRUNCATE TABLE time_zone_transition_type; +START TRANSACTION; INSERT INTO time_zone (Use_leap_seconds) VALUES ('N'); SET @time_zone_id= LAST_INSERT_ID(); INSERT INTO time_zone_name (Name, Time_zone_id) VALUES ('GMT', @time_zone_id); @@ -32,6 +33,7 @@ INSERT INTO time_zone_transition_type (Time_zone_id, Transition_type_id, Offset, Warning: Unable to load 'MYSQLTEST_VARDIR/zoneinfo/posix/garbage' as time zone. Skipping it. Warning: Unable to load 'MYSQLTEST_VARDIR/zoneinfo/posix/ignored.tab' as time zone. Skipping it. Warning: Skipping directory 'MYSQLTEST_VARDIR/zoneinfo/posix/posix': to avoid infinite symlink recursion. +COMMIT; ALTER TABLE time_zone_transition ORDER BY Time_zone_id, Transition_time; ALTER TABLE time_zone_transition_type ORDER BY Time_zone_id, Transition_type_id; \d | @@ -57,6 +59,7 @@ TRUNCATE TABLE time_zone; TRUNCATE TABLE time_zone_name; TRUNCATE TABLE time_zone_transition; TRUNCATE TABLE time_zone_transition_type; +START TRANSACTION; INSERT INTO time_zone (Use_leap_seconds) VALUES ('N'); SET @time_zone_id= LAST_INSERT_ID(); INSERT INTO time_zone_name (Name, Time_zone_id) VALUES ('GMT', @time_zone_id); @@ -71,6 +74,7 @@ INSERT INTO time_zone_transition_type (Time_zone_id, Transition_type_id, Offset, (@time_zone_id, 0, 0, 0, 'GMT') ; Warning: Unable to load 'MYSQLTEST_VARDIR/zoneinfo/posix/garbage' as time zone. Skipping it. +COMMIT; ALTER TABLE time_zone_transition ORDER BY Time_zone_id, Transition_time; ALTER TABLE time_zone_transition_type ORDER BY Time_zone_id, Transition_type_id; \d | diff --git a/mysql-test/suite/wsrep/r/mysql_tzinfo_to_sql_symlink_skip.result b/mysql-test/suite/wsrep/r/mysql_tzinfo_to_sql_symlink_skip.result index 85c4d858be2..aff02cb413e 100644 --- a/mysql-test/suite/wsrep/r/mysql_tzinfo_to_sql_symlink_skip.result +++ b/mysql-test/suite/wsrep/r/mysql_tzinfo_to_sql_symlink_skip.result @@ -9,6 +9,7 @@ TRUNCATE TABLE time_zone; TRUNCATE TABLE time_zone_name; TRUNCATE TABLE time_zone_transition; TRUNCATE TABLE time_zone_transition_type; +START TRANSACTION; INSERT INTO time_zone (Use_leap_seconds) VALUES ('N'); SET @time_zone_id= LAST_INSERT_ID(); INSERT INTO time_zone_name (Name, Time_zone_id) VALUES ('GMT', @time_zone_id); @@ -26,6 +27,7 @@ INSERT INTO time_zone_transition_type (Time_zone_id, Transition_type_id, Offset, Warning: Unable to load 'MYSQLTEST_VARDIR/zoneinfo/posix/garbage' as time zone. Skipping it. Warning: Unable to load 'MYSQLTEST_VARDIR/zoneinfo/posix/ignored.tab' as time zone. Skipping it. Warning: Skipping directory 'MYSQLTEST_VARDIR/zoneinfo/posix/posix': to avoid infinite symlink recursion. +COMMIT; ALTER TABLE time_zone_transition ORDER BY Time_zone_id, Transition_time; ALTER TABLE time_zone_transition_type ORDER BY Time_zone_id, Transition_type_id; # Silent run @@ -36,6 +38,7 @@ TRUNCATE TABLE time_zone; TRUNCATE TABLE time_zone_name; TRUNCATE TABLE time_zone_transition; TRUNCATE TABLE time_zone_transition_type; +START TRANSACTION; INSERT INTO time_zone (Use_leap_seconds) VALUES ('N'); SET @time_zone_id= LAST_INSERT_ID(); INSERT INTO time_zone_name (Name, Time_zone_id) VALUES ('GMT', @time_zone_id); @@ -50,6 +53,7 @@ INSERT INTO time_zone_transition_type (Time_zone_id, Transition_type_id, Offset, (@time_zone_id, 0, 0, 0, 'GMT') ; Warning: Unable to load 'MYSQLTEST_VARDIR/zoneinfo/posix/garbage' as time zone. Skipping it. +COMMIT; ALTER TABLE time_zone_transition ORDER BY Time_zone_id, Transition_time; ALTER TABLE time_zone_transition_type ORDER BY Time_zone_id, Transition_type_id; # diff --git a/mysys/stacktrace.c b/mysys/stacktrace.c index a512f5879d6..f5e6352a72e 100644 --- a/mysys/stacktrace.c +++ b/mysys/stacktrace.c @@ -34,108 +34,11 @@ #include <execinfo.h> #endif -#ifdef __linux__ -#define PTR_SANE(p) ((p) && (char*)(p) >= heap_start && (char*)(p) <= heap_end) -static char *heap_start; -char *__bss_start; -#else -#define PTR_SANE(p) (p) -#endif /* __linux */ - - -void my_init_stacktrace() -{ -#ifdef __linux__ - heap_start = (char*) &__bss_start; -#endif /* __linux */ -} - -#ifdef __linux__ - -static void print_buffer(char *buffer, size_t count) -{ - const char s[]= " "; - for (; count && *buffer; --count) - { - my_write_stderr(isprint(*buffer) ? buffer : s, 1); - ++buffer; - } -} - -/** - Access the pages of this process through /proc/self/task/<tid>/mem - in order to safely print the contents of a memory address range. - - @param addr The address at the start of the memory region. - @param max_len The length of the memory region. - - @return Zero on success. -*/ -static int safe_print_str(const char *addr, size_t max_len) -{ - int fd; - pid_t tid; - off_t offset; - ssize_t nbytes= 0; - size_t total, count; - char buf[256]; - - tid= (pid_t) syscall(SYS_gettid); - - sprintf(buf, "/proc/self/task/%d/mem", tid); - - if ((fd= open(buf, O_RDONLY)) < 0) - return -1; - - /* Ensure that off_t can hold a pointer. */ - compile_time_assert(sizeof(off_t) >= sizeof(intptr)); - - total= max_len; - offset= (intptr) addr; - - /* Read up to the maximum number of bytes. */ - while (total) - { - count= MY_MIN(sizeof(buf), total); - - if ((nbytes= pread(fd, buf, count, offset)) < 0) - { - /* Just in case... */ - if (errno == EINTR) - continue; - else - break; - } - - /* Advance offset into memory. */ - total-= nbytes; - offset+= nbytes; - addr+= nbytes; - - /* Output the printable characters. */ - print_buffer(buf, nbytes); - - /* Break if less than requested... */ - if ((count - nbytes)) - break; - } - - if (nbytes == -1) - my_safe_printf_stderr("Can't read from address %p", addr); - - close(fd); - - return 0; -} - -#endif - /* Attempt to print a char * pointer as a string. SYNOPSIS - Prints either until the end of string ('\0'), or max_len characters have - been printed. + Prints until max_len characters have been printed. RETURN VALUE 0 Pointer was within the heap address space. @@ -150,24 +53,25 @@ static int safe_print_str(const char *addr, size_t max_len) int my_safe_print_str(const char* val, size_t max_len) { -#ifdef __linux__ - char *heap_end; - - // Try and make use of /proc filesystem to safely print memory contents. - if (!safe_print_str(val, max_len)) - return 0; - - heap_end= (char*) sbrk(0); -#endif - - if (!PTR_SANE(val)) + const char *orig_val= val; + if (!val) { - my_safe_printf_stderr("%s", "is an invalid pointer"); + my_safe_printf_stderr("%s", "(null)"); return 1; } - for (; max_len && PTR_SANE(val) && *val; --max_len) - my_write_stderr((val++), 1); + for (; max_len; --max_len) + { + if (my_write_stderr((val++), 1) != 1) + { + if ((errno == EFAULT) &&(val == orig_val + 1)) + { + // We can not read the address from very beginning + my_safe_printf_stderr("Can't access address %p", orig_val); + } + break; + } + } my_safe_printf_stderr("%s", "\n"); return 0; @@ -511,11 +415,6 @@ static EXCEPTION_POINTERS *exception_ptrs; #define MODULE64_SIZE_WINXP 576 #define STACKWALK_MAX_FRAMES 64 -void my_init_stacktrace() -{ -} - - void my_set_exception_pointers(EXCEPTION_POINTERS *ep) { exception_ptrs = ep; diff --git a/scripts/mysqld_safe.sh b/scripts/mysqld_safe.sh index f40a68a3b1e..22d5a5531c6 100644 --- a/scripts/mysqld_safe.sh +++ b/scripts/mysqld_safe.sh @@ -23,6 +23,7 @@ numa_interleave=0 wsrep_on=0 dry_run=0 defaults_group_suffix= +ignore_unknown=1 # Initial logging status: error log is not open, and not using syslog logging=init @@ -361,11 +362,22 @@ parse_arguments() { --help) usage ;; + --ignore-unknown) ignore_unknown=1 ;; + --no-ignore-unknown|--not-ignore-unknown) ignore_unknown=0 ;; + *) - case "$unrecognized_handling" in - collect) append_arg_to_args "$arg" ;; - complain) log_error "unknown option '$arg'" ;; - esac + if test $ignore_unknown -eq 0 + then + case "$unrecognized_handling" in + collect) append_arg_to_args "$arg" ;; + complain) log_error "unknown option '$arg'" + esac + else + case "$arg" in + "--loose-"*) append_arg_to_args "$arg" ;; + *) append_arg_to_args "--loose-$arg" + esac + fi esac done } diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 3a509fb8beb..377d549a045 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -3389,7 +3389,6 @@ void init_signals(void) sigemptyset(&sa.sa_mask); sigprocmask(SIG_SETMASK,&sa.sa_mask,NULL); - my_init_stacktrace(); #if defined(__amiga__) sa.sa_handler=(void(*)())handle_fatal_signal; #else diff --git a/sql/tztime.cc b/sql/tztime.cc index ca4c10975ca..4ef20d79d5d 100644 --- a/sql/tztime.cc +++ b/sql/tztime.cc @@ -2739,9 +2739,11 @@ main(int argc, char **argv) printf("TRUNCATE TABLE time_zone_name;\n"); printf("TRUNCATE TABLE time_zone_transition;\n"); printf("TRUNCATE TABLE time_zone_transition_type;\n"); + printf("START TRANSACTION;\n"); if (scan_tz_dir(root_name_end, 0, opt_verbose)) { + printf("ROLLBACK;\n"); fflush(stdout); fprintf(stderr, "There were fatal errors during processing " @@ -2749,6 +2751,7 @@ main(int argc, char **argv) return 1; } + printf("COMMIT;\n"); printf("ALTER TABLE time_zone_transition " "ORDER BY Time_zone_id, Transition_time;\n"); printf("ALTER TABLE time_zone_transition_type " diff --git a/storage/innobase/btr/btr0cur.cc b/storage/innobase/btr/btr0cur.cc index fffa36475e6..a68bc6550d7 100644 --- a/storage/innobase/btr/btr0cur.cc +++ b/storage/innobase/btr/btr0cur.cc @@ -3360,7 +3360,7 @@ fail: /* prefetch siblings of the leaf for the pessimistic operation, if the page is leaf. */ - if (page_is_leaf(page)) { + if (page_is_leaf(page) && !index->is_ibuf()) { btr_cur_prefetch_siblings(block); } fail_err: @@ -4330,6 +4330,7 @@ btr_cur_optimistic_update( if (rec_offs_any_extern(*offsets)) { any_extern: + ut_ad(!index->is_ibuf()); /* Externally stored fields are treated in pessimistic update */ @@ -4525,7 +4526,7 @@ func_exit: } } - if (err != DB_SUCCESS) { + if (err != DB_SUCCESS && !index->is_ibuf()) { /* prefetch siblings of the leaf for the pessimistic operation. */ btr_cur_prefetch_siblings(block); diff --git a/storage/innobase/buf/buf0buf.cc b/storage/innobase/buf/buf0buf.cc index 076b9c33c00..ea1916e192d 100644 --- a/storage/innobase/buf/buf0buf.cc +++ b/storage/innobase/buf/buf0buf.cc @@ -5653,7 +5653,23 @@ buf_page_create( if (drop_hash_entry) { mutex_enter(&block->mutex); - buf_page_set_sticky(&block->page); + /* Avoid a hang if I/O is going on. Release + the buffer pool mutex and page hash lock + and wait for I/O to complete */ + while (buf_block_get_io_fix(block) != BUF_IO_NONE) { + buf_block_fix(block); + mutex_exit(&block->mutex); + buf_pool_mutex_exit(buf_pool); + rw_lock_x_unlock(hash_lock); + + os_thread_yield(); + + buf_pool_mutex_enter(buf_pool); + rw_lock_x_lock(hash_lock); + mutex_enter(&block->mutex); + buf_block_unfix(block); + } + rw_lock_x_lock(&block->lock); mutex_exit(&block->mutex); } #endif @@ -5665,11 +5681,7 @@ buf_page_create( #ifdef BTR_CUR_HASH_ADAPT if (drop_hash_entry) { btr_search_drop_page_hash_index(block); - buf_pool_mutex_enter(buf_pool); - mutex_enter(&block->mutex); - buf_page_unset_sticky(&block->page); - mutex_exit(&block->mutex); - buf_pool_mutex_exit(buf_pool); + rw_lock_x_unlock(&block->lock); } #endif /* BTR_CUR_HASH_ADAPT */ diff --git a/storage/innobase/buf/buf0flu.cc b/storage/innobase/buf/buf0flu.cc index e1acc7b9095..6f56a09eda2 100644 --- a/storage/innobase/buf/buf0flu.cc +++ b/storage/innobase/buf/buf0flu.cc @@ -3116,7 +3116,7 @@ DECLARE_THREAD(buf_flush_page_cleaner_coordinator)(void*) /* The page_cleaner skips sleep if the server is idle and there are no pending IOs in the buffer pool and there is work to do. */ - if (srv_check_activity(&last_activity) + if (srv_check_activity(last_activity) || buf_get_n_pending_read_ios() || n_flushed == 0) { @@ -3208,7 +3208,7 @@ DECLARE_THREAD(buf_flush_page_cleaner_coordinator)(void*) n_flushed = n_flushed_lru + n_flushed_list; - } else if (srv_check_activity(&last_activity)) { + } else if (srv_check_activity(last_activity)) { ulint n_to_flush; lsn_t lsn_limit = 0; diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index c87e396b0de..21b68dd0fb3 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -447,6 +447,14 @@ TYPELIB innodb_flush_method_typelib = { NULL }; +/* The following counter is used to convey information to InnoDB +about server activity: in case of normal DML ops it is not +sensible to call srv_active_wake_master_thread after each +operation, we only do it every INNOBASE_WAKE_INTERVAL'th step. */ + +#define INNOBASE_WAKE_INTERVAL 32 +static ulong innobase_active_counter = 0; + /** Allowed values of innodb_change_buffering */ static const char* innodb_change_buffering_names[] = { "none", /* IBUF_USE_NONE */ @@ -1844,6 +1852,23 @@ thd_to_trx_id( #endif /* WITH_WSREP */ /********************************************************************//** +Increments innobase_active_counter and every INNOBASE_WAKE_INTERVALth +time calls srv_active_wake_master_thread. This function should be used +when a single database operation may introduce a small need for +server utility activity, like checkpointing. */ +inline +void +innobase_active_small(void) +/*=======================*/ +{ + innobase_active_counter++; + + if ((innobase_active_counter % INNOBASE_WAKE_INTERVAL) == 0) { + srv_active_wake_master_thread(); + } +} + +/********************************************************************//** 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 timeout or a deadlock. @@ -3488,8 +3513,7 @@ static int innodb_init_abort() DBUG_RETURN(1); } -/** Update log_checksum_algorithm_ptr with a pointer to the function -corresponding to whether checksums are enabled. +/** If applicable, emit a message that log checksums cannot be disabled. @param[in,out] thd client session, or NULL if at startup @param[in] check whether redo log block checksums are enabled @return whether redo log block checksums are enabled */ @@ -3497,34 +3521,21 @@ static inline bool innodb_log_checksums_func_update(THD* thd, bool check) { - static const char msg[] = "innodb_encrypt_log implies" - " innodb_log_checksums"; + static const char msg[] = "innodb_log_checksums is deprecated" + " and has no effect outside recovery"; ut_ad(!thd == !srv_was_started); if (!check) { - check = srv_encrypt_log; - if (!check) { - } else if (thd) { + if (thd) { push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN, HA_ERR_UNSUPPORTED, msg); + check = true; } else { sql_print_warning(msg); } } - if (thd) { - log_mutex_enter(); - log_checksum_algorithm_ptr = check - ? log_block_calc_checksum_crc32 - : log_block_calc_checksum_none; - log_mutex_exit(); - } else { - log_checksum_algorithm_ptr = check - ? log_block_calc_checksum_crc32 - : log_block_calc_checksum_none; - } - return(check); } @@ -6456,6 +6467,11 @@ ha_innobase::close() MONITOR_INC(MONITOR_TABLE_CLOSE); + /* Tell InnoDB server that there might be work for + utility threads: */ + + srv_active_wake_master_thread(); + DBUG_RETURN(0); } @@ -8166,6 +8182,8 @@ report_error: } func_exit: + innobase_active_small(); + DBUG_RETURN(error_result); } @@ -8852,6 +8870,11 @@ func_exit: error, m_prebuilt->table->flags, m_user_thd); } + /* Tell InnoDB server that there might be work for + utility threads: */ + + innobase_active_small(); + #ifdef WITH_WSREP if (error == DB_SUCCESS && trx->is_wsrep() && wsrep_thd_exec_mode(m_user_thd) == LOCAL_STATE && @@ -8910,6 +8933,11 @@ ha_innobase::delete_row( innobase_srv_conc_exit_innodb(m_prebuilt); + /* Tell the InnoDB server that there might be work for + utility threads: */ + + innobase_active_small(); + #ifdef WITH_WSREP if (error == DB_SUCCESS && trx->is_wsrep() && wsrep_thd_exec_mode(m_user_thd) == LOCAL_STATE @@ -12697,6 +12725,7 @@ create_table_info_t::create_table_update_dict() if (m_flags2 & DICT_TF2_FTS) { if (!innobase_fts_load_stopword(innobase_table, NULL, m_thd)) { dict_table_close(innobase_table, FALSE, FALSE); + srv_active_wake_master_thread(); trx_free(m_trx); DBUG_RETURN(-1); } @@ -12846,6 +12875,11 @@ ha_innobase::create( error = info.create_table_update_dict(); + /* Tell the InnoDB server that there might be work for + utility threads: */ + + srv_active_wake_master_thread(); + DBUG_RETURN(error); } @@ -19068,7 +19102,7 @@ static MYSQL_SYSVAR_ENUM(checksum_algorithm, srv_checksum_algorithm, static MYSQL_SYSVAR_BOOL(log_checksums, innodb_log_checksums, PLUGIN_VAR_RQCMDARG, - "Whether to compute and require checksums for InnoDB redo log blocks", + "DEPRECATED. Whether to require checksums for InnoDB redo log blocks.", NULL, innodb_log_checksums_update, TRUE); static MYSQL_SYSVAR_BOOL(checksums, innobase_use_checksums, diff --git a/storage/innobase/handler/handler0alter.cc b/storage/innobase/handler/handler0alter.cc index 98d68250029..896052f34ac 100644 --- a/storage/innobase/handler/handler0alter.cc +++ b/storage/innobase/handler/handler0alter.cc @@ -9415,11 +9415,11 @@ ha_innobase::commit_inplace_alter_table( /* Exclusively lock the table, to ensure that no other transaction is holding locks on the table while we - change the table definition. The MySQL meta-data lock + change the table definition. The meta-data lock (MDL) should normally guarantee that no conflicting locks exist. However, FOREIGN KEY constraints checks and any transactions collected during crash recovery could be - holding InnoDB locks only, not MySQL locks. */ + holding InnoDB locks only, not MDL. */ dberr_t error = row_merge_lock_table( m_prebuilt->trx, ctx->old_table, LOCK_X); @@ -9795,6 +9795,11 @@ foreign_fail: log_append_on_checkpoint(NULL); + /* Tell the InnoDB server that there might be work for + utility threads: */ + + srv_active_wake_master_thread(); + if (fail) { for (inplace_alter_handler_ctx** pctx = ctx_array; *pctx; pctx++) { diff --git a/storage/innobase/include/dict0mem.h b/storage/innobase/include/dict0mem.h index 2504b2ef61d..59723a3c178 100644 --- a/storage/innobase/include/dict0mem.h +++ b/storage/innobase/include/dict0mem.h @@ -1041,6 +1041,9 @@ struct dict_index_t{ /** @return whether this is a spatial index */ bool is_spatial() const { return UNIV_UNLIKELY(type & DICT_SPATIAL); } + /** @return whether this is the change buffer */ + bool is_ibuf() const { return UNIV_UNLIKELY(type & DICT_IBUF); } + /** @return whether the index includes virtual columns */ bool has_virtual() const { return type & DICT_VIRTUAL; } diff --git a/storage/innobase/include/log0log.h b/storage/innobase/include/log0log.h index 133b1692d31..b201de06d17 100644 --- a/storage/innobase/include/log0log.h +++ b/storage/innobase/include/log0log.h @@ -2,7 +2,7 @@ Copyright (c) 1995, 2017, Oracle and/or its affiliates. All rights reserved. Copyright (c) 2009, Google Inc. -Copyright (c) 2017, 2019, MariaDB Corporation. +Copyright (c) 2017, 2020, MariaDB Corporation. Portions of this file contain modifications contributed and copyrighted by Google, Inc. Those modifications are gratefully acknowledged and are described @@ -56,12 +56,6 @@ step which modifies the database, is started */ #define LOG_CHECKPOINT_FREE_PER_THREAD (4U << srv_page_size_shift) #define LOG_CHECKPOINT_EXTRA_FREE (8U << srv_page_size_shift) -typedef ulint (*log_checksum_func_t)(const byte* log_block); - -/** Pointer to the log checksum calculation function. Protected with -log_sys.mutex. */ -extern log_checksum_func_t log_checksum_algorithm_ptr; - /** Append a string to the log. @param[in] str string @param[in] len string length @@ -266,14 +260,6 @@ log_block_set_data_len( /*===================*/ byte* log_block, /*!< in/out: log block */ ulint len); /*!< in: data length */ -/************************************************************//** -Calculates the checksum for a log block. -@return checksum */ -UNIV_INLINE -ulint -log_block_calc_checksum( -/*====================*/ - const byte* block); /*!< in: log block */ /** Calculates the checksum for a log block using the CRC32 algorithm. @param[in] block log block @@ -283,12 +269,6 @@ ulint log_block_calc_checksum_crc32( const byte* block); -/** Calculates the checksum for a log block using the "no-op" algorithm. -@return the calculated checksum value */ -UNIV_INLINE -ulint -log_block_calc_checksum_none(const byte*); - /************************************************************//** Gets a log block checksum field value. @return checksum */ @@ -365,7 +345,7 @@ void log_refresh_stats(void); /*===================*/ -/** Whether to generate and require checksums on the redo log pages */ +/** Whether to require checksums on the redo log pages */ extern my_bool innodb_log_checksums; /* Values used as flags */ diff --git a/storage/innobase/include/log0log.ic b/storage/innobase/include/log0log.ic index 722e658a24b..be28fee7b8e 100644 --- a/storage/innobase/include/log0log.ic +++ b/storage/innobase/include/log0log.ic @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 1995, 2015, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2017, 2018, MariaDB Corporation. +Copyright (c) 2017, 2020, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -190,18 +190,6 @@ log_block_convert_lsn_to_no( 0xFUL, 0x3FFFFFFFUL)) + 1); } -/************************************************************//** -Calculates the checksum for a log block. -@return checksum */ -UNIV_INLINE -ulint -log_block_calc_checksum( -/*====================*/ - const byte* block) /*!< in: log block */ -{ - return(log_checksum_algorithm_ptr(block)); -} - /** Calculate the checksum for a log block using the pre-5.7.9 algorithm. @param[in] block log block @return checksum */ @@ -242,15 +230,6 @@ log_block_calc_checksum_crc32( return(ut_crc32(block, OS_FILE_LOG_BLOCK_SIZE - LOG_BLOCK_TRL_SIZE)); } -/** Calculates the checksum for a log block using the "no-op" algorithm. -@return checksum */ -UNIV_INLINE -ulint -log_block_calc_checksum_none(const byte*) -{ - return(LOG_NO_CHECKSUM_MAGIC); -} - /************************************************************//** Gets a log block checksum field value. @return checksum */ diff --git a/storage/innobase/include/srv0srv.h b/storage/innobase/include/srv0srv.h index 93755ad7520..6c575733710 100644 --- a/storage/innobase/include/srv0srv.h +++ b/storage/innobase/include/srv0srv.h @@ -788,6 +788,19 @@ srv_reset_io_thread_op_info(); /** Wake up the purge threads if there is work to do. */ void srv_wake_purge_thread_if_not_active(); +/** Wake up the InnoDB master thread if it was suspended (not sleeping). */ +void +srv_active_wake_master_thread_low(); + +#define srv_active_wake_master_thread() \ + do { \ + if (!srv_read_only_mode) { \ + srv_active_wake_master_thread_low(); \ + } \ + } while (0) +/** Wake up the master thread if it is suspended or being suspended. */ +void +srv_wake_master_thread(); /******************************************************************//** Outputs to a file the output of the InnoDB Monitor. @@ -816,13 +829,13 @@ reading this value as it is only used in heuristics. ulint srv_get_activity_count(void); /*========================*/ - -/** Check if there has been any activity. -@param[in,out] activity_count recent activity count to be returned -if there is a change +/*******************************************************************//** +Check if there has been any activity. @return FALSE if no change in activity counter. */ -bool srv_check_activity(ulint *activity_count); - +ibool +srv_check_activity( +/*===============*/ + ulint old_activity_count); /*!< old activity count */ /******************************************************************//** Increment the server activity counter. */ void diff --git a/storage/innobase/log/log0log.cc b/storage/innobase/log/log0log.cc index e8f39e03b50..997430497bc 100644 --- a/storage/innobase/log/log0log.cc +++ b/storage/innobase/log/log0log.cc @@ -2,7 +2,7 @@ Copyright (c) 1995, 2017, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 2009, Google Inc. -Copyright (c) 2014, 2019, MariaDB Corporation. +Copyright (c) 2014, 2020, MariaDB Corporation. Portions of this file contain modifications contributed and copyrighted by Google, Inc. Those modifications are gratefully acknowledged and are described @@ -83,12 +83,9 @@ reduce the size of the log. /** Redo log system */ log_t log_sys; -/** Whether to generate and require checksums on the redo log pages */ +/** Whether to require checksums on the redo log pages */ my_bool innodb_log_checksums; -/** Pointer to the log checksum calculation function */ -log_checksum_func_t log_checksum_algorithm_ptr; - /* Next log block number to do dummy record filling if no log records written for a while */ static ulint next_lbn_to_pad = 0; @@ -679,7 +676,7 @@ log_block_store_checksum( /*=====================*/ byte* block) /*!< in/out: pointer to a log block */ { - log_block_set_checksum(block, log_block_calc_checksum(block)); + log_block_set_checksum(block, log_block_calc_checksum_crc32(block)); } /******************************************************//** diff --git a/storage/innobase/log/log0recv.cc b/storage/innobase/log/log0recv.cc index a9b5b1e25d0..b6f6bc26165 100644 --- a/storage/innobase/log/log0recv.cc +++ b/storage/innobase/log/log0recv.cc @@ -1199,7 +1199,10 @@ static dberr_t recv_log_recover_10_4() % univ_page_size.physical()), OS_FILE_LOG_BLOCK_SIZE, buf, NULL); - if (log_block_calc_checksum(buf) != log_block_get_checksum(buf)) { + const ulint cksum = log_block_get_checksum(buf); + + if (cksum != LOG_NO_CHECKSUM_MAGIC + && cksum != log_block_calc_checksum_crc32(buf)) { return DB_CORRUPTION; } diff --git a/storage/innobase/row/row0mysql.cc b/storage/innobase/row/row0mysql.cc index 0c5f96e20a5..5dcd596fc98 100644 --- a/storage/innobase/row/row0mysql.cc +++ b/storage/innobase/row/row0mysql.cc @@ -3817,7 +3817,7 @@ funct_exit_all_freed: trx->op_info = ""; - srv_inc_activity_count(); + srv_wake_master_thread(); DBUG_RETURN(err); } @@ -4528,12 +4528,20 @@ end: if (err != DB_SUCCESS) { if (old_is_tmp) { - ib::error() << "In ALTER TABLE " + /* In case of copy alter, ignore the + loading of foreign key constraint + when foreign_key_check is disabled */ + ib::error_or_warn(trx->check_foreigns) + << "In ALTER TABLE " << ut_get_name(trx, new_name) << " has or is referenced in foreign" " key constraints which are not" " compatible with the new table" " definition."; + if (!trx->check_foreigns) { + err = DB_SUCCESS; + goto funct_exit; + } } else { ib::error() << "In RENAME TABLE table " << ut_get_name(trx, new_name) diff --git a/storage/innobase/row/row0uins.cc b/storage/innobase/row/row0uins.cc index 1e560dad7b3..be0f6373e21 100644 --- a/storage/innobase/row/row0uins.cc +++ b/storage/innobase/row/row0uins.cc @@ -82,6 +82,7 @@ row_undo_ins_remove_clust_rec( mtr.set_log_mode(MTR_LOG_NO_REDO); } else { index->set_modified(mtr); + ut_ad(lock_table_has_locks(index->table)); } /* This is similar to row_undo_mod_clust(). The DDL thread may @@ -92,8 +93,7 @@ row_undo_ins_remove_clust_rec( online = dict_index_is_online_ddl(index); if (online) { - ut_ad(node->trx->dict_operation_lock_mode - != RW_X_LATCH); + ut_ad(!node->trx->dict_operation_lock_mode); ut_ad(node->table->id != DICT_INDEXES_ID); mtr_s_lock_index(index, &mtr); } @@ -568,6 +568,9 @@ row_undo_ins( return(DB_SUCCESS); } + ut_ad(node->table->is_temporary() + || lock_table_has_locks(node->table)); + /* Iterate over all the indexes and undo the insert.*/ node->index = dict_table_get_first_index(node->table); diff --git a/storage/innobase/row/row0umod.cc b/storage/innobase/row/row0umod.cc index 2ac54c4025e..3e46c2f6123 100644 --- a/storage/innobase/row/row0umod.cc +++ b/storage/innobase/row/row0umod.cc @@ -219,10 +219,7 @@ row_undo_mod_clust( bool online; ut_ad(thr_get_trx(thr) == node->trx); - ut_ad(node->trx->dict_operation_lock_mode); ut_ad(node->trx->in_rollback); - ut_ad(rw_lock_own_flagged(&dict_operation_lock, - RW_LOCK_FLAG_X | RW_LOCK_FLAG_S)); log_free_check(); pcur = &node->pcur; @@ -234,11 +231,12 @@ row_undo_mod_clust( mtr.set_log_mode(MTR_LOG_NO_REDO); } else { index->set_modified(mtr); + ut_ad(lock_table_has_locks(index->table)); } online = dict_index_is_online_ddl(index); if (online) { - ut_ad(node->trx->dict_operation_lock_mode != RW_X_LATCH); + ut_ad(!node->trx->dict_operation_lock_mode); mtr_s_lock_index(index, &mtr); } @@ -277,17 +275,7 @@ row_undo_mod_clust( ut_ad(err == DB_SUCCESS || err == DB_OUT_OF_FILE_SPACE); } - /* Online rebuild cannot be initiated while we are holding - dict_operation_lock and index->lock. (It can be aborted.) */ - ut_ad(online || !dict_index_is_online_ddl(index)); - - if (err == DB_SUCCESS && online) { - - ut_ad(rw_lock_own_flagged( - &index->lock, - RW_LOCK_FLAG_S | RW_LOCK_FLAG_X - | RW_LOCK_FLAG_SX)); - + if (err == DB_SUCCESS && online && dict_index_is_online_ddl(index)) { switch (node->rec_type) { case TRX_UNDO_DEL_MARK_REC: row_log_table_insert( @@ -836,37 +824,6 @@ func_exit_no_pcur: } /***********************************************************//** -Flags a secondary index corrupted. */ -static MY_ATTRIBUTE((nonnull)) -void -row_undo_mod_sec_flag_corrupted( -/*============================*/ - trx_t* trx, /*!< in/out: transaction */ - dict_index_t* index) /*!< in: secondary index */ -{ - ut_ad(!dict_index_is_clust(index)); - - switch (trx->dict_operation_lock_mode) { - case RW_S_LATCH: - /* Because row_undo() is holding an S-latch - on the data dictionary during normal rollback, - we can only mark the index corrupted in the - data dictionary cache. TODO: fix this somehow.*/ - mutex_enter(&dict_sys->mutex); - dict_set_corrupted_index_cache_only(index); - mutex_exit(&dict_sys->mutex); - break; - default: - ut_ad(0); - /* fall through */ - case RW_X_LATCH: - /* This should be the rollback of a data dictionary - transaction. */ - dict_set_corrupted(index, trx, "rollback"); - } -} - -/***********************************************************//** Undoes a modify in secondary indexes when undo record type is UPD_DEL. @return DB_SUCCESS or DB_OUT_OF_FILE_SPACE */ static MY_ATTRIBUTE((nonnull, warn_unused_result)) @@ -979,8 +936,7 @@ row_undo_mod_del_mark_sec( } if (err == DB_DUPLICATE_KEY) { - row_undo_mod_sec_flag_corrupted( - thr_get_trx(thr), index); + index->type |= DICT_CORRUPT; err = DB_SUCCESS; /* Do not return any error to the caller. The duplicate will be reported by ALTER TABLE or @@ -1125,8 +1081,7 @@ row_undo_mod_upd_exist_sec( } if (err == DB_DUPLICATE_KEY) { - row_undo_mod_sec_flag_corrupted( - thr_get_trx(thr), index); + index->type |= DICT_CORRUPT; err = DB_SUCCESS; } else if (err != DB_SUCCESS) { break; @@ -1292,6 +1247,8 @@ row_undo_mod( return(DB_SUCCESS); } + ut_ad(node->table->is_temporary() + || lock_table_has_locks(node->table)); node->index = dict_table_get_first_index(node->table); ut_ad(dict_index_is_clust(node->index)); diff --git a/storage/innobase/row/row0undo.cc b/storage/innobase/row/row0undo.cc index 762228503be..68b8123cbb6 100644 --- a/storage/innobase/row/row0undo.cc +++ b/storage/innobase/row/row0undo.cc @@ -283,15 +283,16 @@ row_undo( ? UNDO_NODE_INSERT : UNDO_NODE_MODIFY; } - /* Prevent DROP TABLE etc. while we are rolling back this row. - If we are doing a TABLE CREATE or some other dictionary operation, - then we already have dict_operation_lock locked in x-mode. Do not - try to lock again, because that would cause a hang. */ - - const bool locked_data_dict = (trx->dict_operation_lock_mode == 0); - - if (locked_data_dict) { - + /* Prevent prepare_inplace_alter_table_dict() from adding + dict_table_t::indexes while we are processing the record. + Recovered transactions are not protected by MDL, and the + secondary index creation is not protected by table locks + for online operation. (A table lock would only be acquired + when committing the ALTER TABLE operation.) */ + const bool locked_data_dict = UNIV_UNLIKELY(trx->is_recovered) + && !trx->dict_operation_lock_mode; + + if (UNIV_UNLIKELY(locked_data_dict)) { row_mysql_freeze_data_dictionary(trx); } @@ -307,8 +308,7 @@ row_undo( err = row_undo_mod(node, thr); } - if (locked_data_dict) { - + if (UNIV_UNLIKELY(locked_data_dict)) { row_mysql_unfreeze_data_dictionary(trx); } diff --git a/storage/innobase/srv/srv0srv.cc b/storage/innobase/srv/srv0srv.cc index 6af3b89f15c..c5b08cd5eb8 100644 --- a/storage/innobase/srv/srv0srv.cc +++ b/storage/innobase/srv/srv0srv.cc @@ -1923,6 +1923,33 @@ srv_get_active_thread_type(void) return(ret); } +/** Wake up the InnoDB master thread if it was suspended (not sleeping). */ +void +srv_active_wake_master_thread_low() +{ + ut_ad(!srv_read_only_mode); + ut_ad(!srv_sys_mutex_own()); + + srv_inc_activity_count(); + + if (my_atomic_loadlint(&srv_sys.n_threads_active[SRV_MASTER]) == 0) { + srv_slot_t* slot; + + srv_sys_mutex_enter(); + + slot = &srv_sys.sys_threads[SRV_MASTER_SLOT]; + + /* Only if the master thread has been started. */ + + if (slot->in_use) { + ut_a(srv_slot_get_type(slot) == SRV_MASTER); + os_event_set(slot->event); + } + + srv_sys_mutex_exit(); + } +} + /** Wake up the purge threads if there is work to do. */ void srv_wake_purge_thread_if_not_active() @@ -1937,6 +1964,14 @@ srv_wake_purge_thread_if_not_active() } } +/** Wake up the master thread if it is suspended or being suspended. */ +void +srv_wake_master_thread() +{ + srv_inc_activity_count(); + srv_release_threads(SRV_MASTER, 1); +} + /*******************************************************************//** Get current server activity count. We don't hold srv_sys::mutex while reading this value as it is only used in heuristics. @@ -1948,20 +1983,15 @@ srv_get_activity_count(void) return(srv_sys.activity_count); } -/** Check if there has been any activity. -@param[in,out] activity_count recent activity count to be returned -if there is a change +/*******************************************************************//** +Check if there has been any activity. @return FALSE if no change in activity counter. */ -bool srv_check_activity(ulint *activity_count) +ibool +srv_check_activity( +/*===============*/ + ulint old_activity_count) /*!< in: old activity count */ { - ulint new_activity_count= srv_sys.activity_count; - if (new_activity_count != *activity_count) - { - *activity_count= new_activity_count; - return true; - } - - return false; + return(srv_sys.activity_count != old_activity_count); } /********************************************************************//** @@ -2362,30 +2392,52 @@ DECLARE_THREAD(srv_master_thread)( slot = srv_reserve_slot(SRV_MASTER); ut_a(slot == srv_sys.sys_threads); +loop: while (srv_shutdown_state <= SRV_SHUTDOWN_INITIATED) { srv_master_sleep(); MONITOR_INC(MONITOR_MASTER_THREAD_SLEEP); - if (srv_check_activity(&old_activity_count)) { + if (srv_check_activity(old_activity_count)) { + old_activity_count = srv_get_activity_count(); srv_master_do_active_tasks(); } else { srv_master_do_idle_tasks(); } } - ut_ad(srv_shutdown_state == SRV_SHUTDOWN_EXIT_THREADS - || srv_shutdown_state == SRV_SHUTDOWN_CLEANUP); - - if (srv_shutdown_state == SRV_SHUTDOWN_CLEANUP - && srv_fast_shutdown < 2) { - srv_shutdown(srv_fast_shutdown == 0); + switch (srv_shutdown_state) { + case SRV_SHUTDOWN_NONE: + case SRV_SHUTDOWN_INITIATED: + break; + case SRV_SHUTDOWN_FLUSH_PHASE: + case SRV_SHUTDOWN_LAST_PHASE: + ut_ad(0); + /* fall through */ + case SRV_SHUTDOWN_EXIT_THREADS: + /* srv_init_abort() must have been invoked */ + case SRV_SHUTDOWN_CLEANUP: + if (srv_shutdown_state == SRV_SHUTDOWN_CLEANUP + && srv_fast_shutdown < 2) { + srv_shutdown(srv_fast_shutdown == 0); + } + srv_suspend_thread(slot); + my_thread_end(); + os_thread_exit(); } + srv_main_thread_op_info = "suspending"; + srv_suspend_thread(slot); - my_thread_end(); - os_thread_exit(); - OS_THREAD_DUMMY_RETURN; + + /* DO NOT CHANGE THIS STRING. innobase_start_or_create_for_mysql() + waits for database activity to die down when converting < 4.1.x + databases, and relies on this string being exactly as it is. InnoDB + manual also mentions this string in several places. */ + srv_main_thread_op_info = "waiting for server activity"; + + srv_resume_thread(slot); + goto loop; } /** @return whether purge should exit due to shutdown */ @@ -2553,13 +2605,15 @@ static ulint srv_do_purge(ulint* n_total_purged ++n_use_threads; } - } else if (srv_check_activity(&old_activity_count) + } else if (srv_check_activity(old_activity_count) && n_use_threads > 1) { /* History length same or smaller since last snapshot, use fewer threads. */ --n_use_threads; + + old_activity_count = srv_get_activity_count(); } /* Ensure that the purge threads are less than what diff --git a/storage/innobase/srv/srv0start.cc b/storage/innobase/srv/srv0start.cc index 859e5a3eec2..318ab49cc9c 100644 --- a/storage/innobase/srv/srv0start.cc +++ b/storage/innobase/srv/srv0start.cc @@ -1178,7 +1178,7 @@ srv_shutdown_all_bg_threads() if (srv_start_state_is_set(SRV_START_STATE_MASTER)) { /* c. We wake the master thread so that it exits */ - srv_inc_activity_count(); + srv_wake_master_thread(); } if (srv_start_state_is_set(SRV_START_STATE_PURGE)) { @@ -2526,7 +2526,7 @@ void srv_shutdown_bg_undo_sources() fts_optimize_shutdown(); dict_stats_shutdown(); while (row_get_background_drop_list_len_low()) { - srv_inc_activity_count(); + srv_wake_master_thread(); os_thread_yield(); } srv_undo_sources = false; diff --git a/storage/innobase/trx/trx0roll.cc b/storage/innobase/trx/trx0roll.cc index c61a67ec05e..1be444adf07 100644 --- a/storage/innobase/trx/trx0roll.cc +++ b/storage/innobase/trx/trx0roll.cc @@ -164,6 +164,9 @@ trx_rollback_to_savepoint_low( mem_heap_free(heap); + /* There might be work for utility threads.*/ + srv_active_wake_master_thread(); + MONITOR_DEC(MONITOR_TRX_ACTIVE); } diff --git a/storage/innobase/trx/trx0trx.cc b/storage/innobase/trx/trx0trx.cc index e1efc7c895f..1d4202b3033 100644 --- a/storage/innobase/trx/trx0trx.cc +++ b/storage/innobase/trx/trx0trx.cc @@ -1470,6 +1470,12 @@ trx_commit_in_memory( } trx->commit_lsn = lsn; + + /* Tell server some activity has happened, since the trx + does changes something. Background utility threads like + master thread, purge thread or page_cleaner thread might + have some work to do. */ + srv_active_wake_master_thread(); } ut_ad(!trx->rsegs.m_noredo.undo); diff --git a/unittest/mysys/CMakeLists.txt b/unittest/mysys/CMakeLists.txt index ec4e0b91626..984b033e7aa 100644 --- a/unittest/mysys/CMakeLists.txt +++ b/unittest/mysys/CMakeLists.txt @@ -15,7 +15,7 @@ MY_ADD_TESTS(bitmap base64 my_atomic my_rdtsc lf my_malloc my_getopt dynstring byte_order - queues LINK_LIBRARIES mysys) + queues stacktrace LINK_LIBRARIES mysys) MY_ADD_TESTS(my_vsnprintf LINK_LIBRARIES strings mysys) MY_ADD_TESTS(aes LINK_LIBRARIES mysys mysys_ssl) ADD_DEFINITIONS(${SSL_DEFINES}) diff --git a/unittest/mysys/stacktrace-t.c b/unittest/mysys/stacktrace-t.c new file mode 100644 index 00000000000..8fa0db15b36 --- /dev/null +++ b/unittest/mysys/stacktrace-t.c @@ -0,0 +1,67 @@ + +/* Copyright (c) 2020, MariaDB Corporation. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ + +#include <my_global.h> +#include <my_sys.h> +#include <stdio.h> +#include <my_stacktrace.h> +#include <tap.h> + +char b_bss[10]; + +void test_my_safe_print_str() +{ + char b_stack[10]; + char *b_heap= strdup("LEGAL"); + memcpy(b_stack, "LEGAL", 6); + memcpy(b_bss, "LEGAL", 6); + +#ifndef __SANITIZE_ADDRESS__ + fprintf(stderr, "\n===== stack =====\n"); + my_safe_print_str(b_stack, 65535); + fprintf(stderr, "\n===== heap =====\n"); + my_safe_print_str(b_heap, 65535); + fprintf(stderr, "\n===== BSS =====\n"); + my_safe_print_str(b_bss, 65535); + fprintf(stderr, "\n===== data =====\n"); + my_safe_print_str("LEGAL", 65535); + fprintf(stderr, "\n===== Above is a junk, but it is expected. =====\n"); +#endif /*__SANITIZE_ADDRESS__*/ + fprintf(stderr, "\n===== Nornal length test =====\n"); + my_safe_print_str("LEGAL", 5); + fprintf(stderr, "\n===== NULL =====\n"); + my_safe_print_str(0, 5); +#ifndef __SANITIZE_ADDRESS__ + fprintf(stderr, "\n===== (const char*) 1 =====\n"); + my_safe_print_str((const char*)1, 5); +#endif /*__SANITIZE_ADDRESS__*/ + + free(b_heap); + + ok(1, "test_my_safe_print_str"); +} + + +int main(int argc __attribute__((unused)), char **argv) +{ + MY_INIT(argv[0]); + plan(1); + + test_my_safe_print_str(); + + my_end(0); + return exit_status(); +} |