From 771296eb063e7d1f8d5264f48a254adad439616b Mon Sep 17 00:00:00 2001 From: unknown Date: Sun, 9 Dec 2007 19:35:51 +0200 Subject: [PATCH 1/2] Manageable transactional log purge and file size support added to maria. mysql-test/r/maria.result: New variables added. storage/maria/ha_maria.cc: Variable for transactional log purge method added. Variable for transactional log size added. SHOW for engine logs added. Log flush purge logs in case of "ondemand" type of log processing. storage/maria/ma_checkpoint.c: log purge call enabled. storage/maria/ma_loghandler.c: Support for different methods of log purge added. Functions for getting information about logs state added. Functions for getting/setting log size. storage/maria/ma_loghandler.h: Fixed defines. Functions for for transactional log mannegment added. storage/maria/ma_recovery.c: Dependence on TRANSLOG_FILE_SIZE removed. mysql-test/r/maria-purge.result: New BitKeeper file ``mysql-test/r/maria-purge.result'' mysql-test/t/maria-purge.test: New BitKeeper file ``mysql-test/t/maria-purge.test'' --- mysql-test/r/maria-purge.result | 82 +++++++++++++++ mysql-test/r/maria.result | 2 + mysql-test/t/maria-purge.test | 95 +++++++++++++++++ storage/maria/ha_maria.cc | 151 ++++++++++++++++++++++++++- storage/maria/ma_checkpoint.c | 2 - storage/maria/ma_loghandler.c | 174 +++++++++++++++++++++++++++++--- storage/maria/ma_loghandler.h | 23 ++++- storage/maria/ma_recovery.c | 5 +- 8 files changed, 511 insertions(+), 23 deletions(-) create mode 100644 mysql-test/r/maria-purge.result create mode 100644 mysql-test/t/maria-purge.test diff --git a/mysql-test/r/maria-purge.result b/mysql-test/r/maria-purge.result new file mode 100644 index 00000000000..6c3e709f343 --- /dev/null +++ b/mysql-test/r/maria-purge.result @@ -0,0 +1,82 @@ +set global storage_engine=maria; +set session storage_engine=maria; +drop table if exists t1,t2; +SET SQL_WARNINGS=1; +CREATE TABLE t1 ( +STRING_DATA char(255) default NULL +); +CREATE TABLE t2 ( +STRING_DATA char(255) default NULL +); +INSERT INTO t1 VALUES ('AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'); +INSERT INTO t1 VALUES ('DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD'); +insert into t2 select * from t1; +insert into t1 select * from t2; +insert into t2 select * from t1; +insert into t1 select * from t2; +insert into t2 select * from t1; +insert into t1 select * from t2; +insert into t2 select * from t1; +insert into t1 select * from t2; +insert into t2 select * from t1; +insert into t1 select * from t2; +insert into t2 select * from t1; +insert into t1 select * from t2; +insert into t2 select * from t1; +insert into t1 select * from t2; +insert into t2 select * from t1; +insert into t1 select * from t2; +insert into t2 select * from t1; +insert into t1 select * from t2; +insert into t2 select * from t1; +insert into t1 select * from t2; +insert into t2 select * from t1; +insert into t1 select * from t2; +insert into t2 select * from t1; +insert into t1 select * from t2; +set global maria_checkpoint_interval=2; +SHOW ENGINE maria logs; +Type Name Status +maria master-data/maria_log.00000001 in use +set global maria_log_file_size=16777216; +select @@global.maria_log_file_size; +@@global.maria_log_file_size +16777216 +SHOW ENGINE maria logs; +Type Name Status +maria master-data/maria_log.00000002 in use +set global maria_log_file_size=8388608; +select @@global.maria_log_file_size; +@@global.maria_log_file_size +8388608 +set global maria_log_purge_type=at_flush; +insert into t1 select * from t2; +SHOW ENGINE maria logs; +Type Name Status +maria master-data/maria_log.00000002 free +maria master-data/maria_log.00000003 free +maria master-data/maria_log.00000004 free +maria master-data/maria_log.00000005 in use +flush logs; +SHOW ENGINE maria logs; +Type Name Status +maria master-data/maria_log.00000005 in use +set global maria_log_file_size=16777216; +set global maria_log_purge_type=external; +insert into t1 select * from t2; +SHOW ENGINE maria logs; +Type Name Status +maria master-data/maria_log.00000005 free +maria master-data/maria_log.00000006 in use +flush logs; +SHOW ENGINE maria logs; +Type Name Status +maria master-data/maria_log.00000005 free +maria master-data/maria_log.00000006 in use +set global maria_log_purge_type=immediate; +insert into t1 select * from t2; +SHOW ENGINE maria logs; +Type Name Status +maria master-data/maria_log.00000007 in use +maria master-data/maria_log.00000008 in use +drop table t1, t2; diff --git a/mysql-test/r/maria.result b/mysql-test/r/maria.result index 982ae512e70..31503330d1e 100644 --- a/mysql-test/r/maria.result +++ b/mysql-test/r/maria.result @@ -1977,6 +1977,8 @@ show variables like 'maria%'; Variable_name Value maria_block_size 8192 maria_checkpoint_interval 30 +maria_log_file_size 1073741824 +maria_log_purge_type immediate maria_max_sort_file_size 9223372036853727232 maria_pagecache_age_threshold 300 maria_pagecache_buffer_size 8384512 diff --git a/mysql-test/t/maria-purge.test b/mysql-test/t/maria-purge.test new file mode 100644 index 00000000000..607255c311c --- /dev/null +++ b/mysql-test/t/maria-purge.test @@ -0,0 +1,95 @@ +-- source include/have_maria.inc +-- source include/big_test.inc +let $default=`select @@global.storage_engine`; +set global storage_engine=maria; +set session storage_engine=maria; +let $def_logsize=`select @@global.maria_log_file_size`; +let $def_checkinterval=`select @@global.maria_checkpoint_interval`; + +# Initialise +--disable_warnings +drop table if exists t1,t2; +--enable_warnings +SET SQL_WARNINGS=1; + +CREATE TABLE t1 ( + STRING_DATA char(255) default NULL +); +CREATE TABLE t2 ( + STRING_DATA char(255) default NULL +); + +INSERT INTO t1 VALUES ('AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'); +INSERT INTO t1 VALUES ('DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD'); +insert into t2 select * from t1; +insert into t1 select * from t2; +insert into t2 select * from t1; +insert into t1 select * from t2; +insert into t2 select * from t1; +insert into t1 select * from t2; +insert into t2 select * from t1; +insert into t1 select * from t2; +insert into t2 select * from t1; +insert into t1 select * from t2; +insert into t2 select * from t1; +insert into t1 select * from t2; +insert into t2 select * from t1; +insert into t1 select * from t2; +insert into t2 select * from t1; +insert into t1 select * from t2; +insert into t2 select * from t1; +insert into t1 select * from t2; +insert into t2 select * from t1; +insert into t1 select * from t2; +insert into t2 select * from t1; +insert into t1 select * from t2; +insert into t2 select * from t1; +insert into t1 select * from t2; + + +set global maria_checkpoint_interval=2; +--replace_regex /Size +[0-9]+ ; .+master-data/master-data/ +SHOW ENGINE maria logs; +set global maria_log_file_size=16777216; +select @@global.maria_log_file_size; +sleep 7; +--replace_regex /Size +[0-9]+ ; .+master-data/master-data/ +SHOW ENGINE maria logs; +set global maria_log_file_size=8388608; +select @@global.maria_log_file_size; + +set global maria_log_purge_type=at_flush; +insert into t1 select * from t2; +sleep 7; +--replace_regex /Size +[0-9]+ ; .+master-data/master-data/ +SHOW ENGINE maria logs; +flush logs; +--replace_regex /Size +[0-9]+ ; .+master-data/master-data/ +SHOW ENGINE maria logs; + +set global maria_log_file_size=16777216; +set global maria_log_purge_type=external; +insert into t1 select * from t2; +sleep 7; +--replace_regex /Size +[0-9]+ ; .+master-data/master-data/ +SHOW ENGINE maria logs; +flush logs; +--replace_regex /Size +[0-9]+ ; .+master-data/master-data/ +SHOW ENGINE maria logs; + +set global maria_log_purge_type=immediate; +insert into t1 select * from t2; +sleep 7; +--replace_regex /Size +[0-9]+ ; .+master-data/master-data/ +SHOW ENGINE maria logs; + +drop table t1, t2; + +--disable_result_log +--disable_query_log +set global maria_log_purge_type=immediate; +eval set global storage_engine=$default; +eval set global maria_log_file_size=$def_logsize; +eval set global maria_checkpoint_interval=$def_checkinterval; +--enable_result_log +--enable_query_log diff --git a/storage/maria/ha_maria.cc b/storage/maria/ha_maria.cc index 220534335e1..f83d265e2ad 100644 --- a/storage/maria/ha_maria.cc +++ b/storage/maria/ha_maria.cc @@ -22,6 +22,7 @@ #include "mysql_priv.h" #include #include +#include #include #include #include "ha_maria.h" @@ -81,11 +82,25 @@ TYPELIB maria_stats_method_typelib= maria_stats_method_names, NULL }; +/* transactions log purge mode */ +const char *maria_translog_purge_type_names[]= +{ + "immediate", "external", "at_flush", NullS +}; +TYPELIB maria_translog_purge_type_typelib= +{ + array_elements(maria_translog_purge_type_names) - 1, "", + maria_translog_purge_type_names, NULL +}; + /** @brief 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, void *save); +static void update_log_file_size(MYSQL_THD thd, + struct st_mysql_sys_var *var, + void *var_ptr, void *save); static MYSQL_SYSVAR_ULONG(block_size, maria_block_size, PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY, @@ -99,6 +114,20 @@ static MYSQL_SYSVAR_ULONG(checkpoint_interval, checkpoint_interval, " 0 means 'no automatic checkpoints'.", NULL, update_checkpoint_interval, 30, 0, UINT_MAX, 1); +static MYSQL_SYSVAR_ULONG(log_file_size, log_file_size, + PLUGIN_VAR_RQCMDARG, + "Limit for transaction log size", + NULL, update_log_file_size, TRANSLOG_FILE_SIZE, + TRANSLOG_MIN_FILE_SIZE, 0xffffffffL, TRANSLOG_PAGE_SIZE); + +static MYSQL_SYSVAR_ENUM(log_purge_type, log_purge_type, + PLUGIN_VAR_RQCMDARG, + "Specifies how maria transactional log will be purged. " + "Possible values of name are \"immediate\", \"external\" " + "and \"at_flush\"", + NULL, NULL, TRANSLOG_PURGE_IMMIDIATE, + &maria_translog_purge_type_typelib); + static MYSQL_SYSVAR_ULONGLONG(max_sort_file_size, maria_max_temp_length, PLUGIN_VAR_RQCMDARG, "Don't use the fast sort index method to created index if the " @@ -2417,6 +2446,109 @@ static int maria_rollback(handlerton *hton __attribute__ ((unused)), } + +/** + @brief flush log handler + + @param hton maria handlerton (unused) + + @retval FALSE OK + @retval TRUE Error +*/ + +bool maria_flush_logs(handlerton *hton) +{ + return test(translog_purge_at_flush()); +} + + +#define SHOW_MSG_LEN (FN_REFLEN + 20) +/** + @brief show status handler + + @param hton maria handlerton + @param thd thread handler + @param print print function + @param stat type of status +*/ + +bool maria_show_status(handlerton *hton, + THD *thd, + stat_print_fn *print, + enum ha_stat_type stat) +{ + char engine_name[]= "maria"; + switch (stat) + { + case HA_ENGINE_LOGS: + { + TRANSLOG_ADDRESS horizon= translog_get_horizon(); + uint32 last_file= LSN_FILE_NO(horizon); + uint32 first_needed= translog_get_first_needed_file(); + uint32 first_file= translog_get_first_file(horizon); + uint32 i; + const char unknown[]= "unknown"; + const char needed[]= "in use"; + const char unneeded[]= "free"; + char path[FN_REFLEN]; + + if (first_file == 0) + { + const char error[]= "error"; + print(thd, engine_name, sizeof(engine_name), + STRING_WITH_LEN(""), error, sizeof(error)); + break; + } + + for (i= first_file; i <= last_file; i++) + { + char *file; + const char *status; + uint length, status_len; + MY_STAT stat_buff, *stat; + const char error[]= "can't stat"; + char object[SHOW_MSG_LEN]; + file= translog_filename_by_fileno(i, path); + if (!(stat= my_stat(file, &stat_buff, MYF(MY_WME)))) + { + status= error; + status_len= sizeof(error); + length= snprintf(object, SHOW_MSG_LEN, "Size unknown ; %s", file); + } + else + { + if (first_needed == 0) + { + status= unknown; + status_len= sizeof(unknown); + } + else if (i < first_needed) + { + status= unneeded; + status_len= sizeof(unneeded); + } + else + { + status= needed; + status_len= sizeof(needed); + } + length= snprintf(object, SHOW_MSG_LEN, "Size %12lu ; %s", + (ulong) stat->st_size, file); + } + + print(thd, engine_name, sizeof(engine_name), + object, length, status, status_len); + } + break; + } + case HA_ENGINE_STATUS: + case HA_ENGINE_MUTEX: + default: + break; + } + return 0; +} + static int ha_maria_init(void *p) { int res; @@ -2427,6 +2559,8 @@ static int ha_maria_init(void *p) maria_hton->panic= maria_hton_panic; maria_hton->commit= maria_commit; maria_hton->rollback= maria_rollback; + maria_hton->flush_logs= maria_flush_logs; + maria_hton->show_status= maria_show_status; /* TODO: decide if we support Maria being used for log tables */ maria_hton->flags= HTON_CAN_RECREATE | HTON_SUPPORT_LOG_TABLES; bzero(maria_log_pagecache, sizeof(*maria_log_pagecache)); @@ -2438,7 +2572,7 @@ static int ha_maria_init(void *p) (init_pagecache(maria_log_pagecache, TRANSLOG_PAGECACHE_SIZE, 0, 0, TRANSLOG_PAGE_SIZE) == 0) || - translog_init(maria_data_root, TRANSLOG_FILE_SIZE, + translog_init(maria_data_root, log_file_size, MYSQL_VERSION_ID, server_id, maria_log_pagecache, TRANSLOG_DEFAULT_FLAGS) || maria_recover() || @@ -2526,6 +2660,8 @@ 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(log_file_size), + MYSQL_SYSVAR(log_purge_type), MYSQL_SYSVAR(max_sort_file_size), MYSQL_SYSVAR(pagecache_age_threshold), MYSQL_SYSVAR(pagecache_buffer_size), @@ -2549,6 +2685,19 @@ static void update_checkpoint_interval(MYSQL_THD thd, ma_checkpoint_init(*(ulong *)var_ptr= (ulong)(*(long *)save)); } +/** + @brief Updates the transaction log file limit. +*/ + +static void update_log_file_size(MYSQL_THD thd, + struct st_mysql_sys_var *var, + void *var_ptr, void *save) +{ + uint32 size= (uint32)((ulong)(*(long *)save)); + size= translog_set_file_size(size); + *(ulong *)var_ptr= size; +} + static SHOW_VAR status_variables[]= { {"Maria_pagecache_blocks_not_flushed", (char*) &maria_pagecache_var.global_blocks_changed, SHOW_LONG}, {"Maria_pagecache_blocks_unused", (char*) &maria_pagecache_var.blocks_unused, SHOW_LONG}, diff --git a/storage/maria/ma_checkpoint.c b/storage/maria/ma_checkpoint.c index 76f1723b053..9af74aa11af 100644 --- a/storage/maria/ma_checkpoint.c +++ b/storage/maria/ma_checkpoint.c @@ -280,10 +280,8 @@ static int really_execute_checkpoint(void) be robust against that: remember a few previous checkpoints in the control file, and not purge logs immediately... Think about it. */ -#if 0 /* purging/keeping will be an option */ if (translog_purge(log_low_water_mark)) fprintf(stderr, "Maria engine: log purge failed\n"); /* not deadly */ -#endif goto end; diff --git a/storage/maria/ma_loghandler.c b/storage/maria/ma_loghandler.c index 67830653824..37d12da41f0 100644 --- a/storage/maria/ma_loghandler.c +++ b/storage/maria/ma_loghandler.c @@ -199,6 +199,11 @@ struct st_translog_descriptor pthread_mutex_t unfinished_files_lock; DYNAMIC_ARRAY unfinished_files; + /* + minimum number of still need file calculeted during last + translog_purge call + */ + uint32 min_need_file; /* Purger data: minimum file in the log (or 0 if unknown) */ uint32 min_file_number; /* Protect purger from many calls and it's data */ @@ -209,6 +214,9 @@ struct st_translog_descriptor static struct st_translog_descriptor log_descriptor; +ulong log_purge_type= TRANSLOG_PURGE_IMMIDIATE; +ulong log_file_size= TRANSLOG_FILE_SIZE; + /* Marker for end of log */ static uchar end_of_log= 0; #define END_OF_LOG &end_of_log @@ -647,18 +655,16 @@ static void translog_check_cursor(struct st_buffer_cursor *cursor) #endif /* - Get file name of the log by log number + @brief Get file name of the log by log number - SYNOPSIS - translog_filename_by_fileno() - file_no Number of the log we want to open - path Pointer to buffer where file name will be + @param file_no Number of the log we want to open + @param path Pointer to buffer where file name will be stored (must be FN_REFLEN bytes at least) - RETURN - pointer to path + + @return pointer to path */ -static char *translog_filename_by_fileno(uint32 file_no, char *path) +char *translog_filename_by_fileno(uint32 file_no, char *path) { char buff[11], *end; uint length; @@ -668,7 +674,7 @@ static char *translog_filename_by_fileno(uint32 file_no, char *path) /* log_descriptor.directory is already formated */ end= strxmov(path, log_descriptor.directory, "maria_log.0000000", NullS); length= (uint) (int10_to_str(file_no, buff, 10) - buff); - strmov(end-length+1, buff); + strmov(end - length +1, buff); DBUG_PRINT("info", ("Path: '%s' path: 0x%lx", path, (ulong) path)); DBUG_RETURN(path); @@ -2726,6 +2732,18 @@ static my_bool translog_truncate_log(TRANSLOG_ADDRESS addr) DBUG_RETURN(0); } +/** + @brief round correctly transaction log size + + @return maximum possible log size less or equal then given one +*/ + +static uint32 translog_round_log_size(uint32 size) +{ + size= (size - (size % TRANSLOG_PAGE_SIZE)); + return max(size, TRANSLOG_MIN_FILE_SIZE); +} + /* Initialize transaction log @@ -2776,6 +2794,7 @@ my_bool translog_init(const char *directory, sizeof(struct st_file_counter), 10, 10 CALLER_INFO)) DBUG_RETURN(1); + log_descriptor.min_need_file= 0; log_descriptor.min_file_number= 0; log_descriptor.last_lsn_checked= LSN_IMPOSSIBLE; @@ -2792,8 +2811,8 @@ my_bool translog_init(const char *directory, log_descriptor.in_buffers_only= LSN_IMPOSSIBLE; /* max size of one log size (for new logs creation) */ - log_descriptor.log_file_max_size= - log_file_max_size - (log_file_max_size % TRANSLOG_PAGE_SIZE); + log_file_size= log_descriptor.log_file_max_size= + translog_round_log_size(log_file_max_size); /* server version */ log_descriptor.server_version= server_version; /* server ID */ @@ -6769,7 +6788,7 @@ my_bool translog_is_file(uint file_no) static uint32 translog_first_file(TRANSLOG_ADDRESS horizon, int is_protected) { - uint min_file= 1, max_file; + uint min_file= 0, max_file; DBUG_ENTER("translog_first_file"); if (!is_protected) translog_mutex_lock(&log_descriptor.purger_lock); @@ -6943,7 +6962,7 @@ LSN translog_first_lsn_in_log() /** - @brief returns theoretical first LSN if first log is present + @brief Returns theoretical first LSN if first log is present @retval LSN_ERROR Error @retval LSN_IMPOSSIBLE no log @@ -6979,7 +6998,7 @@ LSN translog_first_theoretical_lsn() /** - @brief Check given low water mark and purge files if it is need + @brief Checks given low water mark and purge files if it is need @param low the last (minimum) address which is need @@ -7002,7 +7021,6 @@ my_bool translog_purge(TRANSLOG_ADDRESS low) uint32 i; uint32 min_file= translog_first_file(horizon, 1); DBUG_ASSERT(min_file != 0); /* log is already started */ - for(i= min_file; i < last_need_file && rc == 0; i++) { LSN lsn= translog_get_file_max_lsn_stored(i); @@ -7016,14 +7034,140 @@ my_bool translog_purge(TRANSLOG_ADDRESS low) if (cmp_translog_addr(lsn, low) >= 0) break; DBUG_PRINT("info", ("purge file %lu", (ulong) i)); + if (log_purge_type == TRANSLOG_PURGE_IMMIDIATE) { char path[FN_REFLEN], *file_name; file_name= translog_filename_by_fileno(i, path); rc= test(my_delete(file_name, MYF(MY_WME))); } } + if (unlikely(rc == 1)) + log_descriptor.min_need_file= 0; /* impossible value */ + else + log_descriptor.min_need_file= i; } translog_mutex_unlock(&log_descriptor.purger_lock); DBUG_RETURN(rc); } + + +/** + @brief Purges files by stored min need file in case of + "ondemend" purge type + + @note This function do real work only if it is "ondemend" purge type + and translog_purge() was called at least once and last time without + errors + + @retval 0 OK + @retval 1 Error +*/ + +my_bool translog_purge_at_flush() +{ + uint32 i, min_file; + int rc= 0; + DBUG_ENTER("translog_purge_at_flush"); + DBUG_ASSERT(translog_inited == 1); + + if (log_purge_type != TRANSLOG_PURGE_ONDEMAND) + { + DBUG_PRINT("info", ("It is not \"at_flush\" => exit")); + DBUG_RETURN(0); + } + + translog_mutex_lock(&log_descriptor.purger_lock); + + if (unlikely(log_descriptor.min_need_file == 0)) + { + DBUG_PRINT("info", ("No info about min need file => exit")); + translog_mutex_unlock(&log_descriptor.purger_lock); + DBUG_RETURN(0); + } + + min_file= translog_first_file(translog_get_horizon(), 1); + DBUG_ASSERT(min_file != 0); /* log is already started */ + for(i= min_file; i < log_descriptor.min_need_file && rc == 0; i++) + { + char path[FN_REFLEN], *file_name; + DBUG_PRINT("info", ("purge file %lu\n", (ulong) i)); + file_name= translog_filename_by_fileno(i, path); + rc= test(my_delete(file_name, MYF(MY_WME))); + } + + translog_mutex_unlock(&log_descriptor.purger_lock); + DBUG_RETURN(rc); +} + + +/** + @brief Gets min file number + + @param horizon the end of the log + + @retval minimum file number + @retval 0 no files found +*/ + +uint32 translog_get_first_file(TRANSLOG_ADDRESS horizon) +{ + return translog_first_file(horizon, 0); +} + + +/** + @brief Gets min file number which is needed + + @retval minimum file number + @retval 0 unknown +*/ + +uint32 translog_get_first_needed_file() +{ + uint32 file_no; + translog_mutex_lock(&log_descriptor.purger_lock); + file_no= log_descriptor.min_need_file; + translog_mutex_unlock(&log_descriptor.purger_lock); + return file_no; +} + + +/** + @brief Gets transaction log file size + + @return transaction log file size +*/ + +uint32 translog_get_file_size() +{ + uint32 res; + translog_lock(); + res= log_descriptor.log_file_max_size; + translog_unlock(); + return (res); +} + + +/** + @brief Sets transaction log file size + + @return Returns actually set transaction log size +*/ + +uint32 translog_set_file_size(uint32 size) +{ + uint32 res; + translog_lock(); + res= log_descriptor.log_file_max_size= translog_round_log_size(size); + /* if current file longer then finish it*/ + if (LSN_OFFSET(log_descriptor.horizon) >= log_descriptor.log_file_max_size) + { + struct st_translog_buffer *old_buffer= log_descriptor.bc.buffer; + translog_buffer_next(&log_descriptor.horizon, &log_descriptor.bc, 1); + translog_buffer_unlock(old_buffer); + } + translog_unlock(); + return (res); +} + diff --git a/storage/maria/ma_loghandler.h b/storage/maria/ma_loghandler.h index 9ea3bfca263..3c33c08b3d1 100644 --- a/storage/maria/ma_loghandler.h +++ b/storage/maria/ma_loghandler.h @@ -17,9 +17,11 @@ #define _ma_loghandler_h /* transaction log default cache size (TODO: make it global variable) */ -#define TRANSLOG_PAGECACHE_SIZE 1024*1024*2 -/* transaction log default file size (TODO: make it global variable) */ -#define TRANSLOG_FILE_SIZE 1024*1024*1024 +#define TRANSLOG_PAGECACHE_SIZE (1024*1024*2) +/* transaction log default file size */ +#define TRANSLOG_FILE_SIZE (1024*1024*1024) +/* minimum possible transaction log size */ +#define TRANSLOG_MIN_FILE_SIZE (1024*1024*4) /* transaction log default flags (TODO: make it global variable) */ #define TRANSLOG_DEFAULT_FLAGS 0 @@ -290,6 +292,12 @@ extern my_bool translog_inited; extern LSN translog_first_lsn_in_log(); extern LSN translog_first_theoretical_lsn(); extern LSN translog_next_LSN(TRANSLOG_ADDRESS addr, TRANSLOG_ADDRESS horizon); +extern my_bool translog_purge_at_flush(); +extern uint32 translog_get_first_file(TRANSLOG_ADDRESS horizon); +extern uint32 translog_get_first_needed_file(); +extern char *translog_filename_by_fileno(uint32 file_no, char *path); +extern uint32 translog_get_file_size(); +extern uint32 translog_set_file_size(uint32 size); /* record parts descriptor */ struct st_translog_parts @@ -374,5 +382,14 @@ typedef struct st_log_record_type_descriptor extern LOG_DESC log_record_type_descriptor[LOGREC_NUMBER_OF_TYPES]; #endif +typedef enum +{ + TRANSLOG_PURGE_IMMIDIATE, + TRANSLOG_PURGE_EXTERNAL, + TRANSLOG_PURGE_ONDEMAND +} enum_maria_translog_purge_type; +extern ulong log_purge_type; +extern ulong log_file_size; + C_MODE_END #endif diff --git a/storage/maria/ma_recovery.c b/storage/maria/ma_recovery.c index 97c9b56d9e8..d601893a050 100644 --- a/storage/maria/ma_recovery.c +++ b/storage/maria/ma_recovery.c @@ -2336,8 +2336,9 @@ static void print_redo_phase_progress(TRANSLOG_ADDRESS addr) int cur_offset= LSN_OFFSET(addr); ulonglong remainder; remainder= (cur_logno == end_logno) ? (end_offset - cur_offset) : - (TRANSLOG_FILE_SIZE - cur_offset + - max(end_logno - cur_logno - 1, 0) * TRANSLOG_FILE_SIZE + end_offset); + (((longlong)log_file_size) - cur_offset + + max(end_logno - cur_logno - 1, 0) * ((longlong)log_file_size) + + end_offset); if (initial_remainder == (ulonglong)(-1)) initial_remainder= remainder; int percentage_done= From fed1d21b1db8460c73dc3fe1d6394dbe62e68e50 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 11 Dec 2007 15:26:08 +0200 Subject: [PATCH 2/2] Post review fix (serg). Added more checks. storage/maria/ha_maria.cc: Let control size to my_get_opts(). storage/maria/ma_loghandler.c: Let control size to my_get_opts(). Removed unused function. Assert to check log file size. Additional compilation warnings. storage/maria/ma_loghandler.h: New log size bounds. Removed unused function. storage/maria/unittest/ma_test_loghandler-t.c: Fixed test to confirm new log size bounds. --- storage/maria/ha_maria.cc | 2 +- storage/maria/ma_loghandler.c | 34 +++++++++---------- storage/maria/ma_loghandler.h | 5 ++- storage/maria/unittest/ma_test_loghandler-t.c | 4 +-- 4 files changed, 21 insertions(+), 24 deletions(-) diff --git a/storage/maria/ha_maria.cc b/storage/maria/ha_maria.cc index 82bcbdd07c7..606710f1f6c 100644 --- a/storage/maria/ha_maria.cc +++ b/storage/maria/ha_maria.cc @@ -2693,7 +2693,7 @@ static void update_log_file_size(MYSQL_THD thd, void *var_ptr, void *save) { uint32 size= (uint32)((ulong)(*(long *)save)); - size= translog_set_file_size(size); + translog_set_file_size(size); *(ulong *)var_ptr= size; } diff --git a/storage/maria/ma_loghandler.c b/storage/maria/ma_loghandler.c index 1c9abd8508c..9fa556cec68 100644 --- a/storage/maria/ma_loghandler.c +++ b/storage/maria/ma_loghandler.c @@ -29,7 +29,7 @@ /* number of opened log files in the pagecache (should be at least 2) */ #define OPENED_FILES_NUM 3 -/* records buffer size (should be LOG_PAGE_SIZE * n) */ +/* records buffer size (should be TRANSLOG_PAGE_SIZE * n) */ #define TRANSLOG_WRITE_BUFFER (1024*1024) /* min chunk length */ #define TRANSLOG_MIN_CHUNK 3 @@ -2812,18 +2812,6 @@ static my_bool translog_truncate_log(TRANSLOG_ADDRESS addr) DBUG_RETURN(0); } -/** - @brief round correctly transaction log size - - @return maximum possible log size less or equal then given one -*/ - -static uint32 translog_round_log_size(uint32 size) -{ - size= (size - (size % TRANSLOG_PAGE_SIZE)); - return max(size, TRANSLOG_MIN_FILE_SIZE); -} - /* Initialize transaction log @@ -2857,6 +2845,9 @@ my_bool translog_init(const char *directory, my_bool version_changed= 0; DBUG_ENTER("translog_init"); DBUG_ASSERT(translog_inited == 0); + compile_time_assert(TRANSLOG_MIN_FILE_SIZE > + TRANSLOG_WRITE_BUFFER * TRANSLOG_BUFFERS_NO); + compile_time_assert(TRANSLOG_WRITE_BUFFER % TRANSLOG_PAGE_SIZE == 0); loghandler_init(); /* Safe to do many times */ @@ -2890,9 +2881,12 @@ my_bool translog_init(const char *directory, } log_descriptor.in_buffers_only= LSN_IMPOSSIBLE; + DBUG_ASSERT(log_file_max_size % TRANSLOG_PAGE_SIZE == 0 && + log_file_max_size >= TRANSLOG_MIN_FILE_SIZE && + log_file_max_size <= 0xffffffffL); /* max size of one log size (for new logs creation) */ log_file_size= log_descriptor.log_file_max_size= - translog_round_log_size(log_file_max_size); + log_file_max_size; /* server version */ log_descriptor.server_version= server_version; /* server ID */ @@ -7218,11 +7212,15 @@ uint32 translog_get_file_size() @return Returns actually set transaction log size */ -uint32 translog_set_file_size(uint32 size) +void translog_set_file_size(uint32 size) { - uint32 res; + DBUG_ENTER("translog_set_file_size"); translog_lock(); - res= log_descriptor.log_file_max_size= translog_round_log_size(size); + DBUG_PRINT("enter", ("Size: %lu", (ulong) size)); + DBUG_ASSERT(size % TRANSLOG_PAGE_SIZE == 0 && + size >= TRANSLOG_MIN_FILE_SIZE && + size <= 0xffffffffL); + log_descriptor.log_file_max_size= size; /* if current file longer then finish it*/ if (LSN_OFFSET(log_descriptor.horizon) >= log_descriptor.log_file_max_size) { @@ -7231,6 +7229,6 @@ uint32 translog_set_file_size(uint32 size) translog_buffer_unlock(old_buffer); } translog_unlock(); - return (res); + DBUG_VOID_RETURN; } diff --git a/storage/maria/ma_loghandler.h b/storage/maria/ma_loghandler.h index 8d8494696bf..da233f2d715 100644 --- a/storage/maria/ma_loghandler.h +++ b/storage/maria/ma_loghandler.h @@ -21,7 +21,7 @@ /* transaction log default file size */ #define TRANSLOG_FILE_SIZE (1024*1024*1024) /* minimum possible transaction log size */ -#define TRANSLOG_MIN_FILE_SIZE (1024*1024*4) +#define TRANSLOG_MIN_FILE_SIZE (1024*1024*8) /* transaction log default flags (TODO: make it global variable) */ #define TRANSLOG_DEFAULT_FLAGS 0 @@ -313,8 +313,7 @@ extern my_bool translog_purge_at_flush(); extern uint32 translog_get_first_file(TRANSLOG_ADDRESS horizon); extern uint32 translog_get_first_needed_file(); extern char *translog_filename_by_fileno(uint32 file_no, char *path); -extern uint32 translog_get_file_size(); -extern uint32 translog_set_file_size(uint32 size); +extern void translog_set_file_size(uint32 size); /* record parts descriptor */ struct st_translog_parts diff --git a/storage/maria/unittest/ma_test_loghandler-t.c b/storage/maria/unittest/ma_test_loghandler-t.c index a5a85c2e589..6c0b8614285 100644 --- a/storage/maria/unittest/ma_test_loghandler-t.c +++ b/storage/maria/unittest/ma_test_loghandler-t.c @@ -18,12 +18,12 @@ static TRN *trn= &dummy_transaction_object; #ifdef LONG_LOG_TEST #define LOG_FLAGS 0 -#define LOG_FILE_SIZE (1024L*1024L) +#define LOG_FILE_SIZE (1024L*1024L*8) #define ITERATIONS (1600*4) #else #define LOG_FLAGS (TRANSLOG_SECTOR_PROTECTION | TRANSLOG_PAGE_CRC) -#define LOG_FILE_SIZE (1024L*1024L*3L) +#define LOG_FILE_SIZE (1024L*1024L*8L) #define ITERATIONS 1600 #endif