Commit 7f9dc0d8 authored by Eugene Kosov's avatar Eugene Kosov

split log_t::buf into two buffers

Maybe this patch will help catch problems like buffer overflow.

log_t::first_in_use: removed

log_t::buf: this is where mtr_t are supposed to append data
log_t::flush_buf: this is from server writes to a file

Those two buffers are std::swap()ped when some thread is gonna write
to a file
parent 1fbdcada
......@@ -1246,10 +1246,11 @@ buf_madvise_do_dump()
/* mirrors allocation in log_t::create() */
if (log_sys.buf) {
ret+= madvise(log_sys.first_in_use
? log_sys.buf
: log_sys.buf - srv_log_buffer_size,
srv_log_buffer_size * 2,
ret += madvise(log_sys.buf,
srv_log_buffer_size,
MADV_DODUMP);
ret += madvise(log_sys.flush_buf,
srv_log_buffer_size,
MADV_DODUMP);
}
/* mirrors recv_sys_init() */
......
......@@ -524,19 +524,11 @@ struct log_t{
mtr_commit and still ensure that
insertions in the flush_list happen
in the LSN order. */
byte* buf; /*!< Memory of double the
srv_log_buffer_size is
allocated here. This pointer will change
however to either the first half or the
second half in turns, so that log
write/flush to disk don't block
concurrent mtrs which will write
log to this buffer. Care to switch back
to the first half before freeing/resizing
must be undertaken. */
bool first_in_use; /*!< true if buf points to the first
half of the buffer, false
if the second half */
/** log_buffer, append data here */
byte* buf;
/** log_buffer, writing data to file from this buffer.
Before flushing write_buf is swapped with flush_buf */
byte* flush_buf;
ulong max_buf_free; /*!< recommended maximum value of
buf_free for the buffer in use, after
which the buffer is flushed */
......
......@@ -162,16 +162,19 @@ log_buf_pool_get_oldest_modification(void)
void log_buffer_extend(ulong len)
{
const ulong new_buf_size = ut_calc_align(len, srv_page_size);
byte* new_buf = static_cast<byte*>(
ut_malloc_dontdump(new_buf_size * 2));
TRASH_ALLOC(new_buf, new_buf_size * 2);
byte* new_buf = static_cast<byte*>(ut_malloc_dontdump(new_buf_size));
TRASH_ALLOC(new_buf, new_buf_size);
byte* new_flush_buf =
static_cast<byte*>(ut_malloc_dontdump(new_buf_size));
TRASH_ALLOC(new_flush_buf, new_buf_size);
log_mutex_enter();
if (len <= srv_log_buffer_size) {
/* Already extended enough by the others */
log_mutex_exit();
ut_free_dodump(new_buf, new_buf_size * 2);
ut_free_dodump(new_buf, new_buf_size);
ut_free_dodump(new_flush_buf, new_buf_size);
return;
}
......@@ -179,14 +182,14 @@ void log_buffer_extend(ulong len)
" exceeds innodb_log_buffer_size="
<< srv_log_buffer_size << " / 2). Trying to extend it.";
const byte* old_buf_begin = log_sys.buf;
byte* old_buf = log_sys.buf;
byte* old_flush_buf = log_sys.flush_buf;
const ulong old_buf_size = srv_log_buffer_size;
byte* old_buf = log_sys.first_in_use
? log_sys.buf : log_sys.buf - old_buf_size;
srv_log_buffer_size = new_buf_size;
log_sys.buf = new_buf;
log_sys.first_in_use = true;
memcpy(log_sys.buf, old_buf_begin, log_sys.buf_free);
log_sys.flush_buf = new_flush_buf;
memcpy(new_buf, old_buf, log_sys.buf_free);
log_sys.max_buf_free = new_buf_size / LOG_BUF_FLUSH_RATIO
- LOG_BUF_FLUSH_MARGIN;
......@@ -194,6 +197,7 @@ void log_buffer_extend(ulong len)
log_mutex_exit();
ut_free_dodump(old_buf, old_buf_size);
ut_free_dodump(old_flush_buf, old_buf_size);
ib::info() << "innodb_log_buffer_size was extended to "
<< new_buf_size << ".";
......@@ -547,10 +551,10 @@ void log_t::create()
ut_ad(srv_log_buffer_size >= 16 * OS_FILE_LOG_BLOCK_SIZE);
ut_ad(srv_log_buffer_size >= 4U << srv_page_size_shift);
buf= static_cast<byte*>(ut_malloc_dontdump(srv_log_buffer_size * 2));
TRASH_ALLOC(buf, srv_log_buffer_size * 2);
first_in_use= true;
buf= static_cast<byte*>(ut_malloc_dontdump(srv_log_buffer_size));
TRASH_ALLOC(buf, srv_log_buffer_size);
flush_buf= static_cast<byte*>(ut_malloc_dontdump(srv_log_buffer_size));
TRASH_ALLOC(flush_buf, srv_log_buffer_size);
max_buf_free= srv_log_buffer_size / LOG_BUF_FLUSH_RATIO -
LOG_BUF_FLUSH_MARGIN;
......@@ -824,8 +828,8 @@ log_write_flush_to_disk_low()
os_event_set(log_sys.flush_event);
}
/** Switch the log buffer in use, and copy the content of last block
from old log buffer to the head of the to be used one. Thus, buf_free and
/** Swap log buffers, and copy the content of last block
from old buf to the head of the new buf. Thus, buf_free and
buf_next_to_write would be changed accordingly */
static inline
void
......@@ -834,27 +838,16 @@ log_buffer_switch()
ut_ad(log_mutex_own());
ut_ad(log_write_mutex_own());
const byte* old_buf = log_sys.buf;
ulong area_end = ut_calc_align(
log_sys.buf_free, ulong(OS_FILE_LOG_BLOCK_SIZE));
if (log_sys.first_in_use) {
log_sys.first_in_use = false;
ut_ad(log_sys.buf == ut_align(log_sys.buf,
OS_FILE_LOG_BLOCK_SIZE));
log_sys.buf += srv_log_buffer_size;
} else {
log_sys.first_in_use = true;
log_sys.buf -= srv_log_buffer_size;
ut_ad(log_sys.buf == ut_align(log_sys.buf,
OS_FILE_LOG_BLOCK_SIZE));
}
/* Copy the last block to new buf */
ut_memcpy(log_sys.buf,
old_buf + area_end - OS_FILE_LOG_BLOCK_SIZE,
ut_memcpy(log_sys.flush_buf,
log_sys.buf + area_end - OS_FILE_LOG_BLOCK_SIZE,
OS_FILE_LOG_BLOCK_SIZE);
std::swap(log_sys.buf, log_sys.flush_buf);
log_sys.buf_free %= OS_FILE_LOG_BLOCK_SIZE;
log_sys.buf_next_to_write = log_sys.buf_free;
}
......@@ -1942,10 +1935,10 @@ void log_t::close()
m_initialised = false;
log.close();
if (!first_in_use)
buf -= srv_log_buffer_size;
ut_free_dodump(buf, srv_log_buffer_size * 2);
ut_free_dodump(buf, srv_log_buffer_size);
buf = NULL;
ut_free_dodump(flush_buf, srv_log_buffer_size);
flush_buf = NULL;
os_event_destroy(flush_event);
rw_lock_free(&checkpoint_lock);
......
......@@ -502,6 +502,7 @@ create_log_files(
memset(log_sys.buf, 0, srv_log_buffer_size);
log_block_init(log_sys.buf, log_sys.lsn);
log_block_set_first_rec_group(log_sys.buf, LOG_BLOCK_HDR_SIZE);
memset(log_sys.flush_buf, 0, srv_log_buffer_size);
log_sys.buf_free = LOG_BLOCK_HDR_SIZE;
log_sys.lsn += LOG_BLOCK_HDR_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