Commit 648fb98e authored by Jan Lindström's avatar Jan Lindström

MDEV-6348: mariadb crash signal 11

Analysis: sync array output function, should make sure that all
used pointers are valid before using them.

Merge revision 4225 from lp:maria/5.5.
parent 2b4b857d
--echo #
--echo # Testing robustness against random compression failures
--echo #
--source include/not_embedded.inc
--source include/have_innodb.inc
--disable_query_log
# record the file format in order to restore in the end.
--let $file_format_save = `SELECT @@innodb_file_format`
--let $file_format_max_save = `SELECT @@innodb_file_format_max`
--let $simulate_comp_failures_save = `SELECT @@innodb_simulate_comp_failures`
--disable_warnings
DROP TABLE IF EXISTS t1;
SET GLOBAL INNODB_FILE_FORMAT='Barracuda';
--enable_warnings
# since this test generates lot of errors in log, suppress checking errors
call mtr.add_suppression(".*");
--enable_query_log
# create the table with compressed pages of size 8K.
CREATE TABLE t1(id INT AUTO_INCREMENT PRIMARY KEY, msg VARCHAR(255), KEY msg_i(msg)) ENGINE=INNODB ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=8;
# percentage of compressions that will be forced to fail
SET GLOBAL innodb_simulate_comp_failures = 25;
--disable_query_log
--disable_result_log
let $num_inserts_ind = $num_inserts;
while ($num_inserts_ind)
{
let $repeat = `select floor(rand() * 10)`;
eval
INSERT INTO t1(id, msg)
VALUES ($num_inserts_ind, REPEAT('abcdefghijklmnopqrstuvwxyz', $repeat));
dec $num_inserts_ind;
}
--enable_query_log
--enable_result_log
SELECT COUNT(*) FROM t1;
--disable_query_log
--disable_result_log
# do random ops, making sure that some pages will get fragmented and reorganized.
let $num_ops_ind = $num_ops;
while($num_ops_ind)
{
let $idx = `select floor(rand()*$num_inserts)`;
let $insert_or_update = `select floor(rand()*3)`;
let $repeat = `select floor(rand() * 9) + 1`;
let $msg = query_get_value(`select repeat('abcdefghijklmnopqrstuvwxyz', $repeat) as x`, x, 1);
let $single_or_multi = `select floor(rand()*10)`;
if ($insert_or_update)
{
let $cnt = query_get_value(SELECT COUNT(*) cnt FROM t1 WHERE id=$idx, cnt, 1);
if ($cnt)
{
let $update = `select floor(rand()*2)`;
if ($update)
{
if ($single_or_multi)
{
eval UPDATE t1 SET msg=\"$msg\" WHERE id=$idx;
}
if (!$single_or_multi)
{
eval UPDATE t1 SET msg=\"$msg\" WHERE id >= $idx - 100 AND id <= $idx + 100;
}
}
if (!$update)
{
if ($single_or_multi)
{
eval INSERT INTO t1(msg, id) VALUES (\"$msg\", $idx) ON DUPLICATE KEY UPDATE msg=VALUES(msg), id = VALUES(id);
}
if (!$single_or_multi)
{
let $diff = 200;
while ($diff)
{
eval INSERT INTO t1(msg, id) VALUES (\"$msg\", $idx + 100 - $diff) ON DUPLICATE KEY UPDATE msg=VALUES(msg), id=VALUES(id);
dec $diff;
}
}
}
}
if (!$cnt)
{
let $null_msg = `select floor(rand()*2)`;
if ($null_msg)
{
eval INSERT INTO t1(id,msg) VALUES ($idx, NULL);
}
if (!$null_msg)
{
eval INSERT INTO t1(id, msg) VALUES ($idx, \"$msg\");
}
}
}
if (!$insert_or_update)
{
if ($single_or_multi)
{
eval DELETE from t1 WHERE id=$idx;
}
if (!$single_or_multi)
{
eval DELETE from t1 WHERE id >= $idx - 100 AND id <= $idx + 100;
}
}
dec $num_ops_ind;
}
# final cleanup
DROP TABLE t1;
# restore innodb_file_format and innodb_file_format_max
eval SET GLOBAL innodb_file_format = \"$file_format_save\";
eval SET GLOBAL innodb_file_format_max = \"$file_format_max_save\";
eval SET GLOBAL innodb_simulate_comp_failures = $simulate_comp_failures_save;
--enable_query_log
#
# Testing robustness against random compression failures
#
CREATE TABLE t1(id INT AUTO_INCREMENT PRIMARY KEY, msg VARCHAR(255), KEY msg_i(msg)) ENGINE=INNODB ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=8;
SET GLOBAL innodb_simulate_comp_failures = 25;
SELECT COUNT(*) FROM t1;
COUNT(*)
100000
#
# Testing robustness against random compression failures
#
CREATE TABLE t1(id INT AUTO_INCREMENT PRIMARY KEY, msg VARCHAR(255), KEY msg_i(msg)) ENGINE=INNODB ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=8;
SET GLOBAL innodb_simulate_comp_failures = 25;
SELECT COUNT(*) FROM t1;
COUNT(*)
10000
--source include/big_test.inc
# test takes too long with valgrind
--source include/not_valgrind.inc
--let $num_inserts = 100000
--let $num_ops = 30000
--source suite/innodb/include/innodb_simulate_comp_failures.inc
# clean exit
--exit
--let $num_inserts = 10000
--let $num_ops = 3000
--source suite/innodb/include/innodb_simulate_comp_failures.inc
# clean exit
--exit
--source include/have_innodb.inc
SET @start_global_value = @@global.innodb_simulate_comp_failures;
SELECT @start_global_value;
#
# exists as global only
#
--echo Valid values are between 0 and 99
select @@global.innodb_simulate_comp_failures between 0 and 99;
select @@global.innodb_simulate_comp_failures;
--error ER_INCORRECT_GLOBAL_LOCAL_VAR
select @@session.innodb_simulate_comp_failures;
show global variables like 'innodb_simulate_comp_failures';
show session variables like 'innodb_simulate_comp_failures';
select * from information_schema.global_variables where variable_name='innodb_simulate_comp_failures';
select * from information_schema.session_variables where variable_name='innodb_simulate_comp_failures';
#
# show that it's writable
#
set global innodb_simulate_comp_failures=10;
select @@global.innodb_simulate_comp_failures;
select * from information_schema.global_variables where variable_name='innodb_simulate_comp_failures';
select * from information_schema.session_variables where variable_name='innodb_simulate_comp_failures';
--error ER_GLOBAL_VARIABLE
set session innodb_simulate_comp_failures=1;
#
# incorrect types
#
--error ER_WRONG_TYPE_FOR_VAR
set global innodb_simulate_comp_failures=1.1;
--error ER_WRONG_TYPE_FOR_VAR
set global innodb_simulate_comp_failures=1e1;
--error ER_WRONG_TYPE_FOR_VAR
set global innodb_simulate_comp_failures="foo";
set global innodb_simulate_comp_failures=-7;
select @@global.innodb_simulate_comp_failures;
select * from information_schema.global_variables where variable_name='innodb_simulate_comp_failures';
set global innodb_simulate_comp_failures=106;
select @@global.innodb_simulate_comp_failures;
select * from information_schema.global_variables where variable_name='innodb_simulate_comp_failures';
#
# min/max/DEFAULT values
#
set global innodb_simulate_comp_failures=0;
select @@global.innodb_simulate_comp_failures;
set global innodb_simulate_comp_failures=99;
select @@global.innodb_simulate_comp_failures;
set global innodb_simulate_comp_failures=DEFAULT;
select @@global.innodb_simulate_comp_failures;
SET @@global.innodb_simulate_comp_failures = @start_global_value;
SELECT @@global.innodb_simulate_comp_failures;
......@@ -16793,6 +16793,11 @@ static MYSQL_SYSVAR_ULONG(saved_page_number_debug,
NULL, innodb_save_page_no, 0, 0, UINT_MAX32, 0);
#endif /* UNIV_DEBUG */
static MYSQL_SYSVAR_UINT(simulate_comp_failures, srv_simulate_comp_failures,
PLUGIN_VAR_NOCMDARG,
"Simulate compression failures.",
NULL, NULL, 0, 0, 99, 0);
static struct st_mysql_sys_var* innobase_system_variables[]= {
MYSQL_SYSVAR(additional_mem_pool_size),
MYSQL_SYSVAR(api_trx_level),
......@@ -16950,6 +16955,7 @@ static struct st_mysql_sys_var* innobase_system_variables[]= {
MYSQL_SYSVAR(fil_make_page_dirty_debug),
MYSQL_SYSVAR(saved_page_number_debug),
#endif /* UNIV_DEBUG */
MYSQL_SYSVAR(simulate_comp_failures),
NULL
};
......
......@@ -3,6 +3,7 @@
Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved.
Copyright (c) 2008, 2009, Google Inc.
Copyright (c) 2009, Percona Inc.
Copyright (c) 2013, 2014, SkySQL Ab. All Rights Reserved.
Portions of this file contain modifications contributed and copyrighted by
Google, Inc. Those modifications are gratefully acknowledged and are described
......@@ -449,6 +450,9 @@ extern struct export_var_t export_vars;
/** Global counters */
extern srv_stats_t srv_stats;
/** Simulate compression failures. */
extern uint srv_simulate_comp_failures;
# ifdef UNIV_PFS_THREAD
/* Keys to register InnoDB threads with performance schema */
extern mysql_pfs_key_t buf_page_cleaner_thread_key;
......
......@@ -1309,6 +1309,28 @@ page_zip_compress(
MONITOR_INC(MONITOR_PAGE_COMPRESS);
/* Simulate a compression failure with a probability determined by
innodb_simulate_comp_failures, only if the page has 2 or more
records. */
if (srv_simulate_comp_failures
&& page_get_n_recs(page) >= 2
&& ((ulint)(rand() % 100) < srv_simulate_comp_failures)) {
#ifdef UNIV_DEBUG
fprintf(stderr,
"InnoDB: Simulating a compression failure"
" for table %s, index %s, page %lu (%s)\n",
index->table_name,
index->name,
page_get_page_no(page),
page_is_leaf(page) ? "leaf" : "non-leaf");
#endif
goto err_exit;
}
heap = mem_heap_create(page_zip_get_size(page_zip)
+ n_fields * (2 + sizeof(ulint))
+ REC_OFFS_HEADER_SIZE
......
......@@ -3,6 +3,7 @@
Copyright (c) 1995, 2013, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2008, 2009 Google Inc.
Copyright (c) 2009, Percona Inc.
Copyright (c) 2013, 2014, SkySQL Ab. All Rights Reserved.
Portions of this file contain modifications contributed and copyrighted by
Google, Inc. Those modifications are gratefully acknowledged and are described
......@@ -465,6 +466,9 @@ current_time % 5 != 0. */
#endif /* MEM_PERIODIC_CHECK */
# define SRV_MASTER_DICT_LRU_INTERVAL (47)
/** Simulate compression failures. */
UNIV_INTERN uint srv_simulate_comp_failures = 0;
/** Acquire the system_mutex. */
#define srv_sys_mutex_enter() do { \
mutex_enter(&srv_sys->mutex); \
......
......@@ -454,19 +454,21 @@ sync_array_cell_print(
been freed meanwhile */
mutex = cell->old_wait_mutex;
fprintf(file,
"Mutex at %p created file %s line %lu, lock var %lu\n"
if (mutex) {
fprintf(file,
"Mutex at %p created file %s line %lu, lock var %lu\n"
#ifdef UNIV_SYNC_DEBUG
"Last time reserved in file %s line %lu, "
"Last time reserved in file %s line %lu, "
#endif /* UNIV_SYNC_DEBUG */
"waiters flag %lu\n",
(void*) mutex, innobase_basename(mutex->cfile_name),
(ulong) mutex->cline,
(ulong) mutex->lock_word,
"waiters flag %lu\n",
(void*) mutex, innobase_basename(mutex->cfile_name),
(ulong) mutex->cline,
(ulong) mutex->lock_word,
#ifdef UNIV_SYNC_DEBUG
mutex->file_name, (ulong) mutex->line,
mutex->file_name, (ulong) mutex->line,
#endif /* UNIV_SYNC_DEBUG */
(ulong) mutex->waiters);
(ulong) mutex->waiters);
}
} else if (type == RW_LOCK_EX
|| type == RW_LOCK_WAIT_EX
......@@ -478,33 +480,35 @@ sync_array_cell_print(
rwlock = cell->old_wait_rw_lock;
fprintf(file,
" RW-latch at %p created in file %s line %lu\n",
(void*) rwlock, innobase_basename(rwlock->cfile_name),
(ulong) rwlock->cline);
writer = rw_lock_get_writer(rwlock);
if (writer != RW_LOCK_NOT_LOCKED) {
if (rwlock) {
fprintf(file,
"a writer (thread id %lu) has"
" reserved it in mode %s",
(ulong) os_thread_pf(rwlock->writer_thread),
writer == RW_LOCK_EX
? " exclusive\n"
: " wait exclusive\n");
}
" RW-latch at %p created in file %s line %lu\n",
(void*) rwlock, innobase_basename(rwlock->cfile_name),
(ulong) rwlock->cline);
writer = rw_lock_get_writer(rwlock);
if (writer != RW_LOCK_NOT_LOCKED) {
fprintf(file,
"a writer (thread id %lu) has"
" reserved it in mode %s",
(ulong) os_thread_pf(rwlock->writer_thread),
writer == RW_LOCK_EX
? " exclusive\n"
: " wait exclusive\n");
}
fprintf(file,
"number of readers %lu, waiters flag %lu, "
"lock_word: %lx\n"
"Last time read locked in file %s line %lu\n"
"Last time write locked in file %s line %lu\n",
(ulong) rw_lock_get_reader_count(rwlock),
(ulong) rwlock->waiters,
rwlock->lock_word,
innobase_basename(rwlock->last_s_file_name),
(ulong) rwlock->last_s_line,
rwlock->last_x_file_name,
(ulong) rwlock->last_x_line);
fprintf(file,
"number of readers %lu, waiters flag %lu, "
"lock_word: %lx\n"
"Last time read locked in file %s line %lu\n"
"Last time write locked in file %s line %lu\n",
(ulong) rw_lock_get_reader_count(rwlock),
(ulong) rwlock->waiters,
rwlock->lock_word,
innobase_basename(rwlock->last_s_file_name),
(ulong) rwlock->last_s_line,
rwlock->last_x_file_name,
(ulong) rwlock->last_x_line);
}
} else {
ut_error;
}
......
......@@ -17938,6 +17938,11 @@ static MYSQL_SYSVAR_ULONG(saved_page_number_debug,
NULL, innodb_save_page_no, 0, 0, UINT_MAX32, 0);
#endif /* UNIV_DEBUG */
static MYSQL_SYSVAR_UINT(simulate_comp_failures, srv_simulate_comp_failures,
PLUGIN_VAR_NOCMDARG,
"Simulate compression failures.",
NULL, NULL, 0, 0, 99, 0);
const char *corrupt_table_action_names[]=
{
"assert", /* 0 */
......@@ -18165,6 +18170,7 @@ static struct st_mysql_sys_var* innobase_system_variables[]= {
MYSQL_SYSVAR(fake_changes),
MYSQL_SYSVAR(locking_fake_changes),
MYSQL_SYSVAR(use_stacktrace),
MYSQL_SYSVAR(simulate_comp_failures),
NULL
};
......
......@@ -3,6 +3,7 @@
Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved.
Copyright (c) 2008, 2009, Google Inc.
Copyright (c) 2009, Percona Inc.
Copyright (c) 2013, 2014, SkySQL Ab. All Rights Reserved.
Portions of this file contain modifications contributed and copyrighted by
Google, Inc. Those modifications are gratefully acknowledged and are described
......@@ -587,6 +588,8 @@ extern srv_stats_t srv_stats;
When FALSE, row locks are not taken at all. */
extern my_bool srv_fake_changes_locks;
/** Simulate compression failures. */
extern uint srv_simulate_comp_failures;
# ifdef UNIV_PFS_THREAD
/* Keys to register InnoDB threads with performance schema */
......
......@@ -2,6 +2,7 @@
Copyright (c) 2005, 2014, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2012, Facebook Inc.
Copyright (c) 2014, SkySQL Ab. All Rights Reserved.
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
......@@ -1313,6 +1314,28 @@ page_zip_compress(
MONITOR_INC(MONITOR_PAGE_COMPRESS);
/* Simulate a compression failure with a probability determined by
innodb_simulate_comp_failures, only if the page has 2 or more
records. */
if (srv_simulate_comp_failures
&& page_get_n_recs(page) >= 2
&& ((ulint)(rand() % 100) < srv_simulate_comp_failures)) {
#ifdef UNIV_DEBUG
fprintf(stderr,
"InnoDB: Simulating a compression failure"
" for table %s, index %s, page %lu (%s)\n",
index->table_name,
index->name,
page_get_page_no(page),
page_is_leaf(page) ? "leaf" : "non-leaf");
#endif
goto err_exit;
}
heap = mem_heap_create(page_zip_get_size(page_zip)
+ n_fields * (2 + sizeof(ulint))
+ REC_OFFS_HEADER_SIZE
......
......@@ -3,6 +3,7 @@
Copyright (c) 1995, 2013, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2008, 2009 Google Inc.
Copyright (c) 2009, Percona Inc.
Copyright (c) 2013, 2014, SkySQL Ab. All Rights Reserved.
Portions of this file contain modifications contributed and copyrighted by
Google, Inc. Those modifications are gratefully acknowledged and are described
......@@ -619,6 +620,9 @@ current_time % 5 != 0. */
? thd_lock_wait_timeout((trx)->mysql_thd) \
: 0)
/** Simulate compression failures. */
UNIV_INTERN uint srv_simulate_comp_failures = 0;
/*
IMPLEMENTATION OF THE SERVER MAIN PROGRAM
=========================================
......
......@@ -2,6 +2,7 @@
Copyright (c) 1995, 2013, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2008, Google Inc.
Copyright (c) 2013, 2014, SkySQL Ab. All Rights Reserved.
Portions of this file contain modifications contributed and copyrighted by
Google, Inc. Those modifications are gratefully acknowledged and are described
......@@ -460,16 +461,9 @@ sync_array_cell_print(
innobase_basename(cell->file), (ulong) cell->line,
difftime(time(NULL), cell->reservation_time));
/* If stacktrace feature is enabled we will send a SIGUSR2
signal to thread waiting for the semaphore. Signal handler
will then dump the current stack to error log. */
if (srv_use_stacktrace) {
#ifdef __linux__
pthread_kill(cell->thread, SIGUSR2);
#endif
}
if (type == SYNC_MUTEX || type == SYNC_PRIO_MUTEX) {
/* We use old_wait_mutex in case the cell has already
been freed meanwhile */
if (type == SYNC_MUTEX) {
......@@ -483,18 +477,29 @@ sync_array_cell_print(
}
fprintf(file,
"Mutex at %p '%s', lock var %lu\n"
if (mutex) {
fprintf(file,
"Mutex at %p '%s', lock var %lu\n"
#ifdef UNIV_SYNC_DEBUG
"Last time reserved in file %s line %lu, "
"Last time reserved in file %s line %lu, "
#endif /* UNIV_SYNC_DEBUG */
"waiters flag %lu\n",
(void*) mutex, mutex->cmutex_name,
(ulong) mutex->lock_word,
"waiters flag %lu\n",
(void*) mutex, mutex->cmutex_name,
(ulong) mutex->lock_word,
#ifdef UNIV_SYNC_DEBUG
mutex->file_name, (ulong) mutex->line,
mutex->file_name, (ulong) mutex->line,
#endif /* UNIV_SYNC_DEBUG */
(ulong) mutex->waiters);
(ulong) mutex->waiters);
}
/* If stacktrace feature is enabled we will send a SIGUSR2
signal to thread waiting for the semaphore. Signal handler
will then dump the current stack to error log. */
if (srv_use_stacktrace && cell && cell->thread) {
#ifdef __linux__
pthread_kill(cell->thread, SIGUSR2);
#endif
}
if (type == SYNC_PRIO_MUTEX) {
......@@ -529,40 +534,45 @@ sync_array_cell_print(
rwlock = &prio_rwlock->base_lock;
}
fprintf(file,
" RW-latch at %p '%s'\n",
(void*) rwlock, rwlock->lock_name);
writer = rw_lock_get_writer(rwlock);
if (writer != RW_LOCK_NOT_LOCKED) {
if (rwlock) {
fprintf(file,
"a writer (thread id %lu) has"
" reserved it in mode %s",
(ulong) os_thread_pf(rwlock->writer_thread),
writer == RW_LOCK_EX
? " exclusive\n"
: " wait exclusive\n");
}
fprintf(file,
"number of readers %lu, waiters flag %lu, "
"lock_word: %lx\n"
"Last time read locked in file %s line %lu\n"
"Last time write locked in file %s line %lu\n",
(ulong) rw_lock_get_reader_count(rwlock),
(ulong) rwlock->waiters,
rwlock->lock_word,
innobase_basename(rwlock->last_s_file_name),
(ulong) rwlock->last_s_line,
rwlock->last_x_file_name,
(ulong) rwlock->last_x_line);
" RW-latch at %p '%s'\n",
(void*) rwlock, rwlock->lock_name);
writer = rw_lock_get_writer(rwlock);
if (writer && writer != RW_LOCK_NOT_LOCKED) {
fprintf(file,
"a writer (thread id %lu) has"
" reserved it in mode %s",
(ulong) os_thread_pf(rwlock->writer_thread),
writer == RW_LOCK_EX
? " exclusive\n"
: " wait exclusive\n");
}
/* If stacktrace feature is enabled we will send a SIGUSR2
signal to thread that has locked RW-latch with write mode.
Signal handler will then dump the current stack to error log. */
if (writer != RW_LOCK_NOT_LOCKED && srv_use_stacktrace) {
fprintf(file,
"number of readers %lu, waiters flag %lu, "
"lock_word: %lx\n"
"Last time read locked in file %s line %lu\n"
"Last time write locked in file %s line %lu\n",
(ulong) rw_lock_get_reader_count(rwlock),
(ulong) rwlock->waiters,
rwlock->lock_word,
innobase_basename(rwlock->last_s_file_name),
(ulong) rwlock->last_s_line,
rwlock->last_x_file_name,
(ulong) rwlock->last_x_line);
/* If stacktrace feature is enabled we will send a SIGUSR2
signal to thread that has locked RW-latch with write mode.
Signal handler will then dump the current stack to error log. */
if (writer != RW_LOCK_NOT_LOCKED && srv_use_stacktrace &&
rwlock && rwlock->writer_thread) {
#ifdef __linux__
pthread_kill(rwlock->writer_thread, SIGUSR2);
pthread_kill(rwlock->writer_thread, SIGUSR2);
#endif
}
}
if (prio_rwlock) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment