Commit 47312f19 authored by Yasufumi Kinoshita's avatar Yasufumi Kinoshita

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
parent 57df886c
......@@ -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
......
......@@ -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);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment