mirror of
https://github.com/MariaDB/server.git
synced 2025-07-30 16:24:05 +03:00
WL#4374 "Maria - force start if Recovery fails multiple times"
http://forge.mysql.com/worklog/task.php?id=4374 new option --maria-force-start-after-recovery-failures=N; number of consecutive recovery failures (failures of log reading or recovery processing, anything in [translog_init(),maria_recovery_from_log()]) is stored in the control file; if at a Maria start they are more than N, logs are removed. This is for automated systems which have to run whatever happens. As tables risk staying corrupted, --maria-recover should also be used on them: this revision makes maria-recover work (it was disabled). Fixed bug in translog_is_log_files(). translog_init() now prints message to error log if failed. Removed \0 in the output of SHOW ENGINE MARIA LOGS; removed hard-coded engine name there. KNOWN_BUGS.txt: As option --maria-force-start-after-recovery-failures is added, it corresponds to the wish "we should fix that if this happens etc". LOAD INDEX is not ignored since a few weeks. Listed concurrency bugs have been fixed some time ago. Recovery of fulltext and GIS indexes works since a few weeks. mysql-test/include/maria_make_snapshot.inc: configurable prefix in table's name (so far 't' or 't_corrupted') mysql-test/include/maria_make_snapshot_for_comparison.inc: configurable prefix in table's name (so far 't' or 't_corrupted') mysql-test/include/maria_make_snapshot_for_feeding_recovery.inc: configurable prefix in table's name (so far 't' or 't_corrupted') mysql-test/include/maria_verify_recovery.inc: configurable prefix in table's name (so far 't' or 't_corrupted') mysql-test/lib/mtr_report.pl: new test maria-recover.test generates expected corruption warnings in the error log. maria-recovery.test's corrupted table is renamed to t_corrupted1 instead of t1. mysql-test/r/maria-preload.result: result update. maria_pagecache_read* values are similar to the previous version of this file, though a bit bigger because using the information_schema and the join leads to some internal maria temp table being used, and thus some blocks of it being read. mysql-test/r/maria-purge.result: engine's name in SHOW ENGINE MARIA LOGS changed. mysql-test/r/maria-recover.result: result for new test. We see corruption messages at first SELECT and then none at second SELECT, expected. mysql-test/r/maria-recovery.result: result update mysql-test/r/maria.result: new variables show up mysql-test/t/disabled.def: BUG#34911 is not fixed but the test had been made independent of the bug (workaround). A new bug (crash) has popped recently, so it has to stay disabled (BUG#35107). mysql-test/t/maria-preload.test: Work around BUG#34911 "FLUSH STATUS doesn't flush what it should": compute differences in status variables before and after relevant queries mysql-test/t/maria-recover-master.opt: test --maria-recover mysql-test/t/maria-recover.test: Test of the --maria-recover option (build a corrupted table and see if it is auto-repaired) mysql-test/t/maria-recovery-big.test: update for new API of include/maria*.inc mysql-test/t/maria-recovery-bitmap.test: update for new API of include/maria*.inc mysql-test/t/maria-recovery.test: update for new API of include/maria*.inc. Corrupted table t1 renamed to t_corrupted1, so that mtr_report.pl does not blindly remove all corruption messages for t1 which is a common name. storage/maria/ha_maria.cc: Enabling maria-recover. Adding option and global variable --maria_force_start_after_recovery_failures: ha_maria_init() calls mark_recovery_start() and mark_recovery_success() to keep track of failed consecutive recoveries and remove logs if needed. Removed \0 in the output of SHOW ENGINE MARIA LOGS; removed hard-coded engine name there. storage/maria/ma_checkpoint.c: new prototype storage/maria/ma_control_file.c: Storing in one byte in the control file, the number of consecutive recovery failures. storage/maria/ma_control_file.h: new prototype storage/maria/ma_init.c: new prototype storage/maria/ma_locking.c: Need to update open_count on disk at first write and close for transactional tables, like we already did for non-transactional tables, otherwise we cannot notice that the table is dubious. storage/maria/ma_loghandler.c: translog_is_log_files() is made more generic to serve either to search or to delete logs (the latter is for --maria-force-start-after-recovery-failures). It also had a bug (always returned FALSE). storage/maria/ma_loghandler.h: export function because ha_maria::mark_recovery_start() needs it storage/maria/ma_recovery.c: changing name of maria_recover() to distinguish from the maria-recover option. storage/maria/ma_recovery.h: changing name of maria_recover() to distinguish from the maria-recover option. storage/maria/ma_test_force_start.pl: Test of --maria-force-start-after-recovery-failures (and also, to be realistic, of --maria-recover). This is standalone because mysql-test-run does not support testing that multiple mysqld restarts expectedly failed. I'll have to run it on my machine and also on a Windows machine. storage/maria/unittest/ma_control_file-t.c: adding recovery_failures to the test storage/maria/unittest/ma_test_loghandler_multigroup-t.c: fix for compiler warning (unused variable in non-debug build)
This commit is contained in:
@ -24,23 +24,9 @@ or in the worst case add it here for others to know!
|
|||||||
Known bugs that we are working on and will be fixed shortly
|
Known bugs that we are working on and will be fixed shortly
|
||||||
===========================================================
|
===========================================================
|
||||||
|
|
||||||
- If the log files are damaged or inconsistent, Maria may fail to start.
|
|
||||||
We should fix that if this happens and mysqld is restarted (thanks to
|
|
||||||
mysqld_safe, instance manager or other script) it should disregard the
|
|
||||||
old logs, start anyway and automaticly repair any tables that was found
|
|
||||||
to be crashed on open.
|
|
||||||
Temporary fix is to remove or maria_log.???????? files from the data
|
|
||||||
directory, restart mysqld and run CHECK TABLE / REPAIR TABLE or
|
|
||||||
mysqlcheck on your Maria tables
|
|
||||||
- We have some instabilities in log writing that is under investigatation
|
- We have some instabilities in log writing that is under investigatation
|
||||||
This causes mainly assert to triggers in the code and sometimes
|
This causes mainly assert to triggers in the code and sometimes
|
||||||
the log handler doesn't start up after restart.
|
the log handler doesn't start up after restart.
|
||||||
- LOAD INDEX commands are for the moment ignored for Maria tables
|
|
||||||
(The code needs to be rewritten to do all reads through page cache to
|
|
||||||
avoid half-block reads)
|
|
||||||
- Some concurrency bugs in Maria's page cache which sometimes show up
|
|
||||||
under load http://bugs.mysql.com/bug.php?id=34161 and
|
|
||||||
http://bugs.mysql.com/bug.php?id=34634 .
|
|
||||||
|
|
||||||
Known bugs that are planned to be fixed before Beta
|
Known bugs that are planned to be fixed before Beta
|
||||||
===================================================
|
===================================================
|
||||||
@ -61,19 +47,15 @@ Known bugs that are planned to be fixed before Beta
|
|||||||
Missing features that is planned to fix before Beta
|
Missing features that is planned to fix before Beta
|
||||||
===================================================
|
===================================================
|
||||||
|
|
||||||
- We will add an maria-recover option to automaticly repair any
|
|
||||||
crashed tables on open. (This is needed for not transactional tables
|
|
||||||
and also in edge cases for transactional tables when the table
|
|
||||||
crashed because of a bug in MySQL or Maria code)
|
|
||||||
- Multiple concurrent inserts & multiple concurrent readers at same time
|
- Multiple concurrent inserts & multiple concurrent readers at same time
|
||||||
with full MVCC control. Note that UPDATE and DELETE will still be
|
with full MVCC control. Note that UPDATE and DELETE will still be
|
||||||
blocking (as with MyISAM)
|
blocking (as with MyISAM)
|
||||||
- COUNT(*) and TABLE CHECKSUM under MVCC (ie, they are instant and kept up
|
- COUNT(*) and TABLE CHECKSUM under MVCC (ie, they are instant and kept up
|
||||||
to date even with multiple inserter)
|
to date even with multiple inserter)
|
||||||
- Recovery of fulltext and GIS indexes.
|
|
||||||
|
|
||||||
|
|
||||||
Features planned for future releases
|
Features planned for future releases
|
||||||
====================================
|
====================================
|
||||||
|
|
||||||
http://forge.mysql.com/worklog/
|
http://forge.mysql.com/worklog/
|
||||||
|
(you can enter "maria" in the "quick search" field there).
|
||||||
|
@ -10,28 +10,29 @@
|
|||||||
# $mms_copy : to copy table from database to spare directory
|
# $mms_copy : to copy table from database to spare directory
|
||||||
# $mms_reverse : to copy it back
|
# $mms_reverse : to copy it back
|
||||||
# $mms_compare_physically : to compare both byte-for-byte
|
# $mms_compare_physically : to compare both byte-for-byte
|
||||||
# 2) set $mms_table_to_use to a number N: table will be mysqltest.tN
|
# 2) set $mms_tname to a string and set $mms_table_to_use to a number: tables
|
||||||
|
# will be mysqltest.$mms_tname$mms_table_to_use.
|
||||||
# 3) set $mms_purpose to say what this copy is for (influences the naming
|
# 3) set $mms_purpose to say what this copy is for (influences the naming
|
||||||
# of the spare directory).
|
# of the spare directory).
|
||||||
|
|
||||||
if ($mms_copy)
|
if ($mms_copy)
|
||||||
{
|
{
|
||||||
--echo * copied t$mms_table_to_use for $mms_purpose
|
--echo * copied $mms_tname$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/$mms_tname$mms_table_to_use.MAD $MYSQLTEST_VARDIR/master-data/mysqltest_for_$mms_purpose/$mms_tname$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/$mms_tname$mms_table_to_use.MAI $MYSQLTEST_VARDIR/master-data/mysqltest_for_$mms_purpose/$mms_tname$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;
|
copy_file $MYSQLTEST_VARDIR/master-data/mysqltest/$mms_tname$mms_table_to_use.frm $MYSQLTEST_VARDIR/master-data/mysqltest_for_$mms_purpose/$mms_tname$mms_table_to_use.frm;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($mms_reverse_copy)
|
if ($mms_reverse_copy)
|
||||||
{
|
{
|
||||||
# do not call this without flushing target table first!
|
# do not call this without flushing target table first!
|
||||||
--echo * copied t$mms_table_to_use back for $mms_purpose
|
--echo * copied $mms_tname$mms_table_to_use back for $mms_purpose
|
||||||
-- error 0,1
|
-- error 0,1
|
||||||
remove_file $MYSQLTEST_VARDIR/master-data/mysqltest/t$mms_table_to_use.MAD;
|
remove_file $MYSQLTEST_VARDIR/master-data/mysqltest/$mms_tname$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;
|
copy_file $MYSQLTEST_VARDIR/master-data/mysqltest_for_$mms_purpose/$mms_tname$mms_table_to_use.MAD $MYSQLTEST_VARDIR/master-data/mysqltest/$mms_tname$mms_table_to_use.MAD;
|
||||||
-- error 0,1
|
-- error 0,1
|
||||||
remove_file $MYSQLTEST_VARDIR/master-data/mysqltest/t$mms_table_to_use.MAI;
|
remove_file $MYSQLTEST_VARDIR/master-data/mysqltest/$mms_tname$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;
|
copy_file $MYSQLTEST_VARDIR/master-data/mysqltest_for_$mms_purpose/$mms_tname$mms_table_to_use.MAI $MYSQLTEST_VARDIR/master-data/mysqltest/$mms_tname$mms_table_to_use.MAI;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($mms_compare_physically)
|
if ($mms_compare_physically)
|
||||||
@ -41,8 +42,8 @@ if ($mms_compare_physically)
|
|||||||
# So, do this only when testing REDO phase.
|
# So, do this only when testing REDO phase.
|
||||||
# If UNDO phase, we nevertheless compare checksums
|
# If UNDO phase, we nevertheless compare checksums
|
||||||
# (see maria_verify_recovery.inc).
|
# (see maria_verify_recovery.inc).
|
||||||
--echo * compared t$mms_table_to_use to old version
|
--echo * compared $mms_tname$mms_table_to_use to old version
|
||||||
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;
|
diff_files $MYSQLTEST_VARDIR/master-data/mysqltest/$mms_tname$mms_table_to_use.MAD $MYSQLTEST_VARDIR/master-data/mysqltest_for_$mms_purpose/$mms_tname$mms_table_to_use.MAD;
|
||||||
# index file not yet recovered
|
# 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;
|
# diff_files $MYSQLTEST_VARDIR/master-data/mysqltest/$mms_tname$mms_table_to_use.MAI $MYSQLTEST_VARDIR/master-data/mysqltest_for_$mms_purpose/$mms_tname$mms_table_to_use.MAI;
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
# Maria helper script
|
# Maria helper script
|
||||||
# Copies clean tables' data and index file to other directory
|
# Copies clean tables' data and index file to other directory
|
||||||
# Tables are t1...t[$mms_tables]
|
# Tables are $mms_tname1...$mms_tname[$mms_tables]
|
||||||
# They are later used as a reference to see if recovery works.
|
# They are later used as a reference to see if recovery works.
|
||||||
|
|
||||||
# API:
|
# API:
|
||||||
# set $mms_tables to N, the script will cover tables mysqltest.t1,...tN
|
# set $mms_tname to a string, and $mms_tables to a number N, the script will
|
||||||
|
# cover tables mysqltest.$mms_tname1,...$mms_tnameN
|
||||||
|
|
||||||
connection admin;
|
connection admin;
|
||||||
|
|
||||||
@ -22,7 +23,7 @@ eval create database mysqltest_for_$mms_purpose;
|
|||||||
while ($mms_table_to_use)
|
while ($mms_table_to_use)
|
||||||
{
|
{
|
||||||
# to serve as a reference, table must be in a clean state
|
# to serve as a reference, table must be in a clean state
|
||||||
eval flush table t$mms_table_to_use;
|
eval flush table $mms_tname$mms_table_to_use;
|
||||||
-- source include/maria_make_snapshot.inc
|
-- source include/maria_make_snapshot.inc
|
||||||
dec $mms_table_to_use;
|
dec $mms_table_to_use;
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,14 @@
|
|||||||
# Maria helper script
|
# Maria helper script
|
||||||
# Copies tables' data and index file to other directory, and control file.
|
# Copies tables' data and index file to other directory, and control file.
|
||||||
# Tables are t1...t[$mms_tables].
|
# Tables are $mms_tname1...$mms_tname[$mms_tables].
|
||||||
# Later, mysqld is shutdown, and that snapshot is put back into the
|
# Later, mysqld is shutdown, and that snapshot is put back into the
|
||||||
# datadir, control file too ("flashing recovery's brain"), and recovery is let
|
# datadir, control file too ("flashing recovery's brain"), and recovery is let
|
||||||
# to run on it (see maria_verify_recovery.inc).
|
# to run on it (see maria_verify_recovery.inc).
|
||||||
|
|
||||||
# API:
|
# API:
|
||||||
# set $mms_tables to N, the script will cover tables mysqltest.t1,...tN
|
# set $mms_tname to a string, and $mms_tables to a number N, the script will
|
||||||
|
# cover tables mysqltest.$mms_tname1,...$mms_tnameN
|
||||||
|
|
||||||
|
|
||||||
connection admin;
|
connection admin;
|
||||||
|
|
||||||
|
@ -2,7 +2,8 @@
|
|||||||
# Runs recovery, compare with expected table data.
|
# Runs recovery, compare with expected table data.
|
||||||
|
|
||||||
# API:
|
# API:
|
||||||
# 1) set $mms_tables to N, the script will cover tables mysqltest.t1,...tN
|
# 1) set $mms_tname to a string, and $mms_tables to a number N, the script
|
||||||
|
# will cover tables mysqltest.$mms_tname1,...$mms_tnameN
|
||||||
# 2) set $mvr_debug_option to the crash way
|
# 2) set $mvr_debug_option to the crash way
|
||||||
# 3) set $mvr_crash_statement to the statement which will trigger a crash
|
# 3) set $mvr_crash_statement to the statement which will trigger a crash
|
||||||
# 4) set $mvr_restore_old_snapshot to 1 if you want recovery to run on
|
# 4) set $mvr_restore_old_snapshot to 1 if you want recovery to run on
|
||||||
@ -77,10 +78,10 @@ let $mms_purpose=comparison;
|
|||||||
let $mms_compare_physically=$mms_compare_physically_save;
|
let $mms_compare_physically=$mms_compare_physically_save;
|
||||||
while ($mms_table_to_use)
|
while ($mms_table_to_use)
|
||||||
{
|
{
|
||||||
eval check table t$mms_table_to_use extended;
|
eval check table $mms_tname$mms_table_to_use extended;
|
||||||
--echo * testing that checksum after recovery is as expected
|
--echo * testing that checksum after recovery is as expected
|
||||||
let $new_checksum=`CHECKSUM TABLE t$mms_table_to_use`;
|
let $new_checksum=`CHECKSUM TABLE $mms_tname$mms_table_to_use`;
|
||||||
let $old_checksum=`CHECKSUM TABLE mysqltest_for_$mms_purpose.t$mms_table_to_use`;
|
let $old_checksum=`CHECKSUM TABLE mysqltest_for_$mms_purpose.$mms_tname$mms_table_to_use`;
|
||||||
# the $ text variables above are of the form "db.tablename\tchecksum",
|
# the $ text variables above are of the form "db.tablename\tchecksum",
|
||||||
# as db differs, we use substring().
|
# as db differs, we use substring().
|
||||||
--disable_query_log
|
--disable_query_log
|
||||||
|
@ -405,7 +405,12 @@ sub mtr_report_stats ($) {
|
|||||||
# maria-recovery.test has warning about missing log file
|
# maria-recovery.test has warning about missing log file
|
||||||
/File '.*maria_log.000.*' not found \(Errcode: 2\)/ or
|
/File '.*maria_log.000.*' not found \(Errcode: 2\)/ or
|
||||||
# and about marked-corrupted table
|
# and about marked-corrupted table
|
||||||
/Table '.\/mysqltest\/t1' is crashed, skipping it. Please repair it with maria_chk -r/
|
/Table '.\/mysqltest\/t_corrupted1' is crashed, skipping it. Please repair it with maria_chk -r/ or
|
||||||
|
# maria-recover.test corrupts tables on purpose
|
||||||
|
/Checking table: '.\/mysqltest\/t_corrupted2'/ or
|
||||||
|
/Recovering table: '.\/mysqltest\/t_corrupted2'/ or
|
||||||
|
/Table '.\/mysqltest\/t_corrupted2' is marked as crashed and should be repaired/ or
|
||||||
|
/Incorrect key file for table '.\/mysqltest\/t_corrupted2.MAI'; try to repair it/
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
next; # Skip these lines
|
next; # Skip these lines
|
||||||
|
@ -1,4 +1,7 @@
|
|||||||
drop table if exists t1, t2;
|
drop table if exists t1, t2;
|
||||||
|
create temporary table initial
|
||||||
|
select variable_name,variable_value from
|
||||||
|
information_schema.global_status where variable_name like "Maria_pagecache_read%";
|
||||||
create table t1 (
|
create table t1 (
|
||||||
a int not null auto_increment,
|
a int not null auto_increment,
|
||||||
b char(16) not null,
|
b char(16) not null,
|
||||||
@ -46,24 +49,24 @@ count(*)
|
|||||||
20672
|
20672
|
||||||
flush tables;
|
flush tables;
|
||||||
flush status;
|
flush status;
|
||||||
show status like "maria_pagecache_read%";
|
select g.variable_name,g.variable_value-i.variable_value from information_schema.global_status as g,initial as i where g.variable_name like "Maria_pagecache_read%" and g.variable_name=i.variable_name order by g.variable_name desc;
|
||||||
Variable_name Value
|
variable_name g.variable_value-i.variable_value
|
||||||
Maria_pagecache_read_requests 211388
|
MARIA_PAGECACHE_READ_REQUESTS 211644
|
||||||
Maria_pagecache_reads 115
|
MARIA_PAGECACHE_READS 3
|
||||||
select count(*) from t1 where b = 'test1';
|
select count(*) from t1 where b = 'test1';
|
||||||
count(*)
|
count(*)
|
||||||
4181
|
4181
|
||||||
show status like "maria_pagecache_read%";
|
select g.variable_name,g.variable_value-i.variable_value from information_schema.global_status as g,initial as i where g.variable_name like "Maria_pagecache_read%" and g.variable_name=i.variable_name order by g.variable_name desc;
|
||||||
Variable_name Value
|
variable_name g.variable_value-i.variable_value
|
||||||
Maria_pagecache_read_requests 211414
|
MARIA_PAGECACHE_READ_REQUESTS 211926
|
||||||
Maria_pagecache_reads 122
|
MARIA_PAGECACHE_READS 11
|
||||||
select count(*) from t1 where b = 'test1';
|
select count(*) from t1 where b = 'test1';
|
||||||
count(*)
|
count(*)
|
||||||
4181
|
4181
|
||||||
show status like "maria_pagecache_read%";
|
select g.variable_name,g.variable_value-i.variable_value from information_schema.global_status as g,initial as i where g.variable_name like "Maria_pagecache_read%" and g.variable_name=i.variable_name order by g.variable_name desc;
|
||||||
Variable_name Value
|
variable_name g.variable_value-i.variable_value
|
||||||
Maria_pagecache_read_requests 211440
|
MARIA_PAGECACHE_READ_REQUESTS 212208
|
||||||
Maria_pagecache_reads 122
|
MARIA_PAGECACHE_READS 12
|
||||||
flush tables;
|
flush tables;
|
||||||
flush status;
|
flush status;
|
||||||
select @@preload_buffer_size;
|
select @@preload_buffer_size;
|
||||||
@ -72,23 +75,23 @@ select @@preload_buffer_size;
|
|||||||
load index into cache t1;
|
load index into cache t1;
|
||||||
Table Op Msg_type Msg_text
|
Table Op Msg_type Msg_text
|
||||||
test.t1 preload_keys status OK
|
test.t1 preload_keys status OK
|
||||||
show status like "maria_pagecache_read%";
|
select g.variable_name,g.variable_value-i.variable_value from information_schema.global_status as g,initial as i where g.variable_name like "Maria_pagecache_read%" and g.variable_name=i.variable_name order by g.variable_name desc;
|
||||||
Variable_name Value
|
variable_name g.variable_value-i.variable_value
|
||||||
Maria_pagecache_read_requests 211511
|
MARIA_PAGECACHE_READ_REQUESTS 212535
|
||||||
Maria_pagecache_reads 193
|
MARIA_PAGECACHE_READS 84
|
||||||
select count(*) from t1 where b = 'test1';
|
select count(*) from t1 where b = 'test1';
|
||||||
count(*)
|
count(*)
|
||||||
4181
|
4181
|
||||||
show status like "maria_pagecache_read%";
|
select g.variable_name,g.variable_value-i.variable_value from information_schema.global_status as g,initial as i where g.variable_name like "Maria_pagecache_read%" and g.variable_name=i.variable_name order by g.variable_name desc;
|
||||||
Variable_name Value
|
variable_name g.variable_value-i.variable_value
|
||||||
Maria_pagecache_read_requests 211537
|
MARIA_PAGECACHE_READ_REQUESTS 212817
|
||||||
Maria_pagecache_reads 193
|
MARIA_PAGECACHE_READS 85
|
||||||
flush tables;
|
flush tables;
|
||||||
flush status;
|
flush status;
|
||||||
show status like "maria_pagecache_read%";
|
select g.variable_name,g.variable_value-i.variable_value from information_schema.global_status as g,initial as i where g.variable_name like "Maria_pagecache_read%" and g.variable_name=i.variable_name order by g.variable_name desc;
|
||||||
Variable_name Value
|
variable_name g.variable_value-i.variable_value
|
||||||
Maria_pagecache_read_requests 211537
|
MARIA_PAGECACHE_READ_REQUESTS 213073
|
||||||
Maria_pagecache_reads 193
|
MARIA_PAGECACHE_READS 86
|
||||||
set session preload_buffer_size=256*1024;
|
set session preload_buffer_size=256*1024;
|
||||||
select @@preload_buffer_size;
|
select @@preload_buffer_size;
|
||||||
@@preload_buffer_size
|
@@preload_buffer_size
|
||||||
@ -96,23 +99,23 @@ select @@preload_buffer_size;
|
|||||||
load index into cache t1 ignore leaves;
|
load index into cache t1 ignore leaves;
|
||||||
Table Op Msg_type Msg_text
|
Table Op Msg_type Msg_text
|
||||||
test.t1 preload_keys status OK
|
test.t1 preload_keys status OK
|
||||||
show status like "maria_pagecache_read%";
|
select g.variable_name,g.variable_value-i.variable_value from information_schema.global_status as g,initial as i where g.variable_name like "Maria_pagecache_read%" and g.variable_name=i.variable_name order by g.variable_name desc;
|
||||||
Variable_name Value
|
variable_name g.variable_value-i.variable_value
|
||||||
Maria_pagecache_read_requests 211608
|
MARIA_PAGECACHE_READ_REQUESTS 213400
|
||||||
Maria_pagecache_reads 264
|
MARIA_PAGECACHE_READS 158
|
||||||
select count(*) from t1 where b = 'test1';
|
select count(*) from t1 where b = 'test1';
|
||||||
count(*)
|
count(*)
|
||||||
4181
|
4181
|
||||||
show status like "maria_pagecache_read%";
|
select g.variable_name,g.variable_value-i.variable_value from information_schema.global_status as g,initial as i where g.variable_name like "Maria_pagecache_read%" and g.variable_name=i.variable_name order by g.variable_name desc;
|
||||||
Variable_name Value
|
variable_name g.variable_value-i.variable_value
|
||||||
Maria_pagecache_read_requests 211634
|
MARIA_PAGECACHE_READ_REQUESTS 213682
|
||||||
Maria_pagecache_reads 270
|
MARIA_PAGECACHE_READS 165
|
||||||
flush tables;
|
flush tables;
|
||||||
flush status;
|
flush status;
|
||||||
show status like "maria_pagecache_read%";
|
select g.variable_name,g.variable_value-i.variable_value from information_schema.global_status as g,initial as i where g.variable_name like "Maria_pagecache_read%" and g.variable_name=i.variable_name order by g.variable_name desc;
|
||||||
Variable_name Value
|
variable_name g.variable_value-i.variable_value
|
||||||
Maria_pagecache_read_requests 211634
|
MARIA_PAGECACHE_READ_REQUESTS 213938
|
||||||
Maria_pagecache_reads 270
|
MARIA_PAGECACHE_READS 166
|
||||||
set session preload_buffer_size=1*1024;
|
set session preload_buffer_size=1*1024;
|
||||||
select @@preload_buffer_size;
|
select @@preload_buffer_size;
|
||||||
@@preload_buffer_size
|
@@preload_buffer_size
|
||||||
@ -121,52 +124,53 @@ load index into cache t1, t2 key (primary,b) ignore leaves;
|
|||||||
Table Op Msg_type Msg_text
|
Table Op Msg_type Msg_text
|
||||||
test.t1 preload_keys status OK
|
test.t1 preload_keys status OK
|
||||||
test.t2 preload_keys status OK
|
test.t2 preload_keys status OK
|
||||||
show status like "maria_pagecache_read%";
|
select g.variable_name,g.variable_value-i.variable_value from information_schema.global_status as g,initial as i where g.variable_name like "Maria_pagecache_read%" and g.variable_name=i.variable_name order by g.variable_name desc;
|
||||||
Variable_name Value
|
variable_name g.variable_value-i.variable_value
|
||||||
Maria_pagecache_read_requests 211748
|
MARIA_PAGECACHE_READ_REQUESTS 214308
|
||||||
Maria_pagecache_reads 384
|
MARIA_PAGECACHE_READS 281
|
||||||
select count(*) from t1 where b = 'test1';
|
select count(*) from t1 where b = 'test1';
|
||||||
count(*)
|
count(*)
|
||||||
4181
|
4181
|
||||||
select count(*) from t2 where b = 'test1';
|
select count(*) from t2 where b = 'test1';
|
||||||
count(*)
|
count(*)
|
||||||
2584
|
2584
|
||||||
show status like "maria_pagecache_read%";
|
select g.variable_name,g.variable_value-i.variable_value from information_schema.global_status as g,initial as i where g.variable_name like "Maria_pagecache_read%" and g.variable_name=i.variable_name order by g.variable_name desc;
|
||||||
Variable_name Value
|
variable_name g.variable_value-i.variable_value
|
||||||
Maria_pagecache_read_requests 211788
|
MARIA_PAGECACHE_READ_REQUESTS 214604
|
||||||
Maria_pagecache_reads 387
|
MARIA_PAGECACHE_READS 285
|
||||||
flush tables;
|
flush tables;
|
||||||
flush status;
|
flush status;
|
||||||
show status like "maria_pagecache_read%";
|
select g.variable_name,g.variable_value-i.variable_value from information_schema.global_status as g,initial as i where g.variable_name like "Maria_pagecache_read%" and g.variable_name=i.variable_name order by g.variable_name desc;
|
||||||
Variable_name Value
|
variable_name g.variable_value-i.variable_value
|
||||||
Maria_pagecache_read_requests 211788
|
MARIA_PAGECACHE_READ_REQUESTS 214860
|
||||||
Maria_pagecache_reads 387
|
MARIA_PAGECACHE_READS 286
|
||||||
load index into cache t3, t2 key (primary,b) ;
|
load index into cache t3, t2 key (primary,b) ;
|
||||||
Table Op Msg_type Msg_text
|
Table Op Msg_type Msg_text
|
||||||
test.t3 preload_keys Error Table 'test.t3' doesn't exist
|
test.t3 preload_keys Error Table 'test.t3' doesn't exist
|
||||||
test.t3 preload_keys error Corrupt
|
test.t3 preload_keys error Corrupt
|
||||||
test.t2 preload_keys status OK
|
test.t2 preload_keys status OK
|
||||||
show status like "maria_pagecache_read%";
|
select g.variable_name,g.variable_value-i.variable_value from information_schema.global_status as g,initial as i where g.variable_name like "Maria_pagecache_read%" and g.variable_name=i.variable_name order by g.variable_name desc;
|
||||||
Variable_name Value
|
variable_name g.variable_value-i.variable_value
|
||||||
Maria_pagecache_read_requests 211831
|
MARIA_PAGECACHE_READ_REQUESTS 215159
|
||||||
Maria_pagecache_reads 430
|
MARIA_PAGECACHE_READS 330
|
||||||
flush tables;
|
flush tables;
|
||||||
flush status;
|
flush status;
|
||||||
show status like "maria_pagecache_read%";
|
select g.variable_name,g.variable_value-i.variable_value from information_schema.global_status as g,initial as i where g.variable_name like "Maria_pagecache_read%" and g.variable_name=i.variable_name order by g.variable_name desc;
|
||||||
Variable_name Value
|
variable_name g.variable_value-i.variable_value
|
||||||
Maria_pagecache_read_requests 211831
|
MARIA_PAGECACHE_READ_REQUESTS 215415
|
||||||
Maria_pagecache_reads 430
|
MARIA_PAGECACHE_READS 331
|
||||||
load index into cache t3 key (b), t2 key (c) ;
|
load index into cache t3 key (b), t2 key (c) ;
|
||||||
Table Op Msg_type Msg_text
|
Table Op Msg_type Msg_text
|
||||||
test.t3 preload_keys Error Table 'test.t3' doesn't exist
|
test.t3 preload_keys Error Table 'test.t3' doesn't exist
|
||||||
test.t3 preload_keys error Corrupt
|
test.t3 preload_keys error Corrupt
|
||||||
test.t2 preload_keys Error Key 'c' doesn't exist in table 't2'
|
test.t2 preload_keys Error Key 'c' doesn't exist in table 't2'
|
||||||
test.t2 preload_keys status Operation failed
|
test.t2 preload_keys status Operation failed
|
||||||
show status like "maria_pagecache_read%";
|
select g.variable_name,g.variable_value-i.variable_value from information_schema.global_status as g,initial as i where g.variable_name like "Maria_pagecache_read%" and g.variable_name=i.variable_name order by g.variable_name desc;
|
||||||
Variable_name Value
|
variable_name g.variable_value-i.variable_value
|
||||||
Maria_pagecache_read_requests 211831
|
MARIA_PAGECACHE_READ_REQUESTS 215671
|
||||||
Maria_pagecache_reads 430
|
MARIA_PAGECACHE_READS 332
|
||||||
drop table t1, t2;
|
drop table t1, t2;
|
||||||
|
drop temporary table initial;
|
||||||
show status like "key_read%";
|
show status like "key_read%";
|
||||||
Variable_name Value
|
Variable_name Value
|
||||||
Key_read_requests 0
|
Key_read_requests 0
|
||||||
|
@ -37,13 +37,13 @@ set global maria_log_file_size=16777216;
|
|||||||
set global maria_checkpoint_interval=30;
|
set global maria_checkpoint_interval=30;
|
||||||
SHOW ENGINE maria logs;
|
SHOW ENGINE maria logs;
|
||||||
Type Name Status
|
Type Name Status
|
||||||
maria master-data/maria_log.00000002 in use
|
MARIA master-data/maria_log.00000002 in use
|
||||||
insert into t2 select * from t1;
|
insert into t2 select * from t1;
|
||||||
insert into t1 select * from t2;
|
insert into t1 select * from t2;
|
||||||
set global maria_checkpoint_interval=30;
|
set global maria_checkpoint_interval=30;
|
||||||
SHOW ENGINE maria logs;
|
SHOW ENGINE maria logs;
|
||||||
Type Name Status
|
Type Name Status
|
||||||
maria master-data/maria_log.00000004 in use
|
MARIA master-data/maria_log.00000004 in use
|
||||||
set global maria_log_file_size=16777216;
|
set global maria_log_file_size=16777216;
|
||||||
select @@global.maria_log_file_size;
|
select @@global.maria_log_file_size;
|
||||||
@@global.maria_log_file_size
|
@@global.maria_log_file_size
|
||||||
@ -51,7 +51,7 @@ select @@global.maria_log_file_size;
|
|||||||
set global maria_checkpoint_interval=30;
|
set global maria_checkpoint_interval=30;
|
||||||
SHOW ENGINE maria logs;
|
SHOW ENGINE maria logs;
|
||||||
Type Name Status
|
Type Name Status
|
||||||
maria master-data/maria_log.00000004 in use
|
MARIA master-data/maria_log.00000004 in use
|
||||||
set global maria_log_file_size=8388608;
|
set global maria_log_file_size=8388608;
|
||||||
select @@global.maria_log_file_size;
|
select @@global.maria_log_file_size;
|
||||||
@@global.maria_log_file_size
|
@@global.maria_log_file_size
|
||||||
@ -61,32 +61,32 @@ insert into t1 select * from t2;
|
|||||||
set global maria_checkpoint_interval=30;
|
set global maria_checkpoint_interval=30;
|
||||||
SHOW ENGINE maria logs;
|
SHOW ENGINE maria logs;
|
||||||
Type Name Status
|
Type Name Status
|
||||||
maria master-data/maria_log.00000004 free
|
MARIA master-data/maria_log.00000004 free
|
||||||
maria master-data/maria_log.00000005 free
|
MARIA master-data/maria_log.00000005 free
|
||||||
maria master-data/maria_log.00000006 free
|
MARIA master-data/maria_log.00000006 free
|
||||||
maria master-data/maria_log.00000007 free
|
MARIA master-data/maria_log.00000007 free
|
||||||
maria master-data/maria_log.00000008 in use
|
MARIA master-data/maria_log.00000008 in use
|
||||||
flush logs;
|
flush logs;
|
||||||
SHOW ENGINE maria logs;
|
SHOW ENGINE maria logs;
|
||||||
Type Name Status
|
Type Name Status
|
||||||
maria master-data/maria_log.00000008 in use
|
MARIA master-data/maria_log.00000008 in use
|
||||||
set global maria_log_file_size=16777216;
|
set global maria_log_file_size=16777216;
|
||||||
set global maria_log_purge_type=external;
|
set global maria_log_purge_type=external;
|
||||||
insert into t1 select * from t2;
|
insert into t1 select * from t2;
|
||||||
set global maria_checkpoint_interval=30;
|
set global maria_checkpoint_interval=30;
|
||||||
SHOW ENGINE maria logs;
|
SHOW ENGINE maria logs;
|
||||||
Type Name Status
|
Type Name Status
|
||||||
maria master-data/maria_log.00000008 free
|
MARIA master-data/maria_log.00000008 free
|
||||||
maria master-data/maria_log.00000009 in use
|
MARIA master-data/maria_log.00000009 in use
|
||||||
flush logs;
|
flush logs;
|
||||||
SHOW ENGINE maria logs;
|
SHOW ENGINE maria logs;
|
||||||
Type Name Status
|
Type Name Status
|
||||||
maria master-data/maria_log.00000008 free
|
MARIA master-data/maria_log.00000008 free
|
||||||
maria master-data/maria_log.00000009 in use
|
MARIA master-data/maria_log.00000009 in use
|
||||||
set global maria_log_purge_type=immediate;
|
set global maria_log_purge_type=immediate;
|
||||||
insert into t1 select * from t2;
|
insert into t1 select * from t2;
|
||||||
set global maria_checkpoint_interval=30;
|
set global maria_checkpoint_interval=30;
|
||||||
SHOW ENGINE maria logs;
|
SHOW ENGINE maria logs;
|
||||||
Type Name Status
|
Type Name Status
|
||||||
maria master-data/maria_log.00000011 in use
|
MARIA master-data/maria_log.00000011 in use
|
||||||
drop table t1, t2;
|
drop table t1, t2;
|
||||||
|
35
mysql-test/r/maria-recover.result
Normal file
35
mysql-test/r/maria-recover.result
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
select @@global.maria_recover;
|
||||||
|
@@global.maria_recover
|
||||||
|
BACKUP
|
||||||
|
set global maria_recover=off;
|
||||||
|
select @@global.maria_recover;
|
||||||
|
@@global.maria_recover
|
||||||
|
OFF
|
||||||
|
set global maria_recover=default;
|
||||||
|
select @@global.maria_recover;
|
||||||
|
@@global.maria_recover
|
||||||
|
OFF
|
||||||
|
set global maria_recover=normal;
|
||||||
|
select @@global.maria_recover;
|
||||||
|
@@global.maria_recover
|
||||||
|
NORMAL
|
||||||
|
drop database if exists mysqltest;
|
||||||
|
create database mysqltest;
|
||||||
|
use mysqltest;
|
||||||
|
create table t1 (a varchar(1000), index(a)) engine=maria;
|
||||||
|
insert into t1 values("ThursdayMorningsMarket");
|
||||||
|
flush table t1;
|
||||||
|
insert into t1 select concat(a,'b') from t1 limit 1;
|
||||||
|
select * from t_corrupted2;
|
||||||
|
a
|
||||||
|
ThursdayMorningsMarket
|
||||||
|
Warnings:
|
||||||
|
Error 145 Table './mysqltest/t_corrupted2' is marked as crashed and should be repaired
|
||||||
|
Error 1194 Table 't_corrupted2' is marked as crashed and should be repaired
|
||||||
|
Error 1034 1 client is using or hasn't closed the table properly
|
||||||
|
Error 126 Incorrect key file for table './mysqltest/t_corrupted2.MAI'; try to repair it
|
||||||
|
Error 1034 Wrong base information on indexpage at page: 1
|
||||||
|
select * from t_corrupted2;
|
||||||
|
a
|
||||||
|
ThursdayMorningsMarket
|
||||||
|
drop database mysqltest;
|
@ -362,24 +362,24 @@ Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_par
|
|||||||
t1 1 a 1 a A 1 NULL NULL YES BTREE
|
t1 1 a 1 a A 1 NULL NULL YES BTREE
|
||||||
drop table t1;
|
drop table t1;
|
||||||
* TEST of recovery when OPTIMIZE has replaced the index file and crash
|
* TEST of recovery when OPTIMIZE has replaced the index file and crash
|
||||||
create table t1 (a varchar(100), key(a)) engine=maria;
|
create table t_corrupted1 (a varchar(100), key(a)) engine=maria;
|
||||||
insert into t1 select (rand()) from t2;
|
insert into t_corrupted1 select (rand()) from t2;
|
||||||
flush table t1;
|
flush table t_corrupted1;
|
||||||
* copied t1 for comparison
|
* copied t_corrupted1 for comparison
|
||||||
SET SESSION debug="+d,maria_flush_whole_log,maria_flush_whole_page_cache,maria_crash_sort_index";
|
SET SESSION debug="+d,maria_flush_whole_log,maria_flush_whole_page_cache,maria_crash_sort_index";
|
||||||
* crashing mysqld intentionally
|
* crashing mysqld intentionally
|
||||||
optimize table t1;
|
optimize table t_corrupted1;
|
||||||
ERROR HY000: Lost connection to MySQL server during query
|
ERROR HY000: Lost connection to MySQL server during query
|
||||||
* recovery happens
|
* recovery happens
|
||||||
check table t1 extended;
|
check table t_corrupted1 extended;
|
||||||
Table Op Msg_type Msg_text
|
Table Op Msg_type Msg_text
|
||||||
mysqltest.t1 check warning Table is marked as crashed and last repair failed
|
mysqltest.t_corrupted1 check warning Table is marked as crashed and last repair failed
|
||||||
mysqltest.t1 check status OK
|
mysqltest.t_corrupted1 check status OK
|
||||||
* testing that checksum after recovery is as expected
|
* testing that checksum after recovery is as expected
|
||||||
Checksum-check
|
Checksum-check
|
||||||
ok
|
ok
|
||||||
use mysqltest;
|
use mysqltest;
|
||||||
drop table t1, t2;
|
drop table t_corrupted1, t2;
|
||||||
drop database mysqltest_for_feeding_recovery;
|
drop database mysqltest_for_feeding_recovery;
|
||||||
drop database mysqltest_for_comparison;
|
drop database mysqltest_for_comparison;
|
||||||
drop database mysqltest;
|
drop database mysqltest;
|
||||||
|
@ -2121,6 +2121,7 @@ show variables like 'maria%';
|
|||||||
Variable_name Value
|
Variable_name Value
|
||||||
maria_block_size 8192
|
maria_block_size 8192
|
||||||
maria_checkpoint_interval 30
|
maria_checkpoint_interval 30
|
||||||
|
maria_force_start_after_recovery_failures 0
|
||||||
maria_log_file_size 4294959104
|
maria_log_file_size 4294959104
|
||||||
maria_log_purge_type immediate
|
maria_log_purge_type immediate
|
||||||
maria_max_sort_file_size 9223372036854775807
|
maria_max_sort_file_size 9223372036854775807
|
||||||
@ -2128,6 +2129,7 @@ maria_page_checksum OFF
|
|||||||
maria_pagecache_age_threshold 300
|
maria_pagecache_age_threshold 300
|
||||||
maria_pagecache_buffer_size 8388600
|
maria_pagecache_buffer_size 8388600
|
||||||
maria_pagecache_division_limit 100
|
maria_pagecache_division_limit 100
|
||||||
|
maria_recover OFF
|
||||||
maria_repair_threads 1
|
maria_repair_threads 1
|
||||||
maria_sort_buffer_size 8388608
|
maria_sort_buffer_size 8388608
|
||||||
maria_stats_method nulls_unequal
|
maria_stats_method nulls_unequal
|
||||||
|
@ -19,4 +19,4 @@ ctype_create : Bug#32965 main.ctype_create fails
|
|||||||
status : Bug#32966 main.status fails
|
status : Bug#32966 main.status fails
|
||||||
ps_ddl : Bug#12093 2007-12-14 pending WL#4165 / WL#4166
|
ps_ddl : Bug#12093 2007-12-14 pending WL#4165 / WL#4166
|
||||||
csv_alter_table : Bug#33696 2008-01-21 pcrews no .result file - bug allows NULL columns in CSV tables
|
csv_alter_table : Bug#33696 2008-01-21 pcrews no .result file - bug allows NULL columns in CSV tables
|
||||||
maria-preload : Bug#34911 unrepeatable output of SHOW STATUS
|
maria-preload : Bug#35107 crashes
|
||||||
|
@ -8,6 +8,11 @@
|
|||||||
drop table if exists t1, t2;
|
drop table if exists t1, t2;
|
||||||
--enable_warnings
|
--enable_warnings
|
||||||
|
|
||||||
|
# Work around BUG#34911 "FLUSH STATUS doesn't flush what it should":
|
||||||
|
# compute differences in status variables before and after relevant queries
|
||||||
|
create temporary table initial
|
||||||
|
select variable_name,variable_value from
|
||||||
|
information_schema.global_status where variable_name like "Maria_pagecache_read%";
|
||||||
|
|
||||||
# we don't use block-format because we want page cache stats
|
# we don't use block-format because we want page cache stats
|
||||||
# about indices and not data pages.
|
# about indices and not data pages.
|
||||||
@ -59,50 +64,50 @@ select count(*) from t1;
|
|||||||
select count(*) from t2;
|
select count(*) from t2;
|
||||||
|
|
||||||
flush tables; flush status;
|
flush tables; flush status;
|
||||||
show status like "maria_pagecache_read%";
|
let $show_stat=select g.variable_name,g.variable_value-i.variable_value from information_schema.global_status as g,initial as i where g.variable_name like "Maria_pagecache_read%" and g.variable_name=i.variable_name order by g.variable_name desc;
|
||||||
|
eval $show_stat;
|
||||||
select count(*) from t1 where b = 'test1';
|
select count(*) from t1 where b = 'test1';
|
||||||
show status like "maria_pagecache_read%";
|
eval $show_stat;
|
||||||
select count(*) from t1 where b = 'test1';
|
select count(*) from t1 where b = 'test1';
|
||||||
show status like "maria_pagecache_read%";
|
eval $show_stat;
|
||||||
|
|
||||||
flush tables; flush status;
|
flush tables; flush status;
|
||||||
select @@preload_buffer_size;
|
select @@preload_buffer_size;
|
||||||
load index into cache t1;
|
load index into cache t1;
|
||||||
show status like "maria_pagecache_read%";
|
eval $show_stat;
|
||||||
select count(*) from t1 where b = 'test1';
|
select count(*) from t1 where b = 'test1';
|
||||||
show status like "maria_pagecache_read%";
|
eval $show_stat;
|
||||||
|
|
||||||
flush tables; flush status;
|
flush tables; flush status;
|
||||||
show status like "maria_pagecache_read%";
|
eval $show_stat;
|
||||||
set session preload_buffer_size=256*1024;
|
set session preload_buffer_size=256*1024;
|
||||||
select @@preload_buffer_size;
|
select @@preload_buffer_size;
|
||||||
load index into cache t1 ignore leaves;
|
load index into cache t1 ignore leaves;
|
||||||
show status like "maria_pagecache_read%";
|
eval $show_stat;
|
||||||
select count(*) from t1 where b = 'test1';
|
select count(*) from t1 where b = 'test1';
|
||||||
show status like "maria_pagecache_read%";
|
eval $show_stat;
|
||||||
|
|
||||||
flush tables; flush status;
|
flush tables; flush status;
|
||||||
show status like "maria_pagecache_read%";
|
eval $show_stat;
|
||||||
set session preload_buffer_size=1*1024;
|
set session preload_buffer_size=1*1024;
|
||||||
select @@preload_buffer_size;
|
select @@preload_buffer_size;
|
||||||
load index into cache t1, t2 key (primary,b) ignore leaves;
|
load index into cache t1, t2 key (primary,b) ignore leaves;
|
||||||
show status like "maria_pagecache_read%";
|
eval $show_stat;
|
||||||
select count(*) from t1 where b = 'test1';
|
select count(*) from t1 where b = 'test1';
|
||||||
select count(*) from t2 where b = 'test1';
|
select count(*) from t2 where b = 'test1';
|
||||||
show status like "maria_pagecache_read%";
|
eval $show_stat;
|
||||||
|
|
||||||
flush tables; flush status;
|
flush tables; flush status;
|
||||||
show status like "maria_pagecache_read%";
|
eval $show_stat;
|
||||||
load index into cache t3, t2 key (primary,b) ;
|
load index into cache t3, t2 key (primary,b) ;
|
||||||
show status like "maria_pagecache_read%";
|
eval $show_stat;
|
||||||
|
|
||||||
flush tables; flush status;
|
flush tables; flush status;
|
||||||
show status like "maria_pagecache_read%";
|
eval $show_stat;
|
||||||
load index into cache t3 key (b), t2 key (c) ;
|
load index into cache t3 key (b), t2 key (c) ;
|
||||||
show status like "maria_pagecache_read%";
|
eval $show_stat;
|
||||||
|
|
||||||
drop table t1, t2;
|
drop table t1, t2;
|
||||||
|
drop temporary table initial;
|
||||||
|
|
||||||
# check that Maria didn't use key cache
|
# check that Maria didn't use key cache
|
||||||
show status like "key_read%";
|
show status like "key_read%";
|
||||||
|
1
mysql-test/t/maria-recover-master.opt
Normal file
1
mysql-test/t/maria-recover-master.opt
Normal file
@ -0,0 +1 @@
|
|||||||
|
--maria-recover=backup --maria-log-dir-path=../tmp
|
52
mysql-test/t/maria-recover.test
Normal file
52
mysql-test/t/maria-recover.test
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
# Test of the --maria-recover option.
|
||||||
|
|
||||||
|
--source include/have_maria.inc
|
||||||
|
|
||||||
|
select @@global.maria_recover;
|
||||||
|
set global maria_recover=off;
|
||||||
|
select @@global.maria_recover;
|
||||||
|
set global maria_recover=default;
|
||||||
|
select @@global.maria_recover;
|
||||||
|
set global maria_recover=normal;
|
||||||
|
select @@global.maria_recover;
|
||||||
|
|
||||||
|
--disable_warnings
|
||||||
|
drop database if exists mysqltest;
|
||||||
|
--enable_warnings
|
||||||
|
create database mysqltest;
|
||||||
|
|
||||||
|
use mysqltest;
|
||||||
|
|
||||||
|
create table t1 (a varchar(1000), index(a)) engine=maria;
|
||||||
|
insert into t1 values("ThursdayMorningsMarket");
|
||||||
|
|
||||||
|
flush table t1; # put index page on disk
|
||||||
|
insert into t1 select concat(a,'b') from t1 limit 1;
|
||||||
|
# now t1 has its open_count>0 and so will t2_corrupted.
|
||||||
|
# It is not named t2 because the corruption messages which will be put
|
||||||
|
# in the error log need to be detected in mtr_process.pl, and we want
|
||||||
|
# a specific name to do specific detection (don't want to ignore
|
||||||
|
# any corruption messages of other tests using "t2" as table).
|
||||||
|
|
||||||
|
copy_file $MYSQLTEST_VARDIR/master-data/mysqltest/t1.frm $MYSQLTEST_VARDIR/master-data/mysqltest/t_corrupted2.frm;
|
||||||
|
copy_file $MYSQLTEST_VARDIR/master-data/mysqltest/t1.MAD $MYSQLTEST_VARDIR/master-data/mysqltest/t_corrupted2.MAD;
|
||||||
|
copy_file $MYSQLTEST_VARDIR/master-data/mysqltest/t1.MAI $MYSQLTEST_VARDIR/master-data/mysqltest/t_corrupted2.MAI;
|
||||||
|
|
||||||
|
# Ruin the index file.
|
||||||
|
# If maria-block-size is smaller than the default, the corruption
|
||||||
|
# messages will differ.
|
||||||
|
perl;
|
||||||
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
my $fname= "$ENV{'MYSQLTEST_VARDIR'}/master-data/mysqltest/t_corrupted2.MAI";
|
||||||
|
open(FILE, "+<", $fname) or die;
|
||||||
|
my $whatever= ("\xAB" x 100);
|
||||||
|
sysseek (FILE, 8192, 0) or die;
|
||||||
|
syswrite (FILE, $whatever) or die;
|
||||||
|
close FILE;
|
||||||
|
EOF
|
||||||
|
|
||||||
|
select * from t_corrupted2; # should show corruption and repair messages
|
||||||
|
select * from t_corrupted2; # should show just rows
|
||||||
|
|
||||||
|
drop database mysqltest;
|
@ -15,6 +15,7 @@ set global maria_log_file_size=4294967295;
|
|||||||
drop database if exists mysqltest;
|
drop database if exists mysqltest;
|
||||||
--enable_warnings
|
--enable_warnings
|
||||||
create database mysqltest;
|
create database mysqltest;
|
||||||
|
let $mms_tname=t;
|
||||||
|
|
||||||
# Include scripts can perform SQL. For it to not influence the main test
|
# 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
|
# they use a separate connection. This way if they use a DDL it would
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
drop database if exists mysqltest;
|
drop database if exists mysqltest;
|
||||||
--enable_warnings
|
--enable_warnings
|
||||||
create database mysqltest;
|
create database mysqltest;
|
||||||
|
let $mms_tname=t;
|
||||||
|
|
||||||
# Include scripts can perform SQL. For it to not influence the main test
|
# 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
|
# they use a separate connection. This way if they use a DDL it would
|
||||||
|
@ -14,6 +14,7 @@ let $MARIA_LOG=.;
|
|||||||
drop database if exists mysqltest;
|
drop database if exists mysqltest;
|
||||||
--enable_warnings
|
--enable_warnings
|
||||||
create database mysqltest;
|
create database mysqltest;
|
||||||
|
let $mms_tname=t;
|
||||||
|
|
||||||
# Include scripts can perform SQL. For it to not influence the main test
|
# 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
|
# they use a separate connection. This way if they use a DDL it would
|
||||||
|
@ -12,6 +12,7 @@ let $MARIA_LOG=../tmp;
|
|||||||
drop database if exists mysqltest;
|
drop database if exists mysqltest;
|
||||||
--enable_warnings
|
--enable_warnings
|
||||||
create database mysqltest;
|
create database mysqltest;
|
||||||
|
let $mms_tname=t;
|
||||||
|
|
||||||
# Include scripts can perform SQL. For it to not influence the main test
|
# 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
|
# they use a separate connection. This way if they use a DDL it would
|
||||||
@ -297,19 +298,25 @@ show keys from t1; # should be enabled
|
|||||||
drop table t1;
|
drop table t1;
|
||||||
|
|
||||||
--echo * TEST of recovery when OPTIMIZE has replaced the index file and crash
|
--echo * TEST of recovery when OPTIMIZE has replaced the index file and crash
|
||||||
create table t1 (a varchar(100), key(a)) engine=maria;
|
create table t_corrupted1 (a varchar(100), key(a)) engine=maria;
|
||||||
|
# we use a special name because this test portion will generate
|
||||||
|
# corruption warnings, which we tell mtr_report.pl to ignore by
|
||||||
|
# putting the message in mtr_report.pl, but we don't want to it ignore
|
||||||
|
# corruption messages of other tests, hence the special name
|
||||||
|
# 't_corrupted' and not just 't'.
|
||||||
|
let $mms_tname=t_corrupted;
|
||||||
let $mvr_restore_old_snapshot=0;
|
let $mvr_restore_old_snapshot=0;
|
||||||
let $mms_compare_physically=0;
|
let $mms_compare_physically=0;
|
||||||
let $mvr_crash_statement= optimize table t1;
|
let $mvr_crash_statement= optimize table t_corrupted1;
|
||||||
let $mvr_debug_option="+d,maria_flush_whole_log,maria_flush_whole_page_cache,maria_crash_sort_index";
|
let $mvr_debug_option="+d,maria_flush_whole_log,maria_flush_whole_page_cache,maria_crash_sort_index";
|
||||||
insert into t1 select (rand()) from t2;
|
insert into t_corrupted1 select (rand()) from t2;
|
||||||
-- source include/maria_make_snapshot_for_comparison.inc
|
-- source include/maria_make_snapshot_for_comparison.inc
|
||||||
# Recovery will not fix the table, but we expect to see it marked
|
# Recovery will not fix the table, but we expect to see it marked
|
||||||
# "crashed on repair".
|
# "crashed on repair".
|
||||||
# Because crash is mild, the table is actually not corrupted, so the
|
# Because crash is mild, the table is actually not corrupted, so the
|
||||||
# "check table extended" done below fixes the table.
|
# "check table extended" done below fixes the table.
|
||||||
-- source include/maria_verify_recovery.inc
|
-- source include/maria_verify_recovery.inc
|
||||||
drop table t1, t2;
|
drop table t_corrupted1, t2;
|
||||||
|
|
||||||
# clean up everything
|
# clean up everything
|
||||||
let $mms_purpose=feeding_recovery;
|
let $mms_purpose=feeding_recovery;
|
||||||
|
@ -49,13 +49,11 @@ ulong pagecache_division_limit, pagecache_age_threshold;
|
|||||||
ulonglong pagecache_buffer_size;
|
ulonglong pagecache_buffer_size;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@todo For now there is no way for a user to set a different value of
|
As the auto-repair is initiated when opened from the SQL layer
|
||||||
maria_recover_options, i.e. auto-check-and-repair is always disabled.
|
(open_unireg_entry(), check_and_repair()), it does not happen when Maria's
|
||||||
We could enable it. As the auto-repair is initiated when opened from the
|
Recovery internally opens the table to apply log records to it, which is
|
||||||
SQL layer (open_unireg_entry(), check_and_repair()), it does not happen
|
good. It would happen only after Recovery, if the table is still
|
||||||
when Maria's Recovery internally opens the table to apply log records to
|
corrupted.
|
||||||
it, which is good. It would happen only after Recovery, if the table is
|
|
||||||
still corrupted.
|
|
||||||
*/
|
*/
|
||||||
ulong maria_recover_options= HA_RECOVER_NONE;
|
ulong maria_recover_options= HA_RECOVER_NONE;
|
||||||
handlerton *maria_hton;
|
handlerton *maria_hton;
|
||||||
@ -63,7 +61,14 @@ handlerton *maria_hton;
|
|||||||
/* bits in maria_recover_options */
|
/* bits in maria_recover_options */
|
||||||
const char *maria_recover_names[]=
|
const char *maria_recover_names[]=
|
||||||
{
|
{
|
||||||
"DEFAULT", "BACKUP", "FORCE", "QUICK", NullS
|
/*
|
||||||
|
Compared to MyISAM, "default" was renamed to "normal" as it collided with
|
||||||
|
SET var=default which sets to the var's default i.e. what happens when the
|
||||||
|
var is not set i.e. HA_RECOVER_NONE.
|
||||||
|
Another change is that OFF is used to disable, not ""; this is to have OFF
|
||||||
|
display in SHOW VARIABLES which is better than "".
|
||||||
|
*/
|
||||||
|
"OFF", "NORMAL", "BACKUP", "FORCE", "QUICK", NullS
|
||||||
};
|
};
|
||||||
TYPELIB maria_recover_typelib=
|
TYPELIB maria_recover_typelib=
|
||||||
{
|
{
|
||||||
@ -103,11 +108,13 @@ TYPELIB maria_sync_log_dir_typelib=
|
|||||||
maria_sync_log_dir_names, NULL
|
maria_sync_log_dir_names, NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
/** @brief Interval between background checkpoints in seconds */
|
/** Interval between background checkpoints in seconds */
|
||||||
static ulong checkpoint_interval;
|
static ulong checkpoint_interval;
|
||||||
static void update_checkpoint_interval(MYSQL_THD thd,
|
static void update_checkpoint_interval(MYSQL_THD thd,
|
||||||
struct st_mysql_sys_var *var,
|
struct st_mysql_sys_var *var,
|
||||||
void *var_ptr, const void *save);
|
void *var_ptr, const void *save);
|
||||||
|
/** After that many consecutive recovery failures, remove logs */
|
||||||
|
static ulong force_start_after_recovery_failures;
|
||||||
static void update_log_file_size(MYSQL_THD thd,
|
static void update_log_file_size(MYSQL_THD thd,
|
||||||
struct st_mysql_sys_var *var,
|
struct st_mysql_sys_var *var,
|
||||||
void *var_ptr, const void *save);
|
void *var_ptr, const void *save);
|
||||||
@ -124,6 +131,17 @@ static MYSQL_SYSVAR_ULONG(checkpoint_interval, checkpoint_interval,
|
|||||||
" 'no automatic checkpoints' which makes sense only for testing.",
|
" 'no automatic checkpoints' which makes sense only for testing.",
|
||||||
NULL, update_checkpoint_interval, 30, 0, UINT_MAX, 1);
|
NULL, update_checkpoint_interval, 30, 0, UINT_MAX, 1);
|
||||||
|
|
||||||
|
static MYSQL_SYSVAR_ULONG(force_start_after_recovery_failures,
|
||||||
|
force_start_after_recovery_failures,
|
||||||
|
/*
|
||||||
|
Read-only because setting it on the fly has no useful effect,
|
||||||
|
should be set on command-line.
|
||||||
|
*/
|
||||||
|
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
|
||||||
|
"Number of consecutive log recovery failures after which logs will be"
|
||||||
|
" automatically deleted to cure the problem; 0 (the default) disables"
|
||||||
|
" the feature.", NULL, NULL, 0, 0, UINT_MAX8, 1);
|
||||||
|
|
||||||
static MYSQL_SYSVAR_BOOL(page_checksum, maria_page_checksums, 0,
|
static MYSQL_SYSVAR_BOOL(page_checksum, maria_page_checksums, 0,
|
||||||
"Maintain page checksums (can be overridden per table "
|
"Maintain page checksums (can be overridden per table "
|
||||||
"with PAGE_CHECKSUM clause in CREATE TABLE)", 0, 0, 1);
|
"with PAGE_CHECKSUM clause in CREATE TABLE)", 0, 0, 1);
|
||||||
@ -175,6 +193,12 @@ static MYSQL_SYSVAR_ULONG(pagecache_division_limit, pagecache_division_limit,
|
|||||||
"The minimum percentage of warm blocks in key cache", 0, 0,
|
"The minimum percentage of warm blocks in key cache", 0, 0,
|
||||||
100, 1, 100, 1);
|
100, 1, 100, 1);
|
||||||
|
|
||||||
|
static MYSQL_SYSVAR_ENUM(recover, maria_recover_options, PLUGIN_VAR_OPCMDARG,
|
||||||
|
"Specifies how corrupted tables should be automatically repaired."
|
||||||
|
" Possible values are \"NORMAL\" (the default), \"BACKUP\", \"FORCE\","
|
||||||
|
" \"QUICK\", or \"OFF\" which is like not using the option.",
|
||||||
|
NULL, NULL, HA_RECOVER_NONE, &maria_recover_typelib);
|
||||||
|
|
||||||
static MYSQL_THDVAR_ULONG(repair_threads, PLUGIN_VAR_RQCMDARG,
|
static MYSQL_THDVAR_ULONG(repair_threads, PLUGIN_VAR_RQCMDARG,
|
||||||
"Number of threads to use when repairing maria tables. The value of 1 "
|
"Number of threads to use when repairing maria tables. The value of 1 "
|
||||||
"disables parallel repair.",
|
"disables parallel repair.",
|
||||||
@ -186,7 +210,7 @@ static MYSQL_THDVAR_ULONG(sort_buffer_size, PLUGIN_VAR_RQCMDARG,
|
|||||||
0, 0, 8192*1024, 4, ~0L, 1);
|
0, 0, 8192*1024, 4, ~0L, 1);
|
||||||
|
|
||||||
static MYSQL_THDVAR_ENUM(stats_method, PLUGIN_VAR_RQCMDARG,
|
static MYSQL_THDVAR_ENUM(stats_method, PLUGIN_VAR_RQCMDARG,
|
||||||
"Specifies how maria index statistics collection code should threat "
|
"Specifies how maria index statistics collection code should treat "
|
||||||
"NULLs. Possible values are \"nulls_unequal\", \"nulls_equal\", "
|
"NULLs. Possible values are \"nulls_unequal\", \"nulls_equal\", "
|
||||||
"and \"nulls_ignored\".", 0, 0, 0, &maria_stats_method_typelib);
|
"and \"nulls_ignored\".", 0, 0, 0, &maria_stats_method_typelib);
|
||||||
|
|
||||||
@ -870,6 +894,12 @@ int ha_maria::open(const char *name, int mode, uint test_if_locked)
|
|||||||
test_if_locked|= HA_OPEN_MMAP;
|
test_if_locked|= HA_OPEN_MMAP;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
if (unlikely(maria_recover_options != HA_RECOVER_NONE))
|
||||||
|
{
|
||||||
|
/* user asked to trigger a repair if table was not properly closed */
|
||||||
|
test_if_locked|= HA_OPEN_ABORT_IF_CRASHED;
|
||||||
|
}
|
||||||
|
|
||||||
if (!(file= maria_open(name, mode, test_if_locked | HA_OPEN_FROM_SQL_LAYER)))
|
if (!(file= maria_open(name, mode, test_if_locked | HA_OPEN_FROM_SQL_LAYER)))
|
||||||
return (my_errno ? my_errno : -1);
|
return (my_errno ? my_errno : -1);
|
||||||
|
|
||||||
@ -2728,7 +2758,7 @@ bool maria_show_status(handlerton *hton,
|
|||||||
stat_print_fn *print,
|
stat_print_fn *print,
|
||||||
enum ha_stat_type stat)
|
enum ha_stat_type stat)
|
||||||
{
|
{
|
||||||
char engine_name[]= "maria";
|
const LEX_STRING *engine_name= hton_name(hton);
|
||||||
switch (stat) {
|
switch (stat) {
|
||||||
case HA_ENGINE_LOGS:
|
case HA_ENGINE_LOGS:
|
||||||
{
|
{
|
||||||
@ -2745,8 +2775,8 @@ bool maria_show_status(handlerton *hton,
|
|||||||
if (first_file == 0)
|
if (first_file == 0)
|
||||||
{
|
{
|
||||||
const char error[]= "error";
|
const char error[]= "error";
|
||||||
print(thd, engine_name, sizeof(engine_name),
|
print(thd, engine_name->str, engine_name->length,
|
||||||
STRING_WITH_LEN(""), error, sizeof(error));
|
STRING_WITH_LEN(""), error, sizeof(error) - 1);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2762,7 +2792,7 @@ bool maria_show_status(handlerton *hton,
|
|||||||
if (!(stat= my_stat(file, &stat_buff, MYF(MY_WME))))
|
if (!(stat= my_stat(file, &stat_buff, MYF(MY_WME))))
|
||||||
{
|
{
|
||||||
status= error;
|
status= error;
|
||||||
status_len= sizeof(error);
|
status_len= sizeof(error) - 1;
|
||||||
length= my_snprintf(object, SHOW_MSG_LEN, "Size unknown ; %s", file);
|
length= my_snprintf(object, SHOW_MSG_LEN, "Size unknown ; %s", file);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -2770,23 +2800,23 @@ bool maria_show_status(handlerton *hton,
|
|||||||
if (first_needed == 0)
|
if (first_needed == 0)
|
||||||
{
|
{
|
||||||
status= unknown;
|
status= unknown;
|
||||||
status_len= sizeof(unknown);
|
status_len= sizeof(unknown) - 1;
|
||||||
}
|
}
|
||||||
else if (i < first_needed)
|
else if (i < first_needed)
|
||||||
{
|
{
|
||||||
status= unneeded;
|
status= unneeded;
|
||||||
status_len= sizeof(unneeded);
|
status_len= sizeof(unneeded) - 1;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
status= needed;
|
status= needed;
|
||||||
status_len= sizeof(needed);
|
status_len= sizeof(needed) - 1;
|
||||||
}
|
}
|
||||||
length= my_snprintf(object, SHOW_MSG_LEN, "Size %12lu ; %s",
|
length= my_snprintf(object, SHOW_MSG_LEN, "Size %12lu ; %s",
|
||||||
(ulong) stat->st_size, file);
|
(ulong) stat->st_size, file);
|
||||||
}
|
}
|
||||||
|
|
||||||
print(thd, engine_name, sizeof(engine_name),
|
print(thd, engine_name->str, engine_name->length,
|
||||||
object, length, status, status_len);
|
object, length, status, status_len);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -2799,9 +2829,90 @@ bool maria_show_status(handlerton *hton,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
Callback to delete all logs in directory. This is lower-level than other
|
||||||
|
functions in ma_loghandler.c which delete logs, as it does not rely on
|
||||||
|
translog_init() having been called first.
|
||||||
|
|
||||||
|
@param directory directory where file is
|
||||||
|
@param filename base name of the file to delete
|
||||||
|
*/
|
||||||
|
|
||||||
|
static my_bool translog_callback_delete_all(const char *directory,
|
||||||
|
const char *filename)
|
||||||
|
{
|
||||||
|
char complete_name[FN_REFLEN];
|
||||||
|
fn_format(complete_name, filename, directory, "", MYF(MY_UNPACK_FILENAME));
|
||||||
|
return my_delete(complete_name, MYF(MY_WME));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
Helper function for option maria-force-start-after-recovery-failures.
|
||||||
|
Deletes logs if too many failures. Otherwise, increments the counter of
|
||||||
|
failures in the control file.
|
||||||
|
Notice how this has to be called _before_ translog_init() (if log is
|
||||||
|
corrupted, translog_init() might crash the server, so we need to remove logs
|
||||||
|
before).
|
||||||
|
|
||||||
|
@param log_dir directory where logs to be deleted are
|
||||||
|
*/
|
||||||
|
|
||||||
|
static int mark_recovery_start(const char* log_dir)
|
||||||
|
{
|
||||||
|
int res;
|
||||||
|
DBUG_ENTER("mark_recovery_start");
|
||||||
|
if (unlikely(maria_recover_options == HA_RECOVER_NONE))
|
||||||
|
ma_message_no_user(ME_JUST_WARNING, "Please consider using option"
|
||||||
|
" --maria-recover[=...] to automatically check and"
|
||||||
|
" repair tables when logs are removed by option"
|
||||||
|
" --maria-force-start-after-recovery-failures=#");
|
||||||
|
if (recovery_failures >= force_start_after_recovery_failures)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
Remove logs which cause the problem; keep control file which has
|
||||||
|
critical info like uuid, max_trid (removing control file may make
|
||||||
|
correct tables look corrupted!).
|
||||||
|
*/
|
||||||
|
char msg[100];
|
||||||
|
res= translog_walk_filenames(log_dir, &translog_callback_delete_all);
|
||||||
|
my_snprintf(msg, sizeof(msg),
|
||||||
|
"%s logs after %u consecutive failures of"
|
||||||
|
" recovery from logs",
|
||||||
|
(res ? "failed to remove some" : "removed all"),
|
||||||
|
recovery_failures);
|
||||||
|
ma_message_no_user((res ? 0 : ME_JUST_WARNING), msg);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
res= ma_control_file_write_and_force(last_checkpoint_lsn, last_logno,
|
||||||
|
max_trid_in_control_file,
|
||||||
|
recovery_failures + 1);
|
||||||
|
DBUG_RETURN(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
Helper function for option maria-force-start-after-recovery-failures.
|
||||||
|
Records in the control file that recovery was a success, so that it's not
|
||||||
|
counted for maria-force-start-after-recovery-failures.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static int mark_recovery_success(void)
|
||||||
|
{
|
||||||
|
/* success of recovery, reset recovery_failures: */
|
||||||
|
int res;
|
||||||
|
DBUG_ENTER("mark_recovery_success");
|
||||||
|
res= ma_control_file_write_and_force(last_checkpoint_lsn, last_logno,
|
||||||
|
max_trid_in_control_file, 0);
|
||||||
|
DBUG_RETURN(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static int ha_maria_init(void *p)
|
static int ha_maria_init(void *p)
|
||||||
{
|
{
|
||||||
int res;
|
int res;
|
||||||
|
const char *log_dir= maria_data_root;
|
||||||
maria_hton= (handlerton *)p;
|
maria_hton= (handlerton *)p;
|
||||||
maria_hton->state= SHOW_OPTION_YES;
|
maria_hton->state= SHOW_OPTION_YES;
|
||||||
maria_hton->db_type= DB_TYPE_UNKNOWN;
|
maria_hton->db_type= DB_TYPE_UNKNOWN;
|
||||||
@ -2816,6 +2927,8 @@ static int ha_maria_init(void *p)
|
|||||||
bzero(maria_log_pagecache, sizeof(*maria_log_pagecache));
|
bzero(maria_log_pagecache, sizeof(*maria_log_pagecache));
|
||||||
maria_tmpdir= &mysql_tmpdir_list; /* For REDO */
|
maria_tmpdir= &mysql_tmpdir_list; /* For REDO */
|
||||||
res= maria_init() || ma_control_file_open(TRUE, TRUE) ||
|
res= maria_init() || ma_control_file_open(TRUE, TRUE) ||
|
||||||
|
((force_start_after_recovery_failures != 0) &&
|
||||||
|
mark_recovery_start(log_dir)) ||
|
||||||
!init_pagecache(maria_pagecache,
|
!init_pagecache(maria_pagecache,
|
||||||
(size_t) pagecache_buffer_size, pagecache_division_limit,
|
(size_t) pagecache_buffer_size, pagecache_division_limit,
|
||||||
pagecache_age_threshold, maria_block_size, 0) ||
|
pagecache_age_threshold, maria_block_size, 0) ||
|
||||||
@ -2825,7 +2938,8 @@ static int ha_maria_init(void *p)
|
|||||||
translog_init(maria_data_root, log_file_size,
|
translog_init(maria_data_root, log_file_size,
|
||||||
MYSQL_VERSION_ID, server_id, maria_log_pagecache,
|
MYSQL_VERSION_ID, server_id, maria_log_pagecache,
|
||||||
TRANSLOG_DEFAULT_FLAGS, 0) ||
|
TRANSLOG_DEFAULT_FLAGS, 0) ||
|
||||||
maria_recover() ||
|
maria_recovery_from_log() ||
|
||||||
|
((force_start_after_recovery_failures != 0) && mark_recovery_success()) ||
|
||||||
ma_checkpoint_init(checkpoint_interval);
|
ma_checkpoint_init(checkpoint_interval);
|
||||||
maria_multi_threaded= TRUE;
|
maria_multi_threaded= TRUE;
|
||||||
return res ? HA_ERR_INITIALIZATION : 0;
|
return res ? HA_ERR_INITIALIZATION : 0;
|
||||||
@ -2913,6 +3027,7 @@ my_bool ha_maria::register_query_cache_table(THD *thd, char *table_name,
|
|||||||
static struct st_mysql_sys_var* system_variables[]= {
|
static struct st_mysql_sys_var* system_variables[]= {
|
||||||
MYSQL_SYSVAR(block_size),
|
MYSQL_SYSVAR(block_size),
|
||||||
MYSQL_SYSVAR(checkpoint_interval),
|
MYSQL_SYSVAR(checkpoint_interval),
|
||||||
|
MYSQL_SYSVAR(force_start_after_recovery_failures),
|
||||||
MYSQL_SYSVAR(page_checksum),
|
MYSQL_SYSVAR(page_checksum),
|
||||||
MYSQL_SYSVAR(log_dir_path),
|
MYSQL_SYSVAR(log_dir_path),
|
||||||
MYSQL_SYSVAR(log_file_size),
|
MYSQL_SYSVAR(log_file_size),
|
||||||
@ -2921,6 +3036,7 @@ static struct st_mysql_sys_var* system_variables[]= {
|
|||||||
MYSQL_SYSVAR(pagecache_age_threshold),
|
MYSQL_SYSVAR(pagecache_age_threshold),
|
||||||
MYSQL_SYSVAR(pagecache_buffer_size),
|
MYSQL_SYSVAR(pagecache_buffer_size),
|
||||||
MYSQL_SYSVAR(pagecache_division_limit),
|
MYSQL_SYSVAR(pagecache_division_limit),
|
||||||
|
MYSQL_SYSVAR(recover),
|
||||||
MYSQL_SYSVAR(repair_threads),
|
MYSQL_SYSVAR(repair_threads),
|
||||||
MYSQL_SYSVAR(sort_buffer_size),
|
MYSQL_SYSVAR(sort_buffer_size),
|
||||||
MYSQL_SYSVAR(stats_method),
|
MYSQL_SYSVAR(stats_method),
|
||||||
|
@ -245,7 +245,8 @@ static int really_execute_checkpoint(void)
|
|||||||
that log was flushed before we write to the control file).
|
that log was flushed before we write to the control file).
|
||||||
*/
|
*/
|
||||||
if (unlikely(ma_control_file_write_and_force(lsn, last_logno,
|
if (unlikely(ma_control_file_write_and_force(lsn, last_logno,
|
||||||
max_trid_in_control_file)))
|
max_trid_in_control_file,
|
||||||
|
recovery_failures)))
|
||||||
{
|
{
|
||||||
translog_unlock();
|
translog_unlock();
|
||||||
goto err;
|
goto err;
|
||||||
|
@ -39,6 +39,8 @@ Start of changeable part:
|
|||||||
- Checksum of changeable part
|
- Checksum of changeable part
|
||||||
- LSN of last checkpoint
|
- LSN of last checkpoint
|
||||||
- Number of last log file
|
- Number of last log file
|
||||||
|
- Max trid in control file (since Maria 1.5 May 2008)
|
||||||
|
- Number of consecutive recovery failures (since Maria 1.5 May 2008)
|
||||||
..... Here we can add new variables without changing format
|
..... Here we can add new variables without changing format
|
||||||
|
|
||||||
The idea is that one can add new variables to the control file and still
|
The idea is that one can add new variables to the control file and still
|
||||||
@ -80,7 +82,9 @@ one should increment the control file version number.
|
|||||||
#define CF_FILENO_SIZE 4
|
#define CF_FILENO_SIZE 4
|
||||||
#define CF_MAX_TRID_OFFSET (CF_FILENO_OFFSET + CF_FILENO_SIZE)
|
#define CF_MAX_TRID_OFFSET (CF_FILENO_OFFSET + CF_FILENO_SIZE)
|
||||||
#define CF_MAX_TRID_SIZE TRANSID_SIZE
|
#define CF_MAX_TRID_SIZE TRANSID_SIZE
|
||||||
#define CF_CHANGEABLE_TOTAL_SIZE (CF_MAX_TRID_OFFSET + CF_MAX_TRID_SIZE)
|
#define CF_RECOV_FAIL_OFFSET (CF_MAX_TRID_OFFSET + CF_MAX_TRID_SIZE)
|
||||||
|
#define CF_RECOV_FAIL_SIZE 1
|
||||||
|
#define CF_CHANGEABLE_TOTAL_SIZE (CF_RECOV_FAIL_OFFSET + CF_RECOV_FAIL_SIZE)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
The following values should not be changed, except when changing version
|
The following values should not be changed, except when changing version
|
||||||
@ -108,6 +112,12 @@ uint32 last_logno= FILENO_IMPOSSIBLE;
|
|||||||
*/
|
*/
|
||||||
TrID max_trid_in_control_file= 0;
|
TrID max_trid_in_control_file= 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
Number of consecutive log or recovery failures. Reset to 0 after recovery's
|
||||||
|
success.
|
||||||
|
*/
|
||||||
|
uint8 recovery_failures= 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@brief If log's lock should be asserted when writing to control file.
|
@brief If log's lock should be asserted when writing to control file.
|
||||||
|
|
||||||
@ -188,7 +198,7 @@ static CONTROL_FILE_ERROR create_control_file(const char *name,
|
|||||||
|
|
||||||
/* init the file with these "undefined" values */
|
/* init the file with these "undefined" values */
|
||||||
DBUG_RETURN(ma_control_file_write_and_force(LSN_IMPOSSIBLE,
|
DBUG_RETURN(ma_control_file_write_and_force(LSN_IMPOSSIBLE,
|
||||||
FILENO_IMPOSSIBLE, 0));
|
FILENO_IMPOSSIBLE, 0, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -420,6 +430,9 @@ CONTROL_FILE_ERROR ma_control_file_open(my_bool create_if_missing,
|
|||||||
if (new_cf_changeable_size >= (CF_MAX_TRID_OFFSET + CF_MAX_TRID_SIZE))
|
if (new_cf_changeable_size >= (CF_MAX_TRID_OFFSET + CF_MAX_TRID_SIZE))
|
||||||
max_trid_in_control_file=
|
max_trid_in_control_file=
|
||||||
transid_korr(buffer + new_cf_create_time_size + CF_MAX_TRID_OFFSET);
|
transid_korr(buffer + new_cf_create_time_size + CF_MAX_TRID_OFFSET);
|
||||||
|
if (new_cf_changeable_size >= (CF_RECOV_FAIL_OFFSET + CF_RECOV_FAIL_SIZE))
|
||||||
|
recovery_failures=
|
||||||
|
(buffer + new_cf_create_time_size + CF_RECOV_FAIL_OFFSET)[0];
|
||||||
|
|
||||||
ok:
|
ok:
|
||||||
DBUG_RETURN(0);
|
DBUG_RETURN(0);
|
||||||
@ -436,19 +449,21 @@ err:
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
Write information durably to the control file; stores this information into
|
Write information durably to the control file; stores this information into
|
||||||
the last_checkpoint_lsn, last_logno, max_trid_in_control_file global
|
the last_checkpoint_lsn, last_logno, max_trid_in_control_file,
|
||||||
variables.
|
recovery_failures global variables.
|
||||||
Called when we have created a new log (after syncing this log's creation),
|
Called when we have created a new log (after syncing this log's creation),
|
||||||
when we have written a checkpoint (after syncing this log record), and at
|
when we have written a checkpoint (after syncing this log record), at
|
||||||
shutdown (for storing trid in case logs are soon removed by user).
|
shutdown (for storing trid in case logs are soon removed by user), and
|
||||||
|
before and after recovery (to store recovery_failures).
|
||||||
Variables last_checkpoint_lsn and last_logno must be protected by caller
|
Variables last_checkpoint_lsn and last_logno must be protected by caller
|
||||||
using log's lock, unless this function is called at startup.
|
using log's lock, unless this function is called at startup.
|
||||||
|
|
||||||
SYNOPSIS
|
SYNOPSIS
|
||||||
ma_control_file_write_and_force()
|
ma_control_file_write_and_force()
|
||||||
checkpoint_lsn LSN of last checkpoint
|
last_checkpoint_lsn_arg LSN of last checkpoint
|
||||||
logno last log file number
|
last_logno_arg last log file number
|
||||||
trid maximum transaction longid.
|
max_trid_arg maximum transaction longid
|
||||||
|
recovery_failures_arg consecutive recovery failures
|
||||||
|
|
||||||
NOTE
|
NOTE
|
||||||
We always want to do one single my_pwrite() here to be as atomic as
|
We always want to do one single my_pwrite() here to be as atomic as
|
||||||
@ -459,17 +474,26 @@ err:
|
|||||||
1 - Error
|
1 - Error
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int ma_control_file_write_and_force(LSN checkpoint_lsn, uint32 logno,
|
int ma_control_file_write_and_force(LSN last_checkpoint_lsn_arg,
|
||||||
TrID trid)
|
uint32 last_logno_arg,
|
||||||
|
TrID max_trid_arg,
|
||||||
|
uint8 recovery_failures_arg)
|
||||||
{
|
{
|
||||||
uchar buffer[CF_MAX_SIZE];
|
uchar buffer[CF_MAX_SIZE];
|
||||||
uint32 sum;
|
uint32 sum;
|
||||||
|
my_bool no_need_sync;
|
||||||
DBUG_ENTER("ma_control_file_write_and_force");
|
DBUG_ENTER("ma_control_file_write_and_force");
|
||||||
|
|
||||||
if ((last_checkpoint_lsn == checkpoint_lsn) &&
|
/*
|
||||||
(last_logno == logno) &&
|
We don't need to sync if this is just an increase of
|
||||||
(max_trid_in_control_file == trid))
|
recovery_failures: it's even good if that counter is not increased on disk
|
||||||
DBUG_RETURN(0); /* no need to write */
|
in case of power or hardware failure (less false positives when removing
|
||||||
|
logs).
|
||||||
|
*/
|
||||||
|
no_need_sync= ((last_checkpoint_lsn == last_checkpoint_lsn_arg) &&
|
||||||
|
(last_logno == last_logno_arg) &&
|
||||||
|
(max_trid_in_control_file == max_trid_arg) &&
|
||||||
|
(recovery_failures_arg > 0));
|
||||||
|
|
||||||
if (control_file_fd < 0)
|
if (control_file_fd < 0)
|
||||||
DBUG_RETURN(1);
|
DBUG_RETURN(1);
|
||||||
@ -479,9 +503,10 @@ int ma_control_file_write_and_force(LSN checkpoint_lsn, uint32 logno,
|
|||||||
translog_lock_handler_assert_owner();
|
translog_lock_handler_assert_owner();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
lsn_store(buffer + CF_LSN_OFFSET, checkpoint_lsn);
|
lsn_store(buffer + CF_LSN_OFFSET, last_checkpoint_lsn_arg);
|
||||||
int4store(buffer + CF_FILENO_OFFSET, logno);
|
int4store(buffer + CF_FILENO_OFFSET, last_logno_arg);
|
||||||
transid_store(buffer + CF_MAX_TRID_OFFSET, trid);
|
transid_store(buffer + CF_MAX_TRID_OFFSET, max_trid_arg);
|
||||||
|
(buffer + CF_RECOV_FAIL_OFFSET)[0]= recovery_failures_arg;
|
||||||
|
|
||||||
if (cf_changeable_size > CF_CHANGEABLE_TOTAL_SIZE)
|
if (cf_changeable_size > CF_CHANGEABLE_TOTAL_SIZE)
|
||||||
{
|
{
|
||||||
@ -514,12 +539,13 @@ int ma_control_file_write_and_force(LSN checkpoint_lsn, uint32 logno,
|
|||||||
|
|
||||||
if (my_pwrite(control_file_fd, buffer, cf_changeable_size,
|
if (my_pwrite(control_file_fd, buffer, cf_changeable_size,
|
||||||
cf_create_time_size, MYF(MY_FNABP | MY_WME)) ||
|
cf_create_time_size, MYF(MY_FNABP | MY_WME)) ||
|
||||||
my_sync(control_file_fd, MYF(MY_WME)))
|
(!no_need_sync && my_sync(control_file_fd, MYF(MY_WME))))
|
||||||
DBUG_RETURN(1);
|
DBUG_RETURN(1);
|
||||||
|
|
||||||
last_checkpoint_lsn= checkpoint_lsn;
|
last_checkpoint_lsn= last_checkpoint_lsn_arg;
|
||||||
last_logno= logno;
|
last_logno= last_logno_arg;
|
||||||
max_trid_in_control_file= trid;
|
max_trid_in_control_file= max_trid_arg;
|
||||||
|
recovery_failures= recovery_failures_arg;
|
||||||
|
|
||||||
cf_changeable_size= CF_CHANGEABLE_TOTAL_SIZE; /* no more warning */
|
cf_changeable_size= CF_CHANGEABLE_TOTAL_SIZE; /* no more warning */
|
||||||
DBUG_RETURN(0);
|
DBUG_RETURN(0);
|
||||||
@ -558,7 +584,7 @@ int ma_control_file_end(void)
|
|||||||
*/
|
*/
|
||||||
last_checkpoint_lsn= LSN_IMPOSSIBLE;
|
last_checkpoint_lsn= LSN_IMPOSSIBLE;
|
||||||
last_logno= FILENO_IMPOSSIBLE;
|
last_logno= FILENO_IMPOSSIBLE;
|
||||||
max_trid_in_control_file= 0;
|
max_trid_in_control_file= recovery_failures= 0;
|
||||||
|
|
||||||
DBUG_RETURN(close_error);
|
DBUG_RETURN(close_error);
|
||||||
}
|
}
|
||||||
|
@ -44,6 +44,8 @@ extern uint32 last_logno;
|
|||||||
|
|
||||||
extern TrID max_trid_in_control_file;
|
extern TrID max_trid_in_control_file;
|
||||||
|
|
||||||
|
extern uint8 recovery_failures;
|
||||||
|
|
||||||
extern my_bool maria_multi_threaded, maria_in_recovery;
|
extern my_bool maria_multi_threaded, maria_in_recovery;
|
||||||
|
|
||||||
typedef enum enum_control_file_error {
|
typedef enum enum_control_file_error {
|
||||||
@ -63,7 +65,9 @@ typedef enum enum_control_file_error {
|
|||||||
C_MODE_START
|
C_MODE_START
|
||||||
CONTROL_FILE_ERROR ma_control_file_open(my_bool create_if_missing,
|
CONTROL_FILE_ERROR ma_control_file_open(my_bool create_if_missing,
|
||||||
my_bool print_error);
|
my_bool print_error);
|
||||||
int ma_control_file_write_and_force(LSN checkpoint_lsn, uint32 logno, TrID trid);
|
int ma_control_file_write_and_force(LSN last_checkpoint_lsn_arg,
|
||||||
|
uint32 last_logno_arg, TrID max_trid_arg,
|
||||||
|
uint8 recovery_failures_arg);
|
||||||
int ma_control_file_end(void);
|
int ma_control_file_end(void);
|
||||||
my_bool ma_control_file_inited(void);
|
my_bool ma_control_file_inited(void);
|
||||||
C_MODE_END
|
C_MODE_END
|
||||||
|
@ -86,7 +86,7 @@ void maria_end(void)
|
|||||||
from the log, as it cannot process REDOs).
|
from the log, as it cannot process REDOs).
|
||||||
*/
|
*/
|
||||||
(void)ma_control_file_write_and_force(last_checkpoint_lsn, last_logno,
|
(void)ma_control_file_write_and_force(last_checkpoint_lsn, last_logno,
|
||||||
trid);
|
trid, recovery_failures);
|
||||||
}
|
}
|
||||||
trnman_destroy();
|
trnman_destroy();
|
||||||
if (translog_status == TRANSLOG_OK)
|
if (translog_status == TRANSLOG_OK)
|
||||||
|
@ -381,7 +381,7 @@ int _ma_test_if_changed(register MARIA_HA *info)
|
|||||||
tells us if the MARIA file wasn't properly closed. (This is true if
|
tells us if the MARIA file wasn't properly closed. (This is true if
|
||||||
my_disable_locking is set).
|
my_disable_locking is set).
|
||||||
|
|
||||||
open_count is not maintained on disk for transactional or temporary tables.
|
open_count is not maintained on disk for temporary tables.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int _ma_mark_file_changed(MARIA_HA *info)
|
int _ma_mark_file_changed(MARIA_HA *info)
|
||||||
@ -400,11 +400,16 @@ int _ma_mark_file_changed(MARIA_HA *info)
|
|||||||
share->state.open_count++;
|
share->state.open_count++;
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
temp tables don't need an open_count as they are removed on crash;
|
Temp tables don't need an open_count as they are removed on crash.
|
||||||
transactional tables are fixed by log-based recovery, so don't need an
|
In theory transactional tables are fixed by log-based recovery, so don't
|
||||||
open_count either (and we thus avoid the disk write below).
|
need an open_count either, but if recovery has failed and logs have been
|
||||||
|
removed (by maria-force-start-after-recovery-failures), we still need to
|
||||||
|
detect dubious tables.
|
||||||
|
If we didn't maintain open_count on disk for a table, after a crash
|
||||||
|
we wouldn't know if it was closed at crash time (thus does not need a
|
||||||
|
check) or not. So we would have to check all tables: overkill.
|
||||||
*/
|
*/
|
||||||
if (!(share->temporary | share->base.born_transactional))
|
if (!share->temporary)
|
||||||
{
|
{
|
||||||
mi_int2store(buff,share->state.open_count);
|
mi_int2store(buff,share->state.open_count);
|
||||||
buff[2]=1; /* Mark that it's changed */
|
buff[2]=1; /* Mark that it's changed */
|
||||||
@ -471,7 +476,7 @@ int _ma_decrement_open_count(MARIA_HA *info)
|
|||||||
{
|
{
|
||||||
share->state.open_count--;
|
share->state.open_count--;
|
||||||
share->changed= 1; /* We have to update state */
|
share->changed= 1; /* We have to update state */
|
||||||
if (!(share->temporary | share->base.born_transactional))
|
if (!share->temporary)
|
||||||
{
|
{
|
||||||
mi_int2store(buff,share->state.open_count);
|
mi_int2store(buff,share->state.open_count);
|
||||||
write_error= (int) my_pwrite(share->kfile.file, buff, sizeof(buff),
|
write_error= (int) my_pwrite(share->kfile.file, buff, sizeof(buff),
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
#include "trnman.h"
|
#include "trnman.h"
|
||||||
#include "ma_blockrec.h" /* for some constants and in-write hooks */
|
#include "ma_blockrec.h" /* for some constants and in-write hooks */
|
||||||
#include "ma_key_recover.h" /* For some in-write hooks */
|
#include "ma_key_recover.h" /* For some in-write hooks */
|
||||||
|
#include "ma_checkpoint.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
On Windows, neither my_open() nor my_sync() work for directories.
|
On Windows, neither my_open() nor my_sync() work for directories.
|
||||||
@ -1522,7 +1523,8 @@ static my_bool translog_create_new_file()
|
|||||||
DBUG_RETURN(1);
|
DBUG_RETURN(1);
|
||||||
|
|
||||||
if (ma_control_file_write_and_force(last_checkpoint_lsn, file_no,
|
if (ma_control_file_write_and_force(last_checkpoint_lsn, file_no,
|
||||||
max_trid_in_control_file))
|
max_trid_in_control_file,
|
||||||
|
recovery_failures))
|
||||||
{
|
{
|
||||||
translog_stop_writing();
|
translog_stop_writing();
|
||||||
DBUG_RETURN(1);
|
DBUG_RETURN(1);
|
||||||
@ -3211,21 +3213,29 @@ static my_bool translog_truncate_log(TRANSLOG_ADDRESS addr)
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@brief Check log files presence
|
Applies function 'callback' to all files (in a directory) which
|
||||||
|
name looks like a log's name (maria_log.[0-9]{7}).
|
||||||
|
If 'callback' returns TRUE this interrupts the walk and returns
|
||||||
|
TRUE. Otherwise FALSE is returned after processing all log files.
|
||||||
|
It cannot just use log_descriptor.directory because that may not yet have
|
||||||
|
been initialized.
|
||||||
|
|
||||||
@retval 0 no log files.
|
@param directory directory to scan
|
||||||
@retval 1 there is at least 1 log file in the directory
|
@param callback function to apply; is passed directory and base
|
||||||
|
name of found file
|
||||||
*/
|
*/
|
||||||
|
|
||||||
my_bool translog_is_log_files()
|
my_bool translog_walk_filenames(const char *directory,
|
||||||
|
my_bool (*callback)(const char *,
|
||||||
|
const char *))
|
||||||
{
|
{
|
||||||
MY_DIR *dirp;
|
MY_DIR *dirp;
|
||||||
uint i;
|
uint i;
|
||||||
my_bool rc= FALSE;
|
my_bool rc= FALSE;
|
||||||
|
|
||||||
/* Finds and removes transaction log files */
|
/* Finds and removes transaction log files */
|
||||||
if (!(dirp = my_dir(log_descriptor.directory, MYF(MY_DONT_SORT))))
|
if (!(dirp = my_dir(directory, MYF(MY_DONT_SORT))))
|
||||||
return 1;
|
return FALSE;
|
||||||
|
|
||||||
for (i= 0; i < dirp->number_off_files; i++)
|
for (i= 0; i < dirp->number_off_files; i++)
|
||||||
{
|
{
|
||||||
@ -3239,14 +3249,14 @@ my_bool translog_is_log_files()
|
|||||||
file[15] >= '0' && file[15] <= '9' &&
|
file[15] >= '0' && file[15] <= '9' &&
|
||||||
file[16] >= '0' && file[16] <= '9' &&
|
file[16] >= '0' && file[16] <= '9' &&
|
||||||
file[17] >= '0' && file[17] <= '9' &&
|
file[17] >= '0' && file[17] <= '9' &&
|
||||||
file[18] == '\0')
|
file[18] == '\0' && (*callback)(directory, file))
|
||||||
{
|
{
|
||||||
rc= TRUE;
|
rc= TRUE;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
my_dirend(dirp);
|
my_dirend(dirp);
|
||||||
return FALSE;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -3269,6 +3279,19 @@ static void translog_fill_overhead_table()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
Callback to find first log in directory.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static my_bool translog_callback_search_first(const char *directory
|
||||||
|
__attribute__((unused)),
|
||||||
|
const char *filename
|
||||||
|
__attribute__((unused)))
|
||||||
|
{
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@brief Checks that chunk is LSN one
|
@brief Checks that chunk is LSN one
|
||||||
|
|
||||||
@ -3353,7 +3376,7 @@ my_bool translog_init_with_table(const char *directory,
|
|||||||
my_init_dynamic_array(&log_descriptor.unfinished_files,
|
my_init_dynamic_array(&log_descriptor.unfinished_files,
|
||||||
sizeof(struct st_file_counter),
|
sizeof(struct st_file_counter),
|
||||||
10, 10))
|
10, 10))
|
||||||
DBUG_RETURN(1);
|
goto err;
|
||||||
log_descriptor.min_need_file= 0;
|
log_descriptor.min_need_file= 0;
|
||||||
log_descriptor.min_file_number= 0;
|
log_descriptor.min_file_number= 0;
|
||||||
log_descriptor.last_lsn_checked= LSN_IMPOSSIBLE;
|
log_descriptor.last_lsn_checked= LSN_IMPOSSIBLE;
|
||||||
@ -3367,7 +3390,7 @@ my_bool translog_init_with_table(const char *directory,
|
|||||||
my_errno= errno;
|
my_errno= errno;
|
||||||
DBUG_PRINT("error", ("Error %d during opening directory '%s'",
|
DBUG_PRINT("error", ("Error %d during opening directory '%s'",
|
||||||
errno, log_descriptor.directory));
|
errno, log_descriptor.directory));
|
||||||
DBUG_RETURN(1);
|
goto err;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
log_descriptor.in_buffers_only= LSN_IMPOSSIBLE;
|
log_descriptor.in_buffers_only= LSN_IMPOSSIBLE;
|
||||||
@ -3417,7 +3440,7 @@ my_bool translog_init_with_table(const char *directory,
|
|||||||
for (i= 0; i < TRANSLOG_BUFFERS_NO; i++)
|
for (i= 0; i < TRANSLOG_BUFFERS_NO; i++)
|
||||||
{
|
{
|
||||||
if (translog_buffer_init(log_descriptor.buffers + i))
|
if (translog_buffer_init(log_descriptor.buffers + i))
|
||||||
DBUG_RETURN(1);
|
goto err;
|
||||||
#ifndef DBUG_OFF
|
#ifndef DBUG_OFF
|
||||||
log_descriptor.buffers[i].buffer_no= (uint8) i;
|
log_descriptor.buffers[i].buffer_no= (uint8) i;
|
||||||
#endif
|
#endif
|
||||||
@ -3461,7 +3484,8 @@ my_bool translog_init_with_table(const char *directory,
|
|||||||
log_descriptor.horizon= last_page= MAKE_LSN(last_logno, 0);
|
log_descriptor.horizon= last_page= MAKE_LSN(last_logno, 0);
|
||||||
if (translog_get_last_page_addr(&last_page, &pageok, no_errors))
|
if (translog_get_last_page_addr(&last_page, &pageok, no_errors))
|
||||||
{
|
{
|
||||||
if (!translog_is_log_files())
|
if (!translog_walk_filenames(log_descriptor.directory,
|
||||||
|
&translog_callback_search_first))
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
Files was deleted, just start from the next log number, so that
|
Files was deleted, just start from the next log number, so that
|
||||||
@ -3472,7 +3496,7 @@ my_bool translog_init_with_table(const char *directory,
|
|||||||
logs_found= 0;
|
logs_found= 0;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
DBUG_RETURN(1);
|
goto err;
|
||||||
}
|
}
|
||||||
else if (LSN_OFFSET(last_page) == 0)
|
else if (LSN_OFFSET(last_page) == 0)
|
||||||
{
|
{
|
||||||
@ -3485,7 +3509,7 @@ my_bool translog_init_with_table(const char *directory,
|
|||||||
{
|
{
|
||||||
last_page-= LSN_ONE_FILE;
|
last_page-= LSN_ONE_FILE;
|
||||||
if (translog_get_last_page_addr(&last_page, &pageok, 0))
|
if (translog_get_last_page_addr(&last_page, &pageok, 0))
|
||||||
DBUG_RETURN(1);
|
goto err;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (logs_found)
|
if (logs_found)
|
||||||
@ -3497,7 +3521,7 @@ my_bool translog_init_with_table(const char *directory,
|
|||||||
if (allocate_dynamic(&log_descriptor.open_files,
|
if (allocate_dynamic(&log_descriptor.open_files,
|
||||||
log_descriptor.max_file -
|
log_descriptor.max_file -
|
||||||
log_descriptor.min_file + 1))
|
log_descriptor.min_file + 1))
|
||||||
DBUG_RETURN(1);
|
goto err;
|
||||||
for (i = log_descriptor.max_file; i >= log_descriptor.min_file; i--)
|
for (i = log_descriptor.max_file; i >= log_descriptor.min_file; i--)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
@ -3526,10 +3550,10 @@ my_bool translog_init_with_table(const char *directory,
|
|||||||
if (file)
|
if (file)
|
||||||
{
|
{
|
||||||
free(file);
|
free(file);
|
||||||
DBUG_RETURN(1);
|
goto err;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
DBUG_RETURN(1);
|
goto err;
|
||||||
}
|
}
|
||||||
translog_file_init(file, i, 1);
|
translog_file_init(file, i, 1);
|
||||||
/* we allocated space so it can't fail */
|
/* we allocated space so it can't fail */
|
||||||
@ -3543,7 +3567,7 @@ my_bool translog_init_with_table(const char *directory,
|
|||||||
{
|
{
|
||||||
/* There is no logs and there is read-only mode => nothing to read */
|
/* There is no logs and there is read-only mode => nothing to read */
|
||||||
DBUG_PRINT("error", ("No logs and read-only mode"));
|
DBUG_PRINT("error", ("No logs and read-only mode"));
|
||||||
DBUG_RETURN(1);
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (logs_found)
|
if (logs_found)
|
||||||
@ -3568,7 +3592,7 @@ my_bool translog_init_with_table(const char *directory,
|
|||||||
TRANSLOG_ADDRESS current_file_last_page;
|
TRANSLOG_ADDRESS current_file_last_page;
|
||||||
current_file_last_page= current_page;
|
current_file_last_page= current_page;
|
||||||
if (translog_get_last_page_addr(¤t_file_last_page, &pageok, 0))
|
if (translog_get_last_page_addr(¤t_file_last_page, &pageok, 0))
|
||||||
DBUG_RETURN(1);
|
goto err;
|
||||||
if (!pageok)
|
if (!pageok)
|
||||||
{
|
{
|
||||||
DBUG_PRINT("error", ("File %lu have no complete last page",
|
DBUG_PRINT("error", ("File %lu have no complete last page",
|
||||||
@ -3585,7 +3609,7 @@ my_bool translog_init_with_table(const char *directory,
|
|||||||
uchar *page;
|
uchar *page;
|
||||||
data.addr= ¤t_page;
|
data.addr= ¤t_page;
|
||||||
if ((page= translog_get_page(&data, psize_buff.buffer, NULL)) == NULL)
|
if ((page= translog_get_page(&data, psize_buff.buffer, NULL)) == NULL)
|
||||||
DBUG_RETURN(1);
|
goto err;
|
||||||
if (data.was_recovered)
|
if (data.was_recovered)
|
||||||
{
|
{
|
||||||
DBUG_PRINT("error", ("file no: %lu (%d) "
|
DBUG_PRINT("error", ("file no: %lu (%d) "
|
||||||
@ -3614,7 +3638,7 @@ my_bool translog_init_with_table(const char *directory,
|
|||||||
{
|
{
|
||||||
/* Panic!!! Even page which should be valid is invalid */
|
/* Panic!!! Even page which should be valid is invalid */
|
||||||
/* TODO: issue error */
|
/* TODO: issue error */
|
||||||
DBUG_RETURN(1);
|
goto err;
|
||||||
}
|
}
|
||||||
DBUG_PRINT("info", ("Last valid page is in file: %lu "
|
DBUG_PRINT("info", ("Last valid page is in file: %lu "
|
||||||
"offset: %lu (0x%lx) "
|
"offset: %lu (0x%lx) "
|
||||||
@ -3639,7 +3663,7 @@ my_bool translog_init_with_table(const char *directory,
|
|||||||
LSN_FILE_NO(log_descriptor.horizon));
|
LSN_FILE_NO(log_descriptor.horizon));
|
||||||
if ((page= translog_get_page(&data, psize_buff.buffer, NULL)) == NULL ||
|
if ((page= translog_get_page(&data, psize_buff.buffer, NULL)) == NULL ||
|
||||||
(chunk_offset= translog_get_first_chunk_offset(page)) == 0)
|
(chunk_offset= translog_get_first_chunk_offset(page)) == 0)
|
||||||
DBUG_RETURN(1);
|
goto err;
|
||||||
|
|
||||||
/* Puts filled part of old page in the buffer */
|
/* Puts filled part of old page in the buffer */
|
||||||
log_descriptor.horizon= last_valid_page;
|
log_descriptor.horizon= last_valid_page;
|
||||||
@ -3654,7 +3678,7 @@ my_bool translog_init_with_table(const char *directory,
|
|||||||
uint16 chunk_length;
|
uint16 chunk_length;
|
||||||
if ((chunk_length=
|
if ((chunk_length=
|
||||||
translog_get_total_chunk_length(page, chunk_offset)) == 0)
|
translog_get_total_chunk_length(page, chunk_offset)) == 0)
|
||||||
DBUG_RETURN(1);
|
goto err;
|
||||||
DBUG_PRINT("info", ("chunk: offset: %u length: %u",
|
DBUG_PRINT("info", ("chunk: offset: %u length: %u",
|
||||||
(uint) chunk_offset, (uint) chunk_length));
|
(uint) chunk_offset, (uint) chunk_length));
|
||||||
chunk_offset+= chunk_length;
|
chunk_offset+= chunk_length;
|
||||||
@ -3690,7 +3714,7 @@ my_bool translog_init_with_table(const char *directory,
|
|||||||
open_files,
|
open_files,
|
||||||
0, TRANSLOG_FILE **))->
|
0, TRANSLOG_FILE **))->
|
||||||
handler.file))
|
handler.file))
|
||||||
DBUG_RETURN(1);
|
goto err;
|
||||||
version_changed= (info.maria_version != TRANSLOG_VERSION_ID);
|
version_changed= (info.maria_version != TRANSLOG_VERSION_ID);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3702,25 +3726,26 @@ my_bool translog_init_with_table(const char *directory,
|
|||||||
MYF(0));
|
MYF(0));
|
||||||
DBUG_PRINT("info", ("The log is not found => we will create new log"));
|
DBUG_PRINT("info", ("The log is not found => we will create new log"));
|
||||||
if (file == NULL)
|
if (file == NULL)
|
||||||
DBUG_RETURN(1);
|
goto err;
|
||||||
/* Start new log system from scratch */
|
/* Start new log system from scratch */
|
||||||
log_descriptor.horizon= MAKE_LSN(start_file_num,
|
log_descriptor.horizon= MAKE_LSN(start_file_num,
|
||||||
TRANSLOG_PAGE_SIZE); /* header page */
|
TRANSLOG_PAGE_SIZE); /* header page */
|
||||||
if ((file->handler.file=
|
if ((file->handler.file=
|
||||||
create_logfile_by_number_no_cache(start_file_num)) == -1)
|
create_logfile_by_number_no_cache(start_file_num)) == -1)
|
||||||
DBUG_RETURN(1);
|
goto err;
|
||||||
translog_file_init(file, start_file_num, 0);
|
translog_file_init(file, start_file_num, 0);
|
||||||
if (insert_dynamic(&log_descriptor.open_files, (uchar*)&file))
|
if (insert_dynamic(&log_descriptor.open_files, (uchar*)&file))
|
||||||
DBUG_RETURN(1);
|
goto err;
|
||||||
log_descriptor.min_file= log_descriptor.max_file= start_file_num;
|
log_descriptor.min_file= log_descriptor.max_file= start_file_num;
|
||||||
if (translog_write_file_header())
|
if (translog_write_file_header())
|
||||||
DBUG_RETURN(1);
|
goto err;
|
||||||
DBUG_ASSERT(log_descriptor.max_file - log_descriptor.min_file + 1 ==
|
DBUG_ASSERT(log_descriptor.max_file - log_descriptor.min_file + 1 ==
|
||||||
log_descriptor.open_files.elements);
|
log_descriptor.open_files.elements);
|
||||||
|
|
||||||
if (ma_control_file_write_and_force(checkpoint_lsn, start_file_num,
|
if (ma_control_file_write_and_force(checkpoint_lsn, start_file_num,
|
||||||
max_trid_in_control_file))
|
max_trid_in_control_file,
|
||||||
DBUG_RETURN(1);
|
recovery_failures))
|
||||||
|
goto err;
|
||||||
/* assign buffer 0 */
|
/* assign buffer 0 */
|
||||||
translog_start_buffer(log_descriptor.buffers, &log_descriptor.bc, 0);
|
translog_start_buffer(log_descriptor.buffers, &log_descriptor.bc, 0);
|
||||||
translog_new_page_header(&log_descriptor.horizon, &log_descriptor.bc);
|
translog_new_page_header(&log_descriptor.horizon, &log_descriptor.bc);
|
||||||
@ -3734,7 +3759,7 @@ my_bool translog_init_with_table(const char *directory,
|
|||||||
log_descriptor.horizon= LSN_REPLACE_OFFSET(log_descriptor.horizon,
|
log_descriptor.horizon= LSN_REPLACE_OFFSET(log_descriptor.horizon,
|
||||||
TRANSLOG_PAGE_SIZE);
|
TRANSLOG_PAGE_SIZE);
|
||||||
if (translog_create_new_file())
|
if (translog_create_new_file())
|
||||||
DBUG_RETURN(1);
|
goto err;
|
||||||
/*
|
/*
|
||||||
Buffer system left untouched after recovery => we should init it
|
Buffer system left untouched after recovery => we should init it
|
||||||
(starting from buffer 0)
|
(starting from buffer 0)
|
||||||
@ -3767,7 +3792,7 @@ my_bool translog_init_with_table(const char *directory,
|
|||||||
id_to_share= (MARIA_SHARE **) my_malloc(SHARE_ID_MAX * sizeof(MARIA_SHARE*),
|
id_to_share= (MARIA_SHARE **) my_malloc(SHARE_ID_MAX * sizeof(MARIA_SHARE*),
|
||||||
MYF(MY_WME | MY_ZEROFILL));
|
MYF(MY_WME | MY_ZEROFILL));
|
||||||
if (unlikely(!id_to_share))
|
if (unlikely(!id_to_share))
|
||||||
DBUG_RETURN(1);
|
goto err;
|
||||||
id_to_share--; /* min id is 1 */
|
id_to_share--; /* min id is 1 */
|
||||||
|
|
||||||
/* Check the last LSN record integrity */
|
/* Check the last LSN record integrity */
|
||||||
@ -3783,7 +3808,7 @@ my_bool translog_init_with_table(const char *directory,
|
|||||||
page_addr= (log_descriptor.horizon -
|
page_addr= (log_descriptor.horizon -
|
||||||
((log_descriptor.horizon - 1) % TRANSLOG_PAGE_SIZE + 1));
|
((log_descriptor.horizon - 1) % TRANSLOG_PAGE_SIZE + 1));
|
||||||
if (translog_scanner_init(page_addr, 1, &scanner, 1))
|
if (translog_scanner_init(page_addr, 1, &scanner, 1))
|
||||||
DBUG_RETURN(1);
|
goto err;
|
||||||
scanner.page_offset= page_overhead[scanner.page[TRANSLOG_PAGE_FLAGS]];
|
scanner.page_offset= page_overhead[scanner.page[TRANSLOG_PAGE_FLAGS]];
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
@ -3797,7 +3822,7 @@ my_bool translog_init_with_table(const char *directory,
|
|||||||
if (translog_get_next_chunk(&scanner))
|
if (translog_get_next_chunk(&scanner))
|
||||||
{
|
{
|
||||||
translog_destroy_scanner(&scanner);
|
translog_destroy_scanner(&scanner);
|
||||||
DBUG_RETURN(1);
|
goto err;
|
||||||
}
|
}
|
||||||
if (scanner.page != END_OF_LOG)
|
if (scanner.page != END_OF_LOG)
|
||||||
chunk_1byte= scanner.page[scanner.page_offset];
|
chunk_1byte= scanner.page[scanner.page_offset];
|
||||||
@ -3808,7 +3833,7 @@ my_bool translog_init_with_table(const char *directory,
|
|||||||
if (translog_get_next_chunk(&scanner))
|
if (translog_get_next_chunk(&scanner))
|
||||||
{
|
{
|
||||||
translog_destroy_scanner(&scanner);
|
translog_destroy_scanner(&scanner);
|
||||||
DBUG_RETURN(1);
|
goto err;
|
||||||
}
|
}
|
||||||
if (scanner.page == END_OF_LOG)
|
if (scanner.page == END_OF_LOG)
|
||||||
break; /* it was the last record */
|
break; /* it was the last record */
|
||||||
@ -3845,7 +3870,7 @@ my_bool translog_init_with_table(const char *directory,
|
|||||||
}
|
}
|
||||||
translog_destroy_scanner(&scanner);
|
translog_destroy_scanner(&scanner);
|
||||||
if (translog_scanner_init(page_addr, 1, &scanner, 1))
|
if (translog_scanner_init(page_addr, 1, &scanner, 1))
|
||||||
DBUG_RETURN(1);
|
goto err;
|
||||||
scanner.page_offset= page_overhead[scanner.page[TRANSLOG_PAGE_FLAGS]];
|
scanner.page_offset= page_overhead[scanner.page[TRANSLOG_PAGE_FLAGS]];
|
||||||
}
|
}
|
||||||
translog_destroy_scanner(&scanner);
|
translog_destroy_scanner(&scanner);
|
||||||
@ -3872,7 +3897,7 @@ my_bool translog_init_with_table(const char *directory,
|
|||||||
else if (translog_truncate_log(last_lsn))
|
else if (translog_truncate_log(last_lsn))
|
||||||
{
|
{
|
||||||
translog_free_record_header(&rec);
|
translog_free_record_header(&rec);
|
||||||
DBUG_RETURN(1);
|
goto err;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -3898,7 +3923,7 @@ my_bool translog_init_with_table(const char *directory,
|
|||||||
else if (translog_truncate_log(last_lsn))
|
else if (translog_truncate_log(last_lsn))
|
||||||
{
|
{
|
||||||
translog_free_record_header(&rec);
|
translog_free_record_header(&rec);
|
||||||
DBUG_RETURN(1);
|
goto err;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3907,6 +3932,9 @@ my_bool translog_init_with_table(const char *directory,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
DBUG_RETURN(0);
|
DBUG_RETURN(0);
|
||||||
|
err:
|
||||||
|
ma_message_no_user(0, "log initialization failed");
|
||||||
|
DBUG_RETURN(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -317,6 +317,10 @@ extern void translog_deassign_id_from_share(struct st_maria_share *share);
|
|||||||
extern void
|
extern void
|
||||||
translog_assign_id_to_share_from_recovery(struct st_maria_share *share,
|
translog_assign_id_to_share_from_recovery(struct st_maria_share *share,
|
||||||
uint16 id);
|
uint16 id);
|
||||||
|
extern my_bool translog_walk_filenames(const char *directory,
|
||||||
|
my_bool (*callback)(const char *,
|
||||||
|
const char *));
|
||||||
|
|
||||||
enum enum_translog_status
|
enum enum_translog_status
|
||||||
{
|
{
|
||||||
TRANSLOG_UNINITED, /* no initialization done or error during initialization */
|
TRANSLOG_UNINITED, /* no initialization done or error during initialization */
|
||||||
|
@ -191,12 +191,12 @@ static void print_preamble()
|
|||||||
@retval !=0 Error
|
@retval !=0 Error
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int maria_recover(void)
|
int maria_recovery_from_log(void)
|
||||||
{
|
{
|
||||||
int res= 1;
|
int res= 1;
|
||||||
FILE *trace_file;
|
FILE *trace_file;
|
||||||
uint warnings_count;
|
uint warnings_count;
|
||||||
DBUG_ENTER("maria_recover");
|
DBUG_ENTER("maria_recovery_from_log");
|
||||||
|
|
||||||
DBUG_ASSERT(!maria_in_recovery);
|
DBUG_ASSERT(!maria_in_recovery);
|
||||||
maria_in_recovery= TRUE;
|
maria_in_recovery= TRUE;
|
||||||
@ -462,7 +462,12 @@ end:
|
|||||||
"Maria recovery failed. Please run maria_chk -r on all maria "
|
"Maria recovery failed. Please run maria_chk -r on all maria "
|
||||||
"tables and delete all maria_log.######## files", MYF(0));
|
"tables and delete all maria_log.######## files", MYF(0));
|
||||||
procent_printed= 0;
|
procent_printed= 0;
|
||||||
/* we don't cleanly close tables if we hit some error (may corrupt them) */
|
/*
|
||||||
|
We don't cleanly close tables if we hit some error (may corrupt them by
|
||||||
|
flushing some wrong blocks made from wrong REDOs). It also leaves their
|
||||||
|
open_count>0, which ensures that --maria-recover, if used, will try to
|
||||||
|
repair them.
|
||||||
|
*/
|
||||||
DBUG_RETURN(error);
|
DBUG_RETURN(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1224,6 +1229,12 @@ static int new_table(uint16 sid, const char *name, LSN lsn_of_file_id)
|
|||||||
" maria_chk -r", share->open_file_name);
|
" maria_chk -r", share->open_file_name);
|
||||||
error= -1; /* not fatal, try with other tables */
|
error= -1; /* not fatal, try with other tables */
|
||||||
goto end;
|
goto end;
|
||||||
|
/*
|
||||||
|
Note that if a first recovery fails to apply a REDO, it marks the table
|
||||||
|
corrupted and stops the entire recovery. A second recovery will find the
|
||||||
|
table is marked corrupted and skip it (and thus possibly handle other
|
||||||
|
tables).
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
/* don't log any records for this work */
|
/* don't log any records for this work */
|
||||||
_ma_tmp_disable_logging_for_table(info, FALSE);
|
_ma_tmp_disable_logging_for_table(info, FALSE);
|
||||||
|
@ -25,7 +25,7 @@
|
|||||||
C_MODE_START
|
C_MODE_START
|
||||||
enum maria_apply_log_way
|
enum maria_apply_log_way
|
||||||
{ MARIA_LOG_APPLY, MARIA_LOG_DISPLAY_HEADER, MARIA_LOG_CHECK };
|
{ MARIA_LOG_APPLY, MARIA_LOG_DISPLAY_HEADER, MARIA_LOG_CHECK };
|
||||||
int maria_recover(void);
|
int maria_recovery_from_log(void);
|
||||||
int maria_apply_log(LSN lsn, enum maria_apply_log_way apply,
|
int maria_apply_log(LSN lsn, enum maria_apply_log_way apply,
|
||||||
FILE *trace_file,
|
FILE *trace_file,
|
||||||
my_bool execute_undo_phase, my_bool skip_DDLs,
|
my_bool execute_undo_phase, my_bool skip_DDLs,
|
||||||
|
179
storage/maria/ma_test_force_start.pl
Executable file
179
storage/maria/ma_test_force_start.pl
Executable file
@ -0,0 +1,179 @@
|
|||||||
|
#!/usr/bin/env perl
|
||||||
|
|
||||||
|
|
||||||
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
|
||||||
|
my $usage= <<EOF;
|
||||||
|
This program tests that the options
|
||||||
|
--maria-force-start-after-recovery-failures --maria-recover work as
|
||||||
|
expected.
|
||||||
|
It has to be run from directory mysql-test, and works with non-debug
|
||||||
|
and debug binaries.
|
||||||
|
Pass it option -d or -i (to test corruption of data or index file).
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# -d currently exhibits BUG#36578
|
||||||
|
# "Maria: maria-recover may fail to autorepair a table"
|
||||||
|
|
||||||
|
die($usage) if (@ARGV == 0);
|
||||||
|
|
||||||
|
my $corrupt_index;
|
||||||
|
|
||||||
|
if ($ARGV[0] eq '-d')
|
||||||
|
{
|
||||||
|
$corrupt_index= 0;
|
||||||
|
}
|
||||||
|
elsif ($ARGV[0] eq '-i')
|
||||||
|
{
|
||||||
|
$corrupt_index= 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
die($usage);
|
||||||
|
}
|
||||||
|
|
||||||
|
my $force_after= 3;
|
||||||
|
my $corrupt_file= $corrupt_index ? "MAI" : "MAD";
|
||||||
|
my $corrupt_message=
|
||||||
|
"\\[ERROR\\] mysqld: Table '.\/test\/t1' is marked as crashed and should be repaired";
|
||||||
|
|
||||||
|
my $sql_name= "./var/tmp/create_table.sql";
|
||||||
|
my $error_log_name= "./var/log/master.err";
|
||||||
|
my @cmd_output;
|
||||||
|
my $whatever; # garbage data
|
||||||
|
my $base_server_cmd= "perl mysql-test-run.pl --mem --mysqld=--maria-force-start-after-recovery-failures=$force_after maria-recover";
|
||||||
|
my $server_cmd;
|
||||||
|
my $client_cmd= "../client/mysql -u root -S var/tmp/master.sock test < $sql_name";
|
||||||
|
my $server_pid_name="./var/run/master.pid";
|
||||||
|
my $server_pid;
|
||||||
|
my $i; # count of server restarts
|
||||||
|
sub kill_server;
|
||||||
|
|
||||||
|
print "starting mysqld\n";
|
||||||
|
$server_cmd= $base_server_cmd . " --start-and-exit 2>&1";
|
||||||
|
@cmd_output=`$server_cmd`;
|
||||||
|
die if $?;
|
||||||
|
|
||||||
|
open(FILE, ">", $sql_name) or die;
|
||||||
|
|
||||||
|
# To exhibit BUG#36578 with -d, we don't create an index if -d. This is
|
||||||
|
# because the presence of an index will cause repair-by-sort to be used,
|
||||||
|
# where sort_get_next_record() is only called inside
|
||||||
|
#_ma_create_index_by_sort(), so the latter function fails and in this
|
||||||
|
# case retry_repair is set, so bug does not happen. Whereas without
|
||||||
|
# an index, repair-with-key-cache is called, which calls
|
||||||
|
# sort_get_next_record() whose failure itself does not cause a retry.
|
||||||
|
|
||||||
|
print FILE "create table t1 (a varchar(1000)".
|
||||||
|
($corrupt_index ? ", index(a)" : "") .") engine=maria;\n";
|
||||||
|
print FILE <<EOF;
|
||||||
|
insert into t1 values("ThursdayMorningsMarket");
|
||||||
|
# If Recovery executes REDO_INDEX_NEW_PAGE it will overwrite our
|
||||||
|
# intentional corruption; we make Recovery skip this record by bumping
|
||||||
|
# create_rename_lsn using OPTIMIZE TABLE. This also makes sure to put
|
||||||
|
# the pages on disk, so that we can corrupt them.
|
||||||
|
optimize table t1;
|
||||||
|
# mark table open, so that --maria-recover repairs it
|
||||||
|
insert into t1 select concat(a,'b') from t1 limit 1;
|
||||||
|
EOF
|
||||||
|
close FILE;
|
||||||
|
|
||||||
|
print "creating table\n";
|
||||||
|
`$client_cmd`;
|
||||||
|
die if $?;
|
||||||
|
|
||||||
|
print "killing mysqld hard\n";
|
||||||
|
kill_server(9);
|
||||||
|
|
||||||
|
print "ruining " .
|
||||||
|
($corrupt_index ? "first page of keys" : "bitmap page") .
|
||||||
|
" in table to test maria-recover\n";
|
||||||
|
open(FILE, "+<", "./var/master-data/test/t1.$corrupt_file") or die;
|
||||||
|
$whatever= ("\xAB" x 100);
|
||||||
|
sysseek (FILE, $corrupt_index ? 8192 : (8192-100-100), 0) or die;
|
||||||
|
syswrite (FILE, $whatever) or die;
|
||||||
|
close FILE;
|
||||||
|
|
||||||
|
print "ruining log to make recovery fail; mysqld should fail the $force_after first restarts\n";
|
||||||
|
open(FILE, "+<", "./var/tmp/maria_log.00000001") or die;
|
||||||
|
$whatever= ("\xAB" x 8192);
|
||||||
|
sysseek (FILE, 99, 0) or die;
|
||||||
|
syswrite (FILE, $whatever) or die;
|
||||||
|
close FILE;
|
||||||
|
|
||||||
|
$server_cmd= $base_server_cmd . " --start-dirty 2>&1";
|
||||||
|
for($i= 1; $i <= $force_after; $i= $i + 1)
|
||||||
|
{
|
||||||
|
print "mysqld restart number $i... ";
|
||||||
|
unlink($error_log_name) or die;
|
||||||
|
`$server_cmd`;
|
||||||
|
# mysqld should return 1 when can't read log
|
||||||
|
die unless (($? >> 8) == 1);
|
||||||
|
open(FILE, "<", $error_log_name) or die;
|
||||||
|
@cmd_output= <FILE>;
|
||||||
|
close FILE;
|
||||||
|
die unless grep(/\[ERROR\] mysqld: Maria engine: log initialization failed/, @cmd_output);
|
||||||
|
die unless grep(/\[ERROR\] Plugin 'MARIA' init function returned error./, @cmd_output);
|
||||||
|
print "failed - ok\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
print "mysqld restart number $i... ";
|
||||||
|
unlink($error_log_name) or die;
|
||||||
|
@cmd_output=`$server_cmd`;
|
||||||
|
die if $?;
|
||||||
|
open(FILE, "<", $error_log_name) or die;
|
||||||
|
@cmd_output= <FILE>;
|
||||||
|
close FILE;
|
||||||
|
die unless grep(/\[Warning\] mysqld: Maria engine: removed all logs after [\d]+ consecutive failures of recovery from logs/, @cmd_output);
|
||||||
|
die unless grep(/\[ERROR\] mysqld: File '..\/tmp\/maria_log.00000001' not found \(Errcode: 2\)/, @cmd_output);
|
||||||
|
print "success - ok\n";
|
||||||
|
|
||||||
|
open(FILE, ">", $sql_name) or die;
|
||||||
|
print FILE <<EOF;
|
||||||
|
set global maria_recover=normal;
|
||||||
|
insert into t1 values('aaa');
|
||||||
|
EOF
|
||||||
|
close FILE;
|
||||||
|
|
||||||
|
# verify corruption has not yet been noticed
|
||||||
|
open(FILE, "<", $error_log_name) or die;
|
||||||
|
@cmd_output= <FILE>;
|
||||||
|
close FILE;
|
||||||
|
die if grep(/$corrupt_message/, @cmd_output);
|
||||||
|
|
||||||
|
print "inserting in table\n";
|
||||||
|
`$client_cmd`;
|
||||||
|
die if $?;
|
||||||
|
print "table is usable - ok\n";
|
||||||
|
|
||||||
|
open(FILE, "<", $error_log_name) or die;
|
||||||
|
@cmd_output= <FILE>;
|
||||||
|
close FILE;
|
||||||
|
die unless grep(/$corrupt_message/, @cmd_output);
|
||||||
|
die unless grep(/\[Warning\] Recovering table: '.\/test\/t1'/, @cmd_output);
|
||||||
|
print "was corrupted and automatically repaired - ok\n";
|
||||||
|
|
||||||
|
# remove our traces
|
||||||
|
kill_server(15);
|
||||||
|
|
||||||
|
print "TEST ALL OK\n";
|
||||||
|
|
||||||
|
# kills mysqld with signal given in parameter
|
||||||
|
sub kill_server
|
||||||
|
{
|
||||||
|
my ($sig)= @_;
|
||||||
|
my $wait_count= 0;
|
||||||
|
open(FILE, "<", $server_pid_name) or die;
|
||||||
|
@cmd_output= <FILE>;
|
||||||
|
close FILE;
|
||||||
|
$server_pid= $cmd_output[0];
|
||||||
|
die unless $server_pid > 0;
|
||||||
|
kill($sig, $server_pid) or die;
|
||||||
|
while (kill (0, $server_pid))
|
||||||
|
{
|
||||||
|
print "waiting for mysqld to die\n" if ($wait_count > 30);
|
||||||
|
$wait_count= $wait_count + 1;
|
||||||
|
select(undef, undef, undef, 0.1);
|
||||||
|
}
|
||||||
|
}
|
@ -45,6 +45,7 @@ char file_name[FN_REFLEN];
|
|||||||
LSN expect_checkpoint_lsn;
|
LSN expect_checkpoint_lsn;
|
||||||
uint32 expect_logno;
|
uint32 expect_logno;
|
||||||
TrID expect_max_trid;
|
TrID expect_max_trid;
|
||||||
|
uint8 expect_recovery_failures;
|
||||||
|
|
||||||
static int delete_file(myf my_flags);
|
static int delete_file(myf my_flags);
|
||||||
/*
|
/*
|
||||||
@ -55,10 +56,11 @@ static int close_file(void); /* wraps ma_control_file_end */
|
|||||||
/* wraps ma_control_file_open_or_create */
|
/* wraps ma_control_file_open_or_create */
|
||||||
static int open_file(void);
|
static int open_file(void);
|
||||||
/* wraps ma_control_file_write_and_force */
|
/* wraps ma_control_file_write_and_force */
|
||||||
static int write_file(LSN checkpoint_lsn, uint32 logno, TrID trid);
|
static int write_file(LSN checkpoint_lsn, uint32 logno, TrID trid,
|
||||||
|
uint8 rec_failures);
|
||||||
|
|
||||||
/* Tests */
|
/* Tests */
|
||||||
static int test_one_log(void);
|
static int test_one_log_and_recovery_failures(void);
|
||||||
static int test_five_logs_and_max_trid(void);
|
static int test_five_logs_and_max_trid(void);
|
||||||
static int test_3_checkpoints_and_2_logs(void);
|
static int test_3_checkpoints_and_2_logs(void);
|
||||||
static int test_binary_content(void);
|
static int test_binary_content(void);
|
||||||
@ -135,7 +137,8 @@ int main(int argc,char *argv[])
|
|||||||
RET_ERR_UNLESS(0 == delete_file(0)); /* if fails, can't continue */
|
RET_ERR_UNLESS(0 == delete_file(0)); /* if fails, can't continue */
|
||||||
|
|
||||||
diag("Tests of normal conditions");
|
diag("Tests of normal conditions");
|
||||||
ok(0 == test_one_log(), "test of creating one log");
|
ok(0 == test_one_log_and_recovery_failures(),
|
||||||
|
"test of creating one log and recording recovery failures");
|
||||||
ok(0 == test_five_logs_and_max_trid(),
|
ok(0 == test_five_logs_and_max_trid(),
|
||||||
"test of creating five logs and many transactions");
|
"test of creating five logs and many transactions");
|
||||||
ok(0 == test_3_checkpoints_and_2_logs(),
|
ok(0 == test_3_checkpoints_and_2_logs(),
|
||||||
@ -167,7 +170,7 @@ static int delete_file(myf my_flags)
|
|||||||
my_delete(file_name, my_flags);
|
my_delete(file_name, my_flags);
|
||||||
expect_checkpoint_lsn= LSN_IMPOSSIBLE;
|
expect_checkpoint_lsn= LSN_IMPOSSIBLE;
|
||||||
expect_logno= FILENO_IMPOSSIBLE;
|
expect_logno= FILENO_IMPOSSIBLE;
|
||||||
expect_max_trid= 0;
|
expect_max_trid= expect_recovery_failures= 0;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -181,6 +184,7 @@ static int verify_module_values_match_expected(void)
|
|||||||
RET_ERR_UNLESS(last_logno == expect_logno);
|
RET_ERR_UNLESS(last_logno == expect_logno);
|
||||||
RET_ERR_UNLESS(last_checkpoint_lsn == expect_checkpoint_lsn);
|
RET_ERR_UNLESS(last_checkpoint_lsn == expect_checkpoint_lsn);
|
||||||
RET_ERR_UNLESS(max_trid_in_control_file == expect_max_trid);
|
RET_ERR_UNLESS(max_trid_in_control_file == expect_max_trid);
|
||||||
|
RET_ERR_UNLESS(recovery_failures == expect_recovery_failures);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -215,21 +219,28 @@ static int open_file(void)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int write_file(LSN checkpoint_lsn, uint32 logno, TrID trid)
|
static int write_file(LSN checkpoint_lsn, uint32 logno, TrID trid,
|
||||||
|
uint8 rec_failures)
|
||||||
{
|
{
|
||||||
RET_ERR_UNLESS(ma_control_file_write_and_force(checkpoint_lsn, logno, trid)
|
RET_ERR_UNLESS(ma_control_file_write_and_force(checkpoint_lsn, logno, trid,
|
||||||
|
rec_failures)
|
||||||
== 0);
|
== 0);
|
||||||
/* Check that the module reports expected information */
|
/* Check that the module reports expected information */
|
||||||
RET_ERR_UNLESS(verify_module_values_match_expected() == 0);
|
RET_ERR_UNLESS(verify_module_values_match_expected() == 0);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int test_one_log(void)
|
static int test_one_log_and_recovery_failures(void)
|
||||||
{
|
{
|
||||||
RET_ERR_UNLESS(open_file() == CONTROL_FILE_OK);
|
RET_ERR_UNLESS(open_file() == CONTROL_FILE_OK);
|
||||||
expect_logno= 123;
|
expect_logno= 123;
|
||||||
RET_ERR_UNLESS(write_file(last_checkpoint_lsn, expect_logno,
|
RET_ERR_UNLESS(write_file(last_checkpoint_lsn, expect_logno,
|
||||||
max_trid_in_control_file) == 0);
|
max_trid_in_control_file,
|
||||||
|
recovery_failures) == 0);
|
||||||
|
expect_recovery_failures= 158;
|
||||||
|
RET_ERR_UNLESS(write_file(last_checkpoint_lsn, expect_logno,
|
||||||
|
max_trid_in_control_file,
|
||||||
|
expect_recovery_failures) == 0);
|
||||||
RET_ERR_UNLESS(close_file() == 0);
|
RET_ERR_UNLESS(close_file() == 0);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -245,7 +256,8 @@ static int test_five_logs_and_max_trid(void)
|
|||||||
{
|
{
|
||||||
expect_logno*= 3;
|
expect_logno*= 3;
|
||||||
RET_ERR_UNLESS(write_file(last_checkpoint_lsn, expect_logno,
|
RET_ERR_UNLESS(write_file(last_checkpoint_lsn, expect_logno,
|
||||||
expect_max_trid) == 0);
|
expect_max_trid,
|
||||||
|
recovery_failures) == 0);
|
||||||
}
|
}
|
||||||
RET_ERR_UNLESS(close_file() == 0);
|
RET_ERR_UNLESS(close_file() == 0);
|
||||||
return 0;
|
return 0;
|
||||||
@ -260,23 +272,28 @@ static int test_3_checkpoints_and_2_logs(void)
|
|||||||
RET_ERR_UNLESS(open_file() == CONTROL_FILE_OK);
|
RET_ERR_UNLESS(open_file() == CONTROL_FILE_OK);
|
||||||
expect_checkpoint_lsn= MAKE_LSN(5, 10000);
|
expect_checkpoint_lsn= MAKE_LSN(5, 10000);
|
||||||
RET_ERR_UNLESS(write_file(expect_checkpoint_lsn, expect_logno,
|
RET_ERR_UNLESS(write_file(expect_checkpoint_lsn, expect_logno,
|
||||||
max_trid_in_control_file) == 0);
|
max_trid_in_control_file,
|
||||||
|
recovery_failures) == 0);
|
||||||
|
|
||||||
expect_logno= 17;
|
expect_logno= 17;
|
||||||
RET_ERR_UNLESS(write_file(expect_checkpoint_lsn, expect_logno,
|
RET_ERR_UNLESS(write_file(expect_checkpoint_lsn, expect_logno,
|
||||||
max_trid_in_control_file) == 0);
|
max_trid_in_control_file,
|
||||||
|
recovery_failures) == 0);
|
||||||
|
|
||||||
expect_checkpoint_lsn= MAKE_LSN(17, 20000);
|
expect_checkpoint_lsn= MAKE_LSN(17, 20000);
|
||||||
RET_ERR_UNLESS(write_file(expect_checkpoint_lsn, expect_logno,
|
RET_ERR_UNLESS(write_file(expect_checkpoint_lsn, expect_logno,
|
||||||
max_trid_in_control_file) == 0);
|
max_trid_in_control_file,
|
||||||
|
recovery_failures) == 0);
|
||||||
|
|
||||||
expect_checkpoint_lsn= MAKE_LSN(17, 45000);
|
expect_checkpoint_lsn= MAKE_LSN(17, 45000);
|
||||||
RET_ERR_UNLESS(write_file(expect_checkpoint_lsn, expect_logno,
|
RET_ERR_UNLESS(write_file(expect_checkpoint_lsn, expect_logno,
|
||||||
max_trid_in_control_file) == 0);
|
max_trid_in_control_file,
|
||||||
|
recovery_failures) == 0);
|
||||||
|
|
||||||
expect_logno= 19;
|
expect_logno= 19;
|
||||||
RET_ERR_UNLESS(write_file(expect_checkpoint_lsn, expect_logno,
|
RET_ERR_UNLESS(write_file(expect_checkpoint_lsn, expect_logno,
|
||||||
max_trid_in_control_file) == 0);
|
max_trid_in_control_file,
|
||||||
|
recovery_failures) == 0);
|
||||||
RET_ERR_UNLESS(close_file() == 0);
|
RET_ERR_UNLESS(close_file() == 0);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -129,10 +129,10 @@ static my_bool read_and_check_content(TRANSLOG_HEADER_BUFFER *rec,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static const char *load_default_groups[]= {"ma_unit_loghandler", 0};
|
static const char *load_default_groups[]= {"ma_unit_loghandler", 0};
|
||||||
#if defined(__WIN__)
|
#ifndef DBUG_OFF
|
||||||
static const char *default_dbug_option= "d:t:i:O,\\ma_test_loghandler.trace";
|
static const char *default_dbug_option=
|
||||||
#else
|
IF_WIN("d:t:i:O,\\ma_test_loghandler.trace",
|
||||||
static const char *default_dbug_option= "d:t:i:o,/tmp/ma_test_loghandler.trace";
|
"d:t:i:o,/tmp/ma_test_loghandler.trace");
|
||||||
#endif
|
#endif
|
||||||
static const char *opt_wfile= NULL;
|
static const char *opt_wfile= NULL;
|
||||||
static const char *opt_rfile= NULL;
|
static const char *opt_rfile= NULL;
|
||||||
|
Reference in New Issue
Block a user