Commit 7996f506 authored by Sergei Golubchik's avatar Sergei Golubchik

percona-server-5.5.36-34.0.tar.gz

parent 15b4441d
...@@ -1605,17 +1605,8 @@ buf_flush_page_and_try_neighbors( ...@@ -1605,17 +1605,8 @@ buf_flush_page_and_try_neighbors(
ut_ad(block_mutex); ut_ad(block_mutex);
} }
if (UNIV_UNLIKELY(buf_page_get_state(bpage) ut_a(buf_page_in_file(bpage)
== BUF_BLOCK_REMOVE_HASH)) { || 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));
if (buf_flush_ready_for_flush(bpage, flush_type)) { if (buf_flush_ready_for_flush(bpage, flush_type)) {
ulint space; ulint space;
...@@ -1631,8 +1622,10 @@ buf_flush_page_and_try_neighbors( ...@@ -1631,8 +1622,10 @@ buf_flush_page_and_try_neighbors(
/* These fields are protected by both the /* These fields are protected by both the
buffer pool mutex and block mutex. */ buffer pool mutex and block mutex. */
space = buf_page_get_space(bpage); /* Read the fields directly in order to avoid asserting on
offset = buf_page_get_page_no(bpage); BUF_BLOCK_REMOVE_HASH pages. */
space = bpage->space;
offset = bpage->offset;
if (flush_type == BUF_FLUSH_LRU) { if (flush_type == BUF_FLUSH_LRU) {
mutex_exit(block_mutex); mutex_exit(block_mutex);
......
...@@ -65,6 +65,7 @@ UNIV_INTERN uint ibuf_debug; ...@@ -65,6 +65,7 @@ UNIV_INTERN uint ibuf_debug;
#include "srv0start.h" /* SRV_LOG_SPACE_FIRST_ID */ #include "srv0start.h" /* SRV_LOG_SPACE_FIRST_ID */
#include "m_string.h" #include "m_string.h"
#include "my_sys.h" #include "my_sys.h"
#include "lock0lock.h"
#include <ctype.h> #include <ctype.h>
...@@ -1331,6 +1332,7 @@ dict_table_remove_from_cache( ...@@ -1331,6 +1332,7 @@ dict_table_remove_from_cache(
ut_ad(table); ut_ad(table);
ut_ad(mutex_own(&(dict_sys->mutex))); ut_ad(mutex_own(&(dict_sys->mutex)));
ut_ad(table->magic_n == DICT_TABLE_MAGIC_N); ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
ut_ad(lock_table_has_locks(table) == FALSE);
#if 0 #if 0
fputs("Removing table ", stderr); fputs("Removing table ", stderr);
...@@ -1383,6 +1385,53 @@ dict_table_remove_from_cache( ...@@ -1383,6 +1385,53 @@ dict_table_remove_from_cache(
dict_mem_table_free(table); 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 Frees tables from the end of table_LRU if the dictionary cache occupies
too much space. */ too much space. */
...@@ -1394,51 +1443,65 @@ dict_table_LRU_trim( ...@@ -1394,51 +1443,65 @@ dict_table_LRU_trim(
{ {
dict_table_t* table; dict_table_t* table;
dict_table_t* prev_table; dict_table_t* prev_table;
dict_foreign_t* foreign; ulint dict_size;
ulint n_removed; ulint max_depth;
ulint n_have_parent; ulint max_evict;
ulint cached_foreign_tables; ulint visited;
ulint evicted;
#ifdef UNIV_SYNC_DEBUG #ifdef UNIV_SYNC_DEBUG
ut_ad(mutex_own(&(dict_sys->mutex))); ut_ad(mutex_own(&(dict_sys->mutex)));
#endif /* UNIV_SYNC_DEBUG */ #endif /* UNIV_SYNC_DEBUG */
retry: if (srv_dict_size_limit == 0)
n_removed = n_have_parent = 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); table = UT_LIST_GET_LAST(dict_sys->table_LRU);
while ( srv_dict_size_limit && table while (table && dict_size > srv_dict_size_limit
&& ((dict_sys->table_hash->n_cells && visited <= max_depth
+ dict_sys->table_id_hash->n_cells) * sizeof(hash_cell_t) && srv_shutdown_state == SRV_SHUTDOWN_NONE) {
+ dict_sys->size) > srv_dict_size_limit ) {
prev_table = UT_LIST_GET_PREV(table_LRU, table); prev_table = UT_LIST_GET_PREV(table_LRU, table);
if (table == self || table->n_mysql_handles_opened || table->is_corrupt) if (table != self && dict_table_can_be_evicted(table)) {
goto next_loop; dict_table_remove_from_cache(table);
cached_foreign_tables = 0; evicted++;
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);
}
if (cached_foreign_tables == 0) { if (evicted >= max_evict)
dict_table_remove_from_cache(table); break;
n_removed++;
} else { /* Only need to recalculate this when something
n_have_parent++; 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; 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( ...@@ -115,6 +115,7 @@ dict_mem_table_free(
ut_ad(table); ut_ad(table);
ut_ad(table->magic_n == DICT_TABLE_MAGIC_N); ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
ut_d(table->cached = FALSE); ut_d(table->cached = FALSE);
ut_d(table->magic_n = 0);
#ifndef UNIV_HOTBACKUP #ifndef UNIV_HOTBACKUP
mutex_free(&(table->autoinc_mutex)); mutex_free(&(table->autoinc_mutex));
......
...@@ -8675,16 +8675,6 @@ innobase_rename_table( ...@@ -8675,16 +8675,6 @@ innobase_rename_table(
error = row_rename_table_for_mysql( error = row_rename_table_for_mysql(
norm_from, norm_to, trx, lock_and_commit); norm_from, norm_to, trx, lock_and_commit);
if (error != DB_SUCCESS) {
FILE* ef = dict_foreign_err_file;
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) { if (lock_and_commit) {
row_mysql_unlock_data_dictionary(trx); row_mysql_unlock_data_dictionary(trx);
......
...@@ -459,6 +459,16 @@ lock_sec_rec_cons_read_sees( ...@@ -459,6 +459,16 @@ lock_sec_rec_cons_read_sees(
by a read cursor */ by a read cursor */
const read_view_t* view); /*!< in: consistent read view */ 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 Locks the specified database table in the mode given. If the lock cannot
be granted immediately, the query thread is put to wait. be granted immediately, the query thread is put to wait.
@return DB_SUCCESS, DB_LOCK_WAIT, DB_DEADLOCK, or DB_QUE_THR_SUSPENDED */ @return DB_SUCCESS, DB_LOCK_WAIT, DB_DEADLOCK, or DB_QUE_THR_SUSPENDED */
......
...@@ -119,3 +119,17 @@ lock_get_min_heap_no( ...@@ -119,3 +119,17 @@ lock_get_min_heap_no(
FALSE))); 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 */ ...@@ -64,7 +64,7 @@ component, i.e. we show M.N.P as M.N */
(INNODB_VERSION_MAJOR << 8 | INNODB_VERSION_MINOR) (INNODB_VERSION_MAJOR << 8 | INNODB_VERSION_MINOR)
#ifndef PERCONA_INNODB_VERSION #ifndef PERCONA_INNODB_VERSION
#define PERCONA_INNODB_VERSION 33.0 #define PERCONA_INNODB_VERSION 34.0
#endif #endif
#define INNODB_VERSION_STR MYSQL_SERVER_VERSION "-" IB_TO_STR(PERCONA_INNODB_VERSION) #define INNODB_VERSION_STR MYSQL_SERVER_VERSION "-" IB_TO_STR(PERCONA_INNODB_VERSION)
......
...@@ -3832,6 +3832,8 @@ lock_table_remove_low( ...@@ -3832,6 +3832,8 @@ lock_table_remove_low(
trx = lock->trx; trx = lock->trx;
table = lock->un_member.tab_lock.table; 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 /* Remove the table from the transaction's AUTOINC vector, if
the lock that is being release is an AUTOINC lock. */ the lock that is being release is an AUTOINC lock. */
if (lock_get_mode(lock) == LOCK_AUTO_INC) { if (lock_get_mode(lock) == LOCK_AUTO_INC) {
......
...@@ -2365,12 +2365,13 @@ os_file_pread( ...@@ -2365,12 +2365,13 @@ os_file_pread(
os_n_pending_reads++; os_n_pending_reads++;
os_mutex_exit(os_file_count_mutex); 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; ) { 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) { if (n_read > 0) {
n_bytes += n_read; n_bytes += n_read;
offs += n_read; offs += n_read;
buf = (char *)buf + n_read;
} else if (n_read == -1 && errno == EINTR) { } else if (n_read == -1 && errno == EINTR) {
continue; continue;
} else { } else {
...@@ -2493,12 +2494,13 @@ os_file_pwrite( ...@@ -2493,12 +2494,13 @@ os_file_pwrite(
os_n_pending_writes++; os_n_pending_writes++;
os_mutex_exit(os_file_count_mutex); 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; ) { for (ret = 0; ret < (ssize_t) n; ) {
n_written = pwrite(file, buf, (ssize_t)n, offs); n_written = pwrite(file, buf, (ssize_t)n - ret, offs);
if (n_written > 0) { if (n_written >= 0) {
ret += n_written; ret += n_written;
offs += n_written; offs += n_written;
buf = (char *)buf + n_written;
} else if (n_written == -1 && errno == EINTR) { } else if (n_written == -1 && errno == EINTR) {
continue; continue;
} else { } else {
...@@ -4849,6 +4851,7 @@ os_aio_linux_handle( ...@@ -4849,6 +4851,7 @@ os_aio_linux_handle(
segment = os_aio_get_array_and_local_segment(&array, global_seg); segment = os_aio_get_array_and_local_segment(&array, global_seg);
n = array->n_slots / array->n_segments; n = array->n_slots / array->n_segments;
wait_for_event:
/* Loop until we have found a completed request. */ /* Loop until we have found a completed request. */
for (;;) { for (;;) {
ibool any_reserved = FALSE; ibool any_reserved = FALSE;
...@@ -4918,6 +4921,43 @@ found: ...@@ -4918,6 +4921,43 @@ found:
ut_error; ut_error;
} }
#endif /* UNIV_DO_FLUSH */ #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 { } else {
errno = -slot->ret; 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