List:Commits« Previous MessageNext Message »
From:Inaam Rana Date:December 8 2010 3:39pm
Subject:bzr push into mysql-trunk-innodb branch (inaam.rana:3367 to 3368)
View as plain text  
 3368 Inaam Rana	2010-12-08
      WL5664 InnoDB: Use rw_locks for page_hash
      
      Approved by: Marko	rb://507
      
      * Use rw_locks instead of mutexes to protect buffer pool page_hash.
      * innodb_page_hash_mutexes is now changed to innodb_page_hash_locks
      and the default value is 16 instead of 256
      * introduce new UNIV_PERF_DEBUG. innodb_page_hash_locks is on settable
      and visible when UNIV_PERF_DEBUG or UNIV_DEBUG is set
      
      - hash table is now of three types based on the type of synchronization
      .objects used for the access i.e.: NONE, MUTEX, LOCKS.
       - New field ::type added to hash table struct
       - ::n_mutexes replaced by ::n_sync_obj
       - ::mutexes array is replaced by a union of mutex_t* and rw_lock_t*
       - New functions added to hash table implementation
        +# define hash_lock_s(t, f)    
        +# define hash_lock_x(t, f)    
        +# define hash_unlock_s(t, f)  
        +# define hash_unlock_x(t, f)  
        +# define hash_lock_x_all(t)     
        +# define hash_unlock_x_all(t)   
        +# define hash_unlock_x_all_but(t, l)
       
       - Two new inline debug functions hash_assert_can_modify() and
       hash_assert_can_search() to replace the macro ASSERT_HASH_MUTEX_OWN.
      
      - buf_page_hash_get() and buf_block_hash_get() changed to
        buf_page_hash_get_locked() and buf_block_hash_get_locked()
        respectively:
       - Both functions now return a pointer to the rw_lock that is held.
         If NULL is passed then the lock is released just like mutex before.
       - Both functions take a new parameter lock_mode to tell if the lock
         is to be held in x or s mode.
        - macros to access the above functions:
         +#define buf_page_hash_get_s_locked(b, s, o, l)                 \
         +       buf_page_hash_get_locked(b, s, o, l, RW_LOCK_SHARED)
         +#define buf_page_hash_get_x_locked(b, s, o, l)                 \
         +       buf_page_hash_get_locked(b, s, o, l, RW_LOCK_EX)
         +#define buf_page_hash_get(b, s, o)                             \
         +       buf_page_hash_get_locked(b, s, o, NULL, 0)
         
      - innodb_page_hash_mutexees changed to innodb_page_hash_locks which is
        only enabled when UNIV_DEBUG or a new macro UNIV_PERF_DEBUG is
        enabled. Default value is set to 16.
      - buf_pool_watch_occurred() get s-lock in place of hash_mutex.
      - buf_page_get_gen() replace hash_mutex with following:
       - get s-lock when the page is in the buffer pool. This is the most
         typical case.
       - get x-lock if a watch has to be set
       - get x-lock if we need to decompress a compressed page
      - for all other occurrences of hash_mutex replace them with x-lock

    removed:
      mysql-test/suite/sys_vars/r/innodb_page_hash_mutexes_basic.result
      mysql-test/suite/sys_vars/t/innodb_page_hash_mutexes_basic.test
    modified:
      mysql-test/suite/sys_vars/r/all_vars.result
      mysql-test/suite/sys_vars/t/all_vars.test
      storage/innobase/btr/btr0sea.c
      storage/innobase/buf/buf0buddy.c
      storage/innobase/buf/buf0buf.c
      storage/innobase/buf/buf0flu.c
      storage/innobase/buf/buf0lru.c
      storage/innobase/buf/buf0rea.c
      storage/innobase/ha/ha0ha.c
      storage/innobase/ha/hash0hash.c
      storage/innobase/handler/ha_innodb.cc
      storage/innobase/ibuf/ibuf0ibuf.c
      storage/innobase/include/buf0buf.h
      storage/innobase/include/buf0buf.ic
      storage/innobase/include/ha0ha.h
      storage/innobase/include/ha0ha.ic
      storage/innobase/include/hash0hash.h
      storage/innobase/include/hash0hash.ic
      storage/innobase/include/srv0srv.h
      storage/innobase/include/sync0sync.h
      storage/innobase/include/univ.i
      storage/innobase/srv/srv0srv.c
      storage/innobase/sync/sync0sync.c
 3367 Jimmy Yang	2010-12-07
      Re-enable InnoDB information schema system tables (worklog#5373 and rb://330).

    added:
      mysql-test/suite/innodb/r/innodb-system-table-view.result
      mysql-test/suite/innodb/t/innodb-system-table-view.test
    modified:
      mysql-test/r/mysqlshow.result
      storage/innobase/dict/dict0load.c
      storage/innobase/handler/ha_innodb.cc
      storage/innobase/handler/i_s.cc
      storage/innobase/handler/i_s.h
=== modified file 'mysql-test/suite/sys_vars/r/all_vars.result'
--- a/mysql-test/suite/sys_vars/r/all_vars.result	revid:jimmy.yang@stripped
+++ b/mysql-test/suite/sys_vars/r/all_vars.result	revid:inaam.rana@stripped
@@ -4,6 +4,7 @@ load data infile "MYSQLTEST_VARDIR/tmp/s
 insert into t2 select variable_name from information_schema.global_variables;
 insert into t2 select variable_name from information_schema.session_variables;
 delete from t2 where variable_name='innodb_change_buffering_debug';
+delete from t2 where variable_name='innodb_page_hash_locks';
 update t2 set variable_name= replace(variable_name, "PERFORMANCE_SCHEMA_", "PFS_");
 select variable_name as `There should be *no* long test name listed below:` from t2
 where length(variable_name) > 50;

=== removed file 'mysql-test/suite/sys_vars/r/innodb_page_hash_mutexes_basic.result'
--- a/mysql-test/suite/sys_vars/r/innodb_page_hash_mutexes_basic.result	revid:jimmy.yang@stripped
+++ b/mysql-test/suite/sys_vars/r/innodb_page_hash_mutexes_basic.result	1970-01-01 00:00:00 +0000
@@ -1,21 +0,0 @@
-select @@global.innodb_page_hash_mutexes;
-@@global.innodb_page_hash_mutexes
-256
-select @@session.innodb_page_hash_mutexes;
-ERROR HY000: Variable 'innodb_page_hash_mutexes' is a GLOBAL variable
-show global variables like 'innodb_page_hash_mutexes';
-Variable_name	Value
-innodb_page_hash_mutexes	256
-show session variables like 'innodb_page_hash_mutexes';
-Variable_name	Value
-innodb_page_hash_mutexes	256
-select * from information_schema.global_variables where variable_name='innodb_page_hash_mutexes';
-VARIABLE_NAME	VARIABLE_VALUE
-INNODB_PAGE_HASH_MUTEXES	256
-select * from information_schema.session_variables where variable_name='innodb_page_hash_mutexes';
-VARIABLE_NAME	VARIABLE_VALUE
-INNODB_PAGE_HASH_MUTEXES	256
-set global innodb_page_hash_mutexes=1;
-ERROR HY000: Variable 'innodb_page_hash_mutexes' is a read only variable
-set session innodb_page_hash_mutexes=1;
-ERROR HY000: Variable 'innodb_page_hash_mutexes' is a read only variable

=== modified file 'mysql-test/suite/sys_vars/t/all_vars.test'
--- a/mysql-test/suite/sys_vars/t/all_vars.test	revid:jimmy.yang@stripped
+++ b/mysql-test/suite/sys_vars/t/all_vars.test	revid:inaam.rana@stripped
@@ -66,8 +66,9 @@ eval load data infile "$MYSQLTEST_VARDIR
 insert into t2 select variable_name from information_schema.global_variables;
 insert into t2 select variable_name from information_schema.session_variables;
 
-# This is only present in debug builds.
+# These are only present in debug builds.
 delete from t2 where variable_name='innodb_change_buffering_debug';
+delete from t2 where variable_name='innodb_page_hash_locks';
 
 # Performance schema variables are too long for files named
 # 'mysql-test/suite/sys_vars/t/' ...

=== removed file 'mysql-test/suite/sys_vars/t/innodb_page_hash_mutexes_basic.test'
--- a/mysql-test/suite/sys_vars/t/innodb_page_hash_mutexes_basic.test	revid:jimmy.yang@stripped
+++ b/mysql-test/suite/sys_vars/t/innodb_page_hash_mutexes_basic.test	1970-01-01 00:00:00 +0000
@@ -1,20 +0,0 @@
---source include/have_innodb.inc
-
-#
-# show the global and session values;
-#
-select @@global.innodb_page_hash_mutexes;
---error ER_INCORRECT_GLOBAL_LOCAL_VAR
-select @@session.innodb_page_hash_mutexes;
-show global variables like 'innodb_page_hash_mutexes';
-show session variables like 'innodb_page_hash_mutexes';
-select * from information_schema.global_variables where variable_name='innodb_page_hash_mutexes';
-select * from information_schema.session_variables where variable_name='innodb_page_hash_mutexes';
-
-#
-# show that it's read-only
-#
---error ER_INCORRECT_GLOBAL_LOCAL_VAR
-set global innodb_page_hash_mutexes=1;
---error ER_INCORRECT_GLOBAL_LOCAL_VAR
-set session innodb_page_hash_mutexes=1;

=== modified file 'storage/innobase/btr/btr0sea.c'
--- a/storage/innobase/btr/btr0sea.c	revid:jimmy.yang@stripped
+++ b/storage/innobase/btr/btr0sea.c	revid:inaam.rana@stripped
@@ -1821,8 +1821,7 @@ btr_search_validate(void)
 				hash_block = buf_block_hash_get(
 					buf_pool,
 					buf_block_get_space(block),
-					buf_block_get_page_no(block),
-					NULL);
+					buf_block_get_page_no(block));
 			} else {
 				hash_block = NULL;
 			}

=== modified file 'storage/innobase/buf/buf0buddy.c'
--- a/storage/innobase/buf/buf0buddy.c	revid:jimmy.yang@stripped
+++ b/storage/innobase/buf/buf0buddy.c	revid:inaam.rana@stripped
@@ -356,7 +356,7 @@ buf_buddy_relocate_block(
 	buf_pool_t*	buf_pool = buf_pool_from_bpage(bpage);
 	ulint		fold = buf_page_address_fold(bpage->space,
 						     bpage->offset);
-	mutex_t*	hash_mutex = buf_page_hash_mutex_get(buf_pool, fold);
+	rw_lock_t*	hash_lock = buf_page_hash_lock_get(buf_pool, fold);
 
 	ut_ad(buf_pool_mutex_own(buf_pool));
 
@@ -376,11 +376,11 @@ buf_buddy_relocate_block(
 		break;
 	}
 
-	mutex_enter(hash_mutex);
+	rw_lock_x_lock(hash_lock);
 	mutex_enter(&buf_pool->zip_mutex);
 
 	if (!buf_page_can_relocate(bpage)) {
-		mutex_exit(hash_mutex);
+		rw_lock_x_unlock(hash_lock);
 		mutex_exit(&buf_pool->zip_mutex);
 		return(FALSE);
 	}
@@ -400,7 +400,7 @@ buf_buddy_relocate_block(
 
 	UNIV_MEM_INVALID(bpage, sizeof *bpage);
 
-	mutex_exit(hash_mutex);
+	rw_lock_x_unlock(hash_lock);
 	mutex_exit(&buf_pool->zip_mutex);
 	return(TRUE);
 }
@@ -460,7 +460,7 @@ buf_buddy_relocate(
 		on uninitialized value. */
 		UNIV_MEM_VALID(&space, sizeof space);
 		UNIV_MEM_VALID(&page_no, sizeof page_no);
-		bpage = buf_page_hash_get(buf_pool, space, page_no, NULL);
+		bpage = buf_page_hash_get(buf_pool, space, page_no);
 
 		if (!bpage || bpage->zip.data != src) {
 			/* The block has probably been freshly

=== modified file 'storage/innobase/buf/buf0buf.c'
--- a/storage/innobase/buf/buf0buf.c	revid:jimmy.yang@stripped
+++ b/storage/innobase/buf/buf0buf.c	revid:inaam.rana@stripped
@@ -1248,15 +1248,15 @@ buf_pool_init_instance(
 		buf_pool->curr_size = chunk->size;
 		buf_pool->curr_pool_size = buf_pool->curr_size * UNIV_PAGE_SIZE;
 
-		/* Number of mutexes portecting page_hash must be a
+		/* Number of locks portecting page_hash must be a
 		power of two */
-		srv_n_page_hash_mutexes =
-				 ut_2_power_up(srv_n_page_hash_mutexes);
-		ut_a(srv_n_page_hash_mutexes != 0);
-		ut_a(srv_n_page_hash_mutexes <= MAX_PAGE_HASH_MUTEXES);
+		srv_n_page_hash_locks =
+				 ut_2_power_up(srv_n_page_hash_locks);
+		ut_a(srv_n_page_hash_locks != 0);
+		ut_a(srv_n_page_hash_locks <= MAX_PAGE_HASH_LOCKS);
 
 		buf_pool->page_hash = ha_create(2 * buf_pool->curr_size,
-						srv_n_page_hash_mutexes,
+						srv_n_page_hash_locks,
 						MEM_HEAP_FOR_PAGE_HASH,
 						SYNC_BUF_PAGE_HASH);
 
@@ -1497,7 +1497,7 @@ buf_relocate(
 	fold = buf_page_address_fold(bpage->space, bpage->offset);
 
 	ut_ad(buf_pool_mutex_own(buf_pool));
-	ut_ad(buf_page_hash_mutex_own(buf_pool, bpage));
+	ut_ad(buf_page_hash_lock_held_x(buf_pool, bpage));
 	ut_ad(mutex_own(buf_page_get_mutex(bpage)));
 	ut_a(buf_page_get_io_fix(bpage) == BUF_IO_NONE);
 	ut_a(bpage->buf_fix_count == 0);
@@ -1760,25 +1760,25 @@ buf_pool_page_hash_rebuild_instance(
 
 	buf_pool_mutex_enter(buf_pool);
 
-	hash_mutex_enter_all(buf_pool->page_hash);
+	hash_lock_x_all(buf_pool->page_hash);
 
 	/* Free, create, and populate the hash table. */
 	ha_clear(buf_pool->page_hash);
 
 	/*FIXME: This is broken. When we free the hash_table we
-	free the mutex array as well. We either have to have a
+	free the sync_obj array as well. We either have to have a
 	mechanism where it is guaranteed that nobody will try to
-	acquire any of the page_hash mutexes or think some other
+	acquire any of the page_hash locks or think some other
 	way to implement this. It doesn't matter as of now because
 	buffer pool resize code is not used currently. */
 	hash_table_free(buf_pool->page_hash);
 
-	ut_a(srv_n_page_hash_mutexes != 0);
-	ut_a(srv_n_page_hash_mutexes <= MAX_PAGE_HASH_MUTEXES);
+	ut_a(srv_n_page_hash_locks != 0);
+	ut_a(srv_n_page_hash_locks <= MAX_PAGE_HASH_LOCKS);
 
 	buf_pool->page_hash = page_hash
 			    = ha_create(2 * buf_pool->curr_size,
-					srv_n_page_hash_mutexes,
+					srv_n_page_hash_locks,
 					MEM_HEAP_FOR_PAGE_HASH,
 					SYNC_BUF_PAGE_HASH);
 
@@ -1858,7 +1858,7 @@ buf_pool_page_hash_rebuild_instance(
 		}
 	}
 
-	hash_mutex_exit_all(buf_pool->page_hash);
+	hash_unlock_x_all(buf_pool->page_hash);
 	buf_flush_list_mutex_exit(buf_pool);
 	buf_pool_mutex_exit(buf_pool);
 }
@@ -1873,13 +1873,8 @@ buf_pool_watch_is_sentinel(
 	buf_pool_t*		buf_pool,	/*!< buffer pool instance */
 	const buf_page_t*	bpage)		/*!< in: block */
 {
-#ifdef UNIV_DEBUG
-	/* We must also own the appropriate hash_bucket mutex. */
-	ulint	 fold = buf_page_address_fold(bpage->space,
-					      bpage->offset);
-	mutex_t* hash_mutex = buf_page_hash_mutex_get(buf_pool, fold);
-	ut_ad(mutex_own(hash_mutex));
-#endif
+	/* We must also own the appropriate hash lock. */
+	ut_ad(buf_page_hash_lock_held_s_or_x(buf_pool, bpage));
 	ut_ad(buf_page_in_file(bpage));
 
 	if (bpage < &buf_pool->watch[0]
@@ -1901,8 +1896,8 @@ buf_pool_watch_is_sentinel(
 
 /****************************************************************//**
 Add watch for the given page to be read in. Caller must have
-appropriate hash_mutex for the bpage. This function may release the
-hash_mutex and reacquire it.
+appropriate hash_lock for the bpage. This function may release the
+hash_lock and reacquire it.
 @return NULL if watch set, block if the page is in the buffer pool */
 UNIV_INTERN
 buf_page_t*
@@ -1915,11 +1910,13 @@ buf_pool_watch_set(
 	buf_page_t*	bpage;
 	ulint		i;
 	buf_pool_t*	buf_pool = buf_pool_get(space, offset);
-	mutex_t*	hash_mutex;
+	rw_lock_t*	hash_lock;
 
-	hash_mutex = buf_page_hash_mutex_get(buf_pool, fold);
+	hash_lock = buf_page_hash_lock_get(buf_pool, fold);
 
-	ut_ad(mutex_own(hash_mutex));
+#ifdef UNIV_SYNC_DEBUG
+	ut_ad(rw_lock_own(hash_lock, RW_LOCK_EX));
+#endif /* UNIV_SYNC_DEBUG */
 
 	bpage = buf_page_hash_get_low(buf_pool, space, offset, fold);
 
@@ -1936,29 +1933,29 @@ page_found:
 
 	/* From this point this function becomes fairly heavy in terms
 	of latching. We acquire the buf_pool mutex as well as all the
-	hash_mutexes. buf_pool mutex is needed because any changes to
-	the page_hash must be covered by it and hash_mutexes are needed
+	hash_locks. buf_pool mutex is needed because any changes to
+	the page_hash must be covered by it and hash_locks are needed
 	because we don't want to read any stale information in
 	buf_pool->watch[]. However, it is not in the critical code path
 	as this function will be called only by the purge thread. */
 
 
-	/* To obey latching order first release the hash_mutex. */
-	mutex_exit(hash_mutex);
+	/* To obey latching order first release the hash_lock. */
+	rw_lock_x_unlock(hash_lock);
 
 	buf_pool_mutex_enter(buf_pool);
-	hash_mutex_enter_all(buf_pool->page_hash);
+	hash_lock_x_all(buf_pool->page_hash);
 
 	/* We have to recheck that the page
 	was not loaded or a watch set by some other
 	purge thread. This is because of the small
 	time window between when we release the
-	hash_mutex to acquire buf_pool mutex above. */
+	hash_lock to acquire buf_pool mutex above. */
 
 	bpage = buf_page_hash_get_low(buf_pool, space, offset, fold);
 	if (UNIV_LIKELY_NULL(bpage)) {
 		buf_pool_mutex_exit(buf_pool);
-		hash_mutex_exit_all_but(buf_pool->page_hash, hash_mutex);
+		hash_unlock_x_all_but(buf_pool->page_hash, hash_lock);
 		goto page_found;
 	}
 
@@ -1992,10 +1989,10 @@ page_found:
 
 			buf_pool_mutex_exit(buf_pool);
 			/* Once the sentinel is in the page_hash we can
-			safely release all mutexes except just the
-			relevant hash_mutex */
-			hash_mutex_exit_all_but(buf_pool->page_hash,
-						hash_mutex);
+			safely release all locks except just the
+			relevant hash_lock */
+			hash_unlock_x_all_but(buf_pool->page_hash,
+						hash_lock);
 
 			return(NULL);
 		case BUF_BLOCK_ZIP_PAGE:
@@ -2148,11 +2145,11 @@ buf_pool_watch_remove(
 					space, offset) */
 	buf_page_t*	watch)		/*!< in/out: sentinel for watch */
 {
-#ifdef UNIV_DEBUG
+#ifdef UNIV_SYNC_DEBUG
 	/* We must also own the appropriate hash_bucket mutex. */
-	mutex_t* hash_mutex = buf_page_hash_mutex_get(buf_pool, fold);
-	ut_ad(mutex_own(hash_mutex));
-#endif
+	rw_lock_t* hash_lock = buf_page_hash_lock_get(buf_pool, fold);
+	ut_ad(rw_lock_own(hash_lock, RW_LOCK_EX));
+#endif /* UNIV_SYNC_DEBUG */
 
 	ut_ad(buf_pool_mutex_own(buf_pool));
 
@@ -2175,17 +2172,17 @@ buf_pool_watch_unset(
 	buf_page_t*	bpage;
 	buf_pool_t*	buf_pool = buf_pool_get(space, offset);
 	ulint		fold = buf_page_address_fold(space, offset);
-	mutex_t*	hash_mutex = buf_page_hash_mutex_get(buf_pool,
+	rw_lock_t*	hash_lock = buf_page_hash_lock_get(buf_pool,
 							     fold);
 
 	/* We only need to have buf_pool mutex in case where we end
 	up calling buf_pool_watch_remove but to obey latching order
-	we acquire it here before acquiring hash_mutex. This should
+	we acquire it here before acquiring hash_lock. This should
 	not cause too much grief as this function is only ever
 	called from the purge thread. */
 	buf_pool_mutex_enter(buf_pool);
 
-	mutex_enter(hash_mutex);
+	rw_lock_x_lock(hash_lock);
 
 	bpage = buf_page_hash_get_low(buf_pool, space, offset, fold);
 	/* The page must exist because buf_pool_watch_set()
@@ -2208,7 +2205,7 @@ buf_pool_watch_unset(
 	}
 
 	buf_pool_mutex_exit(buf_pool);
-	mutex_exit(hash_mutex);
+	rw_lock_x_unlock(hash_lock);
 }
 
 /****************************************************************//**
@@ -2227,17 +2224,17 @@ buf_pool_watch_occurred(
 	buf_page_t*	bpage;
 	buf_pool_t*	buf_pool = buf_pool_get(space, offset);
 	ulint		fold	= buf_page_address_fold(space, offset);
-	mutex_t*	hash_mutex = buf_page_hash_mutex_get(buf_pool,
+	rw_lock_t*	hash_lock = buf_page_hash_lock_get(buf_pool,
 							     fold);
 
-	mutex_enter(hash_mutex);
+	rw_lock_s_lock(hash_lock);
 
 	bpage = buf_page_hash_get_low(buf_pool, space, offset, fold);
 	/* The page must exist because buf_pool_watch_set()
 	increments buf_fix_count. */
 	ut_a(bpage);
 	ret = !buf_pool_watch_is_sentinel(buf_pool, bpage);
-	mutex_exit(hash_mutex);
+	rw_lock_s_unlock(hash_lock);
 
 	return(ret);
 }
@@ -2307,9 +2304,10 @@ buf_reset_check_index_page_at_flush(
 {
 	buf_block_t*	block;
 	buf_pool_t*	buf_pool = buf_pool_get(space, offset);
-	mutex_t*	hash_mutex;
+	rw_lock_t*	hash_lock;
 
-	block = buf_block_hash_get(buf_pool, space, offset, &hash_mutex);
+	block = buf_block_hash_get_s_locked(buf_pool, space, offset,
+					    &hash_lock);
 
 	if (block) {
 		if (buf_block_get_state(block) == BUF_BLOCK_FILE_PAGE) {
@@ -2318,7 +2316,7 @@ buf_reset_check_index_page_at_flush(
 			block->check_index_page_at_flush = FALSE;
 		}
 
-		mutex_exit(hash_mutex);
+		rw_lock_s_unlock(hash_lock);
 	}
 }
 
@@ -2337,9 +2335,10 @@ buf_page_peek_if_search_hashed(
 	buf_block_t*	block;
 	ibool		is_hashed;
 	buf_pool_t*	buf_pool = buf_pool_get(space, offset);
-	mutex_t*	hash_mutex;
+	rw_lock_t*	hash_lock;
 
-	block = buf_block_hash_get(buf_pool, space, offset, &hash_mutex);
+	block = buf_block_hash_get_s_locked(buf_pool, space, offset,
+					    &hash_lock);
 
 	if (!block || buf_block_get_state(block) != BUF_BLOCK_FILE_PAGE) {
 		is_hashed = FALSE;
@@ -2349,7 +2348,7 @@ buf_page_peek_if_search_hashed(
 	}
 
 	if (block) {
-		mutex_exit(hash_mutex);
+		rw_lock_s_unlock(hash_lock);
 	}
 
 	return(is_hashed);
@@ -2371,14 +2370,15 @@ buf_page_set_file_page_was_freed(
 {
 	buf_page_t*	bpage;
 	buf_pool_t*	buf_pool = buf_pool_get(space, offset);
-	mutex_t*	hash_mutex;
+	rw_lock_t*	hash_lock;
 
-	bpage = buf_page_hash_get(buf_pool, space, offset, &hash_mutex);
+	bpage = buf_page_hash_get_s_locked(buf_pool, space, offset,
+					   &hash_lock);
 
 	if (bpage) {
 		ut_ad(!buf_pool_watch_is_sentinel(buf_pool, bpage));
 		bpage->file_page_was_freed = TRUE;
-		mutex_exit(hash_mutex);
+		rw_lock_s_unlock(hash_lock);
 	}
 
 	return(bpage);
@@ -2399,14 +2399,14 @@ buf_page_reset_file_page_was_freed(
 {
 	buf_page_t*	bpage;
 	buf_pool_t*	buf_pool = buf_pool_get(space, offset);
-	mutex_t*	hash_mutex;
-
-	bpage = buf_page_hash_get(buf_pool, space, offset, &hash_mutex);
+	rw_lock_t*	hash_lock;
 
+	bpage = buf_page_hash_get_s_locked(buf_pool, space, offset,
+					   &hash_lock);
 	if (bpage) {
 		ut_ad(!buf_pool_watch_is_sentinel(buf_pool, bpage));
 		bpage->file_page_was_freed = FALSE;
-		mutex_exit(hash_mutex);
+		rw_lock_s_unlock(hash_lock);
 	}
 
 	return(bpage);
@@ -2435,7 +2435,7 @@ buf_block_try_discard_uncompressed(
 	we need to check again if the block is still in page_hash. */
 	buf_pool_mutex_enter(buf_pool);
 
-	bpage = buf_page_hash_get(buf_pool, space, offset, NULL);
+	bpage = buf_page_hash_get(buf_pool, space, offset);
 
 	if (bpage) {
 		buf_LRU_free_block(bpage, FALSE, NULL);
@@ -2463,7 +2463,7 @@ buf_page_get_zip(
 {
 	buf_page_t*	bpage;
 	mutex_t*	block_mutex;
-	mutex_t*	hash_mutex;
+	rw_lock_t*	hash_lock;
 	ibool		discard_attempted = FALSE;
 	ibool		must_read;
 	unsigned	access_time;
@@ -2479,8 +2479,8 @@ lookup:
 
 		/* The following call will also grab the page_hash
 		mutex if the page is found. */
-		bpage = buf_page_hash_get(buf_pool, space, offset,
-					  &hash_mutex);
+		bpage = buf_page_hash_get_s_locked(buf_pool, space,
+						offset, &hash_lock);
 		if (bpage) {
 			ut_ad(!buf_pool_watch_is_sentinel(buf_pool, bpage));
 			break;
@@ -2488,7 +2488,7 @@ lookup:
 
 		/* Page not in buf_pool: needs to be read from file */
 
-		ut_ad(!hash_mutex);
+		ut_ad(!hash_lock);
 		buf_read_page(space, zip_size, offset);
 
 #if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG
@@ -2496,12 +2496,12 @@ lookup:
 #endif /* UNIV_DEBUG || UNIV_BUF_DEBUG */
 	}
 
-	ut_ad(buf_page_hash_mutex_own(buf_pool, bpage));
+	ut_ad(buf_page_hash_lock_held_s(buf_pool, bpage));
 
 	if (UNIV_UNLIKELY(!bpage->zip.data)) {
 		/* There is no compressed page. */
 err_exit:
-		mutex_exit(hash_mutex);
+		rw_lock_s_unlock(hash_lock);
 		return(NULL);
 	}
 
@@ -2523,7 +2523,7 @@ err_exit:
 	case BUF_BLOCK_FILE_PAGE:
 		/* Discard the uncompressed page frame if possible. */
 		if (!discard_attempted) {
-			mutex_exit(hash_mutex);
+			rw_lock_s_unlock(hash_lock);
 			buf_block_try_discard_uncompressed(space,
 							   offset);
 			discard_attempted = TRUE;
@@ -2544,7 +2544,7 @@ got_block:
 	must_read = buf_page_get_io_fix(bpage) == BUF_IO_READ;
 	access_time = buf_page_is_accessed(bpage);
 
-	mutex_exit(hash_mutex);
+	rw_lock_s_unlock(hash_lock);
 	mutex_exit(block_mutex);
 
 	buf_page_set_accessed_make_young(bpage, access_time);
@@ -2885,7 +2885,7 @@ buf_page_get_gen(
 	unsigned	access_time;
 	ulint		fix_type;
 	ibool		must_read;
-	mutex_t*	hash_mutex;
+	rw_lock_t*	hash_lock;
 	mutex_t*	block_mutex;
 	buf_page_t*	hash_bpage;
 	ulint		retries = 0;
@@ -2909,11 +2909,11 @@ buf_page_get_gen(
 #endif
 	buf_pool->stat.n_page_gets++;
 	fold = buf_page_address_fold(space, offset);
-	hash_mutex = buf_page_hash_mutex_get(buf_pool, fold);
+	hash_lock = buf_page_hash_lock_get(buf_pool, fold);
 loop:
 	block = guess;
 
-	mutex_enter(hash_mutex);
+	rw_lock_s_lock(hash_lock);
 	if (block) {
 		/* If the guess is a compressed page descriptor that
 		has been allocated by buf_buddy_alloc(), it may have
@@ -2944,7 +2944,7 @@ loop:
 
 loop2:
 	if (!block || buf_pool_watch_is_sentinel(buf_pool, &block->page)) {
-		mutex_exit(hash_mutex);
+		rw_lock_s_unlock(hash_lock);
 		block = NULL;
 	}
 
@@ -2952,22 +2952,31 @@ loop2:
 		/* Page not in buf_pool: needs to be read from file */
 
 		if (mode == BUF_GET_IF_IN_POOL_OR_WATCH) {
-			mutex_enter(hash_mutex);
+			rw_lock_x_lock(hash_lock);
 			block = (buf_block_t*) buf_pool_watch_set(
 				space, offset, fold);
 
 			if (UNIV_LIKELY_NULL(block)) {
+				/* We can release hash_lock after we
+				acquire block_mutex to make sure that
+				no state change takes place. */
+				block_mutex = buf_page_get_mutex(&block->page);
+				mutex_enter(block_mutex);
 
-				ut_ad(mutex_own(hash_mutex));
+				/* Now safe to release page_hash mutex */
+				rw_lock_x_unlock(hash_lock);
 				goto got_block;
 			}
-			mutex_exit(hash_mutex);
+
+			rw_lock_x_unlock(hash_lock);
 		}
 
 		if (mode == BUF_GET_IF_IN_POOL
 		    || mode == BUF_GET_IF_IN_POOL_OR_WATCH) {
-
-			ut_ad(!mutex_own(hash_mutex));
+#ifdef UNIV_SYNC_DEBUG
+			ut_ad(!rw_lock_own(hash_lock, RW_LOCK_EX));
+			ut_ad(!rw_lock_own(hash_lock, RW_LOCK_SHARED));
+#endif /* UNIV_SYNC_DEBUG */
 			return(NULL);
 		}
 
@@ -3001,16 +3010,18 @@ loop2:
 		goto loop;
 	}
 
-got_block:
-	/* We can release hash_mutex after we acquire block_mutex to
+
+	/* We can release hash_lock after we acquire block_mutex to
 	make sure that no state change takes place. */
 	block_mutex = buf_page_get_mutex(&block->page);
 	mutex_enter(block_mutex);
 
-	ut_ad(page_zip_get_size(&block->page.zip) == zip_size);
-
 	/* Now safe to release page_hash mutex */
-	mutex_exit(hash_mutex);
+	rw_lock_s_unlock(hash_lock);
+
+got_block:
+	ut_ad(page_zip_get_size(&block->page.zip) == zip_size);
+	ut_ad(mutex_own(block_mutex));
 
 	must_read = buf_block_get_io_fix(block) == BUF_IO_READ;
 
@@ -3056,13 +3067,13 @@ wait_until_unfixed:
 
 		buf_pool_mutex_enter(buf_pool);
 
-		/* As we have released the page_hash mutex and the
+		/* As we have released the page_hash lock and the
 		block_mutex to allocate an uncompressed page it is
 		possible that page_hash might have changed. We do
-		another lookup here while holding the hash_mutex
+		another lookup here while holding the hash_lock
 		to verify that bpage is indeed still a part of
 		page_hash. */
-		mutex_enter(hash_mutex);
+		rw_lock_x_lock(hash_lock);
 		hash_bpage = buf_page_hash_get_low(buf_pool, space,
 						   offset, fold);
 
@@ -3078,8 +3089,10 @@ wait_until_unfixed:
 
 			block = (buf_block_t*) hash_bpage;
 
+			rw_lock_x_unlock(hash_lock);
+			rw_lock_s_lock(hash_lock);
 			/* Note that we are still holding the
-			hash_mutex which is fine as this is what
+			hash_lock which is fine as this is what
 			we expect when we move to loop2 above. */
 			goto loop2;
 		}
@@ -3088,7 +3101,7 @@ wait_until_unfixed:
 		    (bpage->buf_fix_count
 		     || buf_page_get_io_fix(bpage) != BUF_IO_NONE)) {
 
-			mutex_exit(hash_mutex);
+			rw_lock_x_unlock(hash_lock);
 			/* The block was buffer-fixed or I/O-fixed
 			while buf_pool->mutex was not held by this thread.
 			Free the block that was allocated and try again.
@@ -3138,7 +3151,7 @@ wait_until_unfixed:
 
 		UNIV_MEM_INVALID(bpage, sizeof *bpage);
 
-		mutex_exit(hash_mutex);
+		rw_lock_x_unlock(hash_lock);
 		mutex_exit(&block->mutex);
 		mutex_exit(&buf_pool->zip_mutex);
 		buf_pool->n_pend_unzip++;
@@ -3177,7 +3190,11 @@ wait_until_unfixed:
 		break;
 	}
 
-	ut_ad(!mutex_own(hash_mutex));
+#ifdef UNIV_SYNC_DEBUG
+	ut_ad(!rw_lock_own(hash_lock, RW_LOCK_EX));
+	ut_ad(!rw_lock_own(hash_lock, RW_LOCK_SHARED));
+#endif /* UNIV_SYNC_DEBUG */
+
 	ut_ad(buf_block_get_state(block) == BUF_BLOCK_FILE_PAGE);
 
 #if UNIV_WORD_SIZE == 4
@@ -3204,14 +3221,14 @@ wait_until_unfixed:
 		mutex_exit(&block->mutex);
 
 		/* Now we are only holding the buf_pool->mutex,
-		not block->mutex or hash_mutex. Blocks cannot be
+		not block->mutex or hash_lock. Blocks cannot be
 		relocated or enter or exit the buf_pool while we
 		are holding the buf_pool->mutex. */
 
 		if (buf_LRU_free_block(&block->page, TRUE, NULL)
 		    == BUF_LRU_FREED) {
 			buf_pool_mutex_exit(buf_pool);
-			mutex_enter(hash_mutex);
+			rw_lock_x_lock(hash_lock);
 
 			if (mode == BUF_GET_IF_IN_POOL_OR_WATCH) {
 				/* Set the watch, as it would have
@@ -3228,10 +3245,13 @@ wait_until_unfixed:
 				/* The page entered the buffer
 				pool for some reason. Try to
 				evict it again. */
+				mutex_enter(block_mutex);
+				rw_lock_x_unlock(hash_lock);
+
 				goto got_block;
 			}
 
-			mutex_exit(hash_mutex);
+			rw_lock_x_unlock(hash_lock);
 			fprintf(stderr,
 				"innodb_change_buffering_debug evict %u %u\n",
 				(unsigned) space, (unsigned) offset);
@@ -3326,7 +3346,10 @@ wait_until_unfixed:
 	ut_a(ibuf_count_get(buf_block_get_space(block),
 			    buf_block_get_page_no(block)) == 0);
 #endif
-	ut_ad(!mutex_own(hash_mutex));
+#ifdef UNIV_SYNC_DEBUG
+	ut_ad(!rw_lock_own(hash_lock, RW_LOCK_EX));
+	ut_ad(!rw_lock_own(hash_lock, RW_LOCK_SHARED));
+#endif /* UNIV_SYNC_DEBUG */
 	return(block);
 }
 
@@ -3569,16 +3592,17 @@ buf_page_try_get_func(
 	ibool		success;
 	ulint		fix_type;
 	buf_pool_t*	buf_pool = buf_pool_get(space_id, page_no);
-	mutex_t*	hash_mutex;
+	rw_lock_t*	hash_lock;
 
 	ut_ad(mtr);
 	ut_ad(mtr->state == MTR_ACTIVE);
 
-	block = buf_block_hash_get(buf_pool, space_id, page_no, &hash_mutex);
+	block = buf_block_hash_get_s_locked(buf_pool, space_id,
+					    page_no, &hash_lock);
 
 	if (!block || buf_block_get_state(block) != BUF_BLOCK_FILE_PAGE) {
 		if (block) {
-			mutex_exit(hash_mutex);
+			rw_lock_s_unlock(hash_lock);
 		}
 		return(NULL);
 	}
@@ -3586,7 +3610,7 @@ buf_page_try_get_func(
 	ut_ad(!buf_pool_watch_is_sentinel(buf_pool, &block->page));
 
 	mutex_enter(&block->mutex);
-	mutex_exit(hash_mutex);
+	rw_lock_s_unlock(hash_lock);
 
 #if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG
 	ut_a(buf_block_get_state(block) == BUF_BLOCK_FILE_PAGE);
@@ -3676,10 +3700,15 @@ buf_page_init(
 	buf_pool_t*	buf_pool = buf_pool_get(space, offset);
 
 	ut_ad(buf_pool_mutex_own(buf_pool));
-	ut_ad(mutex_own(buf_page_hash_mutex_get(buf_pool, fold)));
+
 	ut_ad(mutex_own(&(block->mutex)));
 	ut_a(buf_block_get_state(block) != BUF_BLOCK_FILE_PAGE);
 
+#ifdef UNIV_SYNC_DEBUG
+	ut_ad(rw_lock_own(buf_page_hash_lock_get(buf_pool, fold),
+			  RW_LOCK_EX));
+#endif /* UNIV_SYNC_DEBUG */
+
 	/* Set the state of the block */
 	buf_block_set_file_page(block, space, offset);
 
@@ -3763,7 +3792,7 @@ buf_page_init_for_read(
 	buf_block_t*	block;
 	buf_page_t*	bpage	= NULL;
 	buf_page_t*	watch_page;
-	mutex_t*	hash_mutex;
+	rw_lock_t*	hash_lock;
 	mtr_t		mtr;
 	ulint		fold;
 	ibool		lru	= FALSE;
@@ -3803,17 +3832,17 @@ buf_page_init_for_read(
 	}
 
 	fold = buf_page_address_fold(space, offset);
-	hash_mutex = buf_page_hash_mutex_get(buf_pool, fold);
+	hash_lock = buf_page_hash_lock_get(buf_pool, fold);
 
 	buf_pool_mutex_enter(buf_pool);
-	mutex_enter(hash_mutex);
+	rw_lock_x_lock(hash_lock);
 
 	watch_page = buf_page_hash_get_low(buf_pool, space, offset, fold);
 	if (watch_page && !buf_pool_watch_is_sentinel(buf_pool, watch_page)) {
 		/* The page is already in the buffer pool. */
 		watch_page = NULL;
 err_exit:
-		mutex_exit(hash_mutex);
+		rw_lock_x_unlock(hash_lock);
 		if (block) {
 			mutex_enter(&block->mutex);
 			buf_LRU_block_free_non_file_page(block);
@@ -3841,7 +3870,7 @@ err_exit:
 		ut_ad(buf_pool_from_bpage(bpage) == buf_pool);
 
 		buf_page_init(space, offset, fold, block);
-		mutex_exit(hash_mutex);
+		rw_lock_x_unlock(hash_lock);
 
 		/* The block must be put to the LRU list, to the old blocks */
 		buf_LRU_add_block(bpage, TRUE/* to old blocks */);
@@ -3885,7 +3914,7 @@ err_exit:
 
 		mutex_exit(&block->mutex);
 	} else {
-		mutex_exit(hash_mutex);
+		rw_lock_x_unlock(hash_lock);
 		/* Defer buf_buddy_alloc() until after the block has
 		been found not to exist.  The buf_buddy_alloc() and
 		buf_buddy_free() calls may be expensive because of
@@ -3901,7 +3930,7 @@ err_exit:
 		/* Initialize the buf_pool pointer. */
 		bpage->buf_pool_index = buf_pool_index(buf_pool);
 
-		mutex_enter(hash_mutex);
+		rw_lock_x_lock(hash_lock);
 
 		/* If buf_buddy_alloc() allocated storage from the LRU list,
 		it released and reacquired buf_pool->mutex.  Thus, we must
@@ -3916,7 +3945,7 @@ err_exit:
 							   watch_page))) {
 
 				/* The block was added by some other thread. */
-				mutex_exit(hash_mutex);
+				rw_lock_x_unlock(hash_lock);
 				watch_page = NULL;
 				buf_buddy_free(buf_pool, bpage, sizeof *bpage);
 				buf_buddy_free(buf_pool, data, zip_size);
@@ -3964,7 +3993,7 @@ err_exit:
 		HASH_INSERT(buf_page_t, hash, buf_pool->page_hash, fold,
 			    bpage);
 
-		mutex_exit(hash_mutex);
+		rw_lock_x_unlock(hash_lock);
 
 		/* The block must be put to the LRU list, to the old blocks */
 		buf_LRU_add_block(bpage, TRUE/* to old blocks */);
@@ -3984,7 +4013,12 @@ func_exit:
 		mtr_commit(&mtr);
 	}
 
-	ut_ad(!mutex_own(hash_mutex));
+
+#ifdef UNIV_SYNC_DEBUG
+	ut_ad(!rw_lock_own(hash_lock, RW_LOCK_EX));
+	ut_ad(!rw_lock_own(hash_lock, RW_LOCK_SHARED));
+#endif /* UNIV_SYNC_DEBUG */
+
 	ut_ad(!bpage || buf_page_in_file(bpage));
 	return(bpage);
 }
@@ -4011,7 +4045,7 @@ buf_page_create(
 	buf_block_t*	free_block	= NULL;
 	ulint		time_ms		= ut_time_ms();
 	buf_pool_t*	buf_pool	= buf_pool_get(space, offset);
-	mutex_t*	hash_mutex;
+	rw_lock_t*	hash_lock;
 
 	ut_ad(mtr);
 	ut_ad(mtr->state == MTR_ACTIVE);
@@ -4020,10 +4054,10 @@ buf_page_create(
 	free_block = buf_LRU_get_free_block(buf_pool, 0);
 
 	fold = buf_page_address_fold(space, offset);
-	hash_mutex = buf_page_hash_mutex_get(buf_pool, fold);
+	hash_lock = buf_page_hash_lock_get(buf_pool, fold);
 
 	buf_pool_mutex_enter(buf_pool);
-	mutex_enter(hash_mutex);
+	rw_lock_x_lock(hash_lock);
 
 	block = (buf_block_t*) buf_page_hash_get_low(
 		buf_pool, space, offset, fold);
@@ -4040,7 +4074,7 @@ buf_page_create(
 
 		/* Page can be found in buf_pool */
 		buf_pool_mutex_exit(buf_pool);
-		mutex_exit(hash_mutex);
+		rw_lock_x_unlock(hash_lock);
 
 		buf_block_free(free_block);
 
@@ -4063,7 +4097,7 @@ buf_page_create(
 
 	buf_page_init(space, offset, fold, block);
 
-	mutex_exit(hash_mutex);
+	rw_lock_x_unlock(hash_lock);
 
 	/* The block must be put to the LRU list */
 	buf_LRU_add_block(&block->page, FALSE);
@@ -4604,7 +4638,7 @@ buf_pool_validate_instance(
 	ut_ad(buf_pool);
 
 	buf_pool_mutex_enter(buf_pool);
-	hash_mutex_enter_all(buf_pool->page_hash);
+	hash_lock_x_all(buf_pool->page_hash);
 
 	chunk = buf_pool->chunks;
 
@@ -4776,7 +4810,7 @@ buf_pool_validate_instance(
 
 	ut_a(UT_LIST_GET_LEN(buf_pool->flush_list) == n_flush);
 
-	hash_mutex_exit_all(buf_pool->page_hash);
+	hash_unlock_x_all(buf_pool->page_hash);
 	buf_flush_list_mutex_exit(buf_pool);
 
 	mutex_exit(&buf_pool->zip_mutex);

=== modified file 'storage/innobase/buf/buf0flu.c'
--- a/storage/innobase/buf/buf0flu.c	revid:jimmy.yang@stripped
+++ b/storage/innobase/buf/buf0flu.c	revid:inaam.rana@stripped
@@ -1442,7 +1442,7 @@ buf_flush_try_neighbors(
 		buf_pool_mutex_enter(buf_pool);
 
 		/* We only want to flush pages from this buffer pool. */
-		bpage = buf_page_hash_get(buf_pool, space, i, NULL);
+		bpage = buf_page_hash_get(buf_pool, space, i);
 
 		if (!bpage) {
 

=== modified file 'storage/innobase/buf/buf0lru.c'
--- a/storage/innobase/buf/buf0lru.c	revid:jimmy.yang@stripped
+++ b/storage/innobase/buf/buf0lru.c	revid:inaam.rana@stripped
@@ -124,8 +124,8 @@ If the block is compressed-only (BUF_BLO
 the object will be freed.
 
 The caller must hold buf_pool->mutex, the buf_page_get_mutex() mutex
-and the appropriate hash_mutex. This function will release the
-buf_page_get_mutex() and the hash_mutex.
+and the appropriate hash_lock. This function will release the
+buf_page_get_mutex() and the hash_lock.
 
 If a compressed page or a compressed-only block descriptor is freed,
 other compressed pages or compressed-only block descriptors may be
@@ -375,12 +375,12 @@ scan_again:
 		} else {
 			ulint fold = buf_page_address_fold(bpage->space,
 							   bpage->offset);
-			mutex_t* hash_mutex = buf_page_hash_mutex_get(buf_pool,
+			rw_lock_t* hash_lock = buf_page_hash_lock_get(buf_pool,
 								      fold);
 
 			mutex_t* block_mutex = buf_page_get_mutex(bpage);
 
-			mutex_enter(hash_mutex);
+			rw_lock_x_lock(hash_lock);
 			mutex_enter(block_mutex);
 
 			if (bpage->buf_fix_count > 0) {
@@ -391,7 +391,7 @@ scan_again:
 				the modifications to the file */
 
 				all_freed = FALSE;
-				mutex_exit(hash_mutex);
+				rw_lock_x_unlock(hash_lock);
 				mutex_exit(block_mutex);
 				goto next_page;
 			}
@@ -446,7 +446,7 @@ scan_again:
 				zip_size = buf_page_get_zip_size(bpage);
 				page_no = buf_page_get_page_no(bpage);
 
-				mutex_exit(hash_mutex);
+				rw_lock_x_unlock(hash_lock);
 				mutex_exit(block_mutex);
 
 				/* Note that the following call will acquire
@@ -490,7 +490,10 @@ scan_again:
 
 			}
 
-			ut_ad(!mutex_own(hash_mutex));
+#ifdef UNIV_SYNC_DEBUG
+                        ut_ad(!rw_lock_own(hash_lock, RW_LOCK_EX)
+                              && !rw_lock_own(hash_lock, RW_LOCK_SHARED));
+#endif /* UNIV_SYNC_DEBUG */
 			ut_ad(!mutex_own(block_mutex));
 		}
 next_page:
@@ -1471,7 +1474,7 @@ buf_LRU_free_block(
 	enum buf_lru_free_block_status	ret;
 	const ulint	fold = buf_page_address_fold(bpage->space,
 						     bpage->offset);
-	mutex_t*	hash_mutex = buf_page_hash_mutex_get(buf_pool, fold);
+	rw_lock_t*	hash_lock = buf_page_hash_lock_get(buf_pool, fold);
 
 	mutex_t*	block_mutex = buf_page_get_mutex(bpage);
 
@@ -1479,7 +1482,7 @@ buf_LRU_free_block(
 	ut_ad(buf_page_in_file(bpage));
 	ut_ad(bpage->in_LRU_list);
 
-	mutex_enter(hash_mutex);
+	rw_lock_x_lock(hash_lock);
 	mutex_enter(block_mutex);
 
 #if UNIV_WORD_SIZE == 4
@@ -1537,7 +1540,7 @@ buf_LRU_free_block(
 no_free_exit:
 			ret = BUF_LRU_NOT_FREED;
 func_exit:
-			mutex_exit(hash_mutex);
+			rw_lock_x_unlock(hash_lock);
 			mutex_exit(block_mutex);
 			return(ret);
 		}
@@ -1568,7 +1571,9 @@ func_exit:
 	}
 #endif /* UNIV_DEBUG */
 
-	ut_ad(mutex_own(hash_mutex));
+#ifdef UNIV_SYNC_DEBUG
+        ut_ad(rw_lock_own(hash_lock, RW_LOCK_EX));
+#endif /* UNIV_SYNC_DEBUG */
 	ut_ad(buf_page_can_relocate(bpage));
 
 	if (buf_LRU_block_remove_hashed_page(bpage, zip)
@@ -1584,7 +1589,7 @@ func_exit:
 		if (b) {
 			buf_page_t*	prev_b	= UT_LIST_GET_PREV(LRU, b);
 
-			mutex_enter(hash_mutex);
+			rw_lock_x_lock(hash_lock);
 			mutex_enter(block_mutex);
 
 			ut_a(!buf_page_hash_get_low(buf_pool,
@@ -1683,7 +1688,7 @@ func_exit:
 			b->buf_fix_count++;
 			b->io_fix = BUF_IO_READ;
 
-			mutex_exit(hash_mutex);
+			rw_lock_x_unlock(hash_lock);
 			mutex_exit(block_mutex);
 		}
 
@@ -1733,7 +1738,10 @@ func_exit:
 
 		buf_LRU_block_free_hashed_page((buf_block_t*) bpage);
 	}
-
+#ifdef UNIV_SYNC_DEBUG
+	ut_ad(!rw_lock_own(hash_lock, RW_LOCK_EX)
+	      && !rw_lock_own(hash_lock, RW_LOCK_SHARED));
+#endif /* UNIV_SYNC_DEBUG */
 	return(BUF_LRU_FREED);
 }
 
@@ -1805,8 +1813,8 @@ If the block is compressed-only (BUF_BLO
 the object will be freed.
 
 The caller must hold buf_pool->mutex, the buf_page_get_mutex() mutex
-and the appropriate hash_mutex. This function will release the
-buf_page_get_mutex() and the hash_mutex.
+and the appropriate hash_lock. This function will release the
+buf_page_get_mutex() and the hash_lock.
 
 If a compressed page or a compressed-only block descriptor is freed,
 other compressed pages or compressed-only block descriptors may be
@@ -1826,15 +1834,17 @@ buf_LRU_block_remove_hashed_page(
 	ulint			fold;
 	const buf_page_t*	hashed_bpage;
 	buf_pool_t*		buf_pool = buf_pool_from_bpage(bpage);
-	mutex_t*		hash_mutex;
+	rw_lock_t*		hash_lock;
 
 	ut_ad(bpage);
 	ut_ad(buf_pool_mutex_own(buf_pool));
 	ut_ad(mutex_own(buf_page_get_mutex(bpage)));
 
 	fold = buf_page_address_fold(bpage->space, bpage->offset);
-	hash_mutex = buf_page_hash_mutex_get(buf_pool, fold);
-	ut_ad(mutex_own(hash_mutex));
+	hash_lock = buf_page_hash_lock_get(buf_pool, fold);
+#ifdef UNIV_SYNC_DEBUG
+        ut_ad(rw_lock_own(hash_lock, RW_LOCK_EX));
+#endif /* UNIV_SYNC_DEBUG */
 
 	ut_a(buf_page_get_io_fix(bpage) == BUF_IO_NONE);
 	ut_a(bpage->buf_fix_count == 0);
@@ -1940,7 +1950,7 @@ buf_LRU_block_remove_hashed_page(
 
 #if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG
 		mutex_exit(buf_page_get_mutex(bpage));
-		mutex_exit(hash_mutex);
+		rw_lock_x_unlock(hash_lock);
 		buf_pool_mutex_exit(buf_pool);
 		buf_print();
 		buf_LRU_print();
@@ -1965,7 +1975,7 @@ buf_LRU_block_remove_hashed_page(
 		UT_LIST_REMOVE(list, buf_pool->zip_clean, bpage);
 
 		mutex_exit(&buf_pool->zip_mutex);
-		mutex_exit(hash_mutex);
+		rw_lock_x_unlock(hash_lock);
 		buf_pool_mutex_exit_forbid(buf_pool);
 
 		buf_buddy_free(
@@ -2006,7 +2016,7 @@ buf_LRU_block_remove_hashed_page(
 		and by the time we'll release it in the caller we'd
 		have inserted the compressed only descriptor in the
 		page_hash. */
-		mutex_exit(hash_mutex);
+		rw_lock_x_unlock(hash_lock);
 		mutex_exit(&((buf_block_t*) bpage)->mutex);
 
 		if (zip && bpage->zip.data) {

=== modified file 'storage/innobase/buf/buf0rea.c'
--- a/storage/innobase/buf/buf0rea.c	revid:jimmy.yang@stripped
+++ b/storage/innobase/buf/buf0rea.c	revid:inaam.rana@stripped
@@ -331,7 +331,7 @@ buf_read_ahead_linear(
 	fail_count = 0;
 
 	for (i = low; i < high; i++) {
-		bpage = buf_page_hash_get(buf_pool, space, i, NULL);
+		bpage = buf_page_hash_get(buf_pool, space, i);
 
 		if (bpage == NULL || !buf_page_is_accessed(bpage)) {
 			/* Not accessed */
@@ -369,7 +369,7 @@ buf_read_ahead_linear(
 	/* If we got this far, we know that enough pages in the area have
 	been accessed in the right order: linear read-ahead can be sensible */
 
-	bpage = buf_page_hash_get(buf_pool, space, offset, NULL);
+	bpage = buf_page_hash_get(buf_pool, space, offset);
 
 	if (bpage == NULL) {
 		buf_pool_mutex_exit(buf_pool);

=== modified file 'storage/innobase/ha/ha0ha.c'
--- a/storage/innobase/ha/ha0ha.c	revid:jimmy.yang@stripped
+++ b/storage/innobase/ha/ha0ha.c	revid:inaam.rana@stripped
@@ -44,11 +44,13 @@ ha_create_func(
 /*===========*/
 	ulint	n,		/*!< in: number of array cells */
 #ifdef UNIV_SYNC_DEBUG
-	ulint	mutex_level,	/*!< in: level of the mutexes in the latching
-				order: this is used in the debug version */
+	ulint	sync_level,	/*!< in: level of the mutexes or rw_locks
+				in the latching order: this is used in the
+				 debug version */
 #endif /* UNIV_SYNC_DEBUG */
-	ulint	n_mutexes,	/*!< in: number of mutexes to protect the
-				hash table: must be a power of 2, or 0 */
+	ulint	n_sync_obj,	/*!< in: number of mutexes or rw_locks
+				to protect the hash table: must be a
+				power of 2, or 0 */
 	ulint	type)		/*!< in: type of datastructure for which
 				the memory heap is going to be used e.g.:
 				MEM_HEAP_FOR_BTR_SEARCH or
@@ -62,13 +64,13 @@ ha_create_func(
 	ut_a(type == MEM_HEAP_FOR_BTR_SEARCH
 	     || type == MEM_HEAP_FOR_PAGE_HASH);
 
-	ut_ad(ut_is_2pow(n_mutexes));
+	ut_ad(ut_is_2pow(n_sync_obj));
 	table = hash_create(n);
 
 	/* Creating MEM_HEAP_BTR_SEARCH type heaps can potentially fail,
 	but in practise it never should in this case, hence the asserts. */
 
-	if (n_mutexes == 0) {
+	if (n_sync_obj == 0) {
 		table->heap = mem_heap_create_typed(
 			ut_min(4096, MEM_MAX_ALLOC_IN_BUF), type);
 		ut_a(table->heap);
@@ -77,11 +79,19 @@ ha_create_func(
 	}
 
 #ifndef UNIV_HOTBACKUP
-	hash_create_mutexes(table, n_mutexes, mutex_level);
+	if (type == MEM_HEAP_FOR_PAGE_HASH) {
+		/* We create a hash table protected by rw_locks for
+		buf_pool->page_hash. */
+		hash_create_sync_obj(table, HASH_TABLE_SYNC_RW_LOCK,
+				     n_sync_obj, sync_level);
+	} else {
+		hash_create_sync_obj(table, HASH_TABLE_SYNC_MUTEX,
+				     n_sync_obj, sync_level);
+	}
 
-	table->heaps = mem_alloc(n_mutexes * sizeof(void*));
+	table->heaps = mem_alloc(n_sync_obj * sizeof(void*));
 
-	for (i = 0; i < n_mutexes; i++) {
+	for (i = 0; i < n_sync_obj; i++) {
 		table->heaps[i] = mem_heap_create_typed(4096, type);
 		ut_a(table->heaps[i]);
 	}
@@ -110,7 +120,7 @@ ha_clear(
 
 #ifndef UNIV_HOTBACKUP
 	/* Free the memory heaps. */
-	n = table->n_mutexes;
+	n = table->n_sync_obj;
 
 	for (i = 0; i < n; i++) {
 		mem_heap_free(table->heaps[i]);
@@ -120,10 +130,25 @@ ha_clear(
 		mem_free(table->heaps);
 	}
 
-	if (table->mutexes) {
-		mem_free(table->mutexes);
+	switch (table->type) {
+	case HASH_TABLE_SYNC_MUTEX:
+		mem_free(table->sync_obj.mutexes);
+		table->sync_obj.mutexes = NULL;
+		break;
+
+	case HASH_TABLE_SYNC_RW_LOCK:
+		mem_free(table->sync_obj.rw_locks);
+		table->sync_obj.rw_locks = NULL;
+		break;
+
+	case HASH_TABLE_SYNC_NONE:
+		/* do nothing */
+		break;
 	}
 
+	table->n_sync_obj = 0;
+	table->type = HASH_TABLE_SYNC_NONE;
+
 #endif /* !UNIV_HOTBACKUP */
 
 	/* Clear the hash table. */
@@ -165,7 +190,7 @@ ha_insert_for_fold_func(
 #if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG
 	ut_a(block->frame == page_align(data));
 #endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */
-	ASSERT_HASH_MUTEX_OWN(table, fold);
+	hash_assert_can_modify(table, fold);
 
 	hash = hash_calc_hash(fold, table);
 
@@ -294,7 +319,7 @@ ha_search_and_update_if_found_func(
 
 	ut_ad(table);
 	ut_ad(table->magic_n == HASH_TABLE_MAGIC_N);
-	ASSERT_HASH_MUTEX_OWN(table, fold);
+	hash_assert_can_modify(table, fold);
 #if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG
 	ut_a(new_block->frame == page_align(new_data));
 #endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */
@@ -333,7 +358,7 @@ ha_remove_all_nodes_to_page(
 
 	ut_ad(table);
 	ut_ad(table->magic_n == HASH_TABLE_MAGIC_N);
-	ASSERT_HASH_MUTEX_OWN(table, fold);
+	hash_assert_can_modify(table, fold);
 
 	node = ha_chain_get_first(table, fold);
 

=== modified file 'storage/innobase/ha/hash0hash.c'
--- a/storage/innobase/ha/hash0hash.c	revid:jimmy.yang@stripped
+++ b/storage/innobase/ha/hash0hash.c	revid:inaam.rana@stripped
@@ -34,6 +34,7 @@ Created 5/20/1997 Heikki Tuuri
 
 # ifdef UNIV_PFS_MUTEX
 UNIV_INTERN mysql_pfs_key_t	hash_table_mutex_key;
+UNIV_INTERN mysql_pfs_key_t	hash_table_rw_lock_key;
 # endif /* UNIV_PFS_MUTEX */
 
 /************************************************************//**
@@ -45,6 +46,7 @@ hash_mutex_enter(
 	hash_table_t*	table,	/*!< in: hash table */
 	ulint		fold)	/*!< in: fold */
 {
+	ut_ad(table->type == HASH_TABLE_SYNC_MUTEX);
 	mutex_enter(hash_get_mutex(table, fold));
 }
 
@@ -57,6 +59,7 @@ hash_mutex_exit(
 	hash_table_t*	table,	/*!< in: hash table */
 	ulint		fold)	/*!< in: fold */
 {
+	ut_ad(table->type == HASH_TABLE_SYNC_MUTEX);
 	mutex_exit(hash_get_mutex(table, fold));
 }
 
@@ -70,9 +73,10 @@ hash_mutex_enter_all(
 {
 	ulint	i;
 
-	for (i = 0; i < table->n_mutexes; i++) {
+	ut_ad(table->type == HASH_TABLE_SYNC_MUTEX);
+	for (i = 0; i < table->n_sync_obj; i++) {
 
-		mutex_enter(table->mutexes + i);
+		mutex_enter(table->sync_obj.mutexes + i);
 	}
 }
 
@@ -86,9 +90,10 @@ hash_mutex_exit_all(
 {
 	ulint	i;
 
-	for (i = 0; i < table->n_mutexes; i++) {
+	ut_ad(table->type == HASH_TABLE_SYNC_MUTEX);
+	for (i = 0; i < table->n_sync_obj; i++) {
 
-		mutex_exit(table->mutexes + i);
+		mutex_exit(table->sync_obj.mutexes + i);
 	}
 }
 
@@ -103,9 +108,10 @@ hash_mutex_exit_all_but(
 {
 	ulint	i;
 
-	for (i = 0; i < table->n_mutexes; i++) {
+	ut_ad(table->type == HASH_TABLE_SYNC_MUTEX);
+	for (i = 0; i < table->n_sync_obj; i++) {
 
-		mutex_t* mutex = table->mutexes + i;
+		mutex_t* mutex = table->sync_obj.mutexes + i;
 		if (UNIV_LIKELY(keep_mutex != mutex)) {
 			mutex_exit(mutex);
 		}
@@ -113,6 +119,167 @@ hash_mutex_exit_all_but(
 
 	ut_ad(mutex_own(keep_mutex));
 }
+
+/************************************************************//**
+s-lock a lock for a fold value in a hash table. */
+UNIV_INTERN
+void
+hash_lock_s(
+/*========*/
+	hash_table_t*	table,	/*!< in: hash table */
+	ulint		fold)	/*!< in: fold */
+{
+
+	rw_lock_t* lock = hash_get_lock(table, fold);
+
+	ut_ad(table->type == HASH_TABLE_SYNC_RW_LOCK);
+	ut_ad(lock);
+
+#ifdef UNIV_SYNC_DEBUG
+	ut_ad(!rw_lock_own(lock, RW_LOCK_SHARED));
+	ut_ad(!rw_lock_own(lock, RW_LOCK_EX));
+#endif /* UNIV_SYNC_DEBUG */
+
+	rw_lock_s_lock(lock);
+}
+
+/************************************************************//**
+x-lock a lock for a fold value in a hash table. */
+UNIV_INTERN
+void
+hash_lock_x(
+/*========*/
+	hash_table_t*	table,	/*!< in: hash table */
+	ulint		fold)	/*!< in: fold */
+{
+
+	rw_lock_t* lock = hash_get_lock(table, fold);
+
+	ut_ad(table->type == HASH_TABLE_SYNC_RW_LOCK);
+	ut_ad(lock);
+
+#ifdef UNIV_SYNC_DEBUG
+	ut_ad(!rw_lock_own(lock, RW_LOCK_SHARED));
+	ut_ad(!rw_lock_own(lock, RW_LOCK_EX));
+#endif /* UNIV_SYNC_DEBUG */
+
+	rw_lock_x_lock(lock);
+}
+
+/************************************************************//**
+unlock an s-lock for a fold value in a hash table. */
+UNIV_INTERN
+void
+hash_unlock_s(
+/*==========*/
+
+	hash_table_t*	table,	/*!< in: hash table */
+	ulint		fold)	/*!< in: fold */
+{
+
+	rw_lock_t* lock = hash_get_lock(table, fold);
+
+	ut_ad(table->type == HASH_TABLE_SYNC_RW_LOCK);
+	ut_ad(lock);
+
+#ifdef UNIV_SYNC_DEBUG
+	ut_ad(rw_lock_own(lock, RW_LOCK_SHARED));
+#endif /* UNIV_SYNC_DEBUG */
+
+	rw_lock_s_unlock(lock);
+}
+
+/************************************************************//**
+unlock x-lock for a fold value in a hash table. */
+UNIV_INTERN
+void
+hash_unlock_x(
+/*==========*/
+	hash_table_t*	table,	/*!< in: hash table */
+	ulint		fold)	/*!< in: fold */
+{
+	rw_lock_t* lock = hash_get_lock(table, fold);
+
+	ut_ad(table->type == HASH_TABLE_SYNC_RW_LOCK);
+	ut_ad(lock);
+
+#ifdef UNIV_SYNC_DEBUG
+	ut_ad(rw_lock_own(lock, RW_LOCK_EX));
+#endif /* UNIV_SYNC_DEBUG */
+
+	rw_lock_x_unlock(lock);
+}
+
+/************************************************************//**
+Reserves all the locks of a hash table, in an ascending order. */
+UNIV_INTERN
+void
+hash_lock_x_all(
+/*============*/
+	hash_table_t*	table)	/*!< in: hash table */
+{
+	ulint	i;
+
+	ut_ad(table->type == HASH_TABLE_SYNC_RW_LOCK);
+	for (i = 0; i < table->n_sync_obj; i++) {
+
+		rw_lock_t* lock = table->sync_obj.rw_locks + i;
+#ifdef UNIV_SYNC_DEBUG
+		ut_ad(!rw_lock_own(lock, RW_LOCK_SHARED));
+		ut_ad(!rw_lock_own(lock, RW_LOCK_EX));
+#endif /* UNIV_SYNC_DEBUG */
+
+		rw_lock_x_lock(lock);
+	}
+}
+
+/************************************************************//**
+Releases all the locks of a hash table, in an ascending order. */
+UNIV_INTERN
+void
+hash_unlock_x_all(
+/*==============*/
+	hash_table_t*	table)	/*!< in: hash table */
+{
+	ulint	i;
+
+	ut_ad(table->type == HASH_TABLE_SYNC_RW_LOCK);
+	for (i = 0; i < table->n_sync_obj; i++) {
+
+		rw_lock_t* lock = table->sync_obj.rw_locks + i;
+#ifdef UNIV_SYNC_DEBUG
+		ut_ad(rw_lock_own(lock, RW_LOCK_EX));
+#endif /* UNIV_SYNC_DEBUG */
+
+		rw_lock_x_unlock(lock);
+	}
+}
+
+/************************************************************//**
+Releases all but passed in lock of a hash table, */
+UNIV_INTERN
+void
+hash_unlock_x_all_but(
+/*==================*/
+	hash_table_t*	table,		/*!< in: hash table */
+	rw_lock_t*	keep_lock)	/*!< in: lock to keep */
+{
+	ulint	i;
+
+	ut_ad(table->type == HASH_TABLE_SYNC_RW_LOCK);
+	for (i = 0; i < table->n_sync_obj; i++) {
+
+		rw_lock_t* lock = table->sync_obj.rw_locks + i;
+#ifdef UNIV_SYNC_DEBUG
+		ut_ad(rw_lock_own(lock, RW_LOCK_EX));
+#endif /* UNIV_SYNC_DEBUG */
+
+		if (UNIV_LIKELY(keep_lock != lock)) {
+			rw_lock_x_unlock(lock);
+		}
+	}
+}
+
 #endif /* !UNIV_HOTBACKUP */
 
 /*************************************************************//**
@@ -135,14 +302,17 @@ hash_create(
 
 	array = ut_malloc(sizeof(hash_cell_t) * prime);
 
+	/* The default type of hash_table is HASH_TABLE_SYNC_NONE i.e.:
+	the caller is responsible for access control to the table. */
+	table->type = HASH_TABLE_SYNC_NONE;
 	table->array = array;
 	table->n_cells = prime;
 #ifndef UNIV_HOTBACKUP
 # if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG
 	table->adaptive = FALSE;
 # endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */
-	table->n_mutexes = 0;
-	table->mutexes = NULL;
+	table->n_sync_obj = 0;
+	table->sync_obj.mutexes = NULL;
 	table->heaps = NULL;
 #endif /* !UNIV_HOTBACKUP */
 	table->heap = NULL;
@@ -171,33 +341,60 @@ hash_table_free(
 
 #ifndef UNIV_HOTBACKUP
 /*************************************************************//**
-Creates a mutex array to protect a hash table. */
+Creates a sync object array array to protect a hash table.
+::sync_obj can be mutexes or rw_locks depening on the type of
+hash table. */
 UNIV_INTERN
 void
-hash_create_mutexes_func(
-/*=====================*/
-	hash_table_t*	table,		/*!< in: hash table */
+hash_create_sync_obj_func(
+/*======================*/
+	hash_table_t*		table,	/*!< in: hash table */
+	enum hash_table_sync_t	type,	/*!< in: HASH_TABLE_SYNC_MUTEX
+					or HASH_TABLE_SYNC_RW_LOCK */
 #ifdef UNIV_SYNC_DEBUG
-	ulint		sync_level,	/*!< in: latching order level of the
-					mutexes: used in the debug version */
+	ulint			sync_level,/*!< in: latching order level
+					of the mutexes: used in the
+					debug version */
 #endif /* UNIV_SYNC_DEBUG */
-	ulint		n_mutexes)	/*!< in: number of mutexes, must be a
-					power of 2 */
+	ulint			n_sync_obj)/*!< in: number of sync objects,
+					must be a power of 2 */
 {
 	ulint	i;
 
 	ut_ad(table);
 	ut_ad(table->magic_n == HASH_TABLE_MAGIC_N);
-	ut_a(n_mutexes > 0);
-	ut_a(ut_is_2pow(n_mutexes));
+	ut_a(n_sync_obj > 0);
+	ut_a(ut_is_2pow(n_sync_obj));
+
+	table->type = type;
+
+	switch (type) {
+	case HASH_TABLE_SYNC_MUTEX:
+		table->sync_obj.mutexes = mem_alloc(n_sync_obj
+						    * sizeof(mutex_t));
+
+		for (i = 0; i < n_sync_obj; i++) {
+			mutex_create(hash_table_mutex_key,
+			     table->sync_obj.mutexes + i, sync_level);
+		}
+
+		break;
+
+	case HASH_TABLE_SYNC_RW_LOCK:
+		table->sync_obj.rw_locks = mem_alloc(n_sync_obj
+						     * sizeof(rw_lock_t));
+
+		for (i = 0; i < n_sync_obj; i++) {
+			rw_lock_create(hash_table_rw_lock_key,
+			     table->sync_obj.rw_locks + i, sync_level);
+		}
 
-	table->mutexes = mem_alloc(n_mutexes * sizeof(mutex_t));
+		break;
 
-	for (i = 0; i < n_mutexes; i++) {
-		mutex_create(hash_table_mutex_key,
-			     table->mutexes + i, sync_level);
+	case HASH_TABLE_SYNC_NONE:
+		ut_error;
 	}
 
-	table->n_mutexes = n_mutexes;
+	table->n_sync_obj = n_sync_obj;
 }
 #endif /* !UNIV_HOTBACKUP */

=== modified file 'storage/innobase/handler/ha_innodb.cc'
--- a/storage/innobase/handler/ha_innodb.cc	revid:jimmy.yang@stripped
+++ b/storage/innobase/handler/ha_innodb.cc	revid:inaam.rana@stripped
@@ -12071,10 +12071,12 @@ static MYSQL_SYSVAR_LONGLONG(buffer_pool
   "The size of the memory buffer InnoDB uses to cache data and indexes of its tables.",
   NULL, NULL, 128*1024*1024L, 5*1024*1024L, LONGLONG_MAX, 1024*1024L);
 
-static MYSQL_SYSVAR_ULONG(page_hash_mutexes, srv_n_page_hash_mutexes,
+#if defined UNIV_DEBUG || defined UNIV_PERF_DEBUG
+static MYSQL_SYSVAR_ULONG(page_hash_locks, srv_n_page_hash_locks,
   PLUGIN_VAR_OPCMDARG | PLUGIN_VAR_READONLY,
-  "Number of mutexes protecting buffer pool page_hash. Rounded up to the next power of 2",
-  NULL, NULL, 256, 1, MAX_PAGE_HASH_MUTEXES, 0);
+  "Number of rw_locks protecting buffer pool page_hash. Rounded up to the next power of 2",
+  NULL, NULL, 16, 1, MAX_PAGE_HASH_LOCKS, 0);
+#endif /* defined UNIV_DEBUG || defined UNIV_PERF_DEBUG */
 
 static MYSQL_SYSVAR_LONG(buffer_pool_instances, innobase_buffer_pool_instances,
   PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
@@ -12314,7 +12316,9 @@ static struct st_mysql_sys_var* innobase
   MYSQL_SYSVAR(reset_all_monitor_counter),
   MYSQL_SYSVAR(purge_threads),
   MYSQL_SYSVAR(purge_batch_size),
-  MYSQL_SYSVAR(page_hash_mutexes),
+#if defined UNIV_DEBUG || defined UNIV_PERF_DEBUG
+  MYSQL_SYSVAR(page_hash_locks),
+#endif /* defined UNIV_DEBUG || defined UNIV_PERF_DEBUG */
   NULL
 };
 

=== modified file 'storage/innobase/ibuf/ibuf0ibuf.c'
--- a/storage/innobase/ibuf/ibuf0ibuf.c	revid:jimmy.yang@stripped
+++ b/storage/innobase/ibuf/ibuf0ibuf.c	revid:inaam.rana@stripped
@@ -3775,13 +3775,8 @@ check_watch:
 
 	{
 		buf_page_t*	bpage;
-		ulint		fold = buf_page_address_fold(space, page_no);
 		buf_pool_t*	buf_pool = buf_pool_get(space, page_no);
-		mutex_t*	hash_mutex = buf_page_hash_mutex_get(buf_pool, fold);
-
-		mutex_enter(hash_mutex);
-		bpage = buf_page_hash_get_low(buf_pool, space, page_no, fold);
-		mutex_exit(hash_mutex);
+		bpage = buf_page_hash_get(buf_pool, space, page_no);
 
 		if (UNIV_LIKELY_NULL(bpage)) {
 			/* A buffer pool watch has been set or the

=== modified file 'storage/innobase/include/buf0buf.h'
--- a/storage/innobase/include/buf0buf.h	revid:jimmy.yang@stripped
+++ b/storage/innobase/include/buf0buf.h	revid:inaam.rana@stripped
@@ -69,8 +69,8 @@ Created 11/5/1995 Heikki Tuuri
 #define BUF_POOL_WATCH_SIZE		(srv_n_purge_threads + 1)
 					/*!< Maximum number of concurrent
 					buffer pool watches */
-#define MAX_PAGE_HASH_MUTEXES	1024	/*!< The maximum number of
-					page_hash mutexes */
+#define MAX_PAGE_HASH_LOCKS	1024	/*!< The maximum number of
+					page_hash locks */
 
 extern	buf_pool_t*	buf_pool_ptr;	/*!< The buffer pools
 					of the database */
@@ -1161,49 +1161,77 @@ buf_page_hash_get_low(
 	ulint		fold);	/*!< in: buf_page_address_fold(space, offset) */
 /******************************************************************//**
 Returns the control block of a file page, NULL if not found.
-If the block is found and mutex is not NULL then the appropriate
-page_hash mutex is acquired. It is up to the caller to release the
-mutex. If the block is found and the mutex is NULL then the page_hash
-mutex is released by this function.
+If the block is found and lock is not NULL then the appropriate
+page_hash lock is acquired in the specified lock mode. Otherwise,
+mode value is ignored. It is up to the caller to release the
+lock. If the block is found and the lock is NULL then the page_hash
+lock is released by this function.
 @return	block, NULL if not found */
 UNIV_INLINE
 buf_page_t*
-buf_page_hash_get(
-/*==============*/
+buf_page_hash_get_locked(
+/*=====================*/
 					/*!< out: pointer to the bpage,
-					or NULL; if NULL, hash_mutex
+					or NULL; if NULL, hash_lock
 					is also NULL. */
 	buf_pool_t*	buf_pool,	/*!< buffer pool instance */
 	ulint		space,		/*!< in: space id */
 	ulint		offset,		/*!< in: page number */
-	mutex_t**	mutex);		/*!< in/out: mutex of the page
+	rw_lock_t**	lock,		/*!< in/out: lock of the page
 					hash acquired if bpage is
 					found. NULL otherwise. If NULL
-					is passed then the hash_mutex
+					is passed then the hash_lock
 					is released by this function */
+	ulint		lock_mode);	/*!< in: RW_LOCK_EX or
+					RW_LOCK_SHARED. Ignored if
+					lock == NULL */
 /******************************************************************//**
-Returns the control block of a file page, NULL if not found or an
-uncompressed page frame does not exist.
-If the block is found and mutex is not NULL then the appropriate
-page_hash mutex is acquired. It is upto the caller to release the
-mutex. If the block is found and the mutex is NULL then the page_hash
-mutex is released by this function.
+Returns the control block of a file page, NULL if not found.
+If the block is found and lock is not NULL then the appropriate
+page_hash lock is acquired in the specified lock mode. Otherwise,
+mode value is ignored. It is up to the caller to release the
+lock. If the block is found and the lock is NULL then the page_hash
+lock is released by this function.
 @return	block, NULL if not found */
 UNIV_INLINE
 buf_block_t*
-buf_block_hash_get(
-/*===============*/
+buf_block_hash_get_locked(
+/*=====================*/
 					/*!< out: pointer to the bpage,
-					or NULL; if NULL, hash_mutex
+					or NULL; if NULL, hash_lock
 					is also NULL. */
 	buf_pool_t*	buf_pool,	/*!< buffer pool instance */
 	ulint		space,		/*!< in: space id */
 	ulint		offset,		/*!< in: page number */
-	mutex_t**	mutex);		/*!< in/out: mutex of the page
+	rw_lock_t**	lock,		/*!< in/out: lock of the page
 					hash acquired if bpage is
 					found. NULL otherwise. If NULL
-					is passed then the hash_mutex
+					is passed then the hash_lock
 					is released by this function */
+	ulint		lock_mode);	/*!< in: RW_LOCK_EX or
+					RW_LOCK_SHARED. Ignored if
+					lock == NULL */
+/* There are four different ways we can try to get a bpage or block
+from the page hash:
+1) Caller already holds the appropriate page hash lock: in the case call
+buf_page_hash_get_low() function.
+2) Caller wants to hold page hash lock in x-mode
+3) Caller wants to hold page hash lock in s-mode
+4) Caller doesn't want to hold page hash lock */
+#define buf_page_hash_get_s_locked(b, s, o, l)			\
+	buf_page_hash_get_locked(b, s, o, l, RW_LOCK_SHARED)
+#define buf_page_hash_get_x_locked(b, s, o, l)			\
+	buf_page_hash_get_locked(b, s, o, l, RW_LOCK_EX)
+#define buf_page_hash_get(b, s, o)				\
+	buf_page_hash_get_locked(b, s, o, NULL, 0)
+
+#define buf_block_hash_get_s_locked(b, s, o, l)			\
+	buf_block_hash_get_locked(b, s, o, l, RW_LOCK_SHARED)
+#define buf_block_hash_get_x_locked(b, s, o, l)			\
+	buf_block_hash_get_locked(b, s, o, l, RW_LOCK_EX)
+#define buf_block_hash_get(b, s, o)				\
+	buf_block_hash_get_locked(b, s, o, NULL, 0)
+
 /*********************************************************************//**
 Gets the current length of the free list of buffer blocks.
 @return	length of the free list */
@@ -1809,19 +1837,46 @@ Use these instead of accessing buf_pool-
 
 
 
-/** Get appropriate page_hash_mutex. */
-#define buf_page_hash_mutex_get(b, f)		\
-	hash_get_mutex(b->page_hash, f)
-
-/** Test if page_hash mutex is owned. */
-#define buf_page_hash_mutex_own(b, p)			\
-	mutex_own(buf_page_hash_mutex_get(b,		\
+/** Get appropriate page_hash_lock. */
+# define buf_page_hash_lock_get(b, f)		\
+	hash_get_lock(b->page_hash, f)
+
+#ifdef UNIV_SYNC_DEBUG
+/** Test if page_hash lock is held in s-mode. */
+# define buf_page_hash_lock_held_s(b, p)		\
+	rw_lock_own(buf_page_hash_lock_get(b,		\
+		  buf_page_address_fold(p->space,	\
+					p->offset)),	\
+					RW_LOCK_SHARED)
+
+/** Test if page_hash lock is held in x-mode. */
+# define buf_page_hash_lock_held_x(b, p)		\
+	rw_lock_own(buf_page_hash_lock_get(b,		\
 		  buf_page_address_fold(p->space,	\
-					p->offset)))
-#define buf_block_hash_mutex_own(b, p)			\
-	mutex_own(buf_page_hash_mutex_get(b,		\
-		  buf_page_address_fold(p->page.space,	\
-					p->page.offset)))
+					p->offset)),	\
+					RW_LOCK_EX)
+
+/** Test if page_hash lock is held in x or s-mode. */
+# define buf_page_hash_lock_held_s_or_x(b, p)		\
+	(buf_page_hash_lock_held_s(b, p)		\
+	 || buf_page_hash_lock_held_x(b, p))
+
+# define buf_block_hash_lock_held_s(b, p)		\
+	buf_page_hash_lock_held_s(b, &(p->page))
+
+# define buf_block_hash_lock_held_x(b, p)		\
+	buf_page_hash_lock_held_x(b, &(p->page))
+
+# define buf_block_hash_lock_held_s_or_x(b, p)		\
+	buf_page_hash_lock_held_s_or_x(b, &(p->page))
+#else /* UNIV_SYNC_DEBUG */
+# define buf_page_hash_lock_held_s(b, p)	(TRUE)
+# define buf_page_hash_lock_held_x(b, p)	(TRUE)
+# define buf_page_hash_lock_held_s_or_x(b, p)	(TRUE)
+# define buf_block_hash_lock_held_s(b, p)	(TRUE)
+# define buf_block_hash_lock_held_x(b, p)	(TRUE)
+# define buf_block_hash_lock_held_s_or_x(b, p)	(TRUE)
+#endif /* UNIV_SYNC_DEBUG */
 
 #if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG
 /** Forbid the release of the buffer pool mutex. */

=== modified file 'storage/innobase/include/buf0buf.ic'
--- a/storage/innobase/include/buf0buf.ic	revid:jimmy.yang@stripped
+++ b/storage/innobase/include/buf0buf.ic	revid:inaam.rana@stripped
@@ -975,18 +975,19 @@ buf_page_hash_get_low(
 {
 	buf_page_t*	bpage;
 
-#ifdef UNIV_DEBUG
-	ulint		hash_fold;
-	mutex_t*	hash_mutex;
-
 	ut_ad(buf_pool);
 
+#ifdef UNIV_SYNC_DEBUG
+	ulint		hash_fold;
+	rw_lock_t*	hash_lock;
+
 	hash_fold = buf_page_address_fold(space, offset);
 	ut_ad(hash_fold == fold);
 
-	hash_mutex = hash_get_mutex(buf_pool->page_hash, fold);
-	ut_ad(mutex_own(hash_mutex));
-#endif /* UNIV_DEBUG */
+	hash_lock = hash_get_lock(buf_pool->page_hash, fold);
+	ut_ad(rw_lock_own(hash_lock, RW_LOCK_EX)
+	      || rw_lock_own(hash_lock, RW_LOCK_SHARED));
+#endif /* UNIV_SYNC_DEBUG */
 
 	/* Look for the page in the hash table */
 
@@ -1011,105 +1012,144 @@ buf_page_hash_get_low(
 
 /******************************************************************//**
 Returns the control block of a file page, NULL if not found.
-If the block is found and mutex is not NULL then the appropriate
-page_hash mutex is acquired. It is up to the caller to release the
-mutex. If the block is found and the mutex is NULL then the page_hash
-mutex is released by this function.
+If the block is found and lock is not NULL then the appropriate
+page_hash lock is acquired in the specified lock mode. Otherwise,
+mode value is ignored. It is up to the caller to release the
+lock. If the block is found and the lock is NULL then the page_hash
+lock is released by this function.
 @return	block, NULL if not found */
 UNIV_INLINE
 buf_page_t*
-buf_page_hash_get(
-/*==============*/
+buf_page_hash_get_locked(
+/*=====================*/
 					/*!< out: pointer to the bpage,
-					or NULL; if NULL, hash_mutex
+					or NULL; if NULL, hash_lock
 					is also NULL. */
 	buf_pool_t*	buf_pool,	/*!< buffer pool instance */
 	ulint		space,		/*!< in: space id */
 	ulint		offset,		/*!< in: page number */
-	mutex_t**	mutex)		/*!< in/out: mutex of the page
+	rw_lock_t**	lock,		/*!< in/out: lock of the page
 					hash acquired if bpage is
 					found. NULL otherwise. If NULL
-					is passed then the hash_mutex
+					is passed then the hash_lock
 					is released by this function */
+	ulint		lock_mode)	/*!< in: RW_LOCK_EX or
+					RW_LOCK_SHARED. Ignored if
+					lock == NULL */
 {
-	buf_page_t*	bpage;
+	buf_page_t*	bpage = NULL;
 	ulint		fold;
-	mutex_t*	hash_mutex;
+	rw_lock_t*	hash_lock;
+	ulint		mode = RW_LOCK_SHARED;
 
-	if (mutex != NULL) {
-		*mutex = NULL;
+	if (lock != NULL) {
+		*lock = NULL;
+		ut_ad(lock_mode == RW_LOCK_EX
+		      || lock_mode == RW_LOCK_SHARED);
+		mode = lock_mode;
 	}
 
 	fold = buf_page_address_fold(space, offset);
-	hash_mutex = hash_get_mutex(buf_pool->page_hash, fold);
+	hash_lock = hash_get_lock(buf_pool->page_hash, fold);
+
+#ifdef UNIV_SYNC_DEBUG
+	ut_ad(!rw_lock_own(hash_lock, RW_LOCK_EX)
+	      && !rw_lock_own(hash_lock, RW_LOCK_SHARED));
+#endif /* UNIV_SYNC_DEBUG */
+
+	if (mode == RW_LOCK_SHARED) {
+		rw_lock_s_lock(hash_lock);
+	} else {
+		rw_lock_x_lock(hash_lock);
+	}
 
-	mutex_enter(hash_mutex);
 	bpage = buf_page_hash_get_low(buf_pool, space, offset, fold);
 
 	if (!bpage || UNIV_UNLIKELY(buf_pool_watch_is_sentinel(buf_pool, bpage))) {
-		mutex_exit(hash_mutex);
-		return(NULL);
+		bpage = NULL;
+		goto unlock_and_exit;
 	}
 
 	ut_ad(buf_page_in_file(bpage));
 	ut_ad(offset == bpage->offset);
 	ut_ad(space == bpage->space);
 
-	if (mutex == NULL) {
-		/* The caller wants us to release the page_hash mutex */
-		mutex_exit(hash_mutex);
+	if (lock == NULL) {
+		/* The caller wants us to release the page_hash lock */
+		goto unlock_and_exit;
 	} else {
 		/* To be released by the caller */
-		*mutex = hash_mutex;
+		*lock = hash_lock;
+		goto exit;
 	}
 
+unlock_and_exit:
+	if (mode == RW_LOCK_SHARED) {
+		rw_lock_s_unlock(hash_lock);
+	} else {
+		rw_lock_x_unlock(hash_lock);
+	}
+exit:
 	return(bpage);
 }
 
 /******************************************************************//**
-Returns the control block of a file page, NULL if not found or an
-uncompressed page frame does not exist.
-If the block is found and mutex is not NULL then the appropriate
-page_hash mutex is acquired. It is upto the caller to release the
-mutex. If the block is found and the mutex is NULL then the page_hash
-mutex is released by this function.
+Returns the control block of a file page, NULL if not found.
+If the block is found and lock is not NULL then the appropriate
+page_hash lock is acquired in the specified lock mode. Otherwise,
+mode value is ignored. It is up to the caller to release the
+lock. If the block is found and the lock is NULL then the page_hash
+lock is released by this function.
 @return	block, NULL if not found */
 UNIV_INLINE
 buf_block_t*
-buf_block_hash_get(
-/*===============*/
+buf_block_hash_get_locked(
+/*=====================*/
 					/*!< out: pointer to the bpage,
-					or NULL; if NULL, hash_mutex
+					or NULL; if NULL, hash_lock
 					is also NULL. */
 	buf_pool_t*	buf_pool,	/*!< buffer pool instance */
 	ulint		space,		/*!< in: space id */
 	ulint		offset,		/*!< in: page number */
-	mutex_t**	mutex)		/*!< in/out: mutex of the page
+	rw_lock_t**	lock,		/*!< in/out: lock of the page
 					hash acquired if bpage is
 					found. NULL otherwise. If NULL
-					is passed then the hash_mutex
+					is passed then the hash_lock
 					is released by this function */
+	ulint		lock_mode)	/*!< in: RW_LOCK_EX or
+					RW_LOCK_SHARED. Ignored if
+					lock == NULL */
 {
-	buf_page_t*	bpage = buf_page_hash_get(buf_pool, space, offset, mutex);
+	buf_page_t*	bpage = buf_page_hash_get_locked(buf_pool,
+							 space,
+							 offset,
+							 lock,
+							 lock_mode);
 	buf_block_t*	block = buf_page_get_block(bpage);
 
 	if (block) {
 		ut_ad(buf_block_get_state(block) == BUF_BLOCK_FILE_PAGE);
-		ut_ad(!mutex || mutex_own(*mutex));
+#ifdef UNIV_SYNC_DEBUG
+		ut_ad(!lock || rw_lock_own(*lock, lock_mode));
+#endif /* UNIV_SYNC_DEBUG */
 		return(block);
 	} else if (bpage) {
 		/* It is not a block. Just a bpage */
 		ut_ad(buf_page_in_file(bpage));
 
-		if (mutex) {
-			mutex_exit(*mutex);
+		if (lock) {
+			if (lock_mode == RW_LOCK_SHARED) {
+				rw_lock_s_unlock(*lock);
+			} else {
+				rw_lock_x_unlock(*lock);
+			}
 		}
-		*mutex = NULL;
+		*lock = NULL;
 		return(NULL);
 	}
 
 	ut_ad(!bpage);
-	ut_ad(mutex == NULL ||*mutex == NULL);
+	ut_ad(lock == NULL ||*lock == NULL);
 	return(NULL);
 }
 
@@ -1129,7 +1169,7 @@ buf_page_peek(
 {
 	buf_pool_t*		buf_pool = buf_pool_get(space, offset);
 
-	return(buf_page_hash_get(buf_pool, space, offset, NULL) != NULL);
+	return(buf_page_hash_get(buf_pool, space, offset) != NULL);
 }
 
 /********************************************************************//**

=== modified file 'storage/innobase/include/ha0ha.h'
--- a/storage/innobase/include/ha0ha.h	revid:jimmy.yang@stripped
+++ b/storage/innobase/include/ha0ha.h	revid:inaam.rana@stripped
@@ -225,20 +225,33 @@ struct ha_node_struct {
 	ulint		fold;	/*!< fold value for the data */
 };
 
-#ifndef UNIV_HOTBACKUP
-/** Assert that the current thread is holding the mutex protecting a
-hash bucket corresponding to a fold value.
-@param table	in: hash table
-@param fold	in: fold value */
-# define ASSERT_HASH_MUTEX_OWN(table, fold)				\
-	ut_ad(!(table)->mutexes || mutex_own(hash_get_mutex(table, fold)))
-#else /* !UNIV_HOTBACKUP */
-/** Assert that the current thread is holding the mutex protecting a
-hash bucket corresponding to a fold value.
-@param table	in: hash table
-@param fold	in: fold value */
-# define ASSERT_HASH_MUTEX_OWN(table, fold) ((void) 0)
-#endif /* !UNIV_HOTBACKUP */
+#ifdef UNIV_DEBUG
+/********************************************************************//**
+Assert that the synchronization object in a hash operation involving
+possible change in the hash table is held.
+Note that in case of mutexes we assert that mutex is owned while in case
+of rw-locks we assert that it is held in exclusive mode. */
+UNIV_INLINE
+void
+hash_assert_can_modify(
+/*===================*/
+	hash_table_t*	table,	/*!< in: hash table */
+	ulint		fold);	/*!< in: fold value */
+/********************************************************************//**
+Assert that the synchronization object in a hash search operation is held.
+Note that in case of mutexes we assert that mutex is owned while in case
+of rw-locks we assert that it is held either in x-mode or s-mode. */
+UNIV_INLINE
+void
+hash_assert_can_search(
+/*===================*/
+	hash_table_t*	table,	/*!< in: hash table */
+	ulint		fold);	/*!< in: fold value */
+#else /* UNIV_DEBUG */
+#define hash_assert_can_modify(t, f)
+#define hash_assert_can_search(t, f)
+#endif /* UNIV_DEBUG */
+
 
 #ifndef UNIV_NONINL
 #include "ha0ha.ic"

=== modified file 'storage/innobase/include/ha0ha.ic'
--- a/storage/innobase/include/ha0ha.ic	revid:jimmy.yang@stripped
+++ b/storage/innobase/include/ha0ha.ic	revid:inaam.rana@stripped
@@ -105,6 +105,56 @@ ha_chain_get_first(
 	       hash_get_nth_cell(table, hash_calc_hash(fold, table))->node);
 }
 
+#ifdef UNIV_DEBUG
+/********************************************************************//**
+Assert that the synchronization object in a hash operation involving
+possible change in the hash table is held.
+Note that in case of mutexes we assert that mutex is owned while in case
+of rw-locks we assert that it is held in exclusive mode. */
+UNIV_INLINE
+void
+hash_assert_can_modify(
+/*===================*/
+	hash_table_t*	table,	/*!< in: hash table */
+	ulint		fold)	/*!< in: fold value */
+{
+	if (table->type == HASH_TABLE_SYNC_MUTEX) {
+		ut_ad(mutex_own(hash_get_mutex(table, fold)));
+	} else if (table->type == HASH_TABLE_SYNC_RW_LOCK) {
+# ifdef UNIV_SYNC_DEBUG
+		rw_lock_t* lock = hash_get_lock(table, fold);
+		ut_ad(rw_lock_own(lock, RW_LOCK_EX));
+# endif
+	} else {
+		ut_ad(table->type == HASH_TABLE_SYNC_NONE);
+	}
+}
+
+/********************************************************************//**
+Assert that the synchronization object in a hash search operation is held.
+Note that in case of mutexes we assert that mutex is owned while in case
+of rw-locks we assert that it is held either in x-mode or s-mode. */
+UNIV_INLINE
+void
+hash_assert_can_search(
+/*===================*/
+	hash_table_t*	table,	/*!< in: hash table */
+	ulint		fold)	/*!< in: fold value */
+{
+	if (table->type == HASH_TABLE_SYNC_MUTEX) {
+		ut_ad(mutex_own(hash_get_mutex(table, fold)));
+	} else if (table->type == HASH_TABLE_SYNC_RW_LOCK) {
+# ifdef UNIV_SYNC_DEBUG
+		rw_lock_t* lock = hash_get_lock(table, fold);
+		ut_ad(rw_lock_own(lock, RW_LOCK_EX)
+		      || rw_lock_own(lock, RW_LOCK_SHARED));
+# endif
+	} else {
+		ut_ad(table->type == HASH_TABLE_SYNC_NONE);
+	}
+}
+#endif /* UNIV_DEBUG */
+
 /*************************************************************//**
 Looks for an element in a hash table.
 @return pointer to the first hash table node in chain having the fold
@@ -118,7 +168,7 @@ ha_search(
 {
 	ha_node_t*	node;
 
-	ASSERT_HASH_MUTEX_OWN(table, fold);
+	hash_assert_can_search(table, fold);
 
 	node = ha_chain_get_first(table, fold);
 
@@ -147,7 +197,7 @@ ha_search_and_get_data(
 {
 	ha_node_t*	node;
 
-	ASSERT_HASH_MUTEX_OWN(table, fold);
+	hash_assert_can_search(table, fold);
 
 	node = ha_chain_get_first(table, fold);
 
@@ -176,7 +226,7 @@ ha_search_with_data(
 {
 	ha_node_t*	node;
 
-	ASSERT_HASH_MUTEX_OWN(table, fold);
+	hash_assert_can_search(table, fold);
 
 	node = ha_chain_get_first(table, fold);
 
@@ -206,7 +256,7 @@ ha_search_and_delete_if_found(
 {
 	ha_node_t*	node;
 
-	ASSERT_HASH_MUTEX_OWN(table, fold);
+	hash_assert_can_modify(table, fold);
 
 	node = ha_search_with_data(table, fold, data);
 

=== modified file 'storage/innobase/include/hash0hash.h'
--- a/storage/innobase/include/hash0hash.h	revid:jimmy.yang@stripped
+++ b/storage/innobase/include/hash0hash.h	revid:inaam.rana@stripped
@@ -30,6 +30,7 @@ Created 5/20/1997 Heikki Tuuri
 #include "mem0mem.h"
 #ifndef UNIV_HOTBACKUP
 # include "sync0sync.h"
+# include "sync0rw.h"
 #endif /* !UNIV_HOTBACKUP */
 
 typedef struct hash_table_struct hash_table_t;
@@ -40,6 +41,18 @@ typedef void*	hash_node_t;
 /* Fix Bug #13859: symbol collision between imap/mysql */
 #define hash_create hash0_create
 
+/* Differnt types of hash_table based on the synchronization
+method used for it. */
+enum hash_table_sync_t {
+	HASH_TABLE_SYNC_NONE = 0,	/*!< Don't use any internal
+					synchronization objects for
+					this hash_table. */
+	HASH_TABLE_SYNC_MUTEX,		/*!< Use mutexes to control
+					access to this hash_table. */
+	HASH_TABLE_SYNC_RW_LOCK,	/*!< Use rw_locks to control
+					access to this hash_table. */
+};
+
 /*************************************************************//**
 Creates a hash table with >= n array cells. The actual number
 of cells is chosen to be a prime number slightly bigger than n.
@@ -51,21 +64,29 @@ hash_create(
 	ulint	n);	/*!< in: number of array cells */
 #ifndef UNIV_HOTBACKUP
 /*************************************************************//**
-Creates a mutex array to protect a hash table. */
+Creates a sync object array array to protect a hash table.
+::sync_obj can be mutexes or rw_locks depening on the type of
+hash table. */
 UNIV_INTERN
 void
-hash_create_mutexes_func(
-/*=====================*/
-	hash_table_t*	table,		/*!< in: hash table */
+hash_create_sync_obj_func(
+/*======================*/
+	hash_table_t*		table,	/*!< in: hash table */
+	enum hash_table_sync_t	type,	/*!< in: HASH_TABLE_SYNC_MUTEX
+					or HASH_TABLE_SYNC_RW_LOCK */
 #ifdef UNIV_SYNC_DEBUG
-	ulint		sync_level,	/*!< in: latching order level of the
-					mutexes: used in the debug version */
+	ulint			sync_level,/*!< in: latching order level
+					of the mutexes: used in the
+					debug version */
 #endif /* UNIV_SYNC_DEBUG */
-	ulint		n_mutexes);	/*!< in: number of mutexes */
+	ulint			n_sync_obj);/*!< in: number of sync objects,
+					must be a power of 2 */
 #ifdef UNIV_SYNC_DEBUG
-# define hash_create_mutexes(t,n,level) hash_create_mutexes_func(t,level,n)
+# define hash_create_sync_obj(t, s, n, level)			\
+			hash_create_sync_obj_func(t, s, level, n)
 #else /* UNIV_SYNC_DEBUG */
-# define hash_create_mutexes(t,n,level) hash_create_mutexes_func(t,n)
+# define hash_create_sync_obj(t, s, n, level)			\
+			hash_create_sync_obj_func(t, s, n)
 #endif /* UNIV_SYNC_DEBUG */
 #endif /* !UNIV_HOTBACKUP */
 
@@ -87,11 +108,12 @@ hash_calc_hash(
 	hash_table_t*	table);	/*!< in: hash table */
 #ifndef UNIV_HOTBACKUP
 /********************************************************************//**
-Assert that the mutex for the table in a hash operation is owned. */
-# define HASH_ASSERT_OWNED(TABLE, FOLD)					\
-ut_ad(!(TABLE)->mutexes || mutex_own(hash_get_mutex(TABLE, FOLD)));
+Assert that the mutex for the table is held */
+# define HASH_ASSERT_OWN(TABLE, FOLD)				\
+	ut_ad((TABLE)->type != HASH_TABLE_SYNC_MUTEX		\
+	      || (mutex_own(hash_get_mutex((TABLE), FOLD))));
 #else /* !UNIV_HOTBACKUP */
-# define HASH_ASSERT_OWNED(TABLE, FOLD)
+# define HASH_ASSERT_OWN(TABLE, FOLD)
 #endif /* !UNIV_HOTBACKUP */
 
 /*******************************************************************//**
@@ -102,7 +124,7 @@ do {\
 	hash_cell_t*	cell3333;\
 	TYPE*		struct3333;\
 \
-	HASH_ASSERT_OWNED(TABLE, FOLD)\
+	HASH_ASSERT_OWN(TABLE, FOLD)\
 \
 	(DATA)->NAME = NULL;\
 \
@@ -138,7 +160,7 @@ do {\
 	hash_cell_t*	cell3333;\
 	TYPE*		struct3333;\
 \
-	HASH_ASSERT_OWNED(TABLE, FOLD)\
+	HASH_ASSERT_OWN(TABLE, FOLD)\
 \
 	cell3333 = hash_get_nth_cell(TABLE, hash_calc_hash(FOLD, TABLE));\
 \
@@ -175,7 +197,7 @@ Looks for a struct in a hash table. */
 #define HASH_SEARCH(NAME, TABLE, FOLD, TYPE, DATA, ASSERTION, TEST)\
 {\
 \
-	HASH_ASSERT_OWNED(TABLE, FOLD)\
+	HASH_ASSERT_OWN(TABLE, FOLD)\
 \
 	(DATA) = (TYPE) HASH_GET_FIRST(TABLE, hash_calc_hash(FOLD, TABLE));\
 	HASH_ASSERT_VALID(DATA);\
@@ -329,12 +351,12 @@ do {\
 } while (0)
 
 /************************************************************//**
-Gets the mutex index for a fold value in a hash table.
-@return	mutex number */
+Gets the sync object index for a fold value in a hash table.
+@return	index */
 UNIV_INLINE
 ulint
-hash_get_mutex_no(
-/*==============*/
+hash_get_sync_obj_index(
+/*====================*/
 	hash_table_t*	table,	/*!< in: hash table */
 	ulint		fold);	/*!< in: fold */
 /************************************************************//**
@@ -365,6 +387,15 @@ hash_get_nth_mutex(
 	hash_table_t*	table,	/*!< in: hash table */
 	ulint		i);	/*!< in: index of the mutex */
 /************************************************************//**
+Gets the nth rw_lock in a hash table.
+@return	rw_lock */
+UNIV_INLINE
+rw_lock_t*
+hash_get_nth_lock(
+/*==============*/
+	hash_table_t*	table,	/*!< in: hash table */
+	ulint		i);	/*!< in: index of the rw_lock */
+/************************************************************//**
 Gets the mutex for a fold value in a hash table.
 @return	mutex */
 UNIV_INLINE
@@ -374,6 +405,15 @@ hash_get_mutex(
 	hash_table_t*	table,	/*!< in: hash table */
 	ulint		fold);	/*!< in: fold */
 /************************************************************//**
+Gets the rw_lock for a fold value in a hash table.
+@return	rw_lock */
+UNIV_INLINE
+rw_lock_t*
+hash_get_lock(
+/*==========*/
+	hash_table_t*	table,	/*!< in: hash table */
+	ulint		fold);	/*!< in: fold */
+/************************************************************//**
 Reserves the mutex for a fold value in a hash table. */
 UNIV_INTERN
 void
@@ -411,10 +451,76 @@ hash_mutex_exit_all_but(
 /*====================*/
 	hash_table_t*	table,		/*!< in: hash table */
 	mutex_t*	keep_mutex);	/*!< in: mutex to keep */
+/************************************************************//**
+s-lock a lock for a fold value in a hash table. */
+UNIV_INTERN
+void
+hash_lock_s(
+/*========*/
+	hash_table_t*	table,	/*!< in: hash table */
+	ulint		fold);	/*!< in: fold */
+/************************************************************//**
+x-lock a lock for a fold value in a hash table. */
+UNIV_INTERN
+void
+hash_lock_x(
+/*========*/
+	hash_table_t*	table,	/*!< in: hash table */
+	ulint		fold);	/*!< in: fold */
+/************************************************************//**
+unlock an s-lock for a fold value in a hash table. */
+UNIV_INTERN
+void
+hash_unlock_s(
+/*==========*/
+
+	hash_table_t*	table,	/*!< in: hash table */
+	ulint		fold);	/*!< in: fold */
+/************************************************************//**
+unlock x-lock for a fold value in a hash table. */
+UNIV_INTERN
+void
+hash_unlock_x(
+/*==========*/
+	hash_table_t*	table,	/*!< in: hash table */
+	ulint		fold);	/*!< in: fold */
+/************************************************************//**
+Reserves all the locks of a hash table, in an ascending order. */
+UNIV_INTERN
+void
+hash_lock_x_all(
+/*============*/
+	hash_table_t*	table);	/*!< in: hash table */
+/************************************************************//**
+Releases all the locks of a hash table, in an ascending order. */
+UNIV_INTERN
+void
+hash_unlock_x_all(
+/*==============*/
+	hash_table_t*	table);	/*!< in: hash table */
+/************************************************************//**
+Releases all but passed in lock of a hash table, */
+UNIV_INTERN
+void
+hash_unlock_x_all_but(
+/*==================*/
+	hash_table_t*	table,		/*!< in: hash table */
+	rw_lock_t*	keep_lock);	/*!< in: lock to keep */
+
 #else /* !UNIV_HOTBACKUP */
 # define hash_get_heap(table, fold)	((table)->heap)
 # define hash_mutex_enter(table, fold)	((void) 0)
 # define hash_mutex_exit(table, fold)	((void) 0)
+# define hash_mutex_enter_all(table)	((void) 0)
+# define hash_mutex_exit_all(table)	((void) 0)
+# define hash_mutex_exit_all_but(t, m)	((void) 0)
+# define hash_lock_s(t, f)		((void) 0)
+# define hash_lock_x(t, f)		((void) 0)
+# define hash_unlock_s(t, f)		((void) 0)
+# define hash_unlock_x(t, f)		((void) 0)
+# define hash_lock_x_all(t)		((void) 0)
+# define hash_unlock_x_all(t)		((void) 0)
+# define hash_unlock_x_all_but(t, l)	((void) 0)
 #endif /* !UNIV_HOTBACKUP */
 
 struct hash_cell_struct{
@@ -423,27 +529,40 @@ struct hash_cell_struct{
 
 /* The hash table structure */
 struct hash_table_struct {
+	enum hash_table_sync_t	type;	/*<! type of hash_table. */
 #if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG
 # ifndef UNIV_HOTBACKUP
-	ibool		adaptive;/* TRUE if this is the hash table of the
-				adaptive hash index */
+	ibool			adaptive;/* TRUE if this is the hash
+					table of the adaptive hash
+					index */
 # endif /* !UNIV_HOTBACKUP */
 #endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */
-	ulint		n_cells;/* number of cells in the hash table */
-	hash_cell_t*	array;	/*!< pointer to cell array */
+	ulint			n_cells;/* number of cells in the hash table */
+	hash_cell_t*		array;	/*!< pointer to cell array */
 #ifndef UNIV_HOTBACKUP
-	ulint		n_mutexes;/* if mutexes != NULL, then the number of
-				mutexes, must be a power of 2 */
-	mutex_t*	mutexes;/* NULL, or an array of mutexes used to
-				protect segments of the hash table */
-	mem_heap_t**	heaps;	/*!< if this is non-NULL, hash chain nodes for
-				external chaining can be allocated from these
-				memory heaps; there are then n_mutexes many of
-				these heaps */
+	ulint			n_sync_obj;/* if sync_objs != NULL, then
+					the number of either the number
+					of mutexes or the number of
+					rw_locks depending on the type.
+					Must be a power of 2 */
+	union {
+		mutex_t*	mutexes;/* NULL, or an array of mutexes
+					used to protect segments of the
+					hash table */
+		rw_lock_t*	rw_locks;/* NULL, or an array of rw_lcoks
+					used to protect segments of the
+					hash table */
+	} sync_obj;
+
+	mem_heap_t**		heaps;	/*!< if this is non-NULL, hash
+					chain nodes for external chaining
+					can be allocated from these memory
+					heaps; there are then n_mutexes
+					many of these heaps */
 #endif /* !UNIV_HOTBACKUP */
-	mem_heap_t*	heap;
+	mem_heap_t*		heap;
 #ifdef UNIV_DEBUG
-	ulint		magic_n;
+	ulint			magic_n;
 # define HASH_TABLE_MAGIC_N	76561114
 #endif /* UNIV_DEBUG */
 };

=== modified file 'storage/innobase/include/hash0hash.ic'
--- a/storage/innobase/include/hash0hash.ic	revid:jimmy.yang@stripped
+++ b/storage/innobase/include/hash0hash.ic	revid:inaam.rana@stripped
@@ -87,20 +87,21 @@ hash_calc_hash(
 
 #ifndef UNIV_HOTBACKUP
 /************************************************************//**
-Gets the mutex index for a fold value in a hash table.
-@return	mutex number */
+Gets the sync object index for a fold value in a hash table.
+@return	index */
 UNIV_INLINE
 ulint
-hash_get_mutex_no(
-/*==============*/
+hash_get_sync_obj_index(
+/*====================*/
 	hash_table_t*	table,	/*!< in: hash table */
 	ulint		fold)	/*!< in: fold */
 {
 	ut_ad(table);
 	ut_ad(table->magic_n == HASH_TABLE_MAGIC_N);
-	ut_ad(ut_is_2pow(table->n_mutexes));
+	ut_ad(table->type != HASH_TABLE_SYNC_NONE);
+	ut_ad(ut_is_2pow(table->n_sync_obj));
 	return(ut_2pow_remainder(hash_calc_hash(fold, table),
-				 table->n_mutexes));
+				 table->n_sync_obj));
 }
 
 /************************************************************//**
@@ -115,7 +116,8 @@ hash_get_nth_heap(
 {
 	ut_ad(table);
 	ut_ad(table->magic_n == HASH_TABLE_MAGIC_N);
-	ut_ad(i < table->n_mutexes);
+	ut_ad(table->type != HASH_TABLE_SYNC_NONE);
+	ut_ad(i < table->n_sync_obj);
 
 	return(table->heaps[i]);
 }
@@ -139,7 +141,7 @@ hash_get_heap(
 		return(table->heap);
 	}
 
-	i = hash_get_mutex_no(table, fold);
+	i = hash_get_sync_obj_index(table, fold);
 
 	return(hash_get_nth_heap(table, i));
 }
@@ -156,9 +158,10 @@ hash_get_nth_mutex(
 {
 	ut_ad(table);
 	ut_ad(table->magic_n == HASH_TABLE_MAGIC_N);
-	ut_ad(i < table->n_mutexes);
+	ut_ad(table->type == HASH_TABLE_SYNC_MUTEX);
+	ut_ad(i < table->n_sync_obj);
 
-	return(table->mutexes + i);
+	return(table->sync_obj.mutexes + i);
 }
 
 /************************************************************//**
@@ -176,8 +179,47 @@ hash_get_mutex(
 	ut_ad(table);
 	ut_ad(table->magic_n == HASH_TABLE_MAGIC_N);
 
-	i = hash_get_mutex_no(table, fold);
+	i = hash_get_sync_obj_index(table, fold);
 
 	return(hash_get_nth_mutex(table, i));
 }
+
+/************************************************************//**
+Gets the nth rw_lock in a hash table.
+@return	rw_lock */
+UNIV_INLINE
+rw_lock_t*
+hash_get_nth_lock(
+/*==============*/
+	hash_table_t*	table,	/*!< in: hash table */
+	ulint		i)	/*!< in: index of the rw_lock */
+{
+	ut_ad(table);
+	ut_ad(table->magic_n == HASH_TABLE_MAGIC_N);
+	ut_ad(table->type == HASH_TABLE_SYNC_RW_LOCK);
+	ut_ad(i < table->n_sync_obj);
+
+	return(table->sync_obj.rw_locks + i);
+}
+
+/************************************************************//**
+Gets the rw_lock for a fold value in a hash table.
+@return	rw_lock */
+UNIV_INLINE
+rw_lock_t*
+hash_get_lock(
+/*==========*/
+	hash_table_t*	table,	/*!< in: hash table */
+	ulint		fold)	/*!< in: fold */
+{
+	ulint	i;
+
+	ut_ad(table);
+	ut_ad(table->type == HASH_TABLE_SYNC_RW_LOCK);
+	ut_ad(table->magic_n == HASH_TABLE_MAGIC_N);
+
+	i = hash_get_sync_obj_index(table, fold);
+
+	return(hash_get_nth_lock(table, i));
+}
 #endif /* !UNIV_HOTBACKUP */

=== modified file 'storage/innobase/include/srv0srv.h'
--- a/storage/innobase/include/srv0srv.h	revid:jimmy.yang@stripped
+++ b/storage/innobase/include/srv0srv.h	revid:inaam.rana@stripped
@@ -155,7 +155,7 @@ extern ibool	srv_use_sys_malloc;
 #endif /* UNIV_HOTBACKUP */
 extern ulint	srv_buf_pool_size;	/*!< requested size in bytes */
 extern ulint    srv_buf_pool_instances; /*!< requested number of buffer pool instances */
-extern ulong	srv_n_page_hash_mutexes;/*!< number of mutexes to
+extern ulong	srv_n_page_hash_locks;	/*!< number of locks to
 					protect buf_pool->page_hash */
 extern ulint	srv_buf_pool_old_size;	/*!< previously requested size */
 extern ulint	srv_buf_pool_curr_size;	/*!< current size in bytes */

=== modified file 'storage/innobase/include/sync0sync.h'
--- a/storage/innobase/include/sync0sync.h	revid:jimmy.yang@stripped
+++ b/storage/innobase/include/sync0sync.h	revid:inaam.rana@stripped
@@ -696,7 +696,7 @@ or row lock! */
 					can call routines there! Otherwise
 					the level is SYNC_MEM_HASH. */
 #define	SYNC_BUF_POOL		150	/* Buffer pool mutex */
-#define	SYNC_BUF_PAGE_HASH	149	/* buf_pool->page_hash mutex */
+#define	SYNC_BUF_PAGE_HASH	149	/* buf_pool->page_hash rw_lock */
 #define	SYNC_BUF_BLOCK		146	/* Block mutex */
 #define	SYNC_BUF_FLUSH_LIST	145	/* Buffer flush list mutex */
 #define SYNC_DOUBLEWRITE	140

=== modified file 'storage/innobase/include/univ.i'
--- a/storage/innobase/include/univ.i	revid:jimmy.yang@stripped
+++ b/storage/innobase/include/univ.i	revid:inaam.rana@stripped
@@ -203,6 +203,9 @@ debugging redo log application problems.
 #define UNIV_IBUF_COUNT_DEBUG			/* debug the insert buffer;
 this limits the database to IBUF_COUNT_N_SPACES and IBUF_COUNT_N_PAGES,
 and the insert buffer must be empty when the database is started */
+#define UNIV_PERF_DEBUG                         /* debug flag that enables
+                                                light weight performance
+                                                related stuff. */
 #define UNIV_SYNC_DEBUG				/* debug mutex and latch
 operations (very slow); also UNIV_DEBUG must be defined */
 #define UNIV_SEARCH_DEBUG			/* debug B-tree comparisons */

=== modified file 'storage/innobase/srv/srv0srv.c'
--- a/storage/innobase/srv/srv0srv.c	revid:jimmy.yang@stripped
+++ b/storage/innobase/srv/srv0srv.c	revid:inaam.rana@stripped
@@ -192,8 +192,8 @@ UNIV_INTERN my_bool	srv_use_sys_malloc	=
 UNIV_INTERN ulint	srv_buf_pool_size	= ULINT_MAX;
 /* requested number of buffer pool instances */
 UNIV_INTERN ulint       srv_buf_pool_instances  = 1;
-/* number of mutexes to protect buf_pool->page_hash */
-UNIV_INTERN ulong	srv_n_page_hash_mutexes = 256;
+/* number of locks to protect buf_pool->page_hash */
+UNIV_INTERN ulong	srv_n_page_hash_locks = 16;
 /* previously requested size */
 UNIV_INTERN ulint	srv_buf_pool_old_size;
 /* current size in kilobytes */

=== modified file 'storage/innobase/sync/sync0sync.c'
--- a/storage/innobase/sync/sync0sync.c	revid:jimmy.yang@stripped
+++ b/storage/innobase/sync/sync0sync.c	revid:inaam.rana@stripped
@@ -1212,7 +1212,7 @@ sync_thread_add_level(
 
 
 	case SYNC_BUF_PAGE_HASH:
-		/* Multiple page_hash mutexes are only allowed during
+		/* Multiple page_hash locks are only allowed during
 		buf_validate and that is where buf_pool mutex is already
 		held. */
 		/* Fall through */


Attachment: [text/bzr-bundle] bzr/inaam.rana@oracle.com-20101208153001-lm0v0sedavr75jqe.bundle
Thread
bzr push into mysql-trunk-innodb branch (inaam.rana:3367 to 3368) Inaam Rana8 Dec