mariadb/mysql-test/t/maria-recovery.test

142 lines
4.6 KiB
Text
Raw Normal View History

* 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.
2007-11-13 17:12:29 +01:00
--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
--disable_warnings
drop database if exists mysqltest;
--enable_warnings
create database mysqltest;
# 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
# A sample test
-- source include/maria_empty_logs.inc
let $mms_tables=1;
create table t1 (a varchar(1000)) engine=maria;
--echo * TEST: see if recovery can reconstruct if we give it an old table
-- source include/maria_make_snapshot_for_feeding_recovery.inc
# Your committed statements here, which we expect to
# be reconstructed from the log
insert into t1 values ("00000000");
-- source include/maria_make_snapshot_for_comparison.inc
# Your statements which should not commit and we expect to be rolled back
lock tables t1 write;
insert into t1 values ("aaaaaaaaa");
# we want recovery to run on the first snapshot made above
let $mvr_restore_old_snapshot=1;
# the script below will trigger recovery and compare checksums
let $mvr_debug_option="+d,maria_flush_whole_log,maria_crash";
-- source include/maria_verify_recovery.inc
# so a SELECT like this is pure visual effect, brings nothing.
select * from t1;
--echo * TEST: normal recovery test (no moving tables under its feet)
# different types of crash => a loop; here are loop control variables
let $crash_no_flush=1;
let $crash_flush_whole_page_cache=0;
let $crash_flush_states=0;
let $crash_flush_whole_log=0;
let $crash_loop=1;
# we want recovery to use the tables as they were at time of crash
let $mvr_restore_old_snapshot=0;
# Note that we don't remove logs between iterations. Test is
# cumulative (each new recovery processes more log records than the previous).
while ($crash_loop)
{
if ($crash_flush_whole_log)
{
let $mvr_debug_option="+d,maria_flush_whole_log,maria_crash";
# set up what next iteration should do:
let $crash_flush_whole_log=0;
let $crash_loop=0;
}
if ($crash_flush_states)
{
let $mvr_debug_option="+d,maria_flush_states,maria_flush_whole_log,maria_crash";
let $crash_flush_states=0;
let $crash_flush_whole_log=1;
}
if ($crash_flush_whole_page_cache)
{
let $mvr_debug_option="+d,maria_flush_whole_page_cache,maria_crash";
let $crash_flush_whole_page_cache=0;
let $crash_flush_states=1;
}
if ($crash_no_flush)
{
let $mvr_debug_option="+d,maria_crash";
let $crash_no_flush=0;
let $crash_flush_whole_page_cache=1;
}
# Your committed statements here
insert into t1 values ("00000000");
-- source include/maria_make_snapshot_for_comparison.inc
# Your statements which we expect to be rolled back
lock tables t1 write;
insert into t1 values ("aaaaaaaaa");
-- source include/maria_verify_recovery.inc
select * from t1;
}
drop table t1;
# what did we compare above:
# - checksum: tells that the tables contain the same amount of rows
# and same data in rows
# - index: no, neither state nor pages were compared
# - bitmap pages: the REPAIR QUICK done above very probably checks
# that bitmap reflects page occupation; do we need to do physical
# compare?
# - page LSN: not compared; we should compare that page's LSN in new
# table is >= page's LSN in old table (it can be >, due to UNDO phase)
# we had a bug where new page's LSN was 0... todo.
#
# Test problem where an UPDATE purges and rewrites a tail page, and
# recovery applied the purge, stamped page with UNDO's LSN, thus
# the rewrite was ignored.
#
-- source include/maria_empty_logs.inc
let $mms_tables=1;
CREATE TABLE t1 (
i int,
b blob default NULL,
c varchar(6000) default NULL
) ENGINE=MARIA CHECKSUM=1;
-- source include/maria_make_snapshot_for_feeding_recovery.inc
INSERT INTO t1 VALUES (1, REPEAT('a', 5000), REPEAT('b', 5000));
UPDATE t1 SET i=3, b=CONCAT(b,'c') WHERE i=1;
SELECT LENGTH(b) FROM t1 WHERE i=3;
-- source include/maria_make_snapshot_for_comparison.inc
# we want recovery to run on the first snapshot made above
let $mvr_restore_old_snapshot=1;
let $mvr_debug_option="+d,maria_flush_whole_log,maria_crash";
-- source include/maria_verify_recovery.inc
SELECT LENGTH(b) FROM t1 WHERE i=3;
drop table t1;
# clean up everything
let $mms_purpose=feeding_recovery;
eval drop database mysqltest_for_$mms_purpose;
let $mms_purpose=comparison;
eval drop database mysqltest_for_$mms_purpose;
drop database mysqltest;