Merge 10.3 into 10.4
This commit is contained in:
commit
2fa9f8c53a
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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 |
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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 |
|
||||
|
@ -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;
|
||||
#
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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 "
|
||||
|
@ -5325,7 +5325,6 @@ btr_validate_index(
|
||||
|
||||
if (!btr_validate_level(index, trx, n - i, lockout)) {
|
||||
err = DB_CORRUPTION;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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 */
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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 */
|
||||
@ -1829,6 +1837,23 @@ wsrep_abort_transaction(handlerton* hton, THD *bf_thd, THD *victim_thd,
|
||||
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
|
||||
@ -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,
|
||||
|
@ -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++) {
|
||||
|
@ -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 */
|
||||
|
@ -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 */
|
||||
|
@ -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
|
||||
|
@ -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));
|
||||
}
|
||||
|
||||
/******************************************************//**
|
||||
|
@ -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)) {
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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(
|
||||
@ -910,37 +898,6 @@ func_exit_no_pcur:
|
||||
return(err);
|
||||
}
|
||||
|
||||
/***********************************************************//**
|
||||
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 */
|
||||
@ -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));
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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})
|
||||
|
67
unittest/mysys/stacktrace-t.c
Normal file
67
unittest/mysys/stacktrace-t.c
Normal file
@ -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();
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user