summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--client/mysqlslap.c15
-rw-r--r--dbug/dbug.c77
-rw-r--r--mysql-test/include/maria_empty_logs.inc2
-rw-r--r--mysql-test/include/mysqladmin_shutdown.inc7
-rw-r--r--mysql-test/include/wait_until_connected_again.inc3
-rw-r--r--mysql-test/include/wait_until_disconnected.inc24
-rwxr-xr-xmysql-test/mysql-test-run.pl11
-rw-r--r--mysql-test/suite/maria/r/maria-recovery3.result29
-rw-r--r--mysql-test/suite/maria/t/maria-recovery3-master.opt1
-rw-r--r--mysql-test/suite/maria/t/maria-recovery3.test71
-rw-r--r--mysql-test/suite/maria/t/maria_showlog_error.test2
-rw-r--r--mysql-test/t/events_logs_tests-master.opt2
-rw-r--r--mysql-test/t/log_tables-big-master.opt2
-rw-r--r--mysql-test/t/log_tables-master.opt2
-rw-r--r--mysql-test/t/multi_statement-master.opt3
-rw-r--r--mysql-test/t/ps-master.opt2
-rw-r--r--mysql-test/t/show_check-master.opt2
-rw-r--r--mysql-test/t/slow_query_log_file_basic-master.opt2
-rw-r--r--mysql-test/t/slow_query_log_file_func-master.opt2
-rw-r--r--mysql-test/t/union-master.opt2
-rw-r--r--sql/mysqld.cc12
-rw-r--r--storage/innobase/handler/ha_innodb.cc11
-rw-r--r--storage/maria/ma_blockrec.c40
-rw-r--r--storage/maria/ma_blockrec.h3
-rw-r--r--storage/maria/ma_commit.c11
-rw-r--r--storage/maria/ma_loghandler.c29
-rw-r--r--storage/maria/ma_open.c2
-rw-r--r--storage/maria/ma_recovery.c14
-rw-r--r--storage/maria/trnman.c25
29 files changed, 319 insertions, 89 deletions
diff --git a/client/mysqlslap.c b/client/mysqlslap.c
index 5ca0b1cd207..9904eeae9d0 100644
--- a/client/mysqlslap.c
+++ b/client/mysqlslap.c
@@ -1886,10 +1886,17 @@ limit_not_met:
{
if (mysql_field_count(mysql))
{
- result= mysql_store_result(mysql);
- while ((row = mysql_fetch_row(result)))
- counter++;
- mysql_free_result(result);
+ if ((result= mysql_store_result(mysql)))
+ {
+ while ((row = mysql_fetch_row(result)))
+ counter++;
+ mysql_free_result(result);
+ }
+ else
+ {
+ fprintf(stderr,"%s: Error in mysql_store_result(): %d %s\n",
+ my_progname, mysql_errno(mysql), mysql_error(mysql));
+ }
}
} while(mysql_next_result(mysql) == 0);
queries++;
diff --git a/dbug/dbug.c b/dbug/dbug.c
index 9a4a27e9f43..fc2faf867e4 100644
--- a/dbug/dbug.c
+++ b/dbug/dbug.c
@@ -177,7 +177,11 @@
static void perror(); /* Fake system/library error print routine */
#endif
+#ifdef SAFEMALLOC
IMPORT int _sanity(const char *file,uint line); /* safemalloc sanity checker */
+#else
+#define _sanity(X,Y) (1)
+#endif
/*
* The user may specify a list of functions to trace or
@@ -287,7 +291,7 @@ static void PushState(CODE_STATE *cs);
/* Free memory associated with debug state. */
static void FreeState (CODE_STATE *cs, struct settings *state, int free_state);
/* Test for tracing enabled */
-static int DoTrace(CODE_STATE *cs, int tracing);
+static int DoTrace(CODE_STATE *cs);
/*
return values of DoTrace.
Can also be used as bitmask: ret & DO_TRACE
@@ -726,7 +730,7 @@ void FixTraceFlags_helper(CODE_STATE *cs, const char *func,
It's ok, because cs->framep may only affect DO_TRACE/DONT_TRACE return
values, but we ignore them here anyway
*/
- switch(DoTrace(cs, 1)) {
+ switch(DoTrace(cs)) {
case ENABLE_TRACE:
framep->level|= TRACE_ON;
break;
@@ -1153,18 +1157,23 @@ void _db_enter_(const char *_func_, const char *_file_,
(void) fflush(cs->stack->prof_file);
}
#endif
- switch (DoTrace(cs, TRACING)) {
+ switch (DoTrace(cs)) {
case ENABLE_TRACE:
cs->framep->level|= TRACE_ON;
if (!TRACING) break;
/* fall through */
case DO_TRACE:
- if (!cs->locked)
- pthread_mutex_lock(&THR_LOCK_dbug);
- DoPrefix(cs, _line_);
- Indent(cs, cs->level);
- (void) fprintf(cs->stack->out_file, ">%s\n", cs->func);
- DbugFlush(cs); /* This does a unlock */
+ if ((cs->stack->flags & SANITY_CHECK_ON) && _sanity(_file_,_line_))
+ cs->stack->flags &= ~SANITY_CHECK_ON;
+ if (TRACING)
+ {
+ if (!cs->locked)
+ pthread_mutex_lock(&THR_LOCK_dbug);
+ DoPrefix(cs, _line_);
+ Indent(cs, cs->level);
+ (void) fprintf(cs->stack->out_file, ">%s\n", cs->func);
+ DbugFlush(cs); /* This does a unlock */
+ }
break;
case DISABLE_TRACE:
cs->framep->level&= ~TRACE_ON;
@@ -1172,11 +1181,6 @@ void _db_enter_(const char *_func_, const char *_file_,
case DONT_TRACE:
break;
}
-#ifdef SAFEMALLOC
- if (cs->stack->flags & SANITY_CHECK_ON)
- if (_sanity(_file_,_line_)) /* Check of safemalloc */
- cs->stack->flags &= ~SANITY_CHECK_ON;
-#endif
errno=save_errno;
}
@@ -1218,25 +1222,24 @@ void _db_return_(uint _line_, struct _db_stack_frame_ *_stack_frame_)
}
else
{
-#ifdef SAFEMALLOC
- if (cs->stack->flags & SANITY_CHECK_ON)
- {
- if (_sanity(_stack_frame_->file,_line_))
- cs->stack->flags &= ~SANITY_CHECK_ON;
- }
-#endif
#ifndef THREAD
if (DoProfile(cs))
(void) fprintf(cs->stack->prof_file, PROF_XFMT, Clock(), cs->func);
#endif
- if (TRACING && DoTrace(cs, 1) & DO_TRACE)
+ if (DoTrace(cs) & DO_TRACE)
{
- if (!cs->locked)
- pthread_mutex_lock(&THR_LOCK_dbug);
- DoPrefix(cs, _line_);
- Indent(cs, cs->level);
- (void) fprintf(cs->stack->out_file, "<%s\n", cs->func);
- DbugFlush(cs);
+ if ((cs->stack->flags & SANITY_CHECK_ON) &&
+ _sanity(_stack_frame_->file,_line_))
+ cs->stack->flags &= ~SANITY_CHECK_ON;
+ if (TRACING)
+ {
+ if (!cs->locked)
+ pthread_mutex_lock(&THR_LOCK_dbug);
+ DoPrefix(cs, _line_);
+ Indent(cs, cs->level);
+ (void) fprintf(cs->stack->out_file, "<%s\n", cs->func);
+ DbugFlush(cs);
+ }
}
}
/*
@@ -1694,28 +1697,24 @@ void _db_end_()
*
* DoTrace check to see if tracing is current enabled
*
- * tracing is the value of TRACING to check if the tracing is enabled
- * or 1 to check if the function is enabled (in _db_keyword_)
- *
* DESCRIPTION
*
- * Checks to see if tracing is enabled based on whether the
- * user has specified tracing, the maximum trace depth has
- * not yet been reached, the current function is selected,
- * and the current process is selected.
+ * Checks to see if dbug in this function is enabled based on
+ * whether the maximum trace depth has been reached, the current
+ * function is selected, and the current process is selected.
*
*/
-static int DoTrace(CODE_STATE *cs, int tracing)
+static int DoTrace(CODE_STATE *cs)
{
if ((cs->stack->maxdepth == 0 || cs->level <= cs->stack->maxdepth) &&
InList(cs->stack->processes, cs->process) & (MATCHED|INCLUDE))
switch(InList(cs->stack->functions, cs->func)) {
case INCLUDE|SUBDIR: return ENABLE_TRACE;
- case INCLUDE: return tracing ? DO_TRACE : DONT_TRACE;
+ case INCLUDE: return DO_TRACE;
case MATCHED|SUBDIR:
case NOT_MATCHED|SUBDIR:
- case MATCHED: return tracing && framep_trace_flag(cs, cs->framep) ?
+ case MATCHED: return framep_trace_flag(cs, cs->framep) ?
DO_TRACE : DONT_TRACE;
case EXCLUDE:
case NOT_MATCHED: return DONT_TRACE;
@@ -1786,7 +1785,7 @@ BOOLEAN _db_keyword_(CODE_STATE *cs, const char *keyword, int strict)
get_code_state_if_not_set_or_return FALSE;
strict=strict ? INCLUDE : INCLUDE|MATCHED;
- return DEBUGGING && DoTrace(cs, 1) & DO_TRACE &&
+ return DEBUGGING && DoTrace(cs) & DO_TRACE &&
InList(cs->stack->keywords, keyword) & strict;
}
diff --git a/mysql-test/include/maria_empty_logs.inc b/mysql-test/include/maria_empty_logs.inc
index 7e3f2181897..0783020c443 100644
--- a/mysql-test/include/maria_empty_logs.inc
+++ b/mysql-test/include/maria_empty_logs.inc
@@ -13,7 +13,7 @@ append_file $MYSQLTEST_VARDIR/tmp/master0.expect;
wait-maria_empty_logs.inc
EOF
---exec $MYSQLADMIN --no-defaults -S $MASTER_MYSOCK -P $MASTER_MYPORT -u root --password= shutdown 2>&1;
+--source include/mysqladmin_shutdown.inc
if (!$mel_keep_control_file)
{
diff --git a/mysql-test/include/mysqladmin_shutdown.inc b/mysql-test/include/mysqladmin_shutdown.inc
new file mode 100644
index 00000000000..16b33c2baf8
--- /dev/null
+++ b/mysql-test/include/mysqladmin_shutdown.inc
@@ -0,0 +1,7 @@
+# Initiates a clean shutdown of the server and waits for its completion
+
+--exec $MYSQLADMIN --no-defaults -S $MASTER_MYSOCK -P $MASTER_MYPORT -u root --password= shutdown 2>&1;
+
+# On Windows mysqladmin does not wait for shutdown to be finished,
+# so we have to monitor this with our connection:
+--source include/wait_until_disconnected.inc
diff --git a/mysql-test/include/wait_until_connected_again.inc b/mysql-test/include/wait_until_connected_again.inc
index 02d544cb966..4379f4d3145 100644
--- a/mysql-test/include/wait_until_connected_again.inc
+++ b/mysql-test/include/wait_until_connected_again.inc
@@ -2,6 +2,9 @@
# Include this script to wait until the connection to the
# server has been restored or timeout occurs.
# You should have done --enable_reconnect first
+# When you change this file you may have to chance its cousin
+# wait_until_disconnected.inc
+
--disable_result_log
--disable_query_log
let $counter= 5000;
diff --git a/mysql-test/include/wait_until_disconnected.inc b/mysql-test/include/wait_until_disconnected.inc
new file mode 100644
index 00000000000..cf4a574573f
--- /dev/null
+++ b/mysql-test/include/wait_until_disconnected.inc
@@ -0,0 +1,24 @@
+#
+# Include this script after a shutdown to wait until the connection
+# to the server has been lost or timeout occurs.
+# When you change this file you may have to chance its cousin
+# wait_until_connected_again.inc
+
+--disable_result_log
+--disable_query_log
+let $counter= 5000;
+let $mysql_errno= 0;
+while (!$mysql_errno)
+{
+ --error 0,2002,2003,2006,1053
+ show status;
+
+ dec $counter;
+ if (!$counter)
+ {
+ --die Server failed to disconnect me
+ }
+ --sleep 0.1
+}
+--enable_query_log
+--enable_result_log
diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl
index 5dbef8d0957..bb7c2f053a8 100755
--- a/mysql-test/mysql-test-run.pl
+++ b/mysql-test/mysql-test-run.pl
@@ -4006,11 +4006,13 @@ sub mysqld_arguments ($$$$) {
}
my $log_base_path= "$opt_vardir/log/$mysqld->{'type'}$sidx";
- mtr_add_arg($args, "%s--general-log-file=%s.log --general-log",
+ mtr_add_arg($args, "%s--general-log-file=%s.log",
$prefix, $log_base_path);
+ mtr_add_arg($args, "--general-log");
mtr_add_arg($args,
- "%s--slow-query-log-file=%s-slow.log --slow-query-log",
+ "%s--slow-query-log-file=%s-slow.log",
$prefix, $log_base_path);
+ mtr_add_arg($args, "--slow-query-log");
# Check if "extra_opt" contains --skip-log-bin
my $skip_binlog= grep(/^--skip-log-bin/, @$extra_opt, @opt_extra_mysqld_opt);
@@ -5113,8 +5115,9 @@ sub gdb_arguments {
else
{
# write init file for mysqld
- mtr_tofile($gdb_init_file,
- "set args $str\n");
+ mtr_tofile($gdb_init_file, <<EOGDB );
+set args $str
+EOGDB
}
if ( $opt_manual_gdb )
diff --git a/mysql-test/suite/maria/r/maria-recovery3.result b/mysql-test/suite/maria/r/maria-recovery3.result
new file mode 100644
index 00000000000..c1acef57a5a
--- /dev/null
+++ b/mysql-test/suite/maria/r/maria-recovery3.result
@@ -0,0 +1,29 @@
+set global maria_log_file_size=4294967295;
+drop database if exists mysqltest;
+create database mysqltest;
+use mysqltest;
+* shut down mysqld, removed logs, restarted it
+* TEST of Checkpoint between writing the commit log record and committing in trnman
+create table t1(a int primary key) engine=maria;
+insert into t1 values(1);
+flush table t1;
+* copied t1 for comparison
+set session debug="+d,maria_sleep_in_commit";
+insert into t1 values(2);
+set global maria_checkpoint_interval=1000;
+delete from t1 where a=2;
+SET SESSION debug="+d,maria_flush_whole_log,maria_crash";
+* crashing mysqld intentionally
+set global maria_checkpoint_interval=1;
+ERROR HY000: Lost connection to MySQL server during query
+* recovery happens
+check table t1 extended;
+Table Op Msg_type Msg_text
+mysqltest.t1 check status OK
+* testing that checksum after recovery is as expected
+Checksum-check
+ok
+use mysqltest;
+drop table t1;
+drop database mysqltest_for_comparison;
+drop database mysqltest;
diff --git a/mysql-test/suite/maria/t/maria-recovery3-master.opt b/mysql-test/suite/maria/t/maria-recovery3-master.opt
new file mode 100644
index 00000000000..9023fb74e8b
--- /dev/null
+++ b/mysql-test/suite/maria/t/maria-recovery3-master.opt
@@ -0,0 +1 @@
+--skip-stack-trace --skip-core-file --loose-maria-log-dir-path=$MYSQLTEST_VARDIR/tmp
diff --git a/mysql-test/suite/maria/t/maria-recovery3.test b/mysql-test/suite/maria/t/maria-recovery3.test
new file mode 100644
index 00000000000..68cc67fd328
--- /dev/null
+++ b/mysql-test/suite/maria/t/maria-recovery3.test
@@ -0,0 +1,71 @@
+--source include/not_embedded.inc
+# Don't test this under valgrind, memory leaks will occur as we crash
+--source include/not_valgrind.inc
+# Binary must be compiled with debug for crash to occur
+--source include/have_debug.inc
+--source include/have_maria.inc
+
+set global maria_log_file_size=4294967295;
+let $MARIA_LOG=../tmp;
+
+--disable_warnings
+drop database if exists mysqltest;
+--enable_warnings
+create database mysqltest;
+let $mms_tname=t;
+
+# Include scripts can perform SQL. For it to not influence the main test
+# they use a separate connection. This way if they use a DDL it would
+# not autocommit in the main test.
+connect (admin, 127.0.0.1, root,,mysqltest,,);
+--enable_reconnect
+
+connection default;
+use mysqltest;
+--enable_reconnect
+
+let $mms_tables=1;
+let $mvr_restore_old_snapshot=0;
+let $mms_compare_physically=0;
+let $mvr_debug_option="+d,maria_flush_whole_log,maria_crash";
+let $mvr_crash_statement= set global maria_checkpoint_interval=1;
+
+-- source include/maria_empty_logs.inc
+
+# Test for BUG#41037 (recovery failure)
+--echo * TEST of Checkpoint between writing the commit log record and committing in trnman
+# we want recovery to use the tables as they were at time of crash
+let $mvr_restore_old_snapshot=0;
+# UNDO phase prevents physical comparison, normally,
+# so we'll only use checksums to compare.
+let $mms_compare_physically=0;
+let $mvr_crash_statement= set global maria_checkpoint_interval=1;
+create table t1(a int primary key) engine=maria;
+insert into t1 values(1);
+-- source include/maria_make_snapshot_for_comparison.inc
+set session debug="+d,maria_sleep_in_commit";
+send insert into t1 values(2);
+sleep 1;
+# Now the INSERT of 2 has written a commit record
+# but not yet called trnman_commit(), so for checkpoint it's not
+# committed.
+connection admin;
+set global maria_checkpoint_interval=1000; # force a checkpoint
+connection default;
+reap; # end of INSERT
+delete from t1 where a=2;
+# Bug was that: Recovery starts REDO scanning from too far: from
+# Checkpoint record which says INSERT is not committed, so
+# Recovery executes the INSERT's UNDO and finds no key to delete
+# (as DELETE already deleted it), fails.
+-- source include/maria_verify_recovery.inc
+drop table t1;
+
+# Note that even if machine is loaded and thus INSERT is committed
+# before checkpoint happens, test should still pass (though it won't
+# reproduce the conditions of the bug).
+
+# clean up everything
+let $mms_purpose=comparison;
+eval drop database mysqltest_for_$mms_purpose;
+drop database mysqltest;
diff --git a/mysql-test/suite/maria/t/maria_showlog_error.test b/mysql-test/suite/maria/t/maria_showlog_error.test
index 4db78a35b38..d5eded903cd 100644
--- a/mysql-test/suite/maria/t/maria_showlog_error.test
+++ b/mysql-test/suite/maria/t/maria_showlog_error.test
@@ -1,4 +1,6 @@
-- source include/have_maria.inc
+# can't restart server in embedded
+--source include/not_embedded.inc
# remove_file can't remove opened file under windows. So we can't reproduce
# the problem there
--source include/not_windows.inc
diff --git a/mysql-test/t/events_logs_tests-master.opt b/mysql-test/t/events_logs_tests-master.opt
index 35ff7911705..73d26b7260d 100644
--- a/mysql-test/t/events_logs_tests-master.opt
+++ b/mysql-test/t/events_logs_tests-master.opt
@@ -1 +1 @@
---log-slow-queries
+--slow-query-log --log-output=table --general-log --general-log-file="" --slow-query-log-file=""
diff --git a/mysql-test/t/log_tables-big-master.opt b/mysql-test/t/log_tables-big-master.opt
index 35ff7911705..b9bc885d0e4 100644
--- a/mysql-test/t/log_tables-big-master.opt
+++ b/mysql-test/t/log_tables-big-master.opt
@@ -1 +1 @@
---log-slow-queries
+--log-output=table,file --slow-query-log --general-log --general-log-file="" --slow-query-log-file=""
diff --git a/mysql-test/t/log_tables-master.opt b/mysql-test/t/log_tables-master.opt
index 35ff7911705..4c25518cefe 100644
--- a/mysql-test/t/log_tables-master.opt
+++ b/mysql-test/t/log_tables-master.opt
@@ -1 +1 @@
---log-slow-queries
+--log-output=table,file --slow-query-log --general-log
diff --git a/mysql-test/t/multi_statement-master.opt b/mysql-test/t/multi_statement-master.opt
index b30df037531..c735cf4c21b 100644
--- a/mysql-test/t/multi_statement-master.opt
+++ b/mysql-test/t/multi_statement-master.opt
@@ -1,2 +1,3 @@
---log-slow-queries=slow.log
+--slow-query-log
+--slow-query-log-file=slow.log
--log-queries-not-using-indexes
diff --git a/mysql-test/t/ps-master.opt b/mysql-test/t/ps-master.opt
index 3eb98fc3d6b..0e3f2e5092d 100644
--- a/mysql-test/t/ps-master.opt
+++ b/mysql-test/t/ps-master.opt
@@ -1 +1 @@
---log-slow-queries --log-long-format --log-queries-not-using-indexes
+--log-output=table,file --slow-query-log --log-long-format --log-queries-not-using-indexes --general-log
diff --git a/mysql-test/t/show_check-master.opt b/mysql-test/t/show_check-master.opt
index 7a438da06cc..6fd0fec0e08 100644
--- a/mysql-test/t/show_check-master.opt
+++ b/mysql-test/t/show_check-master.opt
@@ -1 +1 @@
---log-slow-queries --log-long-format --log-queries-not-using-indexes --myisam-recover=""
+--log-output=table --slow-query-log --log-long-format --log-queries-not-using-indexes --myisam-recover="" --general-log --general-log-file="" --slow-query-log-file=""
diff --git a/mysql-test/t/slow_query_log_file_basic-master.opt b/mysql-test/t/slow_query_log_file_basic-master.opt
index aca191f7fea..2b6ac309d6c 100644
--- a/mysql-test/t/slow_query_log_file_basic-master.opt
+++ b/mysql-test/t/slow_query_log_file_basic-master.opt
@@ -1 +1 @@
---log-slow-queries=slowtest.log
+--slow-query-log --slow-query-log-file=slowtest.log
diff --git a/mysql-test/t/slow_query_log_file_func-master.opt b/mysql-test/t/slow_query_log_file_func-master.opt
index e5b1c0948b0..e866f016022 100644
--- a/mysql-test/t/slow_query_log_file_func-master.opt
+++ b/mysql-test/t/slow_query_log_file_func-master.opt
@@ -1,2 +1,2 @@
---log-slow-queries=my_slow_test.log
+--slow-query-log --slow-query-log-file=my_slow_test.log
diff --git a/mysql-test/t/union-master.opt b/mysql-test/t/union-master.opt
index 3eb98fc3d6b..4ddf5c3734a 100644
--- a/mysql-test/t/union-master.opt
+++ b/mysql-test/t/union-master.opt
@@ -1 +1 @@
---log-slow-queries --log-long-format --log-queries-not-using-indexes
+--slow-query-log --log-long-format --log-queries-not-using-indexes
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index 11838089432..dbf919959e2 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -3449,23 +3449,23 @@ static int init_common_variables(const char *conf_file_name, int argc,
sys_init_slave.value=my_strdup("",MYF(0));
/* check log options and issue warnings if needed */
- if (opt_log && opt_logname && !(log_output_options & LOG_FILE) &&
- !(log_output_options & LOG_NONE))
+ if (opt_log && opt_logname && *opt_logname &&
+ !(log_output_options & (LOG_FILE | LOG_NONE)))
sql_print_warning("Although a path was specified for the "
"--log option, log tables are used. "
"To enable logging to files use the --log-output option.");
- if (opt_slow_log && opt_slow_logname && !(log_output_options & LOG_FILE)
- && !(log_output_options & LOG_NONE))
+ if (opt_slow_log && opt_slow_logname && *opt_slow_logname &&
+ !(log_output_options & (LOG_FILE | LOG_NONE)))
sql_print_warning("Although a path was specified for the "
"--log_slow_queries option, log tables are used. "
"To enable logging to files use the --log-output=file option.");
- s= opt_logname ? opt_logname : make_default_log_name(buff, ".log");
+ s= opt_logname && *opt_logname ? opt_logname : make_default_log_name(buff, ".log");
sys_var_general_log_path.value= my_strdup(s, MYF(0));
sys_var_general_log_path.value_length= strlen(s);
- s= opt_slow_logname ? opt_slow_logname : make_default_log_name(buff, "-slow.log");
+ s= opt_slow_logname && *opt_slow_logname ? opt_slow_logname : make_default_log_name(buff, "-slow.log");
sys_var_slow_log_path.value= my_strdup(s, MYF(0));
sys_var_slow_log_path.value_length= strlen(s);
diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc
index 9c2b71094b6..396844f265b 100644
--- a/storage/innobase/handler/ha_innodb.cc
+++ b/storage/innobase/handler/ha_innodb.cc
@@ -1405,6 +1405,9 @@ innobase_init(
int err;
bool ret;
char *default_path;
+#ifdef SAFE_MUTEX
+ my_bool old_safe_mutex_deadlock_detector;
+#endif
DBUG_ENTER("innobase_init");
handlerton *innobase_hton= (handlerton *)p;
@@ -1660,13 +1663,13 @@ innobase_init(
srv_sizeof_trx_t_in_ha_innodb_cc = sizeof(trx_t);
#ifdef SAFE_MUTEX
- /* Disable deadlock detection as it's very slow for the buffer pool */
- my_bool old_safe_mutex_deadlock_detector;
- safe_mutex_deadlock_detector= 0;
+ /* Disable deadlock detection as it's very slow for the buffer pool */
+ old_safe_mutex_deadlock_detector= safe_mutex_deadlock_detector;
+ safe_mutex_deadlock_detector= 0;
#endif
err = innobase_start_or_create_for_mysql();
#ifdef SAFE_MUTEX
- safe_mutex_deadlock_detector= old_safe_mutex_deadlock_detector;
+ safe_mutex_deadlock_detector= old_safe_mutex_deadlock_detector;
#endif
if (err != DB_SUCCESS) {
my_free(internal_innobase_data_file_path,
diff --git a/storage/maria/ma_blockrec.c b/storage/maria/ma_blockrec.c
index ed4d98015b1..2709a2bba5c 100644
--- a/storage/maria/ma_blockrec.c
+++ b/storage/maria/ma_blockrec.c
@@ -5914,7 +5914,7 @@ my_bool write_hook_for_file_id(enum translog_record_type type
TRN *trn
__attribute__ ((unused)),
MARIA_HA *tbl_info,
- LSN *lsn __attribute__ ((unused)),
+ LSN *lsn,
void *hook_arg
__attribute__ ((unused)))
{
@@ -5923,6 +5923,44 @@ my_bool write_hook_for_file_id(enum translog_record_type type
return 0;
}
+
+/**
+ Updates transaction's rec_lsn when committing.
+
+ A transaction writes its commit record before being committed in trnman, so
+ if Checkpoint happens just between the COMMIT record log write and the
+ commit in trnman, it will record that transaction is not committed. Assume
+ the transaction (trn1) did an INSERT; after the checkpoint, a second
+ transaction (trn2) does a DELETE of what trn1 has inserted. Then crash,
+ Checkpoint record says that trn1 was not committed, and REDO phase starts
+ from Checkpoint record's LSN. So it will not find the COMMIT record of
+ trn1, will want to roll back trn1, which will fail because the row/key
+ which it wants to delete does not exist anymore.
+ To avoid this, Checkpoint needs to know that the REDO phase must start
+ before this COMMIT record, so transaction sets its rec_lsn to the COMMIT's
+ record LSN, and as Checkpoint reads the transaction's rec_lsn, Checkpoint
+ will know.
+
+ @note so after commit trn->rec_lsn is a "commit LSN", which could be of
+ use later.
+
+ @return Operation status, always 0 (success)
+*/
+
+my_bool write_hook_for_commit(enum translog_record_type type
+ __attribute__ ((unused)),
+ TRN *trn,
+ MARIA_HA *tbl_info
+ __attribute__ ((unused)),
+ LSN *lsn,
+ void *hook_arg
+ __attribute__ ((unused)))
+{
+ trn->rec_lsn= *lsn;
+ return 0;
+}
+
+
/***************************************************************************
Applying of REDO log records
***************************************************************************/
diff --git a/storage/maria/ma_blockrec.h b/storage/maria/ma_blockrec.h
index 34f6a3e3008..9b373d1d0ea 100644
--- a/storage/maria/ma_blockrec.h
+++ b/storage/maria/ma_blockrec.h
@@ -271,6 +271,9 @@ my_bool write_hook_for_undo_bulk_insert(enum translog_record_type type,
my_bool write_hook_for_file_id(enum translog_record_type type,
TRN *trn, MARIA_HA *tbl_info, LSN *lsn,
void *hook_arg);
+my_bool write_hook_for_commit(enum translog_record_type type,
+ TRN *trn, MARIA_HA *tbl_info, LSN *lsn,
+ void *hook_arg);
void _ma_block_get_status(void* param, my_bool concurrent_insert);
void _ma_block_update_status(void *param);
void _ma_block_restore_status(void *param);
diff --git a/storage/maria/ma_commit.c b/storage/maria/ma_commit.c
index 1066eb15e11..951de1beeff 100644
--- a/storage/maria/ma_commit.c
+++ b/storage/maria/ma_commit.c
@@ -33,6 +33,7 @@ int ma_commit(TRN *trn)
LEX_CUSTRING log_array[TRANSLOG_INTERNAL_PARTS];
DBUG_ENTER("ma_commit");
+ DBUG_ASSERT(trn->rec_lsn == LSN_IMPOSSIBLE);
if (trn->undo_lsn == 0) /* no work done, rollback (cheaper than commit) */
DBUG_RETURN(trnman_rollback_trn(trn));
/*
@@ -61,8 +62,14 @@ int ma_commit(TRN *trn)
trn, NULL, 0,
sizeof(log_array)/sizeof(log_array[0]),
log_array, NULL, NULL) |
- translog_flush(commit_lsn) |
- trnman_commit_trn(trn));
+ translog_flush(commit_lsn));
+
+ DBUG_EXECUTE_IF("maria_sleep_in_commit",
+ {
+ DBUG_PRINT("info", ("maria_sleep_in_commit"));
+ sleep(3);
+ });
+ res|= trnman_commit_trn(trn);
/*
diff --git a/storage/maria/ma_loghandler.c b/storage/maria/ma_loghandler.c
index cc8c7898d84..a0c8d0e63a3 100644
--- a/storage/maria/ma_loghandler.c
+++ b/storage/maria/ma_loghandler.c
@@ -618,11 +618,11 @@ static LOG_DESC INIT_LOGREC_PREPARE_WITH_UNDO_PURGE=
static LOG_DESC INIT_LOGREC_COMMIT=
{LOGRECTYPE_FIXEDLENGTH, 0, 0, NULL,
- NULL, NULL, 0, "commit", LOGREC_IS_GROUP_ITSELF, NULL,
+ write_hook_for_commit, NULL, 0, "commit", LOGREC_IS_GROUP_ITSELF, NULL,
NULL};
static LOG_DESC INIT_LOGREC_COMMIT_WITH_UNDO_PURGE=
-{LOGRECTYPE_PSEUDOFIXEDLENGTH, 5, 5, NULL, NULL, NULL, 1,
+{LOGRECTYPE_PSEUDOFIXEDLENGTH, 5, 5, NULL, write_hook_for_commit, NULL, 1,
"commit_with_undo_purge", LOGREC_IS_GROUP_ITSELF, NULL, NULL};
static LOG_DESC INIT_LOGREC_CHECKPOINT=
@@ -1404,18 +1404,21 @@ LSN translog_get_file_max_lsn_stored(uint32 file)
SYNOPSIS
translog_buffer_init()
buffer The buffer to initialize
+ num Number of this buffer
RETURN
0 OK
1 Error
*/
-static my_bool translog_buffer_init(struct st_translog_buffer *buffer)
+static my_bool translog_buffer_init(struct st_translog_buffer *buffer, int num)
{
DBUG_ENTER("translog_buffer_init");
buffer->prev_last_lsn= buffer->last_lsn= LSN_IMPOSSIBLE;
DBUG_PRINT("info", ("last_lsn and prev_last_lsn set to 0 buffer: 0x%lx",
(ulong) buffer));
+
+ buffer->buffer_no= (uint8) num;
/* This Buffer File */
buffer->file= NULL;
buffer->overlay= 0;
@@ -1430,10 +1433,23 @@ static my_bool translog_buffer_init(struct st_translog_buffer *buffer)
buffer->copy_to_buffer_in_progress= 0;
/* list of waiting buffer ready threads */
buffer->waiting_flush= 0;
- /* lock for the buffer. Current buffer also lock the handler */
+ /*
+ Buffers locked by fallowing mutex. As far as buffers create logical
+ circle (after last buffer goes first) it trigger false alarm of deadlock
+ detect system, so we remove check of deadlock for this buffers. In deed
+ all mutex locks concentrated around current buffer except flushing
+ thread (but it is only one thread). One thread can't take more then
+ 2 buffer locks at once. So deadlock is impossible here.
+
+ To prevent false alarm of dead lock detection we switch dead lock
+ detection for one buffer in the middle of the buffers chain. Excluding
+ only one of eight buffers from deadlock detection hardly can hide other
+ possible problems which include this mutexes.
+ */
if (my_pthread_mutex_init(&buffer->mutex, MY_MUTEX_INIT_FAST,
"translog_buffer->mutex",
- MYF_NO_DEADLOCK_DETECTION) ||
+ (num == TRANSLOG_BUFFERS_NO - 2 ?
+ MYF_NO_DEADLOCK_DETECTION : 0)) ||
pthread_cond_init(&buffer->prev_sent_to_disk_cond, 0))
DBUG_RETURN(1);
buffer->is_closing_buffer= 0;
@@ -3555,9 +3571,8 @@ my_bool translog_init_with_table(const char *directory,
/* Buffers for log writing */
for (i= 0; i < TRANSLOG_BUFFERS_NO; i++)
{
- if (translog_buffer_init(log_descriptor.buffers + i))
+ if (translog_buffer_init(log_descriptor.buffers + i, i))
goto err;
- log_descriptor.buffers[i].buffer_no= (uint8) i;
DBUG_PRINT("info", ("translog_buffer buffer #%u: 0x%lx",
i, (ulong) log_descriptor.buffers + i));
}
diff --git a/storage/maria/ma_open.c b/storage/maria/ma_open.c
index 992061fcda2..309ccf78ea1 100644
--- a/storage/maria/ma_open.c
+++ b/storage/maria/ma_open.c
@@ -809,7 +809,7 @@ MARIA_HA *maria_open(const char *name, int mode, uint open_flags)
if (!(share->state_history= (MARIA_STATE_HISTORY *)
my_malloc(sizeof(*share->state_history), MYF(MY_WME))))
goto err;
- share->state_history->trid= 0; /* Visibly by all */
+ share->state_history->trid= 0; /* Visible by all */
share->state_history->state= share->state.state;
share->state_history->next= 0;
}
diff --git a/storage/maria/ma_recovery.c b/storage/maria/ma_recovery.c
index 51eedf157c5..baebdcf2eb4 100644
--- a/storage/maria/ma_recovery.c
+++ b/storage/maria/ma_recovery.c
@@ -555,8 +555,9 @@ static void new_transaction(uint16 sid, TrID long_id, LSN undo_lsn,
char llbuf[22];
all_active_trans[sid].long_trid= long_id;
llstr(long_id, llbuf);
- tprint(tracef, "Transaction long_trid %s short_trid %u starts\n",
- llbuf, sid);
+ tprint(tracef, "Transaction long_trid %s short_trid %u starts,"
+ " undo_lsn (%lu,0x%lx) first_undo_lsn (%lu,0x%lx)\n",
+ llbuf, sid, LSN_IN_PARTS(undo_lsn), LSN_IN_PARTS(first_undo_lsn));
all_active_trans[sid].undo_lsn= undo_lsn;
all_active_trans[sid].first_undo_lsn= first_undo_lsn;
set_if_bigger(max_long_trid, long_id);
@@ -2968,6 +2969,8 @@ static LSN parse_checkpoint_record(LSN lsn)
ptr= log_record_buffer.str;
start_address= lsn_korr(ptr);
ptr+= LSN_STORE_SIZE;
+ tprint(tracef, "Checkpoint record has start_horizon at (%lu,0x%lx)\n",
+ LSN_IN_PARTS(start_address));
/* transactions */
nb_active_transactions= uint2korr(ptr);
@@ -2983,6 +2986,9 @@ static LSN parse_checkpoint_record(LSN lsn)
line. It may make start_address slightly decrease (only by the time it
takes to write one or a few rows, roughly).
*/
+ tprint(tracef, "Checkpoint record has min_rec_lsn of active transactions"
+ " at (%lu,0x%lx)\n",
+ LSN_IN_PARTS(minimum_rec_lsn_of_active_transactions));
set_if_smaller(start_address, minimum_rec_lsn_of_active_transactions);
for (i= 0; i < nb_active_transactions; i++)
@@ -3086,6 +3092,8 @@ static LSN parse_checkpoint_record(LSN lsn)
*/
start_address= checkpoint_start=
translog_next_LSN(start_address, LSN_IMPOSSIBLE);
+ tprint(tracef, "Checkpoint record start_horizon now adjusted to"
+ " LSN (%lu,0x%lx)\n", LSN_IN_PARTS(start_address));
if (checkpoint_start == LSN_IMPOSSIBLE)
{
/*
@@ -3095,6 +3103,8 @@ static LSN parse_checkpoint_record(LSN lsn)
return LSN_ERROR;
}
/* now, where the REDO phase should start reading log: */
+ tprint(tracef, "Checkpoint has min_rec_lsn of dirty pages at"
+ " LSN (%lu,0x%lx)\n", LSN_IN_PARTS(minimum_rec_lsn_of_dirty_pages));
set_if_smaller(start_address, minimum_rec_lsn_of_dirty_pages);
DBUG_PRINT("info",
("checkpoint_start: (%lu,0x%lx) start_address: (%lu,0x%lx)",
diff --git a/storage/maria/trnman.c b/storage/maria/trnman.c
index 09c8f9a264f..f523da22291 100644
--- a/storage/maria/trnman.c
+++ b/storage/maria/trnman.c
@@ -261,6 +261,7 @@ TRN *trnman_new_trn(WT_THD *wt)
{
int res;
TRN *trn;
+ union { TRN *trn; void *v; } tmp;
DBUG_ENTER("trnman_new_trn");
/*
@@ -276,19 +277,19 @@ TRN *trnman_new_trn(WT_THD *wt)
pthread_mutex_lock(&LOCK_trn_list);
/* Allocating a new TRN structure */
- trn= pool;
+ tmp.trn= pool;
/*
Popping an unused TRN from the pool
(ABA isn't possible, we're behind a mutex
*/
my_atomic_rwlock_wrlock(&LOCK_pool);
- while (trn && !my_atomic_casptr((void **)&pool, (void **)&trn,
- (void *)trn->next))
+ while (tmp.trn && !my_atomic_casptr((void **)&pool, &tmp.v,
+ (void *)tmp.trn->next))
/* no-op */;
my_atomic_rwlock_wrunlock(&LOCK_pool);
/* Nothing in the pool ? Allocate a new one */
- if (!trn)
+ if (!(trn= tmp.trn))
{
/*
trn should be completely initalized at create time to allow
@@ -359,7 +360,7 @@ TRN *trnman_new_trn(WT_THD *wt)
return 0;
}
- DBUG_PRINT("exit", ("trn: x%lx trid: 0x%lu",
+ DBUG_PRINT("exit", ("trn: 0x%lx trid: 0x%lu",
(ulong) trn, (ulong) trn->trid));
DBUG_RETURN(trn);
@@ -385,11 +386,12 @@ TRN *trnman_new_trn(WT_THD *wt)
my_bool trnman_end_trn(TRN *trn, my_bool commit)
{
int res= 1;
+ uint16 cached_short_id= trn->short_id; /* we have to cache it, see below */
TRN *free_me= 0;
LF_PINS *pins= trn->pins;
DBUG_ENTER("trnman_end_trn");
+ DBUG_PRINT("enter", ("trn=0x%lx commit=%d", (ulong) trn, commit));
- DBUG_ASSERT(trn->rec_lsn == 0);
/* if a rollback, all UNDO records should have been executed */
DBUG_ASSERT(commit || trn->undo_lsn == 0);
DBUG_PRINT("info", ("pthread_mutex_lock LOCK_trn_list"));
@@ -454,11 +456,17 @@ my_bool trnman_end_trn(TRN *trn, my_bool commit)
res= -1;
trnman_active_transactions--;
+ DBUG_PRINT("info", ("pthread_mutex_unlock LOCK_trn_list"));
pthread_mutex_unlock(&LOCK_trn_list);
- /* the rest is done outside of a critical section */
+ /*
+ the rest is done outside of a critical section
+
+ note that we don't own trn anymore, it may be in a shared list now.
+ Thus, we cannot dereference it, and must use cached_short_id below.
+ */
my_atomic_rwlock_rdlock(&LOCK_short_trid_to_trn);
- my_atomic_storeptr((void **)&short_trid_to_active_trn[trn->short_id], 0);
+ my_atomic_storeptr((void **)&short_trid_to_active_trn[cached_short_id], 0);
my_atomic_rwlock_rdunlock(&LOCK_short_trid_to_trn);
/*
@@ -503,7 +511,6 @@ void trnman_free_trn(TRN *trn)
*/
union { TRN *trn; void *v; } tmp;
-
pthread_mutex_lock(&trn->state_lock);
trn->short_id= 0;
pthread_mutex_unlock(&trn->state_lock);