From 56845ed3b4cb9de0bb3f33d8d7c9b1bb68e7662b Mon Sep 17 00:00:00 2001 From: Jimmy Yang Date: Fri, 25 Feb 2011 00:33:13 -0800 Subject: [PATCH 01/18] Fix Bug #11765975 __FILE__ macros expanded to full path instead of relative in CMake builds rb://600 approved by Sunny Bains --- storage/innobase/handler/ha_innodb.cc | 30 ++++++++++++++++++++---- storage/innobase/include/ha_prototypes.h | 9 +++++++ storage/innobase/mem/mem0dbg.c | 13 ++++++---- storage/innobase/sync/sync0arr.c | 12 ++++++---- storage/innobase/sync/sync0rw.c | 12 ++++++---- storage/innobase/sync/sync0sync.c | 9 ++++--- storage/innobase/ut/ut0dbg.c | 9 ++++--- 7 files changed, 69 insertions(+), 25 deletions(-) diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 34c4500a723..725efe33e65 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -51,6 +51,7 @@ Place, Suite 330, Boston, MA 02111-1307 USA #include #include #include +#include /** @file ha_innodb.cc */ @@ -1146,6 +1147,20 @@ innobase_strcasecmp( return(my_strcasecmp(system_charset_info, a, b)); } +/******************************************************************//** +Strip dir name from a full path name and return only the file name +@return file name or "null" if no file name */ +extern "C" UNIV_INTERN +const char* +innobase_basename( +/*==============*/ + const char* path_name) /*!< in: full path name */ +{ + const char* name = base_name(path_name); + + return((name) ? name : "null"); +} + /******************************************************************//** Makes all characters in a NUL-terminated UTF-8 string lower case. */ extern "C" UNIV_INTERN @@ -9251,7 +9266,8 @@ innodb_mutex_show_status( if (mutex->count_using > 0) { buf1len= my_snprintf(buf1, sizeof(buf1), "%s:%s", - mutex->cmutex_name, mutex->cfile_name); + mutex->cmutex_name, + innobase_basename(mutex->cfile_name)); buf2len= my_snprintf(buf2, sizeof(buf2), "count=%lu, spin_waits=%lu," " spin_rounds=%lu, " @@ -9281,7 +9297,8 @@ innodb_mutex_show_status( } #else /* UNIV_DEBUG */ buf1len= (uint) my_snprintf(buf1, sizeof(buf1), "%s:%lu", - mutex->cfile_name, (ulong) mutex->cline); + innobase_basename(mutex->cfile_name), + (ulong) mutex->cline); buf2len= (uint) my_snprintf(buf2, sizeof(buf2), "os_waits=%lu", (ulong) mutex->count_os_wait); @@ -9297,7 +9314,8 @@ innodb_mutex_show_status( if (block_mutex) { buf1len = (uint) my_snprintf(buf1, sizeof buf1, "combined %s:%lu", - block_mutex->cfile_name, + innobase_basename( + block_mutex->cfile_name), (ulong) block_mutex->cline); buf2len = (uint) my_snprintf(buf2, sizeof buf2, "os_waits=%lu", @@ -9328,7 +9346,8 @@ innodb_mutex_show_status( } buf1len = my_snprintf(buf1, sizeof buf1, "%s:%lu", - lock->cfile_name, (ulong) lock->cline); + innobase_basename(lock->cfile_name), + (ulong) lock->cline); buf2len = my_snprintf(buf2, sizeof buf2, "os_waits=%lu", (ulong) lock->count_os_wait); @@ -9343,7 +9362,8 @@ innodb_mutex_show_status( if (block_lock) { buf1len = (uint) my_snprintf(buf1, sizeof buf1, "combined %s:%lu", - block_lock->cfile_name, + innobase_basename( + block_lock->cfile_name), (ulong) block_lock->cline); buf2len = (uint) my_snprintf(buf2, sizeof buf2, "os_waits=%lu", diff --git a/storage/innobase/include/ha_prototypes.h b/storage/innobase/include/ha_prototypes.h index b75002944bd..dd9e8db82ee 100644 --- a/storage/innobase/include/ha_prototypes.h +++ b/storage/innobase/include/ha_prototypes.h @@ -173,6 +173,15 @@ innobase_strcasecmp( const char* a, /*!< in: first string to compare */ const char* b); /*!< in: second string to compare */ +/******************************************************************//** +Strip dir name from a full path name and return only its file name. +@return file name or "null" if no file name */ +UNIV_INTERN +const char* +innobase_basename( +/*==============*/ + const char* path_name); /*!< in: full path name */ + /******************************************************************//** Returns true if the thread is executing a SELECT statement. @return true if thd is executing SELECT */ diff --git a/storage/innobase/mem/mem0dbg.c b/storage/innobase/mem/mem0dbg.c index d91e610a08a..e36a372b087 100644 --- a/storage/innobase/mem/mem0dbg.c +++ b/storage/innobase/mem/mem0dbg.c @@ -400,7 +400,7 @@ mem_hash_remove( fprintf(stderr, "Memory heap or buffer freed in %s line %lu" " did not exist.\n", - file_name, (ulong) line); + innobase_basename(file_name), (ulong) line); ut_error; } @@ -419,8 +419,9 @@ mem_hash_remove( "in %s line %lu and tried to free in %s line %lu.\n" "Hex dump of 400 bytes around memory heap" " first block start:\n", - node->nth_heap, node->file_name, (ulong) node->line, - file_name, (ulong) line); + node->nth_heap, + innobase_basename(node->file_name), (ulong) node->line, + innobase_basename(file_name), (ulong) line); ut_print_buf(stderr, (byte*)node->heap - 200, 400); fputs("\nDump of the mem heap:\n", stderr); mem_heap_validate_or_print(node->heap, NULL, TRUE, &error, @@ -763,7 +764,8 @@ mem_validate_no_assert(void) "Inconsistency in memory heap" " or buffer created\n" "in %s line %lu.\n", - node->file_name, node->line); + innobase_basename(node->file_name), + node->line); mutex_exit(&mem_hash_mutex); @@ -989,7 +991,8 @@ mem_print_info_low( fprintf(outfile, "%lu: file %s line %lu of size %lu phys.size %lu" " with %lu blocks, type %lu\n", - node->nth_heap, node->file_name, node->line, + node->nth_heap, + innobase_basename(node->file_name), node->line, allocated_mem, ph_size, n_blocks, (node->heap)->type); next_heap: diff --git a/storage/innobase/sync/sync0arr.c b/storage/innobase/sync/sync0arr.c index 3ecbce72ebd..0d1581b41b4 100644 --- a/storage/innobase/sync/sync0arr.c +++ b/storage/innobase/sync/sync0arr.c @@ -40,6 +40,7 @@ Created 9/5/1995 Heikki Tuuri #include "os0sync.h" #include "os0file.h" #include "srv0srv.h" +#include "ha_prototypes.h" /* WAIT ARRAY @@ -478,8 +479,8 @@ sync_array_cell_print( fprintf(file, "--Thread %lu has waited at %s line %lu" " for %.2f seconds the semaphore:\n", - (ulong) os_thread_pf(cell->thread), cell->file, - (ulong) cell->line, + (ulong) os_thread_pf(cell->thread), + innobase_basename(cell->file), (ulong) cell->line, difftime(time(NULL), cell->reservation_time)); if (type == SYNC_MUTEX) { @@ -493,7 +494,8 @@ sync_array_cell_print( "Last time reserved in file %s line %lu, " #endif /* UNIV_SYNC_DEBUG */ "waiters flag %lu\n", - (void*) mutex, mutex->cfile_name, (ulong) mutex->cline, + (void*) mutex, innobase_basename(mutex->cfile_name), + (ulong) mutex->cline, (ulong) mutex->lock_word, #ifdef UNIV_SYNC_DEBUG mutex->file_name, (ulong) mutex->line, @@ -512,7 +514,7 @@ sync_array_cell_print( fprintf(file, " RW-latch at %p created in file %s line %lu\n", - (void*) rwlock, rwlock->cfile_name, + (void*) rwlock, innobase_basename(rwlock->cfile_name), (ulong) rwlock->cline); writer = rw_lock_get_writer(rwlock); if (writer != RW_LOCK_NOT_LOCKED) { @@ -533,7 +535,7 @@ sync_array_cell_print( (ulong) rw_lock_get_reader_count(rwlock), (ulong) rwlock->waiters, rwlock->lock_word, - rwlock->last_s_file_name, + innobase_basename(rwlock->last_s_file_name), (ulong) rwlock->last_s_line, rwlock->last_x_file_name, (ulong) rwlock->last_x_line); diff --git a/storage/innobase/sync/sync0rw.c b/storage/innobase/sync/sync0rw.c index 73d1e3aa46e..9010e4fcec1 100644 --- a/storage/innobase/sync/sync0rw.c +++ b/storage/innobase/sync/sync0rw.c @@ -407,7 +407,8 @@ lock_loop: " cfile %s cline %lu rnds %lu\n", (ulong) os_thread_pf(os_thread_get_curr_id()), (void*) lock, - lock->cfile_name, (ulong) lock->cline, (ulong) i); + innobase_basename(lock->cfile_name), + (ulong) lock->cline, (ulong) i); } /* We try once again to obtain the lock */ @@ -442,7 +443,8 @@ lock_loop: "Thread %lu OS wait rw-s-lock at %p" " cfile %s cline %lu\n", os_thread_pf(os_thread_get_curr_id()), - (void*) lock, lock->cfile_name, + (void*) lock, + innobase_basename(lock->cfile_name), (ulong) lock->cline); } @@ -664,7 +666,8 @@ lock_loop: "Thread %lu spin wait rw-x-lock at %p" " cfile %s cline %lu rnds %lu\n", os_thread_pf(os_thread_get_curr_id()), (void*) lock, - lock->cfile_name, (ulong) lock->cline, (ulong) i); + innobase_basename(lock->cfile_name), + (ulong) lock->cline, (ulong) i); } sync_array_reserve_cell(sync_primary_wait_array, @@ -687,7 +690,8 @@ lock_loop: "Thread %lu OS wait for rw-x-lock at %p" " cfile %s cline %lu\n", os_thread_pf(os_thread_get_curr_id()), (void*) lock, - lock->cfile_name, (ulong) lock->cline); + innobase_basename(lock->cfile_name), + (ulong) lock->cline); } /* these stats may not be accurate */ diff --git a/storage/innobase/sync/sync0sync.c b/storage/innobase/sync/sync0sync.c index 0f6a60ca260..b66920a0784 100644 --- a/storage/innobase/sync/sync0sync.c +++ b/storage/innobase/sync/sync0sync.c @@ -543,7 +543,8 @@ spin_loop: "Thread %lu spin wait mutex at %p" " cfile %s cline %lu rnds %lu\n", (ulong) os_thread_pf(os_thread_get_curr_id()), (void*) mutex, - mutex->cfile_name, (ulong) mutex->cline, (ulong) i); + innobase_basename(mutex->cfile_name), + (ulong) mutex->cline, (ulong) i); #endif mutex_spin_round_count += i; @@ -620,7 +621,8 @@ spin_loop: fprintf(stderr, "Thread %lu OS wait mutex at %p cfile %s cline %lu rnds %lu\n", (ulong) os_thread_pf(os_thread_get_curr_id()), (void*) mutex, - mutex->cfile_name, (ulong) mutex->cline, (ulong) i); + innobase_basename(mutex->cfile_name), + (ulong) mutex->cline, (ulong) i); #endif mutex_os_wait_count++; @@ -869,7 +871,8 @@ sync_print_warning( if (mutex->magic_n == MUTEX_MAGIC_N) { fprintf(stderr, "Mutex created at %s %lu\n", - mutex->cfile_name, (ulong) mutex->cline); + innobase_basename(mutex->cfile_name), + (ulong) mutex->cline); if (mutex_get_lock_word(mutex) != 0) { ulint line; diff --git a/storage/innobase/ut/ut0dbg.c b/storage/innobase/ut/ut0dbg.c index 42ad8c03762..64fadd76d1c 100644 --- a/storage/innobase/ut/ut0dbg.c +++ b/storage/innobase/ut/ut0dbg.c @@ -25,6 +25,7 @@ Created 1/30/1994 Heikki Tuuri #include "univ.i" #include "ut0dbg.h" +#include "ha_prototypes.h" #if defined(__GNUC__) && (__GNUC__ > 2) #else @@ -55,12 +56,13 @@ ut_dbg_assertion_failed( ut_print_timestamp(stderr); #ifdef UNIV_HOTBACKUP fprintf(stderr, " InnoDB: Assertion failure in file %s line %lu\n", - file, line); + innobase_basename(file), line); #else /* UNIV_HOTBACKUP */ fprintf(stderr, " InnoDB: Assertion failure in thread %lu" " in file %s line %lu\n", - os_thread_pf(os_thread_get_curr_id()), file, line); + os_thread_pf(os_thread_get_curr_id()), + innobase_basename(file), line); #endif /* UNIV_HOTBACKUP */ if (expr) { fprintf(stderr, @@ -93,7 +95,8 @@ ut_dbg_stop_thread( { #ifndef UNIV_HOTBACKUP fprintf(stderr, "InnoDB: Thread %lu stopped in file %s line %lu\n", - os_thread_pf(os_thread_get_curr_id()), file, line); + os_thread_pf(os_thread_get_curr_id()), + innobase_basename(file), line); os_thread_sleep(1000000000); #endif /* !UNIV_HOTBACKUP */ } From 5a805fe7c4b0ec4907376c4439c677d88b2bb0dd Mon Sep 17 00:00:00 2001 From: Vasil Dimov Date: Fri, 25 Feb 2011 11:50:18 +0200 Subject: [PATCH 02/18] Fix BUG#11798085 - INCORRECT INTEGER TYPES USED IN CALCULATION RESULT IN OVERFLOW Do not assign the result of the difference to a signed variable and checking whether it is negative afterwards because this limits the max diff to 2G on 32 bit systems. E.g. "signed = 3.5G - 1G" would be negative and the code would assume that 3.5G < 1G. Instead compare the two variables directly and assign to unsigned only if we know that the result of the subtraction will be positive. Discussed with: Jimmy and Sunny (via IRC) --- storage/innodb_plugin/buf/buf0buf.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/storage/innodb_plugin/buf/buf0buf.c b/storage/innodb_plugin/buf/buf0buf.c index 6bbd5565c58..51a3a393d36 100644 --- a/storage/innodb_plugin/buf/buf0buf.c +++ b/storage/innodb_plugin/buf/buf0buf.c @@ -1893,16 +1893,19 @@ buf_block_align( /* TODO: protect buf_pool->chunks with a mutex (it will currently remain constant after buf_pool_init()) */ for (chunk = buf_pool->chunks, i = buf_pool->n_chunks; i--; chunk++) { - lint offs = ptr - chunk->blocks->frame; + ulint offs; - if (UNIV_UNLIKELY(offs < 0)) { + if (UNIV_UNLIKELY(ptr < chunk->blocks->frame)) { continue; } + /* else */ + + offs = ptr - chunk->blocks->frame; offs >>= UNIV_PAGE_SIZE_SHIFT; - if (UNIV_LIKELY((ulint) offs < chunk->size)) { + if (UNIV_LIKELY(offs < chunk->size)) { buf_block_t* block = &chunk->blocks[offs]; /* The function buf_chunk_init() invokes From 618f4796f02d833ea12a302f55a5c6ae2af1b61a Mon Sep 17 00:00:00 2001 From: Jimmy Yang Date: Fri, 25 Feb 2011 03:21:02 -0800 Subject: [PATCH 03/18] Include "ha_prototypes.h" to sync/sync0rw.c for innobase_basename(). --- storage/innobase/mem/mem0dbg.c | 2 ++ storage/innobase/sync/sync0rw.c | 1 + storage/innobase/sync/sync0sync.c | 1 + 3 files changed, 4 insertions(+) diff --git a/storage/innobase/mem/mem0dbg.c b/storage/innobase/mem/mem0dbg.c index e36a372b087..ae43d6097a6 100644 --- a/storage/innobase/mem/mem0dbg.c +++ b/storage/innobase/mem/mem0dbg.c @@ -24,6 +24,8 @@ but is included in mem0mem.* ! Created 6/9/1994 Heikki Tuuri *************************************************************************/ +#include "ha_prototypes.h" + #ifdef UNIV_MEM_DEBUG # ifndef UNIV_HOTBACKUP /* The mutex which protects in the debug version the hash table diff --git a/storage/innobase/sync/sync0rw.c b/storage/innobase/sync/sync0rw.c index 9010e4fcec1..397d505df50 100644 --- a/storage/innobase/sync/sync0rw.c +++ b/storage/innobase/sync/sync0rw.c @@ -39,6 +39,7 @@ Created 9/11/1995 Heikki Tuuri #include "mem0mem.h" #include "srv0srv.h" #include "os0sync.h" /* for INNODB_RW_LOCKS_USE_ATOMICS */ +#include "ha_prototypes.h" /* IMPLEMENTATION OF THE RW_LOCK diff --git a/storage/innobase/sync/sync0sync.c b/storage/innobase/sync/sync0sync.c index b66920a0784..23fd64cc5ed 100644 --- a/storage/innobase/sync/sync0sync.c +++ b/storage/innobase/sync/sync0sync.c @@ -43,6 +43,7 @@ Created 9/5/1995 Heikki Tuuri #ifdef UNIV_SYNC_DEBUG # include "srv0start.h" /* srv_is_being_started */ #endif /* UNIV_SYNC_DEBUG */ +#include "ha_prototypes.h" /* REASONS FOR IMPLEMENTING THE SPIN LOCK MUTEX From e99019e570e55a37339f28da313440f9264e9a78 Mon Sep 17 00:00:00 2001 From: Vasil Dimov Date: Mon, 28 Feb 2011 10:39:48 +0200 Subject: [PATCH 04/18] Non-functional change: use plugin_author instead of hardcoded string. plugin_author is currently defined as "Innobase Oy" so this change is a no-op. --- storage/innobase/handler/i_s.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/storage/innobase/handler/i_s.cc b/storage/innobase/handler/i_s.cc index 709274bab16..91acbf579da 100644 --- a/storage/innobase/handler/i_s.cc +++ b/storage/innobase/handler/i_s.cc @@ -1068,7 +1068,7 @@ UNIV_INTERN struct st_mysql_plugin i_s_innodb_lock_waits = /* plugin author (for SHOW PLUGINS) */ /* const char* */ - STRUCT_FLD(author, "Innobase Oy"), + STRUCT_FLD(author, plugin_author), /* general descriptive text (for SHOW PLUGINS) */ /* const char* */ From 17621e724f17a0e6884067ac4c9107d6c27f8e7a Mon Sep 17 00:00:00 2001 From: Vasil Dimov Date: Mon, 28 Feb 2011 11:02:24 +0200 Subject: [PATCH 05/18] Change InnoDB plugins author to Oracle Corporation --- storage/innobase/handler/i_s.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/storage/innobase/handler/i_s.cc b/storage/innobase/handler/i_s.cc index 91acbf579da..3d195f8c47b 100644 --- a/storage/innobase/handler/i_s.cc +++ b/storage/innobase/handler/i_s.cc @@ -47,7 +47,7 @@ extern "C" { #include "trx0trx.h" /* for TRX_QUE_STATE_STR_MAX_LEN */ } -static const char plugin_author[] = "Innobase Oy"; +static const char plugin_author[] = "Oracle Corporation"; #define OK(expr) \ if ((expr) != 0) { \ From 8d8784e93092b883e2bc7619bb57454e46f60d73 Mon Sep 17 00:00:00 2001 From: Vasil Dimov Date: Mon, 28 Feb 2011 11:07:22 +0200 Subject: [PATCH 06/18] Use plugin_author also for the InnoDB SE plugin Move the const variable plugin_author to a common header file that is being included by both ha_innodb.cc and i_s.cc --- storage/innobase/handler/ha_innodb.cc | 2 +- storage/innobase/handler/i_s.cc | 2 -- storage/innobase/handler/i_s.h | 2 ++ 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 725efe33e65..2d02dd0e770 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -11367,7 +11367,7 @@ mysql_declare_plugin(innobase) MYSQL_STORAGE_ENGINE_PLUGIN, &innobase_storage_engine, innobase_hton_name, - "Innobase Oy", + plugin_author, "Supports transactions, row-level locking, and foreign keys", PLUGIN_LICENSE_GPL, innobase_init, /* Plugin Init */ diff --git a/storage/innobase/handler/i_s.cc b/storage/innobase/handler/i_s.cc index 3d195f8c47b..f7fe8a01517 100644 --- a/storage/innobase/handler/i_s.cc +++ b/storage/innobase/handler/i_s.cc @@ -47,8 +47,6 @@ extern "C" { #include "trx0trx.h" /* for TRX_QUE_STATE_STR_MAX_LEN */ } -static const char plugin_author[] = "Oracle Corporation"; - #define OK(expr) \ if ((expr) != 0) { \ DBUG_RETURN(1); \ diff --git a/storage/innobase/handler/i_s.h b/storage/innobase/handler/i_s.h index 402c88bbedb..dc0deef119b 100644 --- a/storage/innobase/handler/i_s.h +++ b/storage/innobase/handler/i_s.h @@ -26,6 +26,8 @@ Created July 18, 2007 Vasil Dimov #ifndef i_s_h #define i_s_h +const char plugin_author[] = "Oracle Corporation"; + extern struct st_mysql_plugin i_s_innodb_trx; extern struct st_mysql_plugin i_s_innodb_locks; extern struct st_mysql_plugin i_s_innodb_lock_waits; From 0f8ae318c7203158e1ea70cbf3a6bba41fd2dde6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Mon, 28 Feb 2011 13:51:18 +0200 Subject: [PATCH 07/18] Bug #58549 Race condition in buf_LRU_drop_page_hash_for_tablespace() and compressed tables buf_LRU_drop_page_hash_for_tablespace(): after releasing and reacquiring the buffer pool mutex, do not dereference any block descriptor pointer that is not known to be a pointer to an uncompressed page frame (type buf_block_t; state == BUF_BLOCK_FILE_PAGE). Also, defer the acquisition of the block_mutex until it is needed. buf_page_get_gen(): Add mode == BUF_GET_IF_IN_POOL_PEEK for buffer-fixing a block without making it young in the LRU list. buf_page_get_gen(), buf_page_init(), buf_LRU_block_remove_hashed_page(): Set bpage->state = BUF_BLOCK_ZIP_FREE before buf_buddy_free(bpage), so that similar race conditions might be detected a little easier. btr_search_drop_page_hash_when_freed(): Use BUF_GET_IF_IN_POOL_PEEK when dropping the hash indexes. rb://528 approved by Jimmy Yang --- storage/innodb_plugin/ChangeLog | 6 ++ storage/innodb_plugin/btr/btr0sea.c | 4 +- storage/innodb_plugin/buf/buf0buf.c | 32 ++++++--- storage/innodb_plugin/buf/buf0lru.c | 87 +++++++++++++------------ storage/innodb_plugin/include/buf0buf.h | 4 +- 5 files changed, 81 insertions(+), 52 deletions(-) diff --git a/storage/innodb_plugin/ChangeLog b/storage/innodb_plugin/ChangeLog index 1b2747ab012..1ece3ad1825 100644 --- a/storage/innodb_plugin/ChangeLog +++ b/storage/innodb_plugin/ChangeLog @@ -1,3 +1,9 @@ +2011-02-28 The InnoDB Team + + * btr/btr0sea.c, buf/buf0buf.c, buf/buf0lru.c: + Fix Bug#58549 Race condition in buf_LRU_drop_page_hash_for_tablespace() + and compressed tables + 2011-02-15 The InnoDB Team * sync/sync0rw.c, innodb_bug59307.test: diff --git a/storage/innodb_plugin/btr/btr0sea.c b/storage/innodb_plugin/btr/btr0sea.c index 9835efcf712..cd0eadbb1b8 100644 --- a/storage/innodb_plugin/btr/btr0sea.c +++ b/storage/innodb_plugin/btr/btr0sea.c @@ -1201,8 +1201,8 @@ btr_search_drop_page_hash_when_freed( having to fear a deadlock. */ block = buf_page_get_gen(space, zip_size, page_no, RW_S_LATCH, NULL, - BUF_GET_IF_IN_POOL, __FILE__, __LINE__, - &mtr); + BUF_PEEK_IF_IN_POOL, __FILE__, __LINE__, + &mtr); /* Because the buffer pool mutex was released by buf_page_peek_if_search_hashed(), it is possible that the block was removed from the buffer pool by another thread diff --git a/storage/innodb_plugin/buf/buf0buf.c b/storage/innodb_plugin/buf/buf0buf.c index 51a3a393d36..14ec7b75911 100644 --- a/storage/innodb_plugin/buf/buf0buf.c +++ b/storage/innodb_plugin/buf/buf0buf.c @@ -2031,7 +2031,7 @@ buf_page_get_gen( ulint rw_latch,/*!< in: RW_S_LATCH, RW_X_LATCH, RW_NO_LATCH */ buf_block_t* guess, /*!< in: guessed block or NULL */ ulint mode, /*!< in: BUF_GET, BUF_GET_IF_IN_POOL, - BUF_GET_NO_LATCH */ + BUF_PEEK_IF_IN_POOL, BUF_GET_NO_LATCH */ const char* file, /*!< in: file name */ ulint line, /*!< in: line where called */ mtr_t* mtr) /*!< in: mini-transaction */ @@ -2047,9 +2047,19 @@ buf_page_get_gen( ut_ad((rw_latch == RW_S_LATCH) || (rw_latch == RW_X_LATCH) || (rw_latch == RW_NO_LATCH)); - ut_ad((mode != BUF_GET_NO_LATCH) || (rw_latch == RW_NO_LATCH)); - ut_ad((mode == BUF_GET) || (mode == BUF_GET_IF_IN_POOL) - || (mode == BUF_GET_NO_LATCH)); +#ifdef UNIV_DEBUG + switch (mode) { + case BUF_GET_NO_LATCH: + ut_ad(rw_latch == RW_NO_LATCH); + break; + case BUF_GET: + case BUF_GET_IF_IN_POOL: + case BUF_PEEK_IF_IN_POOL: + break; + default: + ut_error; + } +#endif /* UNIV_DEBUG */ ut_ad(zip_size == fil_space_get_zip_size(space)); ut_ad(ut_is_2pow(zip_size)); #ifndef UNIV_LOG_DEBUG @@ -2091,7 +2101,8 @@ loop2: buf_pool_mutex_exit(); - if (mode == BUF_GET_IF_IN_POOL) { + if (mode == BUF_GET_IF_IN_POOL + || mode == BUF_PEEK_IF_IN_POOL) { return(NULL); } @@ -2130,7 +2141,8 @@ loop2: must_read = buf_block_get_io_fix(block) == BUF_IO_READ; - if (must_read && mode == BUF_GET_IF_IN_POOL) { + if (must_read && (mode == BUF_GET_IF_IN_POOL + || mode == BUF_PEEK_IF_IN_POOL)) { /* The page is only being read to buffer */ buf_pool_mutex_exit(); @@ -2248,6 +2260,7 @@ wait_until_unfixed: mutex_exit(&buf_pool_zip_mutex); buf_pool->n_pend_unzip++; + bpage->state = BUF_BLOCK_ZIP_FREE; buf_buddy_free(bpage, sizeof *bpage); buf_pool_mutex_exit(); @@ -2324,7 +2337,9 @@ wait_until_unfixed: buf_pool_mutex_exit(); - buf_page_set_accessed_make_young(&block->page, access_time); + if (UNIV_LIKELY(mode != BUF_PEEK_IF_IN_POOL)) { + buf_page_set_accessed_make_young(&block->page, access_time); + } #if defined UNIV_DEBUG_FILE_ACCESSES || defined UNIV_DEBUG ut_a(!block->page.file_page_was_freed); @@ -2377,7 +2392,7 @@ wait_until_unfixed: mtr_memo_push(mtr, block, fix_type); - if (!access_time) { + if (UNIV_LIKELY(mode != BUF_PEEK_IF_IN_POOL) && !access_time) { /* In the case of a first access, try to apply linear read-ahead */ @@ -2926,6 +2941,7 @@ err_exit: && UNIV_LIKELY_NULL(buf_page_hash_get(space, offset))) { /* The block was added by some other thread. */ + bpage->state = BUF_BLOCK_ZIP_FREE; buf_buddy_free(bpage, sizeof *bpage); buf_buddy_free(data, zip_size); diff --git a/storage/innodb_plugin/buf/buf0lru.c b/storage/innodb_plugin/buf/buf0lru.c index 39feb06ff23..a69b2658c51 100644 --- a/storage/innodb_plugin/buf/buf0lru.c +++ b/storage/innodb_plugin/buf/buf0lru.c @@ -246,71 +246,75 @@ buf_LRU_drop_page_hash_for_tablespace( page_arr = ut_malloc(sizeof(ulint) * BUF_LRU_DROP_SEARCH_HASH_SIZE); buf_pool_mutex_enter(); + num_entries = 0; scan_again: - num_entries = 0; bpage = UT_LIST_GET_LAST(buf_pool->LRU); while (bpage != NULL) { - mutex_t* block_mutex = buf_page_get_mutex(bpage); buf_page_t* prev_bpage; + ibool is_fixed; - mutex_enter(block_mutex); prev_bpage = UT_LIST_GET_PREV(LRU, bpage); ut_a(buf_page_in_file(bpage)); if (buf_page_get_state(bpage) != BUF_BLOCK_FILE_PAGE || bpage->space != id - || bpage->buf_fix_count > 0 || bpage->io_fix != BUF_IO_NONE) { - /* We leave the fixed pages as is in this scan. - To be dealt with later in the final scan. */ - mutex_exit(block_mutex); + /* Compressed pages are never hashed. + Skip blocks of other tablespaces. + Skip I/O-fixed blocks (to be dealt with later). */ +next_page: + bpage = prev_bpage; + continue; + } + + mutex_enter(&((buf_block_t*) bpage)->mutex); + is_fixed = bpage->buf_fix_count > 0 + || !((buf_block_t*) bpage)->is_hashed; + mutex_exit(&((buf_block_t*) bpage)->mutex); + + if (is_fixed) { goto next_page; } - if (((buf_block_t*) bpage)->is_hashed) { + /* Store the page number so that we can drop the hash + index in a batch later. */ + page_arr[num_entries] = bpage->offset; + ut_a(num_entries < BUF_LRU_DROP_SEARCH_HASH_SIZE); + ++num_entries; - /* Store the offset(i.e.: page_no) in the array - so that we can drop hash index in a batch - later. */ - page_arr[num_entries] = bpage->offset; - mutex_exit(block_mutex); - ut_a(num_entries < BUF_LRU_DROP_SEARCH_HASH_SIZE); - ++num_entries; - - if (num_entries < BUF_LRU_DROP_SEARCH_HASH_SIZE) { - goto next_page; - } - /* Array full. We release the buf_pool_mutex to - obey the latching order. */ - buf_pool_mutex_exit(); - - buf_LRU_drop_page_hash_batch(id, zip_size, page_arr, - num_entries); - num_entries = 0; - buf_pool_mutex_enter(); - } else { - mutex_exit(block_mutex); + if (num_entries < BUF_LRU_DROP_SEARCH_HASH_SIZE) { + goto next_page; } -next_page: - /* Note that we may have released the buf_pool mutex - above after reading the prev_bpage during processing - of a page_hash_batch (i.e.: when the array was full). - This means that prev_bpage can change in LRU list. - This is OK because this function is a 'best effort' - to drop as many search hash entries as possible and - it does not guarantee that ALL such entries will be - dropped. */ - bpage = prev_bpage; + /* Array full. We release the buf_pool_mutex to + obey the latching order. */ + buf_pool_mutex_exit(); + buf_LRU_drop_page_hash_batch(id, zip_size, page_arr, + num_entries); + buf_pool_mutex_enter(); + num_entries = 0; + + /* Note that we released the buf_pool mutex above + after reading the prev_bpage during processing of a + page_hash_batch (i.e.: when the array was full). + Because prev_bpage could belong to a compressed-only + block, it may have been relocated, and thus the + pointer cannot be trusted. Because bpage is of type + buf_block_t, it is safe to dereference. + + bpage can change in the LRU list. This is OK because + this function is a 'best effort' to drop as many + search hash entries as possible and it does not + guarantee that ALL such entries will be dropped. */ /* If, however, bpage has been removed from LRU list to the free list then we should restart the scan. bpage->state is protected by buf_pool mutex. */ - if (bpage && !buf_page_in_file(bpage)) { - ut_a(num_entries == 0); + if (bpage + && buf_page_get_state(bpage) != BUF_BLOCK_FILE_PAGE) { goto scan_again; } } @@ -1799,6 +1803,7 @@ buf_LRU_block_remove_hashed_page( buf_pool_mutex_exit_forbid(); buf_buddy_free(bpage->zip.data, page_zip_get_size(&bpage->zip)); + bpage->state = BUF_BLOCK_ZIP_FREE; buf_buddy_free(bpage, sizeof(*bpage)); buf_pool_mutex_exit_allow(); UNIV_MEM_UNDESC(bpage); diff --git a/storage/innodb_plugin/include/buf0buf.h b/storage/innodb_plugin/include/buf0buf.h index a16de67aa3a..05dead5ac9e 100644 --- a/storage/innodb_plugin/include/buf0buf.h +++ b/storage/innodb_plugin/include/buf0buf.h @@ -41,6 +41,8 @@ Created 11/5/1995 Heikki Tuuri /* @{ */ #define BUF_GET 10 /*!< get always */ #define BUF_GET_IF_IN_POOL 11 /*!< get if in pool */ +#define BUF_PEEK_IF_IN_POOL 12 /*!< get if in pool, do not make + the block young in the LRU list */ #define BUF_GET_NO_LATCH 14 /*!< get and bufferfix, but set no latch; we have separated this case, because @@ -284,7 +286,7 @@ buf_page_get_gen( ulint rw_latch,/*!< in: RW_S_LATCH, RW_X_LATCH, RW_NO_LATCH */ buf_block_t* guess, /*!< in: guessed block or NULL */ ulint mode, /*!< in: BUF_GET, BUF_GET_IF_IN_POOL, - BUF_GET_NO_LATCH */ + BUF_PEEK_IF_IN_POOL, BUF_GET_NO_LATCH */ const char* file, /*!< in: file name */ ulint line, /*!< in: line where called */ mtr_t* mtr); /*!< in: mini-transaction */ From 08f128f63323924666caf4f7cb0d2b3c39d2b017 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 7 Mar 2011 09:42:07 -0600 Subject: [PATCH 08/18] Bug#60196 / Bug#11831040 Setting lowercase_table_names to 2 on Windows causing Foreign Key problems This problem was exposed by the fix for Bug#55222. There was a codepath in dict0load.c, dict_load_foreigns() that made sure the table name matched case sensitive in order to load a referenced table into the dictionary as needed. If an engine is rebooted which accesses a table with foreign keys, and lower_case_table_names=2, then the table with foreign keys will get an error when it is changed (insert/updated/delete). Once the referenced tables are loaded into the dictionary cache by a select statement on those tables, the same change would succeed because the affected code path would not get followed. --- .../suite/innodb/r/innodb_bug60196.result | 76 ++++++++++++++++ .../suite/innodb/t/innodb_bug60196-master.opt | 1 + .../suite/innodb/t/innodb_bug60196.test | 91 +++++++++++++++++++ storage/innobase/dict/dict0load.c | 8 +- 4 files changed, 173 insertions(+), 3 deletions(-) create mode 100755 mysql-test/suite/innodb/r/innodb_bug60196.result create mode 100755 mysql-test/suite/innodb/t/innodb_bug60196-master.opt create mode 100755 mysql-test/suite/innodb/t/innodb_bug60196.test diff --git a/mysql-test/suite/innodb/r/innodb_bug60196.result b/mysql-test/suite/innodb/r/innodb_bug60196.result new file mode 100755 index 00000000000..296c5ce7e1d --- /dev/null +++ b/mysql-test/suite/innodb/r/innodb_bug60196.result @@ -0,0 +1,76 @@ +DROP TABLE IF EXISTS Bug_60196_FK1 ; +DROP TABLE IF EXISTS Bug_60196_FK2 ; +DROP TABLE IF EXISTS Bug_60196 ; +CREATE TABLE `Bug_60196_FK1` (Primary_Key INT PRIMARY KEY) ENGINE=InnoDB; +CREATE TABLE `Bug_60196_FK2` (Primary_Key INT PRIMARY KEY) ENGINE=InnoDB; +CREATE TABLE `Bug_60196` ( +FK1_Key INT NOT NULL, +FK2_Key INT NOT NULL, +PRIMARY KEY (FK2_Key, FK1_Key), +KEY FK1_Key (FK1_Key), +KEY FK2_Key (FK2_Key), +CONSTRAINT FK_FK1 FOREIGN KEY (FK1_Key) +REFERENCES Bug_60196_FK1 (Primary_Key) +ON DELETE CASCADE +ON UPDATE CASCADE, +CONSTRAINT FK_FK2 FOREIGN KEY (FK2_Key) +REFERENCES Bug_60196_FK2 (Primary_Key) +ON DELETE CASCADE +ON UPDATE CASCADE +) ENGINE=InnoDB; +INSERT INTO Bug_60196_FK1 VALUES (1), (2), (3), (4), (5); +INSERT INTO Bug_60196_FK2 VALUES (1), (2), (3), (4), (5); +INSERT INTO Bug_60196 VALUES (1, 1); +INSERT INTO Bug_60196 VALUES (1, 2); +INSERT INTO Bug_60196 VALUES (1, 3); +INSERT INTO Bug_60196 VALUES (1, 99); +ERROR 23000: Cannot add or update a child row: a foreign key constraint fails (`test`.`bug_60196`, CONSTRAINT `FK_FK2` FOREIGN KEY (`FK2_Key`) REFERENCES `Bug_60196_FK2` (`Primary_Key`) ON DELETE CASCADE ON UPDATE CASCADE) +INSERT INTO Bug_60196 VALUES (99, 1); +ERROR 23000: Cannot add or update a child row: a foreign key constraint fails (`test`.`bug_60196`, CONSTRAINT `FK_FK1` FOREIGN KEY (`FK1_Key`) REFERENCES `Bug_60196_FK1` (`Primary_Key`) ON DELETE CASCADE ON UPDATE CASCADE) +SELECT * FROM bug_60196_FK1; +Primary_Key +1 +2 +3 +4 +5 +SELECT * FROM bug_60196_FK2; +Primary_Key +1 +2 +3 +4 +5 +SELECT * FROM bug_60196; +FK1_Key FK2_Key +1 1 +1 2 +1 3 +# Stop master server +# Restart server. +# +# Try to insert more to the example table with foreign keys. +# Bug60196 causes the foreign key file not to be found after +# the resstart above. +# +SELECT * FROM Bug_60196; +FK1_Key FK2_Key +1 1 +1 2 +1 3 +INSERT INTO Bug_60196 VALUES (2, 1); +INSERT INTO Bug_60196 VALUES (2, 2); +INSERT INTO Bug_60196 VALUES (2, 3); +SELECT * FROM Bug_60196; +FK1_Key FK2_Key +1 1 +1 2 +1 3 +2 1 +2 2 +2 3 + +# Clean up. +DROP TABLE Bug_60196; +DROP TABLE Bug_60196_FK1; +DROP TABLE Bug_60196_FK2; diff --git a/mysql-test/suite/innodb/t/innodb_bug60196-master.opt b/mysql-test/suite/innodb/t/innodb_bug60196-master.opt new file mode 100755 index 00000000000..c0a1981fa7c --- /dev/null +++ b/mysql-test/suite/innodb/t/innodb_bug60196-master.opt @@ -0,0 +1 @@ +--lower-case-table-names=2 diff --git a/mysql-test/suite/innodb/t/innodb_bug60196.test b/mysql-test/suite/innodb/t/innodb_bug60196.test new file mode 100755 index 00000000000..70da220d68a --- /dev/null +++ b/mysql-test/suite/innodb/t/innodb_bug60196.test @@ -0,0 +1,91 @@ +# Bug#60196 - Setting lowercase_table_names to 2 on Windows causing +# Foreign Key problems after an engine is restarted. + +# This test case needs InnoDB. +-- source include/have_innodb.inc + +# +# Precautionary clean up. +# +--disable_warnings +DROP TABLE IF EXISTS Bug_60196_FK1 ; +DROP TABLE IF EXISTS Bug_60196_FK2 ; +DROP TABLE IF EXISTS Bug_60196 ; +--enable_warnings + +# +# Create test data. +# +CREATE TABLE `Bug_60196_FK1` (Primary_Key INT PRIMARY KEY) ENGINE=InnoDB; +CREATE TABLE `Bug_60196_FK2` (Primary_Key INT PRIMARY KEY) ENGINE=InnoDB; +CREATE TABLE `Bug_60196` ( + FK1_Key INT NOT NULL, + FK2_Key INT NOT NULL, + PRIMARY KEY (FK2_Key, FK1_Key), + KEY FK1_Key (FK1_Key), + KEY FK2_Key (FK2_Key), + CONSTRAINT FK_FK1 FOREIGN KEY (FK1_Key) + REFERENCES Bug_60196_FK1 (Primary_Key) + ON DELETE CASCADE + ON UPDATE CASCADE, + CONSTRAINT FK_FK2 FOREIGN KEY (FK2_Key) + REFERENCES Bug_60196_FK2 (Primary_Key) + ON DELETE CASCADE + ON UPDATE CASCADE +) ENGINE=InnoDB; +INSERT INTO Bug_60196_FK1 VALUES (1), (2), (3), (4), (5); +INSERT INTO Bug_60196_FK2 VALUES (1), (2), (3), (4), (5); +INSERT INTO Bug_60196 VALUES (1, 1); +INSERT INTO Bug_60196 VALUES (1, 2); +INSERT INTO Bug_60196 VALUES (1, 3); +--error ER_NO_REFERENCED_ROW_2 +INSERT INTO Bug_60196 VALUES (1, 99); +--error ER_NO_REFERENCED_ROW_2 +INSERT INTO Bug_60196 VALUES (99, 1); + +SELECT * FROM bug_60196_FK1; +SELECT * FROM bug_60196_FK2; +SELECT * FROM bug_60196; + +--echo # Stop master server + +# Write file to make mysql-test-run.pl wait for the server to stop +-- exec echo "wait" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect + +# Send a shutdown request to the server +-- shutdown_server 10 + +# Call script that will poll the server waiting for it to disapear +-- source include/wait_until_disconnected.inc + +--echo # Restart server. + +# Write file to make mysql-test-run.pl start up the server again +--exec echo "restart" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect + +# Turn on reconnect +--enable_reconnect + +# Call script that will poll the server waiting for it to be back online again +--source include/wait_until_connected_again.inc + +# Turn off reconnect again +--disable_reconnect + +--echo # +--echo # Try to insert more to the example table with foreign keys. +--echo # Bug60196 causes the foreign key file not to be found after +--echo # the resstart above. +--echo # +SELECT * FROM Bug_60196; +INSERT INTO Bug_60196 VALUES (2, 1); +INSERT INTO Bug_60196 VALUES (2, 2); +INSERT INTO Bug_60196 VALUES (2, 3); +SELECT * FROM Bug_60196; + +--echo +--echo # Clean up. +DROP TABLE Bug_60196; +DROP TABLE Bug_60196_FK1; +DROP TABLE Bug_60196_FK2; + diff --git a/storage/innobase/dict/dict0load.c b/storage/innobase/dict/dict0load.c index 14490980bb6..37bf4a1ad59 100644 --- a/storage/innobase/dict/dict0load.c +++ b/storage/innobase/dict/dict0load.c @@ -2258,10 +2258,12 @@ loop: /* Since table names in SYS_FOREIGN are stored in a case-insensitive order, we have to check that the table name matches also in a binary string comparison. On Unix, MySQL allows table names that only differ - in character case. */ - - if (0 != ut_memcmp(field, table_name, len)) { + in character case. If lower_case_table_names=2 then what is stored + may not be the same case, but the previous comparison showed that they + match with no-case. */ + if ((srv_lower_case_table_names != 2) + && (0 != ut_memcmp(field, table_name, len))) { goto next_rec; } From 537d8efbe4df7ff664a08a37549d8c2d7180dd00 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 8 Mar 2011 09:04:13 -0600 Subject: [PATCH 09/18] Fix test failure on case-sensitive file systems. --- mysql-test/suite/innodb/t/innodb_bug60196.test | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/mysql-test/suite/innodb/t/innodb_bug60196.test b/mysql-test/suite/innodb/t/innodb_bug60196.test index 70da220d68a..6d77baf8d6c 100755 --- a/mysql-test/suite/innodb/t/innodb_bug60196.test +++ b/mysql-test/suite/innodb/t/innodb_bug60196.test @@ -2,7 +2,9 @@ # Foreign Key problems after an engine is restarted. # This test case needs InnoDB. --- source include/have_innodb.inc +--source include/have_innodb.inc +--source include/have_lowercase2.inc +--source include/have_case_insensitive_file_system.inc # # Precautionary clean up. From 64e19595981611d1e39bbdba2fb3d91a15507db6 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 9 Mar 2011 11:15:55 -0600 Subject: [PATCH 10/18] Bug#60196 / Bug#11831040 Test case cannot run on embedded server. No need for precautionary cleanup of unique names. --- .../suite/innodb/r/innodb_bug60196.result | 11 ++++----- .../suite/innodb/t/innodb_bug60196.test | 24 +++++++------------ 2 files changed, 13 insertions(+), 22 deletions(-) diff --git a/mysql-test/suite/innodb/r/innodb_bug60196.result b/mysql-test/suite/innodb/r/innodb_bug60196.result index 296c5ce7e1d..85707f81a28 100755 --- a/mysql-test/suite/innodb/r/innodb_bug60196.result +++ b/mysql-test/suite/innodb/r/innodb_bug60196.result @@ -1,9 +1,6 @@ -DROP TABLE IF EXISTS Bug_60196_FK1 ; -DROP TABLE IF EXISTS Bug_60196_FK2 ; -DROP TABLE IF EXISTS Bug_60196 ; -CREATE TABLE `Bug_60196_FK1` (Primary_Key INT PRIMARY KEY) ENGINE=InnoDB; -CREATE TABLE `Bug_60196_FK2` (Primary_Key INT PRIMARY KEY) ENGINE=InnoDB; -CREATE TABLE `Bug_60196` ( +CREATE TABLE Bug_60196_FK1 (Primary_Key INT PRIMARY KEY) ENGINE=InnoDB; +CREATE TABLE Bug_60196_FK2 (Primary_Key INT PRIMARY KEY) ENGINE=InnoDB; +CREATE TABLE Bug_60196 ( FK1_Key INT NOT NULL, FK2_Key INT NOT NULL, PRIMARY KEY (FK2_Key, FK1_Key), @@ -46,7 +43,7 @@ FK1_Key FK2_Key 1 1 1 2 1 3 -# Stop master server +# Stop server # Restart server. # # Try to insert more to the example table with foreign keys. diff --git a/mysql-test/suite/innodb/t/innodb_bug60196.test b/mysql-test/suite/innodb/t/innodb_bug60196.test index 6d77baf8d6c..47c646a5a75 100755 --- a/mysql-test/suite/innodb/t/innodb_bug60196.test +++ b/mysql-test/suite/innodb/t/innodb_bug60196.test @@ -1,26 +1,20 @@ # Bug#60196 - Setting lowercase_table_names to 2 on Windows causing # Foreign Key problems after an engine is restarted. -# This test case needs InnoDB. ---source include/have_innodb.inc +# This test case needs InnoDB, a lowercase file system, +# lower-case-table-names=2, and cannot use the embedded server +# because it restarts the server. +--source include/not_embedded.inc --source include/have_lowercase2.inc --source include/have_case_insensitive_file_system.inc - -# -# Precautionary clean up. -# ---disable_warnings -DROP TABLE IF EXISTS Bug_60196_FK1 ; -DROP TABLE IF EXISTS Bug_60196_FK2 ; -DROP TABLE IF EXISTS Bug_60196 ; ---enable_warnings +--source include/have_innodb.inc # # Create test data. # -CREATE TABLE `Bug_60196_FK1` (Primary_Key INT PRIMARY KEY) ENGINE=InnoDB; -CREATE TABLE `Bug_60196_FK2` (Primary_Key INT PRIMARY KEY) ENGINE=InnoDB; -CREATE TABLE `Bug_60196` ( +CREATE TABLE Bug_60196_FK1 (Primary_Key INT PRIMARY KEY) ENGINE=InnoDB; +CREATE TABLE Bug_60196_FK2 (Primary_Key INT PRIMARY KEY) ENGINE=InnoDB; +CREATE TABLE Bug_60196 ( FK1_Key INT NOT NULL, FK2_Key INT NOT NULL, PRIMARY KEY (FK2_Key, FK1_Key), @@ -49,7 +43,7 @@ SELECT * FROM bug_60196_FK1; SELECT * FROM bug_60196_FK2; SELECT * FROM bug_60196; ---echo # Stop master server +--echo # Stop server # Write file to make mysql-test-run.pl wait for the server to stop -- exec echo "wait" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect From 4f4b404e59ec941a3128caaa753f26a0ad8bef88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Tue, 15 Mar 2011 12:01:02 +0200 Subject: [PATCH 11/18] Bug#11849231 inflateInit() invoked without initializing all memory According to the zlib documentation, next_in and avail_in must be initialized before invoking inflateInit or inflateInit2. Furthermore, the zalloc function must clear the allocated memory. btr_copy_zblob_prefix(): Replace the d_stream parameter with buf,len and return the copied length. page_zip_decompress(): Invoke inflateInit2 a little later. page_zip_zalloc(): Rename from page_zip_alloc(). Invoke mem_heap_zalloc() instead of mem_heap_alloc(). rb:619 approved by Jimmy Yang --- storage/innodb_plugin/ChangeLog | 5 ++ storage/innodb_plugin/btr/btr0cur.c | 76 ++++++++++++++------------- storage/innodb_plugin/page/page0zip.c | 17 +++--- 3 files changed, 53 insertions(+), 45 deletions(-) diff --git a/storage/innodb_plugin/ChangeLog b/storage/innodb_plugin/ChangeLog index fdd29908192..7c82cd9c27f 100644 --- a/storage/innodb_plugin/ChangeLog +++ b/storage/innodb_plugin/ChangeLog @@ -1,3 +1,8 @@ +2011-03-15 The InnoDB Team + + * btr/btr0cur.c, page/page0zip.c: + Fix Bug#11849231 inflateInit() invoked without initializing all memory + 2011-02-28 The InnoDB Team * btr/btr0sea.c, buf/buf0buf.c, buf/buf0lru.c: diff --git a/storage/innodb_plugin/btr/btr0cur.c b/storage/innodb_plugin/btr/btr0cur.c index 86d77c79e7b..d7b5ed0d135 100644 --- a/storage/innodb_plugin/btr/btr0cur.c +++ b/storage/innodb_plugin/btr/btr0cur.c @@ -4627,27 +4627,45 @@ btr_copy_blob_prefix( /*******************************************************************//** Copies the prefix of a compressed BLOB. The clustered index record -that points to this BLOB must be protected by a lock or a page latch. */ +that points to this BLOB must be protected by a lock or a page latch. +@return number of bytes written to buf */ static -void +ulint btr_copy_zblob_prefix( /*==================*/ - z_stream* d_stream,/*!< in/out: the decompressing stream */ + byte* buf, /*!< out: the externally stored part of + the field, or a prefix of it */ + ulint len, /*!< in: length of buf, in bytes */ ulint zip_size,/*!< in: compressed BLOB page size */ ulint space_id,/*!< in: space id of the BLOB pages */ ulint page_no,/*!< in: page number of the first BLOB page */ ulint offset) /*!< in: offset on the first BLOB page */ { - ulint page_type = FIL_PAGE_TYPE_ZBLOB; + ulint page_type = FIL_PAGE_TYPE_ZBLOB; + mem_heap_t* heap; + int err; + z_stream d_stream; + + d_stream.next_out = buf; + d_stream.avail_out = len; + d_stream.next_in = Z_NULL; + d_stream.avail_in = 0; + + /* Zlib inflate needs 32 kilobytes for the default + window size, plus a few kilobytes for small objects. */ + heap = mem_heap_create(40000); + page_zip_set_alloc(&d_stream, heap); ut_ad(ut_is_2pow(zip_size)); ut_ad(zip_size >= PAGE_ZIP_MIN_SIZE); ut_ad(zip_size <= UNIV_PAGE_SIZE); ut_ad(space_id); + err = inflateInit(&d_stream); + ut_a(err == Z_OK); + for (;;) { buf_page_t* bpage; - int err; ulint next_page_no; /* There is no latch on bpage directly. Instead, @@ -4663,7 +4681,7 @@ btr_copy_zblob_prefix( " compressed BLOB" " page %lu space %lu\n", (ulong) page_no, (ulong) space_id); - return; + goto func_exit; } if (UNIV_UNLIKELY @@ -4689,13 +4707,13 @@ btr_copy_zblob_prefix( offset += 4; } - d_stream->next_in = bpage->zip.data + offset; - d_stream->avail_in = zip_size - offset; + d_stream.next_in = bpage->zip.data + offset; + d_stream.avail_in = zip_size - offset; - err = inflate(d_stream, Z_NO_FLUSH); + err = inflate(&d_stream, Z_NO_FLUSH); switch (err) { case Z_OK: - if (!d_stream->avail_out) { + if (!d_stream.avail_out) { goto end_of_blob; } break; @@ -4712,13 +4730,13 @@ inflate_error: " compressed BLOB" " page %lu space %lu returned %d (%s)\n", (ulong) page_no, (ulong) space_id, - err, d_stream->msg); + err, d_stream.msg); case Z_BUF_ERROR: goto end_of_blob; } if (next_page_no == FIL_NULL) { - if (!d_stream->avail_in) { + if (!d_stream.avail_in) { ut_print_timestamp(stderr); fprintf(stderr, " InnoDB: unexpected end of" @@ -4727,7 +4745,7 @@ inflate_error: (ulong) page_no, (ulong) space_id); } else { - err = inflate(d_stream, Z_FINISH); + err = inflate(&d_stream, Z_FINISH); switch (err) { case Z_STREAM_END: case Z_BUF_ERROR: @@ -4739,7 +4757,7 @@ inflate_error: end_of_blob: buf_page_release_zip(bpage); - return; + goto func_exit; } buf_page_release_zip(bpage); @@ -4751,6 +4769,12 @@ end_of_blob: offset = FIL_PAGE_NEXT; page_type = FIL_PAGE_TYPE_ZBLOB2; } + +func_exit: + inflateEnd(&d_stream); + mem_heap_free(heap); + UNIV_MEM_ASSERT_RW(buf, d_stream.total_out); + return(d_stream.total_out); } /*******************************************************************//** @@ -4776,28 +4800,8 @@ btr_copy_externally_stored_field_prefix_low( } if (UNIV_UNLIKELY(zip_size)) { - int err; - z_stream d_stream; - mem_heap_t* heap; - - /* Zlib inflate needs 32 kilobytes for the default - window size, plus a few kilobytes for small objects. */ - heap = mem_heap_create(40000); - page_zip_set_alloc(&d_stream, heap); - - err = inflateInit(&d_stream); - ut_a(err == Z_OK); - - d_stream.next_out = buf; - d_stream.avail_out = len; - d_stream.avail_in = 0; - - btr_copy_zblob_prefix(&d_stream, zip_size, - space_id, page_no, offset); - inflateEnd(&d_stream); - mem_heap_free(heap); - UNIV_MEM_ASSERT_RW(buf, d_stream.total_out); - return(d_stream.total_out); + return(btr_copy_zblob_prefix(buf, len, zip_size, + space_id, page_no, offset)); } else { return(btr_copy_blob_prefix(buf, len, space_id, page_no, offset)); diff --git a/storage/innodb_plugin/page/page0zip.c b/storage/innodb_plugin/page/page0zip.c index a1dd4177ba8..6e866b3f016 100644 --- a/storage/innodb_plugin/page/page0zip.c +++ b/storage/innodb_plugin/page/page0zip.c @@ -653,13 +653,13 @@ page_zip_dir_encode( Allocate memory for zlib. */ static void* -page_zip_malloc( +page_zip_zalloc( /*============*/ void* opaque, /*!< in/out: memory heap */ uInt items, /*!< in: number of items to allocate */ uInt size) /*!< in: size of an item in bytes */ { - return(mem_heap_alloc(opaque, items * size)); + return(mem_heap_zalloc(opaque, items * size)); } /**********************************************************************//** @@ -684,7 +684,7 @@ page_zip_set_alloc( { z_stream* strm = stream; - strm->zalloc = page_zip_malloc; + strm->zalloc = page_zip_zalloc; strm->zfree = page_zip_free; strm->opaque = heap; } @@ -2912,19 +2912,18 @@ zlib_error: page_zip_set_alloc(&d_stream, heap); - if (UNIV_UNLIKELY(inflateInit2(&d_stream, UNIV_PAGE_SIZE_SHIFT) - != Z_OK)) { - ut_error; - } - d_stream.next_in = page_zip->data + PAGE_DATA; /* Subtract the space reserved for the page header and the end marker of the modification log. */ d_stream.avail_in = page_zip_get_size(page_zip) - (PAGE_DATA + 1); - d_stream.next_out = page + PAGE_ZIP_START; d_stream.avail_out = UNIV_PAGE_SIZE - PAGE_ZIP_START; + if (UNIV_UNLIKELY(inflateInit2(&d_stream, UNIV_PAGE_SIZE_SHIFT) + != Z_OK)) { + ut_error; + } + /* Decode the zlib header and the index information. */ if (UNIV_UNLIKELY(inflate(&d_stream, Z_BLOCK) != Z_OK)) { From 43088122810bcf96567375d3ec103afd4c559ef6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Tue, 15 Mar 2011 15:24:51 +0200 Subject: [PATCH 12/18] Remove trailing white space. --- storage/innobase/buf/buf0buf.c | 46 +++++++++++++++++----------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/storage/innobase/buf/buf0buf.c b/storage/innobase/buf/buf0buf.c index fcfc15f03e8..aece9586fd2 100644 --- a/storage/innobase/buf/buf0buf.c +++ b/storage/innobase/buf/buf0buf.c @@ -1233,7 +1233,7 @@ buf_pool_init_instance( buf_pool->page_hash = hash_create(2 * buf_pool->curr_size); buf_pool->zip_hash = hash_create(2 * buf_pool->curr_size); - + buf_pool->last_printout_time = ut_time(); } /* 2. Initialize flushing fields @@ -1365,11 +1365,11 @@ buf_pool_drop_hash_index_instance( /* block->is_hashed cannot be modified when we have an x-latch on btr_search_latch; see the comment in buf0buf.h */ - + if (!block->is_hashed) { continue; } - + /* To follow the latching order, we have to release btr_search_latch before acquiring block->latch. */ @@ -1378,14 +1378,14 @@ buf_pool_drop_hash_index_instance( we must rescan all blocks, because some may become hashed again. */ *released_search_latch = TRUE; - + rw_lock_x_lock(&block->lock); - + /* This should be guaranteed by the callers, which will be holding btr_search_enabled_mutex. */ ut_ad(!btr_search_enabled); - + /* Because we did not buffer-fix the block by calling buf_block_get_gen(), it is possible that the block has been @@ -1395,7 +1395,7 @@ buf_pool_drop_hash_index_instance( block is mapped to. All we want to do is to drop any hash entries referring to the page. */ - + /* It is possible that block->page.state != BUF_FILE_PAGE. Even that does not matter, because @@ -1403,18 +1403,18 @@ buf_pool_drop_hash_index_instance( check block->is_hashed before doing anything. block->is_hashed can only be set on uncompressed file pages. */ - + btr_search_drop_page_hash_index(block); - + rw_lock_x_unlock(&block->lock); - + rw_lock_x_lock(&btr_search_latch); - + ut_ad(!btr_search_enabled); } } } - + /********************************************************************//** Drops the adaptive hash index. To prevent a livelock, this function is only to be called while holding btr_search_latch and while @@ -1990,30 +1990,30 @@ buf_pool_resize(void) ulint min_change_size = 1048576 * srv_buf_pool_instances; buf_pool_mutex_enter_all(); - + if (srv_buf_pool_old_size == srv_buf_pool_size) { - + buf_pool_mutex_exit_all(); return; } else if (srv_buf_pool_curr_size + min_change_size > srv_buf_pool_size) { - + change_size = (srv_buf_pool_curr_size - srv_buf_pool_size) / UNIV_PAGE_SIZE; buf_pool_mutex_exit_all(); - + /* Disable adaptive hash indexes and empty the index in order to free up memory in the buffer pool chunks. */ buf_pool_shrink(change_size); } else if (srv_buf_pool_curr_size + min_change_size < srv_buf_pool_size) { - + /* Enlarge the buffer pool by at least one megabyte */ - + change_size = srv_buf_pool_size - srv_buf_pool_curr_size; buf_pool_mutex_exit_all(); @@ -2026,10 +2026,10 @@ buf_pool_resize(void) return; } - + buf_pool_page_hash_rebuild(); } - + /****************************************************************//** Remove the sentinel block for the watch before replacing it with a real block. buf_page_watch_clear() or buf_page_watch_occurred() will notice that @@ -2890,7 +2890,7 @@ wait_until_unfixed: Try again later. */ buf_pool_mutex_exit(buf_pool); os_thread_sleep(WAIT_FOR_READ); - + goto loop; } @@ -4806,7 +4806,7 @@ buf_get_modified_ratio_pct(void) buf_get_total_list_len(&lru_len, &free_len, &flush_list_len); ratio = (100 * flush_list_len) / (1 + lru_len + free_len); - + /* 1 + is there to avoid division by zero */ return(ratio); @@ -5189,7 +5189,7 @@ buf_all_freed(void) return(TRUE); } - + /*********************************************************************//** Checks that there currently are no pending i/o-operations for the buffer pool. From 0dc3b27245566356a9fdea37c2624f07ddade156 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Mon, 21 Mar 2011 09:27:58 +0200 Subject: [PATCH 13/18] Bug#11766305 - 59392: Remove thr0loc.c and ibuf_inside() [part 1] Remove unused member mtr from btr_pcur_struct. rb:624 approved by Sunny Bains --- storage/innobase/include/btr0pcur.h | 19 ------------------- storage/innobase/include/btr0pcur.ic | 28 ---------------------------- 2 files changed, 47 deletions(-) diff --git a/storage/innobase/include/btr0pcur.h b/storage/innobase/include/btr0pcur.h index 2334a266280..f0818b7586d 100644 --- a/storage/innobase/include/btr0pcur.h +++ b/storage/innobase/include/btr0pcur.h @@ -264,22 +264,6 @@ ulint btr_pcur_get_rel_pos( /*=================*/ const btr_pcur_t* cursor);/*!< in: persistent cursor */ -/*********************************************************//** -Sets the mtr field for a pcur. */ -UNIV_INLINE -void -btr_pcur_set_mtr( -/*=============*/ - btr_pcur_t* cursor, /*!< in: persistent cursor */ - mtr_t* mtr); /*!< in, own: mtr */ -/*********************************************************//** -Gets the mtr field for a pcur. -@return mtr */ -UNIV_INLINE -mtr_t* -btr_pcur_get_mtr( -/*=============*/ - btr_pcur_t* cursor); /*!< in: persistent cursor */ /**************************************************************//** Commits the mtr and sets the pcur latch mode to BTR_NO_LATCHES, that is, the cursor becomes detached. If there have been modifications @@ -517,9 +501,6 @@ struct btr_pcur_struct{ /* NOTE that the following fields may possess dynamically allocated memory which should be freed if not needed anymore! */ - mtr_t* mtr; /*!< NULL, or this field may contain - a mini-transaction which holds the - latch on the cursor page */ byte* old_rec_buf; /*!< NULL, or a dynamically allocated buffer for old_rec */ ulint buf_size; /*!< old_rec_buf size if old_rec_buf diff --git a/storage/innobase/include/btr0pcur.ic b/storage/innobase/include/btr0pcur.ic index 0c38797e6c5..35164576f62 100644 --- a/storage/innobase/include/btr0pcur.ic +++ b/storage/innobase/include/btr0pcur.ic @@ -42,34 +42,6 @@ btr_pcur_get_rel_pos( return(cursor->rel_pos); } -/*********************************************************//** -Sets the mtr field for a pcur. */ -UNIV_INLINE -void -btr_pcur_set_mtr( -/*=============*/ - btr_pcur_t* cursor, /*!< in: persistent cursor */ - mtr_t* mtr) /*!< in, own: mtr */ -{ - ut_ad(cursor); - - cursor->mtr = mtr; -} - -/*********************************************************//** -Gets the mtr field for a pcur. -@return mtr */ -UNIV_INLINE -mtr_t* -btr_pcur_get_mtr( -/*=============*/ - btr_pcur_t* cursor) /*!< in: persistent cursor */ -{ - ut_ad(cursor); - - return(cursor->mtr); -} - #ifdef UNIV_DEBUG /*********************************************************//** Returns the btr cursor component of a persistent cursor. From 0cedc70904ecd813c63e62792b3e804dded186e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Mon, 21 Mar 2011 09:56:38 +0200 Subject: [PATCH 14/18] Bug#11766305 - 59392: Remove thr0loc.c and ibuf_inside() [part 2] Add some const qualifiers to accessor and validator functions. btr_pcur_get_up_match(), btr_pcur_get_low_match(): Add const qualifiers. btr_pcur_get_page(), btr_pcur_get_block(), btr_pcur_get_rec(), rec_get_start(), rec_get_end(): Define as constness-preserving macros. In debug builds, discard the const qualifier. page_rec_validate(), page_simple_validate_old(), page_simple_validate_new(), page_dir_slot_check(), page_validate(): Add const qualifiers. rb:626 approved by Sunny Bains --- storage/innobase/include/btr0pcur.h | 21 +++--- storage/innobase/include/btr0pcur.ic | 17 ++--- storage/innobase/include/page0page.h | 8 +-- storage/innobase/include/rem0rec.h | 9 ++- storage/innobase/include/rem0rec.ic | 10 +-- storage/innobase/page/page0page.c | 98 ++++++++++++++-------------- 6 files changed, 87 insertions(+), 76 deletions(-) diff --git a/storage/innobase/include/btr0pcur.h b/storage/innobase/include/btr0pcur.h index f0818b7586d..6c11c973fc9 100644 --- a/storage/innobase/include/btr0pcur.h +++ b/storage/innobase/include/btr0pcur.h @@ -150,7 +150,7 @@ UNIV_INLINE ulint btr_pcur_get_up_match( /*==================*/ - btr_pcur_t* cursor); /*!< in: memory buffer for persistent cursor */ + const btr_pcur_t* cursor); /*!< in: persistent cursor */ /**************************************************************//** Gets the low_match value for a pcur after a search. @return number of matched fields at the cursor or to the right if @@ -159,7 +159,7 @@ UNIV_INLINE ulint btr_pcur_get_low_match( /*===================*/ - btr_pcur_t* cursor); /*!< in: memory buffer for persistent cursor */ + const btr_pcur_t* cursor); /*!< in: persistent cursor */ /**************************************************************//** If mode is PAGE_CUR_G or PAGE_CUR_GE, opens a persistent cursor on the first user record satisfying the search condition, in the case PAGE_CUR_L or @@ -371,10 +371,6 @@ page_cur_t* btr_pcur_get_page_cur( /*==================*/ const btr_pcur_t* cursor); /*!< in: persistent cursor */ -#else /* UNIV_DEBUG */ -# define btr_pcur_get_btr_cur(cursor) (&(cursor)->btr_cur) -# define btr_pcur_get_page_cur(cursor) (&(cursor)->btr_cur.page_cur) -#endif /* UNIV_DEBUG */ /*********************************************************//** Returns the page of a persistent cursor. @return pointer to the page */ @@ -382,7 +378,7 @@ UNIV_INLINE page_t* btr_pcur_get_page( /*==============*/ - btr_pcur_t* cursor);/*!< in: persistent cursor */ + const btr_pcur_t* cursor);/*!< in: persistent cursor */ /*********************************************************//** Returns the buffer block of a persistent cursor. @return pointer to the block */ @@ -390,7 +386,7 @@ UNIV_INLINE buf_block_t* btr_pcur_get_block( /*===============*/ - btr_pcur_t* cursor);/*!< in: persistent cursor */ + const btr_pcur_t* cursor);/*!< in: persistent cursor */ /*********************************************************//** Returns the record of a persistent cursor. @return pointer to the record */ @@ -398,7 +394,14 @@ UNIV_INLINE rec_t* btr_pcur_get_rec( /*=============*/ - btr_pcur_t* cursor);/*!< in: persistent cursor */ + const btr_pcur_t* cursor);/*!< in: persistent cursor */ +#else /* UNIV_DEBUG */ +# define btr_pcur_get_btr_cur(cursor) (&(cursor)->btr_cur) +# define btr_pcur_get_page_cur(cursor) (&(cursor)->btr_cur.page_cur) +# define btr_pcur_get_page(cursor) ((cursor)->btr_cur.page_cur.block->frame) +# define btr_pcur_get_block(cursor) ((cursor)->btr_cur.page_cur.block) +# define btr_pcur_get_rec(cursor) ((cursor)->btr_cur.page_cur.rec) +#endif /* UNIV_DEBUG */ /*********************************************************//** Checks if the persistent cursor is on a user record. */ UNIV_INLINE diff --git a/storage/innobase/include/btr0pcur.ic b/storage/innobase/include/btr0pcur.ic index 35164576f62..59fdb21824b 100644 --- a/storage/innobase/include/btr0pcur.ic +++ b/storage/innobase/include/btr0pcur.ic @@ -67,7 +67,7 @@ btr_pcur_get_page_cur( { return(btr_cur_get_page_cur(btr_pcur_get_btr_cur(cursor))); } -#endif /* UNIV_DEBUG */ + /*********************************************************//** Returns the page of a persistent cursor. @return pointer to the page */ @@ -75,7 +75,7 @@ UNIV_INLINE page_t* btr_pcur_get_page( /*==============*/ - btr_pcur_t* cursor) /*!< in: persistent cursor */ + const btr_pcur_t* cursor) /*!< in: persistent cursor */ { ut_ad(cursor->pos_state == BTR_PCUR_IS_POSITIONED); @@ -89,7 +89,7 @@ UNIV_INLINE buf_block_t* btr_pcur_get_block( /*===============*/ - btr_pcur_t* cursor) /*!< in: persistent cursor */ + const btr_pcur_t* cursor) /*!< in: persistent cursor */ { ut_ad(cursor->pos_state == BTR_PCUR_IS_POSITIONED); @@ -103,13 +103,14 @@ UNIV_INLINE rec_t* btr_pcur_get_rec( /*=============*/ - btr_pcur_t* cursor) /*!< in: persistent cursor */ + const btr_pcur_t* cursor) /*!< in: persistent cursor */ { ut_ad(cursor->pos_state == BTR_PCUR_IS_POSITIONED); ut_ad(cursor->latch_mode != BTR_NO_LATCHES); return(btr_cur_get_rec(btr_pcur_get_btr_cur(cursor))); } +#endif /* UNIV_DEBUG */ /**************************************************************//** Gets the up_match value for a pcur after a search. @@ -119,9 +120,9 @@ UNIV_INLINE ulint btr_pcur_get_up_match( /*==================*/ - btr_pcur_t* cursor) /*!< in: memory buffer for persistent cursor */ + const btr_pcur_t* cursor) /*!< in: persistent cursor */ { - btr_cur_t* btr_cursor; + const btr_cur_t* btr_cursor; ut_ad((cursor->pos_state == BTR_PCUR_WAS_POSITIONED) || (cursor->pos_state == BTR_PCUR_IS_POSITIONED)); @@ -141,9 +142,9 @@ UNIV_INLINE ulint btr_pcur_get_low_match( /*===================*/ - btr_pcur_t* cursor) /*!< in: memory buffer for persistent cursor */ + const btr_pcur_t* cursor) /*!< in: persistent cursor */ { - btr_cur_t* btr_cursor; + const btr_cur_t* btr_cursor; ut_ad((cursor->pos_state == BTR_PCUR_WAS_POSITIONED) || (cursor->pos_state == BTR_PCUR_IS_POSITIONED)); diff --git a/storage/innobase/include/page0page.h b/storage/innobase/include/page0page.h index 826fd13125d..0a15dfbf2a1 100644 --- a/storage/innobase/include/page0page.h +++ b/storage/innobase/include/page0page.h @@ -952,7 +952,7 @@ UNIV_INTERN ibool page_rec_validate( /*==============*/ - rec_t* rec, /*!< in: physical record */ + const rec_t* rec, /*!< in: physical record */ const ulint* offsets);/*!< in: array returned by rec_get_offsets() */ /***************************************************************//** Checks that the first directory slot points to the infimum record and @@ -972,7 +972,7 @@ UNIV_INTERN ibool page_simple_validate_old( /*=====================*/ - page_t* page); /*!< in: old-style index page */ + const page_t* page); /*!< in: index page in ROW_FORMAT=REDUNDANT */ /***************************************************************//** This function checks the consistency of an index page when we do not know the index. This is also resilient so that this should never crash @@ -982,7 +982,7 @@ UNIV_INTERN ibool page_simple_validate_new( /*=====================*/ - page_t* block); /*!< in: new-style index page */ + const page_t* page); /*!< in: index page in ROW_FORMAT!=REDUNDANT */ /***************************************************************//** This function checks the consistency of an index page. @return TRUE if ok */ @@ -990,7 +990,7 @@ UNIV_INTERN ibool page_validate( /*==========*/ - page_t* page, /*!< in: index page */ + const page_t* page, /*!< in: index page */ dict_index_t* index); /*!< in: data dictionary index containing the page record type definition */ /***************************************************************//** diff --git a/storage/innobase/include/rem0rec.h b/storage/innobase/include/rem0rec.h index 9ffb5c7d9e5..3d157f1da95 100644 --- a/storage/innobase/include/rem0rec.h +++ b/storage/innobase/include/rem0rec.h @@ -600,6 +600,7 @@ ulint rec_offs_size( /*==========*/ const ulint* offsets);/*!< in: array returned by rec_get_offsets() */ +#ifdef UNIV_DEBUG /**********************************************************//** Returns a pointer to the start of the record. @return pointer to start */ @@ -607,7 +608,7 @@ UNIV_INLINE byte* rec_get_start( /*==========*/ - rec_t* rec, /*!< in: pointer to record */ + const rec_t* rec, /*!< in: pointer to record */ const ulint* offsets);/*!< in: array returned by rec_get_offsets() */ /**********************************************************//** Returns a pointer to the end of the record. @@ -616,8 +617,12 @@ UNIV_INLINE byte* rec_get_end( /*========*/ - rec_t* rec, /*!< in: pointer to record */ + const rec_t* rec, /*!< in: pointer to record */ const ulint* offsets);/*!< in: array returned by rec_get_offsets() */ +#else /* UNIV_DEBUG */ +# define rec_get_start(rec, offsets) ((rec) - rec_offs_extra_size(offsets)) +# define rec_get_end(rec, offsets) ((rec) + rec_offs_data_size(offsets)) +#endif /* UNIV_DEBUG */ /***************************************************************//** Copies a physical record to a buffer. @return pointer to the origin of the copy */ diff --git a/storage/innobase/include/rem0rec.ic b/storage/innobase/include/rem0rec.ic index ba306eaf27f..3d386710d7d 100644 --- a/storage/innobase/include/rem0rec.ic +++ b/storage/innobase/include/rem0rec.ic @@ -1462,6 +1462,7 @@ rec_offs_size( return(rec_offs_data_size(offsets) + rec_offs_extra_size(offsets)); } +#ifdef UNIV_DEBUG /**********************************************************//** Returns a pointer to the end of the record. @return pointer to end */ @@ -1469,11 +1470,11 @@ UNIV_INLINE byte* rec_get_end( /*========*/ - rec_t* rec, /*!< in: pointer to record */ + const rec_t* rec, /*!< in: pointer to record */ const ulint* offsets)/*!< in: array returned by rec_get_offsets() */ { ut_ad(rec_offs_validate(rec, NULL, offsets)); - return(rec + rec_offs_data_size(offsets)); + return((rec_t*) rec + rec_offs_data_size(offsets)); } /**********************************************************//** @@ -1483,12 +1484,13 @@ UNIV_INLINE byte* rec_get_start( /*==========*/ - rec_t* rec, /*!< in: pointer to record */ + const rec_t* rec, /*!< in: pointer to record */ const ulint* offsets)/*!< in: array returned by rec_get_offsets() */ { ut_ad(rec_offs_validate(rec, NULL, offsets)); - return(rec - rec_offs_extra_size(offsets)); + return((rec_t*) rec - rec_offs_extra_size(offsets)); } +#endif /* UNIV_DEBUG */ /***************************************************************//** Copies a physical record to a buffer. diff --git a/storage/innobase/page/page0page.c b/storage/innobase/page/page0page.c index 99182e85849..964d0e2abef 100644 --- a/storage/innobase/page/page0page.c +++ b/storage/innobase/page/page0page.c @@ -166,11 +166,11 @@ static ibool page_dir_slot_check( /*================*/ - page_dir_slot_t* slot) /*!< in: slot */ + const page_dir_slot_t* slot) /*!< in: slot */ { - page_t* page; - ulint n_slots; - ulint n_owned; + const page_t* page; + ulint n_slots; + ulint n_owned; ut_a(slot); @@ -1803,12 +1803,12 @@ UNIV_INTERN ibool page_rec_validate( /*==============*/ - rec_t* rec, /*!< in: physical record */ + const rec_t* rec, /*!< in: physical record */ const ulint* offsets)/*!< in: array returned by rec_get_offsets() */ { - ulint n_owned; - ulint heap_no; - page_t* page; + ulint n_owned; + ulint heap_no; + const page_t* page; page = page_align(rec); ut_a(!page_is_comp(page) == !rec_offs_comp(offsets)); @@ -1889,16 +1889,16 @@ UNIV_INTERN ibool page_simple_validate_old( /*=====================*/ - page_t* page) /*!< in: old-style index page */ + const page_t* page) /*!< in: index page in ROW_FORMAT=REDUNDANT */ { - page_dir_slot_t* slot; - ulint slot_no; - ulint n_slots; - rec_t* rec; - byte* rec_heap_top; - ulint count; - ulint own_count; - ibool ret = FALSE; + const page_dir_slot_t* slot; + ulint slot_no; + ulint n_slots; + const rec_t* rec; + const byte* rec_heap_top; + ulint count; + ulint own_count; + ibool ret = FALSE; ut_a(!page_is_comp(page)); @@ -2011,7 +2011,7 @@ page_simple_validate_old( goto func_exit; } - rec = page_rec_get_next(rec); + rec = page_rec_get_next_const(rec); own_count++; } @@ -2072,7 +2072,7 @@ page_simple_validate_old( goto func_exit; } - rec = page_rec_get_next(rec); + rec = page_rec_get_next_const(rec); } if (UNIV_UNLIKELY(page_dir_get_n_heap(page) != count + 1)) { @@ -2099,16 +2099,16 @@ UNIV_INTERN ibool page_simple_validate_new( /*=====================*/ - page_t* page) /*!< in: new-style index page */ + const page_t* page) /*!< in: index page in ROW_FORMAT!=REDUNDANT */ { - page_dir_slot_t* slot; - ulint slot_no; - ulint n_slots; - rec_t* rec; - byte* rec_heap_top; - ulint count; - ulint own_count; - ibool ret = FALSE; + const page_dir_slot_t* slot; + ulint slot_no; + ulint n_slots; + const rec_t* rec; + const byte* rec_heap_top; + ulint count; + ulint own_count; + ibool ret = FALSE; ut_a(page_is_comp(page)); @@ -2221,7 +2221,7 @@ page_simple_validate_new( goto func_exit; } - rec = page_rec_get_next(rec); + rec = page_rec_get_next_const(rec); own_count++; } @@ -2283,7 +2283,7 @@ page_simple_validate_new( goto func_exit; } - rec = page_rec_get_next(rec); + rec = page_rec_get_next_const(rec); } if (UNIV_UNLIKELY(page_dir_get_n_heap(page) != count + 1)) { @@ -2308,26 +2308,26 @@ UNIV_INTERN ibool page_validate( /*==========*/ - page_t* page, /*!< in: index page */ + const page_t* page, /*!< in: index page */ dict_index_t* index) /*!< in: data dictionary index containing the page record type definition */ { - page_dir_slot_t*slot; - mem_heap_t* heap; - byte* buf; - ulint count; - ulint own_count; - ulint rec_own_count; - ulint slot_no; - ulint data_size; - rec_t* rec; - rec_t* old_rec = NULL; - ulint offs; - ulint n_slots; - ibool ret = FALSE; - ulint i; - ulint* offsets = NULL; - ulint* old_offsets = NULL; + const page_dir_slot_t* slot; + mem_heap_t* heap; + byte* buf; + ulint count; + ulint own_count; + ulint rec_own_count; + ulint slot_no; + ulint data_size; + const rec_t* rec; + const rec_t* old_rec = NULL; + ulint offs; + ulint n_slots; + ibool ret = FALSE; + ulint i; + ulint* offsets = NULL; + ulint* old_offsets = NULL; if (UNIV_UNLIKELY((ibool) !!page_is_comp(page) != dict_table_is_comp(index->table))) { @@ -2482,7 +2482,7 @@ page_validate( count++; own_count++; old_rec = rec; - rec = page_rec_get_next(rec); + rec = page_rec_get_next_const(rec); /* set old_offsets to offsets; recycle offsets */ { @@ -2556,7 +2556,7 @@ n_owned_zero: buf[offs + i] = 1; } - rec = page_rec_get_next(rec); + rec = page_rec_get_next_const(rec); } if (UNIV_UNLIKELY(page_dir_get_n_heap(page) != count + 1)) { From a4d2a3a3b47ebe44d02e89c2f258b62f3b4b8d89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Tue, 22 Mar 2011 13:39:16 +0200 Subject: [PATCH 15/18] Bug#11766305 - 59392: Remove thr0loc.c and ibuf_inside() [part 3] Remove the slot_no member of struct thr_local_struct. enum srv_thread_type: Remove unused thread types. srv_get_thread_type(): Unused function, remove. thr_local_get_slot_no(), thr_local_set_slot_no(): Remove. srv_thread_type_validate(), srv_slot_get_type(): New functions, for debugging. srv_table_reserve_slot(): Return the srv_slot_t* directly. Do not create thread-local storage. srv_suspend_thread(): Get the srv_slot_t* as parameter. Return void; the caller knows slot->event already. srv_thread_has_reserved_slot(), srv_release_threads(): Assert srv_thread_type_validate(type). srv_init(): Use mem_zalloc() instead of mem_alloc(). Replace srv_table_get_nth_slot(), because it now asserts that the kernel_mutex is being held. srv_master_thread(), srv_purge_thread(): Remember the slot from srv_table_reserve_slot(). rb:629 approved by Inaam Rana --- storage/innobase/include/srv0srv.h | 17 +-- storage/innobase/include/thr0loc.h | 16 --- storage/innobase/srv/srv0srv.c | 169 +++++++++++++---------------- storage/innobase/thr/thr0loc.c | 48 -------- 4 files changed, 74 insertions(+), 176 deletions(-) diff --git a/storage/innobase/include/srv0srv.h b/storage/innobase/include/srv0srv.h index 252d1424c63..fb5bc56920a 100644 --- a/storage/innobase/include/srv0srv.h +++ b/storage/innobase/include/srv0srv.h @@ -442,16 +442,8 @@ typedef enum srv_stats_method_name_enum srv_stats_method_name_t; #ifndef UNIV_HOTBACKUP /** Types of threads existing in the system. */ enum srv_thread_type { - SRV_COM = 1, /**< threads serving communication and queries */ - SRV_CONSOLE, /**< thread serving console */ - SRV_WORKER, /**< threads serving parallelized queries and + SRV_WORKER = 0, /**< threads serving parallelized queries and queries released from lock wait */ -#if 0 - /* Utility threads */ - SRV_BUFFER, /**< thread flushing dirty buffer blocks */ - SRV_RECOVERY, /**< threads finishing a recovery */ - SRV_INSERT, /**< thread flushing the insert buffer to disk */ -#endif SRV_MASTER /**< the master thread, (whose type number must be biggest) */ }; @@ -490,13 +482,6 @@ ulint srv_get_n_threads(void); /*===================*/ /*********************************************************************//** -Returns the calling thread type. -@return SRV_COM, ... */ - -enum srv_thread_type -srv_get_thread_type(void); -/*=====================*/ -/*********************************************************************//** Check whether thread type has reserved a slot. @return slot number or UNDEFINED if not found*/ UNIV_INTERN diff --git a/storage/innobase/include/thr0loc.h b/storage/innobase/include/thr0loc.h index b7eb29f2ed0..bc54f9693b3 100644 --- a/storage/innobase/include/thr0loc.h +++ b/storage/innobase/include/thr0loc.h @@ -59,22 +59,6 @@ thr_local_free( /*===========*/ os_thread_id_t id); /*!< in: thread id */ /*******************************************************************//** -Gets the slot number in the thread table of a thread. -@return slot number */ -UNIV_INTERN -ulint -thr_local_get_slot_no( -/*==================*/ - os_thread_id_t id); /*!< in: thread id of the thread */ -/*******************************************************************//** -Sets in the local storage the slot number in the thread table of a thread. */ -UNIV_INTERN -void -thr_local_set_slot_no( -/*==================*/ - os_thread_id_t id, /*!< in: thread id of the thread */ - ulint slot_no);/*!< in: slot number */ -/*******************************************************************//** Returns pointer to the 'in_ibuf' field within the current thread local storage. @return pointer to the in_ibuf field */ diff --git a/storage/innobase/srv/srv0srv.c b/storage/innobase/srv/srv0srv.c index 3c5eed448bd..59a2bc90052 100644 --- a/storage/innobase/srv/srv0srv.c +++ b/storage/innobase/srv/srv0srv.c @@ -690,7 +690,7 @@ Unix.*/ struct srv_slot_struct{ os_thread_id_t id; /*!< thread id */ os_thread_t handle; /*!< thread handle */ - unsigned type:3; /*!< thread type: user, utility etc. */ + unsigned type:1; /*!< thread type: user, utility etc. */ unsigned in_use:1; /*!< TRUE if this slot is in use */ unsigned suspended:1; /*!< TRUE if the thread is waiting for the event of this slot */ @@ -797,6 +797,7 @@ srv_table_get_nth_slot( /*===================*/ ulint index) /*!< in: index of the slot */ { + ut_ad(mutex_own(&kernel_mutex)); ut_a(index < OS_THREAD_MAX_N); return(srv_sys->threads + index); @@ -815,7 +816,7 @@ srv_get_n_threads(void) mutex_enter(&kernel_mutex); - for (i = SRV_COM; i < SRV_MASTER + 1; i++) { + for (i = 0; i < SRV_MASTER + 1; i++) { n_threads += srv_n_threads[i]; } @@ -825,13 +826,46 @@ srv_get_n_threads(void) return(n_threads); } +#ifdef UNIV_DEBUG /*********************************************************************//** -Reserves a slot in the thread table for the current thread. Also creates the -thread local storage struct for the current thread. NOTE! The server mutex -has to be reserved by the caller! -@return reserved slot index */ +Validates the type of a thread table slot. +@return TRUE if ok */ static -ulint +ibool +srv_thread_type_validate( +/*=====================*/ + enum srv_thread_type type) /*!< in: thread type */ +{ + switch (type) { + case SRV_WORKER: + case SRV_MASTER: + return(TRUE); + } + ut_error; + return(FALSE); +} +#endif /* UNIV_DEBUG */ + +/*********************************************************************//** +Gets the type of a thread table slot. +@return thread type */ +static +enum srv_thread_type +srv_slot_get_type( +/*==============*/ + const srv_slot_t* slot) /*!< in: thread slot */ +{ + enum srv_thread_type type = (enum srv_thread_type) slot->type; + ut_ad(srv_thread_type_validate(type)); + return(type); +} + +/*********************************************************************//** +Reserves a slot in the thread table for the current thread. +NOTE! The server mutex has to be reserved by the caller! +@return reserved slot */ +static +srv_slot_t* srv_table_reserve_slot( /*===================*/ enum srv_thread_type type) /*!< in: type of the thread */ @@ -839,8 +873,7 @@ srv_table_reserve_slot( srv_slot_t* slot; ulint i; - ut_a(type > 0); - ut_a(type <= SRV_MASTER); + ut_ad(srv_thread_type_validate(type)); ut_ad(mutex_own(&kernel_mutex)); i = 0; @@ -851,53 +884,40 @@ srv_table_reserve_slot( slot = srv_table_get_nth_slot(i); } - ut_a(slot->in_use == FALSE); - slot->in_use = TRUE; slot->suspended = FALSE; slot->type = type; + ut_ad(srv_slot_get_type(slot) == type); slot->id = os_thread_get_curr_id(); slot->handle = os_thread_get_curr(); - thr_local_create(); - - thr_local_set_slot_no(os_thread_get_curr_id(), i); - - return(i); + return(slot); } /*********************************************************************//** Suspends the calling thread to wait for the event in its thread slot. -NOTE! The server mutex has to be reserved by the caller! -@return event for the calling thread to wait */ +NOTE! The server mutex has to be reserved by the caller! */ static -os_event_t -srv_suspend_thread(void) -/*====================*/ +void +srv_suspend_thread( +/*===============*/ + srv_slot_t* slot) /*!< in/out: thread slot */ { - srv_slot_t* slot; - os_event_t event; - ulint slot_no; enum srv_thread_type type; ut_ad(mutex_own(&kernel_mutex)); - - slot_no = thr_local_get_slot_no(os_thread_get_curr_id()); + ut_ad(slot->in_use); + ut_ad(!slot->suspended); + ut_ad(slot->id == os_thread_get_curr_id()); if (srv_print_thread_releases) { fprintf(stderr, "Suspending thread %lu to slot %lu\n", - (ulong) os_thread_get_curr_id(), (ulong) slot_no); + (ulong) os_thread_get_curr_id(), + (ulong) (slot - srv_sys->threads)); } - slot = srv_table_get_nth_slot(slot_no); - - type = slot->type; - - ut_ad(type >= SRV_WORKER); - ut_ad(type <= SRV_MASTER); - - event = slot->event; + type = srv_slot_get_type(slot); slot->suspended = TRUE; @@ -905,9 +925,7 @@ srv_suspend_thread(void) srv_n_threads_active[type]--; - os_event_reset(event); - - return(event); + os_event_reset(slot->event); } /*********************************************************************//** @@ -926,8 +944,7 @@ srv_release_threads( ulint i; ulint count = 0; - ut_ad(type >= SRV_WORKER); - ut_ad(type <= SRV_MASTER); + ut_ad(srv_thread_type_validate(type)); ut_ad(n > 0); ut_ad(mutex_own(&kernel_mutex)); @@ -935,7 +952,8 @@ srv_release_threads( slot = srv_table_get_nth_slot(i); - if (slot->in_use && slot->type == type && slot->suspended) { + if (slot->in_use && slot->suspended + && srv_slot_get_type(slot) == type) { slot->suspended = FALSE; @@ -962,34 +980,6 @@ srv_release_threads( return(count); } -/*********************************************************************//** -Returns the calling thread type. -@return SRV_COM, ... */ -UNIV_INTERN -enum srv_thread_type -srv_get_thread_type(void) -/*=====================*/ -{ - ulint slot_no; - srv_slot_t* slot; - enum srv_thread_type type; - - mutex_enter(&kernel_mutex); - - slot_no = thr_local_get_slot_no(os_thread_get_curr_id()); - - slot = srv_table_get_nth_slot(slot_no); - - type = slot->type; - - ut_ad(type >= SRV_WORKER); - ut_ad(type <= SRV_MASTER); - - mutex_exit(&kernel_mutex); - - return(type); -} - /*********************************************************************//** Check whether thread type has reserved a slot. Return the first slot that is found. This works because we currently have only 1 thread of each type. @@ -1003,6 +993,7 @@ srv_thread_has_reserved_slot( ulint i; ulint slot_no = ULINT_UNDEFINED; + ut_ad(srv_thread_type_validate(type)); mutex_enter(&kernel_mutex); for (i = 0; i < OS_THREAD_MAX_N; i++) { @@ -1040,22 +1031,18 @@ srv_init(void) mutex_create(srv_innodb_monitor_mutex_key, &srv_innodb_monitor_mutex, SYNC_NO_ORDER_CHECK); - srv_sys->threads = mem_alloc(OS_THREAD_MAX_N * sizeof(srv_slot_t)); + srv_sys->threads = mem_zalloc(OS_THREAD_MAX_N * sizeof(srv_slot_t)); for (i = 0; i < OS_THREAD_MAX_N; i++) { - slot = srv_table_get_nth_slot(i); - slot->in_use = FALSE; - slot->type=0; /* Avoid purify errors */ + slot = srv_sys->threads + i; slot->event = os_event_create(NULL); ut_a(slot->event); } - srv_mysql_table = mem_alloc(OS_THREAD_MAX_N * sizeof(srv_slot_t)); + srv_mysql_table = mem_zalloc(OS_THREAD_MAX_N * sizeof(srv_slot_t)); for (i = 0; i < OS_THREAD_MAX_N; i++) { slot = srv_mysql_table + i; - slot->in_use = FALSE; - slot->type = 0; slot->event = os_event_create(NULL); ut_a(slot->event); } @@ -1501,7 +1488,7 @@ srv_table_reserve_slot_for_mysql(void) while (slot->in_use) { i++; - if (i >= OS_THREAD_MAX_N) { + if (UNIV_UNLIKELY(i >= OS_THREAD_MAX_N)) { ut_print_timestamp(stderr); @@ -2489,7 +2476,7 @@ srv_is_any_background_thread_active(void) mutex_enter(&kernel_mutex); - for (i = SRV_COM; i <= SRV_MASTER; ++i) { + for (i = 0; i <= SRV_MASTER; ++i) { if (srv_n_threads_active[i] != 0) { ret = TRUE; break; @@ -2643,7 +2630,7 @@ srv_master_thread( os_thread_create */ { buf_pool_stat_t buf_stat; - os_event_t event; + srv_slot_t* slot; ulint old_activity_count; ulint n_pages_purged = 0; ulint n_bytes_merged; @@ -2671,7 +2658,7 @@ srv_master_thread( mutex_enter(&kernel_mutex); - srv_table_reserve_slot(SRV_MASTER); + slot = srv_table_reserve_slot(SRV_MASTER); srv_n_threads_active[SRV_MASTER]++; @@ -3060,7 +3047,7 @@ suspend_thread: goto loop; } - event = srv_suspend_thread(); + srv_suspend_thread(slot); mutex_exit(&kernel_mutex); @@ -3070,7 +3057,7 @@ suspend_thread: manual also mentions this string in several places. */ srv_main_thread_op_info = "waiting for server activity"; - os_event_wait(event); + os_event_wait(slot->event); if (srv_shutdown_state == SRV_SHUTDOWN_EXIT_THREADS) { /* This is only extra safety, the thread should exit @@ -3100,7 +3087,6 @@ srv_purge_thread( { srv_slot_t* slot; ulint retries = 0; - ulint slot_no = ULINT_UNDEFINED; ulint n_total_purged = ULINT_UNDEFINED; ut_a(srv_n_purge_threads == 1); @@ -3116,9 +3102,7 @@ srv_purge_thread( mutex_enter(&kernel_mutex); - slot_no = srv_table_reserve_slot(SRV_WORKER); - - slot = srv_table_get_nth_slot(slot_no); + slot = srv_table_reserve_slot(SRV_WORKER); ++srv_n_threads_active[SRV_WORKER]; @@ -3137,15 +3121,13 @@ srv_purge_thread( || (n_total_purged == 0 && retries >= TRX_SYS_N_RSEGS)) { - os_event_t event; - mutex_enter(&kernel_mutex); - event = srv_suspend_thread(); + srv_suspend_thread(slot); mutex_exit(&kernel_mutex); - os_event_wait(event); + os_event_wait(slot->event); retries = 0; } @@ -3179,16 +3161,11 @@ srv_purge_thread( mutex_enter(&kernel_mutex); - ut_ad(srv_table_get_nth_slot(slot_no) == slot); - /* Decrement the active count. */ - srv_suspend_thread(); + srv_suspend_thread(slot); slot->in_use = FALSE; - /* Free the thread local memory. */ - thr_local_free(os_thread_get_curr_id()); - mutex_exit(&kernel_mutex); #ifdef UNIV_DEBUG_THREAD_CREATION diff --git a/storage/innobase/thr/thr0loc.c b/storage/innobase/thr/thr0loc.c index 2bd3e4b1c43..0fa93922bb1 100644 --- a/storage/innobase/thr/thr0loc.c +++ b/storage/innobase/thr/thr0loc.c @@ -65,8 +65,6 @@ for the field. */ struct thr_local_struct{ os_thread_id_t id; /*!< id of the thread which owns this struct */ os_thread_t handle; /*!< operating system handle to the thread */ - ulint slot_no;/*!< the index of the slot in the thread table - for this thread */ ibool in_ibuf;/*!< TRUE if the thread is doing an ibuf operation */ hash_node_t hash; /*!< hash chain node */ @@ -87,8 +85,6 @@ thr_local_validate( const thr_local_t* local) /*!< in: data to validate */ { ut_ad(local->magic_n == THR_LOCAL_MAGIC_N); - ut_ad(local->slot_no == ULINT_UNDEFINED - || local->slot_no < OS_THREAD_MAX_N); ut_ad(local->in_ibuf == FALSE || local->in_ibuf == TRUE); return(TRUE); } @@ -131,49 +127,6 @@ try_again: return(local); } -/*******************************************************************//** -Gets the slot number in the thread table of a thread. -@return slot number */ -UNIV_INTERN -ulint -thr_local_get_slot_no( -/*==================*/ - os_thread_id_t id) /*!< in: thread id of the thread */ -{ - ulint slot_no; - thr_local_t* local; - - mutex_enter(&thr_local_mutex); - - local = thr_local_get(id); - - slot_no = local->slot_no; - - mutex_exit(&thr_local_mutex); - - return(slot_no); -} - -/*******************************************************************//** -Sets the slot number in the thread table of a thread. */ -UNIV_INTERN -void -thr_local_set_slot_no( -/*==================*/ - os_thread_id_t id, /*!< in: thread id of the thread */ - ulint slot_no)/*!< in: slot number */ -{ - thr_local_t* local; - - mutex_enter(&thr_local_mutex); - - local = thr_local_get(id); - - local->slot_no = slot_no; - - mutex_exit(&thr_local_mutex); -} - /*******************************************************************//** Returns pointer to the 'in_ibuf' field within the current thread local storage. @@ -212,7 +165,6 @@ thr_local_create(void) local->id = os_thread_get_curr_id(); local->handle = os_thread_get_curr(); local->magic_n = THR_LOCAL_MAGIC_N; - local->slot_no = ULINT_UNDEFINED; local->in_ibuf = FALSE; mutex_enter(&thr_local_mutex); From 85dbe88d2f3da283f684428c51f8b789f209cb39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Thu, 24 Mar 2011 14:00:14 +0200 Subject: [PATCH 16/18] Bug#11766305 - 59392: Remove thr0loc.c and ibuf_inside() [part 4 of 4] ibuf_inside(), ibuf_enter(), ibuf_exit(): Add the parameter mtr. The flag is no longer kept in the thread-local storage but in the mini-transaction (mtr->inside_ibuf). mtr_start(): Clean up the comment and remove the unused return value. mtr_commit(): Assert !ibuf_inside(mtr) in debug builds. ibuf_mtr_start(): Like mtr_start(), but sets the flag. ibuf_mtr_commit(), ibuf_btr_pcur_commit_specify_mtr(): Wrappers that assert ibuf_inside(). buf_page_get_zip(), buf_page_init_for_read(), buf_read_ibuf_merge_pages(), fil_io(), ibuf_free_excess_pages(), ibuf_contract_ext(): Remove assertions on ibuf_inside(), because a mini-transaction is not available. buf_read_ahead_linear(): Add the parameter inside_ibuf. ibuf_restore_pos(): When this function returns FALSE, it commits mtr and must therefore do ibuf_exit(mtr). ibuf_delete_rec(): This function commits mtr and must therefore do ibuf_exit(mtr). ibuf_rec_get_page_no(), ibuf_rec_get_space(), ibuf_rec_get_info(), ibuf_rec_get_op_type(), ibuf_build_entry_from_ibuf_rec(), ibuf_rec_get_volume(), ibuf_get_merge_page_nos(), ibuf_get_volume_buffered_count(), ibuf_get_entry_counter_low(): Add the parameter mtr in debug builds, for asserting ibuf_inside(mtr). rb:585 approved by Sunny Bains --- storage/innobase/CMakeLists.txt | 1 - storage/innobase/btr/btr0cur.c | 2 +- storage/innobase/buf/buf0buf.c | 25 +- storage/innobase/buf/buf0rea.c | 19 +- storage/innobase/fil/fil0fil.c | 2 - storage/innobase/handler/ha_innodb.cc | 3 - storage/innobase/ibuf/ibuf0ibuf.c | 593 ++++++++++++++------------ storage/innobase/include/buf0rea.h | 8 +- storage/innobase/include/ibuf0ibuf.h | 24 +- storage/innobase/include/ibuf0ibuf.ic | 40 ++ storage/innobase/include/mtr0mtr.h | 14 +- storage/innobase/include/mtr0mtr.ic | 11 +- storage/innobase/include/sync0sync.h | 1 - storage/innobase/include/thr0loc.h | 74 ---- storage/innobase/include/thr0loc.ic | 24 -- storage/innobase/mtr/mtr0mtr.c | 1 + storage/innobase/srv/srv0srv.c | 4 - storage/innobase/srv/srv0start.c | 2 - storage/innobase/thr/thr0loc.c | 259 ----------- storage/innobase/trx/trx0trx.c | 1 - 20 files changed, 422 insertions(+), 686 deletions(-) delete mode 100644 storage/innobase/include/thr0loc.h delete mode 100644 storage/innobase/include/thr0loc.ic delete mode 100644 storage/innobase/thr/thr0loc.c diff --git a/storage/innobase/CMakeLists.txt b/storage/innobase/CMakeLists.txt index d4b98f2af0d..01034eede69 100644 --- a/storage/innobase/CMakeLists.txt +++ b/storage/innobase/CMakeLists.txt @@ -241,7 +241,6 @@ SET(INNOBASE_SOURCES btr/btr0btr.c btr/btr0cur.c btr/btr0pcur.c btr/btr0sea.c row/row0sel.c row/row0uins.c row/row0umod.c row/row0undo.c row/row0upd.c row/row0vers.c srv/srv0srv.c srv/srv0start.c sync/sync0arr.c sync/sync0rw.c sync/sync0sync.c - thr/thr0loc.c trx/trx0i_s.c trx/trx0purge.c trx/trx0rec.c trx/trx0roll.c trx/trx0rseg.c trx/trx0sys.c trx/trx0trx.c trx/trx0undo.c usr/usr0sess.c diff --git a/storage/innobase/btr/btr0cur.c b/storage/innobase/btr/btr0cur.c index fce3e98e3fa..c4034d0896a 100644 --- a/storage/innobase/btr/btr0cur.c +++ b/storage/innobase/btr/btr0cur.c @@ -402,7 +402,7 @@ btr_cur_search_to_nth_level( ut_ad(level == 0 || mode == PAGE_CUR_LE); ut_ad(dict_index_check_search_tuple(index, tuple)); - ut_ad(!dict_index_is_ibuf(index) || ibuf_inside()); + ut_ad(!dict_index_is_ibuf(index) || ibuf_inside(mtr)); ut_ad(dtuple_check_typed(tuple)); #ifdef UNIV_DEBUG diff --git a/storage/innobase/buf/buf0buf.c b/storage/innobase/buf/buf0buf.c index aece9586fd2..cf5b90a2539 100644 --- a/storage/innobase/buf/buf0buf.c +++ b/storage/innobase/buf/buf0buf.c @@ -2316,9 +2316,6 @@ buf_page_get_zip( unsigned access_time; buf_pool_t* buf_pool = buf_pool_get(space, offset); -#ifndef UNIV_LOG_DEBUG - ut_ad(!ibuf_inside()); -#endif buf_pool->stat.n_page_gets++; for (;;) { @@ -2758,8 +2755,9 @@ buf_page_get_gen( ut_ad(zip_size == fil_space_get_zip_size(space)); ut_ad(ut_is_2pow(zip_size)); #ifndef UNIV_LOG_DEBUG - ut_ad(!ibuf_inside() || ibuf_page_low(space, zip_size, offset, - FALSE, file, line, NULL)); + ut_ad(!ibuf_inside(mtr) + || ibuf_page_low(space, zip_size, offset, + FALSE, file, line, NULL)); #endif buf_pool->stat.n_page_gets++; fold = buf_page_address_fold(space, offset); @@ -3132,7 +3130,8 @@ wait_until_unfixed: /* In the case of a first access, try to apply linear read-ahead */ - buf_read_ahead_linear(space, zip_size, offset); + buf_read_ahead_linear(space, zip_size, offset, + ibuf_inside(mtr)); } #ifdef UNIV_IBUF_COUNT_DEBUG @@ -3189,7 +3188,7 @@ buf_page_optimistic_get( access_time = buf_page_is_accessed(&block->page); buf_page_set_accessed_make_young(&block->page, access_time); - ut_ad(!ibuf_inside() + ut_ad(!ibuf_inside(mtr) || ibuf_page(buf_block_get_space(block), buf_block_get_zip_size(block), buf_block_get_page_no(block), NULL)); @@ -3245,7 +3244,8 @@ buf_page_optimistic_get( buf_read_ahead_linear(buf_block_get_space(block), buf_block_get_zip_size(block), - buf_block_get_page_no(block)); + buf_block_get_page_no(block), + ibuf_inside(mtr)); } #ifdef UNIV_IBUF_COUNT_DEBUG @@ -3321,7 +3321,7 @@ buf_page_get_known_nowait( buf_pool_mutex_exit(buf_pool); } - ut_ad(!ibuf_inside() || (mode == BUF_KEEP_OLD)); + ut_ad(!ibuf_inside(mtr) || mode == BUF_KEEP_OLD); if (rw_latch == RW_S_LATCH) { success = rw_lock_s_lock_nowait(&(block->lock), @@ -3586,14 +3586,13 @@ buf_page_init_for_read( /* It is a read-ahead within an ibuf routine */ ut_ad(!ibuf_bitmap_page(zip_size, offset)); - ut_ad(ibuf_inside()); - mtr_start(&mtr); + ibuf_mtr_start(&mtr); if (!recv_no_ibuf_operations && !ibuf_page(space, zip_size, offset, &mtr)) { - mtr_commit(&mtr); + ibuf_mtr_commit(&mtr); return(NULL); } @@ -3778,7 +3777,7 @@ func_exit: if (mode == BUF_READ_IBUF_PAGES_ONLY) { - mtr_commit(&mtr); + ibuf_mtr_commit(&mtr); } ut_ad(!bpage || buf_page_in_file(bpage)); diff --git a/storage/innobase/buf/buf0rea.c b/storage/innobase/buf/buf0rea.c index 17704a4b65d..eeaa21ae9ef 100644 --- a/storage/innobase/buf/buf0rea.c +++ b/storage/innobase/buf/buf0rea.c @@ -236,10 +236,10 @@ UNIV_INTERN ulint buf_read_ahead_linear( /*==================*/ - ulint space, /*!< in: space id */ - ulint zip_size,/*!< in: compressed page size in bytes, or 0 */ - ulint offset) /*!< in: page number of a page; NOTE: the current thread - must want access to this page (see NOTE 3 above) */ + ulint space, /*!< in: space id */ + ulint zip_size, /*!< in: compressed page size in bytes, or 0 */ + ulint offset, /*!< in: page number; see NOTE 3 above */ + ibool inside_ibuf) /*!< in: TRUE if we are inside ibuf routine */ { buf_pool_t* buf_pool = buf_pool_get(space, offset); ib_int64_t tablespace_version; @@ -429,11 +429,9 @@ buf_read_ahead_linear( /* If we got this far, read-ahead can be sensible: do it */ - if (ibuf_inside()) { - ibuf_mode = BUF_READ_IBUF_PAGES_ONLY; - } else { - ibuf_mode = BUF_READ_ANY_PAGE; - } + ibuf_mode = inside_ibuf + ? BUF_READ_IBUF_PAGES_ONLY | OS_AIO_SIMULATED_WAKE_LATER + : BUF_READ_ANY_PAGE | OS_AIO_SIMULATED_WAKE_LATER; count = 0; @@ -450,7 +448,7 @@ buf_read_ahead_linear( if (!ibuf_bitmap_page(zip_size, i)) { count += buf_read_page_low( &err, FALSE, - ibuf_mode | OS_AIO_SIMULATED_WAKE_LATER, + ibuf_mode, space, zip_size, FALSE, tablespace_version, i); if (err == DB_TABLESPACE_DELETED) { ut_print_timestamp(stderr); @@ -520,7 +518,6 @@ buf_read_ibuf_merge_pages( { ulint i; - ut_ad(!ibuf_inside()); #ifdef UNIV_IBUF_DEBUG ut_a(n_stored < UNIV_PAGE_SIZE); #endif diff --git a/storage/innobase/fil/fil0fil.c b/storage/innobase/fil/fil0fil.c index d940bc70609..6c50b853187 100644 --- a/storage/innobase/fil/fil0fil.c +++ b/storage/innobase/fil/fil0fil.c @@ -4342,8 +4342,6 @@ fil_io( ut_ad(recv_no_ibuf_operations || (type == OS_FILE_WRITE) || !ibuf_bitmap_page(zip_size, block_offset) || sync || is_log); - ut_ad(!ibuf_inside() || is_log || (type == OS_FILE_WRITE) - || ibuf_page(space_id, zip_size, block_offset, NULL)); # endif /* UNIV_LOG_DEBUG */ if (sync) { mode = OS_AIO_SYNC; diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 1a2bb77e27d..c5fc3693c11 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -82,7 +82,6 @@ extern "C" { #include "fil0fil.h" #include "trx0xa.h" #include "row0merge.h" -#include "thr0loc.h" #include "dict0boot.h" #include "ha_prototypes.h" #include "ut0mem.h" @@ -280,7 +279,6 @@ static PSI_mutex_info all_innodb_mutexes[] = { {&sync_thread_mutex_key, "sync_thread_mutex", 0}, # endif /* UNIV_SYNC_DEBUG */ {&trx_doublewrite_mutex_key, "trx_doublewrite_mutex", 0}, - {&thr_local_mutex_key, "thr_local_mutex", 0}, {&trx_undo_mutex_key, "trx_undo_mutex", 0} }; # endif /* UNIV_PFS_MUTEX */ @@ -3042,7 +3040,6 @@ innobase_close_connection( innobase_rollback_trx(trx); - thr_local_free(trx->mysql_thread_id); trx_free_for_mysql(trx); DBUG_RETURN(0); diff --git a/storage/innobase/ibuf/ibuf0ibuf.c b/storage/innobase/ibuf/ibuf0ibuf.c index 93d152bfb74..8110bccc162 100644 --- a/storage/innobase/ibuf/ibuf0ibuf.c +++ b/storage/innobase/ibuf/ibuf0ibuf.c @@ -44,7 +44,6 @@ Created 7/19/1997 Heikki Tuuri #include "fsp0fsp.h" #include "trx0sys.h" #include "fil0fil.h" -#include "thr0loc.h" #include "rem0rec.h" #include "btr0cur.h" #include "btr0pcur.h" @@ -324,52 +323,43 @@ still physically like the index page even if the index would have been dropped! So, there seems to be no problem. */ /******************************************************************//** -Sets the flag in the current OS thread local storage denoting that it is +Sets the flag in the current mini-transaction record indicating we're inside an insert buffer routine. */ UNIV_INLINE void -ibuf_enter(void) -/*============*/ +ibuf_enter( +/*=======*/ + mtr_t* mtr) /*!< in/out: mini-transaction */ { - ibool* ptr; - - ptr = thr_local_get_in_ibuf_field(); - - ut_ad(*ptr == FALSE); - - *ptr = TRUE; + ut_ad(!mtr->inside_ibuf); + mtr->inside_ibuf = TRUE; } /******************************************************************//** -Sets the flag in the current OS thread local storage denoting that it is +Sets the flag in the current mini-transaction record indicating we're exiting an insert buffer routine. */ UNIV_INLINE void -ibuf_exit(void) -/*===========*/ +ibuf_exit( +/*======*/ + mtr_t* mtr) /*!< in/out: mini-transaction */ { - ibool* ptr; - - ptr = thr_local_get_in_ibuf_field(); - - ut_ad(*ptr == TRUE); - - *ptr = FALSE; + ut_ad(mtr->inside_ibuf); + mtr->inside_ibuf = FALSE; } -/******************************************************************//** -Returns TRUE if the current OS thread is performing an insert buffer -routine. - -For instance, a read-ahead of non-ibuf pages is forbidden by threads -that are executing an insert buffer routine. -@return TRUE if inside an insert buffer routine */ -UNIV_INTERN -ibool -ibuf_inside(void) -/*=============*/ +/**************************************************************//** +Commits an insert buffer mini-transaction and sets the persistent +cursor latch mode to BTR_NO_LATCHES, that is, detaches the cursor. */ +UNIV_INLINE +void +ibuf_btr_pcur_commit_specify_mtr( +/*=============================*/ + btr_pcur_t* pcur, /*!< in/out: persistent cursor */ + mtr_t* mtr) /*!< in/out: mini-transaction */ { - return(*thr_local_get_in_ibuf_field()); + ut_d(ibuf_exit(mtr)); + btr_pcur_commit_specify_mtr(pcur, mtr); } /******************************************************************//** @@ -379,11 +369,11 @@ static page_t* ibuf_header_page_get( /*=================*/ - mtr_t* mtr) /*!< in: mtr */ + mtr_t* mtr) /*!< in/out: mini-transaction */ { buf_block_t* block; - ut_ad(!ibuf_inside()); + ut_ad(!ibuf_inside(mtr)); block = buf_page_get( IBUF_SPACE_ID, 0, FSP_IBUF_HEADER_PAGE_NO, RW_X_LATCH, mtr); @@ -404,7 +394,7 @@ ibuf_tree_root_get( buf_block_t* block; page_t* root; - ut_ad(ibuf_inside()); + ut_ad(ibuf_inside(mtr)); ut_ad(mutex_own(&ibuf_mutex)); mtr_x_lock(dict_index_get_lock(ibuf->index), mtr); @@ -547,7 +537,7 @@ ibuf_init_at_db_start(void) fseg_n_reserved_pages(header_page + IBUF_HEADER + IBUF_TREE_SEG_HEADER, &n_used, &mtr); - ibuf_enter(); + ibuf_enter(&mtr); ut_ad(n_used >= 2); @@ -568,9 +558,7 @@ ibuf_init_at_db_start(void) mutex_exit(&ibuf_mutex); ibuf->empty = (page_get_n_recs(root) == 0); - mtr_commit(&mtr); - - ibuf_exit(); + ibuf_mtr_commit(&mtr); heap = mem_heap_create(450); @@ -1230,19 +1218,30 @@ ibuf_page_low( return(ret); } +#ifdef UNIV_DEBUG +# define ibuf_rec_get_page_no(mtr,rec) ibuf_rec_get_page_no_func(mtr,rec) +#else /* UNIV_DEBUG */ +# define ibuf_rec_get_page_no(mtr,rec) ibuf_rec_get_page_no_func(rec) +#endif /* UNIV_DEBUG */ + /********************************************************************//** Returns the page number field of an ibuf record. @return page number */ static ulint -ibuf_rec_get_page_no( -/*=================*/ +ibuf_rec_get_page_no_func( +/*======================*/ +#ifdef UNIV_DEBUG + mtr_t* mtr, /*!< in: mini-transaction owning rec */ +#endif /* UNIV_DEBUG */ const rec_t* rec) /*!< in: ibuf record */ { const byte* field; ulint len; - ut_ad(ibuf_inside()); + ut_ad(mtr_memo_contains_page(mtr, rec, MTR_MEMO_PAGE_X_FIX) + || mtr_memo_contains_page(mtr, rec, MTR_MEMO_PAGE_S_FIX)); + ut_ad(ibuf_inside(mtr)); ut_ad(rec_get_n_fields_old(rec) > 2); field = rec_get_nth_field_old(rec, 1, &len); @@ -1264,20 +1263,31 @@ ibuf_rec_get_page_no( return(mach_read_from_4(field)); } +#ifdef UNIV_DEBUG +# define ibuf_rec_get_space(mtr,rec) ibuf_rec_get_space_func(mtr,rec) +#else /* UNIV_DEBUG */ +# define ibuf_rec_get_space(mtr,rec) ibuf_rec_get_space_func(rec) +#endif /* UNIV_DEBUG */ + /********************************************************************//** Returns the space id field of an ibuf record. For < 4.1.x format records returns 0. @return space id */ static ulint -ibuf_rec_get_space( -/*===============*/ +ibuf_rec_get_space_func( +/*====================*/ +#ifdef UNIV_DEBUG + mtr_t* mtr, /*!< in: mini-transaction owning rec */ +#endif /* UNIV_DEBUG */ const rec_t* rec) /*!< in: ibuf record */ { const byte* field; ulint len; - ut_ad(ibuf_inside()); + ut_ad(mtr_memo_contains_page(mtr, rec, MTR_MEMO_PAGE_X_FIX) + || mtr_memo_contains_page(mtr, rec, MTR_MEMO_PAGE_S_FIX)); + ut_ad(ibuf_inside(mtr)); ut_ad(rec_get_n_fields_old(rec) > 2); field = rec_get_nth_field_old(rec, 1, &len); @@ -1298,12 +1308,22 @@ ibuf_rec_get_space( return(0); } +#ifdef UNIV_DEBUG +# define ibuf_rec_get_info(mtr,rec,op,comp,info_len,counter) \ + ibuf_rec_get_info_func(mtr,rec,op,comp,info_len,counter) +#else /* UNIV_DEBUG */ +# define ibuf_rec_get_info(mtr,rec,op,comp,info_len,counter) \ + ibuf_rec_get_info_func(rec,op,comp,info_len,counter) +#endif /****************************************************************//** Get various information about an ibuf record in >= 4.1.x format. */ static void -ibuf_rec_get_info( -/*==============*/ +ibuf_rec_get_info_func( +/*===================*/ +#ifdef UNIV_DEBUG + mtr_t* mtr, /*!< in: mini-transaction owning rec */ +#endif /* UNIV_DEBUG */ const rec_t* rec, /*!< in: ibuf record */ ibuf_op_t* op, /*!< out: operation type, or NULL */ ibool* comp, /*!< out: compact flag, or NULL */ @@ -1322,7 +1342,9 @@ ibuf_rec_get_info( ulint info_len_local; ulint counter_local; - ut_ad(ibuf_inside()); + ut_ad(mtr_memo_contains_page(mtr, rec, MTR_MEMO_PAGE_X_FIX) + || mtr_memo_contains_page(mtr, rec, MTR_MEMO_PAGE_S_FIX)); + ut_ad(ibuf_inside(mtr)); fields = rec_get_n_fields_old(rec); ut_a(fields > 4); @@ -1371,18 +1393,29 @@ ibuf_rec_get_info( } } +#ifdef UNIV_DEBUG +# define ibuf_rec_get_op_type(mtr,rec) ibuf_rec_get_op_type_func(mtr,rec) +#else /* UNIV_DEBUG */ +# define ibuf_rec_get_op_type(mtr,rec) ibuf_rec_get_op_type_func(rec) +#endif + /****************************************************************//** Returns the operation type field of an ibuf record. @return operation type */ static ibuf_op_t -ibuf_rec_get_op_type( -/*=================*/ +ibuf_rec_get_op_type_func( +/*======================*/ +#ifdef UNIV_DEBUG + mtr_t* mtr, /*!< in: mini-transaction owning rec */ +#endif /* UNIV_DEBUG */ const rec_t* rec) /*!< in: ibuf record */ { ulint len; - ut_ad(ibuf_inside()); + ut_ad(mtr_memo_contains_page(mtr, rec, MTR_MEMO_PAGE_X_FIX) + || mtr_memo_contains_page(mtr, rec, MTR_MEMO_PAGE_S_FIX)); + ut_ad(ibuf_inside(mtr)); ut_ad(rec_get_n_fields_old(rec) > 2); (void) rec_get_nth_field_old(rec, 1, &len); @@ -1394,7 +1427,7 @@ ibuf_rec_get_op_type( } else { ibuf_op_t op; - ibuf_rec_get_info(rec, &op, NULL, NULL, NULL); + ibuf_rec_get_info(mtr, rec, &op, NULL, NULL, NULL); return(op); } @@ -1593,6 +1626,14 @@ ibuf_build_entry_pre_4_1_x( return(tuple); } +#ifdef UNIV_DEBUG +# define ibuf_build_entry_from_ibuf_rec(mtr,ibuf_rec,heap,pindex) \ + ibuf_build_entry_from_ibuf_rec_func(mtr,ibuf_rec,heap,pindex) +#else /* UNIV_DEBUG */ +# define ibuf_build_entry_from_ibuf_rec(mtr,ibuf_rec,heap,pindex) \ + ibuf_build_entry_from_ibuf_rec_func(ibuf_rec,heap,pindex) +#endif + /*********************************************************************//** Builds the entry used to @@ -1611,8 +1652,11 @@ hold a latch to the ibuf_rec page as long as the entry is used! @return own: entry to insert to a non-clustered index */ static dtuple_t* -ibuf_build_entry_from_ibuf_rec( -/*===========================*/ +ibuf_build_entry_from_ibuf_rec_func( +/*================================*/ +#ifdef UNIV_DEBUG + mtr_t* mtr, /*!< in: mini-transaction owning rec */ +#endif /* UNIV_DEBUG */ const rec_t* ibuf_rec, /*!< in: record in an insert buffer */ mem_heap_t* heap, /*!< in: heap where built */ dict_index_t** pindex) /*!< out, own: dummy index that @@ -1629,6 +1673,10 @@ ibuf_build_entry_from_ibuf_rec( ulint comp; dict_index_t* index; + ut_ad(mtr_memo_contains_page(mtr, ibuf_rec, MTR_MEMO_PAGE_X_FIX) + || mtr_memo_contains_page(mtr, ibuf_rec, MTR_MEMO_PAGE_S_FIX)); + ut_ad(ibuf_inside(mtr)); + data = rec_get_nth_field_old(ibuf_rec, 1, &len); if (len > 1) { @@ -1649,7 +1697,7 @@ ibuf_build_entry_from_ibuf_rec( types = rec_get_nth_field_old(ibuf_rec, 3, &len); - ibuf_rec_get_info(ibuf_rec, NULL, &comp, &info_len, NULL); + ibuf_rec_get_info(mtr, ibuf_rec, NULL, &comp, &info_len, NULL); index = ibuf_dummy_index_create(n_fields, comp); @@ -1736,6 +1784,12 @@ ibuf_rec_get_size( return(size); } +#ifdef UNIV_DEBUG +# define ibuf_rec_get_volume(mtr,rec) ibuf_rec_get_volume_func(mtr,rec) +#else /* UNIV_DEBUG */ +# define ibuf_rec_get_volume(mtr,rec) ibuf_rec_get_volume_func(rec) +#endif + /********************************************************************//** Returns the space taken by a stored non-clustered index entry if converted to an index record. @@ -1743,8 +1797,11 @@ an index record. taken in the page directory */ static ulint -ibuf_rec_get_volume( -/*================*/ +ibuf_rec_get_volume_func( +/*=====================*/ +#ifdef UNIV_DEBUG + mtr_t* mtr, /*!< in: mini-transaction owning rec */ +#endif /* UNIV_DEBUG */ const rec_t* ibuf_rec)/*!< in: ibuf record */ { ulint len; @@ -1755,7 +1812,9 @@ ibuf_rec_get_volume( ibool pre_4_1; ulint comp; - ut_ad(ibuf_inside()); + ut_ad(mtr_memo_contains_page(mtr, ibuf_rec, MTR_MEMO_PAGE_X_FIX) + || mtr_memo_contains_page(mtr, ibuf_rec, MTR_MEMO_PAGE_S_FIX)); + ut_ad(ibuf_inside(mtr)); ut_ad(rec_get_n_fields_old(ibuf_rec) > 2); data = rec_get_nth_field_old(ibuf_rec, 1, &len); @@ -1783,7 +1842,7 @@ ibuf_rec_get_volume( types = rec_get_nth_field_old(ibuf_rec, 3, &len); - ibuf_rec_get_info(ibuf_rec, &op, &comp, &info_len, NULL); + ibuf_rec_get_info(mtr, ibuf_rec, &op, &comp, &info_len, NULL); if (op == IBUF_OP_DELETE_MARK || op == IBUF_OP_DELETE) { /* Delete-marking a record doesn't take any @@ -1800,7 +1859,7 @@ ibuf_rec_get_volume( mem_heap_t* heap = mem_heap_create(500); entry = ibuf_build_entry_from_ibuf_rec( - ibuf_rec, heap, &dummy_index); + mtr, ibuf_rec, heap, &dummy_index); volume = rec_get_converted_size(dummy_index, entry, 0); @@ -2158,21 +2217,15 @@ ibuf_add_free_page(void) mtr_commit(&mtr); return(FALSE); - } - - { - buf_block_t* block; - - block = buf_page_get( + } else { + buf_block_t* block = buf_page_get( IBUF_SPACE_ID, 0, page_no, RW_X_LATCH, &mtr); - buf_block_dbg_add_level(block, SYNC_TREE_NODE_NEW); - page = buf_block_get_frame(block); } - ibuf_enter(); + ibuf_enter(&mtr); mutex_enter(&ibuf_mutex); @@ -2200,9 +2253,7 @@ ibuf_add_free_page(void) ibuf_bitmap_page_set_bits( bitmap_page, page_no, zip_size, IBUF_BITMAP_IBUF, TRUE, &mtr); - mtr_commit(&mtr); - - ibuf_exit(); + ibuf_mtr_commit(&mtr); return(TRUE); } @@ -2234,7 +2285,7 @@ ibuf_remove_free_page(void) header_page = ibuf_header_page_get(&mtr); /* Prevent pessimistic inserts to insert buffer trees for a while */ - ibuf_enter(); + ibuf_enter(&mtr); mutex_enter(&ibuf_pessimistic_insert_mutex); mutex_enter(&ibuf_mutex); @@ -2243,14 +2294,12 @@ ibuf_remove_free_page(void) mutex_exit(&ibuf_mutex); mutex_exit(&ibuf_pessimistic_insert_mutex); - ibuf_exit(); - - mtr_commit(&mtr); + ibuf_mtr_commit(&mtr); return; } - mtr_start(&mtr2); + ibuf_mtr_start(&mtr2); root = ibuf_tree_root_get(&mtr2); @@ -2263,9 +2312,8 @@ ibuf_remove_free_page(void) because in fseg_free_page we access level 1 pages, and the root is a level 2 page. */ - mtr_commit(&mtr2); - - ibuf_exit(); + ibuf_mtr_commit(&mtr2); + ibuf_exit(&mtr); /* Since pessimistic inserts were prevented, we know that the page is still in the free list. NOTE that also deletes may take @@ -2280,7 +2328,7 @@ ibuf_remove_free_page(void) buf_page_reset_file_page_was_freed(IBUF_SPACE_ID, page_no); #endif /* UNIV_DEBUG_FILE_ACCESSES || UNIV_DEBUG */ - ibuf_enter(); + ibuf_enter(&mtr); mutex_enter(&ibuf_mutex); @@ -2325,9 +2373,7 @@ ibuf_remove_free_page(void) #if defined UNIV_DEBUG_FILE_ACCESSES || defined UNIV_DEBUG buf_page_set_file_page_was_freed(IBUF_SPACE_ID, page_no); #endif /* UNIV_DEBUG_FILE_ACCESSES || UNIV_DEBUG */ - mtr_commit(&mtr); - - ibuf_exit(); + ibuf_mtr_commit(&mtr); } /***********************************************************************//** @@ -2349,8 +2395,6 @@ ibuf_free_excess_pages(void) ut_ad(rw_lock_get_x_lock_count( fil_space_get_latch(IBUF_SPACE_ID, NULL)) == 1); - ut_ad(!ibuf_inside()); - /* NOTE: We require that the thread did not own the latch before, because then we know that we can obey the correct latching order for ibuf latches */ @@ -2381,20 +2425,30 @@ ibuf_free_excess_pages(void) } } +#ifdef UNIV_DEBUG +# define ibuf_get_merge_page_nos(contract,rec,mtr,ids,vers,pages,n_stored) \ + ibuf_get_merge_page_nos_func(contract,rec,mtr,ids,vers,pages,n_stored) +#else /* UNIV_DEBUG */ +# define ibuf_get_merge_page_nos(contract,rec,mtr,ids,vers,pages,n_stored) \ + ibuf_get_merge_page_nos_func(contract,rec,ids,vers,pages,n_stored) +#endif /* UNIV_DEBUG */ + /*********************************************************************//** Reads page numbers from a leaf in an ibuf tree. @return a lower limit for the combined volume of records which will be merged */ static ulint -ibuf_get_merge_page_nos( -/*====================*/ +ibuf_get_merge_page_nos_func( +/*=========================*/ ibool contract,/*!< in: TRUE if this function is called to contract the tree, FALSE if this is called when a single page becomes full and we look if it pays to read also nearby pages */ - rec_t* rec, /*!< in: record from which we read up and down - in the chain of records */ + const rec_t* rec, /*!< in: insert buffer record */ +#ifdef UNIV_DEBUG + mtr_t* mtr, /*!< in: mini-transaction holding rec */ +#endif /* UNIV_DEBUG */ ulint* space_ids,/*!< in/out: space id's of the pages */ ib_int64_t* space_versions,/*!< in/out: tablespace version timestamps; used to prevent reading in old @@ -2417,18 +2471,22 @@ ibuf_get_merge_page_nos( ulint limit; ulint n_pages; + ut_ad(mtr_memo_contains_page(mtr, rec, MTR_MEMO_PAGE_X_FIX) + || mtr_memo_contains_page(mtr, rec, MTR_MEMO_PAGE_S_FIX)); + ut_ad(ibuf_inside(mtr)); + *n_stored = 0; limit = ut_min(IBUF_MAX_N_PAGES_MERGED, buf_pool_get_curr_size() / 4); if (page_rec_is_supremum(rec)) { - rec = page_rec_get_prev(rec); + rec = page_rec_get_prev_const(rec); } if (page_rec_is_infimum(rec)) { - rec = page_rec_get_next(rec); + rec = page_rec_get_next_const(rec); } if (page_rec_is_supremum(rec)) { @@ -2436,8 +2494,8 @@ ibuf_get_merge_page_nos( return(0); } - first_page_no = ibuf_rec_get_page_no(rec); - first_space_id = ibuf_rec_get_space(rec); + first_page_no = ibuf_rec_get_page_no(mtr, rec); + first_space_id = ibuf_rec_get_space(mtr, rec); n_pages = 0; prev_page_no = 0; prev_space_id = 0; @@ -2448,8 +2506,8 @@ ibuf_get_merge_page_nos( while (!page_rec_is_infimum(rec) && UNIV_LIKELY(n_pages < limit)) { - rec_page_no = ibuf_rec_get_page_no(rec); - rec_space_id = ibuf_rec_get_space(rec); + rec_page_no = ibuf_rec_get_page_no(mtr, rec); + rec_space_id = ibuf_rec_get_space(mtr, rec); if (rec_space_id != first_space_id || (rec_page_no / IBUF_MERGE_AREA) @@ -2466,10 +2524,10 @@ ibuf_get_merge_page_nos( prev_page_no = rec_page_no; prev_space_id = rec_space_id; - rec = page_rec_get_prev(rec); + rec = page_rec_get_prev_const(rec); } - rec = page_rec_get_next(rec); + rec = page_rec_get_next_const(rec); /* At the loop start there is no prev page; we mark this with a pair of space id, page no (0, 0) for which there can never be entries in @@ -2487,8 +2545,8 @@ ibuf_get_merge_page_nos( rec_page_no = 1; rec_space_id = 0; } else { - rec_page_no = ibuf_rec_get_page_no(rec); - rec_space_id = ibuf_rec_get_space(rec); + rec_page_no = ibuf_rec_get_page_no(mtr, rec); + rec_space_id = ibuf_rec_get_space(mtr, rec); ut_ad(rec_page_no > IBUF_TREE_ROOT_PAGE_NO); } @@ -2499,9 +2557,9 @@ ibuf_get_merge_page_nos( || rec_page_no != prev_page_no) && (prev_space_id != 0 || prev_page_no != 0)) { - if ((prev_page_no == first_page_no - && prev_space_id == first_space_id) - || contract + if (contract + || (prev_page_no == first_page_no + && prev_space_id == first_space_id) || (volume_for_page > ((IBUF_MERGE_THRESHOLD - 1) * 4 * UNIV_PAGE_SIZE @@ -2534,14 +2592,14 @@ ibuf_get_merge_page_nos( break; } - rec_volume = ibuf_rec_get_volume(rec); + rec_volume = ibuf_rec_get_volume(mtr, rec); volume_for_page += rec_volume; prev_page_no = rec_page_no; prev_space_id = rec_space_id; - rec = page_rec_get_next(rec); + rec = page_rec_get_next_const(rec); } #ifdef UNIV_IBUF_DEBUG @@ -2576,7 +2634,6 @@ ibuf_contract_ext( mtr_t mtr; *n_pages = 0; - ut_ad(!ibuf_inside()); /* We perform a dirty read of ibuf->empty, without latching the insert buffer root page. We trust this dirty read except @@ -2588,9 +2645,7 @@ ibuf_contract_ext( return(0); } - mtr_start(&mtr); - - ibuf_enter(); + ibuf_mtr_start(&mtr); /* Open a cursor to a randomly chosen leaf of the tree, at a random position within the leaf */ @@ -2609,24 +2664,21 @@ ibuf_contract_ext( ut_ad(page_get_page_no(btr_pcur_get_page(&pcur)) == FSP_IBUF_TREE_ROOT_PAGE_NO); - ibuf_exit(); - - mtr_commit(&mtr); + ibuf_mtr_commit(&mtr); btr_pcur_close(&pcur); return(0); } - sum_sizes = ibuf_get_merge_page_nos(TRUE, btr_pcur_get_rec(&pcur), + sum_sizes = ibuf_get_merge_page_nos(TRUE, + btr_pcur_get_rec(&pcur), &mtr, space_ids, space_versions, page_nos, n_pages); #if 0 /* defined UNIV_IBUF_DEBUG */ fprintf(stderr, "Ibuf contract sync %lu pages %lu volume %lu\n", sync, *n_pages, sum_sizes); #endif - ibuf_exit(); - - mtr_commit(&mtr); + ibuf_mtr_commit(&mtr); btr_pcur_close(&pcur); buf_read_ibuf_merge_pages(sync, space_ids, space_versions, page_nos, @@ -2766,6 +2818,13 @@ ibuf_get_volume_buffered_hash( return(TRUE); } +#ifdef UNIV_DEBUG +# define ibuf_get_volume_buffered_count(mtr,rec,hash,size,n_recs) \ + ibuf_get_volume_buffered_count_func(mtr,rec,hash,size,n_recs) +#else /* UNIV_DEBUG */ +# define ibuf_get_volume_buffered_count(mtr,rec,hash,size,n_recs) \ + ibuf_get_volume_buffered_count_func(rec,hash,size,n_recs) +#endif /*********************************************************************//** Update the estimate of the number of records on a page, and get the space taken by merging the buffered record to the index page. @@ -2773,8 +2832,11 @@ get the space taken by merging the buffered record to the index page. taken in the page directory */ static ulint -ibuf_get_volume_buffered_count( -/*===========================*/ +ibuf_get_volume_buffered_count_func( +/*================================*/ +#ifdef UNIV_DEBUG + mtr_t* mtr, /*!< in: mini-transaction owning rec */ +#endif /* UNIV_DEBUG */ const rec_t* rec, /*!< in: insert buffer record */ ulint* hash, /*!< in/out: hash array */ ulint size, /*!< in: number of elements in hash array */ @@ -2784,9 +2846,13 @@ ibuf_get_volume_buffered_count( ulint len; ibuf_op_t ibuf_op; const byte* types; - ulint n_fields = rec_get_n_fields_old(rec); + ulint n_fields; - ut_ad(ibuf_inside()); + ut_ad(mtr_memo_contains_page(mtr, rec, MTR_MEMO_PAGE_X_FIX) + || mtr_memo_contains_page(mtr, rec, MTR_MEMO_PAGE_S_FIX)); + ut_ad(ibuf_inside(mtr)); + + n_fields = rec_get_n_fields_old(rec); ut_ad(n_fields > 4); n_fields -= 4; @@ -2871,7 +2937,7 @@ get_volume_comp: mem_heap_t* heap = mem_heap_create(500); entry = ibuf_build_entry_from_ibuf_rec( - rec, heap, &dummy_index); + mtr, rec, heap, &dummy_index); volume = rec_get_converted_size(dummy_index, entry, 0); @@ -2892,7 +2958,7 @@ static ulint ibuf_get_volume_buffered( /*=====================*/ - btr_pcur_t* pcur, /*!< in: pcur positioned at a place in an + const btr_pcur_t*pcur, /*!< in: pcur positioned at a place in an insert buffer tree where we would insert an entry for the index page whose number is page_no, latch mode has to be BTR_MODIFY_PREV @@ -2902,16 +2968,17 @@ ibuf_get_volume_buffered( lint* n_recs, /*!< in/out: minimum number of records on the page after the buffered changes have been applied, or NULL to disable the counting */ - mtr_t* mtr) /*!< in: mtr */ + mtr_t* mtr) /*!< in: mini-transaction of pcur */ { - ulint volume; - rec_t* rec; - page_t* page; - ulint prev_page_no; - page_t* prev_page; - ulint next_page_no; - page_t* next_page; - ulint hash_bitmap[128 / sizeof(ulint)]; /* bitmap of buffered recs */ + ulint volume; + const rec_t* rec; + const page_t* page; + ulint prev_page_no; + const page_t* prev_page; + ulint next_page_no; + const page_t* next_page; + /* bitmap of buffered recs */ + ulint hash_bitmap[128 / sizeof(ulint)]; ut_a(trx_sys_multiple_tablespace_format); @@ -2932,26 +2999,22 @@ ibuf_get_volume_buffered( ut_ad(page_validate(page, ibuf->index)); if (page_rec_is_supremum(rec)) { - rec = page_rec_get_prev(rec); + rec = page_rec_get_prev_const(rec); } - for (;;) { - if (page_rec_is_infimum(rec)) { + for (; !page_rec_is_infimum(rec); + rec = page_rec_get_prev_const(rec)) { + ut_ad(page_align(rec) == page); - break; - } - - if (page_no != ibuf_rec_get_page_no(rec) - || space != ibuf_rec_get_space(rec)) { + if (page_no != ibuf_rec_get_page_no(mtr, rec) + || space != ibuf_rec_get_space(mtr, rec)) { goto count_later; } volume += ibuf_get_volume_buffered_count( - rec, hash_bitmap, UT_ARR_SIZE(hash_bitmap), n_recs); - - rec = page_rec_get_prev(rec); - ut_ad(page_align(rec) == page); + mtr, rec, + hash_bitmap, UT_ARR_SIZE(hash_bitmap), n_recs); } /* Look at the previous page */ @@ -2967,7 +3030,8 @@ ibuf_get_volume_buffered( buf_block_t* block; block = buf_page_get( - IBUF_SPACE_ID, 0, prev_page_no, RW_X_LATCH, mtr); + IBUF_SPACE_ID, 0, prev_page_no, RW_X_LATCH, + mtr); buf_block_dbg_add_level(block, SYNC_TREE_NODE); @@ -2977,14 +3041,15 @@ ibuf_get_volume_buffered( } #ifdef UNIV_BTR_DEBUG - ut_a(btr_page_get_next(prev_page, mtr) - == page_get_page_no(page)); + ut_a(btr_page_get_next(prev_page, mtr) == page_get_page_no(page)); #endif /* UNIV_BTR_DEBUG */ rec = page_get_supremum_rec(prev_page); - rec = page_rec_get_prev(rec); + rec = page_rec_get_prev_const(rec); + + for (;; rec = page_rec_get_prev_const(rec)) { + ut_ad(page_align(rec) == prev_page); - for (;;) { if (page_rec_is_infimum(rec)) { /* We cannot go to yet a previous page, because we @@ -2994,42 +3059,35 @@ ibuf_get_volume_buffered( return(UNIV_PAGE_SIZE); } - if (page_no != ibuf_rec_get_page_no(rec) - || space != ibuf_rec_get_space(rec)) { + if (page_no != ibuf_rec_get_page_no(mtr, rec) + || space != ibuf_rec_get_space(mtr, rec)) { goto count_later; } volume += ibuf_get_volume_buffered_count( - rec, hash_bitmap, UT_ARR_SIZE(hash_bitmap), n_recs); - - rec = page_rec_get_prev(rec); - ut_ad(page_align(rec) == prev_page); + mtr, rec, + hash_bitmap, UT_ARR_SIZE(hash_bitmap), n_recs); } count_later: rec = btr_pcur_get_rec(pcur); if (!page_rec_is_supremum(rec)) { - rec = page_rec_get_next(rec); + rec = page_rec_get_next_const(rec); } - for (;;) { - if (page_rec_is_supremum(rec)) { - - break; - } - - if (page_no != ibuf_rec_get_page_no(rec) - || space != ibuf_rec_get_space(rec)) { + for (; !page_rec_is_supremum(rec); + rec = page_rec_get_next_const(rec)) { + if (page_no != ibuf_rec_get_page_no(mtr, rec) + || space != ibuf_rec_get_space(mtr, rec)) { return(volume); } volume += ibuf_get_volume_buffered_count( - rec, hash_bitmap, UT_ARR_SIZE(hash_bitmap), n_recs); - - rec = page_rec_get_next(rec); + mtr, rec, + hash_bitmap, UT_ARR_SIZE(hash_bitmap), n_recs); } /* Look at the next page */ @@ -3045,7 +3103,8 @@ count_later: buf_block_t* block; block = buf_page_get( - IBUF_SPACE_ID, 0, next_page_no, RW_X_LATCH, mtr); + IBUF_SPACE_ID, 0, next_page_no, RW_X_LATCH, + mtr); buf_block_dbg_add_level(block, SYNC_TREE_NODE); @@ -3059,9 +3118,11 @@ count_later: #endif /* UNIV_BTR_DEBUG */ rec = page_get_infimum_rec(next_page); - rec = page_rec_get_next(rec); + rec = page_rec_get_next_const(rec); + + for (;; rec = page_rec_get_next_const(rec)) { + ut_ad(page_align(rec) == next_page); - for (;;) { if (page_rec_is_supremum(rec)) { /* We give up */ @@ -3069,17 +3130,15 @@ count_later: return(UNIV_PAGE_SIZE); } - if (page_no != ibuf_rec_get_page_no(rec) - || space != ibuf_rec_get_space(rec)) { + if (page_no != ibuf_rec_get_page_no(mtr, rec) + || space != ibuf_rec_get_space(mtr, rec)) { return(volume); } volume += ibuf_get_volume_buffered_count( - rec, hash_bitmap, UT_ARR_SIZE(hash_bitmap), n_recs); - - rec = page_rec_get_next(rec); - ut_ad(page_align(rec) == next_page); + mtr, rec, + hash_bitmap, UT_ARR_SIZE(hash_bitmap), n_recs); } } @@ -3100,9 +3159,7 @@ ibuf_update_max_tablespace_id(void) ut_a(!dict_table_is_comp(ibuf->index->table)); - ibuf_enter(); - - mtr_start(&mtr); + ibuf_mtr_start(&mtr); btr_pcur_open_at_index_side( FALSE, ibuf->index, BTR_SEARCH_LEAF, &pcur, TRUE, &mtr); @@ -3125,14 +3182,20 @@ ibuf_update_max_tablespace_id(void) max_space_id = mach_read_from_4(field); } - mtr_commit(&mtr); - ibuf_exit(); + ibuf_mtr_commit(&mtr); /* printf("Maximum space id in insert buffer %lu\n", max_space_id); */ fil_set_max_space_id_if_bigger(max_space_id); } +#ifdef UNIV_DEBUG +# define ibuf_get_entry_counter_low(mtr,rec,space,page_no) \ + ibuf_get_entry_counter_low_func(mtr,rec,space,page_no) +#else /* UNIV_DEBUG */ +# define ibuf_get_entry_counter_low(mtr,rec,space,page_no) \ + ibuf_get_entry_counter_low_func(rec,space,page_no) +#endif /****************************************************************//** Helper function for ibuf_set_entry_counter. Checks if rec is for (space, page_no), and if so, reads counter value from it and returns that + 1. @@ -3140,8 +3203,11 @@ Otherwise, returns 0. @return new counter value, or 0 */ static ulint -ibuf_get_entry_counter_low( -/*=======================*/ +ibuf_get_entry_counter_low_func( +/*============================*/ +#ifdef UNIV_DEBUG + mtr_t* mtr, /*!< in: mini-transaction of rec */ +#endif /* UNIV_DEBUG */ const rec_t* rec, /*!< in: insert buffer record */ ulint space, /*!< in: space id */ ulint page_no) /*!< in: page number */ @@ -3150,7 +3216,9 @@ ibuf_get_entry_counter_low( const byte* field; ulint len; - ut_ad(ibuf_inside()); + ut_ad(ibuf_inside(mtr)); + ut_ad(mtr_memo_contains_page(mtr, rec, MTR_MEMO_PAGE_X_FIX) + || mtr_memo_contains_page(mtr, rec, MTR_MEMO_PAGE_S_FIX)); ut_ad(rec_get_n_fields_old(rec) > 2); field = rec_get_nth_field_old(rec, 1, &len); @@ -3222,12 +3290,15 @@ ibuf_set_entry_counter( ulint counter = 0; /* pcur points to either a user rec or to a page's infimum record. */ + ut_ad(ibuf_inside(mtr)); + ut_ad(mtr_memo_contains(mtr, btr_pcur_get_block(pcur), + MTR_MEMO_PAGE_X_FIX)); ut_ad(page_validate(btr_pcur_get_page(pcur), ibuf->index)); if (btr_pcur_is_on_user_rec(pcur)) { counter = ibuf_get_entry_counter_low( - btr_pcur_get_rec(pcur), space, page_no); + mtr, btr_pcur_get_rec(pcur), space, page_no); if (UNIV_UNLIKELY(counter == ULINT_UNDEFINED)) { /* The record lacks a counter field. @@ -3283,7 +3354,7 @@ ibuf_set_entry_counter( ut_ad(page_rec_is_user_rec(rec)); counter = ibuf_get_entry_counter_low( - rec, space, page_no); + mtr, rec, space, page_no); if (UNIV_UNLIKELY(counter == ULINT_UNDEFINED)) { /* The record lacks a counter field. @@ -3435,7 +3506,6 @@ ibuf_insert_low( if (mode == BTR_MODIFY_TREE) { for (;;) { - ibuf_enter(); mutex_enter(&ibuf_pessimistic_insert_mutex); mutex_enter(&ibuf_mutex); @@ -3446,7 +3516,6 @@ ibuf_insert_low( mutex_exit(&ibuf_mutex); mutex_exit(&ibuf_pessimistic_insert_mutex); - ibuf_exit(); if (UNIV_UNLIKELY(!ibuf_add_free_page())) { @@ -3454,11 +3523,9 @@ ibuf_insert_low( return(DB_STRONG_FAIL); } } - } else { - ibuf_enter(); } - mtr_start(&mtr); + ibuf_mtr_start(&mtr); btr_pcur_open(ibuf->index, ibuf_entry, PAGE_CUR_LE, mode, &pcur, &mtr); ut_ad(page_validate(btr_pcur_get_page(&pcur), ibuf->index)); @@ -3513,7 +3580,7 @@ fail_exit: #ifdef UNIV_IBUF_COUNT_DEBUG ut_a((buffered == 0) || ibuf_count_get(space, page_no)); #endif - mtr_start(&bitmap_mtr); + ibuf_mtr_start(&bitmap_mtr); bitmap_page = ibuf_bitmap_get_map_page(space, page_no, zip_size, &bitmap_mtr); @@ -3534,15 +3601,15 @@ fail_exit: if (buffered + entry_size + page_dir_calc_reserved_space(1) > ibuf_index_page_calc_free_from_bits(zip_size, bits)) { /* Release the bitmap page latch early. */ - mtr_commit(&bitmap_mtr); + ibuf_mtr_commit(&bitmap_mtr); /* It may not fit */ do_merge = TRUE; - ibuf_get_merge_page_nos( - FALSE, btr_pcur_get_rec(&pcur), - space_ids, space_versions, - page_nos, &n_stored); + ibuf_get_merge_page_nos(FALSE, + btr_pcur_get_rec(&pcur), &mtr, + space_ids, space_versions, + page_nos, &n_stored); goto fail_exit; } @@ -3555,7 +3622,7 @@ fail_exit: && !ibuf_set_entry_counter(ibuf_entry, space, page_no, &pcur, mode == BTR_MODIFY_PREV, &mtr)) { bitmap_fail: - mtr_commit(&bitmap_mtr); + ibuf_mtr_commit(&bitmap_mtr); goto fail_exit; } @@ -3573,7 +3640,7 @@ bitmap_fail: &bitmap_mtr); } - mtr_commit(&bitmap_mtr); + ibuf_mtr_commit(&bitmap_mtr); cursor = btr_pcur_get_btr_cur(&pcur); @@ -3638,9 +3705,8 @@ func_exit: } #endif - mtr_commit(&mtr); + ibuf_mtr_commit(&mtr); btr_pcur_close(&pcur); - ibuf_exit(); mem_heap_free(heap); @@ -3898,7 +3964,7 @@ ibuf_insert_to_index_page( page_t* page = buf_block_get_frame(block); rec_t* rec; - ut_ad(ibuf_inside()); + ut_ad(ibuf_inside(mtr)); ut_ad(dtuple_check_typed(entry)); ut_ad(!buf_block_align(page)->is_hashed); @@ -4045,7 +4111,7 @@ ibuf_set_del_mark( page_cur_t page_cur; ulint low_match; - ut_ad(ibuf_inside()); + ut_ad(ibuf_inside(mtr)); ut_ad(dtuple_check_typed(entry)); low_match = page_cur_search( @@ -4102,7 +4168,7 @@ ibuf_delete( page_cur_t page_cur; ulint low_match; - ut_ad(ibuf_inside()); + ut_ad(ibuf_inside(mtr)); ut_ad(dtuple_check_typed(entry)); low_match = page_cur_search( @@ -4190,7 +4256,7 @@ ibuf_restore_pos( /* The tablespace has been dropped. It is possible that another thread has deleted the insert buffer entry. Do not complain. */ - btr_pcur_commit_specify_mtr(pcur, mtr); + ibuf_btr_pcur_commit_specify_mtr(pcur, mtr); } else { fprintf(stderr, "InnoDB: ERROR: Submit the output to" @@ -4208,7 +4274,7 @@ ibuf_restore_pos( page_rec_get_next(btr_pcur_get_rec(pcur))); fflush(stderr); - btr_pcur_commit_specify_mtr(pcur, mtr); + ibuf_btr_pcur_commit_specify_mtr(pcur, mtr); fputs("InnoDB: Validating insert buffer tree:\n", stderr); if (!btr_validate_index(ibuf->index, NULL)) { @@ -4232,8 +4298,8 @@ ibool ibuf_delete_rec( /*============*/ ulint space, /*!< in: space id */ - ulint page_no,/*!< in: index page number where the record - should belong */ + ulint page_no,/*!< in: index page number that the record + should belong to */ btr_pcur_t* pcur, /*!< in: pcur positioned on the record to delete, having latch mode BTR_MODIFY_LEAF */ const dtuple_t* search_tuple, @@ -4244,10 +4310,10 @@ ibuf_delete_rec( page_t* root; ulint err; - ut_ad(ibuf_inside()); + ut_ad(ibuf_inside(mtr)); ut_ad(page_rec_is_user_rec(btr_pcur_get_rec(pcur))); - ut_ad(ibuf_rec_get_page_no(btr_pcur_get_rec(pcur)) == page_no); - ut_ad(ibuf_rec_get_space(btr_pcur_get_rec(pcur)) == space); + ut_ad(ibuf_rec_get_page_no(mtr, btr_pcur_get_rec(pcur)) == page_no); + ut_ad(ibuf_rec_get_space(mtr, btr_pcur_get_rec(pcur)) == space); success = btr_cur_optimistic_delete(btr_pcur_get_btr_cur(pcur), mtr); @@ -4280,22 +4346,22 @@ ibuf_delete_rec( } ut_ad(page_rec_is_user_rec(btr_pcur_get_rec(pcur))); - ut_ad(ibuf_rec_get_page_no(btr_pcur_get_rec(pcur)) == page_no); - ut_ad(ibuf_rec_get_space(btr_pcur_get_rec(pcur)) == space); + ut_ad(ibuf_rec_get_page_no(mtr, btr_pcur_get_rec(pcur)) == page_no); + ut_ad(ibuf_rec_get_space(mtr, btr_pcur_get_rec(pcur)) == space); /* We have to resort to a pessimistic delete from ibuf */ btr_pcur_store_position(pcur, mtr); + ibuf_btr_pcur_commit_specify_mtr(pcur, mtr); - btr_pcur_commit_specify_mtr(pcur, mtr); - + ibuf_mtr_start(mtr); mutex_enter(&ibuf_mutex); - mtr_start(mtr); - if (!ibuf_restore_pos(space, page_no, search_tuple, BTR_MODIFY_TREE, pcur, mtr)) { mutex_exit(&ibuf_mutex); + ut_ad(!ibuf_inside(mtr)); + ut_ad(mtr->state == MTR_COMMITTED); goto func_exit; } @@ -4312,9 +4378,11 @@ ibuf_delete_rec( mutex_exit(&ibuf_mutex); ibuf->empty = (page_get_n_recs(root) == 0); - btr_pcur_commit_specify_mtr(pcur, mtr); + ibuf_btr_pcur_commit_specify_mtr(pcur, mtr); func_exit: + ut_ad(!ibuf_inside(mtr)); + ut_ad(mtr->state == MTR_COMMITTED); btr_pcur_close(pcur); return(TRUE); @@ -4406,18 +4474,20 @@ ibuf_merge_or_delete_for_page( update_ibuf_bitmap = FALSE; } else { page_t* bitmap_page; + ulint bitmap_bits; - mtr_start(&mtr); + ibuf_mtr_start(&mtr); bitmap_page = ibuf_bitmap_get_map_page( space, page_no, zip_size, &mtr); + bitmap_bits = ibuf_bitmap_page_get_bits( + bitmap_page, page_no, zip_size, + IBUF_BITMAP_BUFFERED, &mtr); - if (!ibuf_bitmap_page_get_bits(bitmap_page, page_no, - zip_size, - IBUF_BITMAP_BUFFERED, - &mtr)) { + ibuf_mtr_commit(&mtr); + + if (!bitmap_bits) { /* No inserts buffered for this page */ - mtr_commit(&mtr); if (!tablespace_being_deleted) { fil_decr_pending_ibuf_merges(space); @@ -4425,7 +4495,6 @@ ibuf_merge_or_delete_for_page( return; } - mtr_commit(&mtr); } } else if (block && (ibuf_fixed_addr_page(space, zip_size, page_no) @@ -4434,11 +4503,9 @@ ibuf_merge_or_delete_for_page( return; } - ibuf_enter(); - heap = mem_heap_create(512); - if (!trx_sys_multiple_tablespace_format) { + if (UNIV_UNLIKELY(!trx_sys_multiple_tablespace_format)) { ut_a(trx_doublewrite_must_reset_space_ids); search_tuple = ibuf_search_tuple_build(space, page_no, heap); } else { @@ -4465,7 +4532,7 @@ ibuf_merge_or_delete_for_page( ut_print_timestamp(stderr); - mtr_start(&mtr); + ibuf_mtr_start(&mtr); fputs(" InnoDB: Dump of the ibuf bitmap page:\n", stderr); @@ -4473,8 +4540,7 @@ ibuf_merge_or_delete_for_page( bitmap_page = ibuf_bitmap_get_map_page(space, page_no, zip_size, &mtr); buf_page_print(bitmap_page, 0); - - mtr_commit(&mtr); + ibuf_mtr_commit(&mtr); fputs("\nInnoDB: Dump of the page:\n", stderr); @@ -4505,7 +4571,7 @@ ibuf_merge_or_delete_for_page( memset(dops, 0, sizeof(dops)); loop: - mtr_start(&mtr); + ibuf_mtr_start(&mtr); if (block) { ibool success; @@ -4539,8 +4605,8 @@ loop: rec = btr_pcur_get_rec(&pcur); /* Check if the entry is for this index page */ - if (ibuf_rec_get_page_no(rec) != page_no - || ibuf_rec_get_space(rec) != space) { + if (ibuf_rec_get_page_no(&mtr, rec) != page_no + || ibuf_rec_get_space(&mtr, rec) != space) { if (block) { page_header_reset_last_insert( @@ -4563,7 +4629,7 @@ loop: dtuple_t* entry; trx_id_t max_trx_id; dict_index_t* dummy_index; - ibuf_op_t op = ibuf_rec_get_op_type(rec); + ibuf_op_t op = ibuf_rec_get_op_type(&mtr, rec); max_trx_id = page_get_max_trx_id(page_align(rec)); page_update_max_trx_id(block, page_zip, max_trx_id, @@ -4572,7 +4638,7 @@ loop: ut_ad(page_validate(page_align(rec), ibuf->index)); entry = ibuf_build_entry_from_ibuf_rec( - rec, heap, &dummy_index); + &mtr, rec, heap, &dummy_index); ut_ad(page_validate(block->frame, dummy_index)); @@ -4605,13 +4671,14 @@ loop: Store and restore the cursor position. */ ut_ad(rec == btr_pcur_get_rec(&pcur)); ut_ad(page_rec_is_user_rec(rec)); - ut_ad(ibuf_rec_get_page_no(rec) == page_no); - ut_ad(ibuf_rec_get_space(rec) == space); + ut_ad(ibuf_rec_get_page_no(&mtr, rec) + == page_no); + ut_ad(ibuf_rec_get_space(&mtr, rec) == space); btr_pcur_store_position(&pcur, &mtr); - btr_pcur_commit_specify_mtr(&pcur, &mtr); + ibuf_btr_pcur_commit_specify_mtr(&pcur, &mtr); - mtr_start(&mtr); + ibuf_mtr_start(&mtr); success = buf_page_get_known_nowait( RW_X_LATCH, block, @@ -4626,7 +4693,8 @@ loop: BTR_MODIFY_LEAF, &pcur, &mtr)) { - mtr_commit(&mtr); + ut_ad(!ibuf_inside(&mtr)); + ut_ad(mtr.state == MTR_COMMITTED); mops[op]++; ibuf_dummy_index_free(dummy_index); goto loop; @@ -4641,7 +4709,7 @@ loop: ibuf_dummy_index_free(dummy_index); } else { - dops[ibuf_rec_get_op_type(rec)]++; + dops[ibuf_rec_get_op_type(&mtr, rec)]++; } /* Delete the record from ibuf */ @@ -4652,7 +4720,7 @@ loop: goto loop; } else if (btr_pcur_is_after_last_on_page(&pcur)) { - mtr_commit(&mtr); + ibuf_mtr_commit(&mtr); btr_pcur_close(&pcur); goto loop; @@ -4686,7 +4754,7 @@ reset_bit: } } - mtr_commit(&mtr); + ibuf_mtr_commit(&mtr); btr_pcur_close(&pcur); mem_heap_free(heap); @@ -4710,8 +4778,6 @@ reset_bit: fil_decr_pending_ibuf_merges(space); } - ibuf_exit(); - #ifdef UNIV_IBUF_COUNT_DEBUG ut_a(ibuf_count_get(space, page_no) == 0); #endif @@ -4731,9 +4797,8 @@ ibuf_delete_for_discarded_space( mem_heap_t* heap; btr_pcur_t pcur; dtuple_t* search_tuple; - rec_t* ibuf_rec; + const rec_t* ibuf_rec; ulint page_no; - ibool closed; mtr_t mtr; /* Counts for discarded operations. */ @@ -4748,9 +4813,7 @@ ibuf_delete_for_discarded_space( memset(dops, 0, sizeof(dops)); loop: - ibuf_enter(); - - mtr_start(&mtr); + ibuf_mtr_start(&mtr); /* Position pcur in the insert buffer at the first entry for the space */ @@ -4770,39 +4833,34 @@ loop: ibuf_rec = btr_pcur_get_rec(&pcur); /* Check if the entry is for this space */ - if (ibuf_rec_get_space(ibuf_rec) != space) { + if (ibuf_rec_get_space(&mtr, ibuf_rec) != space) { goto leave_loop; } - page_no = ibuf_rec_get_page_no(ibuf_rec); + page_no = ibuf_rec_get_page_no(&mtr, ibuf_rec); - dops[ibuf_rec_get_op_type(ibuf_rec)]++; + dops[ibuf_rec_get_op_type(&mtr, ibuf_rec)]++; /* Delete the record from ibuf */ - closed = ibuf_delete_rec(space, page_no, &pcur, search_tuple, - &mtr); - if (closed) { + if (ibuf_delete_rec(space, page_no, &pcur, search_tuple, + &mtr)) { /* Deletion was pessimistic and mtr was committed: we start from the beginning again */ - ibuf_exit(); - goto loop; } if (btr_pcur_is_after_last_on_page(&pcur)) { - mtr_commit(&mtr); + ibuf_mtr_commit(&mtr); btr_pcur_close(&pcur); - ibuf_exit(); - goto loop; } } leave_loop: - mtr_commit(&mtr); + ibuf_mtr_commit(&mtr); btr_pcur_close(&pcur); #ifdef HAVE_ATOMIC_BUILTINS @@ -4814,8 +4872,6 @@ leave_loop: mutex_exit(&ibuf_mutex); #endif /* HAVE_ATOMIC_BUILTINS */ - ibuf_exit(); - mem_heap_free(heap); } @@ -4831,18 +4887,15 @@ ibuf_is_empty(void) const page_t* root; mtr_t mtr; - ibuf_enter(); - mtr_start(&mtr); + ibuf_mtr_start(&mtr); mutex_enter(&ibuf_mutex); root = ibuf_tree_root_get(&mtr); mutex_exit(&ibuf_mutex); is_empty = (page_get_n_recs(root) == 0); - mtr_commit(&mtr); - ibuf_exit(); - ut_a(is_empty == ibuf->empty); + ibuf_mtr_commit(&mtr); return(is_empty); } diff --git a/storage/innobase/include/buf0rea.h b/storage/innobase/include/buf0rea.h index 4a52f9dcd8d..cdf6cdba3d1 100644 --- a/storage/innobase/include/buf0rea.h +++ b/storage/innobase/include/buf0rea.h @@ -70,10 +70,10 @@ UNIV_INTERN ulint buf_read_ahead_linear( /*==================*/ - ulint space, /*!< in: space id */ - ulint zip_size,/*!< in: compressed page size in bytes, or 0 */ - ulint offset);/*!< in: page number of a page; NOTE: the current thread - must want access to this page (see NOTE 3 above) */ + ulint space, /*!< in: space id */ + ulint zip_size, /*!< in: compressed page size in bytes, or 0 */ + ulint offset, /*!< in: page number; see NOTE 3 above */ + ibool inside_ibuf); /*!< in: TRUE if we are inside ibuf routine */ /********************************************************************//** Issues read requests for pages which the ibuf module wants to read in, in order to contract the insert buffer tree. Technically, this function is like diff --git a/storage/innobase/include/ibuf0ibuf.h b/storage/innobase/include/ibuf0ibuf.h index 330efae780c..28c97fd609f 100644 --- a/storage/innobase/include/ibuf0ibuf.h +++ b/storage/innobase/include/ibuf0ibuf.h @@ -104,6 +104,22 @@ UNIV_INTERN void ibuf_update_max_tablespace_id(void); /*===============================*/ +/***************************************************************//** +Starts an insert buffer mini-transaction. */ +UNIV_INLINE +void +ibuf_mtr_start( +/*===========*/ + mtr_t* mtr) /*!< out: mini-transaction */ + __attribute__((nonnull)); +/***************************************************************//** +Commits an insert buffer mini-transaction. */ +UNIV_INLINE +void +ibuf_mtr_commit( +/*============*/ + mtr_t* mtr) /*!< in/out: mini-transaction */ + __attribute__((nonnull)); /*********************************************************************//** Initializes an ibuf bitmap page. */ UNIV_INTERN @@ -224,10 +240,12 @@ routine. For instance, a read-ahead of non-ibuf pages is forbidden by threads that are executing an insert buffer routine. @return TRUE if inside an insert buffer routine */ -UNIV_INTERN +UNIV_INLINE ibool -ibuf_inside(void); -/*=============*/ +ibuf_inside( +/*========*/ + const mtr_t* mtr) /*!< in: mini-transaction */ + __attribute__((nonnull, pure)); /***********************************************************************//** Checks if a page address is an ibuf bitmap page (level 3 page) address. @return TRUE if a bitmap page */ diff --git a/storage/innobase/include/ibuf0ibuf.ic b/storage/innobase/include/ibuf0ibuf.ic index e3fa6e3e929..0a22667a260 100644 --- a/storage/innobase/include/ibuf0ibuf.ic +++ b/storage/innobase/include/ibuf0ibuf.ic @@ -37,6 +37,30 @@ buffer inserts to this page. If there is this much of free space, the corresponding bits are set in the ibuf bitmap. */ #define IBUF_PAGE_SIZE_PER_FREE_SPACE 32 +/***************************************************************//** +Starts an insert buffer mini-transaction. */ +UNIV_INLINE +void +ibuf_mtr_start( +/*===========*/ + mtr_t* mtr) /*!< out: mini-transaction */ +{ + mtr_start(mtr); + mtr->inside_ibuf = TRUE; +} +/***************************************************************//** +Commits an insert buffer mini-transaction. */ +UNIV_INLINE +void +ibuf_mtr_commit( +/*============*/ + mtr_t* mtr) /*!< in/out: mini-transaction */ +{ + ut_ad(mtr->inside_ibuf); + ut_d(mtr->inside_ibuf = FALSE); + mtr_commit(mtr); +} + /** Insert buffer struct */ struct ibuf_struct{ ulint size; /*!< current size of the ibuf index @@ -120,6 +144,22 @@ ibuf_should_try( return(FALSE); } +/******************************************************************//** +Returns TRUE if the current OS thread is performing an insert buffer +routine. + +For instance, a read-ahead of non-ibuf pages is forbidden by threads +that are executing an insert buffer routine. +@return TRUE if inside an insert buffer routine */ +UNIV_INLINE +ibool +ibuf_inside( +/*========*/ + const mtr_t* mtr) /*!< in: mini-transaction */ +{ + return(mtr->inside_ibuf); +} + /***********************************************************************//** Checks if a page address is an ibuf bitmap page address. @return TRUE if a bitmap page */ diff --git a/storage/innobase/include/mtr0mtr.h b/storage/innobase/include/mtr0mtr.h index 8abca093548..5582ad63039 100644 --- a/storage/innobase/include/mtr0mtr.h +++ b/storage/innobase/include/mtr0mtr.h @@ -190,21 +190,21 @@ functions). The page number parameter was originally written as 0. @{ */ /* @} */ /***************************************************************//** -Starts a mini-transaction and creates a mini-transaction handle -and buffer in the memory buffer given by the caller. -@return mtr buffer which also acts as the mtr handle */ +Starts a mini-transaction. */ UNIV_INLINE -mtr_t* +void mtr_start( /*======*/ - mtr_t* mtr); /*!< in: memory buffer for the mtr buffer */ + mtr_t* mtr) /*!< out: mini-transaction */ + __attribute__((nonnull)); /***************************************************************//** Commits a mini-transaction. */ UNIV_INTERN void mtr_commit( /*=======*/ - mtr_t* mtr); /*!< in: mini-transaction */ + mtr_t* mtr) /*!< in/out: mini-transaction */ + __attribute__((nonnull)); /**********************************************************//** Sets and returns a savepoint in mtr. @return savepoint */ @@ -378,6 +378,8 @@ struct mtr_struct{ #endif dyn_array_t memo; /*!< memo stack for locks etc. */ dyn_array_t log; /*!< mini-transaction log */ + ibool inside_ibuf; + /*!< TRUE if inside ibuf changes */ ibool modifications; /* TRUE if the mtr made modifications to buffer pool pages */ diff --git a/storage/innobase/include/mtr0mtr.ic b/storage/innobase/include/mtr0mtr.ic index 55f3cf7f147..3d87eea2710 100644 --- a/storage/innobase/include/mtr0mtr.ic +++ b/storage/innobase/include/mtr0mtr.ic @@ -30,26 +30,23 @@ Created 11/26/1995 Heikki Tuuri #include "mach0data.h" /***************************************************************//** -Starts a mini-transaction and creates a mini-transaction handle -and a buffer in the memory buffer given by the caller. -@return mtr buffer which also acts as the mtr handle */ +Starts a mini-transaction. */ UNIV_INLINE -mtr_t* +void mtr_start( /*======*/ - mtr_t* mtr) /*!< in: memory buffer for the mtr buffer */ + mtr_t* mtr) /*!< out: mini-transaction */ { dyn_array_create(&(mtr->memo)); dyn_array_create(&(mtr->log)); mtr->log_mode = MTR_LOG_ALL; mtr->modifications = FALSE; + mtr->inside_ibuf = FALSE; mtr->n_log_recs = 0; ut_d(mtr->state = MTR_ACTIVE); ut_d(mtr->magic_n = MTR_MAGIC_N); - - return(mtr); } /***************************************************//** diff --git a/storage/innobase/include/sync0sync.h b/storage/innobase/include/sync0sync.h index b4f9e21933f..a24c2106033 100644 --- a/storage/innobase/include/sync0sync.h +++ b/storage/innobase/include/sync0sync.h @@ -110,7 +110,6 @@ extern mysql_pfs_key_t syn_arr_mutex_key; extern mysql_pfs_key_t sync_thread_mutex_key; # endif /* UNIV_SYNC_DEBUG */ extern mysql_pfs_key_t trx_doublewrite_mutex_key; -extern mysql_pfs_key_t thr_local_mutex_key; extern mysql_pfs_key_t trx_undo_mutex_key; #endif /* UNIV_PFS_MUTEX */ diff --git a/storage/innobase/include/thr0loc.h b/storage/innobase/include/thr0loc.h deleted file mode 100644 index bc54f9693b3..00000000000 --- a/storage/innobase/include/thr0loc.h +++ /dev/null @@ -1,74 +0,0 @@ -/***************************************************************************** - -Copyright (c) 1995, 2009, Innobase Oy. All Rights Reserved. - -This program is free software; you can redistribute it and/or modify it under -the terms of the GNU General Public License as published by the Free Software -Foundation; version 2 of the License. - -This program is distributed in the hope that it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along with -this program; if not, write to the Free Software Foundation, Inc., 59 Temple -Place, Suite 330, Boston, MA 02111-1307 USA - -*****************************************************************************/ - -/**************************************************//** -@file include/thr0loc.h -The thread local storage - -Created 10/5/1995 Heikki Tuuri -*******************************************************/ - -/* This module implements storage private to each thread, -a capability useful in some situations like storing the -OS handle to the current thread, or its priority. */ - -#ifndef thr0loc_h -#define thr0loc_h - -#include "univ.i" -#include "os0thread.h" - -/****************************************************************//** -Initializes the thread local storage module. */ -UNIV_INTERN -void -thr_local_init(void); -/*================*/ - /****************************************************************//** -Close the thread local storage module. */ -UNIV_INTERN -void -thr_local_close(void); -/*=================*/ -/*******************************************************************//** -Creates a local storage struct for the calling new thread. */ -UNIV_INTERN -void -thr_local_create(void); -/*==================*/ -/*******************************************************************//** -Frees the local storage struct for the specified thread. */ -UNIV_INTERN -void -thr_local_free( -/*===========*/ - os_thread_id_t id); /*!< in: thread id */ -/*******************************************************************//** -Returns pointer to the 'in_ibuf' field within the current thread local -storage. -@return pointer to the in_ibuf field */ -UNIV_INTERN -ibool* -thr_local_get_in_ibuf_field(void); -/*=============================*/ - -#ifndef UNIV_NONINL -#include "thr0loc.ic" -#endif - -#endif diff --git a/storage/innobase/include/thr0loc.ic b/storage/innobase/include/thr0loc.ic deleted file mode 100644 index ce44e512320..00000000000 --- a/storage/innobase/include/thr0loc.ic +++ /dev/null @@ -1,24 +0,0 @@ -/***************************************************************************** - -Copyright (c) 1995, 2009, Innobase Oy. All Rights Reserved. - -This program is free software; you can redistribute it and/or modify it under -the terms of the GNU General Public License as published by the Free Software -Foundation; version 2 of the License. - -This program is distributed in the hope that it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along with -this program; if not, write to the Free Software Foundation, Inc., 59 Temple -Place, Suite 330, Boston, MA 02111-1307 USA - -*****************************************************************************/ - -/**************************************************//** -@file include/thr0loc.ic -Thread local storage - -Created 10/4/1995 Heikki Tuuri -*******************************************************/ diff --git a/storage/innobase/mtr/mtr0mtr.c b/storage/innobase/mtr/mtr0mtr.c index 74d04a22b86..88e698ed818 100644 --- a/storage/innobase/mtr/mtr0mtr.c +++ b/storage/innobase/mtr/mtr0mtr.c @@ -251,6 +251,7 @@ mtr_commit( ut_ad(mtr); ut_ad(mtr->magic_n == MTR_MAGIC_N); ut_ad(mtr->state == MTR_ACTIVE); + ut_ad(!mtr->inside_ibuf); ut_d(mtr->state = MTR_COMMITTING); #ifndef UNIV_HOTBACKUP diff --git a/storage/innobase/srv/srv0srv.c b/storage/innobase/srv/srv0srv.c index 59a2bc90052..99af0b23a04 100644 --- a/storage/innobase/srv/srv0srv.c +++ b/storage/innobase/srv/srv0srv.c @@ -66,7 +66,6 @@ Created 10/8/1995 Heikki Tuuri #include "mem0mem.h" #include "mem0pool.h" #include "sync0sync.h" -#include "thr0loc.h" #include "que0que.h" #include "log0recv.h" #include "pars0pars.h" @@ -1129,7 +1128,6 @@ srv_general_init(void) os_sync_init(); sync_init(); mem_init(srv_mem_pool_size); - thr_local_init(); } /*======================= InnoDB Server FIFO queue =======================*/ @@ -3071,8 +3069,6 @@ suspend_thread: main thread goes back to loop. */ goto loop; - - OS_THREAD_DUMMY_RETURN; /* Not reached, avoid compiler warning */ } /*********************************************************************//** diff --git a/storage/innobase/srv/srv0start.c b/storage/innobase/srv/srv0start.c index 050fe460652..79eae610a05 100644 --- a/storage/innobase/srv/srv0start.c +++ b/storage/innobase/srv/srv0start.c @@ -85,7 +85,6 @@ Created 2/16/1996 Heikki Tuuri # include "row0row.h" # include "row0mysql.h" # include "btr0pcur.h" -# include "thr0loc.h" # include "os0sync.h" /* for INNODB_RW_LOCKS_USE_ATOMICS */ # include "zlib.h" /* for ZLIB_VERSION */ @@ -2210,7 +2209,6 @@ innobase_shutdown_for_mysql(void) ibuf_close(); log_shutdown(); lock_sys_close(); - thr_local_close(); trx_sys_file_format_close(); trx_sys_close(); diff --git a/storage/innobase/thr/thr0loc.c b/storage/innobase/thr/thr0loc.c deleted file mode 100644 index 0fa93922bb1..00000000000 --- a/storage/innobase/thr/thr0loc.c +++ /dev/null @@ -1,259 +0,0 @@ -/***************************************************************************** - -Copyright (c) 1995, 2009, Innobase Oy. All Rights Reserved. - -This program is free software; you can redistribute it and/or modify it under -the terms of the GNU General Public License as published by the Free Software -Foundation; version 2 of the License. - -This program is distributed in the hope that it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along with -this program; if not, write to the Free Software Foundation, Inc., 59 Temple -Place, Suite 330, Boston, MA 02111-1307 USA - -*****************************************************************************/ - -/**************************************************//** -@file thr/thr0loc.c -The thread local storage - -Created 10/5/1995 Heikki Tuuri -*******************************************************/ - -#include "thr0loc.h" -#ifdef UNIV_NONINL -#include "thr0loc.ic" -#endif - -#include "sync0sync.h" -#include "hash0hash.h" -#include "mem0mem.h" -#include "srv0srv.h" - -/* - IMPLEMENTATION OF THREAD LOCAL STORAGE - ====================================== - -The threads sometimes need private data which depends on the thread id. -This is implemented as a hash table, where the hash value is calculated -from the thread id, to prepare for a large number of threads. The hash table -is protected by a mutex. If you need modify the program and put new data to -the thread local storage, just add it to struct thr_local_struct in the -header file. */ - -/** Mutex protecting thr_local_hash */ -static mutex_t thr_local_mutex; - -/** The hash table. The module is not yet initialized when it is NULL. */ -static hash_table_t* thr_local_hash = NULL; - -/** Thread local data */ -typedef struct thr_local_struct thr_local_t; - -#ifdef UNIV_PFS_MUTEX -/* Key to register the mutex with performance schema */ -UNIV_INTERN mysql_pfs_key_t thr_local_mutex_key; -#endif /* UNIV_PFS_MUTEX */ - -/** @brief Thread local data. -The private data for each thread should be put to -the structure below and the accessor functions written -for the field. */ -struct thr_local_struct{ - os_thread_id_t id; /*!< id of the thread which owns this struct */ - os_thread_t handle; /*!< operating system handle to the thread */ - ibool in_ibuf;/*!< TRUE if the thread is doing an ibuf - operation */ - hash_node_t hash; /*!< hash chain node */ - ulint magic_n;/*!< magic number (THR_LOCAL_MAGIC_N) */ -}; - -/** The value of thr_local_struct::magic_n */ -#define THR_LOCAL_MAGIC_N 1231234 - -#ifdef UNIV_DEBUG -/*******************************************************************//** -Validates thread local data. -@return TRUE if valid */ -static -ibool -thr_local_validate( -/*===============*/ - const thr_local_t* local) /*!< in: data to validate */ -{ - ut_ad(local->magic_n == THR_LOCAL_MAGIC_N); - ut_ad(local->in_ibuf == FALSE || local->in_ibuf == TRUE); - return(TRUE); -} -#endif /* UNIV_DEBUG */ - -/*******************************************************************//** -Returns the local storage struct for a thread. -@return local storage */ -static -thr_local_t* -thr_local_get( -/*==========*/ - os_thread_id_t id) /*!< in: thread id of the thread */ -{ - thr_local_t* local; - -try_again: - ut_ad(thr_local_hash); - ut_ad(mutex_own(&thr_local_mutex)); - - /* Look for the local struct in the hash table */ - - local = NULL; - - HASH_SEARCH(hash, thr_local_hash, os_thread_pf(id), - thr_local_t*, local, ut_ad(thr_local_validate(local)), - os_thread_eq(local->id, id)); - if (local == NULL) { - mutex_exit(&thr_local_mutex); - - thr_local_create(); - - mutex_enter(&thr_local_mutex); - - goto try_again; - } - - ut_ad(thr_local_validate(local)); - - return(local); -} - -/*******************************************************************//** -Returns pointer to the 'in_ibuf' field within the current thread local -storage. -@return pointer to the in_ibuf field */ -UNIV_INTERN -ibool* -thr_local_get_in_ibuf_field(void) -/*=============================*/ -{ - thr_local_t* local; - - mutex_enter(&thr_local_mutex); - - local = thr_local_get(os_thread_get_curr_id()); - - mutex_exit(&thr_local_mutex); - - return(&(local->in_ibuf)); -} - -/*******************************************************************//** -Creates a local storage struct for the calling new thread. */ -UNIV_INTERN -void -thr_local_create(void) -/*==================*/ -{ - thr_local_t* local; - - if (thr_local_hash == NULL) { - thr_local_init(); - } - - local = mem_alloc(sizeof(thr_local_t)); - - local->id = os_thread_get_curr_id(); - local->handle = os_thread_get_curr(); - local->magic_n = THR_LOCAL_MAGIC_N; - local->in_ibuf = FALSE; - - mutex_enter(&thr_local_mutex); - - HASH_INSERT(thr_local_t, hash, thr_local_hash, - os_thread_pf(os_thread_get_curr_id()), - local); - - mutex_exit(&thr_local_mutex); -} - -/*******************************************************************//** -Frees the local storage struct for the specified thread. */ -UNIV_INTERN -void -thr_local_free( -/*===========*/ - os_thread_id_t id) /*!< in: thread id */ -{ - thr_local_t* local; - - mutex_enter(&thr_local_mutex); - - /* Look for the local struct in the hash table */ - - HASH_SEARCH(hash, thr_local_hash, os_thread_pf(id), - thr_local_t*, local, ut_ad(thr_local_validate(local)), - os_thread_eq(local->id, id)); - if (local == NULL) { - mutex_exit(&thr_local_mutex); - - return; - } - - HASH_DELETE(thr_local_t, hash, thr_local_hash, - os_thread_pf(id), local); - - mutex_exit(&thr_local_mutex); - - ut_a(local->magic_n == THR_LOCAL_MAGIC_N); - ut_ad(thr_local_validate(local)); - - mem_free(local); -} - -/****************************************************************//** -Initializes the thread local storage module. */ -UNIV_INTERN -void -thr_local_init(void) -/*================*/ -{ - - ut_a(thr_local_hash == NULL); - - thr_local_hash = hash_create(OS_THREAD_MAX_N + 100); - - mutex_create(thr_local_mutex_key, - &thr_local_mutex, SYNC_THR_LOCAL); -} - -/******************************************************************** -Close the thread local storage module. */ -UNIV_INTERN -void -thr_local_close(void) -/*=================*/ -{ - ulint i; - - ut_a(thr_local_hash != NULL); - - /* Free the hash elements. We don't remove them from the table - because we are going to destroy the table anyway. */ - for (i = 0; i < hash_get_n_cells(thr_local_hash); i++) { - thr_local_t* local; - - local = HASH_GET_FIRST(thr_local_hash, i); - - while (local) { - thr_local_t* prev_local = local; - - local = HASH_GET_NEXT(hash, prev_local); - ut_a(prev_local->magic_n == THR_LOCAL_MAGIC_N); - ut_ad(thr_local_validate(prev_local)); - mem_free(prev_local); - } - } - - hash_table_free(thr_local_hash); - thr_local_hash = NULL; -} diff --git a/storage/innobase/trx/trx0trx.c b/storage/innobase/trx/trx0trx.c index 820c40fe857..0d01bedc4fb 100644 --- a/storage/innobase/trx/trx0trx.c +++ b/storage/innobase/trx/trx0trx.c @@ -38,7 +38,6 @@ Created 3/26/1996 Heikki Tuuri #include "usr0sess.h" #include "read0read.h" #include "srv0srv.h" -#include "thr0loc.h" #include "btr0sea.h" #include "os0proc.h" #include "trx0xa.h" From 08d598fb98e0f7e5c34f47c6510577a375d0fab2 Mon Sep 17 00:00:00 2001 From: Vasil Dimov Date: Mon, 28 Mar 2011 11:34:12 +0300 Subject: [PATCH 17/18] Store the '\0'-terminated query in row->trx_query This problem was introduced in marko.makela@oracle.com-20100514130815-ym7j7cfu88ro6km4 and is probably the reason for the following valgrind warning: from http://bugs.mysql.com/52691 , http://bugs.mysql.com/file.php?id=16880 : Version: '5.6.3-m5-valgrind-max-debug' socket: '/tmp/mysql.sock' port: 3306 Source distribution ==14947== Thread 18: ==14947== Conditional jump or move depends on uninitialised value(s) ==14947== at 0x4A06318: __GI_strlen (mc_replace_strmem.c:284) ==14947== by 0x9F3D7A: fill_innodb_trx_from_cache(trx_i_s_cache_struct*, THD*, TABLE*) (i_s.cc:591) ==14947== by 0x9F4D7D: trx_i_s_common_fill_table(THD*, TABLE_LIST*, Item*) (i_s.cc:1238) ==14947== by 0x7689F3: get_schema_tables_result(JOIN*, enum_schema_table_state) (sql_show.cc:6745) ==14947== by 0x715A75: JOIN::exec() (sql_select.cc:2861) ==14947== by 0x7185BD: mysql_select(THD*, Item***, TABLE_LIST*, unsigned int, List&, Item*, unsigned int, st_order*, st_order*, Item*, st_order*, unsigned long long, select_result*, st_select_lex_unit*, st_select_lex*) (sql_select.cc:3609) ==14947== by 0x70E823: handle_select(THD*, LEX*, select_result*, unsigned long) (sql_select.cc:319) ==14947== by 0x6F2305: execute_sqlcom_select(THD*, TABLE_LIST*) (sql_parse.cc:4557) ==14947== by 0x6EAED4: mysql_execute_command(THD*) (sql_parse.cc:2135) ==14947== by 0x6F44C9: mysql_parse(THD*, char*, unsigned int, Parser_state*) (sql_parse.cc:5597) ==14947== by 0x6E864B: dispatch_command(enum_server_command, THD*, char*, unsigned int) (sql_parse.cc:1093) ==14947== by 0x6E785E: do_command(THD*) (sql_parse.cc:815) ==14947== by 0x6C18DD: do_handle_one_connection(THD*) (sql_connect.cc:771) ==14947== by 0x6C146E: handle_one_connection (sql_connect.cc:707) ==14947== by 0x30E1807760: start_thread (pthread_create.c:301) ==14947== by 0x35EA670F: ??? ==14947== Uninitialised value was created by a heap allocation ==14947== at 0x4A0515D: malloc (vg_replace_malloc.c:195) ==14947== by 0xB4B948: mem_area_alloc (mem0pool.c:385) ==14947== by 0xB4A27C: mem_heap_create_block (mem0mem.c:333) ==14947== by 0xB4A530: mem_heap_add_block (mem0mem.c:446) ==14947== by 0xB0D2A4: mem_heap_alloc (mem0mem.ic:186) ==14947== by 0xB0D9C2: ha_storage_put_memlim (ha0storage.c:118) ==14947== by 0xA479D8: fill_trx_row (trx0i_s.c:521) ==14947== by 0xA490E9: fetch_data_into_cache (trx0i_s.c:1319) ==14947== by 0xA491BA: trx_i_s_possibly_fetch_data_into_cache (trx0i_s.c:1352) ==14947== by 0x9F4CE7: trx_i_s_common_fill_table(THD*, TABLE_LIST*, Item*) (i_s.cc:1221) ==14947== by 0x7689F3: get_schema_tables_result(JOIN*, enum_schema_table_state) (sql_show.cc:6745) ==14947== by 0x715A75: JOIN::exec() (sql_select.cc:2861) ==14947== by 0x7185BD: mysql_select(THD*, Item***, TABLE_LIST*, unsigned int, List&, Item*, unsigned int, st_order*, st_order*, Item*, st_order*, unsigned long long, select_result*, st_select_lex_unit*, st_select_lex*) (sql_select.cc:3609) ==14947== by 0x70E823: handle_select(THD*, LEX*, select_result*, unsigned long) (sql_select.cc:319) ==14947== by 0x6F2305: execute_sqlcom_select(THD*, TABLE_LIST*) (sql_parse.cc:4557) ==14947== by 0x6EAED4: mysql_execute_command(THD*) (sql_parse.cc:2135) ==14947== by 0x6F44C9: mysql_parse(THD*, char*, unsigned int, Parser_state*) (sql_parse.cc:5597) ==14947== by 0x6E864B: dispatch_command(enum_server_command, THD*, char*, unsigned int) (sql_parse.cc:1093) ==14947== by 0x6E785E: do_command(THD*) (sql_parse.cc:815) ==14947== by 0x6C18DD: do_handle_one_connection(THD*) (sql_connect.cc:771) ==14947== by 0x6C146E: handle_one_connection (sql_connect.cc:707) ==14947== by 0x30E1807760: start_thread (pthread_create.c:301) ==14947== by 0x35EA670F: ??? (gdb) bt #0 0x0000000004a06318 in _vgrZU_libcZdsoZa___GI_strlen (str=0x3026bfa0 "insert into `blobtest` set `data`='pkefxxpkalpabzgrczlxefkreqljeqbvzrcnhvhsjsfnvxzjsltfuincffigdkmhvvcmnseluzgbtedrfmxvnrdmzesbinjgwvharkpgjplrlnqudfidbqwgbykupycxzyikzqincnsjrxgncqzlgyqwjdbjulztgsffxpjgymsnntdibvklwqylmwhsmdskmllxuwafabdjnwlyofknwuixiyrgnplmerfdewgizkdhznitesfqepsqbbwkdepkmjoseyxjofmmjaqdipwopfrwidmhqbtovdslvayxcnpewzhppeetblccppniamezibuoinvlxkafpcmozawtplfpepxwlwhymsuraezcwvjqzwogsozodlsfzjiyrcaljjhqwdrcjawvelhefzzaexvcbyorlcyupqwgjuamiqpiputtndjwcsuyzdfhuxswuowhrzdvriwrxqmcqthvzzzvivbabbnhdbtcfdtgssvmirrcddnytnctcvqplwytxxzxelldhwahalzxvgynaiwjyezhxqhlsqudngekocfvlbqprxqhyhwbaomgqiwkpfguohuvlnhtrsszgacxhhzeppyqwfwabiqzgyzkperiidyunrykopysvlcxwhrcboetjltawdjergalsfvaxncmzoznryumrjmncvhvxqvqhhbznnifkguuiffmlrbmgwtzvnuwlaguixqadkupfhasbbxnwkrvsfhrqanfmvjtzfqodtutkjlxfcogtsjywrdgmzgszjtsmimaelsveayqrwviqwwefeziuaqsqpauxpnzhaxjtkdfvvodniwezskbxfxszyniyzkzxngcfwgjlyrlskmrzxqnptwlilsxybuguafxxkvryyjrnkhhcmxuusitaflaiuxjhyfnzkahlgmaszujqmfdhyppdnpweqanmvzgjfyzjolbmprhnuuxextcaxzicfvsuochprmlf"...) at mc_replace_strmem.c:284 #1 0x00000000009f3d7b in fill_innodb_trx_from_cache (cache=0x1462440, thd=0x2a495000, table=0x2a422500) at /home/sbester/build/bzr/mysql-trunk/storage/innobase/handler/i_s.cc:591 #2 0x00000000009f4d7e in trx_i_s_common_fill_table (thd=0x2a495000, tables=0x2a4c3ec0) at /home/sbester/build/bzr/mysql-trunk/storage/innobase/handler/i_s.cc:1238 #3 0x00000000007689f4 in get_schema_tables_result (join=0x30f90c40, executed_place=PROCESSED_BY_JOIN_EXEC) at /home/sbester/build/bzr/mysql-trunk/sql/sql_show.cc:6745 #4 0x0000000000715a76 in JOIN::exec (this=0x30f90c40) at /home/sbester/build/bzr/mysql-trunk/sql/sql_select.cc:2861 #5 0x00000000007185be in mysql_select (thd=0x2a495000, rref_pointer_array=0x2a497590, tables=0x2a4c3ec0, wild_num=1, fields=..., conds=0x0, og_num=0, order=0x0, group=0x0, having=0x0, proc_param=0x0, select_options=2684619520, result=0x30319720, unit=0x2a496d28, select_lex=0x2a497378) at /home/sbester/build/bzr/mysql-trunk/sql/sql_select.cc:3609 #6 0x000000000070e824 in handle_select (thd=0x2a495000, lex=0x2a496c78, result=0x30319720, setup_tables_done_option=0) at /home/sbester/build/bzr/mysql-trunk/sql/sql_select.cc:319 #7 0x00000000006f2306 in execute_sqlcom_select (thd=0x2a495000, all_tables=0x2a4c3ec0) at /home/sbester/build/bzr/mysql-trunk/sql/sql_parse.cc:4557 #8 0x00000000006eaed5 in mysql_execute_command (thd=0x2a495000) at /home/sbester/build/bzr/mysql-trunk/sql/sql_parse.cc:2135 #9 0x00000000006f44ca in mysql_parse (thd=0x2a495000, rawbuf=0x30d80060 "select * from innodb_trx", length=24, parser_state=0x35ea5540) at /home/sbester/build/bzr/mysql-trunk/sql/sql_parse.cc:5597 #10 0x00000000006e864c in dispatch_command (command=COM_QUERY, thd=0x2a495000, packet=0x30bb4e31 "select * from innodb_trx", packet_length=24) at /home/sbester/build/bzr/mysql-trunk/sql/sql_parse.cc:1093 #11 0x00000000006e785f in do_command (thd=0x2a495000) at /home/sbester/build/bzr/mysql-trunk/sql/sql_parse.cc:815 #12 0x00000000006c18de in do_handle_one_connection (thd_arg=0x2a495000) at /home/sbester/build/bzr/mysql-trunk/sql/sql_connect.cc:771 #13 0x00000000006c146f in handle_one_connection (arg=0x2a495000) at /home/sbester/build/bzr/mysql-trunk/sql/sql_connect.cc:707 #14 0x00000030e1807761 in start_thread (arg=0x35ea6710) at pthread_create.c:301 #15 0x00000030e14e14ed in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:115 (gdb) frame 1 #1 0x00000000009f3d7b in fill_innodb_trx_from_cache (cache=0x1462440, thd=0x2a495000, table=0x2a422500) at /home/sbester/build/bzr/mysql-trunk/storage/innobase/handler/i_s.cc:591 591 row->trx_query_cs); (gdb) list 586 if (row->trx_query) { 587 /* store will do appropriate character set 588 conversion check */ 589 fields[IDX_TRX_QUERY]->store( 590 row->trx_query, strlen(row->trx_query), 591 row->trx_query_cs); 592 fields[IDX_TRX_QUERY]->set_notnull(); 593 } else { 594 fields[IDX_TRX_QUERY]->set_null(); 595 } --- storage/innodb_plugin/trx/trx0i_s.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/storage/innodb_plugin/trx/trx0i_s.c b/storage/innodb_plugin/trx/trx0i_s.c index 267e91db22e..53f4dcb0bef 100644 --- a/storage/innodb_plugin/trx/trx0i_s.c +++ b/storage/innodb_plugin/trx/trx0i_s.c @@ -508,7 +508,7 @@ fill_trx_row( query[stmt_len] = '\0'; row->trx_query = ha_storage_put_memlim( - cache->storage, stmt, stmt_len + 1, + cache->storage, query, stmt_len + 1, MAX_ALLOWED_FOR_STORAGE(cache)); row->trx_query_cs = innobase_get_charset(trx->mysql_thd); From ddec6ecdd8521d6fd6e4c26498e7bd752fd3eddf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Wed, 30 Mar 2011 14:25:58 +0300 Subject: [PATCH 18/18] Bug#11877216 InnoDB too eager to commit suicide on a busy server sync_array_print_long_waits(): Return the longest waiting thread ID and the longest waited-for lock. Only if those remain unchanged between calls in srv_error_monitor_thread(), increment fatal_cnt. Otherwise, reset fatal_cnt. Background: There is a built-in watchdog in InnoDB whose purpose is to kill the server when some thread is stuck waiting for a mutex or rw-lock. Before this fix, the logic was flawed. The function sync_array_print_long_waits() returns TRUE if it finds a lock wait that exceeds 10 minutes (srv_fatal_semaphore_wait_threshold). The function srv_error_monitor_thread() will kill the server if this happens 10 times in a row (fatal_cnt reaches 10), checked every 30 seconds. This is wrong, because this situation does not mean that the server is hung. If the server is very busy for a little over 15 minutes, it will be killed. Consider this example. Thread T1 is waiting for mutex M. Some time later, threads T2..Tn start waiting for the same mutex M. If T1 keeps waiting for 600 seconds, fatal_cnt will be incremented to 1. So far, so good. Now, if M is granted to T1, the server was obviously not stuck. But, T2..Tn keeps waiting, and their wait time will be longer than 600 seconds. If 5 minutes later, some Tn has still been waiting for more than 10 minutes for the mutex M, the server can be killed, even though it is not stuck. rb:622 approved by Jimmy Yang --- storage/innobase/include/sync0arr.h | 11 +++++--- storage/innobase/srv/srv0srv.c | 19 +++++++++---- storage/innobase/sync/sync0arr.c | 36 ++++++++++++++++++------ storage/innodb_plugin/ChangeLog | 5 ++++ storage/innodb_plugin/include/sync0arr.h | 7 +++-- storage/innodb_plugin/srv/srv0srv.c | 11 +++++++- storage/innodb_plugin/sync/sync0arr.c | 32 ++++++++++++++++----- 7 files changed, 93 insertions(+), 28 deletions(-) diff --git a/storage/innobase/include/sync0arr.h b/storage/innobase/include/sync0arr.h index fae26b7a63e..ec48059dbcb 100644 --- a/storage/innobase/include/sync0arr.h +++ b/storage/innobase/include/sync0arr.h @@ -93,10 +93,13 @@ sync_arr_wake_threads_if_sema_free(void); Prints warnings of long semaphore waits to stderr. */ ibool -sync_array_print_long_waits(void); -/*=============================*/ - /* out: TRUE if fatal semaphore wait threshold - was exceeded */ +sync_array_print_long_waits( +/*========================*/ + /* out: TRUE if fatal semaphore wait threshold + was exceeded */ + os_thread_id_t* waiter, /* out: longest waiting thread */ + const void** sema) /* out: longest-waited-for semaphore */ + __attribute__((nonnull)); /************************************************************************ Validates the integrity of the wait array. Checks that the number of reserved cells equals the count variable. */ diff --git a/storage/innobase/srv/srv0srv.c b/storage/innobase/srv/srv0srv.c index 9c34e73109c..3f6f1982992 100644 --- a/storage/innobase/srv/srv0srv.c +++ b/storage/innobase/srv/srv0srv.c @@ -2180,9 +2180,15 @@ srv_error_monitor_thread( os_thread_create */ { /* number of successive fatal timeouts observed */ - ulint fatal_cnt = 0; - dulint old_lsn; - dulint new_lsn; + ulint fatal_cnt = 0; + dulint old_lsn; + dulint new_lsn; + /* longest waiting thread for a semaphore */ + os_thread_id_t waiter = os_thread_get_curr_id(); + os_thread_id_t old_waiter = waiter; + /* the semaphore that is being waited for */ + const void* sema = NULL; + const void* old_sema = NULL; old_lsn = srv_start_lsn; @@ -2224,10 +2230,11 @@ loop: /* In case mutex_exit is not a memory barrier, it is theoretically possible some threads are left waiting though the semaphore is already released. Wake up those threads: */ - + sync_arr_wake_threads_if_sema_free(); - if (sync_array_print_long_waits()) { + if (sync_array_print_long_waits(&waiter, &sema) + && sema == old_sema && os_thread_eq(waiter, old_waiter)) { fatal_cnt++; if (fatal_cnt > 10) { @@ -2242,6 +2249,8 @@ loop: } } else { fatal_cnt = 0; + old_waiter = waiter; + old_sema = sema; } /* Flush stderr so that a database user gets the output diff --git a/storage/innobase/sync/sync0arr.c b/storage/innobase/sync/sync0arr.c index 41d3492c8c9..93a7398f252 100644 --- a/storage/innobase/sync/sync0arr.c +++ b/storage/innobase/sync/sync0arr.c @@ -916,10 +916,12 @@ sync_arr_wake_threads_if_sema_free(void) Prints warnings of long semaphore waits to stderr. */ ibool -sync_array_print_long_waits(void) -/*=============================*/ - /* out: TRUE if fatal semaphore wait threshold - was exceeded */ +sync_array_print_long_waits( +/*========================*/ + /* out: TRUE if fatal semaphore wait threshold + was exceeded */ + os_thread_id_t* waiter, /* out: longest waiting thread */ + const void** sema) /* out: longest-waited-for semaphore */ { sync_cell_t* cell; ibool old_val; @@ -927,24 +929,40 @@ sync_array_print_long_waits(void) ulint i; ulint fatal_timeout = srv_fatal_semaphore_wait_threshold; ibool fatal = FALSE; + double longest_diff = 0; for (i = 0; i < sync_primary_wait_array->n_cells; i++) { + double diff; + void* wait_object; + cell = sync_array_get_nth_cell(sync_primary_wait_array, i); - if (cell->wait_object != NULL && cell->waiting - && difftime(time(NULL), cell->reservation_time) > 240) { + wait_object = cell->wait_object; + + if (wait_object == NULL || !cell->waiting) { + + continue; + } + + diff = difftime(time(NULL), cell->reservation_time); + + if (diff > 240) { fputs("InnoDB: Warning: a long semaphore wait:\n", stderr); sync_array_cell_print(stderr, cell); noticed = TRUE; } - if (cell->wait_object != NULL && cell->waiting - && difftime(time(NULL), cell->reservation_time) - > fatal_timeout) { + if (diff > fatal_timeout) { fatal = TRUE; } + + if (diff > longest_diff) { + longest_diff = diff; + *sema = wait_object; + *waiter = cell->thread; + } } if (noticed) { diff --git a/storage/innodb_plugin/ChangeLog b/storage/innodb_plugin/ChangeLog index 7c82cd9c27f..100cf3690ce 100644 --- a/storage/innodb_plugin/ChangeLog +++ b/storage/innodb_plugin/ChangeLog @@ -1,3 +1,8 @@ +2011-03-30 The InnoDB Team + + * srv/srv0srv.c, sync/sync0arr.h, sync/sync0arr.c: + Fix Bug#11877216 InnoDB too eager to commit suicide on a busy server + 2011-03-15 The InnoDB Team * btr/btr0cur.c, page/page0zip.c: diff --git a/storage/innodb_plugin/include/sync0arr.h b/storage/innodb_plugin/include/sync0arr.h index 5f1280f5e28..6e931346238 100644 --- a/storage/innodb_plugin/include/sync0arr.h +++ b/storage/innodb_plugin/include/sync0arr.h @@ -115,8 +115,11 @@ Prints warnings of long semaphore waits to stderr. @return TRUE if fatal semaphore wait threshold was exceeded */ UNIV_INTERN ibool -sync_array_print_long_waits(void); -/*=============================*/ +sync_array_print_long_waits( +/*========================*/ + os_thread_id_t* waiter, /*!< out: longest waiting thread */ + const void** sema) /*!< out: longest-waited-for semaphore */ + __attribute__((nonnull)); /********************************************************************//** Validates the integrity of the wait array. Checks that the number of reserved cells equals the count variable. */ diff --git a/storage/innodb_plugin/srv/srv0srv.c b/storage/innodb_plugin/srv/srv0srv.c index 3cf17f33c40..b1fc1ac67fd 100644 --- a/storage/innodb_plugin/srv/srv0srv.c +++ b/storage/innodb_plugin/srv/srv0srv.c @@ -2236,6 +2236,12 @@ srv_error_monitor_thread( ulint fatal_cnt = 0; ib_uint64_t old_lsn; ib_uint64_t new_lsn; + /* longest waiting thread for a semaphore */ + os_thread_id_t waiter = os_thread_get_curr_id(); + os_thread_id_t old_waiter = waiter; + /* the semaphore that is being waited for */ + const void* sema = NULL; + const void* old_sema = NULL; old_lsn = srv_start_lsn; @@ -2284,7 +2290,8 @@ loop: sync_arr_wake_threads_if_sema_free(); - if (sync_array_print_long_waits()) { + if (sync_array_print_long_waits(&waiter, &sema) + && sema == old_sema && os_thread_eq(waiter, old_waiter)) { fatal_cnt++; if (fatal_cnt > 10) { @@ -2299,6 +2306,8 @@ loop: } } else { fatal_cnt = 0; + old_waiter = waiter; + old_sema = sema; } /* Flush stderr so that a database user gets the output diff --git a/storage/innodb_plugin/sync/sync0arr.c b/storage/innodb_plugin/sync/sync0arr.c index ad29b90d344..13970023573 100644 --- a/storage/innodb_plugin/sync/sync0arr.c +++ b/storage/innodb_plugin/sync/sync0arr.c @@ -914,8 +914,10 @@ Prints warnings of long semaphore waits to stderr. @return TRUE if fatal semaphore wait threshold was exceeded */ UNIV_INTERN ibool -sync_array_print_long_waits(void) -/*=============================*/ +sync_array_print_long_waits( +/*========================*/ + os_thread_id_t* waiter, /*!< out: longest waiting thread */ + const void** sema) /*!< out: longest-waited-for semaphore */ { sync_cell_t* cell; ibool old_val; @@ -923,24 +925,40 @@ sync_array_print_long_waits(void) ulint i; ulint fatal_timeout = srv_fatal_semaphore_wait_threshold; ibool fatal = FALSE; + double longest_diff = 0; for (i = 0; i < sync_primary_wait_array->n_cells; i++) { + double diff; + void* wait_object; + cell = sync_array_get_nth_cell(sync_primary_wait_array, i); - if (cell->wait_object != NULL && cell->waiting - && difftime(time(NULL), cell->reservation_time) > 240) { + wait_object = cell->wait_object; + + if (wait_object == NULL || !cell->waiting) { + + continue; + } + + diff = difftime(time(NULL), cell->reservation_time); + + if (diff > 240) { fputs("InnoDB: Warning: a long semaphore wait:\n", stderr); sync_array_cell_print(stderr, cell); noticed = TRUE; } - if (cell->wait_object != NULL && cell->waiting - && difftime(time(NULL), cell->reservation_time) - > fatal_timeout) { + if (diff > fatal_timeout) { fatal = TRUE; } + + if (diff > longest_diff) { + longest_diff = diff; + *sema = wait_object; + *waiter = cell->thread; + } } if (noticed) {