1
0
mirror of https://github.com/MariaDB/server.git synced 2025-07-29 05:21:33 +03:00

* WL#4137 Maria- Framework for testing recovery in mysql-test-run

See test maria-recovery.test for a model; all include scripts have
an "API" section at start if they do take parameters from outside.
* Fixing bug reported by Jani and Monty (when two REDOs about the same
page in one group, see ma_blockrec.c). 
* Fixing small bugs in recovery


mysql-test/include/wait_until_connected_again.inc:
  be sure to enter the loop (the previous query by the caller may not have
  failed: it could be
  query;
  mysqladmin shutdown;
  call this script).
mysql-test/lib/mtr_process.pl:
  * Through the "expect" file a test can tell mtr that a server crash
  is expected. What the file contains is irrelevant. Now if its last
  line starts with "wait", mtr will wait before restarting (it will
  wait for the last line to not start with "wait"). This is for
  tests which need to mangle files under the feet of a dead mysqld.
  * Remove "expect" file before restarting; otherwise there could be a
  race condition: tests sees server restarted, does something, writes
  an "expect" file, and then mtr removes that file, then
  test kills mysqld, and then mtr will never restart it.
storage/maria/ma_blockrec.c:
  - when applying a REDO in recovery, we don't anymore put UNDO's LSN on the page
  at once; indeed if in this REDO's group there comes another REDO
  for the same page it would be wrongly skipped. Instead, we keep
  pages pinned, don't change their LSN. When done with all REDOs
  of the group we unpin them and stamp them with UNDO's LSN.
  - fixing bug in applying of REDO_PURGE_BLOCKS in recovery: page_range
  sometimes has TAIL_BIT set, need to turn it down to know the real page
  range.
  - Both bugs are covered in maria-recovery.test
storage/maria/ma_checkpoint.c:
  Capability to, in debug builds only, do some special operations
  (flush all bitmap and data pages, flush state, flush log)
  and crash mysqld, to later test recovery.
   Driven by some --debug=d, symbols.
storage/maria/ma_open.c:
  debugging info
storage/maria/ma_pagecache.c:
  Now that we can _ma_unpin_all_pages() during the REDO phase
  to set page's LSN, the assertion needs to be relaxed.
storage/maria/ma_recovery.c:
  - open trace file in append mode (useful when a test triggers several
  recoveries, we see them all).
  - fixing wrong error detection, it's possible that during recovery
  we want to open an already open table.
  - when applying a REDO in recovery, we don't anymore put UNDO's LSN on the page
  at once; indeed if in this REDO's group there comes another REDO
  for the same page it would be wrongly skipped. Instead, we keep
  pages pinned, don't change their LSN. When done with all REDOs
  of the group we unpin them and stamp them with UNDO's LSN.
  - we verify that all log records of a group are about the same table,
  for debugging.
mysql-test/r/maria-recovery.result:
  result
mysql-test/t/maria-recovery-master.opt:
  crash is expected, core file would take room, stack trace would
  wake pushbuild up.
mysql-test/t/maria-recovery.test:
  Test of recovery from mysql-test (it is already tested as unit tests
  in ma_test_recovery) (WL#4137)
  - test that, if recovery is made to start on an empty table it can
  replay the effects of committed and uncommitted statements (having only
  the committed ones in the end result). This should be the first test
  for someone writing code of new REDOs.
  - test that, if mysqld is crashed and recovery runs we have only
  committed statements in the end result. Crashes are done in different
  ways: flush nothing (so, uncommitted statement is often missing
  from the log => no rollback to do); flush pagecache (implicitely flushes
  log (WAL)) and flush log, both causes rollbacks; flush log can also
  flush state (state.records etc) to test recovery of the state
  (not tested well now as we repair the index anyway).
  - test of bug found by Jani and Monty in recovery (two REDO about
  the same page in one group).
mysql-test/include/maria_empty_logs.inc:
  removes logs, to have a clean sheet for testing recovery.
mysql-test/include/maria_make_snapshot.inc:
  copies a table to another directory, or back, or compares both
  (comparison is not implemented as physical comparison is impossible
  if an UNDO phase happened).
mysql-test/include/maria_make_snapshot_for_comparison.inc:
  copies tables to another directory so that they can later
  serve as a comparison reference (they are the good tables,
  recovery should produce similar ones).
mysql-test/include/maria_make_snapshot_for_feeding_recovery.inc:
  When we want to force recovery to start on old tables, we prepare
  old tables with this script: we put them in a spare directory.
  They are later copied back over mysqltest tables while mysqld is dead.
  We also need to copy back the control file, otherwise mysqld,
  in recovery, would start from the latest checkpoint: latest
  checkpoint plus old tables is not a recovery-possible scenario of course.
mysql-test/include/maria_verify_recovery.inc:
  causes mysqld to crash, restores old tables if requested,
  lets recovery run, compares resulting tables with reference tables
  by using CHECKSUM TABLE.
  We don't do any sanity checks on page's LSN in resulting tables, yet.
This commit is contained in:
unknown
2007-11-13 17:12:29 +01:00
parent 5e2aaf69d8
commit 5fbd5dafe7
15 changed files with 745 additions and 43 deletions

View File

@ -0,0 +1,33 @@
# Maria help script.
# Cleans up all logs to give recovery a fresh start.
# API: none, just uses vardir, port and socket.
connection admin;
-- echo * shut down mysqld, removed logs, restarted it
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;
remove_file $MYSQLTEST_VARDIR/master-data/maria_log_control;
remove_file $MYSQLTEST_VARDIR/master-data/maria_log.00000001;
-- error 0,1 # maybe there is just one log
remove_file $MYSQLTEST_VARDIR/master-data/maria_log.00000002;
# Hope there were not more than these logs.
-- error 0,1
remove_file $MYSQLTEST_VARDIR/master-data/maria_recovery.trace;
append_file $MYSQLTEST_VARDIR/tmp/master0.expect;
restart-maria_empty_logs.inc
EOF
--source include/wait_until_connected_again.inc
connection default;
# the effect of "use" is lost after a restart so we are back into db "test",
# because connection 'default' was created with db "test".
use mysqltest;

View File

@ -0,0 +1,58 @@
# Maria helper script
# Copies table' data and index file to other directory, or back, or compares.
# The other directory looks like a database directory, so that we can
# read copies from inside mysqld, that's also why we copy the frm.
# "mms" is a namespace for Maria_Make_Snapshot
# API:
# 1) set one of
# $mms_copy : to copy table from database to spare directory
# $mms_reverse : to copy it back
# $mms_compare : to compare both
# 2) set $mms_table_to_use to a number N: table will be mysqltest.tN
# 3) set $mms_purpose to say what this copy is for (influences the naming
# of the spare directory).
if (!$mms_copy)
{
if (!$mms_reverse_copy)
{
if (!$mms_compare)
{
--die misuse of maria_make_snapshot.inc: no command
}
}
}
if ($mms_copy)
{
--echo * copied t$mms_table_to_use for $mms_purpose
copy_file $MYSQLTEST_VARDIR/master-data/mysqltest/t$mms_table_to_use.MAD $MYSQLTEST_VARDIR/master-data/mysqltest_for_$mms_purpose/t$mms_table_to_use.MAD;
copy_file $MYSQLTEST_VARDIR/master-data/mysqltest/t$mms_table_to_use.MAI $MYSQLTEST_VARDIR/master-data/mysqltest_for_$mms_purpose/t$mms_table_to_use.MAI;
copy_file $MYSQLTEST_VARDIR/master-data/mysqltest/t$mms_table_to_use.frm $MYSQLTEST_VARDIR/master-data/mysqltest_for_$mms_purpose/t$mms_table_to_use.frm;
}
if ($mms_reverse_copy)
{
# do not call this without flushing target table first!
--echo * copied t$mms_table_to_use back for $mms_purpose
-- error 0,1
remove_file $MYSQLTEST_VARDIR/master-data/mysqltest/t$mms_table_to_use.MAD;
copy_file $MYSQLTEST_VARDIR/master-data/mysqltest_for_$mms_purpose/t$mms_table_to_use.MAD $MYSQLTEST_VARDIR/master-data/mysqltest/t$mms_table_to_use.MAD;
-- error 0,1
remove_file $MYSQLTEST_VARDIR/master-data/mysqltest/t$mms_table_to_use.MAI;
copy_file $MYSQLTEST_VARDIR/master-data/mysqltest_for_$mms_purpose/t$mms_table_to_use.MAI $MYSQLTEST_VARDIR/master-data/mysqltest/t$mms_table_to_use.MAI;
}
if ($mms_compare)
{
# this was meant to do a physical file compare (diff_files)
# but after the UNDO phase this is normally impossible
# (UNDO execution has created new log records => pages have new LSNs).
# So for now it does nothing.
# --echo * compared t$mms_table_to_use
# diff_files $MYSQLTEST_VARDIR/master-data/mysqltest/t$mms_table_to_use.MAD $MYSQLTEST_VARDIR/master-data/mysqltest_for_$mms_purpose/t$mms_table_to_use.MAD;
# index file not yet recovered
# diff_files $MYSQLTEST_VARDIR/master-data/mysqltest/t$mms_table_to_use.MAI $MYSQLTEST_VARDIR/master-data/mysqltest_for_$mms_purpose/t$mms_table_to_use.MAI;
}

View File

@ -0,0 +1,30 @@
# Maria helper script
# Copies clean tables' data and index file to other directory
# Tables are t1...t[$mms_tables]
# They are later used as a reference to see if recovery works.
# API:
# set $mms_tables to N, the script will cover tables mysqltest.t1,...tN
connection admin;
let $mms_table_to_use=$mms_tables;
let $mms_purpose=comparison;
let $mms_copy=1;
--disable_query_log
--disable_warnings
eval drop database if exists mysqltest_for_$mms_purpose;
--enable_warnings
eval create database mysqltest_for_$mms_purpose;
--enable_query_log
while ($mms_table_to_use)
{
# to serve as a reference, table must be in a clean state
eval flush table t$mms_table_to_use;
-- source include/maria_make_snapshot.inc
dec $mms_table_to_use;
}
let $mms_copy=0;
connection default;

View File

@ -0,0 +1,35 @@
# Maria helper script
# Copies tables' data and index file to other directory, and control file.
# Tables are t1...t[$mms_tables].
# Later, mysqld is shutdown, and that snapshot is put back into the
# datadir, control file too ("flashing recovery's brain"), and recovery is let
# to run on it (see maria_verify_recovery.inc).
# API:
# set $mms_tables to N, the script will cover tables mysqltest.t1,...tN
connection admin;
let $mms_table_to_use=$mms_tables;
let $mms_purpose=feeding_recovery;
let $mms_copy=1;
--disable_query_log
--disable_warnings
eval drop database if exists mysqltest_for_$mms_purpose;
--enable_warnings
eval create database mysqltest_for_$mms_purpose;
--enable_query_log
while ($mms_table_to_use)
{
-- source include/maria_make_snapshot.inc
dec $mms_table_to_use;
}
let $mms_copy=0;
-- error 0,1
remove_file $MYSQLTEST_VARDIR/tmp/mms_for_$mms_purpose.maria_log_control;
copy_file $MYSQLTEST_VARDIR/master-data/maria_log_control $MYSQLTEST_VARDIR/tmp/mms_for_$mms_purpose.maria_log_control;
connection default;

View File

@ -0,0 +1,87 @@
# Maria helper script.
# Runs recovery, compare with expected table data.
# API:
# 1) set $mms_tables to N, the script will cover tables mysqltest.t1,...tN
# 2) set $mvr_debug_option to the crash way
# 3) set $mvr_restore_old_snapshot to 1 if you want recovery to run on
# an old copy of tables and of the control file, 0 for normal recovery.
# "mvr" is a namespace for Maria_Verify_Recovery
connection admin;
# warn mtr that mysqld is going to die and should not be restarted immediately
#append_file $MYSQLTEST_VARDIR/tmp/master0.expect;
#wait-maria_verify_recovery.inc
#EOF
# todo: remove this "system" and uncomment above when BUG#32296 is fixed
system echo wait-maria_verify_recovery.inc >> $MYSQLTEST_VARDIR/tmp/master0.expect;
# flush page cache and log, only log, or nothing, and kill mysqld with
# abort().
# When we restore an old snapshot, we could just kill mysqld nicely,
# but that would implicitely commit all work, which the tester may
# not want (tester may want to observe rollback happening).
eval SET SESSION debug=$mvr_debug_option;
--echo * crashing mysqld intentionally
--error 2013
set global maria_checkpoint_interval=1; # this will crash (DBUG magic)
if ($mvr_restore_old_snapshot)
{
# copy snapshot made by maria_make_snapshot_for_feeding_recovery back
# into datadir.
let $mms_table_to_use=$mms_tables;
let $mms_purpose=feeding_recovery;
let $mms_reverse_copy=1;
while ($mms_table_to_use)
{
-- source include/maria_make_snapshot.inc
dec $mms_table_to_use;
}
let $mms_reverse_copy=0;
# also copy back control file, to force recovery to start from an early
# point, ignoring further checkpoints.
-- error 0,1
remove_file $MYSQLTEST_VARDIR/master-data/maria_log_control;
copy_file $MYSQLTEST_VARDIR/tmp/mms_for_$mms_purpose.maria_log_control $MYSQLTEST_VARDIR/master-data/maria_log_control;
}
--echo * recovery happens
# let mtr restart mysqld (and thus execute the maria log)
#append_file $MYSQLTEST_VARDIR/tmp/master0.expect;
#restart-maria_verify_recovery.inc
#EOF
system echo restart-maria_verify_recovery.inc >> $MYSQLTEST_VARDIR/tmp/master0.expect;
--source include/wait_until_connected_again.inc
# compare that tables of $mms_tables are identical to old.
let $mms_table_to_use=$mms_tables;
let $mms_purpose=comparison;
let $mms_compare=1;
while ($mms_table_to_use)
{
# Todo: remove this REPAIR when we have index recovery working.
# It is a quick repair, so that it will fail if data file is corrupted.
--echo * rebuilding index (until we have recovery of index)
eval repair table t$mms_table_to_use quick;
--echo * testing that checksum after recovery is as expected
let $new_checksum=`CHECKSUM TABLE t$mms_table_to_use`;
let $old_checksum=`CHECKSUM TABLE mysqltest_for_$mms_purpose.t$mms_table_to_use`;
# the $ text variables above are of the form "db.tablename\tchecksum",
# as db differs, we use substring().
eval select if(substring("$new_checksum",instr("$new_checksum",".t1")) = substring("$old_checksum",instr("$old_checksum",".t1")),"ok","failure");
-- source include/maria_make_snapshot.inc
dec $mms_table_to_use;
}
let $mms_compare=0;
connection default;
# the effect of "use" is lost after a restart so we are back into db "test"
use mysqltest;

View File

@ -1,12 +1,14 @@
#
# 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
--disable_result_log
--disable_query_log
let $counter= 500;
let $mysql_errno= 1;
while ($mysql_errno)
{
--error 0,2002,2006
--error 0,2002,2003,2006
show status;
dec $counter;