summaryrefslogtreecommitdiff
path: root/storage/maria/ma_test_recovery
diff options
context:
space:
mode:
authorunknown <guilhem@gbichot4.local>2007-09-06 16:04:36 +0200
committerunknown <guilhem@gbichot4.local>2007-09-06 16:04:36 +0200
commitac4ad9bdba4082c184443858da11bf4b61d582ff (patch)
treebd425f3afa9a6c06987bfdcf725269b62275b277 /storage/maria/ma_test_recovery
parent58ac5254fabb2e571af18f15aba874121a92a05f (diff)
downloadmariadb-git-ac4ad9bdba4082c184443858da11bf4b61d582ff.tar.gz
WL#3072 Maria Recovery
misc fixes of execution of UNDOs in the UNDO phase: - into the CLR_END, store the LSN of the _previous_ UNDO (we debated what was best, so far we're going with "previous"; later we can change to "current" if needed), and store the type of record which is being undone (needed to know how to update state.records when we see the CLR_END during the REDO phase). - declaring all UNDOs and CLR_END as "compressed" - when executing an UNDO in the UNDO phase, state.records is updated as a hook when writing CLR_END (needed for "recovery of the state"), and so is trn->undo_lsn (needed for when we have checkpoints). - bugfix (execution of UNDO_ROW_DELETE didn't store the correct checksum into the re-inserted row, maria_chk -r thus threw the row away). - modifications of ma_test1: where to stop is now driven by --testflag; --test-undo just tells how to stop (flush data, flush log, nothing). - ma_test_recovery: testing of the UNDO phase, more testing of the REDO phase, identification of a bug. storage/maria/ma_blockrec.c: - bugfix: execution of UNDO_ROW_DELETE didn't store the correct checksum into the row (leading to "maria_chk -r" eliminating the re-inserted row, net effect was that rollback appeared to have rolled back no deletion). Reason was that write_block_record() used info->cur_row.checksum, while "row" can be != &info->cur_row (case of UNDO_ROW_DELETE). After fixing this, problems with _ma_update_block_record() appeared; indeed checksum was computed by allocate_and_write_block_record() while _ma_update_block_record() directly calls write_block_record(). Solution is to compute checksum in write_block_record() instead. - when executing an UNDO, we now pass the LSN of the _previous_ UNDO to block_format functions. This LSN can be 0 (if the being-executed UNDO was the transaction's first UNDO), so "undo_lsn==0" cannot work anymore to indicate "this is not UNDO work". Using undo_lsn==LSN_ERROR instead (this is an impossible LSN). - store into CLR_END the type of log record which was undone (INSERT/UPDATE/DELETE); needed for Recovery to know if/how it has to update state.records if it sees this CLR_END in the REDO phase. - when writing the CLR_END in _ma_apply_undo_row_insert(), the place to store file's id is log_data+LSN_STORE_SIZE. - in _ma_apply_undo_row_insert(), the records-- is moved to a hook when writing the CLR_END (this way it is under log's mutex which is needed for "recovery of the state") storage/maria/ma_loghandler.c: - all UNDOs, and CLR_END, start with the LSN of another UNDO; so we can declare them "compressed". - write_hook_for_clr_end() to set trn->undo_lsn (to the previous UNDO's LSN) under log's lock (like UNDOs set trn->undo_lsn under log's lock), and also update, if appropriate, state.records. - reset share->id to 0 when deassigning; not useful for now but sounds logical. storage/maria/ma_recovery.c: - if no table is found for a REDO, it's not an error; for an UNDO, it is - in the REDO phase, when we see a CLR_END we must update trn->undo_lsn and sometimes state.records. - in the UNDO phase, when we execute an UNDO_ROW_INSERT: * update trn->undo_lsn only after executing the record * store the _previous_ undo_lsn into the CLR_END - at the end of the REDO phase, when we recreate TRN objects, they have already their long id in the log (either via a LOGREC_LONG_TRANSACTION_ID, or in a checkpoint record), don't write a new, useless LOGREC_LONG_TRANSACTION_ID for them. storage/maria/ma_test1.c: * where to stop execution is now driven by --testflag and not --test-undo (ma_test2 already has --testflag for the same purpose). This allows us to do a clean stop (with commit) at any point. * --test-undo=# tells how to abort (flush all pages (which implies flushing log) or only log or nothing); all such "ways of crashing" are tested in ma_test_recovery storage/maria/ma_test_recovery: * Testing execution of UNDOs, with and without BLOBs. * Testing idempotency of REDOs. * See @todo for a probable bug with BLOBs. * maria_chk -rq instead of -r, as with -q it nicely stops on any problem in the data file (like the checksum bug see comment of ma_blockrec.c). * Testing if log was written by UNDO phase (often expected), not written by REDO phase (always expected). * Less output on the screen, compares with expected output in the end. * some shell thingies like "set --" and $# are courtesy of Danny and Pekka. storage/maria/maria_read_log.c: when only displaying the records, don't do an UNDO phase storage/maria/ma_test_recovery.expected: This is the expected output of a great part of ma_test_recovery. ma_test_recovery compares its output to the expected output and tells if different. If we look at this file it mentions differences in checksum (normal, it's not recovered yet) and in records count (getting a correct records' count when recovery starts on an already existing table, like when testing rollback, is coded but not yet pushed).
Diffstat (limited to 'storage/maria/ma_test_recovery')
-rwxr-xr-xstorage/maria/ma_test_recovery205
1 files changed, 174 insertions, 31 deletions
diff --git a/storage/maria/ma_test_recovery b/storage/maria/ma_test_recovery
index 4e88824197e..b2d2bab7a2e 100755
--- a/storage/maria/ma_test_recovery
+++ b/storage/maria/ma_test_recovery
@@ -7,58 +7,201 @@ then
maria_path="."
fi
-tmp=$maria_path/tmp
+# test data is always put in the current directory or a tmp subdirectory of it
+tmp="./tmp"
if test '!' -d $tmp
then
mkdir $tmp
fi
-echo "MARIA RECOVERY TESTS - success is if exit code is 0"
+echo "MARIA RECOVERY TESTS"
+check_table_is_same()
+{
+ # Computes checksum of new table and compares to checksum of old table
+ # Shows any difference in table's state (info from the index's header)
+
+ $maria_path/maria_chk -dvv $table | grep -v "Creation time:" > $tmp/maria_chk_message.txt 2>&1
+
+ # save the index file (because we want to test idempotency afterwards)
+ cp $table.MAI tmp/
+ # In the repair below it's good to use -q because it will die on any
+ # incorrectness of the data file if UNDO was badly applied.
+ # QQ: Remove the following line when we also can recover the index file
+ $maria_path/maria_chk -s -rq $table
+
+ $maria_path/maria_chk -s -e $table
+ checksum2=`$maria_path/maria_chk -dss $table`
+ if test "$checksum" != "$checksum2"
+ then
+ echo "checksum differs for $table before and after recovery"
+ return 1;
+ fi
+
+ diff $tmp/maria_chk_message.good.txt $tmp/maria_chk_message.txt > $tmp/maria_chk_diff.txt || true
+ if [ -s $tmp/maria_chk_diff.txt ]
+ then
+ echo "Differences in maria_chk -dvv, recovery not yet perfect !"
+ echo "========DIFF START======="
+ cat $tmp/maria_chk_diff.txt
+ echo "========DIFF END======="
+ fi
+ mv tmp/$table.MAI .
+}
+
+apply_log()
+{
+ # applies log, can verify if applying did write to log or not
+
+ shouldchangelog=$1
+ if [ "$shouldchangelog" != "shouldnotchangelog" ] &&
+ [ "$shouldchangelog" != "shouldchangelog" ] &&
+ [ "$shouldchangelog" != "dontknow" ]
+ then
+ echo "bad argument '$shouldchangelog'"
+ return 1
+ fi
+ log_md5=`md5sum maria_log.*`
+ echo "applying log"
+ $maria_path/maria_read_log -a > $tmp/maria_read_log_$table.txt
+ log_md5_2=`md5sum maria_log.*`
+ if [ "$log_md5" != "$log_md5_2" ]
+ then
+ if [ "$shouldchangelog" == "shouldnotchangelog" ]
+ then
+ echo "maria_read_log should not have modified the log"
+ return 1
+ fi
+ else
+ if [ "$shouldchangelog" == "shouldchangelog" ]
+ then
+ echo "maria_read_log should have modified the log"
+ return 1
+ fi
+ fi
+}
+
+# To not flood the screen, we redirect all the commands below to a text file
+# and just give a final error if their output is not as expected
+
+(
+
+# this message is to remember about the problem with -b (see @todo below)
+echo "!!!!!!!! REMEMBER to FIX this BLOB issue !!!!!!!"
+
+echo "Testing the REDO PHASE ALONE"
# runs a program inserting/deleting rows, then moves the resulting table
# elsewhere; applies the log and checks that the data file is
# identical to the saved original.
# Does not test the index file as we don't have logging for it yet.
-for prog in "$maria_path/ma_test1 $silent -M -T -c" "$maria_path/ma_test2 $silent -L -K -W -P -M -T -c" "$maria_path/ma_test2 $silent -M -T -c -b"
+set -- "$maria_path/ma_test1 $silent -M -T -c" "$maria_path/ma_test2 $silent -L -K -W -P -M -T -c" "$maria_path/ma_test2 $silent -M -T -c -b"
+while [ $# != 0 ]
do
- rm -f maria_log.* maria_log_control
+ prog=$1
+ rm maria_log.* maria_log_control
echo "TEST WITH $prog"
$prog
# derive table's name from program's name
table=`echo $prog | sed -e 's;.*ma_\(test[0-9]\).*;\1;' `
- $maria_path/maria_chk -dvv $table > $tmp/maria_chk_message.good.txt 2>&1
+ $maria_path/maria_chk -dvv $table | grep -v "Creation time:"> $tmp/maria_chk_message.good.txt 2>&1
checksum=`$maria_path/maria_chk -dss $table`
- mv -f $table.MAD $tmp/$table.MAD.good
+ mv $table.MAD $tmp/$table.MAD.good
rm $table.MAI
- echo "applying log"
- $maria_path/maria_read_log -a > $tmp/maria_read_log_$table.txt
- $maria_path/maria_chk -dvv $table > $tmp/maria_chk_message.txt 2>&1
-
+ apply_log "shouldnotchangelog"
+ cmp $table.MAD $tmp/$table.MAD.good
+ check_table_is_same
+ echo "testing idempotency"
+ apply_log "shouldnotchangelog"
cmp $table.MAD $tmp/$table.MAD.good
+ check_table_is_same
+ shift
+done
- # QQ: Remove the following line when we also can recovert the index file
- $maria_path/maria_chk -s -r $table
-
- $maria_path/maria_chk -s -e $table
- checksum2=`$maria_path/maria_chk -dss $table`
- if test "$checksum" != "$checksum2"
- then
- echo "checksum differs for $table before and after recovery"
- exit 1;
- fi
-
-# When "recovery of the table's state" is ready, we can test it like this:
-# diff $tmp/maria_chk_message.good.txt $tmp/maria_chk_message.txt > $tmp/maria_chk_diff.txt || true
-# if [ -s $tmp/maria_chk_diff.txt ]
-# then
-# echo "Differences in maria_chk -dvv, recovery not yet perfect !"
-# echo "========DIFF START======="
-# cat $tmp/maria_chk_diff.txt
-# echo "========DIFF END======="
-# fi
- rm -f $table.* $tmp/maria_chk_*.txt $tmp/maria_read_log_$table.txt
+echo "Testing the REDO AND UNDO PHASE"
+# The test programs look like:
+# work; commit (time T1); work; exit-without-commit (time T2)
+# We first run the test program and let it exit after T1's commit.
+# Then we run it again and let it exit at T2. Then we compare
+# and expect identity.
+
+for blobs in "" "-b" # we test table without blobs and then table with blobs
+do
+ for test_undo in 1 2 3
+ do
+ # first iteration tests rollback of insert, second tests rollback of delete
+ set -- "$maria_path/ma_test1 $silent -M -T -c -N $blobs" "--testflag=1" "--testflag=2" "$maria_path/ma_test1 $silent -M -T -c -N --debug=d:t:i:o,/tmp/ma_test1.trace $blobs" "--testflag=3" "--testflag=4"
+ # -N (create NULL fields) is needed because --test-undo adds it anyway
+ while [ $# != 0 ]
+ do
+ prog=$1
+ commit_run_args=$2
+ abort_run_args=$3;
+ rm maria_log.* maria_log_control
+ echo "TEST WITH $prog $commit_run_args (commit at end)"
+ $prog $commit_run_args
+ # derive table's name from program's name
+ table=`echo $prog | sed -e 's;.*ma_\(test[0-9]\).*;\1;' `
+ $maria_path/maria_chk -dvv $table | grep -v "Creation time:"> $tmp/maria_chk_message.good.txt 2>&1
+ checksum=`$maria_path/maria_chk -dss $table`
+ mv $table.MAD $tmp/$table.MAD.good
+ rm $table.MAI
+ rm maria_log.* maria_log_control
+ echo "TEST WITH $prog $abort_run_args --test-undo=$test_undo (additional aborted work)"
+ $prog $abort_run_args --test-undo=$test_undo
+ cp $table.MAD $tmp/$table.MAD.before_undo
+ if [ $test_undo -lt 3 ]
+ then
+ apply_log "shouldchangelog" # should undo aborted work
+ else
+ # probably nothing to undo went to log or data file
+ apply_log "dontknow"
+ fi
+ cp $table.MAD $tmp/$table.MAD.after_undo
+
+ # It is impossible to do a "cmp" between .good and .after_undo,
+ # because the UNDO phase generated log
+ # records whose LSN tagged pages. Another reason is that rolling back
+ # INSERT only marks the rows free, does not empty them (optimization), so
+ # traces of the INSERT+rollback remain.
+
+ check_table_is_same
+ echo "testing idempotency"
+ apply_log "shouldnotchangelog"
+ cmp $table.MAD $tmp/$table.MAD.after_undo
+ check_table_is_same
+ echo "testing applying of CLRs to recreate table"
+ rm $table.MA?
+ apply_log "shouldnotchangelog"
+ # the cmp below fails with blobs! @todo RECOVERY BUG find out why.
+ # It is probably serious; REDOs shouldn't place rows in different
+ # positions from what the run-time code did. Indeed it may lead to
+ # more or less free space...
+ # Execution of UNDO re-inserted rows at different positions than
+ # originally. This generated REDOs which do not insert at the same
+ # positions as the execution of UNDOs, but at the same positions
+ # as before the row was originally deleted.
+ if [ "$blobs" == "" ]
+ then
+ cmp $table.MAD $tmp/$table.MAD.after_undo
+ fi
+ check_table_is_same
+ shift 3
+ done
done
+done
+rm -f $table.* $tmp/$table* $tmp/maria_chk_*.txt $tmp/maria_read_log_$table.txt
+
+) > $tmp/ma_test_recovery.output
+diff $maria_path/ma_test_recovery.expected $tmp/ma_test_recovery.output > /dev/null || diff_failed=1
+if [ "$diff_failed" == "1" ]
+ then
+ echo "UNEXPECTED OUTPUT OF TESTS, FAILED"
+ echo "For more info, do diff $maria_path/ma_test_recovery.expected $tmp/ma_test_recovery.output"
+ exit 1
+ fi
echo "ALL RECOVERY TESTS OK"
+# this message is to remember about the problem with -b (see @todo above)
+echo "!!!!!!!! BUT REMEMBER to FIX this BLOB issue !!!!!!!"