From 5f0b8a8a65d033e797373302754342588cebea3f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= <marko.makela@mariadb.com>
Date: Mon, 13 Mar 2017 18:31:03 +0200
Subject: [PATCH] MySQL 5.7.17 port of MDEV-12121 Introduce build option
 WITH_INNODB_AHI to disable innodb_adaptive_hash_index

NOTE: Some tests could/should be adjusted
so that they will work with both -DWITH_INNODB_AHI=ON and
-DWITH_INNODB_AHI=OFF. See the commits in MariaDB Server 10.2:
https://github.com/MariaDB/server/commit/ff0530ef681ebb8cf2272d2976f9ed3d718ae387
https://github.com/MariaDB/server/commit/27b9989d316163d00177bfee8fceb10995c2ba9b

The InnoDB adaptive hash index is sometimes degrading the performance of
InnoDB, and it is sometimes disabled to get more consistent performance.
We should have a compile-time option to disable the adaptive hash index.

Let us introduce two options:

OPTION(WITH_INNODB_AHI "Include innodb_adaptive_hash_index" ON)
OPTION(WITH_INNODB_ROOT_GUESS "Cache index root block descriptors" ON)

where WITH_INNODB_AHI always implies WITH_INNODB_ROOT_GUESS.

As part of this change, the misleadingly named function
trx_search_latch_release_if_reserved(trx) will be replaced with the macro
trx_assert_no_search_latch(trx) that will be empty unless
BTR_CUR_HASH_ADAPT is defined (cmake -DWITH_INNODB_AHI=ON).

We will also remove the unused column
INFORMATION_SCHEMA.INNODB_TRX.TRX_ADAPTIVE_HASH_TIMEOUT.
In MariaDB Server 10.1, it used to reflect the value of
trx_t::search_latch_timeout which could be adjusted during
row_search_for_mysql(). In 10.2, there is no such field.

Other than the removal of the unused column TRX_ADAPTIVE_HASH_TIMEOUT,
this is an almost non-functional change to the server when using the
default build options.
---
 scripts/mysql_sys_schema.sql              |   8 +-
 storage/innobase/btr/btr0cur.cc           |  45 ++++++-----
 storage/innobase/btr/btr0sea.cc           |  39 +---------
 storage/innobase/buf/buf0buf.cc           |  28 +++++--
 storage/innobase/buf/buf0lru.cc           |  46 ++++++-----
 storage/innobase/dict/dict0dict.cc        |  21 ++---
 storage/innobase/fsp/fsp0fsp.cc           |  45 +++++++----
 storage/innobase/gis/gis0sea.cc           |   2 +
 storage/innobase/ha/ha0ha.cc              |   4 +
 storage/innobase/ha/hash0hash.cc          |   2 +
 storage/innobase/handler/ha_innodb.cc     | 125 ++++++++++++------------------
 storage/innobase/handler/ha_innopart.cc   |   6 +-
 storage/innobase/handler/handler0alter.cc |   5 +-
 storage/innobase/handler/i_s.cc           | 103 ++++++++++++------------
 storage/innobase/ibuf/ibuf0ibuf.cc        |   4 +
 storage/innobase/include/btr0cur.h        |  11 ++-
 storage/innobase/include/btr0sea.h        |  67 ++++++++++------
 storage/innobase/include/btr0sea.ic       |  31 +++++---
 storage/innobase/include/btr0types.h      |   2 +
 storage/innobase/include/buf0buf.h        |  22 ++++--
 storage/innobase/include/dict0mem.h       |   4 +
 storage/innobase/include/dict0mem.ic      |   2 +
 storage/innobase/include/fsp0fsp.h        |  34 ++++++--
 storage/innobase/include/ha0ha.h          |   8 +-
 storage/innobase/include/ha0ha.ic         |  18 +++--
 storage/innobase/include/hash0hash.h      |   4 +-
 storage/innobase/include/page0cur.h       |   4 +-
 storage/innobase/include/srv0mon.h        |   4 +
 storage/innobase/include/sync0types.h     |   2 +
 storage/innobase/include/trx0i_s.h        |   2 +
 storage/innobase/include/trx0trx.h        |  20 +++--
 storage/innobase/include/trx0trx.ic       |  10 ---
 storage/innobase/innodb.cmake             |  16 +++-
 storage/innobase/page/page0cur.cc         |  22 +++---
 storage/innobase/row/row0sel.cc           |  98 +++++++++++------------
 storage/innobase/srv/srv0conc.cc          |  22 +++---
 storage/innobase/srv/srv0mon.cc           |   8 +-
 storage/innobase/srv/srv0srv.cc           |   9 +++
 storage/innobase/srv/srv0start.cc         |   4 +
 storage/innobase/trx/trx0i_s.cc           |   2 +
 storage/innobase/trx/trx0trx.cc           |   7 +-
 storage/innobase/ut/ut0new.cc             |   4 +
 42 files changed, 516 insertions(+), 404 deletions(-)

diff --git a/scripts/mysql_sys_schema.sql b/scripts/mysql_sys_schema.sql
index 94ec0d1902c..b036115f479 100644
--- a/scripts/mysql_sys_schema.sql
+++ b/scripts/mysql_sys_schema.sql
@@ -134,13 +134,13 @@ DROP FUNCTION IF EXISTS version_patch;
 
 CREATE DEFINER='mysql.sys'@'localhost' FUNCTION version_patch () RETURNS TINYINT UNSIGNED COMMENT '\n Description\n \n Returns the patch release version of MySQL Server.\n \n Returns\n \n TINYINT UNSIGNED\n \n Example\n \n mysql> SELECT VERSION(), sys.version_patch();\n +--------------------------------------+---------------------+\n | VERSION()                            | sys.version_patch() |\n +--------------------------------------+---------------------+\n | 5.7.9-enterprise-commercial-advanced | 9                   |\n +--------------------------------------+---------------------+\n 1 row in set (0.00 sec)\n ' SQL SECURITY INVOKER NOT DETERMINISTIC NO SQL BEGIN RETURN SUBSTRING_INDEX(SUBSTRING_INDEX(VERSION(), '-', 1), '.', -1); END;
 
-CREATE OR REPLACE ALGORITHM = TEMPTABLE DEFINER = 'mysql.sys'@'localhost' SQL SECURITY INVOKER  VIEW innodb_buffer_stats_by_schema ( object_schema, allocated, data, pages, pages_hashed, pages_old, rows_cached ) AS SELECT IF(LOCATE('.', ibp.table_name) = 0, 'InnoDB System', REPLACE(SUBSTRING_INDEX(ibp.table_name, '.', 1), '`', '')) AS object_schema, sys.format_bytes(SUM(IF(ibp.compressed_size = 0, 16384, compressed_size))) AS allocated, sys.format_bytes(SUM(ibp.data_size)) AS data, COUNT(ibp.page_number) AS pages, COUNT(IF(ibp.is_hashed = 'YES', 1, NULL)) AS pages_hashed, COUNT(IF(ibp.is_old = 'YES', 1, NULL)) AS pages_old, ROUND(SUM(ibp.number_records)/COUNT(DISTINCT ibp.index_name)) AS rows_cached  FROM information_schema.innodb_buffer_page ibp  WHERE table_name IS NOT NULL GROUP BY object_schema ORDER BY SUM(IF(ibp.compressed_size = 0, 16384, compressed_size)) DESC;
+CREATE OR REPLACE ALGORITHM = TEMPTABLE DEFINER = 'mysql.sys'@'localhost' SQL SECURITY INVOKER  VIEW innodb_buffer_stats_by_schema ( object_schema, allocated, data, pages, pages_hashed, pages_old, rows_cached ) AS SELECT IF(LOCATE('.', ibp.table_name) = 0, 'InnoDB System', REPLACE(SUBSTRING_INDEX(ibp.table_name, '.', 1), '`', '')) AS object_schema, sys.format_bytes(SUM(IF(ibp.compressed_size = 0, 16384, compressed_size))) AS allocated, sys.format_bytes(SUM(ibp.data_size)) AS data, COUNT(ibp.page_number) AS pages, 0 AS pages_hashed, COUNT(IF(ibp.is_old = 'YES', 1, NULL)) AS pages_old, ROUND(SUM(ibp.number_records)/COUNT(DISTINCT ibp.index_name)) AS rows_cached  FROM information_schema.innodb_buffer_page ibp  WHERE table_name IS NOT NULL GROUP BY object_schema ORDER BY SUM(IF(ibp.compressed_size = 0, 16384, compressed_size)) DESC;
 
-CREATE OR REPLACE ALGORITHM = TEMPTABLE DEFINER = 'mysql.sys'@'localhost' SQL SECURITY INVOKER  VIEW x$innodb_buffer_stats_by_schema ( object_schema, allocated, data, pages, pages_hashed, pages_old, rows_cached ) AS SELECT IF(LOCATE('.', ibp.table_name) = 0, 'InnoDB System', REPLACE(SUBSTRING_INDEX(ibp.table_name, '.', 1), '`', '')) AS object_schema, SUM(IF(ibp.compressed_size = 0, 16384, compressed_size)) AS allocated, SUM(ibp.data_size) AS data, COUNT(ibp.page_number) AS pages, COUNT(IF(ibp.is_hashed = 'YES', 1, NULL)) AS pages_hashed, COUNT(IF(ibp.is_old = 'YES', 1, NULL)) AS pages_old, ROUND(IFNULL(SUM(ibp.number_records)/NULLIF(COUNT(DISTINCT ibp.index_name), 0), 0)) AS rows_cached  FROM information_schema.innodb_buffer_page ibp  WHERE table_name IS NOT NULL GROUP BY object_schema ORDER BY SUM(IF(ibp.compressed_size = 0, 16384, compressed_size)) DESC;
+CREATE OR REPLACE ALGORITHM = TEMPTABLE DEFINER = 'mysql.sys'@'localhost' SQL SECURITY INVOKER  VIEW x$innodb_buffer_stats_by_schema ( object_schema, allocated, data, pages, pages_hashed, pages_old, rows_cached ) AS SELECT IF(LOCATE('.', ibp.table_name) = 0, 'InnoDB System', REPLACE(SUBSTRING_INDEX(ibp.table_name, '.', 1), '`', '')) AS object_schema, SUM(IF(ibp.compressed_size = 0, 16384, compressed_size)) AS allocated, SUM(ibp.data_size) AS data, COUNT(ibp.page_number) AS pages, 0 AS pages_hashed, COUNT(IF(ibp.is_old = 'YES', 1, NULL)) AS pages_old, ROUND(IFNULL(SUM(ibp.number_records)/NULLIF(COUNT(DISTINCT ibp.index_name), 0), 0)) AS rows_cached  FROM information_schema.innodb_buffer_page ibp  WHERE table_name IS NOT NULL GROUP BY object_schema ORDER BY SUM(IF(ibp.compressed_size = 0, 16384, compressed_size)) DESC;
 
-CREATE OR REPLACE ALGORITHM = TEMPTABLE DEFINER = 'mysql.sys'@'localhost' SQL SECURITY INVOKER  VIEW innodb_buffer_stats_by_table ( object_schema, object_name, allocated, data, pages, pages_hashed, pages_old, rows_cached ) AS SELECT IF(LOCATE('.', ibp.table_name) = 0, 'InnoDB System', REPLACE(SUBSTRING_INDEX(ibp.table_name, '.', 1), '`', '')) AS object_schema, REPLACE(SUBSTRING_INDEX(ibp.table_name, '.', -1), '`', '') AS object_name, sys.format_bytes(SUM(IF(ibp.compressed_size = 0, 16384, compressed_size))) AS allocated, sys.format_bytes(SUM(ibp.data_size)) AS data, COUNT(ibp.page_number) AS pages, COUNT(IF(ibp.is_hashed = 'YES', 1, NULL)) AS pages_hashed, COUNT(IF(ibp.is_old = 'YES', 1, NULL)) AS pages_old, ROUND(SUM(ibp.number_records)/COUNT(DISTINCT ibp.index_name)) AS rows_cached  FROM information_schema.innodb_buffer_page ibp  WHERE table_name IS NOT NULL GROUP BY object_schema, object_name ORDER BY SUM(IF(ibp.compressed_size = 0, 16384, compressed_size)) DESC;
+CREATE OR REPLACE ALGORITHM = TEMPTABLE DEFINER = 'mysql.sys'@'localhost' SQL SECURITY INVOKER  VIEW innodb_buffer_stats_by_table ( object_schema, object_name, allocated, data, pages, pages_hashed, pages_old, rows_cached ) AS SELECT IF(LOCATE('.', ibp.table_name) = 0, 'InnoDB System', REPLACE(SUBSTRING_INDEX(ibp.table_name, '.', 1), '`', '')) AS object_schema, REPLACE(SUBSTRING_INDEX(ibp.table_name, '.', -1), '`', '') AS object_name, sys.format_bytes(SUM(IF(ibp.compressed_size = 0, 16384, compressed_size))) AS allocated, sys.format_bytes(SUM(ibp.data_size)) AS data, COUNT(ibp.page_number) AS pages, 0 AS pages_hashed, COUNT(IF(ibp.is_old = 'YES', 1, NULL)) AS pages_old, ROUND(SUM(ibp.number_records)/COUNT(DISTINCT ibp.index_name)) AS rows_cached  FROM information_schema.innodb_buffer_page ibp  WHERE table_name IS NOT NULL GROUP BY object_schema, object_name ORDER BY SUM(IF(ibp.compressed_size = 0, 16384, compressed_size)) DESC;
 
-CREATE OR REPLACE ALGORITHM = TEMPTABLE DEFINER = 'mysql.sys'@'localhost' SQL SECURITY INVOKER  VIEW x$innodb_buffer_stats_by_table ( object_schema, object_name, allocated, data, pages, pages_hashed, pages_old, rows_cached ) AS SELECT IF(LOCATE('.', ibp.table_name) = 0, 'InnoDB System', REPLACE(SUBSTRING_INDEX(ibp.table_name, '.', 1), '`', '')) AS object_schema, REPLACE(SUBSTRING_INDEX(ibp.table_name, '.', -1), '`', '') AS object_name, SUM(IF(ibp.compressed_size = 0, 16384, compressed_size)) AS allocated, SUM(ibp.data_size) AS data, COUNT(ibp.page_number) AS pages, COUNT(IF(ibp.is_hashed = 'YES', 1, NULL)) AS pages_hashed, COUNT(IF(ibp.is_old = 'YES', 1, NULL)) AS pages_old, ROUND(IFNULL(SUM(ibp.number_records)/NULLIF(COUNT(DISTINCT ibp.index_name), 0), 0)) AS rows_cached  FROM information_schema.innodb_buffer_page ibp  WHERE table_name IS NOT NULL GROUP BY object_schema, object_name ORDER BY SUM(IF(ibp.compressed_size = 0, 16384, compressed_size)) DESC;
+CREATE OR REPLACE ALGORITHM = TEMPTABLE DEFINER = 'mysql.sys'@'localhost' SQL SECURITY INVOKER  VIEW x$innodb_buffer_stats_by_table ( object_schema, object_name, allocated, data, pages, pages_hashed, pages_old, rows_cached ) AS SELECT IF(LOCATE('.', ibp.table_name) = 0, 'InnoDB System', REPLACE(SUBSTRING_INDEX(ibp.table_name, '.', 1), '`', '')) AS object_schema, REPLACE(SUBSTRING_INDEX(ibp.table_name, '.', -1), '`', '') AS object_name, SUM(IF(ibp.compressed_size = 0, 16384, compressed_size)) AS allocated, SUM(ibp.data_size) AS data, COUNT(ibp.page_number) AS pages, 0 AS pages_hashed, COUNT(IF(ibp.is_old = 'YES', 1, NULL)) AS pages_old, ROUND(IFNULL(SUM(ibp.number_records)/NULLIF(COUNT(DISTINCT ibp.index_name), 0), 0)) AS rows_cached  FROM information_schema.innodb_buffer_page ibp  WHERE table_name IS NOT NULL GROUP BY object_schema, object_name ORDER BY SUM(IF(ibp.compressed_size = 0, 16384, compressed_size)) DESC;
 
 CREATE OR REPLACE ALGORITHM = TEMPTABLE DEFINER = 'mysql.sys'@'localhost' SQL SECURITY INVOKER  VIEW innodb_lock_waits ( wait_started, wait_age, wait_age_secs, locked_table, locked_index, locked_type, waiting_trx_id, waiting_trx_started, waiting_trx_age, waiting_trx_rows_locked, waiting_trx_rows_modified, waiting_pid, waiting_query, waiting_lock_id, waiting_lock_mode, blocking_trx_id, blocking_pid, blocking_query, blocking_lock_id, blocking_lock_mode, blocking_trx_started, blocking_trx_age, blocking_trx_rows_locked, blocking_trx_rows_modified, sql_kill_blocking_query, sql_kill_blocking_connection ) AS SELECT r.trx_wait_started AS wait_started, TIMEDIFF(NOW(), r.trx_wait_started) AS wait_age, TIMESTAMPDIFF(SECOND, r.trx_wait_started, NOW()) AS wait_age_secs, rl.lock_table AS locked_table, rl.lock_index AS locked_index, rl.lock_type AS locked_type, r.trx_id AS waiting_trx_id, r.trx_started as waiting_trx_started, TIMEDIFF(NOW(), r.trx_started) AS waiting_trx_age, r.trx_rows_locked AS waiting_trx_rows_locked, r.trx_rows_modified AS waiting_trx_rows_modified, r.trx_mysql_thread_id AS waiting_pid, sys.format_statement(r.trx_query) AS waiting_query, rl.lock_id AS waiting_lock_id, rl.lock_mode AS waiting_lock_mode, b.trx_id AS blocking_trx_id, b.trx_mysql_thread_id AS blocking_pid, sys.format_statement(b.trx_query) AS blocking_query, bl.lock_id AS blocking_lock_id, bl.lock_mode AS blocking_lock_mode, b.trx_started AS blocking_trx_started, TIMEDIFF(NOW(), b.trx_started) AS blocking_trx_age, b.trx_rows_locked AS blocking_trx_rows_locked, b.trx_rows_modified AS blocking_trx_rows_modified, CONCAT('KILL QUERY ', b.trx_mysql_thread_id) AS sql_kill_blocking_query, CONCAT('KILL ', b.trx_mysql_thread_id) AS sql_kill_blocking_connection FROM information_schema.innodb_lock_waits w INNER JOIN information_schema.innodb_trx b    ON b.trx_id = w.blocking_trx_id INNER JOIN information_schema.innodb_trx r    ON r.trx_id = w.requesting_trx_id INNER JOIN information_schema.innodb_locks bl ON bl.lock_id = w.blocking_lock_id INNER JOIN information_schema.innodb_locks rl ON rl.lock_id = w.requested_lock_id ORDER BY r.trx_wait_started;
 
diff --git a/storage/innobase/btr/btr0cur.cc b/storage/innobase/btr/btr0cur.cc
index 54429a38418..65b092b3921 100644
--- a/storage/innobase/btr/btr0cur.cc
+++ b/storage/innobase/btr/btr0cur.cc
@@ -105,22 +105,24 @@ throughput clearly from about 100000. */
 #define BTR_CUR_FINE_HISTORY_LENGTH	100000
 
 /** Number of searches down the B-tree in btr_cur_search_to_nth_level(). */
-ulint	btr_cur_n_non_sea	= 0;
-/** Number of successful adaptive hash index lookups in
-btr_cur_search_to_nth_level(). */
-ulint	btr_cur_n_sea		= 0;
+ulint	btr_cur_n_non_sea;
 /** Old value of btr_cur_n_non_sea.  Copied by
 srv_refresh_innodb_monitor_stats().  Referenced by
 srv_printf_innodb_monitor(). */
-ulint	btr_cur_n_non_sea_old	= 0;
+ulint	btr_cur_n_non_sea_old;
+#ifdef BTR_CUR_HASH_ADAPT
+/** Number of successful adaptive hash index lookups in
+btr_cur_search_to_nth_level(). */
+ulint	btr_cur_n_sea;
 /** Old value of btr_cur_n_sea.  Copied by
 srv_refresh_innodb_monitor_stats().  Referenced by
 srv_printf_innodb_monitor(). */
-ulint	btr_cur_n_sea_old	= 0;
+ulint	btr_cur_n_sea_old;
+#endif /* BTR_CUR_HASH_ADAPT */
 
 #ifdef UNIV_DEBUG
 /* Flag to limit optimistic insert records */
-uint	btr_cur_limit_optimistic_insert_debug = 0;
+uint	btr_cur_limit_optimistic_insert_debug;
 #endif /* UNIV_DEBUG */
 
 /** In the optimistic insert, if the insert does not fit, but this much space
@@ -948,7 +950,7 @@ btr_cur_search_to_nth_level(
 
 	if (has_search_latch) {
 		/* Release possible search latch to obey latching order */
-		rw_lock_s_unlock(btr_get_search_latch(index));
+		btr_search_s_unlock(index);
 	}
 
 	/* Store the position of the tree latch we push to mtr so that we
@@ -1426,6 +1428,7 @@ retry_page_get:
 			cursor->low_match =
 				DICT_INDEX_SPATIAL_NODEPTR_SIZE + 1;
 		}
+#ifdef BTR_CUR_HASH_ADAPT
 	} else if (height == 0 && btr_search_enabled
 		   && !dict_index_is_spatial(index)) {
 		/* The adaptive hash index is only used when searching
@@ -1435,6 +1438,7 @@ retry_page_get:
 		page_cur_search_with_match_bytes(
 			block, index, tuple, page_mode, &up_match, &up_bytes,
 			&low_match, &low_bytes, page_cursor);
+#endif /* BTR_CUR_HASH_ADAPT */
 	} else {
 		/* Search for complete index fields. */
 		up_bytes = low_bytes = 0;
@@ -1908,7 +1912,7 @@ need_opposite_intention:
 		cursor->up_match = up_match;
 		cursor->up_bytes = up_bytes;
 
-#ifdef BTR_CUR_ADAPT
+#ifdef BTR_CUR_HASH_ADAPT
 		/* We do a dirty read of btr_search_enabled here.  We
 		will properly check btr_search_enabled again in
 		btr_search_build_page_hash_index() before building a
@@ -1916,7 +1920,7 @@ need_opposite_intention:
 		if (btr_search_enabled && !index->disable_ahi) {
 			btr_search_info_update(index, cursor);
 		}
-#endif
+#endif /* BTR_CUR_HASH_ADAPT */
 		ut_ad(cursor->up_match != ULINT_UNDEFINED
 		      || mode != PAGE_CUR_GE);
 		ut_ad(cursor->up_match != ULINT_UNDEFINED
@@ -1952,8 +1956,7 @@ func_exit:
 	}
 
 	if (has_search_latch) {
-
-		rw_lock_s_lock(btr_get_search_latch(index));
+		btr_search_s_lock(index);
 	}
 
 	if (mbr_adj) {
@@ -3457,7 +3460,7 @@ btr_cur_pessimistic_insert(
 		}
 	}
 
-#ifdef BTR_CUR_ADAPT
+#ifdef BTR_CUR_HASH_ADAPT
 	if (!index->disable_ahi) {
 		btr_search_update_hash_on_insert(cursor);
 	}
@@ -3792,7 +3795,6 @@ btr_cur_update_in_place(
 	rec_t*		rec;
 	roll_ptr_t	roll_ptr	= 0;
 	ulint		was_delete_marked;
-	ibool		is_hashed;
 
 	rec = btr_cur_get_rec(cursor);
 	index = cursor->index;
@@ -3852,9 +3854,8 @@ btr_cur_update_in_place(
 	was_delete_marked = rec_get_deleted_flag(
 		rec, page_is_comp(buf_block_get_frame(block)));
 
-	is_hashed = (block->index != NULL);
-
-	if (is_hashed) {
+#ifdef BTR_CUR_HASH_ADAPT
+	if (block->index) {
 		/* TO DO: Can we skip this if none of the fields
 		index->search_info->curr_n_fields
 		are being updated? */
@@ -3871,15 +3872,19 @@ btr_cur_update_in_place(
 			btr_search_update_hash_on_delete(cursor);
 		}
 
-		rw_lock_x_lock(btr_get_search_latch(index));
+		btr_search_x_lock(index);
 	}
 
 	assert_block_ahi_valid(block);
+#endif /* BTR_CUR_HASH_ADAPT */
+
 	row_upd_rec_in_place(rec, index, offsets, update, page_zip);
 
-	if (is_hashed) {
-		rw_lock_x_unlock(btr_get_search_latch(index));
+#ifdef BTR_CUR_HASH_ADAPT
+	if (block->index) {
+		btr_search_x_unlock(index);
 	}
+#endif /* BTR_CUR_HASH_ADAPT */
 
 	btr_cur_update_in_place_log(flags, rec, index, update,
 				    trx_id, roll_ptr, mtr);
diff --git a/storage/innobase/btr/btr0sea.cc b/storage/innobase/btr/btr0sea.cc
index ba0e7028c56..abf81f8c109 100644
--- a/storage/innobase/btr/btr0sea.cc
+++ b/storage/innobase/btr/btr0sea.cc
@@ -31,6 +31,7 @@ Created 2/17/1996 Heikki Tuuri
 *************************************************************************/
 
 #include "btr0sea.h"
+#ifdef BTR_CUR_HASH_ADAPT
 #ifdef UNIV_NONINL
 #include "btr0sea.ic"
 #endif /* UNIV_NOINL */
@@ -375,43 +376,6 @@ btr_search_enable()
 	btr_search_x_unlock_all();
 }
 
-/** Creates and initializes a search info struct.
-@param[in]	heap		heap where created.
-@return own: search info struct */
-btr_search_t*
-btr_search_info_create(mem_heap_t* heap)
-{
-	btr_search_t*	info;
-
-	info = (btr_search_t*) mem_heap_alloc(heap, sizeof(btr_search_t));
-
-	ut_d(info->magic_n = BTR_SEARCH_MAGIC_N);
-
-	info->ref_count = 0;
-	info->root_guess = NULL;
-	info->withdraw_clock = 0;
-
-	info->hash_analysis = 0;
-	info->n_hash_potential = 0;
-
-	info->last_hash_succ = FALSE;
-
-#ifdef UNIV_SEARCH_PERF_STAT
-	info->n_hash_succ = 0;
-	info->n_hash_fail = 0;
-	info->n_patt_succ = 0;
-	info->n_searches = 0;
-#endif /* UNIV_SEARCH_PERF_STAT */
-
-	/* Set some sensible values */
-	info->n_fields = 1;
-	info->n_bytes = 0;
-
-	info->left_side = TRUE;
-
-	return(info);
-}
-
 /** Returns the value of ref_count. The value is protected by latch.
 @param[in]	info		search info
 @param[in]	index		index identifier
@@ -2160,3 +2124,4 @@ btr_search_validate()
 }
 
 #endif /* defined UNIV_AHI_DEBUG || defined UNIV_DEBUG */
+#endif /* BTR_CUR_HASH_ADAPT */
diff --git a/storage/innobase/buf/buf0buf.cc b/storage/innobase/buf/buf0buf.cc
index fe30630a198..37924d065c9 100644
--- a/storage/innobase/buf/buf0buf.cc
+++ b/storage/innobase/buf/buf0buf.cc
@@ -1432,7 +1432,9 @@ buf_block_init(
 
 	ut_d(block->page.file_page_was_freed = FALSE);
 
+#ifdef BTR_CUR_HASH_ADAPT
 	block->index = NULL;
+#endif /* BTR_CUR_HASH_ADAPT */
 	block->made_dirty_with_no_latch = false;
 	block->skip_flush_check = false;
 
@@ -2098,6 +2100,7 @@ buf_page_realloc(
 
 		/* set other flags of buf_block_t */
 
+#ifdef BTR_CUR_HASH_ADAPT
 		/* This code should only be executed by buf_pool_resize(),
 		while the adaptive hash index is disabled. */
 		assert_block_ahi_empty(block);
@@ -2107,6 +2110,7 @@ buf_page_realloc(
 		new_block->n_hash_helps	= 0;
 		new_block->n_fields	= 1;
 		new_block->left_side	= TRUE;
+#endif /* BTR_CUR_HASH_ADAPT */
 
 		new_block->lock_hash_val = block->lock_hash_val;
 		ut_ad(new_block->lock_hash_val == lock_rec_hash(
@@ -2569,7 +2573,7 @@ buf_pool_resize()
 
 		buf_pool_mutex_exit(buf_pool);
 	}
-
+#ifdef BTR_CUR_HASH_ADAPT
 	/* disable AHI if needed */
 	bool	btr_search_disabled = false;
 
@@ -2588,6 +2592,7 @@ buf_pool_resize()
 	if (btr_search_disabled) {
 		ib::info() << "disabled adaptive hash index.";
 	}
+#endif /* BTR_CUR_HASH_ADAPT */
 
 	/* set withdraw target */
 	for (ulint i = 0; i < srv_buf_pool_instances; i++) {
@@ -2959,7 +2964,10 @@ calc_buf_pool_size:
 		dict_resize();
 
 		ib::info() << "Resized hash tables at lock_sys,"
-			" adaptive hash index, dictionary.";
+#ifdef BTR_CUR_HASH_ADAPT
+			" adaptive hash index,"
+#endif /* BTR_CUR_HASH_ADAPT */
+			" dictionary.";
 	}
 
 	/* normalize ibuf->max_size */
@@ -2973,11 +2981,13 @@ calc_buf_pool_size:
 		srv_buf_pool_old_size = srv_buf_pool_size;
 	}
 
+#ifdef BTR_CUR_HASH_ADAPT
 	/* enable AHI if needed */
 	if (btr_search_disabled) {
 		btr_search_enable();
 		ib::info() << "Re-enabled adaptive hash index.";
 	}
+#endif /* BTR_CUR_HASH_ADAPT */
 
 	char	now[32];
 
@@ -3043,11 +3053,10 @@ DECLARE_THREAD(buf_resize_thread)(
 	OS_THREAD_DUMMY_RETURN;
 }
 
-/********************************************************************//**
-Clears the adaptive hash index on all pages in the buffer pool. */
+#ifdef BTR_CUR_HASH_ADAPT
+/** Clear the adaptive hash index on all pages in the buffer pool. */
 void
-buf_pool_clear_hash_index(void)
-/*===========================*/
+buf_pool_clear_hash_index()
 {
 	ulint	p;
 
@@ -3087,6 +3096,7 @@ buf_pool_clear_hash_index(void)
 		}
 	}
 }
+#endif /* BTR_CUR_HASH_ADAPT */
 
 /********************************************************************//**
 Relocate a buffer control block.  Relocates the block on the LRU list
@@ -3773,14 +3783,16 @@ buf_block_init_low(
 	/* No adaptive hash index entries may point to a previously
 	unused (and now freshly allocated) block. */
 	assert_block_ahi_empty_on_init(block);
-	block->index		= NULL;
 	block->made_dirty_with_no_latch = false;
 	block->skip_flush_check = false;
 
+#ifdef BTR_CUR_HASH_ADAPT
+	block->index		= NULL;
 	block->n_hash_helps	= 0;
 	block->n_fields		= 1;
 	block->n_bytes		= 0;
 	block->left_side	= TRUE;
+#endif /* BTR_CUR_HASH_ADAPT */
 }
 #endif /* !UNIV_HOTBACKUP */
 
@@ -3854,6 +3866,7 @@ buf_zip_decompress(
 }
 
 #ifndef UNIV_HOTBACKUP
+#ifdef BTR_CUR_HASH_ADAPT
 /** Get a buffer block from an adaptive hash index pointer.
 This function does not return if the block is not identified.
 @param[in]	ptr	pointer to within a page frame
@@ -3896,6 +3909,7 @@ buf_block_from_ahi(const byte* ptr)
 	ut_ad(state == BUF_BLOCK_FILE_PAGE || state == BUF_BLOCK_REMOVE_HASH);
 	return(block);
 }
+#endif /* BTR_CUR_HASH_ADAPT */
 
 /********************************************************************//**
 Find out if a pointer belongs to a buf_block_t. It can be a pointer to
diff --git a/storage/innobase/buf/buf0lru.cc b/storage/innobase/buf/buf0lru.cc
index a78112746f5..30128f31fda 100644
--- a/storage/innobase/buf/buf0lru.cc
+++ b/storage/innobase/buf/buf0lru.cc
@@ -220,6 +220,7 @@ buf_LRU_evict_from_unzip_LRU(
 	return(unzip_avg <= io_avg * BUF_LRU_IO_TO_UNZIP_FACTOR);
 }
 
+#ifdef BTR_CUR_HASH_ADAPT
 /** Attempts to drop page hash index on a batch of pages belonging to a
 particular space id.
 @param[in]	space_id	space id
@@ -373,6 +374,7 @@ next_page:
 	buf_LRU_drop_page_hash_batch(id, page_size, page_arr, num_entries);
 	ut_free(page_arr);
 }
+#endif /* BTR_CUR_HASH_ADAPT */
 
 /******************************************************************//**
 While flushing (or removing dirty) pages from a tablespace we don't
@@ -797,7 +799,7 @@ scan_again:
 				      bpage->id.space(),
 				      bpage->id.page_no(),
 				      bpage->state));
-
+#ifdef BTR_CUR_HASH_ADAPT
 		if (buf_page_get_state(bpage) != BUF_BLOCK_FILE_PAGE) {
 			/* Do nothing, because the adaptive hash index
 			covers uncompressed pages only. */
@@ -830,6 +832,7 @@ scan_again:
 			be no concurrect access to the contained tables.) */
 			assert_block_ahi_empty((buf_block_t*) bpage);
 		}
+#endif /* BTR_CUR_HASH_ADAPT */
 
 		if (bpage->oldest_modification != 0) {
 
@@ -931,7 +934,7 @@ buf_LRU_flush_or_remove_pages(
 		buf_pool_t*	buf_pool;
 
 		buf_pool = buf_pool_from_array(i);
-
+#ifdef BTR_CUR_HASH_ADAPT
 		switch (buf_remove) {
 		case BUF_REMOVE_ALL_NO_WRITE:
 			buf_LRU_drop_page_hash_for_tablespace(buf_pool, id);
@@ -947,7 +950,7 @@ buf_LRU_flush_or_remove_pages(
 			table, there is no need to drop the AHI entries. */
 			break;
 		}
-
+#endif /* BTR_CUR_HASH_ADAPT */
 		buf_LRU_remove_pages(buf_pool, id, buf_remove, trx);
 	}
 }
@@ -1229,15 +1232,15 @@ buf_LRU_check_size_of_non_data_objects(
 	    + UT_LIST_GET_LEN(buf_pool->LRU) < buf_pool->curr_size / 20) {
 
 		ib::fatal() << "Over 95 percent of the buffer pool is"
-			" occupied by lock heaps or the adaptive hash index!"
+			" occupied by lock heaps"
+#ifdef BTR_CUR_HASH_ADAPT
+			" or the adaptive hash index!"
+#endif /* BTR_CUR_HASH_ADAPT */
 			" Check that your transactions do not set too many"
-			" row locks. Your buffer pool size is "
-			<< (buf_pool->curr_size
-				/ (1024 * 1024 / UNIV_PAGE_SIZE)) << " MB."
-			" Maybe you should make the buffer pool bigger?"
-			" We intentionally generate a seg fault to print"
-			" a stack trace on Linux!";
-
+			" row locks, or review if"
+			" innodb_buffer_pool_size="
+			<< (buf_pool->curr_size >> (20 - UNIV_PAGE_SIZE_SHIFT))
+			<< "M could be bigger.";
 	} else if (!recv_recovery_is_on()
 		   && buf_pool->curr_size == buf_pool->old_size
 		   && (UT_LIST_GET_LEN(buf_pool->free)
@@ -1251,16 +1254,17 @@ buf_LRU_check_size_of_non_data_objects(
 			leak! */
 
 			ib::warn() << "Over 67 percent of the buffer pool is"
-				" occupied by lock heaps or the adaptive hash"
-				" index! Check that your transactions do not"
-				" set too many row locks. Your buffer pool"
-				" size is "
-				<< (buf_pool->curr_size
-					 / (1024 * 1024 / UNIV_PAGE_SIZE))
-				<< " MB. Maybe you should make the buffer pool"
-				" bigger?. Starting the InnoDB Monitor to print"
-				" diagnostics, including lock heap and hash"
-				" index sizes.";
+				" occupied by lock heaps"
+#ifdef BTR_CUR_HASH_ADAPT
+				" or the adaptive hash index!"
+#endif /* BTR_CUR_HASH_ADAPT */
+				" Check that your transactions do not"
+				" set too many row locks."
+				" innodb_buffer_pool_size="
+				<< (buf_pool->curr_size >>
+				    (20 - UNIV_PAGE_SIZE_SHIFT)) << "M."
+				" Starting the InnoDB Monitor to print"
+				" diagnostics.";
 
 			buf_lru_switched_on_innodb_mon = true;
 			srv_print_innodb_monitor = TRUE;
diff --git a/storage/innobase/dict/dict0dict.cc b/storage/innobase/dict/dict0dict.cc
index 51a8f9de012..8e4e94743f5 100644
--- a/storage/innobase/dict/dict0dict.cc
+++ b/storage/innobase/dict/dict0dict.cc
@@ -1470,8 +1470,6 @@ dict_table_can_be_evicted(
 	ut_a(table->referenced_set.empty());
 
 	if (table->get_ref_count() == 0) {
-		dict_index_t*	index;
-
 		/* The transaction commit and rollback are called from
 		outside the handler interface. This means that there is
 		a window where the table->n_ref_count can be zero but
@@ -1481,7 +1479,8 @@ dict_table_can_be_evicted(
 			return(FALSE);
 		}
 
-		for (index = dict_table_get_first_index(table);
+#ifdef BTR_CUR_HASH_ADAPT
+		for (dict_index_t* index = dict_table_get_first_index(table);
 		     index != NULL;
 		     index = dict_table_get_next_index(index)) {
 
@@ -1503,6 +1502,7 @@ dict_table_can_be_evicted(
 				return(FALSE);
 			}
 		}
+#endif /* BTR_CUR_HASH_ADAPT */
 
 		return(TRUE);
 	}
@@ -2610,7 +2610,9 @@ dict_index_add_to_cache_w_vcol(
 	new_index->set_committed(index->is_committed());
 	new_index->allow_duplicates = index->allow_duplicates;
 	new_index->nulls_equal = index->nulls_equal;
+#ifdef BTR_CUR_HASH_ADAPT
 	new_index->disable_ahi = index->disable_ahi;
+#endif /* BTR_CUR_HASH_ADAPT */
 
 	if (dict_index_too_big_for_tree(table, new_index, strict)) {
 
@@ -2680,7 +2682,9 @@ dict_index_add_to_cache_w_vcol(
 	UT_LIST_ADD_LAST(table->indexes, new_index);
 	new_index->table = table;
 	new_index->table_name = table->name.m_name;
+#ifdef BTR_CUR_ADAPT
 	new_index->search_info = btr_search_info_create(new_index->heap);
+#endif /* BTR_CUR_ADAPT */
 
 	new_index->page = page_no;
 	rw_lock_create(index_tree_rw_lock_key, &new_index->lock,
@@ -2737,8 +2741,6 @@ dict_index_remove_from_cache_low(
 					to make room in the table LRU list */
 {
 	lint		size;
-	ulint		retries = 0;
-	btr_search_t*	info;
 
 	ut_ad(table && index);
 	ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
@@ -2753,9 +2755,11 @@ dict_index_remove_from_cache_low(
 		row_log_free(index->online_log);
 	}
 
+#ifdef BTR_CUR_HASH_ADAPT
 	/* We always create search info whether or not adaptive
 	hash index is enabled or not. */
-	info = btr_search_get_info(index);
+	btr_search_t*	info = btr_search_get_info(index);
+	ulint		retries = 0;
 	ut_ad(info);
 
 	/* We are not allowed to free the in-memory index struct
@@ -2789,10 +2793,9 @@ dict_index_remove_from_cache_low(
 
 		/* To avoid a hang here we commit suicide if the
 		ref_count doesn't drop to zero in 600 seconds. */
-		if (retries >= 60000) {
-			ut_error;
-		}
+		ut_a(retries < 60000);
 	} while (srv_shutdown_state == SRV_SHUTDOWN_NONE || !lru_evict);
+#endif /* BTR_CUR_HASH_ADAPT */
 
 	rw_lock_free(&index->lock);
 
diff --git a/storage/innobase/fsp/fsp0fsp.cc b/storage/innobase/fsp/fsp0fsp.cc
index 011a786844c..da652d52771 100644
--- a/storage/innobase/fsp/fsp0fsp.cc
+++ b/storage/innobase/fsp/fsp0fsp.cc
@@ -3572,7 +3572,9 @@ fseg_free_page_low(
 	fseg_inode_t*		seg_inode,
 	const page_id_t&	page_id,
 	const page_size_t&	page_size,
+#ifdef BTR_CUR_HASH_ADAPT
 	bool			ahi,
+#endif /* BTR_CUR_HASH_ADAPT */
 	mtr_t*			mtr)
 {
 	xdes_t*	descr;
@@ -3588,13 +3590,14 @@ fseg_free_page_low(
 	      == FSEG_MAGIC_N_VALUE);
 	ut_ad(!((page_offset(seg_inode) - FSEG_ARR_OFFSET) % FSEG_INODE_SIZE));
 	ut_d(fsp_space_modify_check(page_id.space(), mtr));
-
+#ifdef BTR_CUR_HASH_ADAPT
 	/* Drop search system page hash index if the page is found in
 	the pool and is hashed */
 
 	if (ahi) {
 		btr_search_drop_page_hash_when_freed(page_id, page_size);
 	}
+#endif /* BTR_CUR_HASH_ADAPT */
 
 	descr = xdes_get_descriptor(page_id.space(), page_id.page_no(),
 				    page_size, mtr);
@@ -3682,16 +3685,22 @@ crash:
 	}
 }
 
+#ifndef BTR_CUR_HASH_ADAPT
+# define fseg_free_page_low(inode, id, page_size, ahi, mtr)	\
+	fseg_free_page_low(inode, id, page_size, mtr)
+#endif /* !BTR_CUR_HASH_ADAPT */
+
 /**********************************************************************//**
 Frees a single page of a segment. */
 void
-fseg_free_page(
-/*===========*/
+fseg_free_page_func(
 	fseg_header_t*	seg_header, /*!< in: segment header */
 	ulint		space_id,/*!< in: space id */
 	ulint		page,	/*!< in: page offset */
+#ifdef BTR_CUR_HASH_ADAPT
 	bool		ahi,	/*!< in: whether we may need to drop
 				the adaptive hash index */
+#endif /* BTR_CUR_HASH_ADAPT */
 	mtr_t*		mtr)	/*!< in/out: mini-transaction */
 {
 	fseg_inode_t*		seg_inode;
@@ -3757,15 +3766,15 @@ fseg_free_extent(
 	ulint		space,	/*!< in: space id */
 	const page_size_t&	page_size,
 	ulint		page,	/*!< in: a page in the extent */
+#ifdef BTR_CUR_HASH_ADAPT
 	bool		ahi,	/*!< in: whether we may need to drop
 				the adaptive hash index */
+#endif /* BTR_CUR_HASH_ADAPT */
 	mtr_t*		mtr)	/*!< in/out: mini-transaction */
 {
-	ulint	first_page_in_extent;
 	xdes_t*	descr;
 	ulint	not_full_n_used;
 	ulint	descr_n_used;
-	ulint	i;
 
 	ut_ad(seg_inode != NULL);
 	ut_ad(mtr != NULL);
@@ -3778,10 +3787,12 @@ fseg_free_extent(
 	      == FSEG_MAGIC_N_VALUE);
 	ut_d(fsp_space_modify_check(space, mtr));
 
-	first_page_in_extent = page - (page % FSP_EXTENT_SIZE);
-
+#if defined BTR_CUR_HASH_ADAPT || defined UNIV_DEBUG
+	ulint	first_page_in_extent = page - (page % FSP_EXTENT_SIZE);
+#endif
+#ifdef BTR_CUR_HASH_ADAPT
 	if (ahi) {
-		for (i = 0; i < FSP_EXTENT_SIZE; i++) {
+		for (ulint i = 0; i < FSP_EXTENT_SIZE; i++) {
 			if (!xdes_mtr_get_bit(descr, XDES_FREE_BIT, i, mtr)) {
 
 				/* Drop search system page hash index
@@ -3795,6 +3806,7 @@ fseg_free_extent(
 			}
 		}
 	}
+#endif /* BTR_CUR_HASH_ADAPT */
 
 	if (xdes_is_full(descr, mtr)) {
 		flst_remove(seg_inode + FSEG_FULL,
@@ -3819,7 +3831,7 @@ fseg_free_extent(
 	fsp_free_extent(page_id_t(space, page), page_size, mtr);
 
 #ifdef UNIV_DEBUG
-	for (i = 0; i < FSP_EXTENT_SIZE; i++) {
+	for (ulint i = 0; i < FSP_EXTENT_SIZE; i++) {
 
 		buf_page_set_file_page_was_freed(
 			page_id_t(space, first_page_in_extent + i));
@@ -3827,6 +3839,11 @@ fseg_free_extent(
 #endif /* UNIV_DEBUG */
 }
 
+#ifndef BTR_CUR_HASH_ADAPT
+# define fseg_free_extent(inode, space, page_size, page, ahi, mtr)	\
+	fseg_free_extent(inode, space, page_size, page, mtr)
+#endif /* !BTR_CUR_HASH_ADAPT */
+
 /**********************************************************************//**
 Frees part of a segment. This function can be used to free a segment by
 repeatedly calling this function in different mini-transactions. Doing
@@ -3834,14 +3851,15 @@ the freeing in a single mini-transaction might result in too big a
 mini-transaction.
 @return TRUE if freeing completed */
 ibool
-fseg_free_step(
-/*===========*/
+fseg_free_step_func(
 	fseg_header_t*	header,	/*!< in, own: segment header; NOTE: if the header
 				resides on the first page of the frag list
 				of the segment, this pointer becomes obsolete
 				after the last freeing step */
+#ifdef BTR_CUR_HASH_ADAPT
 	bool		ahi,	/*!< in: whether we may need to drop
 				the adaptive hash index */
+#endif /* BTR_CUR_HASH_ADAPT */
 	mtr_t*		mtr)	/*!< in/out: mini-transaction */
 {
 	ulint		n;
@@ -3920,12 +3938,13 @@ Frees part of a segment. Differs from fseg_free_step because this function
 leaves the header page unfreed.
 @return TRUE if freeing completed, except the header page */
 ibool
-fseg_free_step_not_header(
-/*======================*/
+fseg_free_step_not_header_func(
 	fseg_header_t*	header,	/*!< in: segment header which must reside on
 				the first fragment page of the segment */
+#ifdef BTR_CUR_HASH_ADAPT
 	bool		ahi,	/*!< in: whether we may need to drop
 				the adaptive hash index */
+#endif /* BTR_CUR_HASH_ADAPT */
 	mtr_t*		mtr)	/*!< in/out: mini-transaction */
 {
 	ulint		n;
diff --git a/storage/innobase/gis/gis0sea.cc b/storage/innobase/gis/gis0sea.cc
index f426935d551..c760f8e2d29 100644
--- a/storage/innobase/gis/gis0sea.cc
+++ b/storage/innobase/gis/gis0sea.cc
@@ -1558,6 +1558,7 @@ rtr_copy_buf(
 	/* Skip buf_block_t::lock */
 	matches->block.lock_hash_val = block->lock_hash_val;
 	matches->block.modify_clock = block->modify_clock;
+#ifdef BTR_CUR_HASH_ADAPT
 	matches->block.n_hash_helps = block->n_hash_helps;
 	matches->block.n_fields = block->n_fields;
 	matches->block.left_side = block->left_side;
@@ -1567,6 +1568,7 @@ rtr_copy_buf(
 	matches->block.curr_n_fields = block->curr_n_fields;
 	matches->block.curr_left_side = block->curr_left_side;
 	matches->block.index = block->index;
+#endif /* BTR_CUR_HASH_ADAPT */
 	matches->block.made_dirty_with_no_latch
 		= block->made_dirty_with_no_latch;
 
diff --git a/storage/innobase/ha/ha0ha.cc b/storage/innobase/ha/ha0ha.cc
index 2e18891304e..10fb46bd16f 100644
--- a/storage/innobase/ha/ha0ha.cc
+++ b/storage/innobase/ha/ha0ha.cc
@@ -153,7 +153,9 @@ ha_clear(
 	hash_table_t*	table)	/*!< in, own: hash table */
 {
 	ut_ad(table->magic_n == HASH_TABLE_MAGIC_N);
+#ifdef BTR_CUR_HASH_ADAPT
 	ut_ad(!table->adaptive || btr_search_own_all(RW_LOCK_X));
+#endif /* BTR_CUR_HASH_ADAPT */
 
 	for (ulint i = 0; i < table->n_sync_obj; i++) {
 		mem_heap_free(table->heaps[i]);
@@ -196,6 +198,7 @@ ha_clear(
 	}
 }
 
+#ifdef BTR_CUR_HASH_ADAPT
 /*************************************************************//**
 Inserts an entry into a hash table. If an entry with the same fold number
 is found, its node is updated to point to the new data, and no new node
@@ -548,4 +551,5 @@ builds, see http://bugs.mysql.com/36941 */
 			(ulong) n_bufs);
 	}
 }
+#endif /* BTR_CUR_HASH_ADAPT */
 #endif /* !UNIV_HOTBACKUP */
diff --git a/storage/innobase/ha/hash0hash.cc b/storage/innobase/ha/hash0hash.cc
index 234fd7ac032..7f154437e3b 100644
--- a/storage/innobase/ha/hash0hash.cc
+++ b/storage/innobase/ha/hash0hash.cc
@@ -278,9 +278,11 @@ hash_create(
 	table->array = array;
 	table->n_cells = prime;
 #ifndef UNIV_HOTBACKUP
+#ifdef BTR_CUR_HASH_ADAPT
 # if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG
 	table->adaptive = FALSE;
 # endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */
+#endif /* BTR_CUR_HASH_ADAPT */
 	table->n_sync_obj = 0;
 	table->sync_obj.mutexes = NULL;
 	table->heaps = NULL;
diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc
index 61967b50976..b0aeec35ce2 100644
--- a/storage/innobase/handler/ha_innodb.cc
+++ b/storage/innobase/handler/ha_innodb.cc
@@ -1520,11 +1520,13 @@ innobase_srv_conc_exit_innodb(
 	}
 
 	trx_t*			trx = prebuilt->trx;
-#ifdef UNIV_DEBUG
+#ifdef BTR_CUR_HASH_ADAPT
+# ifdef UNIV_DEBUG
 	btrsea_sync_check	check(trx->has_search_latch);
 
 	ut_ad(!sync_check_iterate(check));
-#endif /* UNIV_DEBUG */
+# endif /* UNIV_DEBUG */
+#endif /* BTR_CUR_HASH_ADAPT */
 
 	/* This is to avoid making an unnecessary function call. */
 	if (trx->declared_to_be_inside_innodb
@@ -1542,11 +1544,13 @@ innobase_srv_conc_force_exit_innodb(
 /*================================*/
 	trx_t*	trx)	/*!< in: transaction handle */
 {
-#ifdef UNIV_DEBUG
+#ifdef BTR_CUR_HASH_ADAPT
+# ifdef UNIV_DEBUG
 	btrsea_sync_check	check(trx->has_search_latch);
 
 	ut_ad(!sync_check_iterate(check));
-#endif /* UNIV_DEBUG */
+# endif /* UNIV_DEBUG */
+#endif /* BTR_CUR_HASH_ADAPT */
 
 	/* This is to avoid making an unnecessary function call. */
 	if (trx->declared_to_be_inside_innodb) {
@@ -1624,12 +1628,13 @@ const char*
 thd_innodb_tmpdir(
 	THD*	thd)
 {
-
-#ifdef UNIV_DEBUG
+#ifdef BTR_CUR_HASH_ADAPT
+# ifdef UNIV_DEBUG
 	trx_t*	trx = thd_to_trx(thd);
 	btrsea_sync_check	check(trx->has_search_latch);
 	ut_ad(!sync_check_iterate(check));
-#endif /* UNIV_DEBUG */
+# endif /* UNIV_DEBUG */
+#endif /* BTR_CUR_HASH_ADAPT */
 
 	const char*	tmp_dir = THDVAR(thd, tmpdir);
 
@@ -1737,7 +1742,7 @@ innobase_release_temporary_latches(
 	trx_t*	trx = thd_to_trx(thd);
 
 	if (trx != NULL) {
-		trx_search_latch_release_if_reserved(trx);
+		trx_assert_no_search_latch(trx);
 	}
 
 	return(0);
@@ -2966,7 +2971,6 @@ innobase_query_caching_of_table_permitted(
 				to the table */
 	ulonglong *unused)	/*!< unused for this engine */
 {
-	bool	is_autocommit;
 	char	norm_name[1000];
 	trx_t*	trx = check_trx_exists(thd);
 
@@ -2976,29 +2980,14 @@ innobase_query_caching_of_table_permitted(
 		/* In the SERIALIZABLE mode we add LOCK IN SHARE MODE to every
 		plain SELECT if AUTOCOMMIT is not on. */
 
-		return(static_cast<my_bool>(false));
-	}
-
-	if (trx->has_search_latch) {
-		sql_print_error("The calling thread is holding the adaptive"
-				" search, latch though calling"
-				" innobase_query_caching_of_table_permitted.");
-		trx_print(stderr, trx, 1024);
+		return(false);
 	}
 
-	trx_search_latch_release_if_reserved(trx);
-
+	trx_assert_no_search_latch(trx);
 	innobase_srv_conc_force_exit_innodb(trx);
 
-	if (!thd_test_options(thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) {
-
-		is_autocommit = true;
-	} else {
-		is_autocommit = false;
-
-	}
-
-	if (is_autocommit && trx->n_mysql_tables_in_use == 0) {
+	if (!thd_test_options(thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)
+	    && trx->n_mysql_tables_in_use == 0) {
 		/* We are going to retrieve the query result from the query
 		cache. This cannot be a store operation to the query cache
 		because then MySQL would have locks on tables already.
@@ -3017,7 +3006,7 @@ innobase_query_caching_of_table_permitted(
 		then trx2 would have already invalidated the cache. Thus we
 		can trust the result in the cache is ok for this query. */
 
-		return((my_bool)TRUE);
+		return(true);
 	}
 
 	/* Normalize the table name to InnoDB format */
@@ -3025,12 +3014,7 @@ innobase_query_caching_of_table_permitted(
 
 	innobase_register_trx(innodb_hton_ptr, thd, trx);
 
-	if (row_search_check_if_query_cache_permitted(trx, norm_name)) {
-
-		return(static_cast<my_bool>(true));
-	}
-
-	return(static_cast<my_bool>(false));
+	return(row_search_check_if_query_cache_permitted(trx, norm_name));
 }
 
 /*****************************************************************//**
@@ -3256,7 +3240,7 @@ ha_innobase::init_table_handle_for_HANDLER(void)
 	/* Initialize the m_prebuilt struct much like it would be inited in
 	external_lock */
 
-	trx_search_latch_release_if_reserved(m_prebuilt->trx);
+	trx_assert_no_search_latch(m_prebuilt->trx);
 
 	innobase_srv_conc_force_exit_innodb(m_prebuilt->trx);
 
@@ -4461,11 +4445,9 @@ innobase_rollback_trx(
 	DBUG_ENTER("innobase_rollback_trx");
 	DBUG_PRINT("trans", ("aborting transaction"));
 
-	/* Release a possible FIFO ticket and search latch. Since we will
-	reserve the trx_sys->mutex, we have to release the search system
-	latch first to obey the latching order. */
+	/* Release a possible FIFO ticket. */
 
-	trx_search_latch_release_if_reserved(trx);
+	trx_assert_no_search_latch(trx);
 
 	innobase_srv_conc_force_exit_innodb(trx);
 
@@ -10348,6 +10330,7 @@ create_index(
 		index->nulls_equal =
 			(key->flags & HA_NULL_ARE_EQUAL) ? true : false;
 
+#ifdef BTR_CUR_HASH_ADAPT
 		/* Disable use of AHI for intrinsic table indexes as AHI
 		validates the predicated entry using index-id which has to be
 		system-wide unique that is not the case with indexes of
@@ -10356,6 +10339,7 @@ create_index(
 		and update AHI would not help on performance front as it does
 		with normal tables. */
 		index->disable_ahi = true;
+#endif /* BTR_CUR_HASH_ADAPT */
 	}
 
 	for (ulint i = 0; i < key->user_defined_key_parts; i++) {
@@ -10472,7 +10456,7 @@ create_clustered_index_when_no_primary(
 	innodb_session_t*& priv = thd_to_innodb_session(trx->mysql_thd);
 
 	dict_table_t* handler = priv->lookup_table_handler(table_name);
-
+#ifdef BTR_CUR_HASH_ADAPT
 	if (handler != NULL) {
 		/* Disable use of AHI for intrinsic table indexes as AHI
 		validates the predicated entry using index-id which has to be
@@ -10483,6 +10467,7 @@ create_clustered_index_when_no_primary(
 		with normal tables. */
 		index->disable_ahi = true;
 	}
+#endif /* BTR_CUR_HASH_ADAPT */
 
 	error = row_create_index_for_mysql(index, trx, NULL, handler);
 
@@ -11664,10 +11649,7 @@ create_table_info_t::initialize()
 
 	parent_trx = check_trx_exists(m_thd);
 
-	/* In case MySQL calls this in the middle of a SELECT query, release
-	possible adaptive hash latch to avoid deadlocks of threads */
-
-	trx_search_latch_release_if_reserved(parent_trx);
+	trx_assert_no_search_latch(parent_trx);
 	DBUG_RETURN(0);
 }
 
@@ -12706,14 +12688,7 @@ innobase_create_tablespace(
 		DBUG_RETURN(convert_error_code_to_mysql(err, 0, NULL));
 	}
 
-	/* Get the transaction associated with the current thd and make
-	sure it will not block this DDL. */
-	trx_t*	parent_trx = check_trx_exists(thd);
-
-	/* In case MySQL calls this in the middle of a SELECT
-	query, release possible adaptive hash latch to avoid
-	deadlocks of threads */
-	trx_search_latch_release_if_reserved(parent_trx);
+	trx_assert_no_search_latch(check_trx_exists(thd));
 
 	/* Allocate a new transaction for this DDL */
 	trx = innobase_trx_allocate(thd);
@@ -12806,14 +12781,7 @@ innobase_drop_tablespace(
 		DBUG_RETURN(HA_ERR_TABLESPACE_IS_NOT_EMPTY);
 	}
 
-	/* Get the transaction associated with the current thd and make sure
-	it will not block this DDL. */
-	trx_t*	parent_trx = check_trx_exists(thd);
-
-	/* In case MySQL calls this in the middle of a SELECT
-	query, release possible adaptive hash latch to avoid
-	deadlocks of threads */
-	trx_search_latch_release_if_reserved(parent_trx);
+	trx_assert_no_search_latch(check_trx_exists(thd));
 
 	/* Allocate a new transaction for this DDL */
 	trx = innobase_trx_allocate(thd);
@@ -12941,16 +12909,11 @@ innobase_drop_database(
 
 	THD*	thd = current_thd;
 
-	/* In the Windows plugin, thd = current_thd is always NULL */
-	if (thd != NULL) {
-		trx_t*	parent_trx = check_trx_exists(thd);
-
-		/* In case MySQL calls this in the middle of a SELECT
-		query, release possible adaptive hash latch to avoid
-		deadlocks of threads */
+	/* In case MySQL calls this in the middle of a SELECT
+	query, release possible adaptive hash latch to avoid
+	deadlocks of threads */
 
-		trx_search_latch_release_if_reserved(parent_trx);
-	}
+	trx_assert_no_search_latch(check_trx_exists(thd));
 
 	ulint	len = 0;
 	char*	ptr = strend(path) - 2;
@@ -13809,7 +13772,7 @@ ha_innobase::info_low(
 
 	m_prebuilt->trx->op_info = (char*)"returning various info to MySQL";
 
-	trx_search_latch_release_if_reserved(m_prebuilt->trx);
+	trx_assert_no_search_latch(m_prebuilt->trx);
 
 	ib_table = m_prebuilt->table;
 	DBUG_ASSERT(ib_table->n_ref_count > 0);
@@ -14560,7 +14523,8 @@ ha_innobase::check(
 
 	/* Restore the original isolation level */
 	m_prebuilt->trx->isolation_level = old_isolation_level;
-#if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG
+#ifdef BTR_CUR_HASH_ADAPT
+# if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG
 	/* We validate the whole adaptive hash index for all tables
 	at every CHECK TABLE only when QUICK flag is not present. */
 
@@ -14570,7 +14534,8 @@ ha_innobase::check(
 			     "InnoDB: The adaptive hash index is corrupted.");
 		is_ok = false;
 	}
-#endif /* defined UNIV_AHI_DEBUG || defined UNIV_DEBUG */
+# endif /* defined UNIV_AHI_DEBUG || defined UNIV_DEBUG */
+#endif /* BTR_CUR_HASH_ADAPT */
 	m_prebuilt->trx->op_info = "";
 	if (thd_killed(m_user_thd)) {
 		thd_set_kill_status(m_user_thd);
@@ -14603,7 +14568,7 @@ ha_innobase::get_foreign_key_create_info(void)
 	release possible adaptive hash latch to avoid
 	deadlocks of threads */
 
-	trx_search_latch_release_if_reserved(m_prebuilt->trx);
+	trx_assert_no_search_latch(m_prebuilt->trx);
 
 	if (!srv_read_only_mode) {
 		mutex_enter(&srv_dict_tmpfile_mutex);
@@ -15669,7 +15634,7 @@ innodb_show_status(
 
 	trx_t*	trx = check_trx_exists(thd);
 
-	trx_search_latch_release_if_reserved(trx);
+	trx_assert_no_search_latch(trx);
 
 	innobase_srv_conc_force_exit_innodb(trx);
 
@@ -16908,7 +16873,7 @@ innobase_xa_prepare(
 	reserve the trx_sys->mutex, we have to release the search system
 	latch first to obey the latching order. */
 
-	trx_search_latch_release_if_reserved(trx);
+	trx_assert_no_search_latch(trx);
 
 	innobase_srv_conc_force_exit_innodb(trx);
 
@@ -17677,6 +17642,7 @@ innodb_internal_table_update(
 	}
 }
 
+#ifdef BTR_CUR_HASH_ADAPT
 /****************************************************************//**
 Update the system variable innodb_adaptive_hash_index using the "saved"
 value. This function is registered as a callback with MySQL. */
@@ -17698,6 +17664,7 @@ innodb_adaptive_hash_index_update(
 		btr_search_disable(true);
 	}
 }
+#endif /* BTR_CUR_HASH_ADAPT */
 
 /****************************************************************//**
 Update the system variable innodb_cmp_per_index using the "saved"
@@ -19437,6 +19404,7 @@ static MYSQL_SYSVAR_ULONGLONG(stats_persistent_sample_pages,
   " statistics (by ANALYZE, default 20)",
   NULL, NULL, 20, 1, ~0ULL, 0);
 
+#ifdef BTR_CUR_HASH_ADAPT
 static MYSQL_SYSVAR_BOOL(adaptive_hash_index, btr_search_enabled,
   PLUGIN_VAR_OPCMDARG,
   "Enable InnoDB adaptive hash index (enabled by default). "
@@ -19448,8 +19416,9 @@ Each partition is protected by its own latch and so we have parts number
 of latches protecting complete search system. */
 static MYSQL_SYSVAR_ULONG(adaptive_hash_index_parts, btr_ahi_parts,
   PLUGIN_VAR_OPCMDARG | PLUGIN_VAR_READONLY,
-  "Number of InnoDB Adapative Hash Index Partitions. (default = 8). ",
+  "Number of InnoDB Adaptive Hash Index Partitions (default 8)",
   NULL, NULL, 8, 1, 512, 0);
+#endif /* BTR_CUR_HASH_ADAPT */
 
 static MYSQL_SYSVAR_ULONG(replication_delay, srv_replication_delay,
   PLUGIN_VAR_RQCMDARG,
@@ -20166,8 +20135,10 @@ static struct st_mysql_sys_var* innobase_system_variables[]= {
   MYSQL_SYSVAR(stats_persistent),
   MYSQL_SYSVAR(stats_persistent_sample_pages),
   MYSQL_SYSVAR(stats_auto_recalc),
+#ifdef BTR_CUR_HASH_ADAPT
   MYSQL_SYSVAR(adaptive_hash_index),
   MYSQL_SYSVAR(adaptive_hash_index_parts),
+#endif /* BTR_CUR_HASH_ADAPT */
   MYSQL_SYSVAR(stats_method),
   MYSQL_SYSVAR(replication_delay),
   MYSQL_SYSVAR(status_file),
diff --git a/storage/innobase/handler/ha_innopart.cc b/storage/innobase/handler/ha_innopart.cc
index 5fd02dfa016..0958ee5f51d 100644
--- a/storage/innobase/handler/ha_innopart.cc
+++ b/storage/innobase/handler/ha_innopart.cc
@@ -3191,7 +3191,7 @@ ha_innopart::records_in_range(
 	/* In case MySQL calls this in the middle of a SELECT query, release
 	possible adaptive hash latch to avoid deadlocks of threads. */
 
-	trx_search_latch_release_if_reserved(m_prebuilt->trx);
+	trx_assert_no_search_latch(m_prebuilt->trx);
 
 	active_index = keynr;
 
@@ -3330,7 +3330,7 @@ ha_innopart::estimate_rows_upper_bound()
 	/* In case MySQL calls this in the middle of a SELECT query, release
 	possible adaptive hash latch to avoid deadlocks of threads. */
 
-	trx_search_latch_release_if_reserved(m_prebuilt->trx);
+	trx_assert_no_search_latch(m_prebuilt->trx);
 
 	for (uint i = m_part_info->get_first_used_partition();
 	     i < m_tot_parts;
@@ -3448,7 +3448,7 @@ ha_innopart::info_low(
 
 	m_prebuilt->trx->op_info = (char*)"returning various info to MySQL";
 
-	trx_search_latch_release_if_reserved(m_prebuilt->trx);
+	trx_assert_no_search_latch(m_prebuilt->trx);
 
 	ut_ad(m_part_share->get_table_part(0)->n_ref_count > 0);
 
diff --git a/storage/innobase/handler/handler0alter.cc b/storage/innobase/handler/handler0alter.cc
index aeccb357358..7a3a0035c8d 100644
--- a/storage/innobase/handler/handler0alter.cc
+++ b/storage/innobase/handler/handler0alter.cc
@@ -568,7 +568,7 @@ ha_innobase::check_if_supported_inplace_alter(
 	}
 
 	update_thd();
-	trx_search_latch_release_if_reserved(m_prebuilt->trx);
+	trx_assert_no_search_latch(m_prebuilt->trx);
 
 	if (ha_alter_info->handler_flags
 	    & ~(INNOBASE_INPLACE_IGNORE
@@ -8588,11 +8588,12 @@ foreign_fail:
 		}
 
 		trx_commit_for_mysql(m_prebuilt->trx);
-
+#ifdef BTR_CUR_HASH_ADAPT
 		if (btr_search_enabled) {
 			btr_search_disable(false);
 			btr_search_enable();
 		}
+#endif /* BTR_CUR_HASH_ADAPT */
 
 		char	tb_name[FN_REFLEN];
 		ut_strcpy(tb_name, m_prebuilt->table->name.m_name);
diff --git a/storage/innobase/handler/i_s.cc b/storage/innobase/handler/i_s.cc
index cb203896e8a..82cbac440b7 100644
--- a/storage/innobase/handler/i_s.cc
+++ b/storage/innobase/handler/i_s.cc
@@ -119,8 +119,10 @@ struct buf_page_info_t{
 	unsigned	io_fix:2;	/*!< type of pending I/O operation */
 	unsigned	fix_count:19;	/*!< Count of how manyfold this block
 					is bufferfixed */
+#ifdef BTR_CUR_HASH_ADAPT
 	unsigned	hashed:1;	/*!< Whether hash index has been
 					built on this page */
+#endif /* BTR_CUR_HASH_ADAPT */
 	unsigned	is_old:1;	/*!< TRUE if the block is in the old
 					blocks in buf_pool->LRU_old */
 	unsigned	freed_page_clock:31; /*!< the value of
@@ -352,6 +354,12 @@ field_store_ulint(
 	return(ret);
 }
 
+#ifdef BTR_CUR_HASH_ADAPT
+# define I_S_AHI 1 /* Include the IS_HASHED column */
+#else
+# define I_S_AHI 0 /* Omit the IS_HASHED column */
+#endif
+
 /* Fields of the dynamic table INFORMATION_SCHEMA.innodb_trx */
 static ST_FIELD_INFO	innodb_trx_fields_info[] =
 {
@@ -535,6 +543,7 @@ static ST_FIELD_INFO	innodb_trx_fields_info[] =
 	 STRUCT_FLD(old_name,		""),
 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
 
+#ifdef BTR_CUR_HASH_ADAPT
 #define IDX_TRX_ADAPTIVE_HASH_LATCHED	20
 	{STRUCT_FLD(field_name,		"trx_adaptive_hash_latched"),
 	 STRUCT_FLD(field_length,	1),
@@ -543,17 +552,9 @@ static ST_FIELD_INFO	innodb_trx_fields_info[] =
 	 STRUCT_FLD(field_flags,	0),
 	 STRUCT_FLD(old_name,		""),
 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
+#endif /* BTR_CUR_HASH_ADAPT */
 
-#define IDX_TRX_ADAPTIVE_HASH_TIMEOUT	21
-	{STRUCT_FLD(field_name,		"trx_adaptive_hash_timeout"),
-	 STRUCT_FLD(field_length,	MY_INT64_NUM_DECIMAL_DIGITS),
-	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONGLONG),
-	 STRUCT_FLD(value,		0),
-	 STRUCT_FLD(field_flags,	MY_I_S_UNSIGNED),
-	 STRUCT_FLD(old_name,		""),
-	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
-
-#define IDX_TRX_READ_ONLY		22
+#define IDX_TRX_READ_ONLY		20 + I_S_AHI
 	{STRUCT_FLD(field_name,		"trx_is_read_only"),
 	 STRUCT_FLD(field_length,	1),
 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONG),
@@ -562,7 +563,7 @@ static ST_FIELD_INFO	innodb_trx_fields_info[] =
 	 STRUCT_FLD(old_name,		""),
 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
 
-#define IDX_TRX_AUTOCOMMIT_NON_LOCKING	23
+#define IDX_TRX_AUTOCOMMIT_NON_LOCKING	21 + I_S_AHI
 	{STRUCT_FLD(field_name,		"trx_autocommit_non_locking"),
 	 STRUCT_FLD(field_length,	1),
 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONG),
@@ -709,9 +710,11 @@ fill_innodb_trx_from_cache(
 		OK(field_store_string(fields[IDX_TRX_LAST_FOREIGN_KEY_ERROR],
 				      row->trx_foreign_key_error));
 
+#ifdef BTR_CUR_HASH_ADAPT
 		/* trx_adaptive_hash_latched */
 		OK(fields[IDX_TRX_ADAPTIVE_HASH_LATCHED]->store(
 			   row->trx_has_search_latch, true));
+#endif /* BTR_CUR_HASH_ADAPT */
 
 		/* trx_is_read_only*/
 		OK(fields[IDX_TRX_READ_ONLY]->store(
@@ -5081,6 +5084,7 @@ static ST_FIELD_INFO	i_s_innodb_buffer_page_fields_info[] =
 	 STRUCT_FLD(old_name,		""),
 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
 
+#ifdef BTR_CUR_HASH_ADAPT
 #define IDX_BUFFER_PAGE_HASHED		7
 	{STRUCT_FLD(field_name,		"IS_HASHED"),
 	 STRUCT_FLD(field_length,	3),
@@ -5089,8 +5093,9 @@ static ST_FIELD_INFO	i_s_innodb_buffer_page_fields_info[] =
 	 STRUCT_FLD(field_flags,	MY_I_S_MAYBE_NULL),
 	 STRUCT_FLD(old_name,		""),
 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
+#endif /* BTR_CUR_HASH_ADAPT */
 
-#define IDX_BUFFER_PAGE_NEWEST_MOD	8
+#define IDX_BUFFER_PAGE_NEWEST_MOD	7 + I_S_AHI
 	{STRUCT_FLD(field_name,		"NEWEST_MODIFICATION"),
 	 STRUCT_FLD(field_length,	MY_INT64_NUM_DECIMAL_DIGITS),
 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONGLONG),
@@ -5099,7 +5104,7 @@ static ST_FIELD_INFO	i_s_innodb_buffer_page_fields_info[] =
 	 STRUCT_FLD(old_name,		""),
 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
 
-#define IDX_BUFFER_PAGE_OLDEST_MOD	9
+#define IDX_BUFFER_PAGE_OLDEST_MOD	8 + I_S_AHI
 	{STRUCT_FLD(field_name,		"OLDEST_MODIFICATION"),
 	 STRUCT_FLD(field_length,	MY_INT64_NUM_DECIMAL_DIGITS),
 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONGLONG),
@@ -5108,7 +5113,7 @@ static ST_FIELD_INFO	i_s_innodb_buffer_page_fields_info[] =
 	 STRUCT_FLD(old_name,		""),
 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
 
-#define IDX_BUFFER_PAGE_ACCESS_TIME	10
+#define IDX_BUFFER_PAGE_ACCESS_TIME	9 + I_S_AHI
 	{STRUCT_FLD(field_name,		"ACCESS_TIME"),
 	 STRUCT_FLD(field_length,	MY_INT64_NUM_DECIMAL_DIGITS),
 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONGLONG),
@@ -5117,7 +5122,7 @@ static ST_FIELD_INFO	i_s_innodb_buffer_page_fields_info[] =
 	 STRUCT_FLD(old_name,		""),
 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
 
-#define IDX_BUFFER_PAGE_TABLE_NAME	11
+#define IDX_BUFFER_PAGE_TABLE_NAME	10 + I_S_AHI
 	{STRUCT_FLD(field_name,		"TABLE_NAME"),
 	 STRUCT_FLD(field_length,	1024),
 	 STRUCT_FLD(field_type,		MYSQL_TYPE_STRING),
@@ -5126,7 +5131,7 @@ static ST_FIELD_INFO	i_s_innodb_buffer_page_fields_info[] =
 	 STRUCT_FLD(old_name,		""),
 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
 
-#define IDX_BUFFER_PAGE_INDEX_NAME	12
+#define IDX_BUFFER_PAGE_INDEX_NAME	11 + I_S_AHI
 	{STRUCT_FLD(field_name,		"INDEX_NAME"),
 	 STRUCT_FLD(field_length,	1024),
 	 STRUCT_FLD(field_type,		MYSQL_TYPE_STRING),
@@ -5135,7 +5140,7 @@ static ST_FIELD_INFO	i_s_innodb_buffer_page_fields_info[] =
 	 STRUCT_FLD(old_name,		""),
 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
 
-#define IDX_BUFFER_PAGE_NUM_RECS	13
+#define IDX_BUFFER_PAGE_NUM_RECS	12 + I_S_AHI
 	{STRUCT_FLD(field_name,		"NUMBER_RECORDS"),
 	 STRUCT_FLD(field_length,	MY_INT64_NUM_DECIMAL_DIGITS),
 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONGLONG),
@@ -5144,7 +5149,7 @@ static ST_FIELD_INFO	i_s_innodb_buffer_page_fields_info[] =
 	 STRUCT_FLD(old_name,		""),
 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
 
-#define IDX_BUFFER_PAGE_DATA_SIZE	14
+#define IDX_BUFFER_PAGE_DATA_SIZE	13 + I_S_AHI
 	{STRUCT_FLD(field_name,		"DATA_SIZE"),
 	 STRUCT_FLD(field_length,	MY_INT64_NUM_DECIMAL_DIGITS),
 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONGLONG),
@@ -5153,7 +5158,7 @@ static ST_FIELD_INFO	i_s_innodb_buffer_page_fields_info[] =
 	 STRUCT_FLD(old_name,		""),
 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
 
-#define IDX_BUFFER_PAGE_ZIP_SIZE	15
+#define IDX_BUFFER_PAGE_ZIP_SIZE	14 + I_S_AHI
 	{STRUCT_FLD(field_name,		"COMPRESSED_SIZE"),
 	 STRUCT_FLD(field_length,	MY_INT64_NUM_DECIMAL_DIGITS),
 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONGLONG),
@@ -5162,7 +5167,7 @@ static ST_FIELD_INFO	i_s_innodb_buffer_page_fields_info[] =
 	 STRUCT_FLD(old_name,		""),
 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
 
-#define IDX_BUFFER_PAGE_STATE		16
+#define IDX_BUFFER_PAGE_STATE		15 + I_S_AHI
 	{STRUCT_FLD(field_name,		"PAGE_STATE"),
 	 STRUCT_FLD(field_length,	64),
 	 STRUCT_FLD(field_type,		MYSQL_TYPE_STRING),
@@ -5171,7 +5176,7 @@ static ST_FIELD_INFO	i_s_innodb_buffer_page_fields_info[] =
 	 STRUCT_FLD(old_name,		""),
 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
 
-#define IDX_BUFFER_PAGE_IO_FIX		17
+#define IDX_BUFFER_PAGE_IO_FIX		16 + I_S_AHI
 	{STRUCT_FLD(field_name,		"IO_FIX"),
 	 STRUCT_FLD(field_length,	64),
 	 STRUCT_FLD(field_type,		MYSQL_TYPE_STRING),
@@ -5180,7 +5185,7 @@ static ST_FIELD_INFO	i_s_innodb_buffer_page_fields_info[] =
 	 STRUCT_FLD(old_name,		""),
 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
 
-#define IDX_BUFFER_PAGE_IS_OLD		18
+#define IDX_BUFFER_PAGE_IS_OLD		17 + I_S_AHI
 	{STRUCT_FLD(field_name,		"IS_OLD"),
 	 STRUCT_FLD(field_length,	3),
 	 STRUCT_FLD(field_type,		MYSQL_TYPE_STRING),
@@ -5189,7 +5194,7 @@ static ST_FIELD_INFO	i_s_innodb_buffer_page_fields_info[] =
 	 STRUCT_FLD(old_name,		""),
 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
 
-#define IDX_BUFFER_PAGE_FREE_CLOCK	19
+#define IDX_BUFFER_PAGE_FREE_CLOCK	18 + I_S_AHI
 	{STRUCT_FLD(field_name,		"FREE_PAGE_CLOCK"),
 	 STRUCT_FLD(field_length,	MY_INT64_NUM_DECIMAL_DIGITS),
 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONGLONG),
@@ -5259,13 +5264,11 @@ i_s_innodb_buffer_page_fill(
 		OK(fields[IDX_BUFFER_PAGE_FIX_COUNT]->store(
 			   page_info->fix_count));
 
-		if (page_info->hashed) {
-			OK(field_store_string(
-				   fields[IDX_BUFFER_PAGE_HASHED], "YES"));
-		} else {
-			OK(field_store_string(
-				   fields[IDX_BUFFER_PAGE_HASHED], "NO"));
-		}
+#ifdef BTR_CUR_HASH_ADAPT
+		OK(field_store_string(
+			   fields[IDX_BUFFER_PAGE_HASHED],
+			   page_info->hashed ? "YES" : "NO"));
+#endif /* BTR_CUR_HASH_ADAPT */
 
 		OK(fields[IDX_BUFFER_PAGE_NEWEST_MOD]->store(
 			   page_info->newest_mod, true));
@@ -5515,11 +5518,13 @@ i_s_innodb_buffer_page_get_info(
 
 			block = reinterpret_cast<const buf_block_t*>(bpage);
 			frame = block->frame;
+#ifdef BTR_CUR_HASH_ADAPT
 			/* Note: this may be a false positive, that
 			is, block->index will not always be set to
 			NULL when the last adaptive hash index
 			reference is dropped. */
 			page_info->hashed = (block->index != NULL);
+#endif /* BTR_CUR_HASH_ADAPT */
 		} else {
 			ut_ad(page_info->zip_ssize);
 			frame = bpage->zip.data;
@@ -5804,6 +5809,7 @@ static ST_FIELD_INFO	i_s_innodb_buf_page_lru_fields_info[] =
 	 STRUCT_FLD(old_name,		""),
 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
 
+#ifdef BTR_CUR_HASH_ADAPT
 #define IDX_BUF_LRU_PAGE_HASHED		7
 	{STRUCT_FLD(field_name,		"IS_HASHED"),
 	 STRUCT_FLD(field_length,	3),
@@ -5812,8 +5818,9 @@ static ST_FIELD_INFO	i_s_innodb_buf_page_lru_fields_info[] =
 	 STRUCT_FLD(field_flags,	MY_I_S_MAYBE_NULL),
 	 STRUCT_FLD(old_name,		""),
 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
+#endif /* BTR_CUR_HASH_ADAPT */
 
-#define IDX_BUF_LRU_PAGE_NEWEST_MOD	8
+#define IDX_BUF_LRU_PAGE_NEWEST_MOD	7 + I_S_AHI
 	{STRUCT_FLD(field_name,		"NEWEST_MODIFICATION"),
 	 STRUCT_FLD(field_length,	MY_INT64_NUM_DECIMAL_DIGITS),
 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONGLONG),
@@ -5822,7 +5829,7 @@ static ST_FIELD_INFO	i_s_innodb_buf_page_lru_fields_info[] =
 	 STRUCT_FLD(old_name,		""),
 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
 
-#define IDX_BUF_LRU_PAGE_OLDEST_MOD	9
+#define IDX_BUF_LRU_PAGE_OLDEST_MOD	8 + I_S_AHI
 	{STRUCT_FLD(field_name,		"OLDEST_MODIFICATION"),
 	 STRUCT_FLD(field_length,	MY_INT64_NUM_DECIMAL_DIGITS),
 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONGLONG),
@@ -5831,7 +5838,7 @@ static ST_FIELD_INFO	i_s_innodb_buf_page_lru_fields_info[] =
 	 STRUCT_FLD(old_name,		""),
 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
 
-#define IDX_BUF_LRU_PAGE_ACCESS_TIME	10
+#define IDX_BUF_LRU_PAGE_ACCESS_TIME	9 + I_S_AHI
 	{STRUCT_FLD(field_name,		"ACCESS_TIME"),
 	 STRUCT_FLD(field_length,	MY_INT64_NUM_DECIMAL_DIGITS),
 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONGLONG),
@@ -5840,7 +5847,7 @@ static ST_FIELD_INFO	i_s_innodb_buf_page_lru_fields_info[] =
 	 STRUCT_FLD(old_name,		""),
 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
 
-#define IDX_BUF_LRU_PAGE_TABLE_NAME	11
+#define IDX_BUF_LRU_PAGE_TABLE_NAME	10 + I_S_AHI
 	{STRUCT_FLD(field_name,		"TABLE_NAME"),
 	 STRUCT_FLD(field_length,	1024),
 	 STRUCT_FLD(field_type,		MYSQL_TYPE_STRING),
@@ -5849,7 +5856,7 @@ static ST_FIELD_INFO	i_s_innodb_buf_page_lru_fields_info[] =
 	 STRUCT_FLD(old_name,		""),
 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
 
-#define IDX_BUF_LRU_PAGE_INDEX_NAME	12
+#define IDX_BUF_LRU_PAGE_INDEX_NAME	11 + I_S_AHI
 	{STRUCT_FLD(field_name,		"INDEX_NAME"),
 	 STRUCT_FLD(field_length,	1024),
 	 STRUCT_FLD(field_type,		MYSQL_TYPE_STRING),
@@ -5858,7 +5865,7 @@ static ST_FIELD_INFO	i_s_innodb_buf_page_lru_fields_info[] =
 	 STRUCT_FLD(old_name,		""),
 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
 
-#define IDX_BUF_LRU_PAGE_NUM_RECS	13
+#define IDX_BUF_LRU_PAGE_NUM_RECS	12 + I_S_AHI
 	{STRUCT_FLD(field_name,		"NUMBER_RECORDS"),
 	 STRUCT_FLD(field_length,	MY_INT64_NUM_DECIMAL_DIGITS),
 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONGLONG),
@@ -5867,7 +5874,7 @@ static ST_FIELD_INFO	i_s_innodb_buf_page_lru_fields_info[] =
 	 STRUCT_FLD(old_name,		""),
 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
 
-#define IDX_BUF_LRU_PAGE_DATA_SIZE	14
+#define IDX_BUF_LRU_PAGE_DATA_SIZE	13 + I_S_AHI
 	{STRUCT_FLD(field_name,		"DATA_SIZE"),
 	 STRUCT_FLD(field_length,	MY_INT64_NUM_DECIMAL_DIGITS),
 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONGLONG),
@@ -5876,7 +5883,7 @@ static ST_FIELD_INFO	i_s_innodb_buf_page_lru_fields_info[] =
 	 STRUCT_FLD(old_name,		""),
 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
 
-#define IDX_BUF_LRU_PAGE_ZIP_SIZE	15
+#define IDX_BUF_LRU_PAGE_ZIP_SIZE	14 + I_S_AHI
 	{STRUCT_FLD(field_name,		"COMPRESSED_SIZE"),
 	 STRUCT_FLD(field_length,	MY_INT64_NUM_DECIMAL_DIGITS),
 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONGLONG),
@@ -5885,7 +5892,7 @@ static ST_FIELD_INFO	i_s_innodb_buf_page_lru_fields_info[] =
 	 STRUCT_FLD(old_name,		""),
 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
 
-#define IDX_BUF_LRU_PAGE_STATE		16
+#define IDX_BUF_LRU_PAGE_STATE		15 + I_S_AHI
 	{STRUCT_FLD(field_name,		"COMPRESSED"),
 	 STRUCT_FLD(field_length,	3),
 	 STRUCT_FLD(field_type,		MYSQL_TYPE_STRING),
@@ -5894,7 +5901,7 @@ static ST_FIELD_INFO	i_s_innodb_buf_page_lru_fields_info[] =
 	 STRUCT_FLD(old_name,		""),
 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
 
-#define IDX_BUF_LRU_PAGE_IO_FIX		17
+#define IDX_BUF_LRU_PAGE_IO_FIX		16 + I_S_AHI
 	{STRUCT_FLD(field_name,		"IO_FIX"),
 	 STRUCT_FLD(field_length,	64),
 	 STRUCT_FLD(field_type,		MYSQL_TYPE_STRING),
@@ -5903,7 +5910,7 @@ static ST_FIELD_INFO	i_s_innodb_buf_page_lru_fields_info[] =
 	 STRUCT_FLD(old_name,		""),
 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
 
-#define IDX_BUF_LRU_PAGE_IS_OLD		18
+#define IDX_BUF_LRU_PAGE_IS_OLD		17 + I_S_AHI
 	{STRUCT_FLD(field_name,		"IS_OLD"),
 	 STRUCT_FLD(field_length,	3),
 	 STRUCT_FLD(field_type,		MYSQL_TYPE_STRING),
@@ -5912,7 +5919,7 @@ static ST_FIELD_INFO	i_s_innodb_buf_page_lru_fields_info[] =
 	 STRUCT_FLD(old_name,		""),
 	 STRUCT_FLD(open_method,	SKIP_OPEN_TABLE)},
 
-#define IDX_BUF_LRU_PAGE_FREE_CLOCK	19
+#define IDX_BUF_LRU_PAGE_FREE_CLOCK	18 + I_S_AHI
 	{STRUCT_FLD(field_name,		"FREE_PAGE_CLOCK"),
 	 STRUCT_FLD(field_length,	MY_INT64_NUM_DECIMAL_DIGITS),
 	 STRUCT_FLD(field_type,		MYSQL_TYPE_LONGLONG),
@@ -5985,13 +5992,11 @@ i_s_innodb_buf_page_lru_fill(
 		OK(fields[IDX_BUF_LRU_PAGE_FIX_COUNT]->store(
 			   page_info->fix_count, true));
 
-		if (page_info->hashed) {
-			OK(field_store_string(
-				   fields[IDX_BUF_LRU_PAGE_HASHED], "YES"));
-		} else {
-			OK(field_store_string(
-				   fields[IDX_BUF_LRU_PAGE_HASHED], "NO"));
-		}
+#ifdef BTR_CUR_HASH_ADAPT
+		OK(field_store_string(
+			   fields[IDX_BUF_LRU_PAGE_HASHED],
+			   page_info->hashed ? "YES" : "NO"));
+#endif /* BTR_CUR_HASH_ADAPT */
 
 		OK(fields[IDX_BUF_LRU_PAGE_NEWEST_MOD]->store(
 			   page_info->newest_mod, true));
diff --git a/storage/innobase/ibuf/ibuf0ibuf.cc b/storage/innobase/ibuf/ibuf0ibuf.cc
index 07c698e4f4c..183c60e7eaa 100644
--- a/storage/innobase/ibuf/ibuf0ibuf.cc
+++ b/storage/innobase/ibuf/ibuf0ibuf.cc
@@ -560,7 +560,9 @@ ibuf_init_at_db_start(void)
 	ibuf->index->n_uniq = REC_MAX_N_FIELDS;
 	rw_lock_create(index_tree_rw_lock_key, &ibuf->index->lock,
 		       SYNC_IBUF_INDEX_TREE);
+#ifdef BTR_CUR_ADAPT
 	ibuf->index->search_info = btr_search_info_create(ibuf->index->heap);
+#endif /* BTR_CUR_ADAPT */
 	ibuf->index->page = FSP_IBUF_TREE_ROOT_PAGE_NO;
 	ut_d(ibuf->index->cached = TRUE);
 }
@@ -3919,11 +3921,13 @@ ibuf_insert_to_index_page(
 	ut_ad(!dict_index_is_online_ddl(index));// this is an ibuf_dummy index
 	ut_ad(ibuf_inside(mtr));
 	ut_ad(dtuple_check_typed(entry));
+#ifdef BTR_CUR_HASH_ADAPT
 	/* A change buffer merge must occur before users are granted
 	any access to the page. No adaptive hash index entries may
 	point to a freshly read page. */
 	ut_ad(!block->index);
 	assert_block_ahi_empty(block);
+#endif /* BTR_CUR_HASH_ADAPT */
 	ut_ad(mtr->is_named_space(block->page.id.space()));
 
 	if (UNIV_UNLIKELY(dict_table_is_comp(index->table)
diff --git a/storage/innobase/include/btr0cur.h b/storage/innobase/include/btr0cur.h
index 8e706d5f15b..e41c4e06888 100644
--- a/storage/innobase/include/btr0cur.h
+++ b/storage/innobase/include/btr0cur.h
@@ -65,9 +65,6 @@ struct btr_latch_leaves_t {
 #include "row0types.h"
 #include "ha0ha.h"
 
-#define BTR_CUR_ADAPT
-#define BTR_CUR_HASH_ADAPT
-
 #ifdef UNIV_DEBUG
 /*********************************************************//**
 Returns the page cursor component of a tree cursor.
@@ -1029,17 +1026,19 @@ inherited external field. */
 
 /** Number of searches down the B-tree in btr_cur_search_to_nth_level(). */
 extern ulint	btr_cur_n_non_sea;
-/** Number of successful adaptive hash index lookups in
-btr_cur_search_to_nth_level(). */
-extern ulint	btr_cur_n_sea;
 /** Old value of btr_cur_n_non_sea.  Copied by
 srv_refresh_innodb_monitor_stats().  Referenced by
 srv_printf_innodb_monitor(). */
 extern ulint	btr_cur_n_non_sea_old;
+#ifdef BTR_CUR_HASH_ADAPT
+/** Number of successful adaptive hash index lookups in
+btr_cur_search_to_nth_level(). */
+extern ulint	btr_cur_n_sea;
 /** Old value of btr_cur_n_sea.  Copied by
 srv_refresh_innodb_monitor_stats().  Referenced by
 srv_printf_innodb_monitor(). */
 extern ulint	btr_cur_n_sea_old;
+#endif /* BTR_CUR_HASH_ADAPT */
 #endif /* !UNIV_HOTBACKUP */
 
 #ifdef UNIV_DEBUG
diff --git a/storage/innobase/include/btr0sea.h b/storage/innobase/include/btr0sea.h
index 12659037904..0072f468bba 100644
--- a/storage/innobase/include/btr0sea.h
+++ b/storage/innobase/include/btr0sea.h
@@ -32,6 +32,7 @@ Created 2/17/1996 Heikki Tuuri
 #include "dict0dict.h"
 #include "btr0types.h"
 #include "mtr0mtr.h"
+#ifdef BTR_CUR_HASH_ADAPT
 #include "ha0ha.h"
 
 /** Creates and initializes the adaptive search system at a database start.
@@ -57,22 +58,6 @@ btr_search_disable(
 void
 btr_search_enable();
 
-/********************************************************************//**
-Returns search info for an index.
-@return search info; search mutex reserved */
-UNIV_INLINE
-btr_search_t*
-btr_search_get_info(
-/*================*/
-	dict_index_t*	index)	/*!< in: index */
-	MY_ATTRIBUTE((nonnull));
-
-/** Creates and initializes a search info struct.
-@param[in]	heap		heap where created.
-@return own: search info struct */
-btr_search_t*
-btr_search_info_create(mem_heap_t* heap);
-
 /** Returns the value of ref_count. The value is protected by latch.
 @param[in]	info		search info
 @param[in]	index		index identifier
@@ -257,16 +242,41 @@ A table is selected from an array of tables using pair of index-id, space-id.
 UNIV_INLINE
 hash_table_t*
 btr_get_search_table(const dict_index_t* index);
+#else /* BTR_CUR_HASH_ADAPT */
+# define btr_search_sys_create(size)
+# define btr_search_drop_page_hash_index(block)
+# define btr_search_clear_on_table(table)
+# define btr_search_s_lock(index)
+# define btr_search_s_unlock(index)
+# define btr_search_x_lock(index)
+# define btr_search_x_unlock(index)
+# define btr_search_info_update(index, cursor)
+# define btr_search_move_or_delete_hash_entries(new_block, block, index)
+# define btr_search_update_hash_on_insert(cursor)
+# define btr_search_update_hash_on_delete(cursor)
+# define btr_search_sys_resize(hash_size)
+#endif /* BTR_CUR_HASH_ADAPT */
+
+#ifdef BTR_CUR_ADAPT
+/** Create and initialize search info.
+@param[in,out]	heap		heap where created
+@return own: search info struct */
+UNIV_INLINE
+btr_search_t*
+btr_search_info_create(mem_heap_t* heap)
+	MY_ATTRIBUTE((nonnull, warn_unused_result));
+
+/** @return the search info of an index */
+UNIV_INLINE
+btr_search_t*
+btr_search_get_info(dict_index_t* index)
+{
+	return(index->search_info);
+}
+#endif /* BTR_CUR_ADAPT */
 
 /** The search info struct in an index */
 struct btr_search_t{
-	ulint	ref_count;	/*!< Number of blocks in this index tree
-				that have search index built
-				i.e. block->index points to this index.
-				Protected by search latch except
-				when during initialization in
-				btr_search_info_create(). */
-
 	/* @{ The following fields are not protected by any latch.
 	Unfortunately, this means that they must be aligned to
 	the machine word, i.e., they cannot be turned into bit-fields. */
@@ -274,6 +284,7 @@ struct btr_search_t{
 				fetched, or NULL */
 	ulint	withdraw_clock;	/*!< the withdraw clock value of the buffer
 				pool when root_guess was stored */
+#ifdef BTR_CUR_HASH_ADAPT
 	ulint	hash_analysis;	/*!< when this exceeds
 				BTR_SEARCH_HASH_ANALYSIS, the hash
 				analysis starts; this is reset if no
@@ -289,6 +300,13 @@ struct btr_search_t{
 				using the hash index;
 				the range is 0 .. BTR_SEARCH_BUILD_LIMIT + 5 */
 	/* @} */
+	ulint	ref_count;	/*!< Number of blocks in this index tree
+				that have search index built
+				i.e. block->index points to this index.
+				Protected by search latch except
+				when during initialization in
+				btr_search_info_create(). */
+
 	/*---------------------- @{ */
 	ulint	n_fields;	/*!< recommended prefix length for hash search:
 				number of full fields */
@@ -308,6 +326,7 @@ struct btr_search_t{
 				far */
 	ulint	n_searches;	/*!< number of searches */
 #endif /* UNIV_SEARCH_PERF_STAT */
+#endif /* BTR_CUR_HASH_ADAPT */
 #ifdef UNIV_DEBUG
 	ulint	magic_n;	/*!< magic number @see BTR_SEARCH_MAGIC_N */
 /** value of btr_search_t::magic_n, used in assertions */
@@ -315,6 +334,7 @@ struct btr_search_t{
 #endif /* UNIV_DEBUG */
 };
 
+#ifdef BTR_CUR_HASH_ADAPT
 /** The hash index system */
 struct btr_search_sys_t{
 	hash_table_t**	hash_tables;	/*!< the adaptive hash tables,
@@ -352,6 +372,7 @@ the hash index */
 over calls from MySQL. If we notice someone waiting for the latch, we
 again set this much timeout. This is to reduce contention. */
 #define BTR_SEA_TIMEOUT			10000
+#endif /* BTR_CUR_HASH_ADAPT */
 
 #ifndef UNIV_NONINL
 #include "btr0sea.ic"
diff --git a/storage/innobase/include/btr0sea.ic b/storage/innobase/include/btr0sea.ic
index 5f7c39ba500..b5a7536a2b4 100644
--- a/storage/innobase/include/btr0sea.ic
+++ b/storage/innobase/include/btr0sea.ic
@@ -27,6 +27,24 @@ Created 2/17/1996 Heikki Tuuri
 #include "btr0cur.h"
 #include "buf0buf.h"
 
+/** Create and initialize search info.
+@param[in,out]	heap		heap where created
+@return own: search info struct */
+UNIV_INLINE
+btr_search_t*
+btr_search_info_create(mem_heap_t* heap)
+{
+	btr_search_t*	info = static_cast<btr_search_t*>(
+		mem_heap_zalloc(heap, sizeof(btr_search_t)));
+	ut_d(info->magic_n = BTR_SEARCH_MAGIC_N);
+#ifdef BTR_CUR_HASH_ADAPT
+	info->n_fields = 1;
+	info->left_side = TRUE;
+#endif /* BTR_CUR_HASH_ADAPT */
+	return(info);
+}
+
+#ifdef BTR_CUR_HASH_ADAPT
 /*********************************************************************//**
 Updates the search info. */
 void
@@ -35,18 +53,6 @@ btr_search_info_update_slow(
 	btr_search_t*	info,	/*!< in/out: search info */
 	btr_cur_t*	cursor);/*!< in: cursor which was just positioned */
 
-/********************************************************************//**
-Returns search info for an index.
-@return search info; search mutex reserved */
-UNIV_INLINE
-btr_search_t*
-btr_search_get_info(
-/*================*/
-	dict_index_t*	index)	/*!< in: index */
-{
-	return(index->search_info);
-}
-
 /*********************************************************************//**
 Updates the search info. */
 UNIV_INLINE
@@ -221,3 +227,4 @@ btr_get_search_table(const dict_index_t* index)
 
 	return(btr_search_sys->hash_tables[ifold % btr_ahi_parts]);
 }
+#endif /* BTR_CUR_HASH_ADAPT */
diff --git a/storage/innobase/include/btr0types.h b/storage/innobase/include/btr0types.h
index 19c21982011..77d1b286fbb 100644
--- a/storage/innobase/include/btr0types.h
+++ b/storage/innobase/include/btr0types.h
@@ -40,12 +40,14 @@ struct btr_cur_t;
 /** B-tree search information for the adaptive hash index */
 struct btr_search_t;
 
+#ifdef BTR_CUR_HASH_ADAPT
 /** Is search system enabled.
 Search system is protected by array of latches. */
 extern char	btr_search_enabled;
 
 /** Number of adaptive hash index partition. */
 extern ulong	btr_ahi_parts;
+#endif /* BTR_CUR_HASH_ADAPT */
 
 /** The size of a reference to data stored on a different page.
 The reference is stored at the end of the prefix of the field
diff --git a/storage/innobase/include/buf0buf.h b/storage/innobase/include/buf0buf.h
index 0df5cd04c03..b135ee174bf 100644
--- a/storage/innobase/include/buf0buf.h
+++ b/storage/innobase/include/buf0buf.h
@@ -406,11 +406,11 @@ DECLARE_THREAD(buf_resize_thread)(
 	void*	arg);				/*!< in: a dummy parameter
 						required by os_thread_create */
 
-/********************************************************************//**
-Clears the adaptive hash index on all pages in the buffer pool. */
+#ifdef BTR_CUR_HASH_ADAPT
+/** Clear the adaptive hash index on all pages in the buffer pool. */
 void
-buf_pool_clear_hash_index(void);
-/*===========================*/
+buf_pool_clear_hash_index();
+#endif /* BTR_CUR_HASH_ADAPT */
 
 /*********************************************************************//**
 Gets the current size of buffer buf_pool in bytes.
@@ -1233,12 +1233,14 @@ if applicable. */
 	((block)->page.zip.data ? &(block)->page.zip : NULL)
 #ifndef UNIV_HOTBACKUP
 
+#ifdef BTR_CUR_HASH_ADAPT
 /** Get a buffer block from an adaptive hash index pointer.
 This function does not return if the block is not identified.
 @param[in]	ptr	pointer to within a page frame
 @return pointer to block, never NULL */
 buf_block_t*
 buf_block_from_ahi(const byte* ptr);
+#endif /* BTR_CUR_HASH_ADAPT */
 
 /********************************************************************//**
 Find out if a pointer belongs to a buf_block_t. It can be a pointer to
@@ -1742,6 +1744,7 @@ struct buf_block_t{
 					bufferfixed, or (2) the thread has an
 					x-latch on the block */
 	/* @} */
+#ifdef BTR_CUR_HASH_ADAPT
 	/** @name Hash search fields (unprotected)
 	NOTE that these fields are NOT protected by any semaphore! */
 	/* @{ */
@@ -1792,8 +1795,8 @@ struct buf_block_t{
 	is explicitly commented. */
 
 	/* @{ */
-
-#if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG
+#endif /* BTR_CUR_HASH_ADAPT */
+#if defined BTR_CUR_HASH_ADAPT && (defined UNIV_AHI_DEBUG || defined UNIV_DEBUG)
 	ulint		n_pointers;	/*!< used in debugging: the number of
 					pointers in the adaptive hash index
 					pointing to this frame;
@@ -1808,11 +1811,12 @@ struct buf_block_t{
 # define assert_block_ahi_valid(block)					\
 	ut_a((block)->index						\
 	     || os_atomic_increment_ulint(&(block)->n_pointers, 0) == 0)
-#else /* UNIV_AHI_DEBUG || UNIV_DEBUG */
+#else /* BTR_CUR_HASH_ADAPT && (UNIV_AHI_DEBUG || UNIV_DEBUG) */
 # define assert_block_ahi_empty(block) /* nothing */
 # define assert_block_ahi_empty_on_init(block) /* nothing */
 # define assert_block_ahi_valid(block) /* nothing */
-#endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */
+#endif /* BTR_CUR_HASH_ADAPT && (UNIV_AHI_DEBUG || UNIV_DEBUG) */
+#ifdef BTR_CUR_HASH_ADAPT
 	unsigned	curr_n_fields:10;/*!< prefix length for hash indexing:
 					number of full fields */
 	unsigned	curr_n_bytes:15;/*!< number of bytes in hash
@@ -1828,6 +1832,8 @@ struct buf_block_t{
 					have been hash collisions,
 					record deletions, etc. */
 	/* @} */
+#endif /* BTR_CUR_HASH_ADAPT */
+
 	bool		made_dirty_with_no_latch;
 					/*!< true if block has been made dirty
 					without acquiring X/SX latch as the
diff --git a/storage/innobase/include/dict0mem.h b/storage/innobase/include/dict0mem.h
index 214c2c48667..6c9d52f1b7f 100644
--- a/storage/innobase/include/dict0mem.h
+++ b/storage/innobase/include/dict0mem.h
@@ -894,12 +894,14 @@ struct dict_index_t{
 				constraint */
 	unsigned	nulls_equal:1;
 				/*!< if true, SQL NULL == SQL NULL */
+#ifdef BTR_CUR_HASH_ADAPT
 	unsigned	disable_ahi:1;
 				/*!< in true, then disable AHI.
 				Currently limited to intrinsic
 				temporary table as index id is not
 				unqiue for such table which is one of the
 				validation criterion for ahi. */
+#endif /* BTR_CUR_HASH_ADAPT */
 	unsigned	n_uniq:10;/*!< number of fields from the beginning
 				which are enough to determine an index
 				entry uniquely */
@@ -939,8 +941,10 @@ struct dict_index_t{
 #ifndef UNIV_HOTBACKUP
 	UT_LIST_NODE_T(dict_index_t)
 			indexes;/*!< list of indexes of the table */
+#ifdef BTR_CUR_ADAPT
 	btr_search_t*	search_info;
 				/*!< info used in optimistic searches */
+#endif /* BTR_CUR_ADAPT */
 	row_log_t*	online_log;
 				/*!< the log of modifications
 				during online index creation;
diff --git a/storage/innobase/include/dict0mem.ic b/storage/innobase/include/dict0mem.ic
index 3269596feb7..d986b0924af 100644
--- a/storage/innobase/include/dict0mem.ic
+++ b/storage/innobase/include/dict0mem.ic
@@ -71,7 +71,9 @@ dict_mem_fill_index_struct(
 	of an empty mem block */
 	index->allow_duplicates = false;
 	index->nulls_equal = false;
+#ifdef BTR_CUR_HASH_ADAPT
 	index->disable_ahi = false;
+#endif /* BTR_CUR_HASH_ADAPT */
 
 	new (&index->rec_cache) rec_cache_t();
 
diff --git a/storage/innobase/include/fsp0fsp.h b/storage/innobase/include/fsp0fsp.h
index 301337f7615..1e82d7dbaf9 100644
--- a/storage/innobase/include/fsp0fsp.h
+++ b/storage/innobase/include/fsp0fsp.h
@@ -559,14 +559,22 @@ fsp_get_available_space_in_free_extents(
 /**********************************************************************//**
 Frees a single page of a segment. */
 void
-fseg_free_page(
-/*===========*/
+fseg_free_page_func(
 	fseg_header_t*	seg_header, /*!< in: segment header */
 	ulint		space_id, /*!< in: space id */
 	ulint		page,	/*!< in: page offset */
+#ifdef BTR_CUR_HASH_ADAPT
 	bool		ahi,	/*!< in: whether we may need to drop
 				the adaptive hash index */
+#endif /* BTR_CUR_HASH_ADAPT */
 	mtr_t*		mtr);	/*!< in/out: mini-transaction */
+#ifdef BTR_CUR_HASH_ADAPT
+# define fseg_free_page(header, space_id, page, ahi, mtr)	\
+	fseg_free_page_func(header, space_id, page, ahi, mtr)
+#else /* BTR_CUR_HASH_ADAPT */
+# define fseg_free_page(header, space_id, page, ahi, mtr)	\
+	fseg_free_page_func(header, space_id, page, mtr)
+#endif /* BTR_CUR_HASH_ADAPT */
 /**********************************************************************//**
 Checks if a single page of a segment is free.
 @return true if free */
@@ -584,29 +592,43 @@ Doing the freeing in a single mini-transaction might result in
 too big a mini-transaction.
 @return TRUE if freeing completed */
 ibool
-fseg_free_step(
-/*===========*/
+fseg_free_step_func(
 	fseg_header_t*	header,	/*!< in, own: segment header; NOTE: if the header
 				resides on the first page of the frag list
 				of the segment, this pointer becomes obsolete
 				after the last freeing step */
+#ifdef BTR_CUR_HASH_ADAPT
 	bool		ahi,	/*!< in: whether we may need to drop
 				the adaptive hash index */
+#endif /* BTR_CUR_HASH_ADAPT */
 	mtr_t*		mtr)	/*!< in/out: mini-transaction */
 	MY_ATTRIBUTE((warn_unused_result));
+#ifdef BTR_CUR_HASH_ADAPT
+# define fseg_free_step(header, ahi, mtr) fseg_free_step_func(header, ahi, mtr)
+#else /* BTR_CUR_HASH_ADAPT */
+# define fseg_free_step(header, ahi, mtr) fseg_free_step_func(header, mtr)
+#endif /* BTR_CUR_HASH_ADAPT */
 /**********************************************************************//**
 Frees part of a segment. Differs from fseg_free_step because this function
 leaves the header page unfreed.
 @return TRUE if freeing completed, except the header page */
 ibool
-fseg_free_step_not_header(
-/*======================*/
+fseg_free_step_not_header_func(
 	fseg_header_t*	header,	/*!< in: segment header which must reside on
 				the first fragment page of the segment */
+#ifdef BTR_CUR_HASH_ADAPT
 	bool		ahi,	/*!< in: whether we may need to drop
 				the adaptive hash index */
+#endif /* BTR_CUR_HASH_ADAPT */
 	mtr_t*		mtr)	/*!< in/out: mini-transaction */
 	MY_ATTRIBUTE((warn_unused_result));
+#ifdef BTR_CUR_HASH_ADAPT
+# define fseg_free_step_not_header(header, ahi, mtr)	\
+	fseg_free_step_not_header_func(header, ahi, mtr)
+#else /* BTR_CUR_HASH_ADAPT */
+# define fseg_free_step_not_header(header, ahi, mtr)	\
+	fseg_free_step_not_header_func(header, mtr)
+#endif /* BTR_CUR_HASH_ADAPT */
 
 /** Checks if a page address is an extent descriptor page address.
 @param[in]	page_id		page id
diff --git a/storage/innobase/include/ha0ha.h b/storage/innobase/include/ha0ha.h
index 15a99ddf683..940b4176849 100644
--- a/storage/innobase/include/ha0ha.h
+++ b/storage/innobase/include/ha0ha.h
@@ -33,6 +33,7 @@ Created 8/18/1994 Heikki Tuuri
 #include "buf0types.h"
 #include "rem0types.h"
 
+#ifdef BTR_CUR_HASH_ADAPT
 /*************************************************************//**
 Looks for an element in a hash table.
 @return pointer to the data of the first hash table node in chain
@@ -79,6 +80,7 @@ updates the pointer to data if found.
 # define ha_search_and_update_if_found(table,fold,data,new_block,new_data) \
 	ha_search_and_update_if_found_func(table,fold,data,new_data)
 #endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */
+#endif /* BTR_CUR_HASH_ADAPT */
 
 /*************************************************************//**
 Creates a hash table with at least n array cells.  The actual number
@@ -115,6 +117,7 @@ ha_clear(
 /*=====*/
 	hash_table_t*	table);	/*!< in, own: hash table */
 
+#ifdef BTR_CUR_HASH_ADAPT
 /*************************************************************//**
 Inserts an entry into a hash table. If an entry with the same fold number
 is found, its node is updated to point to the new data, and no new node
@@ -240,7 +243,10 @@ hash_assert_can_search(
 #define hash_assert_can_modify(t, f)
 #define hash_assert_can_search(t, f)
 #endif /* UNIV_DEBUG */
-
+#else /* BTR_CUR_HASH_ADAPT */
+#define hash_assert_can_modify(t, f)
+#define hash_assert_can_search(t, f)
+#endif /* BTR_CUR_HASH_ADAPT */
 
 #ifndef UNIV_NONINL
 #include "ha0ha.ic"
diff --git a/storage/innobase/include/ha0ha.ic b/storage/innobase/include/ha0ha.ic
index 854ff9bc046..1513df209ad 100644
--- a/storage/innobase/include/ha0ha.ic
+++ b/storage/innobase/include/ha0ha.ic
@@ -23,18 +23,11 @@ The hash table with external chains
 Created 8/18/1994 Heikki Tuuri
 *************************************************************************/
 
+#ifdef BTR_CUR_HASH_ADAPT
 #include "ut0rnd.h"
 #include "mem0mem.h"
 #include "btr0types.h"
 
-/***********************************************************//**
-Deletes a hash node. */
-void
-ha_delete_hash_node(
-/*================*/
-	hash_table_t*	table,		/*!< in: hash table */
-	ha_node_t*	del_node);	/*!< in: node to be deleted */
-
 /******************************************************************//**
 Gets a hash node data.
 @return pointer to the data */
@@ -213,6 +206,14 @@ ha_search_with_data(
 	return(NULL);
 }
 
+/***********************************************************//**
+Deletes a hash node. */
+void
+ha_delete_hash_node(
+/*================*/
+	hash_table_t*	table,		/*!< in: hash table */
+	ha_node_t*	del_node);	/*!< in: node to be deleted */
+
 /*********************************************************//**
 Looks for an element when we know the pointer to the data, and deletes
 it from the hash table, if found.
@@ -240,3 +241,4 @@ ha_search_and_delete_if_found(
 
 	return(FALSE);
 }
+#endif /* BTR_CUR_HASH_ADAPT */
diff --git a/storage/innobase/include/hash0hash.h b/storage/innobase/include/hash0hash.h
index e088fed47cf..b3addb7c578 100644
--- a/storage/innobase/include/hash0hash.h
+++ b/storage/innobase/include/hash0hash.h
@@ -533,13 +533,13 @@ struct hash_cell_t{
 /* The hash table structure */
 struct hash_table_t {
 	enum hash_table_sync_t	type;	/*<! type of hash_table. */
-#if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG
+#if defined BTR_CUR_HASH_ADAPT && (defined UNIV_AHI_DEBUG || defined UNIV_DEBUG)
 # ifndef UNIV_HOTBACKUP
 	ibool			adaptive;/* TRUE if this is the hash
 					table of the adaptive hash
 					index */
 # endif /* !UNIV_HOTBACKUP */
-#endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */
+#endif /* BTR_CUR_HASH_ADAPT && (UNIV_AHI_DEBUG || UNIV_DEBUG) */
 	ulint			n_cells;/* number of cells in the hash table */
 	hash_cell_t*		array;	/*!< pointer to cell array */
 #ifndef UNIV_HOTBACKUP
diff --git a/storage/innobase/include/page0cur.h b/storage/innobase/include/page0cur.h
index c111717d868..fc1a3d01df5 100644
--- a/storage/innobase/include/page0cur.h
+++ b/storage/innobase/include/page0cur.h
@@ -36,8 +36,6 @@ Created 10/4/1994 Heikki Tuuri
 #include "gis0type.h"
 
 
-#define PAGE_CUR_ADAPT
-
 #ifdef UNIV_DEBUG
 /*********************************************************//**
 Gets pointer to the page frame where the cursor is positioned.
@@ -315,6 +313,7 @@ page_cur_search_with_match(
 					fields in lower limit record */
 	page_cur_t*		cursor,	/*!< out: page cursor */
 	rtr_info_t*		rtr_info);/*!< in/out: rtree search stack */
+#ifdef BTR_CUR_HASH_ADAPT
 /** Search the right position for a page cursor.
 @param[in]	block			buffer block
 @param[in]	index			index tree
@@ -340,6 +339,7 @@ page_cur_search_with_match_bytes(
 	ulint*			ilow_matched_fields,
 	ulint*			ilow_matched_bytes,
 	page_cur_t*		cursor);
+#endif /* BTR_CUR_HASH_ADAPT */
 /***********************************************************//**
 Positions a page cursor on a randomly chosen user record on a page. If there
 are no user records, sets the cursor on the infimum record. */
diff --git a/storage/innobase/include/srv0mon.h b/storage/innobase/include/srv0mon.h
index 1bd67fd9a17..18b9dec831d 100644
--- a/storage/innobase/include/srv0mon.h
+++ b/storage/innobase/include/srv0mon.h
@@ -342,16 +342,20 @@ enum monitor_id_t {
 	MONITOR_INDEX_REORG_SUCCESSFUL,
 	MONITOR_INDEX_DISCARD,
 
+#ifdef BTR_CUR_HASH_ADAPT
 	/* Adaptive Hash Index related counters */
 	MONITOR_MODULE_ADAPTIVE_HASH,
 	MONITOR_OVLD_ADAPTIVE_HASH_SEARCH,
+#endif /* BTR_CUR_HASH_ADAPT */
 	MONITOR_OVLD_ADAPTIVE_HASH_SEARCH_BTREE,
+#ifdef BTR_CUR_HASH_ADAPT
 	MONITOR_ADAPTIVE_HASH_PAGE_ADDED,
 	MONITOR_ADAPTIVE_HASH_PAGE_REMOVED,
 	MONITOR_ADAPTIVE_HASH_ROW_ADDED,
 	MONITOR_ADAPTIVE_HASH_ROW_REMOVED,
 	MONITOR_ADAPTIVE_HASH_ROW_REMOVE_NOT_FOUND,
 	MONITOR_ADAPTIVE_HASH_ROW_UPDATED,
+#endif /* BTR_CUR_HASH_ADAPT */
 
 	/* Tablespace related counters */
 	MONITOR_MODULE_FIL_SYSTEM,
diff --git a/storage/innobase/include/sync0types.h b/storage/innobase/include/sync0types.h
index 2c11fc53e85..0918ff99412 100644
--- a/storage/innobase/include/sync0types.h
+++ b/storage/innobase/include/sync0types.h
@@ -1067,6 +1067,7 @@ struct sync_check_functor_t {
 	virtual bool result() const = 0;
 };
 
+#ifdef BTR_CUR_HASH_ADAPT
 /** Functor to check whether the calling thread owns the btr search mutex. */
 struct btrsea_sync_check : public sync_check_functor_t {
 
@@ -1128,6 +1129,7 @@ private:
 	/** If the caller owns the search latch */
 	const bool	m_has_search_latch;
 };
+#endif /* BTR_CUR_HASH_ADAPT */
 
 /** Functor to check for dictionay latching constraints. */
 struct dict_sync_check : public sync_check_functor_t {
diff --git a/storage/innobase/include/trx0i_s.h b/storage/innobase/include/trx0i_s.h
index f588d820743..17a297527af 100644
--- a/storage/innobase/include/trx0i_s.h
+++ b/storage/innobase/include/trx0i_s.h
@@ -162,8 +162,10 @@ struct i_s_trx_row_t {
 					/*!< check_foreigns in trx_t */
 	const char*	trx_foreign_key_error;
 					/*!< detailed_error in trx_t */
+#ifdef BTR_CUR_HASH_ADAPT
 	ibool		trx_has_search_latch;
 					/*!< has_search_latch in trx_t */
+#endif /* BTR_CUR_HASH_ADAPT */
 	ulint		trx_is_read_only;
 					/*!< trx_t::read_only */
 	ulint		trx_is_autocommit_non_locking;
diff --git a/storage/innobase/include/trx0trx.h b/storage/innobase/include/trx0trx.h
index 1a5f5b16855..0bdf8364de5 100644
--- a/storage/innobase/include/trx0trx.h
+++ b/storage/innobase/include/trx0trx.h
@@ -58,12 +58,14 @@ class FlushObserver;
 /** Dummy session used currently in MySQL interface */
 extern sess_t*	trx_dummy_sess;
 
-/**
-Releases the search latch if trx has reserved it.
-@param[in,out] trx		Transaction that may own the AHI latch */
-UNIV_INLINE
-void
-trx_search_latch_release_if_reserved(trx_t* trx);
+#ifdef BTR_CUR_HASH_ADAPT
+/** Assert that the transaction is not holding the adaptive hash index latch.
+@param[in] trx		transaction */
+# define trx_assert_no_search_latch(trx) \
+	ut_ad(!trx->has_search_latch)
+#else /* BTR_CUR_HASH_ADAPT */
+# define trx_assert_no_search_latch(trx)
+#endif
 
 /** Set flush observer for the transaction
 @param[in/out]	trx		transaction struct
@@ -1065,9 +1067,11 @@ struct trx_t {
 					flush the log in
 					trx_commit_complete_for_mysql() */
 	ulint		duplicates;	/*!< TRX_DUP_IGNORE | TRX_DUP_REPLACE */
+#ifdef BTR_CUR_HASH_ADAPT
 	bool		has_search_latch;
 					/*!< TRUE if this trx has latched the
 					search system latch in S-mode */
+#endif /* BTR_CUR_HASH_ADAPT */
 	trx_dict_op_t	dict_operation;	/**< @see enum trx_dict_op_t */
 
 	/* Fields protected by the srv_conc_mutex. */
@@ -1470,7 +1474,7 @@ private:
 
 		/* Only the owning thread should release the latch. */
 
-		trx_search_latch_release_if_reserved(trx);
+		trx_assert_no_search_latch(trx);
 
 		trx_mutex_enter(trx);
 
@@ -1505,7 +1509,7 @@ private:
 
 		/* Only the owning thread should release the latch. */
 
-		trx_search_latch_release_if_reserved(trx);
+		trx_assert_no_search_latch(trx);
 
 		trx_mutex_enter(trx);
 
diff --git a/storage/innobase/include/trx0trx.ic b/storage/innobase/include/trx0trx.ic
index 7120a7aaced..d1b651ed992 100644
--- a/storage/innobase/include/trx0trx.ic
+++ b/storage/innobase/include/trx0trx.ic
@@ -203,16 +203,6 @@ ok:
 	trx->dict_operation = op;
 }
 
-/**
-Releases the search latch if trx has reserved it.
-@param[in,out] trx		Transaction that may own the AHI latch */
-UNIV_INLINE
-void
-trx_search_latch_release_if_reserved(trx_t* trx)
-{
-	ut_a(!trx->has_search_latch);
-}
-
 /********************************************************************//**
 Check if redo rseg is modified for insert/update. */
 UNIV_INLINE
diff --git a/storage/innobase/innodb.cmake b/storage/innobase/innodb.cmake
index a90fe67f492..22af4bd4229 100644
--- a/storage/innobase/innodb.cmake
+++ b/storage/innobase/innodb.cmake
@@ -77,6 +77,17 @@ ENDIF()
 # Enable InnoDB's UNIV_DEBUG in debug builds
 SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DUNIV_DEBUG")
 
+OPTION(WITH_INNODB_AHI "Include innodb_adaptive_hash_index" ON)
+OPTION(WITH_INNODB_ROOT_GUESS "Cache index root block descriptors" ON)
+IF(WITH_INNODB_AHI)
+  ADD_DEFINITIONS(-DBTR_CUR_HASH_ADAPT -DBTR_CUR_ADAPT)
+  IF(NOT WITH_INNODB_ROOT_GUESS)
+    MESSAGE(WARNING "WITH_INNODB_AHI implies WITH_INNODB_ROOT_GUESS")
+  ENDIF()
+ELSEIF(WITH_INNODB_ROOT_GUESS)
+  ADD_DEFINITIONS(-DBTR_CUR_ADAPT)
+ENDIF()
+
 OPTION(WITH_INNODB_EXTRA_DEBUG "Enable extra InnoDB debug checks" OFF)
 IF(WITH_INNODB_EXTRA_DEBUG)
   IF(NOT WITH_DEBUG)
@@ -84,7 +95,9 @@ IF(WITH_INNODB_EXTRA_DEBUG)
   ENDIF()
 
   SET(EXTRA_DEBUG_FLAGS "")
-  SET(EXTRA_DEBUG_FLAGS "${EXTRA_DEBUG_FLAGS} -DUNIV_AHI_DEBUG")
+  IF(WITH_INNODB_AHI)
+    SET(EXTRA_DEBUG_FLAGS "${EXTRA_DEBUG_FLAGS} -DUNIV_AHI_DEBUG")
+  ENDIF()
   SET(EXTRA_DEBUG_FLAGS "${EXTRA_DEBUG_FLAGS} -DUNIV_DDL_DEBUG")
   SET(EXTRA_DEBUG_FLAGS "${EXTRA_DEBUG_FLAGS} -DUNIV_DEBUG_FILE_ACCESSES")
   SET(EXTRA_DEBUG_FLAGS "${EXTRA_DEBUG_FLAGS} -DUNIV_ZIP_DEBUG")
@@ -242,7 +255,6 @@ ENDIF()
 
 ENDIF(NOT MSVC)
 
-CHECK_FUNCTION_EXISTS(asprintf  HAVE_ASPRINTF)
 CHECK_FUNCTION_EXISTS(vasprintf  HAVE_VASPRINTF)
 
 # Solaris atomics
diff --git a/storage/innobase/page/page0cur.cc b/storage/innobase/page/page0cur.cc
index d3f39b649a9..981f8e9bba8 100644
--- a/storage/innobase/page/page0cur.cc
+++ b/storage/innobase/page/page0cur.cc
@@ -41,11 +41,6 @@ Created 10/4/1994 Heikki Tuuri
 
 #include <algorithm>
 
-#ifdef PAGE_CUR_ADAPT
-# ifdef UNIV_SEARCH_PERF_STAT
-static ulint	page_cur_short_succ	= 0;
-# endif /* UNIV_SEARCH_PERF_STAT */
-
 /*******************************************************************//**
 This is a linear congruential generator PRNG. Returns a pseudo random
 number between 0 and 2^64-1 inclusive. The formula and the constants
@@ -80,6 +75,11 @@ page_cur_lcg_prng(void)
 	return(lcg_current);
 }
 
+#ifdef BTR_CUR_HASH_ADAPT
+# ifdef UNIV_SEARCH_PERF_STAT
+static ulint	page_cur_short_succ;
+# endif /* UNIV_SEARCH_PERF_STAT */
+
 /** Try a search shortcut based on the last insert.
 @param[in]	block			index page
 @param[in]	index			index tree
@@ -247,7 +247,7 @@ exit_func:
 	}
 	return(success);
 }
-#endif
+#endif /* BTR_CUR_HASH_ADAPT */
 
 #ifdef PAGE_CUR_LE_OR_EXTENDS
 /****************************************************************//**
@@ -450,7 +450,7 @@ page_cur_search_with_match(
 
 	ut_d(page_check_dir(page));
 
-#ifdef PAGE_CUR_ADAPT
+#ifdef BTR_CUR_HASH_ADAPT
 	if (page_is_leaf(page)
 	    && (mode == PAGE_CUR_LE)
 	    && !dict_index_is_spatial(index)
@@ -471,7 +471,7 @@ page_cur_search_with_match(
 		mode = PAGE_CUR_LE;
 	}
 # endif
-#endif
+#endif /* BTR_CUR_HASH_ADAPT */
 
 	/* If the mode is for R-tree indexes, use the special MBR
 	related compare functions */
@@ -659,6 +659,7 @@ up_rec_match:
 	}
 }
 
+#ifdef BTR_CUR_HASH_ADAPT
 /** Search the right position for a page cursor.
 @param[in]	block			buffer block
 @param[in]	index			index tree
@@ -726,7 +727,7 @@ page_cur_search_with_match_bytes(
 
 	ut_d(page_check_dir(page));
 
-#ifdef PAGE_CUR_ADAPT
+#ifdef BTR_CUR_HASH_ADAPT
 	if (page_is_leaf(page)
 	    && (mode == PAGE_CUR_LE)
 	    && (page_header_get_field(page, PAGE_N_DIRECTION) > 3)
@@ -746,7 +747,7 @@ page_cur_search_with_match_bytes(
 		mode = PAGE_CUR_LE;
 	}
 # endif
-#endif
+#endif /* BTR_CUR_HASH_ADAPT */
 
 	/* The following flag does not work for non-latin1 char sets because
 	cmp_full_field does not tell how many bytes matched */
@@ -912,6 +913,7 @@ up_rec_match:
 		mem_heap_free(heap);
 	}
 }
+#endif /* BTR_CUR_HASH_ADAPT */
 
 /***********************************************************//**
 Positions a page cursor on a randomly chosen user record on a page. If there
diff --git a/storage/innobase/row/row0sel.cc b/storage/innobase/row/row0sel.cc
index 96e436cf753..39249558b00 100644
--- a/storage/innobase/row/row0sel.cc
+++ b/storage/innobase/row/row0sel.cc
@@ -1455,6 +1455,7 @@ plan_reset_cursor(
 	plan->n_rows_prefetched = 0;
 }
 
+#ifdef BTR_CUR_HASH_ADAPT
 /*********************************************************************//**
 Tries to do a shortcut to fetch a clustered index record with a unique key,
 using the hash index if possible (not always).
@@ -1484,11 +1485,8 @@ row_sel_try_search_shortcut(
 	ut_ad(node->read_view);
 	ut_ad(plan->unique_search);
 	ut_ad(!plan->must_get_clust);
-#ifdef UNIV_DEBUG
-	if (search_latch_locked) {
-		ut_ad(rw_lock_own(btr_get_search_latch(index), RW_LOCK_S));
-	}
-#endif /* UNIV_DEBUG */
+	ut_ad(!search_latch_locked
+	      || rw_lock_own(btr_get_search_latch(index), RW_LOCK_S));
 
 	row_sel_open_pcur(plan, search_latch_locked, mtr);
 
@@ -1563,6 +1561,7 @@ func_exit:
 	}
 	return(ret);
 }
+#endif /* BTR_CUR_HASH_ADAPT */
 
 /*********************************************************************//**
 Performs a select step.
@@ -1581,7 +1580,6 @@ row_sel(
 	rec_t*		rec;
 	rec_t*		old_vers;
 	rec_t*		clust_rec;
-	ibool		search_latch_locked;
 	ibool		consistent_read;
 
 	/* The following flag becomes TRUE when we are doing a
@@ -1600,7 +1598,6 @@ row_sel(
 	contains a clustered index latch, and
 	&mtr must be committed before we move
 	to the next non-clustered record */
-	ulint		found_flag;
 	dberr_t		err;
 	mem_heap_t*	heap				= NULL;
 	ulint		offsets_[REC_OFFS_NORMAL_SIZE];
@@ -1609,7 +1606,11 @@ row_sel(
 
 	ut_ad(thr->run_node == node);
 
-	search_latch_locked = FALSE;
+#ifdef BTR_CUR_HASH_ADAPT
+	ibool		search_latch_locked = FALSE;
+#else /* BTR_CUR_HASH_ADAPT */
+# define search_latch_locked false
+#endif /* BTR_CUR_HASH_ADAPT */
 
 	if (node->read_view) {
 		/* In consistent reads, we try to do with the hash index and
@@ -1656,11 +1657,12 @@ table_loop:
 
 	mtr_start(&mtr);
 
+#ifdef BTR_CUR_HASH_ADAPT
 	if (consistent_read && plan->unique_search && !plan->pcur_is_open
 	    && !plan->must_get_clust
 	    && !plan->table->big_rows) {
 		if (!search_latch_locked) {
-			rw_lock_s_lock(btr_get_search_latch(index));
+			btr_search_s_lock(index);
 
 			search_latch_locked = TRUE;
 		} else if (rw_lock_get_writer(btr_get_search_latch(index))
@@ -1673,25 +1675,23 @@ table_loop:
 			from acquiring an s-latch for a long time, lowering
 			performance significantly in multiprocessors. */
 
-			rw_lock_s_unlock(btr_get_search_latch(index));
-			rw_lock_s_lock(btr_get_search_latch(index));
+			btr_search_s_unlock(index);
+			btr_search_s_lock(index);
 		}
 
-		found_flag = row_sel_try_search_shortcut(node, plan,
-							 search_latch_locked,
-							 &mtr);
-
-		if (found_flag == SEL_FOUND) {
-
+		switch (row_sel_try_search_shortcut(node, plan,
+						    search_latch_locked,
+						    &mtr)) {
+		case SEL_FOUND:
 			goto next_table;
-
-		} else if (found_flag == SEL_EXHAUSTED) {
-
+		case SEL_EXHAUSTED:
 			goto table_exhausted;
+		default:
+			ut_ad(0);
+		case SEL_RETRY:
+			break;
 		}
 
-		ut_ad(found_flag == SEL_RETRY);
-
 		plan_reset_cursor(plan);
 
 		mtr_commit(&mtr);
@@ -1699,10 +1699,11 @@ table_loop:
 	}
 
 	if (search_latch_locked) {
-		rw_lock_s_unlock(btr_get_search_latch(index));
+		btr_search_s_unlock(index);
 
 		search_latch_locked = FALSE;
 	}
+#endif /* BTR_CUR_HASH_ADAPT */
 
 	if (!plan->pcur_is_open) {
 		/* Evaluate the expressions to build the search tuple and
@@ -2239,13 +2240,15 @@ stop_for_a_while:
 
 	mtr_commit(&mtr);
 
-#ifdef UNIV_DEBUG
+#ifdef BTR_CUR_HASH_ADAPT
+# ifdef UNIV_DEBUG
 	{
 		btrsea_sync_check	check(true);
 
 		ut_ad(!sync_check_iterate(check));
 	}
-#endif /* UNIV_DEBUG */
+# endif /* UNIV_DEBUG */
+#endif /* BTR_CUR_HASH_ADAPT */
 
 	err = DB_SUCCESS;
 	goto func_exit;
@@ -2294,9 +2297,11 @@ lock_wait_or_error:
 #endif /* UNIV_DEBUG */
 
 func_exit:
+#ifdef BTR_CUR_HASH_ADAPT
 	if (search_latch_locked) {
-		rw_lock_s_unlock(btr_get_search_latch(index));
+		btr_search_s_unlock(index);
 	}
+#endif /* BTR_CUR_HASH_ADAPT */
 
 	if (heap != NULL) {
 		mem_heap_free(heap);
@@ -3080,7 +3085,7 @@ row_sel_store_mysql_field_func(
 		mem_heap_t*	heap;
 		/* Copy an externally stored field to a temporary heap */
 
-		ut_a(!prebuilt->trx->has_search_latch);
+		trx_assert_no_search_latch(prebuilt->trx);
 		ut_ad(field_no == templ->clust_rec_field_no);
 		ut_ad(templ->type != DATA_POINT);
 
@@ -3927,6 +3932,7 @@ row_sel_enqueue_cache_row_for_mysql(
 	++prebuilt->n_fetch_cached;
 }
 
+#ifdef BTR_CUR_HASH_ADAPT
 /*********************************************************************//**
 Tries to do a shortcut to fetch a clustered index record with a unique key,
 using the hash index if possible (not always). We assume that the search
@@ -3995,6 +4001,7 @@ row_sel_try_search_shortcut_for_mysql(
 
 	return(SEL_FOUND);
 }
+#endif /* BTR_CUR_HASH_ADAPT */
 
 /*********************************************************************//**
 Check a pushed-down index condition.
@@ -4523,12 +4530,14 @@ row_search_mvcc(
 		DBUG_RETURN(DB_END_OF_INDEX);
 	}
 
-#ifdef UNIV_DEBUG
+#ifdef BTR_CUR_HASH_ADAPT
+# ifdef UNIV_DEBUG
 	{
 		btrsea_sync_check	check(trx->has_search_latch);
 		ut_ad(!sync_check_iterate(check));
 	}
-#endif /* UNIV_DEBUG */
+# endif /* UNIV_DEBUG */
+#endif /* BTR_CUR_HASH_ADAPT */
 
 	if (dict_table_is_discarded(prebuilt->table)) {
 
@@ -4554,24 +4563,7 @@ row_search_mvcc(
 		&& (prebuilt->read_just_key
 		    || prebuilt->m_read_virtual_key);
 
-	/*-------------------------------------------------------------*/
-	/* PHASE 0: Release a possible s-latch we are holding on the
-	adaptive hash index latch if there is someone waiting behind */
-
-	if (trx->has_search_latch
-#ifndef INNODB_RW_LOCKS_USE_ATOMICS
-	    && rw_lock_get_writer(
-		btr_get_search_latch(index)) != RW_LOCK_NOT_LOCKED
-#endif /* !INNODB_RW_LOCKS_USE_ATOMICS */
-	    ) {
-
-		/* There is an x-latch request on the adaptive hash index:
-		release the s-latch to reduce starvation and wait for
-		BTR_SEA_TIMEOUT rounds before trying to keep it again over
-		calls from MySQL */
-
-		trx_search_latch_release_if_reserved(trx);
-	}
+	trx_assert_no_search_latch(trx);
 
 	/* Reset the new record lock info if srv_locks_unsafe_for_binlog
 	is set or session is using a READ COMMITED isolation level. Then
@@ -4690,6 +4682,7 @@ row_search_mvcc(
 
 	mtr_start(&mtr);
 
+#ifdef BTR_CUR_HASH_ADAPT
 	/*-------------------------------------------------------------*/
 	/* PHASE 2: Try fast adaptive hash index search if possible */
 
@@ -4728,7 +4721,7 @@ row_search_mvcc(
 			and if we try that, we can deadlock on the adaptive
 			hash index semaphore! */
 
-			ut_a(!trx->has_search_latch);
+			trx_assert_no_search_latch(trx);
 			rw_lock_s_lock(btr_get_search_latch(index));
 			trx->has_search_latch = true;
 
@@ -4814,11 +4807,12 @@ row_search_mvcc(
                         trx->has_search_latch = false;
 		}
 	}
+#endif /* BTR_CUR_HASH_ADAPT */
 
 	/*-------------------------------------------------------------*/
 	/* PHASE 3: Open or restore index cursor position */
 
-	trx_search_latch_release_if_reserved(trx);
+	trx_assert_no_search_latch(trx);
 
 	spatial_search = dict_index_is_spatial(index)
 			 && mode >= PAGE_CUR_CONTAIN;
@@ -6041,13 +6035,15 @@ func_exit:
 		}
 	}
 
-#ifdef UNIV_DEBUG
+#ifdef BTR_CUR_HASH_ADAPT
+# ifdef UNIV_DEBUG
 	{
 		btrsea_sync_check	check(trx->has_search_latch);
 
 		ut_ad(!sync_check_iterate(check));
 	}
-#endif /* UNIV_DEBUG */
+# endif /* UNIV_DEBUG */
+#endif /* BTR_CUR_HASH_ADAPT */
 
 	DEBUG_SYNC_C("innodb_row_search_for_mysql_exit");
 
diff --git a/storage/innobase/srv/srv0conc.cc b/storage/innobase/srv/srv0conc.cc
index ae06869c1ec..05b64548686 100644
--- a/storage/innobase/srv/srv0conc.cc
+++ b/storage/innobase/srv/srv0conc.cc
@@ -187,9 +187,7 @@ srv_conc_enter_innodb_with_atomics(
 			/* Release possible search system latch this
 			thread has */
 
-			if (trx->has_search_latch) {
-				trx_search_latch_release_if_reserved(trx);
-			}
+			trx_assert_no_search_latch(trx);
 
 			thd_wait_begin(trx->mysql_thd, THD_WAIT_USER_LOCK);
 
@@ -246,13 +244,15 @@ srv_conc_enter_innodb(
 {
 	trx_t*	trx	= prebuilt->trx;
 
-#ifdef UNIV_DEBUG
+#ifdef BTR_CUR_HASH_ADAPT
+# ifdef UNIV_DEBUG
 	{
 		btrsea_sync_check	check(trx->has_search_latch);
 
 		ut_ad(!sync_check_iterate(check));
 	}
-#endif /* UNIV_DEBUG */
+# endif /* UNIV_DEBUG */
+#endif /* BTR_CUR_HASH_ADAPT */
 
 	srv_conc_enter_innodb_with_atomics(trx);
 }
@@ -266,13 +266,15 @@ srv_conc_force_enter_innodb(
 	trx_t*	trx)	/*!< in: transaction object associated with the
 			thread */
 {
-#ifdef UNIV_DEBUG
+#ifdef BTR_CUR_HASH_ADAPT
+# ifdef UNIV_DEBUG
 	{
 		btrsea_sync_check	check(trx->has_search_latch);
 
 		ut_ad(!sync_check_iterate(check));
 	}
-#endif /* UNIV_DEBUG */
+# endif /* UNIV_DEBUG */
+#endif /* BTR_CUR_HASH_ADAPT */
 
 	if (!srv_thread_concurrency) {
 
@@ -305,13 +307,15 @@ srv_conc_force_exit_innodb(
 
 	srv_conc_exit_innodb_with_atomics(trx);
 
-#ifdef UNIV_DEBUG
+#ifdef BTR_CUR_HASH_ADAPT
+# ifdef UNIV_DEBUG
 	{
 		btrsea_sync_check	check(trx->has_search_latch);
 
 		ut_ad(!sync_check_iterate(check));
 	}
-#endif /* UNIV_DEBUG */
+# endif /* UNIV_DEBUG */
+#endif /* BTR_CUR_HASH_ADAPT */
 }
 
 /*********************************************************************//**
diff --git a/storage/innobase/srv/srv0mon.cc b/storage/innobase/srv/srv0mon.cc
index f23790abe89..4f64b3a6a43 100644
--- a/storage/innobase/srv/srv0mon.cc
+++ b/storage/innobase/srv/srv0mon.cc
@@ -988,8 +988,9 @@ static monitor_info_t	innodb_counter_info[] =
 	 MONITOR_NONE,
 	 MONITOR_DEFAULT_START, MONITOR_INDEX_DISCARD},
 
+#ifdef BTR_CUR_HASH_ADAPT
 	/* ========== Counters for Adaptive Hash Index ========== */
-	{"module_adaptive_hash", "adaptive_hash_index", "Adpative Hash Index",
+	{"module_adaptive_hash", "adaptive_hash_index", "Adaptive Hash Index",
 	 MONITOR_MODULE,
 	 MONITOR_DEFAULT_START, MONITOR_MODULE_ADAPTIVE_HASH},
 
@@ -998,6 +999,7 @@ static monitor_info_t	innodb_counter_info[] =
 	 static_cast<monitor_type_t>(
 	 MONITOR_EXISTING | MONITOR_DEFAULT_ON),
 	 MONITOR_DEFAULT_START, MONITOR_OVLD_ADAPTIVE_HASH_SEARCH},
+#endif /* BTR_CUR_HASH_ADAPT */
 
 	{"adaptive_hash_searches_btree", "adaptive_hash_index",
 	 "Number of searches using B-tree on an index search",
@@ -1005,6 +1007,7 @@ static monitor_info_t	innodb_counter_info[] =
 	 MONITOR_EXISTING | MONITOR_DEFAULT_ON),
 	 MONITOR_DEFAULT_START, MONITOR_OVLD_ADAPTIVE_HASH_SEARCH_BTREE},
 
+#ifdef BTR_CUR_HASH_ADAPT
 	{"adaptive_hash_pages_added", "adaptive_hash_index",
 	 "Number of index pages on which the Adaptive Hash Index is built",
 	 MONITOR_NONE,
@@ -1036,6 +1039,7 @@ static monitor_info_t	innodb_counter_info[] =
 	 "Number of Adaptive Hash Index rows updated",
 	 MONITOR_NONE,
 	 MONITOR_DEFAULT_START, MONITOR_ADAPTIVE_HASH_ROW_UPDATED},
+#endif /* BTR_CUR_HASH_ADAPT */
 
 	/* ========== Counters for tablespace ========== */
 	{"module_file", "file_system", "Tablespace and File System Manager",
@@ -1888,9 +1892,11 @@ srv_mon_process_existing_counter(
 		value = log_sys->max_modified_age_sync;
 		break;
 
+#ifdef BTR_CUR_HASH_ADAPT
 	case MONITOR_OVLD_ADAPTIVE_HASH_SEARCH:
 		value = btr_cur_n_sea;
 		break;
+#endif /* BTR_CUR_HASH_ADAPT */
 
 	case MONITOR_OVLD_ADAPTIVE_HASH_SEARCH_BTREE:
 		value = btr_cur_n_non_sea;
diff --git a/storage/innobase/srv/srv0srv.cc b/storage/innobase/srv/srv0srv.cc
index 5eb17535b08..14a215b0259 100644
--- a/storage/innobase/srv/srv0srv.cc
+++ b/storage/innobase/srv/srv0srv.cc
@@ -1129,7 +1129,9 @@ srv_refresh_innodb_monitor_stats(void)
 
 	os_aio_refresh_stats();
 
+#ifdef BTR_CUR_HASH_ADAPT
 	btr_cur_n_sea_old = btr_cur_n_sea;
+#endif /* BTR_CUR_HASH_ADAPT */
 	btr_cur_n_non_sea_old = btr_cur_n_non_sea;
 
 	log_refresh_stats();
@@ -1255,6 +1257,7 @@ srv_printf_innodb_monitor(
 	      "-------------------------------------\n", file);
 	ibuf_print(file);
 
+#ifdef BTR_CUR_HASH_ADAPT
 	for (ulint i = 0; i < btr_ahi_parts; ++i) {
 		rw_lock_s_lock(btr_search_latches[i]);
 		ha_print_info(file, btr_search_sys->hash_tables[i]);
@@ -1268,6 +1271,12 @@ srv_printf_innodb_monitor(
 		(btr_cur_n_non_sea - btr_cur_n_non_sea_old)
 		/ time_elapsed);
 	btr_cur_n_sea_old = btr_cur_n_sea;
+#else /* BTR_CUR_HASH_ADAPT */
+	fprintf(file,
+		"%.2f non-hash searches/s\n",
+		(btr_cur_n_non_sea - btr_cur_n_non_sea_old)
+		/ time_elapsed);
+#endif /* BTR_CUR_HASH_ADAPT */
 	btr_cur_n_non_sea_old = btr_cur_n_non_sea;
 
 	fputs("---\n"
diff --git a/storage/innobase/srv/srv0start.cc b/storage/innobase/srv/srv0start.cc
index d673a7a8b75..dc9df629cf7 100644
--- a/storage/innobase/srv/srv0start.cc
+++ b/storage/innobase/srv/srv0start.cc
@@ -2716,9 +2716,11 @@ innobase_shutdown_for_mysql(void)
 		dict_stats_thread_deinit();
 	}
 
+#ifdef BTR_CUR_HASH_ADAPT
 	/* This must be disabled before closing the buffer pool
 	and closing the data dictionary.  */
 	btr_search_disable(true);
+#endif /* BTR_CUR_HASH_ADAPT */
 
 	ibuf_close();
 	log_shutdown();
@@ -2737,7 +2739,9 @@ innobase_shutdown_for_mysql(void)
 	}
 
 	dict_close();
+#ifdef BTR_CUR_HASH_ADAPT
 	btr_search_sys_free();
+#endif /* BTR_CUR_HASH_ADAPT */
 
 	/* 3. Free all InnoDB's own mutexes and the os_fast_mutexes inside
 	them */
diff --git a/storage/innobase/trx/trx0i_s.cc b/storage/innobase/trx/trx0i_s.cc
index 05bf6ff7b6a..e8da3a10722 100644
--- a/storage/innobase/trx/trx0i_s.cc
+++ b/storage/innobase/trx/trx0i_s.cc
@@ -588,7 +588,9 @@ thd_done:
 		row->trx_foreign_key_error = NULL;
 	}
 
+#ifdef BTR_CUR_HASH_ADAPT
 	row->trx_has_search_latch = (ibool) trx->has_search_latch;
+#endif /* BTR_CUR_HASH_ADAPT */
 
 	row->trx_is_read_only = trx->read_only;
 
diff --git a/storage/innobase/trx/trx0trx.cc b/storage/innobase/trx/trx0trx.cc
index 7f89df7094a..5e1ed8a34a1 100644
--- a/storage/innobase/trx/trx0trx.cc
+++ b/storage/innobase/trx/trx0trx.cc
@@ -270,8 +270,7 @@ struct TrxFactory {
 		ut_a(trx->lock.wait_lock == NULL);
 		ut_a(trx->lock.wait_thr == NULL);
 
-		ut_a(!trx->has_search_latch);
-
+		trx_assert_no_search_latch(trx);
 		ut_a(trx->dict_operation_lock_mode == 0);
 
 		if (trx->lock.lock_heap != NULL) {
@@ -340,7 +339,7 @@ struct TrxFactory {
 		ut_a(trx->lock.wait_thr == NULL);
 		ut_a(trx->lock.wait_lock == NULL);
 
-		ut_a(!trx->has_search_latch);
+		trx_assert_no_search_latch(trx);
 
 		ut_a(trx->dict_operation_lock_mode == 0);
 
@@ -2586,10 +2585,12 @@ state_ok:
 			(ulong) n_rec_locks);
 	}
 
+#ifdef BTR_CUR_HASH_ADAPT
 	if (trx->has_search_latch) {
 		newline = TRUE;
 		fputs(", holds adaptive hash latch", f);
 	}
+#endif /* BTR_CUR_HASH_ADAPT */
 
 	if (trx->undo_no != 0) {
 		newline = TRUE;
diff --git a/storage/innobase/ut/ut0new.cc b/storage/innobase/ut/ut0new.cc
index c2e3eb813af..e287a3b6dec 100644
--- a/storage/innobase/ut/ut0new.cc
+++ b/storage/innobase/ut/ut0new.cc
@@ -32,7 +32,9 @@ const size_t	alloc_max_retries = 60;
 
 /** Keys for registering allocations with performance schema.
 Keep this list alphabetically sorted. */
+#ifdef BTR_CUR_HASH_ADAPT
 PSI_memory_key	mem_key_ahi;
+#endif /* BTR_CUR_HASH_ADAPT */
 PSI_memory_key	mem_key_buf_buf_pool;
 PSI_memory_key	mem_key_dict_stats_bg_recalc_pool_t;
 PSI_memory_key	mem_key_dict_stats_index_map_t;
@@ -59,7 +61,9 @@ the list below:
    (in ut_new_boot()) then mem_key_other is used.
 Keep this list alphabetically sorted. */
 static PSI_memory_info	pfs_info[] = {
+#ifdef BTR_CUR_HASH_ADAPT
 	{&mem_key_ahi, "adaptive hash index", 0},
+#endif /* BTR_CUR_HASH_ADAPT */
 	{&mem_key_buf_buf_pool, "buf_buf_pool", 0},
 	{&mem_key_dict_stats_bg_recalc_pool_t, "dict_stats_bg_recalc_pool_t", 0},
 	{&mem_key_dict_stats_index_map_t, "dict_stats_index_map_t", 0},
-- 
2.11.0

