summaryrefslogtreecommitdiff
path: root/storage/maria/ha_maria.cc
diff options
context:
space:
mode:
Diffstat (limited to 'storage/maria/ha_maria.cc')
-rw-r--r--storage/maria/ha_maria.cc154
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),