merge with latest 5.1-maria
This commit is contained in:
commit
ccfb9c32f8
@ -13,7 +13,7 @@ append_file $MYSQLTEST_VARDIR/tmp/master0.expect;
|
|||||||
wait-maria_empty_logs.inc
|
wait-maria_empty_logs.inc
|
||||||
EOF
|
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)
|
if (!$mel_keep_control_file)
|
||||||
{
|
{
|
||||||
|
7
mysql-test/include/mysqladmin_shutdown.inc
Normal file
7
mysql-test/include/mysqladmin_shutdown.inc
Normal file
@ -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
|
@ -2,6 +2,9 @@
|
|||||||
# Include this script to wait until the connection to the
|
# Include this script to wait until the connection to the
|
||||||
# server has been restored or timeout occurs.
|
# server has been restored or timeout occurs.
|
||||||
# You should have done --enable_reconnect first
|
# 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_result_log
|
||||||
--disable_query_log
|
--disable_query_log
|
||||||
let $counter= 5000;
|
let $counter= 5000;
|
||||||
|
24
mysql-test/include/wait_until_disconnected.inc
Normal file
24
mysql-test/include/wait_until_disconnected.inc
Normal file
@ -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
|
29
mysql-test/suite/maria/r/maria-recovery3.result
Normal file
29
mysql-test/suite/maria/r/maria-recovery3.result
Normal file
@ -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;
|
1
mysql-test/suite/maria/t/maria-recovery3-master.opt
Normal file
1
mysql-test/suite/maria/t/maria-recovery3-master.opt
Normal file
@ -0,0 +1 @@
|
|||||||
|
--skip-stack-trace --skip-core-file --loose-maria-log-dir-path=$MYSQLTEST_VARDIR/tmp
|
71
mysql-test/suite/maria/t/maria-recovery3.test
Normal file
71
mysql-test/suite/maria/t/maria-recovery3.test
Normal file
@ -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;
|
@ -5914,7 +5914,7 @@ my_bool write_hook_for_file_id(enum translog_record_type type
|
|||||||
TRN *trn
|
TRN *trn
|
||||||
__attribute__ ((unused)),
|
__attribute__ ((unused)),
|
||||||
MARIA_HA *tbl_info,
|
MARIA_HA *tbl_info,
|
||||||
LSN *lsn __attribute__ ((unused)),
|
LSN *lsn,
|
||||||
void *hook_arg
|
void *hook_arg
|
||||||
__attribute__ ((unused)))
|
__attribute__ ((unused)))
|
||||||
{
|
{
|
||||||
@ -5923,6 +5923,44 @@ my_bool write_hook_for_file_id(enum translog_record_type type
|
|||||||
return 0;
|
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
|
Applying of REDO log records
|
||||||
***************************************************************************/
|
***************************************************************************/
|
||||||
|
@ -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,
|
my_bool write_hook_for_file_id(enum translog_record_type type,
|
||||||
TRN *trn, MARIA_HA *tbl_info, LSN *lsn,
|
TRN *trn, MARIA_HA *tbl_info, LSN *lsn,
|
||||||
void *hook_arg);
|
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_get_status(void* param, my_bool concurrent_insert);
|
||||||
void _ma_block_update_status(void *param);
|
void _ma_block_update_status(void *param);
|
||||||
void _ma_block_restore_status(void *param);
|
void _ma_block_restore_status(void *param);
|
||||||
|
@ -33,6 +33,7 @@ int ma_commit(TRN *trn)
|
|||||||
LEX_CUSTRING log_array[TRANSLOG_INTERNAL_PARTS];
|
LEX_CUSTRING log_array[TRANSLOG_INTERNAL_PARTS];
|
||||||
DBUG_ENTER("ma_commit");
|
DBUG_ENTER("ma_commit");
|
||||||
|
|
||||||
|
DBUG_ASSERT(trn->rec_lsn == LSN_IMPOSSIBLE);
|
||||||
if (trn->undo_lsn == 0) /* no work done, rollback (cheaper than commit) */
|
if (trn->undo_lsn == 0) /* no work done, rollback (cheaper than commit) */
|
||||||
DBUG_RETURN(trnman_rollback_trn(trn));
|
DBUG_RETURN(trnman_rollback_trn(trn));
|
||||||
/*
|
/*
|
||||||
@ -61,8 +62,14 @@ int ma_commit(TRN *trn)
|
|||||||
trn, NULL, 0,
|
trn, NULL, 0,
|
||||||
sizeof(log_array)/sizeof(log_array[0]),
|
sizeof(log_array)/sizeof(log_array[0]),
|
||||||
log_array, NULL, NULL) |
|
log_array, NULL, NULL) |
|
||||||
translog_flush(commit_lsn) |
|
translog_flush(commit_lsn));
|
||||||
trnman_commit_trn(trn));
|
|
||||||
|
DBUG_EXECUTE_IF("maria_sleep_in_commit",
|
||||||
|
{
|
||||||
|
DBUG_PRINT("info", ("maria_sleep_in_commit"));
|
||||||
|
sleep(3);
|
||||||
|
});
|
||||||
|
res|= trnman_commit_trn(trn);
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -618,11 +618,11 @@ static LOG_DESC INIT_LOGREC_PREPARE_WITH_UNDO_PURGE=
|
|||||||
|
|
||||||
static LOG_DESC INIT_LOGREC_COMMIT=
|
static LOG_DESC INIT_LOGREC_COMMIT=
|
||||||
{LOGRECTYPE_FIXEDLENGTH, 0, 0, NULL,
|
{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};
|
NULL};
|
||||||
|
|
||||||
static LOG_DESC INIT_LOGREC_COMMIT_WITH_UNDO_PURGE=
|
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};
|
"commit_with_undo_purge", LOGREC_IS_GROUP_ITSELF, NULL, NULL};
|
||||||
|
|
||||||
static LOG_DESC INIT_LOGREC_CHECKPOINT=
|
static LOG_DESC INIT_LOGREC_CHECKPOINT=
|
||||||
|
@ -555,8 +555,9 @@ static void new_transaction(uint16 sid, TrID long_id, LSN undo_lsn,
|
|||||||
char llbuf[22];
|
char llbuf[22];
|
||||||
all_active_trans[sid].long_trid= long_id;
|
all_active_trans[sid].long_trid= long_id;
|
||||||
llstr(long_id, llbuf);
|
llstr(long_id, llbuf);
|
||||||
tprint(tracef, "Transaction long_trid %s short_trid %u starts\n",
|
tprint(tracef, "Transaction long_trid %s short_trid %u starts,"
|
||||||
llbuf, sid);
|
" 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].undo_lsn= undo_lsn;
|
||||||
all_active_trans[sid].first_undo_lsn= first_undo_lsn;
|
all_active_trans[sid].first_undo_lsn= first_undo_lsn;
|
||||||
set_if_bigger(max_long_trid, long_id);
|
set_if_bigger(max_long_trid, long_id);
|
||||||
@ -2968,6 +2969,8 @@ static LSN parse_checkpoint_record(LSN lsn)
|
|||||||
ptr= log_record_buffer.str;
|
ptr= log_record_buffer.str;
|
||||||
start_address= lsn_korr(ptr);
|
start_address= lsn_korr(ptr);
|
||||||
ptr+= LSN_STORE_SIZE;
|
ptr+= LSN_STORE_SIZE;
|
||||||
|
tprint(tracef, "Checkpoint record has start_horizon at (%lu,0x%lx)\n",
|
||||||
|
LSN_IN_PARTS(start_address));
|
||||||
|
|
||||||
/* transactions */
|
/* transactions */
|
||||||
nb_active_transactions= uint2korr(ptr);
|
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
|
line. It may make start_address slightly decrease (only by the time it
|
||||||
takes to write one or a few rows, roughly).
|
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);
|
set_if_smaller(start_address, minimum_rec_lsn_of_active_transactions);
|
||||||
|
|
||||||
for (i= 0; i < nb_active_transactions; i++)
|
for (i= 0; i < nb_active_transactions; i++)
|
||||||
@ -3086,6 +3092,8 @@ static LSN parse_checkpoint_record(LSN lsn)
|
|||||||
*/
|
*/
|
||||||
start_address= checkpoint_start=
|
start_address= checkpoint_start=
|
||||||
translog_next_LSN(start_address, LSN_IMPOSSIBLE);
|
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)
|
if (checkpoint_start == LSN_IMPOSSIBLE)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
@ -3095,6 +3103,8 @@ static LSN parse_checkpoint_record(LSN lsn)
|
|||||||
return LSN_ERROR;
|
return LSN_ERROR;
|
||||||
}
|
}
|
||||||
/* now, where the REDO phase should start reading log: */
|
/* 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);
|
set_if_smaller(start_address, minimum_rec_lsn_of_dirty_pages);
|
||||||
DBUG_PRINT("info",
|
DBUG_PRINT("info",
|
||||||
("checkpoint_start: (%lu,0x%lx) start_address: (%lu,0x%lx)",
|
("checkpoint_start: (%lu,0x%lx) start_address: (%lu,0x%lx)",
|
||||||
|
@ -392,7 +392,6 @@ my_bool trnman_end_trn(TRN *trn, my_bool commit)
|
|||||||
DBUG_ENTER("trnman_end_trn");
|
DBUG_ENTER("trnman_end_trn");
|
||||||
DBUG_PRINT("enter", ("trn=0x%lx commit=%d", (ulong) trn, commit));
|
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 */
|
/* if a rollback, all UNDO records should have been executed */
|
||||||
DBUG_ASSERT(commit || trn->undo_lsn == 0);
|
DBUG_ASSERT(commit || trn->undo_lsn == 0);
|
||||||
DBUG_PRINT("info", ("pthread_mutex_lock LOCK_trn_list"));
|
DBUG_PRINT("info", ("pthread_mutex_lock LOCK_trn_list"));
|
||||||
|
Loading…
x
Reference in New Issue
Block a user