summaryrefslogtreecommitdiff
path: root/storage/xtradb/log/log0log.c
diff options
context:
space:
mode:
Diffstat (limited to 'storage/xtradb/log/log0log.c')
-rw-r--r--storage/xtradb/log/log0log.c116
1 files changed, 115 insertions, 1 deletions
diff --git a/storage/xtradb/log/log0log.c b/storage/xtradb/log/log0log.c
index 9b09d52e576..74b0abb2087 100644
--- a/storage/xtradb/log/log0log.c
+++ b/storage/xtradb/log/log0log.c
@@ -36,6 +36,12 @@ Created 12/9/1995 Heikki Tuuri
#include "log0log.ic"
#endif
+#ifdef HAVE_ALLOCA_H
+#include "alloca.h"
+#elif defined(HAVE_MALLOC_H)
+#include "malloc.h"
+#endif
+
#ifndef UNIV_HOTBACKUP
#include "mem0mem.h"
#include "buf0buf.h"
@@ -264,6 +270,85 @@ log_check_tracking_margin(
return tracked_lsn_age + lsn_advance > log_sys->max_checkpoint_age;
}
+/** 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=alloca(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;
+ memset(log_sys->buf, '\0', 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.
@return start lsn of the log record */
@@ -281,10 +366,38 @@ log_open(
#endif /* UNIV_LOG_ARCHIVE */
ulint count = 0;
- 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:
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 */
@@ -901,6 +1014,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);