Commit 644361af authored by unknown's avatar unknown

WL#3072 - Maria recovery

maria_read_log used to always print a warning message at startup
to say it is unsafe if ALTER TABLE was used. Now it prints it only
if the log does show the problem (=ALTER TABLE or CREATE SELECT, which
both disable logging of REDO_INSERT*).
For that, when ha_maria::external_lock() disables transactionality
it writes a LOGREC_INCOMPLETE_LOG to the log, which "maria_read_log -a"
picks up to write a warning.
REPAIR TABLE also disables those REDO_INSERT* but as maria_read_log
executes LOGREC_REDO_REPAIR no warning is needed.


storage/maria/ha_maria.cc:
  as we now log a record when disabling transactionility, we need the
  TRN to be set up first
storage/maria/ma_blockrec.c:
  comment
storage/maria/ma_loghandler.c:
  new type of log record
storage/maria/ma_loghandler.h:
  new type of log record
storage/maria/ma_recovery.c:
  * maria_apply_log() now returns a count of warnings. What currently
  produces warnings is:
  - skipping applying UNDOs though there are some (=> inconsistent table)
  - replaying log (in maria_read_log) though the log contains some
  ALTER TABLE or CREATE SELECT (log misses REDO_INSERT* for those
  and is so incomplete).
  Count of warnings affects the final message of maria_read_log and
  recovery (though in recovery none of the two conditions above should
  happen).
  * maria_read_log used to always print a warning message at startup
  to say it is unsafe if ALTER TABLE was used. Now it prints it only
  if the log does show the problem, i.e. ALTER TABLE or CREATE SELECT
  was used (both disable logging of REDO_INSERT* as those records are
  not needed for recovery; those missing records in turn make
  recreation-from-scratch, via maria_read_log, impossible). For that,
  when ha_maria::external_lock() disables transactionality,
  _ma_tmp_disable_logging_for_table() writes a LOGREC_INCOMPLETE_LOG to
  the log, which maria_apply_log() picks up to write a warning.
storage/maria/ma_recovery.h:
  maria_apply_log() returns a count of warnings
storage/maria/maria_def.h:
  _ma_tmp_disable_logging_for_table() grows so becomes a function
storage/maria/maria_read_log.c:
  maria_apply_log can now return a count of warnings, to temper the
  "SUCCESS" message printed in the end by maria_read_log.
  Advise users to make a backup first.
parent 9c6f8a2b
...@@ -2043,20 +2043,6 @@ int ha_maria::external_lock(THD *thd, int lock_type) ...@@ -2043,20 +2043,6 @@ int ha_maria::external_lock(THD *thd, int lock_type)
goto skip_transaction; goto skip_transaction;
if (lock_type != F_UNLCK) if (lock_type != F_UNLCK)
{ {
if (!thd->transaction.on)
{
/*
No need to log REDOs/UNDOs. If this is an internal temporary table
which will be renamed to a permanent table (like in ALTER TABLE),
the rename happens after unlocking so will be durable (and the table
will get its create_rename_lsn).
Note: if we wanted to enable users to have an old backup and apply
tons of archived logs to roll-forward, we could then not disable
REDOs/UNDOs in this case.
*/
DBUG_PRINT("info", ("Disabling logging for table"));
_ma_tmp_disable_logging_for_table(file->s);
}
if (!trn) /* no transaction yet - open it now */ if (!trn) /* no transaction yet - open it now */
{ {
trn= trnman_new_trn(& thd->mysys_var->mutex, trn= trnman_new_trn(& thd->mysys_var->mutex,
...@@ -2077,6 +2063,20 @@ int ha_maria::external_lock(THD *thd, int lock_type) ...@@ -2077,6 +2063,20 @@ int ha_maria::external_lock(THD *thd, int lock_type)
trans_register_ha(thd, FALSE, maria_hton); trans_register_ha(thd, FALSE, maria_hton);
trnman_new_statement(trn); trnman_new_statement(trn);
} }
if (!thd->transaction.on)
{
/*
No need to log REDOs/UNDOs. If this is an internal temporary table
which will be renamed to a permanent table (like in ALTER TABLE),
the rename happens after unlocking so will be durable (and the table
will get its create_rename_lsn).
Note: if we wanted to enable users to have an old backup and apply
tons of archived logs to roll-forward, we could then not disable
REDOs/UNDOs in this case.
*/
DBUG_PRINT("info", ("Disabling logging for table"));
_ma_tmp_disable_logging_for_table(file, TRUE);
}
} }
else else
{ {
......
...@@ -5256,7 +5256,9 @@ uint _ma_apply_redo_purge_blocks(MARIA_HA *info, ...@@ -5256,7 +5256,9 @@ uint _ma_apply_redo_purge_blocks(MARIA_HA *info,
we need to distinguish between blob page (too big, can't pin, and we need to distinguish between blob page (too big, can't pin, and
needn't pin because in a group there is a single REDO touching the needn't pin because in a group there is a single REDO touching the
page) and head/tail. page) and head/tail.
When merged with newer code this should become possible. When merged with newer code this should become possible, as full
pages will be purged with different types of records than head/tail
pages.
*/ */
if (pagecache_write(share->pagecache, if (pagecache_write(share->pagecache,
&info->dfile, page+i, 0, &info->dfile, page+i, 0,
......
...@@ -536,6 +536,11 @@ static LOG_DESC INIT_LOGREC_LONG_TRANSACTION_ID= ...@@ -536,6 +536,11 @@ static LOG_DESC INIT_LOGREC_LONG_TRANSACTION_ID=
{LOGRECTYPE_FIXEDLENGTH, 6, 6, NULL, NULL, NULL, 0, {LOGRECTYPE_FIXEDLENGTH, 6, 6, NULL, NULL, NULL, 0,
"long_transaction_id", LOGREC_IS_GROUP_ITSELF, NULL, NULL}; "long_transaction_id", LOGREC_IS_GROUP_ITSELF, NULL, NULL};
static LOG_DESC INIT_LOGREC_INCOMPLETE_LOG=
{LOGRECTYPE_FIXEDLENGTH, FILEID_STORE_SIZE, FILEID_STORE_SIZE,
NULL, NULL, NULL, 0,
"incomplete_log", LOGREC_IS_GROUP_ITSELF, NULL, NULL};
const myf log_write_flags= MY_WME | MY_NABP | MY_WAIT_IF_FULL; const myf log_write_flags= MY_WME | MY_NABP | MY_WAIT_IF_FULL;
static void loghandler_init() static void loghandler_init()
...@@ -603,12 +608,14 @@ static void loghandler_init() ...@@ -603,12 +608,14 @@ static void loghandler_init()
INIT_LOGREC_FILE_ID; INIT_LOGREC_FILE_ID;
log_record_type_descriptor[LOGREC_LONG_TRANSACTION_ID]= log_record_type_descriptor[LOGREC_LONG_TRANSACTION_ID]=
INIT_LOGREC_LONG_TRANSACTION_ID; INIT_LOGREC_LONG_TRANSACTION_ID;
for (i= LOGREC_LONG_TRANSACTION_ID + 1; log_record_type_descriptor[LOGREC_INCOMPLETE_LOG]=
INIT_LOGREC_INCOMPLETE_LOG;
for (i= LOGREC_INCOMPLETE_LOG + 1;
i < LOGREC_NUMBER_OF_TYPES; i < LOGREC_NUMBER_OF_TYPES;
i++) i++)
log_record_type_descriptor[i].class= LOGRECTYPE_NOT_ALLOWED; log_record_type_descriptor[i].class= LOGRECTYPE_NOT_ALLOWED;
DBUG_EXECUTE("info", DBUG_EXECUTE("info",
check_translog_description_table(LOGREC_LONG_TRANSACTION_ID);); check_translog_description_table(LOGREC_INCOMPLETE_LOG););
}; };
......
...@@ -127,6 +127,7 @@ enum translog_record_type ...@@ -127,6 +127,7 @@ enum translog_record_type
LOGREC_REDO_REPAIR_TABLE, LOGREC_REDO_REPAIR_TABLE,
LOGREC_FILE_ID, LOGREC_FILE_ID,
LOGREC_LONG_TRANSACTION_ID, LOGREC_LONG_TRANSACTION_ID,
LOGREC_INCOMPLETE_LOG,
LOGREC_RESERVED_FUTURE_EXTENSION= 63 LOGREC_RESERVED_FUTURE_EXTENSION= 63
}; };
#define LOGREC_NUMBER_OF_TYPES 64 /* Maximum, can't be extended */ #define LOGREC_NUMBER_OF_TYPES 64 /* Maximum, can't be extended */
......
This diff is collapsed.
...@@ -30,5 +30,5 @@ int maria_recover(void); ...@@ -30,5 +30,5 @@ int maria_recover(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,
my_bool take_checkpoints); my_bool take_checkpoints, uint *warnings_count);
C_MODE_END C_MODE_END
...@@ -952,8 +952,8 @@ int _ma_update_create_rename_lsn_sub(MARIA_SHARE *share, ...@@ -952,8 +952,8 @@ int _ma_update_create_rename_lsn_sub(MARIA_SHARE *share,
LSN lsn, my_bool do_sync); LSN lsn, my_bool do_sync);
void _ma_unpin_all_pages(MARIA_HA *info, LSN undo_lsn); void _ma_unpin_all_pages(MARIA_HA *info, LSN undo_lsn);
#define _ma_tmp_disable_logging_for_table(S) \ void _ma_tmp_disable_logging_for_table(MARIA_HA *info,
{ (S)->now_transactional= FALSE; (S)->page_type= PAGECACHE_PLAIN_PAGE; } my_bool log_incomplete);
#define _ma_reenable_logging_for_table(S) \ #define _ma_reenable_logging_for_table(S) \
{ if (((S)->now_transactional= (S)->base.born_transactional)) \ { if (((S)->now_transactional= (S)->base.born_transactional)) \
(S)->page_type= PAGECACHE_LSN_PAGE; } (S)->page_type= PAGECACHE_LSN_PAGE; }
......
...@@ -38,6 +38,7 @@ int main(int argc, char **argv) ...@@ -38,6 +38,7 @@ int main(int argc, char **argv)
{ {
LSN lsn; LSN lsn;
char **default_argv; char **default_argv;
uint warnings_count;
MY_INIT(argv[0]); MY_INIT(argv[0]);
my_progname_short= my_progname+dirname_length(my_progname); my_progname_short= my_progname+dirname_length(my_progname);
...@@ -106,9 +107,13 @@ int main(int argc, char **argv) ...@@ -106,9 +107,13 @@ int main(int argc, char **argv)
if (maria_apply_log(lsn, opt_apply ? MARIA_LOG_APPLY : if (maria_apply_log(lsn, opt_apply ? MARIA_LOG_APPLY :
(opt_check ? MARIA_LOG_CHECK : (opt_check ? MARIA_LOG_CHECK :
MARIA_LOG_DISPLAY_HEADER), opt_silent ? NULL : stdout, MARIA_LOG_DISPLAY_HEADER), opt_silent ? NULL : stdout,
opt_apply_undo, FALSE, FALSE)) opt_apply_undo, FALSE, FALSE, &warnings_count))
goto err; goto err;
if (warnings_count == 0)
fprintf(stdout, "%s: SUCCESS\n", my_progname_short); fprintf(stdout, "%s: SUCCESS\n", my_progname_short);
else
fprintf(stdout, "%s: DOUBTFUL (%u warnings, check previous output)\n",
my_progname_short, warnings_count);
goto end; goto end;
err: err:
...@@ -130,7 +135,8 @@ int main(int argc, char **argv) ...@@ -130,7 +135,8 @@ int main(int argc, char **argv)
static struct my_option my_long_options[] = static struct my_option my_long_options[] =
{ {
{"apply", 'a', {"apply", 'a',
"Apply log to tables. Will display a lot of information if not run with --silent", "Apply log to tables: modifies tables! you should make a backup first! "
" Displays a lot of information if not run with --silent",
(uchar **) &opt_apply, (uchar **) &opt_apply, 0, (uchar **) &opt_apply, (uchar **) &opt_apply, 0,
GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
{"check", 'c', {"check", 'c',
...@@ -143,7 +149,7 @@ static struct my_option my_long_options[] = ...@@ -143,7 +149,7 @@ static struct my_option my_long_options[] =
#endif #endif
{"help", '?', "Display this help and exit.", {"help", '?', "Display this help and exit.",
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
{"only-display", 'o', "display brief info about records's header", {"only-display", 'o', "display brief info read from records' header",
(uchar **) &opt_only_display, (uchar **) &opt_only_display, 0, GET_BOOL, (uchar **) &opt_only_display, (uchar **) &opt_only_display, 0, GET_BOOL,
NO_ARG,0, 0, 0, 0, 0, 0}, NO_ARG,0, 0, 0, 0, 0, 0},
{ "page_buffer_size", 'P', "", { "page_buffer_size", 'P', "",
...@@ -154,7 +160,7 @@ static struct my_option my_long_options[] = ...@@ -154,7 +160,7 @@ static struct my_option my_long_options[] =
{"silent", 's', "Print less information during apply/undo phase", {"silent", 's', "Print less information during apply/undo phase",
(uchar **) &opt_silent, (uchar **) &opt_silent, 0, (uchar **) &opt_silent, (uchar **) &opt_silent, 0,
GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
{"undo", 'u', "Apply undos to tables. (disable with --disable-undo)", {"undo", 'u', "Apply UNDO records to tables. (disable with --disable-undo)",
(uchar **) &opt_apply_undo, (uchar **) &opt_apply_undo, 0, (uchar **) &opt_apply_undo, (uchar **) &opt_apply_undo, 0,
GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0}, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0},
{"version", 'V', "Print version and exit.", {"version", 'V', "Print version and exit.",
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment