diff options
author | Yasufumi Kinoshita <yasufumi.kinoshita@oracle.com> | 2013-09-30 13:41:48 +0900 |
---|---|---|
committer | Yasufumi Kinoshita <yasufumi.kinoshita@oracle.com> | 2013-09-30 13:41:48 +0900 |
commit | 47312f19cb79d833d7b52d29761d8277360f99c9 (patch) | |
tree | d869d94f7127fbbe8179cafc3f5501fdcd812dee /storage | |
parent | 57df886c9f145d1614c1dcaff1a455136dace4a2 (diff) | |
download | mariadb-git-47312f19cb79d833d7b52d29761d8277360f99c9.tar.gz |
Bug#11758196 : INNODB ASSERTION FAILURE WHEN CONVERTING FROM MYISAM TO INNODB
Changed to try to extend log buffer instead of crash, when log size is too large for the size.
Approved by Marko in rb#3229
Diffstat (limited to 'storage')
-rw-r--r-- | storage/innobase/include/log0log.h | 2 | ||||
-rw-r--r-- | storage/innobase/log/log0log.c | 109 |
2 files changed, 110 insertions, 1 deletions
diff --git a/storage/innobase/include/log0log.h b/storage/innobase/include/log0log.h index 5524272d811..b0e5e9bda3b 100644 --- a/storage/innobase/include/log0log.h +++ b/storage/innobase/include/log0log.h @@ -809,6 +809,8 @@ struct log_struct{ later; this is advanced when a flush operation is completed to all the log groups */ + volatile ibool is_extending; /*!< this is set to true during extend + the log buffer size */ ib_uint64_t written_to_some_lsn; /*!< first log sequence number not yet written to any log group; for this to diff --git a/storage/innobase/log/log0log.c b/storage/innobase/log/log0log.c index 8bae95f0a5d..046c494c99d 100644 --- a/storage/innobase/log/log0log.c +++ b/storage/innobase/log/log0log.c @@ -213,6 +213,84 @@ log_buf_pool_get_oldest_modification(void) return(lsn); } +/** Extends the log buffer. +@param[in] len requested minimum size in bytes */ +static +void +log_buffer_extend( + ulint len) +{ + ulint move_start; + ulint move_end; + byte tmp_buf[OS_FILE_LOG_BLOCK_SIZE]; + + mutex_enter(&(log_sys->mutex)); + + while (log_sys->is_extending) { + /* Another thread is trying to extend already. + Needs to wait for. */ + mutex_exit(&(log_sys->mutex)); + + log_buffer_flush_to_disk(); + + mutex_enter(&(log_sys->mutex)); + + if (srv_log_buffer_size > len / UNIV_PAGE_SIZE) { + /* Already extended enough by the others */ + mutex_exit(&(log_sys->mutex)); + return; + } + } + + log_sys->is_extending = TRUE; + + while (log_sys->n_pending_writes != 0 + || ut_calc_align_down(log_sys->buf_free, + OS_FILE_LOG_BLOCK_SIZE) + != ut_calc_align_down(log_sys->buf_next_to_write, + OS_FILE_LOG_BLOCK_SIZE)) { + /* Buffer might have >1 blocks to write still. */ + mutex_exit(&(log_sys->mutex)); + + log_buffer_flush_to_disk(); + + mutex_enter(&(log_sys->mutex)); + } + + move_start = ut_calc_align_down( + log_sys->buf_free, + OS_FILE_LOG_BLOCK_SIZE); + move_end = log_sys->buf_free; + + /* store the last log block in buffer */ + ut_memcpy(tmp_buf, log_sys->buf + move_start, + move_end - move_start); + + log_sys->buf_free -= move_start; + log_sys->buf_next_to_write -= move_start; + + /* reallocate log buffer */ + srv_log_buffer_size = len / UNIV_PAGE_SIZE + 1; + mem_free(log_sys->buf_ptr); + log_sys->buf_ptr = mem_alloc(LOG_BUFFER_SIZE + OS_FILE_LOG_BLOCK_SIZE); + log_sys->buf = ut_align(log_sys->buf_ptr, OS_FILE_LOG_BLOCK_SIZE); + log_sys->buf_size = LOG_BUFFER_SIZE; + log_sys->max_buf_free = log_sys->buf_size / LOG_BUF_FLUSH_RATIO + - LOG_BUF_FLUSH_MARGIN; + + /* restore the last log block */ + ut_memcpy(log_sys->buf, tmp_buf, move_end - move_start); + + ut_ad(log_sys->is_extending); + log_sys->is_extending = FALSE; + + mutex_exit(&(log_sys->mutex)); + + fprintf(stderr, + "InnoDB: innodb_log_buffer_size was extended to %lu.\n", + LOG_BUFFER_SIZE); +} + /************************************************************//** Opens the log for log_write_low. The log must be closed with log_close and released with log_release. @@ -233,11 +311,39 @@ log_reserve_and_open( ulint count = 0; #endif /* UNIV_DEBUG */ - ut_a(len < log->buf_size / 2); + if (len >= log->buf_size / 2) { + DBUG_EXECUTE_IF("ib_log_buffer_is_short_crash", + DBUG_SUICIDE();); + + /* log_buffer is too small. try to extend instead of crash. */ + ut_print_timestamp(stderr); + fprintf(stderr, + " InnoDB: Warning: " + "The transaction log size is too large" + " for innodb_log_buffer_size (%lu >= %lu / 2). " + "Trying to extend it.\n", + len, LOG_BUFFER_SIZE); + + log_buffer_extend((len + 1) * 2); + } loop: mutex_enter(&(log->mutex)); ut_ad(!recv_no_log_write); + if (log->is_extending) { + + mutex_exit(&(log->mutex)); + + /* Log buffer size is extending. Writing up to the next block + should wait for the extending finished. */ + + os_thread_sleep(100000); + + ut_ad(++count < 50); + + goto loop; + } + /* Calculate an upper limit for the space the string may take in the log buffer */ @@ -788,6 +894,7 @@ log_init(void) log_sys->buf = ut_align(log_sys->buf_ptr, OS_FILE_LOG_BLOCK_SIZE); log_sys->buf_size = LOG_BUFFER_SIZE; + log_sys->is_extending = FALSE; memset(log_sys->buf, '\0', LOG_BUFFER_SIZE); |