Commit 5ad18f12 authored by Sergei Golubchik's avatar Sergei Golubchik

percona-server-5.5.36-34.0

parents 9ae0471e 7996f506
......@@ -1605,17 +1605,8 @@ buf_flush_page_and_try_neighbors(
ut_ad(block_mutex);
}
if (UNIV_UNLIKELY(buf_page_get_state(bpage)
== BUF_BLOCK_REMOVE_HASH)) {
/* In case we don't hold the LRU list mutex, we may see a page
that is about to be relocated on the flush list. Do not
attempt to flush it. */
ut_ad(flush_type == BUF_FLUSH_LIST);
return (flushed);
}
ut_a(buf_page_in_file(bpage));
ut_a(buf_page_in_file(bpage)
|| buf_page_get_state(bpage) == BUF_BLOCK_REMOVE_HASH);
if (buf_flush_ready_for_flush(bpage, flush_type)) {
ulint space;
......@@ -1631,8 +1622,10 @@ buf_flush_page_and_try_neighbors(
/* These fields are protected by both the
buffer pool mutex and block mutex. */
space = buf_page_get_space(bpage);
offset = buf_page_get_page_no(bpage);
/* Read the fields directly in order to avoid asserting on
BUF_BLOCK_REMOVE_HASH pages. */
space = bpage->space;
offset = bpage->offset;
if (flush_type == BUF_FLUSH_LRU) {
mutex_exit(block_mutex);
......
......@@ -65,6 +65,7 @@ UNIV_INTERN uint ibuf_debug;
#include "srv0start.h" /* SRV_LOG_SPACE_FIRST_ID */
#include "m_string.h"
#include "my_sys.h"
#include "lock0lock.h"
#include <ctype.h>
......@@ -1331,6 +1332,7 @@ dict_table_remove_from_cache(
ut_ad(table);
ut_ad(mutex_own(&(dict_sys->mutex)));
ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
ut_ad(lock_table_has_locks(table) == FALSE);
#if 0
fputs("Removing table ", stderr);
......@@ -1383,6 +1385,53 @@ dict_table_remove_from_cache(
dict_mem_table_free(table);
}
/**********************************************************************//**
Test whether a table can be evicted from the LRU cache.
@return TRUE if table can be evicted. */
static
ibool
dict_table_can_be_evicted(
/*======================*/
const dict_table_t* table) /*!< in: table to test */
{
dict_index_t* index;
dict_foreign_t* foreign;
ibool has_locks;
ut_ad(mutex_own(&dict_sys->mutex));
/* bug 758788: A table may not have an active handle opened on it
but may still have locks held on it across multiple statements
within an individual transaction. So a table is not evictable if
there are locks held on it */
has_locks = lock_table_has_locks(table);
if (table->n_mysql_handles_opened || table->is_corrupt || has_locks)
return(FALSE);
/* bug 758788: We are not allowed to free the in-memory index struct
dict_index_t if there are any locks held on any of its indexes. */
for (index = dict_table_get_first_index(table); index != NULL;
index = dict_table_get_next_index(index)) {
rw_lock_t* lock = dict_index_get_lock(index);
if (rw_lock_is_locked(lock, RW_LOCK_SHARED)
|| rw_lock_is_locked(lock, RW_LOCK_EX)) {
return(FALSE);
}
}
for (foreign = UT_LIST_GET_FIRST(table->foreign_list); foreign != NULL;
foreign = UT_LIST_GET_NEXT(foreign_list, foreign)) {
if (foreign->referenced_table) {
return(FALSE);
}
}
return(TRUE);
}
/**************************************************************************
Frees tables from the end of table_LRU if the dictionary cache occupies
too much space. */
......@@ -1394,51 +1443,65 @@ dict_table_LRU_trim(
{
dict_table_t* table;
dict_table_t* prev_table;
dict_foreign_t* foreign;
ulint n_removed;
ulint n_have_parent;
ulint cached_foreign_tables;
ulint dict_size;
ulint max_depth;
ulint max_evict;
ulint visited;
ulint evicted;
#ifdef UNIV_SYNC_DEBUG
ut_ad(mutex_own(&(dict_sys->mutex)));
#endif /* UNIV_SYNC_DEBUG */
retry:
n_removed = n_have_parent = 0;
if (srv_dict_size_limit == 0)
return;
/* Calculate this once here and then once on every eviction */
dict_size = (dict_sys->table_hash->n_cells
+ dict_sys->table_id_hash->n_cells)
* sizeof(hash_cell_t) + dict_sys->size;
/* Just some magic numbers to help keep us from holding the dict mutex
for too long as well as preventing constant full scans of the list in
a memory pressure situation. */
/* Don't go scanning into the front 50% of the list, chances are very
good that there is nothing to be evicted in there and if there is,
it should quickly get pushed into the back 50% */
max_depth = UT_LIST_GET_LEN(dict_sys->table_LRU) / 2;
/* Don't try to evict any more than 10% of evictable tables at once. */
max_evict = UT_LIST_GET_LEN(dict_sys->table_LRU) / 10;
visited = evicted = 0;
table = UT_LIST_GET_LAST(dict_sys->table_LRU);
while ( srv_dict_size_limit && table
&& ((dict_sys->table_hash->n_cells
+ dict_sys->table_id_hash->n_cells) * sizeof(hash_cell_t)
+ dict_sys->size) > srv_dict_size_limit ) {
while (table && dict_size > srv_dict_size_limit
&& visited <= max_depth
&& srv_shutdown_state == SRV_SHUTDOWN_NONE) {
prev_table = UT_LIST_GET_PREV(table_LRU, table);
if (table == self || table->n_mysql_handles_opened || table->is_corrupt)
goto next_loop;
if (table != self && dict_table_can_be_evicted(table)) {
dict_table_remove_from_cache(table);
cached_foreign_tables = 0;
foreign = UT_LIST_GET_FIRST(table->foreign_list);
while (foreign != NULL) {
if (foreign->referenced_table)
cached_foreign_tables++;
foreign = UT_LIST_GET_NEXT(foreign_list, foreign);
}
evicted++;
if (cached_foreign_tables == 0) {
dict_table_remove_from_cache(table);
n_removed++;
} else {
n_have_parent++;
if (evicted >= max_evict)
break;
/* Only need to recalculate this when something
has been evicted */
dict_size = (dict_sys->table_hash->n_cells
+ dict_sys->table_id_hash->n_cells)
* sizeof(hash_cell_t) + dict_sys->size;
}
next_loop:
visited++;
table = prev_table;
}
if ( srv_dict_size_limit && n_have_parent && n_removed
&& ((dict_sys->table_hash->n_cells
+ dict_sys->table_id_hash->n_cells) * sizeof(hash_cell_t)
+ dict_sys->size) > srv_dict_size_limit )
goto retry;
}
/****************************************************************//**
......
......@@ -115,6 +115,7 @@ dict_mem_table_free(
ut_ad(table);
ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
ut_d(table->cached = FALSE);
ut_d(table->magic_n = 0);
#ifndef UNIV_HOTBACKUP
mutex_free(&(table->autoinc_mutex));
......
......@@ -8837,17 +8837,6 @@ innobase_rename_table(
error = row_rename_table_for_mysql(
norm_from, norm_to, trx, lock_and_commit);
if (error != DB_SUCCESS) {
FILE* ef = dict_foreign_err_file;
DBUG_PRINT("info", ("rename failed: %d", error));
fputs("InnoDB: Renaming table ", ef);
ut_print_name(ef, trx, TRUE, norm_from);
fputs(" to ", ef);
ut_print_name(ef, trx, TRUE, norm_to);
fputs(" failed!\n", ef);
}
if (lock_and_commit) {
row_mysql_unlock_data_dictionary(trx);
......
......@@ -459,6 +459,16 @@ lock_sec_rec_cons_read_sees(
by a read cursor */
const read_view_t* view); /*!< in: consistent read view */
/*********************************************************************//**
Check if there are any locks (table or rec) against table.
@return TRUE if locks exist */
UNIV_INLINE
ibool
lock_table_has_locks(
/*=================*/
const dict_table_t* table); /*!< in: check if there are any locks
held on records in this table or on the
table itself */
/*********************************************************************//**
Locks the specified database table in the mode given. If the lock cannot
be granted immediately, the query thread is put to wait.
@return DB_SUCCESS, DB_LOCK_WAIT, DB_DEADLOCK, or DB_QUE_THR_SUSPENDED */
......
......@@ -119,3 +119,17 @@ lock_get_min_heap_no(
FALSE)));
}
}
/*******************************************************************//**
Check if there are any locks (table or rec) against table.
@return TRUE if table has either table or record locks. */
UNIV_INLINE
ibool
lock_table_has_locks(
/*=================*/
const dict_table_t* table) /*!< in: check if there are any locks
held on records in this table or on the
table itself */
{
return(UT_LIST_GET_LEN(table->locks) > 0);
}
......@@ -64,7 +64,7 @@ component, i.e. we show M.N.P as M.N */
(INNODB_VERSION_MAJOR << 8 | INNODB_VERSION_MINOR)
#ifndef PERCONA_INNODB_VERSION
#define PERCONA_INNODB_VERSION 33.0
#define PERCONA_INNODB_VERSION 34.0
#endif
#define INNODB_VERSION_STR MYSQL_SERVER_VERSION "-" IB_TO_STR(PERCONA_INNODB_VERSION)
......
......@@ -3832,6 +3832,8 @@ lock_table_remove_low(
trx = lock->trx;
table = lock->un_member.tab_lock.table;
ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
/* Remove the table from the transaction's AUTOINC vector, if
the lock that is being release is an AUTOINC lock. */
if (lock_get_mode(lock) == LOCK_AUTO_INC) {
......
......@@ -2474,12 +2474,13 @@ os_file_pread(
os_n_pending_reads++;
os_mutex_exit(os_file_count_mutex);
/* Handle signal interruptions correctly */
/* Handle partial reads and signal interruptions correctly */
for (n_bytes = 0; n_bytes < (ssize_t) n; ) {
n_read = pread(file, buf, (ssize_t)n, offs);
n_read = pread(file, buf, (ssize_t)n - n_bytes, offs);
if (n_read > 0) {
n_bytes += n_read;
offs += n_read;
buf = (char *)buf + n_read;
} else if (n_read == -1 && errno == EINTR) {
continue;
} else {
......@@ -2602,12 +2603,13 @@ os_file_pwrite(
os_n_pending_writes++;
os_mutex_exit(os_file_count_mutex);
/* Handle signal interruptions correctly */
/* Handle partial writes and signal interruptions correctly */
for (ret = 0; ret < (ssize_t) n; ) {
n_written = pwrite(file, buf, (ssize_t)n, offs);
if (n_written > 0) {
n_written = pwrite(file, buf, (ssize_t)n - ret, offs);
if (n_written >= 0) {
ret += n_written;
offs += n_written;
buf = (char *)buf + n_written;
} else if (n_written == -1 && errno == EINTR) {
continue;
} else {
......@@ -4792,6 +4794,7 @@ os_aio_linux_handle(
segment = os_aio_get_array_and_local_segment(&array, global_seg);
n = array->n_slots / array->n_segments;
wait_for_event:
/* Loop until we have found a completed request. */
for (;;) {
ibool any_reserved = FALSE;
......@@ -4861,6 +4864,43 @@ found:
ut_error;
}
#endif /* UNIV_DO_FLUSH */
} else if ((slot->ret == 0) && (slot->n_bytes > 0)
&& (slot->n_bytes < (long) slot->len)) {
/* Partial read or write scenario */
int submit_ret;
struct iocb* iocb;
slot->buf = (byte*)slot->buf + slot->n_bytes;
slot->offset = slot->offset + slot->n_bytes;
slot->len = slot->len - slot->n_bytes;
/* Resetting the bytes read/written */
slot->n_bytes = 0;
slot->io_already_done = FALSE;
iocb = &(slot->control);
if (slot->type == OS_FILE_READ) {
io_prep_pread(&slot->control, slot->file, slot->buf,
slot->len, (off_t) slot->offset);
} else {
ut_a(slot->type == OS_FILE_WRITE);
io_prep_pwrite(&slot->control, slot->file, slot->buf,
slot->len, (off_t) slot->offset);
}
/* Resubmit an I/O request */
submit_ret = io_submit(array->aio_ctx[segment], 1, &iocb);
if (submit_ret < 0 ) {
/* Aborting in case of submit failure */
ut_print_timestamp(stderr);
fprintf(stderr,
"InnoDB: Error: Native Linux AIO interface. "
"io_submit() call failed when resubmitting a "
"partial I/O request on the file %s.",
slot->name);
ut_error;
} else {
ret = FALSE;
os_mutex_exit(array->mutex);
goto wait_for_event;
}
} else {
errno = -slot->ret;
......
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