=== modified file 'storage/innobase/handler/ha_innodb.cc' --- storage/innobase/handler/ha_innodb.cc 2013-07-25 10:01:06 +0000 +++ storage/innobase/handler/ha_innodb.cc 2013-11-19 05:17:47 +0000 @@ -131,6 +131,7 @@ static ulong innobase_read_io_threads; static ulong innobase_write_io_threads; static long innobase_buffer_pool_instances = 1; +static long innobase_log_copy_mutexes = 64; static long long innobase_buffer_pool_size, innobase_log_file_size; @@ -2462,6 +2463,9 @@ srv_file_flush_method_str = innobase_file_flush_method; + srv_n_log_copy_mutexes = (ulint) innobase_log_copy_mutexes; + srv_log_copy_mutex_ctl_len = (ulint) innobase_log_buffer_size + / innobase_log_copy_mutexes; srv_n_log_groups = (ulint) innobase_mirrored_log_groups; srv_n_log_files = (ulint) innobase_log_files_in_group; srv_log_file_size = (ulint) innobase_log_file_size; @@ -11645,6 +11649,11 @@ "Number of log files in the log group. InnoDB writes to the files in a circular fashion. Value 3 is recommended here.", NULL, NULL, 2, 2, 100, 0); +static MYSQL_SYSVAR_LONG(log_copy_mutexes, innobase_log_copy_mutexes, + PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY, + "Number of log copy mutex in redo log buffer.", + NULL, NULL, 64, 1, 256, 2); + static MYSQL_SYSVAR_LONG(mirrored_log_groups, innobase_mirrored_log_groups, PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY, "Number of identical copies of log groups we keep for the database. Currently this should be set to 1.", @@ -11808,6 +11817,7 @@ MYSQL_SYSVAR(log_archive), #endif /* UNIV_LOG_ARCHIVE */ MYSQL_SYSVAR(log_buffer_size), + MYSQL_SYSVAR(log_copy_mutexes), MYSQL_SYSVAR(log_file_size), MYSQL_SYSVAR(log_files_in_group), MYSQL_SYSVAR(log_group_home_dir), === modified file 'storage/innobase/include/log0log.h' --- storage/innobase/include/log0log.h 2012-07-25 08:23:01 +0000 +++ storage/innobase/include/log0log.h 2013-11-19 05:21:29 +0000 @@ -96,6 +96,20 @@ ib_int64_t log_file_size); /*!< in: log file size (including the header) */ #ifndef UNIV_HOTBACKUP +/******************************************************//** +Try to get requested copy mutexes. */ +UNIV_INLINE +void +log_copy_mutexes_enter( + ulint first_copy_mutex_index, + ulint last_copy_mutex_index); +/******************************************************//** +Release requested copy mutexes. */ +UNIV_INLINE +void +log_copy_mutexes_exit( + ulint first_copy_mutex_index, + ulint last_copy_mutex_index); /************************************************************//** Writes to the log the string given. The log must be released with log_release. @@ -702,6 +716,8 @@ #define LOG_GROUP_OK 301 #define LOG_GROUP_CORRUPTED 302 +#define GET_COPY_MUTEX_INDEX(A) ((ulint)(A) / srv_log_copy_mutex_ctl_len) + /** Log group consists of a number of log files, each of the same size; a log group is implemented as a space in the sense of the module fil0fil. */ struct log_group_struct{ @@ -764,7 +780,9 @@ ulint buf_free; /*!< first free offset within the log buffer */ #ifndef UNIV_HOTBACKUP - mutex_t mutex; /*!< mutex protecting the log */ + mutex_t mutex; /*!< mutex protecting the log allocation */ + mutex_t write_mutex; /*!< mutex protecting write from log buffer to log file */ + mutex_t** copy_mutex; /*!< mutex protecting the process that copy to log buffer */ mutex_t log_flush_order_mutex;/*!< mutex to serialize access to the flush list when we are putting @@ -977,6 +995,17 @@ mutex_exit(&log_sys->log_flush_order_mutex); \ } while (0) +/** Acquire the copy mutex. */ +#define log_copy_mutex_enter(I) do { \ + ut_a(I < srv_n_log_copy_mutexes); \ + mutex_enter(log_sys->copy_mutex[I]); \ +} while (0) +/** Release the copy mutex. */ +# define log_copy_mutex_exit(I) do { \ + ut_a(I < srv_n_log_copy_mutexes); \ + mutex_exit(log_sys->copy_mutex[I]); \ +} while (0) + #ifdef UNIV_LOG_ARCHIVE /** Archiving state @{ */ #define LOG_ARCH_ON 71 === modified file 'storage/innobase/include/log0log.ic' --- storage/innobase/include/log0log.ic 2013-06-10 20:29:41 +0000 +++ storage/innobase/include/log0log.ic 2013-11-19 05:17:47 +0000 @@ -26,6 +26,7 @@ #include "os0file.h" #include "mach0data.h" #include "mtr0mtr.h" +#include "srv0srv.h" #ifdef UNIV_LOG_DEBUG /******************************************************//** @@ -298,6 +299,42 @@ log_block_set_first_rec_group(log_block, 0); } +/******************************************************//** +Try to get requested copy mutexes. */ +UNIV_INLINE +void +log_copy_mutexes_enter( + ulint first_copy_mutex_index, + ulint last_copy_mutex_index) +{ + ulint i; + + ut_a(first_copy_mutex_index < srv_n_log_copy_mutexes); + ut_a(last_copy_mutex_index < srv_n_log_copy_mutexes); + + for (i = first_copy_mutex_index; i <= last_copy_mutex_index; ++i) { + log_copy_mutex_enter(i); + } +} + +/******************************************************//** +Release requested copy mutexes. */ +UNIV_INLINE +void +log_copy_mutexes_exit( + ulint first_copy_mutex_index, + ulint last_copy_mutex_index) +{ + ulint i; + + ut_a(first_copy_mutex_index < srv_n_log_copy_mutexes); + ut_a(last_copy_mutex_index < srv_n_log_copy_mutexes); + + for (i = first_copy_mutex_index; i <= last_copy_mutex_index; ++i) { + log_copy_mutex_exit(i); + } +} + #ifndef UNIV_HOTBACKUP /************************************************************//** Writes to the log the string given. The log must be released with @@ -312,6 +349,7 @@ ib_uint64_t* start_lsn)/*!< out: start lsn of the log record */ { ulint data_len; + ulint first_copy_mutex_index, last_copy_mutex_index; #ifdef UNIV_LOG_LSN_DEBUG /* length of the LSN pseudo-record */ ulint lsn_len; @@ -342,6 +380,11 @@ *start_lsn = log_sys->lsn; + first_copy_mutex_index = GET_COPY_MUTEX_INDEX(log_sys->buf_free); + last_copy_mutex_index = GET_COPY_MUTEX_INDEX(log_sys->buf_free + len - 1); + + log_copy_mutexes_enter(first_copy_mutex_index, last_copy_mutex_index); + #ifdef UNIV_LOG_LSN_DEBUG { /* Write the LSN pseudo-record. */ @@ -379,6 +422,8 @@ log_sys->buf_free - log_sys->old_buf_free, log_sys->old_lsn); #endif + log_copy_mutexes_exit(first_copy_mutex_index, last_copy_mutex_index); + return(log_sys->lsn); } === modified file 'storage/innobase/include/srv0srv.h' --- storage/innobase/include/srv0srv.h 2013-06-10 20:29:41 +0000 +++ storage/innobase/include/srv0srv.h 2013-11-19 05:17:47 +0000 @@ -134,6 +134,8 @@ extern ibool srv_created_new_raw; +extern ulint srv_log_copy_mutex_ctl_len; +extern ulint srv_n_log_copy_mutexes; extern ulint srv_n_log_groups; extern ulint srv_n_log_files; extern ulint srv_log_file_size; === modified file 'storage/innobase/include/sync0sync.h' --- storage/innobase/include/sync0sync.h 2013-06-10 19:50:25 +0000 +++ storage/innobase/include/sync0sync.h 2013-11-19 05:22:38 +0000 @@ -669,6 +669,8 @@ #define SYNC_TRX_SYS_HEADER 290 #define SYNC_PURGE_QUEUE 200 #define SYNC_LOG 170 +#define SYNC_LOG_COPY 171 +#define SYNC_LOG_WRITE 172 #define SYNC_LOG_FLUSH_ORDER 147 #define SYNC_RECV 168 #define SYNC_WORK_QUEUE 162 === modified file 'storage/innobase/log/log0log.c' --- storage/innobase/log/log0log.c 2012-03-21 03:48:12 +0000 +++ storage/innobase/log/log0log.c 2013-11-19 06:15:44 +0000 @@ -91,6 +91,8 @@ #ifdef UNIV_PFS_MUTEX UNIV_INTERN mysql_pfs_key_t log_sys_mutex_key; +UNIV_INTERN mysql_pfs_key_t log_sys_copy_mutex_key; +UNIV_INTERN mysql_pfs_key_t log_sys_write_mutex_key; UNIV_INTERN mysql_pfs_key_t log_flush_order_mutex_key; #endif /* UNIV_PFS_MUTEX */ @@ -302,8 +304,15 @@ ulint len; ulint data_len; byte* log_block; + ulint copy_mutex_index; + ulint first_copy_mutex_index, last_copy_mutex_index; ut_ad(mutex_own(&(log->mutex))); + + copy_mutex_index = GET_COPY_MUTEX_INDEX(log->buf_free); + first_copy_mutex_index = copy_mutex_index; + + log_copy_mutex_enter(copy_mutex_index); part_loop: ut_ad(!recv_no_log_write); /* Calculate a part length */ @@ -323,6 +332,11 @@ - LOG_BLOCK_TRL_SIZE; } + if (copy_mutex_index != GET_COPY_MUTEX_INDEX(log->buf_free + len - 1)) { // Another Mutex + copy_mutex_index = GET_COPY_MUTEX_INDEX(log->buf_free + len - 1); + log_copy_mutex_enter(copy_mutex_index); + } + ut_memcpy(log->buf + log->buf_free, str, len); str_len -= len; @@ -355,6 +369,10 @@ goto part_loop; } + last_copy_mutex_index = copy_mutex_index; + + log_copy_mutexes_exit(first_copy_mutex_index, last_copy_mutex_index); + srv_log_write_requests++; } @@ -494,7 +512,8 @@ /*===================*/ const log_group_t* group) /*!< in: log group */ { - ut_ad(mutex_own(&(log_sys->mutex))); + /* Nobody can modify file_size and n_files online */ + //ut_ad(mutex_own(&(log_sys->mutex))); return((group->file_size - LOG_FILE_HDR_SIZE) * group->n_files); } @@ -511,7 +530,8 @@ log group */ const log_group_t* group) /*!< in: log group */ { - ut_ad(mutex_own(&(log_sys->mutex))); + /* Nobody can modify file_size online */ + //ut_ad(mutex_own(&(log_sys->write_mutex))); return(offset - LOG_FILE_HDR_SIZE * (1 + offset / group->file_size)); } @@ -528,7 +548,8 @@ log group */ const log_group_t* group) /*!< in: log group */ { - ut_ad(mutex_own(&(log_sys->mutex))); + /* Nobody can modify file_size online */ + //ut_ad(mutex_own(&(log_sys->write_mutex))); return(offset + LOG_FILE_HDR_SIZE * (1 + offset / (group->file_size - LOG_FILE_HDR_SIZE))); @@ -551,7 +572,8 @@ ib_int64_t group_size; ib_int64_t offset; - ut_ad(mutex_own(&(log_sys->mutex))); + + ut_ad(mutex_own(&(log_sys->write_mutex))); /* If total log file size is > 2 GB we can easily get overflows with 32-bit integers. Use 64-bit integers instead. */ @@ -766,9 +788,18 @@ log_init(void) /*==========*/ { + uint i; + log_sys = mem_alloc(sizeof(log_t)); mutex_create(log_sys_mutex_key, &log_sys->mutex, SYNC_LOG); + mutex_create(log_sys_write_mutex_key, &log_sys->write_mutex, SYNC_LOG_WRITE); + + log_sys->copy_mutex = (mutex_t **) ut_malloc(sizeof(mutex_t*) * srv_n_log_copy_mutexes); + for (i = 0; i < srv_n_log_copy_mutexes; ++i) { + log_sys->copy_mutex[i] = (mutex_t *) ut_malloc(sizeof(mutex_t)); + mutex_create(log_sys_copy_mutex_key, log_sys->copy_mutex[i], SYNC_LOG_COPY); + } mutex_create(log_flush_order_mutex_key, &log_sys->log_flush_order_mutex, @@ -1055,6 +1086,7 @@ if (log_sys->write_end_offset > log_sys->max_buf_free / 2) { /* Move the log buffer content to the start of the buffer */ + log_copy_mutexes_enter(0, srv_n_log_copy_mutexes - 1); move_start = ut_calc_align_down( log_sys->write_end_offset, @@ -1067,6 +1099,8 @@ log_sys->buf_free -= move_start; log_sys->buf_next_to_write -= move_start; + + log_copy_mutexes_exit(0, srv_n_log_copy_mutexes - 1); } return(LOG_UNLOCK_FLUSH_LOCK); @@ -1159,7 +1193,7 @@ byte* buf; ulint dest_offset; - ut_ad(mutex_own(&(log_sys->mutex))); + ut_ad(mutex_own(&(log_sys->write_mutex))); ut_ad(!recv_no_log_write); ut_a(nth_file < group->n_files); @@ -1231,7 +1265,7 @@ ulint next_offset; ulint i; - ut_ad(mutex_own(&(log_sys->mutex))); + ut_ad(mutex_own(&(log_sys->write_mutex))); ut_ad(!recv_no_log_write); ut_a(len % OS_FILE_LOG_BLOCK_SIZE == 0); ut_a(((ulint) start_lsn) % OS_FILE_LOG_BLOCK_SIZE == 0); @@ -1326,6 +1360,7 @@ } } + /******************************************************//** This function is called, e.g., when a transaction wants to commit. It checks that the log has been written to the log file up to the last log entry written @@ -1353,6 +1388,7 @@ ulint loop_count = 0; #endif /* UNIV_DEBUG */ ulint unlock; + ulint first_copy_mutex_index, last_copy_mutex_index; if (recv_no_ibuf_operations) { /* Recovery is running and no operations on the log files are @@ -1441,6 +1477,7 @@ log_sys->lsn); } #endif /* UNIV_DEBUG */ + log_sys->n_pending_writes++; group = UT_LIST_GET_FIRST(log_sys->log_groups); @@ -1450,6 +1487,8 @@ os_event_reset(log_sys->no_flush_event); os_event_reset(log_sys->one_flushed_event); + mutex_enter(&(log_sys->write_mutex)); + start_offset = log_sys->buf_next_to_write; end_offset = log_sys->buf_free; @@ -1484,6 +1523,13 @@ group = UT_LIST_GET_FIRST(log_sys->log_groups); + first_copy_mutex_index = GET_COPY_MUTEX_INDEX(area_start); + last_copy_mutex_index = GET_COPY_MUTEX_INDEX(area_end); + + log_copy_mutexes_enter(first_copy_mutex_index, last_copy_mutex_index); + + mutex_exit(&(log_sys->mutex)); + /* Do the write to the log files */ while (group) { @@ -1499,7 +1545,9 @@ group = UT_LIST_GET_NEXT(log_groups, group); } - mutex_exit(&(log_sys->mutex)); + log_copy_mutexes_exit(first_copy_mutex_index, last_copy_mutex_index); + + mutex_exit(&(log_sys->write_mutex)); if (srv_unix_file_flush_method == SRV_UNIX_O_DSYNC) { /* O_DSYNC means the OS did not buffer the log file at all: @@ -1762,7 +1810,7 @@ byte* buf; ulint i; - ut_ad(mutex_own(&(log_sys->mutex))); + ut_ad(mutex_own(&(log_sys->write_mutex))); #if LOG_CHECKPOINT_SIZE > OS_FILE_LOG_BLOCK_SIZE # error "LOG_CHECKPOINT_SIZE > OS_FILE_LOG_BLOCK_SIZE" #endif @@ -1947,7 +1995,7 @@ { log_group_t* group; - ut_ad(mutex_own(&(log_sys->mutex))); + ut_ad(mutex_own(&(log_sys->write_mutex))); group = UT_LIST_GET_FIRST(log_sys->log_groups); @@ -2040,9 +2088,13 @@ } #endif /* UNIV_DEBUG */ + mutex_enter(&(log_sys->write_mutex)); + + mutex_exit(&(log_sys->mutex)); + log_groups_write_checkpoint_info(); - mutex_exit(&(log_sys->mutex)); + mutex_exit(&(log_sys->write_mutex)); if (sync) { /* Wait for the checkpoint write to complete */ @@ -3521,6 +3573,7 @@ /*==============*/ { log_group_t* group; + uint i; group = UT_LIST_GET_FIRST(log_sys->log_groups); @@ -3546,6 +3599,14 @@ rw_lock_free(&log_sys->checkpoint_lock); mutex_free(&log_sys->mutex); + mutex_free(&log_sys->write_mutex); + + for(i = 0; i < srv_n_log_copy_mutexes; ++i) + { + mutex_free(log_sys->copy_mutex[i]); + ut_free(log_sys->copy_mutex[i]); + } + ut_free(log_sys->copy_mutex); #ifdef UNIV_LOG_ARCHIVE rw_lock_free(&log_sys->archive_lock); === modified file 'storage/innobase/log/log0recv.c' --- storage/innobase/log/log0recv.c 2013-06-10 20:29:41 +0000 +++ storage/innobase/log/log0recv.c 2013-11-19 06:04:49 +0000 @@ -581,6 +581,8 @@ ut_a(start_lsn != end_lsn); + mutex_enter(&(log_sys->write_mutex)); + log_group_read_log_seg(LOG_RECOVER, recv_sys->last_block, up_to_date_group, start_lsn, end_lsn); @@ -610,6 +612,8 @@ log_groups_write_checkpoint_info(); + mutex_exit(&(log_sys->write_mutex)); + mutex_exit(&(log_sys->mutex)); /* Wait for the checkpoint write to complete */ @@ -2812,6 +2816,8 @@ start_lsn = *contiguous_lsn; + mutex_enter(&(log_sys->write_mutex)); + while (!finished) { end_lsn = start_lsn + RECV_SCAN_SIZE; @@ -2827,6 +2833,8 @@ start_lsn = end_lsn; } + mutex_exit(&(log_sys->write_mutex)); + #ifdef UNIV_DEBUG if (log_debug_writes) { fprintf(stderr, === modified file 'storage/innobase/srv/srv0srv.c' --- storage/innobase/srv/srv0srv.c 2013-07-29 09:16:16 +0000 +++ storage/innobase/srv/srv0srv.c 2013-11-19 05:17:47 +0000 @@ -181,6 +181,8 @@ UNIV_INTERN ulint srv_n_log_groups = ULINT_MAX; UNIV_INTERN ulint srv_n_log_files = ULINT_MAX; +UNIV_INTERN ulint srv_n_log_copy_mutexes = ULINT_MAX; +UNIV_INTERN ulint srv_log_copy_mutex_ctl_len = ULINT_MAX; /* size in database pages */ UNIV_INTERN ulint srv_log_file_size = ULINT_MAX; /* size in database pages */ === modified file 'storage/innobase/sync/sync0sync.c' --- storage/innobase/sync/sync0sync.c 2013-06-10 19:50:25 +0000 +++ storage/innobase/sync/sync0sync.c 2013-11-19 05:17:47 +0000 @@ -1213,6 +1213,8 @@ case SYNC_RECV: case SYNC_WORK_QUEUE: case SYNC_LOG: + case SYNC_LOG_COPY: + case SYNC_LOG_WRITE: case SYNC_LOG_FLUSH_ORDER: case SYNC_ANY_LATCH: case SYNC_FILE_FORMAT_TAG: