diff options
author | Marko Mäkelä <marko.makela@mariadb.com> | 2020-08-20 11:01:47 +0300 |
---|---|---|
committer | Marko Mäkelä <marko.makela@mariadb.com> | 2020-08-20 11:01:47 +0300 |
commit | 2fa9f8c53a80e8b52c14d8c3260b18e7e77cc154 (patch) | |
tree | e1e69ba81d7dd1b170b8572edc6e7625b38567b8 | |
parent | f8bf5b0f8431493975f8f4488d0bef6e0e4e289e (diff) | |
parent | de0e7cd72a6e071aba686178a8ff461dd5a757f5 (diff) | |
download | mariadb-git-2fa9f8c53a80e8b52c14d8c3260b18e7e77cc154.tar.gz |
Merge 10.3 into 10.4
38 files changed, 453 insertions, 323 deletions
diff --git a/client/mysqltest.cc b/client/mysqltest.cc index 33e4d04527f..368ac6a0fb7 100644 --- a/client/mysqltest.cc +++ b/client/mysqltest.cc @@ -9043,10 +9043,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 67e38ebf821..69005b69b63 100644 --- a/extra/mariabackup/xtrabackup.cc +++ b/extra/mariabackup/xtrabackup.cc @@ -252,6 +252,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 @@ -2002,10 +2008,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 9de067b0e3f..a7426327ecf 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 ff5b7c15b8b..e2b456aa2ed 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 d54228dd090..c2ec14e3bfe 100644 --- a/mysql-test/suite/innodb/r/foreign_key.result +++ b/mysql-test/suite/innodb/r/foreign_key.result @@ -659,6 +659,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, @@ -714,6 +715,32 @@ 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 CREATE TABLE t1 (a GEOMETRY, INDEX(a(8)), FOREIGN KEY (a) REFERENCES x (xx)) ENGINE=InnoDB; diff --git a/mysql-test/suite/innodb/r/innodb.result b/mysql-test/suite/innodb/r/innodb.result index e2937fe2073..b48a85a2443 100644 --- a/mysql-test/suite/innodb/r/innodb.result +++ b/mysql-test/suite/innodb/r/innodb.result @@ -2544,7 +2544,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; @@ -2553,6 +2552,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 7ff154538cb..acf31bc6131 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 # MDEV-21792 Server aborts upon attempt to create foreign key on spatial field diff --git a/mysql-test/suite/innodb/t/innodb.test b/mysql-test/suite/innodb/t/innodb.test index ab12cac5ea1..a81e6c3f900 100644 --- a/mysql-test/suite/innodb/t/innodb.test +++ b/mysql-test/suite/innodb/t/innodb.test @@ -1626,7 +1626,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; @@ -1642,6 +1641,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 183dab52cbf..2da3ae77b9f 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 f219625b490..d5bbecfa7c2 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 3dda22507af..dc04c18a6c1 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 @@ -370,11 +371,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 106151c4989..856d9bb0d98 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -3092,7 +3092,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 9465a51f3fe..05b8389a521 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/btr0btr.cc b/storage/innobase/btr/btr0btr.cc index 7ff0820dd13..1f104e59db8 100644 --- a/storage/innobase/btr/btr0btr.cc +++ b/storage/innobase/btr/btr0btr.cc @@ -5325,7 +5325,6 @@ btr_validate_index( if (!btr_validate_level(index, trx, n - i, lockout)) { err = DB_CORRUPTION; - break; } } diff --git a/storage/innobase/btr/btr0cur.cc b/storage/innobase/btr/btr0cur.cc index 0dae73c56d7..ac88ea26d39 100644 --- a/storage/innobase/btr/btr0cur.cc +++ b/storage/innobase/btr/btr0cur.cc @@ -3497,7 +3497,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: @@ -4585,6 +4585,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 */ @@ -4781,7 +4782,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 905c04fa811..51b67237f22 100644 --- a/storage/innobase/buf/buf0buf.cc +++ b/storage/innobase/buf/buf0buf.cc @@ -5615,9 +5615,21 @@ buf_page_create( && block->index); if (drop_hash_entry) { - mutex_enter(&block->mutex); - buf_page_set_sticky(&block->page); - mutex_exit(&block->mutex); + /* 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) { + block->fix(); + 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); + block->unfix(); + } + rw_lock_x_lock(&block->lock); } #endif /* Page can be found in buf_pool */ @@ -5628,11 +5640,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 9b49b9570e2..45c9b661d6f 100644 --- a/storage/innobase/buf/buf0flu.cc +++ b/storage/innobase/buf/buf0flu.cc @@ -3079,7 +3079,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) { @@ -3171,7 +3171,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 38429878b65..c088a5c7dc1 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -431,6 +431,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 */ @@ -1830,6 +1838,23 @@ static int innobase_wsrep_set_checkpoint(handlerton* hton, const XID* xid); static int innobase_wsrep_get_checkpoint(handlerton* hton, XID* xid); #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. @@ -3478,8 +3503,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 */ @@ -3487,34 +3511,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); } @@ -6453,6 +6464,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); } @@ -8150,6 +8166,8 @@ report_error: } func_exit: + innobase_active_small(); + DBUG_RETURN(error_result); } @@ -8829,6 +8847,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_is_local(m_user_thd) @@ -8890,6 +8913,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_is_local(m_user_thd) @@ -12705,6 +12733,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); } @@ -12854,6 +12883,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); } @@ -18782,7 +18816,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 df42f20c55d..2b74d2a4b4c 100644 --- a/storage/innobase/handler/handler0alter.cc +++ b/storage/innobase/handler/handler0alter.cc @@ -10863,11 +10863,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); @@ -11244,6 +11244,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/log0log.h b/storage/innobase/include/log0log.h index 399319537c8..368d912f07f 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 @@ -263,14 +257,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 @@ -280,12 +266,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 */ @@ -362,7 +342,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 7dfa7c0db68..8dfd86d3078 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, 2019, 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_CHECKSUM); } -/** 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 961d6aa1073..e1d37613dc9 100644 --- a/storage/innobase/include/srv0srv.h +++ b/storage/innobase/include/srv0srv.h @@ -784,6 +784,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. @@ -812,13 +825,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 8e0fe582c84..130c830858b 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; @@ -674,7 +671,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/page/page0page.cc b/storage/innobase/page/page0page.cc index 86c86bd084d..ae2cf1870e1 100644 --- a/storage/innobase/page/page0page.cc +++ b/storage/innobase/page/page0page.cc @@ -2455,6 +2455,7 @@ wrong_page_type: /* Validate the record list in a loop checking also that it is consistent with the directory. */ ulint count = 0, data_size = 0, own_count = 1, slot_no = 0; + ulint info_bits; slot_no = 0; slot = page_dir_get_nth_slot(page, slot_no); @@ -2478,9 +2479,16 @@ wrong_page_type: goto next_rec; } + info_bits = rec_get_info_bits(rec, page_is_comp(page)); + if (info_bits + & ~(REC_INFO_MIN_REC_FLAG | REC_INFO_DELETED_FLAG)) { + ib::error() << "info_bits has an incorrect value " + << info_bits; + ret = false; + } + if (rec == first_rec) { - if ((rec_get_info_bits(rec, page_is_comp(page)) - & REC_INFO_MIN_REC_FLAG)) { + if (info_bits & REC_INFO_MIN_REC_FLAG) { if (page_has_prev(page)) { ib::error() << "REC_INFO_MIN_REC_FLAG " "is set on non-left page"; @@ -2491,8 +2499,7 @@ wrong_page_type: ib::error() << "REC_INFO_MIN_REC_FLAG " "is set in a leaf-page record"; ret = false; - } else if (!rec_get_deleted_flag( - rec, page_is_comp(page)) + } else if (!(info_bits & REC_INFO_DELETED_FLAG) != !index->table->instant) { ib::error() << (index->table->instant ? "Metadata record " @@ -2506,13 +2513,51 @@ wrong_page_type: ib::error() << "Metadata record is missing"; ret = false; } - } else if (rec_get_info_bits(rec, page_is_comp(page)) - & REC_INFO_MIN_REC_FLAG) { + } else if (info_bits & REC_INFO_MIN_REC_FLAG) { ib::error() << "REC_INFO_MIN_REC_FLAG record is not " "first in page"; ret = false; } + if (page_is_comp(page)) { + const rec_comp_status_t status = rec_get_status(rec); + if (status != REC_STATUS_ORDINARY + && status != REC_STATUS_NODE_PTR + && status != REC_STATUS_INFIMUM + && status != REC_STATUS_SUPREMUM + && status != REC_STATUS_INSTANT) { + ib::error() << "impossible record status " + << status; + ret = false; + } else if (page_rec_is_infimum(rec)) { + if (status != REC_STATUS_INFIMUM) { + ib::error() + << "infimum record has status " + << status; + ret = false; + } + } else if (page_rec_is_supremum(rec)) { + if (status != REC_STATUS_SUPREMUM) { + ib::error() << "supremum record has " + "status " + << status; + ret = false; + } + } else if (!page_is_leaf(page)) { + if (status != REC_STATUS_NODE_PTR) { + ib::error() << "node ptr record has " + "status " + << status; + ret = false; + } + } else if (!index->is_instant() + && status == REC_STATUS_INSTANT) { + ib::error() << "instantly added record in a " + "non-instant index"; + ret = false; + } + } + /* Check that the records are in the ascending order */ if (count >= PAGE_HEAP_NO_USER_LOW && !page_rec_is_supremum(rec)) { diff --git a/storage/innobase/row/row0mysql.cc b/storage/innobase/row/row0mysql.cc index ac5986243d6..86cdf1995db 100644 --- a/storage/innobase/row/row0mysql.cc +++ b/storage/innobase/row/row0mysql.cc @@ -3811,7 +3811,7 @@ funct_exit_all_freed: trx->op_info = ""; - srv_inc_activity_count(); + srv_wake_master_thread(); DBUG_RETURN(err); } @@ -4522,12 +4522,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 2f66f3636ff..2f4cb90e265 100644 --- a/storage/innobase/row/row0uins.cc +++ b/storage/innobase/row/row0uins.cc @@ -84,11 +84,11 @@ row_undo_ins_remove_clust_rec( online = false; } 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->rec_type == TRX_UNDO_INSERT_REC); - 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); ut_ad(node->table->id != DICT_COLUMNS_ID); mtr_s_lock_index(index, &mtr); @@ -551,6 +551,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 e9551d33c73..e4654354068 100644 --- a/storage/innobase/row/row0umod.cc +++ b/storage/innobase/row/row0umod.cc @@ -269,10 +269,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_sys.latch, - RW_LOCK_FLAG_X | RW_LOCK_FLAG_S)); log_free_check(); pcur = &node->pcur; @@ -284,11 +281,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); } @@ -327,17 +325,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_sys.latch 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( @@ -911,37 +899,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)) @@ -1054,8 +1011,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 @@ -1200,8 +1156,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; @@ -1364,6 +1319,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 a07258910b4..789bcc441bc 100644 --- a/storage/innobase/row/row0undo.cc +++ b/storage/innobase/row/row0undo.cc @@ -418,15 +418,17 @@ row_undo( return DB_SUCCESS; } - /* 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_sys.latch locked in x-mode. Do not - try to lock again, because that would cause a hang. */ - + /* 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.) */ trx_t* trx = node->trx; - const bool locked_data_dict = (trx->dict_operation_lock_mode == 0); + const bool locked_data_dict = UNIV_UNLIKELY(trx->is_recovered) + && !trx->dict_operation_lock_mode; - if (locked_data_dict) { + if (UNIV_UNLIKELY(locked_data_dict)) { row_mysql_freeze_data_dictionary(trx); } @@ -446,7 +448,7 @@ row_undo( err = DB_CORRUPTION; } - 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 0bd52cb486d..a5305684935 100644 --- a/storage/innobase/srv/srv0srv.cc +++ b/storage/innobase/srv/srv0srv.cc @@ -1910,6 +1910,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(!mutex_own(&srv_sys.mutex)); + + srv_inc_activity_count(); + + if (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() @@ -1925,6 +1952,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. @@ -1936,20 +1971,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); } /********************************************************************//** @@ -2346,30 +2376,48 @@ 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; + + srv_main_thread_op_info = "waiting for server activity"; + + srv_resume_thread(slot); + goto loop; } /** @return whether purge should exit due to shutdown */ @@ -2537,13 +2585,15 @@ static uint32_t 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 42d757d1a84..746935f5794 100644 --- a/storage/innobase/srv/srv0start.cc +++ b/storage/innobase/srv/srv0start.cc @@ -1088,7 +1088,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)) { @@ -2420,7 +2420,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 917274d5f0d..32b053b2bab 100644 --- a/storage/innobase/trx/trx0roll.cc +++ b/storage/innobase/trx/trx0roll.cc @@ -160,6 +160,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 d63d7db4e32..7da5b2bc738 100644 --- a/storage/innobase/trx/trx0trx.cc +++ b/storage/innobase/trx/trx0trx.cc @@ -1485,6 +1485,11 @@ inline void trx_t::commit_in_memory(const mtr_t *mtr) must_flush_log_later= true; else if (srv_flush_log_at_trx_commit) trx_flush_log_if_needed(commit_lsn, this); + + /* 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(!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(); +} |