diff options
Diffstat (limited to 'storage/maria/ha_maria.cc')
-rw-r--r-- | storage/maria/ha_maria.cc | 154 |
1 files changed, 135 insertions, 19 deletions
diff --git a/storage/maria/ha_maria.cc b/storage/maria/ha_maria.cc index 3a4f2b6df23..a6339b28332 100644 --- a/storage/maria/ha_maria.cc +++ b/storage/maria/ha_maria.cc @@ -49,13 +49,11 @@ ulong pagecache_division_limit, pagecache_age_threshold; ulonglong pagecache_buffer_size; /** - @todo For now there is no way for a user to set a different value of - maria_recover_options, i.e. auto-check-and-repair is always disabled. - We could enable it. As the auto-repair is initiated when opened from the - SQL layer (open_unireg_entry(), check_and_repair()), it does not happen - when Maria's Recovery internally opens the table to apply log records to - it, which is good. It would happen only after Recovery, if the table is - still corrupted. + As the auto-repair is initiated when opened from the SQL layer + (open_unireg_entry(), check_and_repair()), it does not happen when Maria's + Recovery internally opens the table to apply log records to it, which is + good. It would happen only after Recovery, if the table is still + corrupted. */ ulong maria_recover_options= HA_RECOVER_NONE; handlerton *maria_hton; @@ -63,7 +61,14 @@ handlerton *maria_hton; /* bits in maria_recover_options */ 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= { @@ -103,11 +108,13 @@ TYPELIB maria_sync_log_dir_typelib= maria_sync_log_dir_names, NULL }; -/** @brief Interval between background checkpoints in seconds */ +/** Interval between background checkpoints in seconds */ static ulong checkpoint_interval; static void update_checkpoint_interval(MYSQL_THD thd, struct st_mysql_sys_var *var, 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, struct st_mysql_sys_var *var, 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.", 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, "Maintain page checksums (can be overridden per table " "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, 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, "Number of threads to use when repairing maria tables. The value of 1 " "disables parallel repair.", @@ -186,7 +210,7 @@ static MYSQL_THDVAR_ULONG(sort_buffer_size, PLUGIN_VAR_RQCMDARG, 0, 0, 8192*1024, 4, ~0L, 1); 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\", " "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; #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))) return (my_errno ? my_errno : -1); @@ -2728,7 +2758,7 @@ bool maria_show_status(handlerton *hton, stat_print_fn *print, enum ha_stat_type stat) { - char engine_name[]= "maria"; + const LEX_STRING *engine_name= hton_name(hton); switch (stat) { case HA_ENGINE_LOGS: { @@ -2745,8 +2775,8 @@ bool maria_show_status(handlerton *hton, if (first_file == 0) { const char error[]= "error"; - print(thd, engine_name, sizeof(engine_name), - STRING_WITH_LEN(""), error, sizeof(error)); + print(thd, engine_name->str, engine_name->length, + STRING_WITH_LEN(""), error, sizeof(error) - 1); break; } @@ -2762,7 +2792,7 @@ bool maria_show_status(handlerton *hton, if (!(stat= my_stat(file, &stat_buff, MYF(MY_WME)))) { status= error; - status_len= sizeof(error); + status_len= sizeof(error) - 1; length= my_snprintf(object, SHOW_MSG_LEN, "Size unknown ; %s", file); } else @@ -2770,23 +2800,23 @@ bool maria_show_status(handlerton *hton, if (first_needed == 0) { status= unknown; - status_len= sizeof(unknown); + status_len= sizeof(unknown) - 1; } else if (i < first_needed) { status= unneeded; - status_len= sizeof(unneeded); + status_len= sizeof(unneeded) - 1; } else { status= needed; - status_len= sizeof(needed); + status_len= sizeof(needed) - 1; } length= my_snprintf(object, SHOW_MSG_LEN, "Size %12lu ; %s", (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); } break; @@ -2799,9 +2829,90 @@ bool maria_show_status(handlerton *hton, 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) { int res; + const char *log_dir= maria_data_root; maria_hton= (handlerton *)p; maria_hton->state= SHOW_OPTION_YES; 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)); maria_tmpdir= &mysql_tmpdir_list; /* For REDO */ res= maria_init() || ma_control_file_open(TRUE, TRUE) || + ((force_start_after_recovery_failures != 0) && + mark_recovery_start(log_dir)) || !init_pagecache(maria_pagecache, (size_t) pagecache_buffer_size, pagecache_division_limit, 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, MYSQL_VERSION_ID, server_id, maria_log_pagecache, TRANSLOG_DEFAULT_FLAGS, 0) || - maria_recover() || + maria_recovery_from_log() || + ((force_start_after_recovery_failures != 0) && mark_recovery_success()) || ma_checkpoint_init(checkpoint_interval); maria_multi_threaded= TRUE; 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[]= { MYSQL_SYSVAR(block_size), MYSQL_SYSVAR(checkpoint_interval), + MYSQL_SYSVAR(force_start_after_recovery_failures), MYSQL_SYSVAR(page_checksum), MYSQL_SYSVAR(log_dir_path), 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_buffer_size), MYSQL_SYSVAR(pagecache_division_limit), + MYSQL_SYSVAR(recover), MYSQL_SYSVAR(repair_threads), MYSQL_SYSVAR(sort_buffer_size), MYSQL_SYSVAR(stats_method), |