Commit c12c382f authored by unknown's avatar unknown
Browse files

This ChangeSet must be null-merged to 5.1. Applied innodb-5.0-ss982, -ss998, -ss1003

Fixes:
- Bug #15815: Very poor performance with multiple queries running concurrently
- Bug #22868: 'Thread thrashing' with > 50 concurrent conns under an upd-intensive workloadw
- Bug #23769: Debug assertion failure with innodb_locks_unsafe_for_binlog
- Bug #24089: Race condition in fil_flush_file_spaces()


innobase/buf/buf0buf.c:
  Applied innodb-5.0-ss982, -ss998, -ss1003
  
  Revision r1000:
  branches/5.0: Merge r999 from trunk:
  
  Reduce buffer pool mutex contention under >= 4 big concurrent
  CPU-bound SELECT queries.  (Bug #22868)
  
  Fix: replace the mutex by one mutex protecting the 'flush list'
  (and the free list) and several mutexes protecting portions of the
  buffer pool, where we keep several indivudual LRU lists of pages.
  
  This patch is from Sunny Bains and Heikki Tuuri.
innobase/buf/buf0flu.c:
  Applied innodb-5.0-ss982, -ss998, -ss1003
  
  Revision r1000:
  branches/5.0: Merge r999 from trunk:
  
  Reduce buffer pool mutex contention under >= 4 big concurrent
  CPU-bound SELECT queries.  (Bug #22868)
  
  Fix: replace the mutex by one mutex protecting the 'flush list'
  (and the free list) and several mutexes protecting portions of the
  buffer pool, where we keep several indivudual LRU lists of pages.
  
  This patch is from Sunny Bains and Heikki Tuuri.
innobase/buf/buf0lru.c:
  Applied innodb-5.0-ss982, -ss998, -ss1003
  
  Revision r1000:
  branches/5.0: Merge r999 from trunk:
  
  Reduce buffer pool mutex contention under >= 4 big concurrent
  CPU-bound SELECT queries.  (Bug #22868)
  
  Fix: replace the mutex by one mutex protecting the 'flush list'
  (and the free list) and several mutexes protecting portions of the
  buffer pool, where we keep several indivudual LRU lists of pages.
  
  This patch is from Sunny Bains and Heikki Tuuri.
innobase/dict/dict0crea.c:
  Applied innodb-5.0-ss982, -ss998, -ss1003
  
  Revision r974:
  branches/5.0: Port r973 from trunk.
  
  Do not break the latching order in TRUNCATE TABLE.
  
  dict_truncate_index_tree(): Replace parameter rec_t* rec with
  btr_pcur_t* pcur.  Reposition pcur before calling btr_create().
  
  sync_thread_add_level(): Remove the relaxation of the assertion added in r968.
innobase/fil/fil0fil.c:
  Applied innodb-5.0-ss982, -ss998, -ss1003
  
  Revision r1003:
  branches/5.0: Merge r1002 from trunk:
  
  fil_flush_file_spaces(): Copy the system->unflushed_spaces list to an
  array while holding the mutex.  This removes the crash-triggering
  race condition that was introduced when fixing Bug 15653.  (Bug #24089)
innobase/include/buf0buf.h:
  Applied innodb-5.0-ss982, -ss998, -ss1003
  
  Revision r1000:
  branches/5.0: Merge r999 from trunk:
  
  Reduce buffer pool mutex contention under >= 4 big concurrent
  CPU-bound SELECT queries.  (Bug #22868)
  
  Fix: replace the mutex by one mutex protecting the 'flush list'
  (and the free list) and several mutexes protecting portions of the
  buffer pool, where we keep several indivudual LRU lists of pages.
  
  This patch is from Sunny Bains and Heikki Tuuri.
innobase/include/buf0buf.ic:
  Applied innodb-5.0-ss982, -ss998, -ss1003
  
  Revision r1000:
  branches/5.0: Merge r999 from trunk:
  
  Reduce buffer pool mutex contention under >= 4 big concurrent
  CPU-bound SELECT queries.  (Bug #22868)
  
  Fix: replace the mutex by one mutex protecting the 'flush list'
  (and the free list) and several mutexes protecting portions of the
  buffer pool, where we keep several indivudual LRU lists of pages.
  
  This patch is from Sunny Bains and Heikki Tuuri.
innobase/include/dict0crea.h:
  Applied innodb-5.0-ss982, -ss998, -ss1003
  
  Revision r974:
  branches/5.0: Port r973 from trunk.
  
  Do not break the latching order in TRUNCATE TABLE.
  
  dict_truncate_index_tree(): Replace parameter rec_t* rec with
  btr_pcur_t* pcur.  Reposition pcur before calling btr_create().
  
  sync_thread_add_level(): Remove the relaxation of the assertion added in r968.
innobase/include/sync0arr.h:
  Applied innodb-5.0-ss982, -ss998, -ss1003
  
  Revision r1001:
  branches/5.0: Reduce locking contention:
  
  Bug #15815: 'Thread thrashing' with > 50 concurrent connections under
  an update-intensive workload.
  Fix: Introduce one event per InnoDB semaphore.
  
  This patch is from Sunny Bains and Heikki Tuuri.
  This patch will not be merged to trunk (MySQL/InnoDB 5.1) yet,
  because it tries to address the problem in a different way.
innobase/include/sync0rw.h:
  Applied innodb-5.0-ss982, -ss998, -ss1003
  
  Revision r1001:
  branches/5.0: Reduce locking contention:
  
  Bug #15815: 'Thread thrashing' with > 50 concurrent connections under
  an update-intensive workload.
  Fix: Introduce one event per InnoDB semaphore.
  
  This patch is from Sunny Bains and Heikki Tuuri.
  This patch will not be merged to trunk (MySQL/InnoDB 5.1) yet,
  because it tries to address the problem in a different way.
innobase/include/sync0rw.ic:
  Applied innodb-5.0-ss982, -ss998, -ss1003
  
  Revision r1001:
  branches/5.0: Reduce locking contention:
  
  Bug #15815: 'Thread thrashing' with > 50 concurrent connections under
  an update-intensive workload.
  Fix: Introduce one event per InnoDB semaphore.
  
  This patch is from Sunny Bains and Heikki Tuuri.
  This patch will not be merged to trunk (MySQL/InnoDB 5.1) yet,
  because it tries to address the problem in a different way.
innobase/include/sync0sync.h:
  Applied innodb-5.0-ss982, -ss998, -ss1003
  
  Revision r1001:
  branches/5.0: Reduce locking contention:
  
  Bug #15815: 'Thread thrashing' with > 50 concurrent connections under
  an update-intensive workload.
  Fix: Introduce one event per InnoDB semaphore.
  
  This patch is from Sunny Bains and Heikki Tuuri.
  This patch will not be merged to trunk (MySQL/InnoDB 5.1) yet,
  because it tries to address the problem in a different way.
innobase/os/os0sync.c:
  Applied innodb-5.0-ss982, -ss998, -ss1003
  
  Revision r1001:
  branches/5.0: Reduce locking contention:
  
  Bug #15815: 'Thread thrashing' with > 50 concurrent connections under
  an update-intensive workload.
  Fix: Introduce one event per InnoDB semaphore.
  
  This patch is from Sunny Bains and Heikki Tuuri.
  This patch will not be merged to trunk (MySQL/InnoDB 5.1) yet,
  because it tries to address the problem in a different way.
innobase/row/row0mysql.c:
  Applied innodb-5.0-ss982, -ss998, -ss1003
  
  Revision r974:
  branches/5.0: Port r973 from trunk.
  
  Do not break the latching order in TRUNCATE TABLE.
  
  dict_truncate_index_tree(): Replace parameter rec_t* rec with
  btr_pcur_t* pcur.  Reposition pcur before calling btr_create().
  
  sync_thread_add_level(): Remove the relaxation of the assertion added in r968.
innobase/row/row0sel.c:
  Applied innodb-5.0-ss982, -ss998, -ss1003
  
  Revision r982:
  branches/5.0: row_sel(): Do not try to acquire a LOCK_REC_NOT_GAP lock
  on the supremum record.  Instead, skip to the next record.  (Bug #23769)
  This fix was backported from r623 in the 5.1 tree.
innobase/srv/srv0start.c:
  Applied innodb-5.0-ss982, -ss998, -ss1003
  
  Revision r926:
  Refer to bug: 22268. Since no one tries to run 5.0 on Windows 95/ME it was
  decided to raise the limit of srv_max_n_threads to 10000 on Windows.
innobase/sync/sync0arr.c:
  Applied innodb-5.0-ss982, -ss998, -ss1003
  
  Revision r1001:
  branches/5.0: Reduce locking contention:
  
  Bug #15815: 'Thread thrashing' with > 50 concurrent connections under
  an update-intensive workload.
  Fix: Introduce one event per InnoDB semaphore.
  
  This patch is from Sunny Bains and Heikki Tuuri.
  This patch will not be merged to trunk (MySQL/InnoDB 5.1) yet,
  because it tries to address the problem in a different way.
innobase/sync/sync0rw.c:
  Applied innodb-5.0-ss982, -ss998, -ss1003
  
  Revision r1001:
  branches/5.0: Reduce locking contention:
  
  Bug #15815: 'Thread thrashing' with > 50 concurrent connections under
  an update-intensive workload.
  Fix: Introduce one event per InnoDB semaphore.
  
  This patch is from Sunny Bains and Heikki Tuuri.
  This patch will not be merged to trunk (MySQL/InnoDB 5.1) yet,
  because it tries to address the problem in a different way.
innobase/sync/sync0sync.c:
  Applied innodb-5.0-ss982, -ss998, -ss1003
  
  Revision r969:
  branches/5.0: Port r968 from trunk:
  
  sync_thread_add_level(): When level == SYNC_TREE_NODE, allow the latching
  order to be violated if the thread holds dict_operation_lock, whose level is
  SYNC_DICT_OPERATION.  This removes the assertion failure of TRUNCATE TABLE
  #ifdef UNIV_SYNC_DEBUG.
  
  
  Revision r974:
  branches/5.0: Port r973 from trunk.
  
  Do not break the latching order in TRUNCATE TABLE.
  
  dict_truncate_index_tree(): Replace parameter rec_t* rec with
  btr_pcur_t* pcur.  Reposition pcur before calling btr_create().
  
  sync_thread_add_level(): Remove the relaxation of the assertion added in r968.
  
  
  Revision r1001:
  branches/5.0: Reduce locking contention:
  
  Bug #15815: 'Thread thrashing' with > 50 concurrent connections under
  an update-intensive workload.
  Fix: Introduce one event per InnoDB semaphore.
  
  This patch is from Sunny Bains and Heikki Tuuri.
  This patch will not be merged to trunk (MySQL/InnoDB 5.1) yet,
  because it tries to address the problem in a different way.
parent 8bad3511
Loading
Loading
Loading
Loading
+125 −56
Original line number Diff line number Diff line
@@ -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 */

#ifdef UNIV_DEBUG
@@ -488,6 +491,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)));

@@ -756,8 +762,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);
@@ -790,6 +803,8 @@ buf_awe_map_page_to_frame(

			buf_pool->n_pages_awe_remapped++;
			
			mutex_exit(&bck->mutex);

			return;
		}
	}
@@ -828,13 +843,22 @@ buf_block_make_young(
/*=================*/
	buf_block_t*	block)	/* in: block to make younger */
{
#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 / 1024)) {
				+ 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);
	}
}

@@ -869,12 +893,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));
}

@@ -1093,9 +1121,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);
@@ -1133,6 +1160,8 @@ buf_page_get_gen(
		goto loop;
	}

	mutex_enter(&block->mutex);

	ut_a(block->state == BUF_BLOCK_FILE_PAGE);

	must_read = FALSE;
@@ -1142,9 +1171,9 @@ buf_page_get_gen(
		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);
		}
@@ -1168,7 +1197,7 @@ buf_page_get_gen(
#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 */

@@ -1176,10 +1205,13 @@ buf_page_get_gen(

	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++;
@@ -1204,13 +1236,14 @@ buf_page_get_gen(
		}

		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);
		}
@@ -1221,18 +1254,16 @@ buf_page_get_gen(
			completes */

		        for (;;) {
			        mutex_enter(&(buf_pool->mutex));
				mutex_enter(&block->mutex);

		                if (block->io_fix == BUF_IO_READ) {

				        mutex_exit(&(buf_pool->mutex));
				  
				        /* Sleep 20 milliseconds */
					mutex_exit(&block->mutex);
				  
				        os_thread_sleep(20000);
					os_thread_sleep(WAIT_FOR_READ);
				} else {
				  
				       mutex_exit(&(buf_pool->mutex));
					mutex_exit(&block->mutex);

				       break;
				}
@@ -1291,14 +1322,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 (UNIV_UNLIKELY(block->state != BUF_BLOCK_FILE_PAGE)
	    || UNIV_UNLIKELY(block->frame != guess)) {
	exit_func:
		mutex_exit(&(buf_pool->mutex));

		mutex_exit(&block->mutex);

		return(FALSE);
	}
@@ -1308,15 +1339,14 @@ buf_page_optimistic_get_func(
#else
	buf_block_buf_fix_inc(block);
#endif
	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));
	mutex_exit(&block->mutex);

	buf_block_make_young(block);

	/* Check if this is the first access to the page */

	ut_ad(!ibuf_inside() || ibuf_page(block->space, block->offset));

@@ -1331,13 +1361,16 @@ buf_page_optimistic_get_func(
	}

	if (UNIV_UNLIKELY(!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
		goto exit_func;
		return(FALSE);
	}

	if (UNIV_UNLIKELY(!UT_DULINT_EQ(modify_clock, block->modify_clock))) {
@@ -1350,13 +1383,16 @@ 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
		goto exit_func;
		return(FALSE);
	}

	mtr_memo_push(mtr, block, fix_type);
@@ -1413,10 +1449,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
@@ -1425,7 +1461,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);
	}
@@ -1437,12 +1473,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) {
@@ -1456,13 +1492,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);
	}
@@ -1510,7 +1548,6 @@ buf_page_init_for_backup_restore(
	block->offset 		= offset;

	block->lock_hash_val	= 0;
	block->lock_mutex	= NULL;

	block->freed_page_clock = 0;

@@ -1543,6 +1580,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);

@@ -1557,7 +1595,6 @@ buf_page_init(
	block->index		= NULL;
	
	block->lock_hash_val	= lock_rec_hash(space, offset);
	block->lock_mutex	= NULL;

	/* Insert into the hash table of file pages */

@@ -1650,6 +1687,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)) {
@@ -1662,7 +1700,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) {
@@ -1682,6 +1722,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
@@ -1693,6 +1734,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) {
@@ -1757,6 +1799,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 */
@@ -1767,13 +1811,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 */
@@ -1822,6 +1868,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) {
@@ -1890,11 +1942,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
@@ -1937,6 +1990,7 @@ buf_page_io_complete(
#endif /* UNIV_DEBUG */
	}
	
	mutex_exit(&block->mutex);
	mutex_exit(&(buf_pool->mutex));

#ifdef UNIV_DEBUG
@@ -1999,6 +2053,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,
@@ -2042,6 +2098,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) {
@@ -2187,11 +2245,17 @@ buf_get_latched_pages_number(void)

		block = buf_pool_get_nth_block(buf_pool, i);

               if (((block->buf_fix_count != 0) || (block->io_fix != 0)) &&
                    block->magic_n == BUF_BLOCK_MAGIC_N )
		if (block->magic_n == BUF_BLOCK_MAGIC_N) {
			mutex_enter(&block->mutex);

			if (block->buf_fix_count != 0 || block->io_fix != 0) {
				fixed_pages_number++;
			}

			mutex_exit(&block->mutex);
		}
        }

        mutex_exit(&(buf_pool->mutex));
        return fixed_pages_number;
}
@@ -2354,16 +2418,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));
+65 −27
Original line number Diff line number Diff line
@@ -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);

@@ -539,8 +541,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;

@@ -578,6 +587,7 @@ buf_flush_try_page(
			locked = TRUE;
		}

		mutex_exit(&block->mutex);
		mutex_exit(&(buf_pool->mutex));

		if (!locked) {
@@ -598,7 +608,7 @@ buf_flush_try_page(
		
		return(1);

	} else if (flush_type == BUF_FLUSH_LRU && block
	} else if (flush_type == BUF_FLUSH_LRU
		   && buf_flush_ready_for_flush(block, flush_type)) {

		/* VERY IMPORTANT:
@@ -639,13 +649,14 @@ 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
	} else if (flush_type == BUF_FLUSH_SINGLE_PAGE
		   && buf_flush_ready_for_flush(block, flush_type)) {
	
		block->io_fix = BUF_IO_WRITE;
@@ -672,6 +683,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);
@@ -688,12 +700,13 @@ buf_flush_try_page(
		buf_flush_write_block_low(block);
		
		return(1);
	} else {
	}

	mutex_exit(&block->mutex);
	mutex_exit(&(buf_pool->mutex));

	return(0);
}
}

/***************************************************************
Flushes to disk all flushable pages within the flush area. */
@@ -737,34 +750,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
		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 {

			mutex_enter(&block->mutex);

		if (block && buf_flush_ready_for_flush(block, flush_type)
			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
				/* 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_exit(&block->mutex);

				mutex_exit(&(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. */
				/* 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);
				count += buf_flush_try_page(space, i,
							    flush_type);

				mutex_enter(&(buf_pool->mutex));
			} else {
				mutex_exit(&block->mutex);
			}
		}
	}
				
@@ -858,12 +885,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;
@@ -881,10 +911,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);
			}
	    	}
@@ -966,10 +1000,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);
+24 −1
Original line number Diff line number Diff line
@@ -86,6 +86,9 @@ buf_LRU_invalidate_tablespace(
	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 @@ buf_LRU_invalidate_tablespace(
			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 @@ buf_LRU_invalidate_tablespace(
			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)) {

#ifdef UNIV_DEBUG
@@ -225,6 +234,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
@@ -233,15 +243,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++;

@@ -415,8 +431,12 @@ buf_LRU_get_free_block(void)
			}
		}
		
		mutex_enter(&block->mutex);

		block->state = BUF_BLOCK_READY_FOR_USE;

		mutex_exit(&block->mutex);

		mutex_exit(&(buf_pool->mutex));

		if (started_monitor) {
@@ -818,6 +838,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);
	
@@ -857,6 +878,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);
	
@@ -914,6 +936,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);

+9 −4
Original line number Diff line number Diff line
@@ -724,8 +724,10 @@ dict_truncate_index_tree(
				/* out: new root page number, or
				FIL_NULL on failure */
	dict_table_t*	table,	/* in: the table the index belongs to */
	rec_t*		rec,	/* in: record in the clustered index of
				SYS_INDEXES table */
	btr_pcur_t*	pcur,	/* in/out: persistent cursor pointing to
				record in the clustered index of
				SYS_INDEXES table. The cursor may be
				repositioned in this call. */
	mtr_t*		mtr)	/* in: mtr having the latch
				on the record page. The mtr may be
				committed and restarted in this call. */
@@ -734,6 +736,7 @@ dict_truncate_index_tree(
	ulint		space;
	ulint		type;
	dulint		index_id;
	rec_t*		rec;
	byte*		ptr;
	ulint		len;
	ulint		comp;
@@ -744,6 +747,7 @@ dict_truncate_index_tree(
#endif /* UNIV_SYNC_DEBUG */

	ut_a(!dict_sys->sys_indexes->comp);
	rec = btr_pcur_get_rec(pcur);
	ptr = rec_get_nth_field_old(rec, DICT_SYS_INDEXES_PAGE_NO_FIELD, &len);

	ut_ad(len == 4);
@@ -809,10 +813,11 @@ dict_truncate_index_tree(
	/* We will need to commit the mini-transaction in order to avoid
	deadlocks in the btr_create() call, because otherwise we would
	be freeing and allocating pages in the same mini-transaction. */
	btr_pcur_store_position(pcur, mtr);
	mtr_commit(mtr);
	/* mtr_commit() will invalidate rec. */
	rec = NULL;

	mtr_start(mtr);
	btr_pcur_restore_position(BTR_MODIFY_LEAF, pcur, mtr);

	/* Find the index corresponding to this SYS_INDEXES record. */
	for (index = UT_LIST_GET_FIRST(table->indexes);
+31 −13
Original line number Diff line number Diff line
@@ -4285,29 +4285,47 @@ fil_flush_file_spaces(
{
	fil_system_t*	system	= fil_system;
	fil_space_t*	space;
	ulint*		space_ids;
	ulint		n_space_ids;
	ulint		i;

	mutex_enter(&(system->mutex));

	space = UT_LIST_GET_FIRST(system->unflushed_spaces);
	n_space_ids = UT_LIST_GET_LEN(system->unflushed_spaces);
	if (n_space_ids == 0) {

	while (space) {
		if (space->purpose == purpose && !space->is_being_deleted) {
		mutex_exit(&system->mutex);
		return;
	}

			space->n_pending_flushes++; /* prevent dropping of the
						    space while we are
						    flushing */
			mutex_exit(&(system->mutex));
	/* Assemble a list of space ids to flush.  Previously, we
	traversed system->unflushed_spaces and called UT_LIST_GET_NEXT()
	on a space that was just removed from the list by fil_flush().
	Thus, the space could be dropped and the memory overwritten. */
	space_ids = mem_alloc(n_space_ids * sizeof *space_ids);

			fil_flush(space->id);
	n_space_ids = 0;

			mutex_enter(&(system->mutex));
	for (space = UT_LIST_GET_FIRST(system->unflushed_spaces);
	     space;
	     space = UT_LIST_GET_NEXT(unflushed_spaces, space)) {

			space->n_pending_flushes--;
		if (space->purpose == purpose && !space->is_being_deleted) {

			space_ids[n_space_ids++] = space->id;
		}
		space = UT_LIST_GET_NEXT(unflushed_spaces, space);
	}

	mutex_exit(&(system->mutex));
	mutex_exit(&system->mutex);

	/* Flush the spaces.  It will not hurt to call fil_flush() on
	a non-existing space id. */
	for (i = 0; i < n_space_ids; i++) {

		fil_flush(space_ids[i]);
	}

	mem_free(space_ids);
}

/**********************************************************************
Loading