From 09c4175dffe2b20e8e418824a6b94663551a45d8 Mon Sep 17 00:00:00 2001 From: "tsmith/tim@siva.hindu.god" <> Date: Fri, 10 Nov 2006 12:13:52 -0700 Subject: [PATCH 1/8] Backport patch of bugfix for: - Bug #15815: Very poor performance with multiple queries running concurrently - Bug #22868: 'Thread thrashing' with > 50 concurrent conns under an upd-intensive workloadw This is a patch from an e-mail; it is not included (yet) in an InnoDB snapshot. --- innobase/buf/buf0buf.c | 173 +++++++++++++++++++++++------------ innobase/buf/buf0flu.c | 92 +++++++++++++------ innobase/buf/buf0lru.c | 25 ++++- innobase/include/buf0buf.h | 40 +++++--- innobase/include/buf0buf.ic | 19 ++-- innobase/include/sync0arr.h | 13 +-- innobase/include/sync0rw.h | 1 + innobase/include/sync0rw.ic | 6 +- innobase/include/sync0sync.h | 1 + innobase/os/os0sync.c | 55 ++++++++++- innobase/sync/sync0arr.c | 119 +++++++++--------------- innobase/sync/sync0rw.c | 2 + innobase/sync/sync0sync.c | 8 +- 13 files changed, 356 insertions(+), 198 deletions(-) diff --git a/innobase/buf/buf0buf.c b/innobase/buf/buf0buf.c index 31a581d2ba8..90da3205a82 100644 --- a/innobase/buf/buf0buf.c +++ b/innobase/buf/buf0buf.c @@ -221,6 +221,9 @@ in the free list to the frames. 5) When we have AWE enabled, we disable adaptive hash indexes. */ +/* Value in microseconds */ +static const int WAIT_FOR_READ = 20000; + buf_pool_t* buf_pool = NULL; /* The buffer buf_pool of the database */ ulint buf_dbg_counter = 0; /* This is used to insert validation @@ -466,6 +469,9 @@ buf_block_init( block->n_pointers = 0; + mutex_create(&block->mutex); + mutex_set_level(&block->mutex, SYNC_BUF_BLOCK); + rw_lock_create(&(block->lock)); ut_ad(rw_lock_validate(&(block->lock))); @@ -734,8 +740,15 @@ buf_awe_map_page_to_frame( bck = UT_LIST_GET_LAST(buf_pool->awe_LRU_free_mapped); while (bck) { - if (bck->state == BUF_BLOCK_FILE_PAGE - && (bck->buf_fix_count != 0 || bck->io_fix != 0)) { + ibool skip; + + mutex_enter(&bck->mutex); + + skip = (bck->state == BUF_BLOCK_FILE_PAGE + && (bck->buf_fix_count != 0 || bck->io_fix != 0)); + + if (skip) { + mutex_exit(&bck->mutex); /* We have to skip this */ bck = UT_LIST_GET_PREV(awe_LRU_free_mapped, bck); @@ -768,6 +781,8 @@ buf_awe_map_page_to_frame( buf_pool->n_pages_awe_remapped++; + mutex_exit(&bck->mutex); + return; } } @@ -806,13 +821,22 @@ buf_block_make_young( /*=================*/ buf_block_t* block) /* in: block to make younger */ { - if (buf_pool->freed_page_clock >= block->freed_page_clock - + 1 + (buf_pool->curr_size / 1024)) { +#ifdef UNIV_SYNC_DEBUG + ut_ad(!mutex_own(&(buf_pool->mutex))); +#endif /* UNIV_SYNC_DEBUG */ + /* Note that we read freed_page_clock's without holding any mutex: + this is allowed since the result is used only in heuristics */ + + if (buf_pool->freed_page_clock >= block->freed_page_clock + + 1 + (buf_pool->curr_size / 4)) { + + mutex_enter(&buf_pool->mutex); /* There has been freeing activity in the LRU list: best to move to the head of the LRU list */ buf_LRU_make_block_young(block); + mutex_exit(&buf_pool->mutex); } } @@ -847,12 +871,16 @@ buf_block_free( /*===========*/ buf_block_t* block) /* in, own: block to be freed */ { - ut_a(block->state != BUF_BLOCK_FILE_PAGE); - mutex_enter(&(buf_pool->mutex)); + mutex_enter(&block->mutex); + + ut_a(block->state != BUF_BLOCK_FILE_PAGE); + buf_LRU_block_free_non_file_page(block); + mutex_exit(&block->mutex); + mutex_exit(&(buf_pool->mutex)); } @@ -1071,9 +1099,8 @@ buf_page_get_gen( #endif buf_pool->n_page_gets++; loop: - mutex_enter_fast(&(buf_pool->mutex)); - block = NULL; + mutex_enter_fast(&(buf_pool->mutex)); if (guess) { block = buf_block_align(guess); @@ -1111,6 +1138,8 @@ loop: goto loop; } + mutex_enter(&block->mutex); + ut_a(block->state == BUF_BLOCK_FILE_PAGE); must_read = FALSE; @@ -1120,9 +1149,9 @@ loop: must_read = TRUE; if (mode == BUF_GET_IF_IN_POOL) { - /* The page is only being read to buffer */ - mutex_exit(&(buf_pool->mutex)); + mutex_exit(&buf_pool->mutex); + mutex_exit(&block->mutex); return(NULL); } @@ -1146,7 +1175,7 @@ loop: #else buf_block_buf_fix_inc(block); #endif - buf_block_make_young(block); + mutex_exit(&buf_pool->mutex); /* Check if this is the first access to the page */ @@ -1154,10 +1183,13 @@ loop: block->accessed = TRUE; + mutex_exit(&block->mutex); + + buf_block_make_young(block); + #ifdef UNIV_DEBUG_FILE_ACCESSES ut_a(block->file_page_was_freed == FALSE); #endif - mutex_exit(&(buf_pool->mutex)); #ifdef UNIV_DEBUG buf_dbg_counter++; @@ -1182,13 +1214,14 @@ loop: } if (!success) { - mutex_enter(&(buf_pool->mutex)); + mutex_enter(&block->mutex); block->buf_fix_count--; + + mutex_exit(&block->mutex); #ifdef UNIV_SYNC_DEBUG rw_lock_s_unlock(&(block->debug_latch)); #endif - mutex_exit(&(buf_pool->mutex)); return(NULL); } @@ -1199,18 +1232,16 @@ loop: completes */ for (;;) { - mutex_enter(&(buf_pool->mutex)); + mutex_enter(&block->mutex); if (block->io_fix == BUF_IO_READ) { - mutex_exit(&(buf_pool->mutex)); + mutex_exit(&block->mutex); - /* Sleep 20 milliseconds */ - - os_thread_sleep(20000); + os_thread_sleep(WAIT_FOR_READ); } else { - mutex_exit(&(buf_pool->mutex)); + mutex_exit(&block->mutex); break; } @@ -1268,14 +1299,14 @@ buf_page_optimistic_get_func( ut_ad(mtr && block); ut_ad((rw_latch == RW_S_LATCH) || (rw_latch == RW_X_LATCH)); - - mutex_enter(&(buf_pool->mutex)); /* If AWE is used, block may have a different frame now, e.g., NULL */ - + + mutex_enter(&block->mutex); + if (block->state != BUF_BLOCK_FILE_PAGE || block->frame != guess) { - mutex_exit(&(buf_pool->mutex)); + mutex_exit(&block->mutex); return(FALSE); } @@ -1285,16 +1316,15 @@ buf_page_optimistic_get_func( #else buf_block_buf_fix_inc(block); #endif + accessed = block->accessed; + block->accessed = TRUE; + + mutex_exit(&block->mutex); + buf_block_make_young(block); /* Check if this is the first access to the page */ - accessed = block->accessed; - - block->accessed = TRUE; - - mutex_exit(&(buf_pool->mutex)); - ut_ad(!ibuf_inside() || ibuf_page(block->space, block->offset)); if (rw_latch == RW_S_LATCH) { @@ -1308,14 +1338,15 @@ buf_page_optimistic_get_func( } if (!success) { - mutex_enter(&(buf_pool->mutex)); - + mutex_enter(&block->mutex); + block->buf_fix_count--; + + mutex_exit(&block->mutex); + #ifdef UNIV_SYNC_DEBUG rw_lock_s_unlock(&(block->debug_latch)); -#endif - mutex_exit(&(buf_pool->mutex)); - +#endif return(FALSE); } @@ -1329,14 +1360,15 @@ buf_page_optimistic_get_func( rw_lock_x_unlock(&(block->lock)); } - mutex_enter(&(buf_pool->mutex)); - + mutex_enter(&block->mutex); + block->buf_fix_count--; + + mutex_exit(&block->mutex); + #ifdef UNIV_SYNC_DEBUG rw_lock_s_unlock(&(block->debug_latch)); -#endif - mutex_exit(&(buf_pool->mutex)); - +#endif return(FALSE); } @@ -1394,10 +1426,10 @@ buf_page_get_known_nowait( ut_ad(mtr); ut_ad((rw_latch == RW_S_LATCH) || (rw_latch == RW_X_LATCH)); - mutex_enter(&(buf_pool->mutex)); - block = buf_block_align(guess); + mutex_enter(&block->mutex); + if (block->state == BUF_BLOCK_REMOVE_HASH) { /* Another thread is just freeing the block from the LRU list of the buffer pool: do not try to access this page; this @@ -1406,7 +1438,7 @@ buf_page_get_known_nowait( we have already removed it from the page address hash table of the buffer pool. */ - mutex_exit(&(buf_pool->mutex)); + mutex_exit(&block->mutex); return(FALSE); } @@ -1418,12 +1450,12 @@ buf_page_get_known_nowait( #else buf_block_buf_fix_inc(block); #endif + mutex_exit(&block->mutex); + if (mode == BUF_MAKE_YOUNG) { buf_block_make_young(block); } - mutex_exit(&(buf_pool->mutex)); - ut_ad(!ibuf_inside() || (mode == BUF_KEEP_OLD)); if (rw_latch == RW_S_LATCH) { @@ -1437,13 +1469,15 @@ buf_page_get_known_nowait( } if (!success) { - mutex_enter(&(buf_pool->mutex)); + mutex_enter(&block->mutex); block->buf_fix_count--; + + mutex_exit(&block->mutex); + #ifdef UNIV_SYNC_DEBUG rw_lock_s_unlock(&(block->debug_latch)); #endif - mutex_exit(&(buf_pool->mutex)); return(FALSE); } @@ -1491,8 +1525,7 @@ buf_page_init_for_backup_restore( block->offset = offset; block->lock_hash_val = 0; - block->lock_mutex = NULL; - + block->freed_page_clock = 0; block->newest_modification = ut_dulint_zero; @@ -1524,6 +1557,7 @@ buf_page_init( { #ifdef UNIV_SYNC_DEBUG ut_ad(mutex_own(&(buf_pool->mutex))); + ut_ad(mutex_own(&(block->mutex))); #endif /* UNIV_SYNC_DEBUG */ ut_a(block->state != BUF_BLOCK_FILE_PAGE); @@ -1537,8 +1571,7 @@ buf_page_init( block->check_index_page_at_flush = FALSE; block->lock_hash_val = lock_rec_hash(space, offset); - block->lock_mutex = NULL; - + /* Insert into the hash table of file pages */ if (buf_page_hash_get(space, offset)) { @@ -1630,6 +1663,7 @@ buf_page_init_for_read( ut_a(block); mutex_enter(&(buf_pool->mutex)); + mutex_enter(&block->mutex); if (fil_tablespace_deleted_or_being_deleted_in_mem(space, tablespace_version)) { @@ -1642,7 +1676,9 @@ buf_page_init_for_read( /* The page belongs to a space which has been deleted or is being deleted, or the page is already in buf_pool, return */ + mutex_exit(&block->mutex); mutex_exit(&(buf_pool->mutex)); + buf_block_free(block); if (mode == BUF_READ_IBUF_PAGES_ONLY) { @@ -1662,6 +1698,7 @@ buf_page_init_for_read( buf_LRU_add_block(block, TRUE); /* TRUE == to old blocks */ block->io_fix = BUF_IO_READ; + buf_pool->n_pend_reads++; /* We set a pass-type x-lock on the frame because then the same @@ -1673,6 +1710,7 @@ buf_page_init_for_read( rw_lock_x_lock_gen(&(block->lock), BUF_IO_READ); + mutex_exit(&block->mutex); mutex_exit(&(buf_pool->mutex)); if (mode == BUF_READ_IBUF_PAGES_ONLY) { @@ -1735,6 +1773,8 @@ buf_page_create( block = free_block; + mutex_enter(&block->mutex); + buf_page_init(space, offset, block); /* The block must be put to the LRU list */ @@ -1745,13 +1785,15 @@ buf_page_create( #else buf_block_buf_fix_inc(block); #endif + buf_pool->n_pages_created++; + + mutex_exit(&(buf_pool->mutex)); + mtr_memo_push(mtr, block, MTR_MEMO_BUF_FIX); block->accessed = TRUE; - buf_pool->n_pages_created++; - - mutex_exit(&(buf_pool->mutex)); + mutex_exit(&block->mutex); /* Delete possible entries for the page from the insert buffer: such can exist if the page belonged to an index which was dropped */ @@ -1800,6 +1842,12 @@ buf_page_io_complete( ut_a(block->state == BUF_BLOCK_FILE_PAGE); + /* We do not need protect block->io_fix here by block->mutex to read + it because this is the only function where we can change the value + from BUF_IO_READ or BUF_IO_WRITE to some other value, and our code + ensures that this is the only thread that handles the i/o for this + block. */ + io_type = block->io_fix; if (io_type == BUF_IO_READ) { @@ -1868,11 +1916,12 @@ buf_page_io_complete( } } + mutex_enter(&(buf_pool->mutex)); + mutex_enter(&block->mutex); + #ifdef UNIV_IBUF_DEBUG ut_a(ibuf_count_get(block->space, block->offset) == 0); #endif - mutex_enter(&(buf_pool->mutex)); - /* Because this thread which does the unlocking is not the same that did the locking, we use a pass value != 0 in unlock, which simply removes the newest lock debug record, without checking the thread @@ -1911,6 +1960,7 @@ buf_page_io_complete( } } + mutex_exit(&block->mutex); mutex_exit(&(buf_pool->mutex)); if (buf_debug_prints) { @@ -1970,6 +2020,8 @@ buf_validate(void) block = buf_pool_get_nth_block(buf_pool, i); + mutex_enter(&block->mutex); + if (block->state == BUF_BLOCK_FILE_PAGE) { ut_a(buf_page_hash_get(block->space, @@ -2013,6 +2065,8 @@ buf_validate(void) } else if (block->state == BUF_BLOCK_NOT_USED) { n_free++; } + + mutex_exit(&block->mutex); } if (n_lru + n_free > buf_pool->curr_size) { @@ -2303,16 +2357,21 @@ buf_all_freed(void) block = buf_pool_get_nth_block(buf_pool, i); + mutex_enter(&block->mutex); + if (block->state == BUF_BLOCK_FILE_PAGE) { if (!buf_flush_ready_for_replace(block)) { fprintf(stderr, "Page %lu %lu still fixed or dirty\n", - (ulong) block->space, (ulong) block->offset); + (ulong) block->space, + (ulong) block->offset); ut_error; } } + + mutex_exit(&block->mutex); } mutex_exit(&(buf_pool->mutex)); diff --git a/innobase/buf/buf0flu.c b/innobase/buf/buf0flu.c index 4df0e9962fb..a8252781f61 100644 --- a/innobase/buf/buf0flu.c +++ b/innobase/buf/buf0flu.c @@ -114,6 +114,7 @@ buf_flush_ready_for_replace( { #ifdef UNIV_SYNC_DEBUG ut_ad(mutex_own(&(buf_pool->mutex))); + ut_ad(mutex_own(&block->mutex)); #endif /* UNIV_SYNC_DEBUG */ if (block->state != BUF_BLOCK_FILE_PAGE) { ut_print_timestamp(stderr); @@ -148,6 +149,7 @@ buf_flush_ready_for_flush( { #ifdef UNIV_SYNC_DEBUG ut_ad(mutex_own(&(buf_pool->mutex))); + ut_ad(mutex_own(&(block->mutex))); #endif /* UNIV_SYNC_DEBUG */ ut_a(block->state == BUF_BLOCK_FILE_PAGE); @@ -533,8 +535,15 @@ buf_flush_try_page( ut_a(!block || block->state == BUF_BLOCK_FILE_PAGE); + if (!block) { + mutex_exit(&(buf_pool->mutex)); + return(0); + } + + mutex_enter(&block->mutex); + if (flush_type == BUF_FLUSH_LIST - && block && buf_flush_ready_for_flush(block, flush_type)) { + && buf_flush_ready_for_flush(block, flush_type)) { block->io_fix = BUF_IO_WRITE; @@ -572,6 +581,7 @@ buf_flush_try_page( locked = TRUE; } + mutex_exit(&block->mutex); mutex_exit(&(buf_pool->mutex)); if (!locked) { @@ -590,8 +600,8 @@ buf_flush_try_page( return(1); - } else if (flush_type == BUF_FLUSH_LRU && block - && buf_flush_ready_for_flush(block, flush_type)) { + } else if (flush_type == BUF_FLUSH_LRU + && buf_flush_ready_for_flush(block, flush_type)) { /* VERY IMPORTANT: Because any thread may call the LRU flush, even when owning @@ -631,14 +641,15 @@ buf_flush_try_page( buf_pool mutex: this ensures that the latch is acquired immediately. */ + mutex_exit(&block->mutex); mutex_exit(&(buf_pool->mutex)); buf_flush_write_block_low(block); return(1); - } else if (flush_type == BUF_FLUSH_SINGLE_PAGE && block - && buf_flush_ready_for_flush(block, flush_type)) { + } else if (flush_type == BUF_FLUSH_SINGLE_PAGE + && buf_flush_ready_for_flush(block, flush_type)) { block->io_fix = BUF_IO_WRITE; @@ -664,6 +675,7 @@ buf_flush_try_page( (buf_pool->n_flush[flush_type])++; + mutex_exit(&block->mutex); mutex_exit(&(buf_pool->mutex)); rw_lock_s_lock_gen(&(block->lock), BUF_IO_WRITE); @@ -678,11 +690,12 @@ buf_flush_try_page( buf_flush_write_block_low(block); return(1); - } else { - mutex_exit(&(buf_pool->mutex)); + } - return(0); - } + mutex_exit(&block->mutex); + mutex_exit(&(buf_pool->mutex)); + + return(0); } /*************************************************************** @@ -727,34 +740,48 @@ buf_flush_try_neighbors( block = buf_page_hash_get(space, i); ut_a(!block || block->state == BUF_BLOCK_FILE_PAGE); - if (block && flush_type == BUF_FLUSH_LRU && i != offset - && !block->old) { + if (!block) { + + continue; + + } else if (flush_type == BUF_FLUSH_LRU && i != offset + && !block->old) { /* We avoid flushing 'non-old' blocks in an LRU flush, because the flushed blocks are soon freed */ continue; - } + } else { - if (block && buf_flush_ready_for_flush(block, flush_type) - && (i == offset || block->buf_fix_count == 0)) { - /* We only try to flush those neighbors != offset - where the buf fix count is zero, as we then know that - we probably can latch the page without a semaphore - wait. Semaphore waits are expensive because we must - flush the doublewrite buffer before we start - waiting. */ + mutex_enter(&block->mutex); - mutex_exit(&(buf_pool->mutex)); + if (buf_flush_ready_for_flush(block, flush_type) + && (i == offset || block->buf_fix_count == 0)) { + /* We only try to flush those + neighbors != offset where the buf fix count is + zero, as we then know that we probably can + latch the page without a semaphore wait. + Semaphore waits are expensive because we must + flush the doublewrite buffer before we start + waiting. */ - /* Note: as we release the buf_pool mutex above, in - buf_flush_try_page we cannot be sure the page is still - in a flushable state: therefore we check it again - inside that function. */ + mutex_exit(&block->mutex); - count += buf_flush_try_page(space, i, flush_type); + mutex_exit(&(buf_pool->mutex)); - mutex_enter(&(buf_pool->mutex)); + /* Note: as we release the buf_pool mutex + above, in buf_flush_try_page we cannot be sure + the page is still in a flushable state: + therefore we check it again inside that + function. */ + + count += buf_flush_try_page(space, i, + flush_type); + + mutex_enter(&(buf_pool->mutex)); + } else { + mutex_exit(&block->mutex); + } } } @@ -848,12 +875,15 @@ buf_flush_batch( while ((block != NULL) && !found) { ut_a(block->state == BUF_BLOCK_FILE_PAGE); + mutex_enter(&block->mutex); + if (buf_flush_ready_for_flush(block, flush_type)) { found = TRUE; space = block->space; offset = block->offset; + mutex_exit(&block->mutex); mutex_exit(&(buf_pool->mutex)); old_page_count = page_count; @@ -871,10 +901,14 @@ buf_flush_batch( } else if (flush_type == BUF_FLUSH_LRU) { + mutex_exit(&block->mutex); + block = UT_LIST_GET_PREV(LRU, block); } else { ut_ad(flush_type == BUF_FLUSH_LIST); + mutex_exit(&block->mutex); + block = UT_LIST_GET_PREV(flush_list, block); } } @@ -951,10 +985,14 @@ buf_flush_LRU_recommendation(void) + BUF_FLUSH_EXTRA_MARGIN) && (distance < BUF_LRU_FREE_SEARCH_LEN)) { + mutex_enter(&block->mutex); + if (buf_flush_ready_for_replace(block)) { n_replaceable++; } + mutex_exit(&block->mutex); + distance++; block = UT_LIST_GET_PREV(LRU, block); diff --git a/innobase/buf/buf0lru.c b/innobase/buf/buf0lru.c index 05e92933edf..681b4d81462 100644 --- a/innobase/buf/buf0lru.c +++ b/innobase/buf/buf0lru.c @@ -86,6 +86,9 @@ scan_again: block = UT_LIST_GET_LAST(buf_pool->LRU); while (block != NULL) { + + mutex_enter(&block->mutex); + ut_a(block->state == BUF_BLOCK_FILE_PAGE); if (block->space == id @@ -112,6 +115,8 @@ scan_again: if (block->is_hashed) { page_no = block->offset; + mutex_exit(&block->mutex); + mutex_exit(&(buf_pool->mutex)); /* Note that the following call will acquire @@ -138,6 +143,7 @@ scan_again: buf_LRU_block_free_hashed_page(block); } next_page: + mutex_exit(&block->mutex); block = UT_LIST_GET_PREV(LRU, block); } @@ -211,6 +217,9 @@ buf_LRU_search_and_free_block( while (block != NULL) { ut_a(block->in_LRU_list); + + mutex_enter(&block->mutex); + if (buf_flush_ready_for_replace(block)) { if (buf_debug_prints) { @@ -223,6 +232,7 @@ buf_LRU_search_and_free_block( buf_LRU_block_remove_hashed_page(block); mutex_exit(&(buf_pool->mutex)); + mutex_exit(&block->mutex); /* Remove possible adaptive hash index built on the page; in the case of AWE the block may not have a @@ -231,15 +241,21 @@ buf_LRU_search_and_free_block( if (block->frame) { btr_search_drop_page_hash_index(block->frame); } - mutex_enter(&(buf_pool->mutex)); ut_a(block->buf_fix_count == 0); + mutex_enter(&(buf_pool->mutex)); + mutex_enter(&block->mutex); + buf_LRU_block_free_hashed_page(block); freed = TRUE; + mutex_exit(&block->mutex); break; } + + mutex_exit(&block->mutex); + block = UT_LIST_GET_PREV(LRU, block); distance++; @@ -413,8 +429,12 @@ loop: } } + mutex_enter(&block->mutex); + block->state = BUF_BLOCK_READY_FOR_USE; + mutex_exit(&block->mutex); + mutex_exit(&(buf_pool->mutex)); if (started_monitor) { @@ -815,6 +835,7 @@ buf_LRU_block_free_non_file_page( { #ifdef UNIV_SYNC_DEBUG ut_ad(mutex_own(&(buf_pool->mutex))); + ut_ad(mutex_own(&block->mutex)); #endif /* UNIV_SYNC_DEBUG */ ut_ad(block); @@ -854,6 +875,7 @@ buf_LRU_block_remove_hashed_page( { #ifdef UNIV_SYNC_DEBUG ut_ad(mutex_own(&(buf_pool->mutex))); + ut_ad(mutex_own(&block->mutex)); #endif /* UNIV_SYNC_DEBUG */ ut_ad(block); @@ -911,6 +933,7 @@ buf_LRU_block_free_hashed_page( { #ifdef UNIV_SYNC_DEBUG ut_ad(mutex_own(&(buf_pool->mutex))); + ut_ad(mutex_own(&block->mutex)); #endif /* UNIV_SYNC_DEBUG */ ut_a(block->state == BUF_BLOCK_REMOVE_HASH); diff --git a/innobase/include/buf0buf.h b/innobase/include/buf0buf.h index 53599d03c73..f9c69581476 100644 --- a/innobase/include/buf0buf.h +++ b/innobase/include/buf0buf.h @@ -455,8 +455,8 @@ Gets the mutex number protecting the page record lock hash chain in the lock table. */ UNIV_INLINE mutex_t* -buf_frame_get_lock_mutex( -/*=====================*/ +buf_frame_get_mutex( +/*================*/ /* out: mutex */ byte* ptr); /* in: pointer to within a buffer frame */ /*********************************************************************** @@ -699,7 +699,10 @@ struct buf_block_struct{ ulint magic_n; /* magic number to check */ ulint state; /* state of the control block: - BUF_BLOCK_NOT_USED, ... */ + BUF_BLOCK_NOT_USED, ...; changing + this is only allowed when a thread + has BOTH the buffer pool mutex AND + block->mutex locked */ byte* frame; /* pointer to buffer frame which is of size UNIV_PAGE_SIZE, and aligned to an address divisible by @@ -717,8 +720,12 @@ struct buf_block_struct{ ulint offset; /* page number within the space */ ulint lock_hash_val; /* hashed value of the page address in the record lock hash table */ - mutex_t* lock_mutex; /* mutex protecting the chain in the - record lock hash table */ + mutex_t mutex; /* mutex protecting this block: + state (also protected by the buffer + pool mutex), io_fix, buf_fix_count, + and accessed; we introduce this new + mutex in InnoDB-5.1 to relieve + contention on the buffer pool mutex */ rw_lock_t lock; /* read-write lock of the buffer frame */ buf_block_t* hash; /* node used in chaining to the page @@ -774,20 +781,27 @@ struct buf_block_struct{ in heuristic algorithms, because of the possibility of a wrap-around! */ ulint freed_page_clock;/* the value of freed_page_clock - buffer pool when this block was - last time put to the head of the - LRU list */ + of the buffer pool when this block was + the last time put to the head of the + LRU list; a thread is allowed to + read this for heuristic purposes + without holding any mutex or latch */ ibool old; /* TRUE if the block is in the old blocks in the LRU list */ ibool accessed; /* TRUE if the page has been accessed while in the buffer pool: read-ahead may read in pages which have not been - accessed yet */ + accessed yet; this is protected by + block->mutex; a thread is allowed to + read this for heuristic purposes + without holding any mutex or latch */ ulint buf_fix_count; /* count of how manyfold this block - is currently bufferfixed */ + is currently bufferfixed; this is + protected by block->mutex */ ulint io_fix; /* if a read is pending to the frame, io_fix is BUF_IO_READ, in the case - of a write BUF_IO_WRITE, otherwise 0 */ + of a write BUF_IO_WRITE, otherwise 0; + this is protected by block->mutex */ /* 4. Optimistic search field */ dulint modify_clock; /* this clock is incremented every @@ -940,7 +954,9 @@ struct buf_pool_struct{ number of buffer blocks removed from the end of the LRU list; NOTE that this counter may wrap around at 4 - billion! */ + billion! A thread is allowed to + read this for heuristic purposes + without holding any mutex or latch */ ulint LRU_flush_ended;/* when an LRU flush ends for a page, this is incremented by one; this is set to zero when a buffer block is diff --git a/innobase/include/buf0buf.ic b/innobase/include/buf0buf.ic index 681a0ef000a..8a18b2fb0fa 100644 --- a/innobase/include/buf0buf.ic +++ b/innobase/include/buf0buf.ic @@ -333,8 +333,8 @@ Gets the mutex number protecting the page record lock hash chain in the lock table. */ UNIV_INLINE mutex_t* -buf_frame_get_lock_mutex( -/*=====================*/ +buf_frame_get_mutex( +/*================*/ /* out: mutex */ byte* ptr) /* in: pointer to within a buffer frame */ { @@ -342,7 +342,7 @@ buf_frame_get_lock_mutex( block = buf_block_align(ptr); - return(block->lock_mutex); + return(&block->mutex); } /************************************************************************* @@ -521,6 +521,7 @@ buf_block_buf_fix_inc_debug( ret = rw_lock_s_lock_func_nowait(&(block->debug_latch), file, line); ut_ad(ret == TRUE); + ut_ad(mutex_own(&block->mutex)); #endif block->buf_fix_count++; } @@ -533,6 +534,9 @@ buf_block_buf_fix_inc( /*==================*/ buf_block_t* block) /* in: block to bufferfix */ { +#ifdef UNIV_SYNC_DEBUG + ut_ad(mutex_own(&block->mutex)); +#endif block->buf_fix_count++; } #endif /* UNIV_SYNC_DEBUG */ @@ -627,23 +631,24 @@ buf_page_release( ut_ad(block); - mutex_enter_fast(&(buf_pool->mutex)); - ut_a(block->state == BUF_BLOCK_FILE_PAGE); ut_a(block->buf_fix_count > 0); if (rw_latch == RW_X_LATCH && mtr->modifications) { - + mutex_enter(&buf_pool->mutex); buf_flush_note_modification(block, mtr); + mutex_exit(&buf_pool->mutex); } + mutex_enter(&block->mutex); + #ifdef UNIV_SYNC_DEBUG rw_lock_s_unlock(&(block->debug_latch)); #endif buf_fix_count = block->buf_fix_count; block->buf_fix_count = buf_fix_count - 1; - mutex_exit(&(buf_pool->mutex)); + mutex_exit(&block->mutex); if (rw_latch == RW_S_LATCH) { rw_lock_s_unlock(&(block->lock)); diff --git a/innobase/include/sync0arr.h b/innobase/include/sync0arr.h index fecd910683e..ba712d14aad 100644 --- a/innobase/include/sync0arr.h +++ b/innobase/include/sync0arr.h @@ -75,17 +75,12 @@ sync_array_free_cell( sync_array_t* arr, /* in: wait array */ ulint index); /* in: index of the cell in array */ /************************************************************************** -Looks for the cells in the wait array which refer -to the wait object specified, -and sets their corresponding events to the signaled state. In this -way releases the threads waiting for the object to contend for the object. -It is possible that no such cell is found, in which case does nothing. */ +Note that one of the wait objects was signalled. */ void -sync_array_signal_object( -/*=====================*/ - sync_array_t* arr, /* in: wait array */ - void* object);/* in: wait object */ +sync_array_object_signalled( +/*========================*/ + sync_array_t* arr); /* in: wait array */ /************************************************************************** If the wakeup algorithm does not work perfectly at semaphore relases, this function will do the waking (see the comment in mutex_exit). This diff --git a/innobase/include/sync0rw.h b/innobase/include/sync0rw.h index 9a988a03e92..c59608e0916 100644 --- a/innobase/include/sync0rw.h +++ b/innobase/include/sync0rw.h @@ -410,6 +410,7 @@ blocked by readers, a writer may queue for the lock by setting the writer field. Then no new readers are allowed in. */ struct rw_lock_struct { + os_event_t event; /* Used by sync0arr.c for thread queueing */ ulint reader_count; /* Number of readers who have locked this lock in the shared mode */ ulint writer; /* This field is set to RW_LOCK_EX if there diff --git a/innobase/include/sync0rw.ic b/innobase/include/sync0rw.ic index 3a92100ba01..92a75059ee3 100644 --- a/innobase/include/sync0rw.ic +++ b/innobase/include/sync0rw.ic @@ -380,7 +380,8 @@ rw_lock_s_unlock_func( mutex_exit(mutex); if (sg == TRUE) { - sync_array_signal_object(sync_primary_wait_array, lock); + os_event_set(lock->event); + sync_array_object_signalled(sync_primary_wait_array); } ut_ad(rw_lock_validate(lock)); @@ -459,7 +460,8 @@ rw_lock_x_unlock_func( mutex_exit(&(lock->mutex)); if (sg == TRUE) { - sync_array_signal_object(sync_primary_wait_array, lock); + os_event_set(lock->event); + sync_array_object_signalled(sync_primary_wait_array); } ut_ad(rw_lock_validate(lock)); diff --git a/innobase/include/sync0sync.h b/innobase/include/sync0sync.h index 8e0ec715b12..1b008c69d3c 100644 --- a/innobase/include/sync0sync.h +++ b/innobase/include/sync0sync.h @@ -447,6 +447,7 @@ Do not use its fields directly! The structure used in the spin lock implementation of a mutual exclusion semaphore. */ struct mutex_struct { + os_event_t event; /* Used by sync0arr.c for the wait queue */ ulint lock_word; /* This ulint is the target of the atomic test-and-set instruction in Win32 */ #if !defined(_WIN32) || !defined(UNIV_CAN_USE_X86_ASSEMBLER) diff --git a/innobase/os/os0sync.c b/innobase/os/os0sync.c index 4ad9473fe66..bf82f69023d 100644 --- a/innobase/os/os0sync.c +++ b/innobase/os/os0sync.c @@ -21,6 +21,7 @@ Created 9/6/1995 Heikki Tuuri /* Type definition for an operating system mutex struct */ struct os_mutex_struct{ + os_event_t event; /* Used by sync0arr.c for queing threads */ void* handle; /* OS handle to mutex */ ulint count; /* we use this counter to check that the same thread does not @@ -35,6 +36,7 @@ struct os_mutex_struct{ /* Mutex protecting counts and the lists of OS mutexes and events */ os_mutex_t os_sync_mutex; ibool os_sync_mutex_inited = FALSE; +ibool os_sync_free_called = FALSE; /* This is incremented by 1 in os_thread_create and decremented by 1 in os_thread_exit */ @@ -50,6 +52,10 @@ ulint os_event_count = 0; ulint os_mutex_count = 0; ulint os_fast_mutex_count = 0; +/* Because a mutex is embedded inside an event and there is an +event embedded inside a mutex, on free, this generates a recursive call. +This version of the free event function doesn't acquire the global lock */ +static void os_event_free_internal(os_event_t event); /************************************************************* Initializes global event and OS 'slow' mutex lists. */ @@ -76,6 +82,7 @@ os_sync_free(void) os_event_t event; os_mutex_t mutex; + os_sync_free_called = TRUE; event = UT_LIST_GET_FIRST(os_event_list); while (event) { @@ -99,6 +106,7 @@ os_sync_free(void) mutex = UT_LIST_GET_FIRST(os_mutex_list); } + os_sync_free_called = FALSE; } /************************************************************* @@ -146,14 +154,21 @@ os_event_create( event->signal_count = 0; #endif /* __WIN__ */ - /* Put to the list of events */ - os_mutex_enter(os_sync_mutex); + /* The os_sync_mutex can be NULL because during startup an event + can be created [ because it's embedded in the mutex/rwlock ] before + this module has been initialized */ + if (os_sync_mutex != NULL) { + os_mutex_enter(os_sync_mutex); + } + /* Put to the list of events */ UT_LIST_ADD_FIRST(os_event_list, os_event_list, event); os_event_count++; - os_mutex_exit(os_sync_mutex); + if (os_sync_mutex != NULL) { + os_mutex_exit(os_sync_mutex); + } return(event); } @@ -255,6 +270,35 @@ os_event_reset( #endif } +/************************************************************** +Frees an event object, without acquiring the global lock. */ +static +void +os_event_free_internal( +/*===================*/ + os_event_t event) /* in: event to free */ +{ +#ifdef __WIN__ + ut_a(event); + + ut_a(CloseHandle(event->handle)); +#else + ut_a(event); + + /* This is to avoid freeing the mutex twice */ + os_fast_mutex_free(&(event->os_mutex)); + + ut_a(0 == pthread_cond_destroy(&(event->cond_var))); +#endif + /* Remove from the list of events */ + + UT_LIST_REMOVE(os_event_list, os_event_list, event); + + os_event_count--; + + ut_free(event); +} + /************************************************************** Frees an event object. */ @@ -456,6 +500,7 @@ os_mutex_create( mutex_str->handle = mutex; mutex_str->count = 0; + mutex_str->event = os_event_create(NULL); if (os_sync_mutex_inited) { /* When creating os_sync_mutex itself we cannot reserve it */ @@ -532,6 +577,10 @@ os_mutex_free( { ut_a(mutex); + if (!os_sync_free_called) { + os_event_free_internal(mutex->event); + } + if (os_sync_mutex_inited) { os_mutex_enter(os_sync_mutex); } diff --git a/innobase/sync/sync0arr.c b/innobase/sync/sync0arr.c index 198ef49ca9f..64f9310bad3 100644 --- a/innobase/sync/sync0arr.c +++ b/innobase/sync/sync0arr.c @@ -62,9 +62,6 @@ struct sync_cell_struct { ibool waiting; /* TRUE if the thread has already called sync_array_event_wait on this cell */ - ibool event_set; /* TRUE if the event is set */ - os_event_t event; /* operating system event - semaphore handle */ time_t reservation_time;/* time when the thread reserved the wait cell */ }; @@ -218,10 +215,7 @@ sync_array_create( for (i = 0; i < n_cells; i++) { cell = sync_array_get_nth_cell(arr, i); cell->wait_object = NULL; - - /* Create an operating system event semaphore with no name */ - cell->event = os_event_create(NULL); - cell->event_set = FALSE; /* it is created in reset state */ + cell->waiting = FALSE; } return(arr); @@ -235,19 +229,12 @@ sync_array_free( /*============*/ sync_array_t* arr) /* in, own: sync wait array */ { - ulint i; - sync_cell_t* cell; ulint protection; ut_a(arr->n_reserved == 0); sync_array_validate(arr); - for (i = 0; i < arr->n_cells; i++) { - cell = sync_array_get_nth_cell(arr, i); - os_event_free(cell->event); - } - protection = arr->protection; /* Release the mutex protecting the wait array complex */ @@ -292,28 +279,20 @@ sync_array_validate( sync_array_exit(arr); } -/*********************************************************************** -Puts the cell event in set state. */ -static -void -sync_cell_event_set( -/*================*/ - sync_cell_t* cell) /* in: array cell */ -{ - os_event_set(cell->event); - cell->event_set = TRUE; -} - /*********************************************************************** Puts the cell event in reset state. */ static void sync_cell_event_reset( /*==================*/ - sync_cell_t* cell) /* in: array cell */ + ulint type, /* in: lock type mutex/rw_lock */ + void* object) /* in: the rw_lock/mutex object */ { - os_event_reset(cell->event); - cell->event_set = FALSE; + if (type == SYNC_MUTEX) { + os_event_reset(((mutex_t *) object)->event); + } else { + os_event_reset(((rw_lock_t *) object)->event); + } } /********************************************************************** @@ -346,14 +325,7 @@ sync_array_reserve_cell( if (cell->wait_object == NULL) { - /* Make sure the event is reset */ - if (cell->event_set) { - sync_cell_event_reset(cell); - } - - cell->reservation_time = time(NULL); - cell->thread = os_thread_get_curr_id(); - + cell->waiting = FALSE; cell->wait_object = object; if (type == SYNC_MUTEX) { @@ -363,7 +335,6 @@ sync_array_reserve_cell( } cell->request_type = type; - cell->waiting = FALSE; cell->file = file; cell->line = line; @@ -373,6 +344,13 @@ sync_array_reserve_cell( *index = i; sync_array_exit(arr); + + /* Make sure the event is reset */ + sync_cell_event_reset(type, object); + + cell->reservation_time = time(NULL); + + cell->thread = os_thread_get_curr_id(); return; } @@ -408,7 +386,12 @@ sync_array_wait_event( ut_a(!cell->waiting); ut_ad(os_thread_get_curr_id() == cell->thread); - event = cell->event; + if (cell->request_type == SYNC_MUTEX) { + event = ((mutex_t*) cell->wait_object)->event; + } else { + event = ((rw_lock_t*) cell->wait_object)->event; + } + cell->waiting = TRUE; #ifdef UNIV_SYNC_DEBUG @@ -510,10 +493,6 @@ sync_array_cell_print( if (!cell->waiting) { fputs("wait has ended\n", file); } - - if (cell->event_set) { - fputs("wait is ending\n", file); - } } #ifdef UNIV_SYNC_DEBUG @@ -623,7 +602,7 @@ sync_array_detect_deadlock( depth++; - if (cell->event_set || !cell->waiting) { + if (!cell->waiting) { return(FALSE); /* No deadlock here */ } @@ -802,6 +781,7 @@ sync_array_free_cell( ut_a(cell->wait_object != NULL); + cell->waiting = FALSE; cell->wait_object = NULL; ut_a(arr->n_reserved > 0); @@ -811,44 +791,17 @@ sync_array_free_cell( } /************************************************************************** -Looks for the cells in the wait array which refer to the wait object -specified, and sets their corresponding events to the signaled state. In this -way releases the threads waiting for the object to contend for the object. -It is possible that no such cell is found, in which case does nothing. */ +Increments the signalled count. */ void -sync_array_signal_object( -/*=====================*/ - sync_array_t* arr, /* in: wait array */ - void* object) /* in: wait object */ +sync_array_object_signalled( +/*========================*/ + sync_array_t* arr) /* in: wait array */ { - sync_cell_t* cell; - ulint count; - ulint i; - sync_array_enter(arr); arr->sg_count++; - i = 0; - count = 0; - - while (count < arr->n_reserved) { - - cell = sync_array_get_nth_cell(arr, i); - - if (cell->wait_object != NULL) { - - count++; - if (cell->wait_object == object) { - - sync_cell_event_set(cell); - } - } - - i++; - } - sync_array_exit(arr); } @@ -881,7 +834,17 @@ sync_arr_wake_threads_if_sema_free(void) if (sync_arr_cell_can_wake_up(cell)) { - sync_cell_event_set(cell); + if (cell->request_type == SYNC_MUTEX) { + mutex_t* mutex; + + mutex = cell->wait_object; + os_event_set(mutex->event); + } else { + rw_lock_t* lock; + + lock = cell->wait_object; + os_event_set(lock->event); + } } } @@ -911,7 +874,7 @@ sync_array_print_long_waits(void) cell = sync_array_get_nth_cell(sync_primary_wait_array, i); - if (cell->wait_object != NULL + if (cell->wait_object != NULL && cell->waiting && difftime(time(NULL), cell->reservation_time) > 240) { fputs("InnoDB: Warning: a long semaphore wait:\n", stderr); @@ -919,7 +882,7 @@ sync_array_print_long_waits(void) noticed = TRUE; } - if (cell->wait_object != NULL + if (cell->wait_object != NULL && cell->waiting && difftime(time(NULL), cell->reservation_time) > fatal_timeout) { fatal = TRUE; diff --git a/innobase/sync/sync0rw.c b/innobase/sync/sync0rw.c index 77757685208..384c2e6dfad 100644 --- a/innobase/sync/sync0rw.c +++ b/innobase/sync/sync0rw.c @@ -123,6 +123,7 @@ rw_lock_create_func( lock->last_x_file_name = "not yet reserved"; lock->last_s_line = 0; lock->last_x_line = 0; + lock->event = os_event_create(NULL); mutex_enter(&rw_lock_list_mutex); @@ -158,6 +159,7 @@ rw_lock_free( mutex_free(rw_lock_get_mutex(lock)); mutex_enter(&rw_lock_list_mutex); + os_event_free(lock->event); if (UT_LIST_GET_PREV(list, lock)) { ut_a(UT_LIST_GET_PREV(list, lock)->magic_n == RW_LOCK_MAGIC_N); diff --git a/innobase/sync/sync0sync.c b/innobase/sync/sync0sync.c index 86306e49cac..468789c120d 100644 --- a/innobase/sync/sync0sync.c +++ b/innobase/sync/sync0sync.c @@ -210,6 +210,7 @@ mutex_create_func( os_fast_mutex_init(&(mutex->os_fast_mutex)); mutex->lock_word = 0; #endif + mutex->event = os_event_create(NULL); mutex_set_waiters(mutex, 0); mutex->magic_n = MUTEX_MAGIC_N; #ifdef UNIV_SYNC_DEBUG @@ -275,6 +276,8 @@ mutex_free( mutex_exit(&mutex_list_mutex); } + os_event_free(mutex->event); + #if !defined(_WIN32) || !defined(UNIV_CAN_USE_X86_ASSEMBLER) os_fast_mutex_free(&(mutex->os_fast_mutex)); #endif @@ -498,8 +501,8 @@ mutex_signal_object( /* The memory order of resetting the waiters field and signaling the object is important. See LEMMA 1 above. */ - - sync_array_signal_object(sync_primary_wait_array, mutex); + os_event_set(mutex->event); + sync_array_object_signalled(sync_primary_wait_array); } #ifdef UNIV_SYNC_DEBUG @@ -1047,6 +1050,7 @@ sync_thread_add_level( ut_a(sync_thread_levels_g(array, SYNC_PURGE_SYS)); } else if (level == SYNC_TREE_NODE) { ut_a(sync_thread_levels_contain(array, SYNC_INDEX_TREE) + || sync_thread_levels_contain(array, SYNC_DICT_OPERATION) || sync_thread_levels_g(array, SYNC_TREE_NODE - 1)); } else if (level == SYNC_TREE_NODE_FROM_HASH) { ut_a(1); From 4a5eb6bd17c56fe76c5cbfd216ea4624d979614f Mon Sep 17 00:00:00 2001 From: "serg@janus.mylan" <> Date: Wed, 19 Dec 2007 21:31:04 +0100 Subject: [PATCH 2/8] correct invalid values in SET GLOBAL var=DEFAULT bug#33382 --- mysql-test/r/bdb_notembedded.result | 35 -------------------------- mysql-test/r/variables.result | 2 +- mysql-test/t/bdb_notembedded.test | 38 ----------------------------- mysql-test/t/variables.test | 2 +- sql/set_var.cc | 26 ++++++++++++++------ 5 files changed, 21 insertions(+), 82 deletions(-) delete mode 100644 mysql-test/r/bdb_notembedded.result delete mode 100644 mysql-test/t/bdb_notembedded.test diff --git a/mysql-test/r/bdb_notembedded.result b/mysql-test/r/bdb_notembedded.result deleted file mode 100644 index 14cb5fad915..00000000000 --- a/mysql-test/r/bdb_notembedded.result +++ /dev/null @@ -1,35 +0,0 @@ -set autocommit=1; -reset master; -create table bug16206 (a int); -insert into bug16206 values(1); -start transaction; -insert into bug16206 values(2); -commit; -show binlog events; -Log_name Pos Event_type Server_id End_log_pos Info -f n Format_desc 1 n Server ver: VERSION, Binlog ver: 4 -f n Query 1 n use `test`; create table bug16206 (a int) -f n Query 1 n use `test`; insert into bug16206 values(1) -f n Query 1 n use `test`; insert into bug16206 values(2) -drop table bug16206; -reset master; -create table bug16206 (a int) engine= bdb; -insert into bug16206 values(0); -insert into bug16206 values(1); -start transaction; -insert into bug16206 values(2); -commit; -insert into bug16206 values(3); -show binlog events; -Log_name Pos Event_type Server_id End_log_pos Info -f n Format_desc 1 n Server ver: VERSION, Binlog ver: 4 -f n Query 1 n use `test`; create table bug16206 (a int) engine= bdb -f n Query 1 n use `test`; insert into bug16206 values(0) -f n Query 1 n use `test`; insert into bug16206 values(1) -f n Query 1 n use `test`; BEGIN -f n Query 1 n use `test`; insert into bug16206 values(2) -f n Query 1 n use `test`; COMMIT -f n Query 1 n use `test`; insert into bug16206 values(3) -drop table bug16206; -set autocommit=0; -End of 5.0 tests diff --git a/mysql-test/r/variables.result b/mysql-test/r/variables.result index 9c360ef4ab3..376a8ffa38e 100644 --- a/mysql-test/r/variables.result +++ b/mysql-test/r/variables.result @@ -182,7 +182,7 @@ show global variables like 'myisam_max_sort_file_size'; Variable_name Value myisam_max_sort_file_size 1048576 set GLOBAL myisam_max_sort_file_size=default; -show variables like 'myisam_max_sort_file_size'; +show global variables like 'myisam_max_sort_file_size'; Variable_name Value myisam_max_sort_file_size FILE_SIZE set global net_retry_count=10, session net_retry_count=10; diff --git a/mysql-test/t/bdb_notembedded.test b/mysql-test/t/bdb_notembedded.test deleted file mode 100644 index 24e64ebbfb2..00000000000 --- a/mysql-test/t/bdb_notembedded.test +++ /dev/null @@ -1,38 +0,0 @@ --- source include/not_embedded.inc --- source include/have_bdb.inc - -# -# Bug #16206: Superfluous COMMIT event in binlog when updating BDB in autocommit mode -# -set autocommit=1; - -let $VERSION=`select version()`; - -reset master; -create table bug16206 (a int); -insert into bug16206 values(1); -start transaction; -insert into bug16206 values(2); -commit; ---replace_result $VERSION VERSION ---replace_column 1 f 2 n 5 n -show binlog events; -drop table bug16206; - -reset master; -create table bug16206 (a int) engine= bdb; -insert into bug16206 values(0); -insert into bug16206 values(1); -start transaction; -insert into bug16206 values(2); -commit; -insert into bug16206 values(3); ---replace_result $VERSION VERSION ---replace_column 1 f 2 n 5 n -show binlog events; -drop table bug16206; - -set autocommit=0; - - ---echo End of 5.0 tests diff --git a/mysql-test/t/variables.test b/mysql-test/t/variables.test index c86e7dfa7f3..1748b63ceb9 100644 --- a/mysql-test/t/variables.test +++ b/mysql-test/t/variables.test @@ -127,7 +127,7 @@ set GLOBAL myisam_max_sort_file_size=2000000; show global variables like 'myisam_max_sort_file_size'; set GLOBAL myisam_max_sort_file_size=default; --replace_result 9223372036853727232 FILE_SIZE 2146435072 FILE_SIZE -show variables like 'myisam_max_sort_file_size'; +show global variables like 'myisam_max_sort_file_size'; set global net_retry_count=10, session net_retry_count=10; set global net_buffer_length=1024, net_write_timeout=200, net_read_timeout=300; diff --git a/sql/set_var.cc b/sql/set_var.cc index d0362edaa29..4cb6b836c39 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -113,8 +113,7 @@ static int check_max_delayed_threads(THD *thd, set_var *var); static void fix_thd_mem_root(THD *thd, enum_var_type type); static void fix_trans_mem_root(THD *thd, enum_var_type type); static void fix_server_id(THD *thd, enum_var_type type); -static ulonglong fix_unsigned(THD *thd, ulonglong num, - const struct my_option *option_limits); +static ulonglong fix_unsigned(THD *, ulonglong, const struct my_option *); static bool get_unsigned(THD *thd, set_var *var); static void throw_bounds_warning(THD *thd, const char *name, ulonglong num); static KEY_CACHE *create_key_cache(const char *name, uint length); @@ -1524,8 +1523,10 @@ bool sys_var_long_ptr_global::update(THD *thd, set_var *var) void sys_var_long_ptr_global::set_default(THD *thd, enum_var_type type) { + bool not_used; pthread_mutex_lock(guard); - *value= (ulong) option_limits->def_value; + *value= (ulong) getopt_ull_limit_value((ulong) option_limits->def_value, + option_limits, ¬_used); pthread_mutex_unlock(guard); } @@ -1545,8 +1546,10 @@ bool sys_var_ulonglong_ptr::update(THD *thd, set_var *var) void sys_var_ulonglong_ptr::set_default(THD *thd, enum_var_type type) { + bool not_used; pthread_mutex_lock(&LOCK_global_system_variables); - *value= (ulonglong) option_limits->def_value; + *value= getopt_ull_limit_value((ulonglong) option_limits->def_value, + option_limits, ¬_used); pthread_mutex_unlock(&LOCK_global_system_variables); } @@ -1616,8 +1619,11 @@ void sys_var_thd_ulong::set_default(THD *thd, enum_var_type type) { if (type == OPT_GLOBAL) { + bool not_used; /* We will not come here if option_limits is not set */ - global_system_variables.*offset= (ulong) option_limits->def_value; + global_system_variables.*offset= + getopt_ull_limit_value((ulong) option_limits->def_value, + option_limits, ¬_used); } else thd->variables.*offset= global_system_variables.*offset; @@ -1660,9 +1666,12 @@ void sys_var_thd_ha_rows::set_default(THD *thd, enum_var_type type) { if (type == OPT_GLOBAL) { + bool not_used; /* We will not come here if option_limits is not set */ pthread_mutex_lock(&LOCK_global_system_variables); - global_system_variables.*offset= (ha_rows) option_limits->def_value; + global_system_variables.*offset= + (ha_rows) getopt_ull_limit_value((ha_rows) option_limits->def_value, + option_limits, ¬_used); pthread_mutex_unlock(&LOCK_global_system_variables); } else @@ -1709,8 +1718,11 @@ void sys_var_thd_ulonglong::set_default(THD *thd, enum_var_type type) { if (type == OPT_GLOBAL) { + bool not_used; pthread_mutex_lock(&LOCK_global_system_variables); - global_system_variables.*offset= (ulonglong) option_limits->def_value; + global_system_variables.*offset= + getopt_ull_limit_value((ulonglong) option_limits->def_value, + option_limits, ¬_used); pthread_mutex_unlock(&LOCK_global_system_variables); } else From 97754ffae7be102823a7467be096b753000298df Mon Sep 17 00:00:00 2001 From: "serg@janus.mylan" <> Date: Fri, 21 Dec 2007 10:31:47 +0100 Subject: [PATCH 3/8] warning on windows --- sql/set_var.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sql/set_var.cc b/sql/set_var.cc index 4cb6b836c39..c78df4d8918 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -1622,8 +1622,8 @@ void sys_var_thd_ulong::set_default(THD *thd, enum_var_type type) bool not_used; /* We will not come here if option_limits is not set */ global_system_variables.*offset= - getopt_ull_limit_value((ulong) option_limits->def_value, - option_limits, ¬_used); + (ulonglong) getopt_ull_limit_value((ulong) option_limits->def_value, + option_limits, ¬_used); } else thd->variables.*offset= global_system_variables.*offset; From baf53c8524f87d8a485433b1d705b8958b47fb07 Mon Sep 17 00:00:00 2001 From: "serg@janus.mylan" <> Date: Fri, 21 Dec 2007 11:28:34 +0100 Subject: [PATCH 4/8] cast corrected --- sql/set_var.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sql/set_var.cc b/sql/set_var.cc index c78df4d8918..fe57b46745a 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -1622,8 +1622,8 @@ void sys_var_thd_ulong::set_default(THD *thd, enum_var_type type) bool not_used; /* We will not come here if option_limits is not set */ global_system_variables.*offset= - (ulonglong) getopt_ull_limit_value((ulong) option_limits->def_value, - option_limits, ¬_used); + (ulong) getopt_ull_limit_value((ulong) option_limits->def_value, + option_limits, ¬_used); } else thd->variables.*offset= global_system_variables.*offset; From c13d726f5d73de5e08e30982742b84c2e94a5efd Mon Sep 17 00:00:00 2001 From: "cmiller@zippy.cornsilk.net" <> Date: Wed, 23 Jan 2008 11:34:08 -0500 Subject: [PATCH 5/8] Bug#27427: resolveip fails on hostnames with a leading digit Patch by Kasper Dupont. No CLA required for this size of patch. "resolveip" program produces incorrect result if given a hostname starting with a digit. Someone seems to have thought that names can not have digits at the beginning. Instead, use the resolver library to work out the rules of hostnames, as it will undoubtedly be better at it than we are. --- configure.in | 2 ++ extra/resolveip.c | 6 ++++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/configure.in b/configure.in index 63d3976aa3c..cf75aaa38f3 100644 --- a/configure.in +++ b/configure.in @@ -838,6 +838,8 @@ AC_CHECK_FUNC(p2open, , AC_CHECK_LIB(gen, p2open)) AC_CHECK_FUNC(bind, , AC_CHECK_LIB(bind, bind)) # Check if crypt() exists in libc or libcrypt, sets LIBS if needed AC_SEARCH_LIBS(crypt, crypt, AC_DEFINE(HAVE_CRYPT, 1, [crypt])) +# See if we need a library for address lookup. +AC_SEARCH_LIBS(inet_aton, [socket nsl resolv]) # For the sched_yield() function on Solaris AC_CHECK_FUNC(sched_yield, , AC_CHECK_LIB(posix4, sched_yield)) diff --git a/extra/resolveip.c b/extra/resolveip.c index 1061cafe380..c613f6a8cb6 100644 --- a/extra/resolveip.c +++ b/extra/resolveip.c @@ -116,11 +116,13 @@ int main(int argc, char **argv) while (argc--) { + struct in_addr addr; ip = *argv++; - if (my_isdigit(&my_charset_latin1,ip[0])) + /* Not compatible with IPv6! Probably should use getnameinfo(). */ + if (inet_aton(ip, &addr) != 0) { - taddr = inet_addr(ip); + taddr= addr.s_addr; if (taddr == htonl(INADDR_BROADCAST)) { puts("Broadcast"); From 71316696a1f23cdc6565a0752aeb6ae63b342bcc Mon Sep 17 00:00:00 2001 From: "cmiller@zippy.cornsilk.net" <> Date: Wed, 23 Jan 2008 11:37:46 -0500 Subject: [PATCH 6/8] Patch contributed by Jocelyn Fournier. CLA received 2007-02-27. Bug#25347: mysqlcheck -A -r doesn't repair table marked as crashed mysqlcheck tests nullness of the engine type to know whether the "table" is a view or not. That also falsely catches tables that are severly damaged. Instead, use SHOW FULL TABLES to test whether a "table" is a view or not. (Don't add new function. Instead, get original data a smarter way.) Make it safe for use against databases before when views appeared. --- client/mysqlcheck.c | 19 ++++++++++++------- mysql-test/r/mysqlcheck.result | 10 ++++++++++ mysql-test/t/mysqlcheck.test | 16 ++++++++++++++++ 3 files changed, 38 insertions(+), 7 deletions(-) diff --git a/client/mysqlcheck.c b/client/mysqlcheck.c index 3b504eb50b0..473e172adf9 100644 --- a/client/mysqlcheck.c +++ b/client/mysqlcheck.c @@ -483,14 +483,17 @@ static int process_all_tables_in_db(char *database) { MYSQL_RES *res; MYSQL_ROW row; + uint num_columns; LINT_INIT(res); if (use_db(database)) return 1; - if (mysql_query(sock, "SHOW TABLE STATUS") || + if (mysql_query(sock, "SHOW /*!50002 FULL*/ TABLES") || !((res= mysql_store_result(sock)))) return 1; + num_columns= mysql_num_fields(res); + if (opt_all_in_1) { /* @@ -513,12 +516,11 @@ static int process_all_tables_in_db(char *database) } for (end = tables + 1; (row = mysql_fetch_row(res)) ;) { - /* Skip tables with an engine of NULL (probably a view). */ - if (row[1]) - { - end= fix_table_name(end, row[0]); - *end++= ','; - } + if ((num_columns == 2) && (strcmp(row[1], "VIEW") == 0)) + continue; + + end= fix_table_name(end, row[0]); + *end++= ','; } *--end = 0; if (tot_length) @@ -531,6 +533,9 @@ static int process_all_tables_in_db(char *database) /* Skip tables with an engine of NULL (probably a view). */ if (row[1]) { + if ((num_columns == 2) && (strcmp(row[1], "VIEW") == 0)) + continue; + handle_request_for_tables(row[0], fixed_name_length(row[0])); } } diff --git a/mysql-test/r/mysqlcheck.result b/mysql-test/r/mysqlcheck.result index f8a28009c42..7c72cfeb889 100644 --- a/mysql-test/r/mysqlcheck.result +++ b/mysql-test/r/mysqlcheck.result @@ -46,4 +46,14 @@ create table `t 1`(a int); test.t 1 OK test.t`1 OK drop table `t``1`, `t 1`; +create database d_bug25347; +use d_bug25347; +create table t_bug25347 (a int); +create view v_bug25347 as select * from t_bug25347; +removing and creating +d_bug25347.t_bug25347 OK +drop view v_bug25347; +drop table t_bug25347; +drop database d_bug25347; +use test; End of 5.0 tests diff --git a/mysql-test/t/mysqlcheck.test b/mysql-test/t/mysqlcheck.test index 04e7b6b4bdb..532e34d1980 100644 --- a/mysql-test/t/mysqlcheck.test +++ b/mysql-test/t/mysqlcheck.test @@ -40,4 +40,20 @@ create table `t 1`(a int); --exec $MYSQL_CHECK --databases test drop table `t``1`, `t 1`; +# +# Bug#25347: mysqlcheck -A -r doesn't repair table marked as crashed +# +create database d_bug25347; +use d_bug25347; +create table t_bug25347 (a int); +create view v_bug25347 as select * from t_bug25347; +--echo removing and creating +--exec rm $MYSQLTEST_VARDIR/master-data/d_bug25347/t_bug25347.MYI; +--exec touch $MYSQLTEST_VARDIR/master-data/d_bug25347/t_bug25347.MYI; +--exec $MYSQL_CHECK --repair --databases d_bug25347 +drop view v_bug25347; +drop table t_bug25347; +drop database d_bug25347; +use test; + --echo End of 5.0 tests From 218627aa33664d6e21bf17953e64a57b446caf90 Mon Sep 17 00:00:00 2001 From: "tsmith@ramayana.hindu.god" <> Date: Fri, 25 Jan 2008 16:00:15 -0700 Subject: [PATCH 7/8] Un-break test case on Windows, for bug #25347 --- mysql-test/t/mysqlcheck.test | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/mysql-test/t/mysqlcheck.test b/mysql-test/t/mysqlcheck.test index 532e34d1980..c2e194fd8f2 100644 --- a/mysql-test/t/mysqlcheck.test +++ b/mysql-test/t/mysqlcheck.test @@ -48,8 +48,9 @@ use d_bug25347; create table t_bug25347 (a int); create view v_bug25347 as select * from t_bug25347; --echo removing and creating ---exec rm $MYSQLTEST_VARDIR/master-data/d_bug25347/t_bug25347.MYI; ---exec touch $MYSQLTEST_VARDIR/master-data/d_bug25347/t_bug25347.MYI; +--remove_file $MYSQLTEST_VARDIR/master-data/d_bug25347/t_bug25347.MYI +--write_file $MYSQLTEST_VARDIR/master-data/d_bug25347/t_bug25347.MYI +EOF --exec $MYSQL_CHECK --repair --databases d_bug25347 drop view v_bug25347; drop table t_bug25347; From 1bf737a1522db56e2596add02aeec7d67642878f Mon Sep 17 00:00:00 2001 From: "tsmith@ramayana.hindu.god" <> Date: Sun, 27 Jan 2008 14:28:50 -0700 Subject: [PATCH 8/8] Fix test case for Bug #25347 so that it actually tests the code fix, and so that it works correctly on Windows. --- mysql-test/r/mysqlcheck.result | 1 + mysql-test/t/mysqlcheck.test | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/mysqlcheck.result b/mysql-test/r/mysqlcheck.result index 7c72cfeb889..8d7a2d41649 100644 --- a/mysql-test/r/mysqlcheck.result +++ b/mysql-test/r/mysqlcheck.result @@ -50,6 +50,7 @@ create database d_bug25347; use d_bug25347; create table t_bug25347 (a int); create view v_bug25347 as select * from t_bug25347; +flush tables; removing and creating d_bug25347.t_bug25347 OK drop view v_bug25347; diff --git a/mysql-test/t/mysqlcheck.test b/mysql-test/t/mysqlcheck.test index c2e194fd8f2..8d5e1a1c4c5 100644 --- a/mysql-test/t/mysqlcheck.test +++ b/mysql-test/t/mysqlcheck.test @@ -47,11 +47,12 @@ create database d_bug25347; use d_bug25347; create table t_bug25347 (a int); create view v_bug25347 as select * from t_bug25347; +flush tables; --echo removing and creating --remove_file $MYSQLTEST_VARDIR/master-data/d_bug25347/t_bug25347.MYI --write_file $MYSQLTEST_VARDIR/master-data/d_bug25347/t_bug25347.MYI EOF ---exec $MYSQL_CHECK --repair --databases d_bug25347 +--exec $MYSQL_CHECK --repair --databases --use-frm d_bug25347 drop view v_bug25347; drop table t_bug25347; drop database d_bug25347;