Merge lp:~laurynas-biveinis/percona-server/ahi-partitions-5.6-5.6 into lp:percona-server/5.6

Proposed by Laurynas Biveinis
Status: Merged
Approved by: Alexey Kopytov
Approved revision: no longer in the source branch.
Merged at revision: 420
Proposed branch: lp:~laurynas-biveinis/percona-server/ahi-partitions-5.6-5.6
Merge into: lp:percona-server/5.6
Diff against target: 1897 lines (+678/-212)
30 files modified
Percona-Server/mysql-test/suite/innodb/r/percona_ahi_partitions.result (+33/-0)
Percona-Server/mysql-test/suite/innodb/t/percona_ahi_partitions-master.opt (+1/-0)
Percona-Server/mysql-test/suite/innodb/t/percona_ahi_partitions.test (+67/-0)
Percona-Server/mysql-test/suite/sys_vars/r/innodb_adaptive_hash_index_partitions_basic.result (+9/-0)
Percona-Server/mysql-test/suite/sys_vars/t/innodb_adaptive_hash_index_partitions_basic.test (+14/-0)
Percona-Server/storage/innobase/btr/btr0cur.cc (+6/-5)
Percona-Server/storage/innobase/btr/btr0sea.cc (+212/-117)
Percona-Server/storage/innobase/buf/buf0buf.cc (+3/-1)
Percona-Server/storage/innobase/dict/dict0dict.cc (+4/-2)
Percona-Server/storage/innobase/ha/ha0ha.cc (+30/-4)
Percona-Server/storage/innobase/handler/ha_innodb.cc (+7/-0)
Percona-Server/storage/innobase/handler/xtradb_i_s.cc (+28/-28)
Percona-Server/storage/innobase/include/btr0sea.h (+52/-2)
Percona-Server/storage/innobase/include/btr0sea.ic (+79/-2)
Percona-Server/storage/innobase/include/btr0types.h (+4/-4)
Percona-Server/storage/innobase/include/buf0buf.h (+2/-0)
Percona-Server/storage/innobase/include/mtr0log.ic (+1/-0)
Percona-Server/storage/innobase/include/que0que.h (+1/-0)
Percona-Server/storage/innobase/include/read0read.h (+1/-0)
Percona-Server/storage/innobase/include/trx0roll.h (+1/-0)
Percona-Server/storage/innobase/include/trx0trx.h (+1/-4)
Percona-Server/storage/innobase/include/trx0trx.ic (+8/-4)
Percona-Server/storage/innobase/include/univ.i (+0/-1)
Percona-Server/storage/innobase/os/os0file.cc (+1/-0)
Percona-Server/storage/innobase/row/row0sel.cc (+71/-24)
Percona-Server/storage/innobase/srv/srv0conc.cc (+1/-0)
Percona-Server/storage/innobase/srv/srv0srv.cc (+20/-13)
Percona-Server/storage/innobase/sync/sync0sync.cc (+19/-1)
Percona-Server/storage/innobase/trx/trx0trx.cc (+1/-0)
Percona-Server/storage/innobase/ut/ut0ut.cc (+1/-0)
To merge this branch: bzr merge lp:~laurynas-biveinis/percona-server/ahi-partitions-5.6-5.6
Reviewer Review Type Date Requested Status
Alexey Kopytov (community) Approve
Review via email: mp+182960@code.launchpad.net

This proposal supersedes a proposal from 2013-08-29.

Description of the change

4th MP:

Removed btr_search_s_unlock_all().
Local compilation testing + percona_ahi_partitions testcase run.

3rd MP:

Review comments addressed,
http://jenkins.percona.com/job/percona-server-5.6-param/241/

2nd MP:

Review comments addressed.
http://jenkins.percona.com/job/percona-server-5.6-param/238/
Testsuite changes only, no new MTR 8 partitions Jenkins run.

1st MP:

Port AHI partitions from 5.5 to 5.6, implementing https://blueprints.launchpad.net/percona-server/+spec/ahi-part-5-6.

Default Jenkins run at
http://jenkins.percona.com/job/percona-server-5.6-param/233/
and additional MTR --mysqld=--mysqld=--innodb-adaptive-hash-index-partitions=8 run at
http://jenkins.percona.com/job/percona-server-5.6-param/234/.

Port adaptive hash index partitions from 5.5.

There are no major algorithmic differences from the 5.5 version. The
are minor differences from the 5.5 version:
- simplify latching changes in row_search_for_mysql() by spliting out
  a helper function trx_search_latch_lock(), by using
  trx_search_latch_release_if_reserved() where appropriate, by not
  bothering to compute an X waiters bit mask in phase 0 but checking
  whether any X waiter is present instead;
- add additional latching order enforcement code to
  sync_thread_add_level();
- some comments in surrounding code were updated to reflect the
  partitioning;
- added missing header and arg comments. Add function attributes to
  btr_search_get_hash_index(), btr_search_get_latch(). New helper
  function btr_search_own_all().
- merged btr_search_drop_page_hash_index() with 5.6 version and
  adjusted UNIV_LIKELY/UNIV_UNLIKELY annotations to better reflect my
  expected reality;
- instead of adding an outer loop to it as in 5.5, rename
  btr_search_validate() to btr_search_validate_one_table() and add a
  new function btr_search_validate() that calls the former in a loop;
- instead of disabling UNIV_SYNC_DEBUG checks in ha_clear(),
  ha_delete_hash_node(), and ha_search_and_update_if_found_func(),
  implement a helper function ha_assert_btr_x_locked() which is then
  called from them;
- fix AHI-related code formatting in
  xtradb_internal_hash_tables_fill_table().
- expanded the sys_vars suite test
  innodb_adaptive_hash_index_partitions_basic.test;

At the same time fix bug 1216815 /
http://bugs.mysql.com/bug.php?id=69617 (5.6.12 removed UNIV_SYNC_DEBUG
from UNIV_DEBUG) by re-enabling it in univ.i.

Merge bug 1214449 (Adaptive hash index partitions not tested in MTR)
fix by merging the testcase.

To post a comment you must log in.
Revision history for this message
Alexey Kopytov (akopytov) wrote : Posted in a previous version of this proposal

Same comments about excessive INSERT/SELECT statements as in https://code.launchpad.net/~laurynas-biveinis/percona-server/ahi-partitions-5.6-5.5/+merge/181713.

I haven't reviewed the actual code port yet.

review: Needs Fixing
Revision history for this message
Alexey Kopytov (akopytov) wrote : Posted in a previous version of this proposal

More comments on test cases:

> === added file 'Percona-Server/mysql-test/suite/sys_vars/t/innodb_adaptive_hash_index_partitions_basic.test'
> --- Percona-Server/mysql-test/suite/sys_vars/t/innodb_adaptive_hash_index_partitions_basic.test 1970-01-01 00:00:00 +0000
> +++ Percona-Server/mysql-test/suite/sys_vars/t/innodb_adaptive_hash_index_partitions_basic.test 2013-08-26 13:16:30 +0000
> @@ -0,0 +1,32 @@
> +# A sys_vars suite test from innodb_adaptive_hash_index_partitions. Adapted from
> +# innodb_buffer_pool_instances_basic.test.
> +
> +--source include/have_innodb.inc
> +
> +SELECT COUNT(@@GLOBAL.innodb_adaptive_hash_index_partitions) AS should_be_1;
> +

I’m not sure what the above check is supposed to verify. Apparently that
the variable exists and is not NULL. But if that’s the case, the test
would fail anyway.

Just checking the default value would make sense. But it’s not checked
anywhere in the test.

> +--error ER_INCORRECT_GLOBAL_LOCAL_VAR
> +SET @@GLOBAL.innodb_adaptive_hash_index_partitions=1;
> +
> +SELECT COUNT(@@GLOBAL.innodb_adaptive_hash_index_partitions) AS should_be_1;
> +

The same check again?

> +SELECT COUNT(VARIABLE_VALUE) AS should_be_1
> +FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES
> +WHERE VARIABLE_NAME='innodb_adaptive_hash_index_partitions';
> +
> +SELECT @@GLOBAL.innodb_adaptive_hash_index_partitions = VARIABLE_VALUE AS should_be_1
> +FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES
> +WHERE VARIABLE_NAME='innodb_adaptive_hash_index_partitions';
> +
> +SELECT @@innodb_adaptive_hash_index_partitions = @@GLOBAL.innodb_adaptive_hash_index_partitions AS should_be_1;
> +
> +SELECT COUNT(@@innodb_adaptive_hash_index_partitions) AS should_be_1;
> +
> +--Error ER_INCORRECT_GLOBAL_LOCAL_VAR
> +SELECT COUNT(@@LOCAL.innodb_adaptive_hash_index_partitions);
> +
> +--Error ER_INCORRECT_GLOBAL_LOCAL_VAR
> +SELECT COUNT(@@SESSION.innodb_adaptive_hash_index_partitions);
> +
> +--Error ER_BAD_FIELD_ERROR
> +SELECT innodb_adaptive_hash_index_partitions = @@SESSION.innodb_adaptive_hash_index_partitions;

I don’t know the purpose of all these checks which are replicated from
one test case to another. It looks like some incompetent (to put it
mildly) person first wrote them, and then everyone else copies that
stuff whenever he needs to implement a variable test.

What I would expect to see in a sys_var.*_basic test is verifying
the variable type, and default/min/max values. Instead most tests do
some acrobatics with I_S and different syntax to access the variable.

Please also consider backporting it to 5.5 as I mentioned in the 5.5 MP.

review: Needs Fixing
Revision history for this message
Laurynas Biveinis (laurynas-biveinis) wrote : Posted in a previous version of this proposal

> More comments on test cases:
...
> I don’t know the purpose of all these checks which are replicated from
> one test case to another. It looks like some incompetent (to put it
> mildly) person first wrote them, and then everyone else copies that
> stuff whenever he needs to implement a variable test.
>
> What I would expect to see in a sys_var.*_basic test is verifying
> the variable type, and default/min/max values. Instead most tests do
> some acrobatics with I_S and different syntax to access the variable.

I absolutely agree with all these comments and obviously I have cut some corners when copied/pasted/modified it.

What do you think about the following? The variable is global-only, read-only. Check the default, check the read-only-ness, check that global only. For 5.5 too.

# A sys_vars suite test from innodb_adaptive_hash_index_partitions.

--source include/have_innodb.inc

SELECT @@GLOBAL.innodb_adaptive_hash_index_partitions;

--error ER_INCORRECT_GLOBAL_LOCAL_VAR
SET @@GLOBAL.innodb_adaptive_hash_index_partitions=1;

--error ER_INCORRECT_GLOBAL_LOCAL_VAR
SELECT @@LOCAL.innodb_adaptive_hash_index_partitions;

--error ER_INCORRECT_GLOBAL_LOCAL_VAR
SELECT @@SESSION.innodb_adaptive_hash_index_partitions;

Revision history for this message
Alexey Kopytov (akopytov) wrote : Posted in a previous version of this proposal

On Tue, Aug 27 2013 15:52:14 +0000, Laurynas Biveinis wrote:

>> More comments on test cases:
> ...
>> I don’t know the purpose of all these checks which are replicated from
>> one test case to another. It looks like some incompetent (to put it
>> mildly) person first wrote them, and then everyone else copies that
>> stuff whenever he needs to implement a variable test.
>>
>> What I would expect to see in a sys_var.*_basic test is verifying
>> the variable type, and default/min/max values. Instead most tests do
>> some acrobatics with I_S and different syntax to access the variable.
>
> I absolutely agree with all these comments and obviously I have cut some corners when copied/pasted/modified it.
>
> What do you think about the following? The variable is global-only, read-only. Check the default, check the read-only-ness, check that global only. For 5.5 too.
>
> # A sys_vars suite test from innodb_adaptive_hash_index_partitions.
>
> --source include/have_innodb.inc
>
> SELECT @@GLOBAL.innodb_adaptive_hash_index_partitions;
>
> --error ER_INCORRECT_GLOBAL_LOCAL_VAR
> SET @@GLOBAL.innodb_adaptive_hash_index_partitions=1;
>
> --error ER_INCORRECT_GLOBAL_LOCAL_VAR
> SELECT @@LOCAL.innodb_adaptive_hash_index_partitions;
>
> --error ER_INCORRECT_GLOBAL_LOCAL_VAR
> SELECT @@SESSION.innodb_adaptive_hash_index_partitions;

OK.

Revision history for this message
Alexey Kopytov (akopytov) wrote : Posted in a previous version of this proposal
Download full text (4.5 KiB)

Hi Laurynas,

As discussed on IRC, I’m only posting comments specific to the port
itself. I’ll handle everything else in the followup work on AHI.

On Wed, Aug 28 2013 13:59:04 +0400, Laurynas Biveinis wrote:

[...]

> - btr_search_latch_temp = (rw_lock_t*) mem_alloc(sizeof(rw_lock_t));
> + /* btr_search_index_num should be <= 32. (bits of
> + trx->has_search_latch) */
> + ut_ad(btr_search_index_num <= 32);

This assertion is wrong. We allow 64 AHI partitions in 64-bit
architectures in 5.5, and its documented. It’s just that the code
comment is wrong.

>
> - rw_lock_create(btr_search_latch_key, &btr_search_latch,
> - SYNC_SEARCH_SYS);
> + btr_search_latch_temp_arr = (rw_lock_t**)
> + mem_alloc(sizeof(rw_lock_t *) * btr_search_index_num);

What’s so temporal about btr_search_latch_temp_arr[]? It might make
sense in the single-lock code (though the reasoning for it is dubious),
but it correctly does not have “temp” in 5.5 code, as it’s a regular array.

[...]

> index = block->index;
> -
> - if (UNIV_LIKELY(!index)) {
> -
> - rw_lock_s_unlock(&btr_search_latch);
> -
> + if (UNIV_UNLIKELY(!index)) {
> + rw_lock_s_unlock(btr_search_latch);
> return;
> }
>
> + ut_a(btr_search_latch == btr_search_get_latch(index->id));
> +

Shouldn’t this be a debug assertion? btr_search_latch is basically a
constant attribute of each index. So it’s more of a code invariant.

[...]

> -btr_search_validate(void)
> -/*=====================*/
> +btr_search_validate_one_table(
> +/*==========================*/
> + ulint t)
> {
> ha_node_t* node;
> ulint n_page_dumps = 0;
> @@ -1874,24 +1944,20 @@
>
> rec_offs_init(offsets_);
>
> - rw_lock_x_lock(&btr_search_latch);
> - buf_pool_mutex_enter_all();
> -
> - cell_count = hash_get_n_cells(btr_search_sys->hash_index);
> + cell_count = hash_get_n_cells(btr_search_sys->hash_index[t]);
>

Why buf_pool_mutex_enter_all() / buf_pool_mutex_exit_all() calls are
being removed from btr_search_validate[_one_table]()?

[...]

> +ha_assert_btr_x_locked(
> +/*===================*/
> + const hash_table_t* table) /*!<in: hash table to check */
> +{
> + ulint i;
> +
> + ut_ad(table->adaptive);
> +
> + for (i = 0; i < btr_search_index_num; i++)
> + if (btr_search_sys->hash_index[i] == table)
> + break;

Braces.

[...]

> +/********************************************************************//**
> +Latches all adaptive hash index latches in shared mode. */
> +UNIV_INLINE
> +void
> +btr_search_s_lock_all(void);
> +/*========================*/
> +
> +/********************************************************************//**
> +Unlatches all adaptive hash index latches in shared mode. */
> +UNIV_INLINE
> +void
> +btr_search_s_unlock_all(void);
> +/*==========================*/
> +

These ones are declared and defined, but not used.

[...]

> === modified file 'Percona-Server/storage/innobase/include/mtr0log.ic'
> --- Percona-Server/storage/innobase/include/mtr0log.ic 2013-08-06 15:16:34 +0000
> +++ Percona-Server/storage/innobase/include/mtr0log.ic 2013-08-28 09:57:53 +0000
> @@ -28,6 +28,7 @@
> #include "buf0buf.h"
> #include "buf0dblwr.h"
> #include "fsp0types.h"
> +#include "btr0types.h"
> #inc...

Read more...

review: Needs Fixing
Revision history for this message
Laurynas Biveinis (laurynas-biveinis) wrote : Posted in a previous version of this proposal

> Why buf_pool_mutex_enter_all() / buf_pool_mutex_exit_all() calls are
> being removed from btr_search_validate[_one_table]()?

A mistake, mix-up with the buffer pool mutex split patch.

> > +#include "btr0types.h"
>
> Why new #includes in mtr0log.ic, que0que.h and read0read.h, trx0roll.h,
> trx0trx.cc, ut0ut.cc and os0file.cc?

It's because trx0trx.ic needs btr stuff in trx_search_latch_reserve_if_needed(), and with these includes I broke the circular dependencies.

Revision history for this message
Alexey Kopytov (akopytov) wrote : Posted in a previous version of this proposal

btr_search_s_unlock_all() is still there.

review: Needs Fixing
Revision history for this message
Laurynas Biveinis (laurynas-biveinis) wrote : Posted in a previous version of this proposal

gah, removing.

Revision history for this message
Alexey Kopytov (akopytov) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added file 'Percona-Server/mysql-test/suite/innodb/r/percona_ahi_partitions.result'
2--- Percona-Server/mysql-test/suite/innodb/r/percona_ahi_partitions.result 1970-01-01 00:00:00 +0000
3+++ Percona-Server/mysql-test/suite/innodb/r/percona_ahi_partitions.result 2013-08-29 17:11:28 +0000
4@@ -0,0 +1,33 @@
5+SELECT @@GLOBAL.innodb_adaptive_hash_index;
6+@@GLOBAL.innodb_adaptive_hash_index
7+1
8+SELECT @@GLOBAL.innodb_adaptive_hash_index_partitions;
9+@@GLOBAL.innodb_adaptive_hash_index_partitions
10+4
11+SET GLOBAL innodb_monitor_enable=module_adaptive_hash;
12+CREATE TABLE t1 (a INT PRIMARY KEY, b INT, c CHAR(200), UNIQUE INDEX b(b)) ENGINE=InnoDB;
13+CREATE TABLE t2 (a INT PRIMARY KEY, b INT, c CHAR(200), UNIQUE INDEX b(b)) ENGINE=InnoDB;
14+CREATE TABLE t3 (a INT PRIMARY KEY, b INT, c CHAR(200), UNIQUE INDEX b(b)) ENGINE=InnoDB;
15+Filling tables
16+Querying
17+SELECT COUNT >= 6 as should_be_1 FROM INFORMATION_SCHEMA.INNODB_METRICS WHERE NAME = 'adaptive_hash_pages_added';
18+should_be_1
19+1
20+SELECT COUNT >= 6 as should_be_1 FROM INFORMATION_SCHEMA.INNODB_METRICS WHERE NAME = 'adaptive_hash_rows_added';
21+should_be_1
22+1
23+SELECT COUNT > 0 as should_be_1 FROM INFORMATION_SCHEMA.INNODB_METRICS WHERE NAME = 'adaptive_hash_searches';
24+should_be_1
25+1
26+SELECT COUNT(*) > 0 AS should_be_1 FROM INFORMATION_SCHEMA.INNODB_BUFFER_PAGE
27+WHERE PAGE_STATE LIKE "MEMORY";
28+should_be_1
29+1
30+SELECT COUNT(*) >= 6 AS should_be_1 FROM INFORMATION_SCHEMA.INNODB_BUFFER_PAGE
31+WHERE IS_HASHED LIKE "YES";
32+should_be_1
33+1
34+SET GLOBAL innodb_monitor_disable=module_adaptive_hash;
35+DROP TABLE t1, t2, t3;
36+SET GLOBAL innodb_monitor_enable=default;
37+SET GLOBAL innodb_monitor_disable=default;
38
39=== added file 'Percona-Server/mysql-test/suite/innodb/t/percona_ahi_partitions-master.opt'
40--- Percona-Server/mysql-test/suite/innodb/t/percona_ahi_partitions-master.opt 1970-01-01 00:00:00 +0000
41+++ Percona-Server/mysql-test/suite/innodb/t/percona_ahi_partitions-master.opt 2013-08-29 17:11:28 +0000
42@@ -0,0 +1,1 @@
43+--innodb-adaptive-hash-index-partitions=4
44
45=== added file 'Percona-Server/mysql-test/suite/innodb/t/percona_ahi_partitions.test'
46--- Percona-Server/mysql-test/suite/innodb/t/percona_ahi_partitions.test 1970-01-01 00:00:00 +0000
47+++ Percona-Server/mysql-test/suite/innodb/t/percona_ahi_partitions.test 2013-08-29 17:11:28 +0000
48@@ -0,0 +1,67 @@
49+#
50+# Basic test for InnoDB adaptive hash index partitions.
51+# TODO: add another testcase that uses DEBUG_SYNC to check the partition locking
52+#
53+--source include/have_innodb.inc
54+
55+# Check setup
56+SELECT @@GLOBAL.innodb_adaptive_hash_index;
57+SELECT @@GLOBAL.innodb_adaptive_hash_index_partitions;
58+
59+SET GLOBAL innodb_monitor_enable=module_adaptive_hash;
60+
61+# 6 index trees across 4 AHI partitions
62+CREATE TABLE t1 (a INT PRIMARY KEY, b INT, c CHAR(200), UNIQUE INDEX b(b)) ENGINE=InnoDB;
63+CREATE TABLE t2 (a INT PRIMARY KEY, b INT, c CHAR(200), UNIQUE INDEX b(b)) ENGINE=InnoDB;
64+CREATE TABLE t3 (a INT PRIMARY KEY, b INT, c CHAR(200), UNIQUE INDEX b(b)) ENGINE=InnoDB;
65+
66+--echo Filling tables
67+--disable_query_log
68+let $i=3;
69+while ($i)
70+{
71+ eval INSERT INTO t1 VALUES ($i, $i, REPEAT("a", 200));
72+ eval INSERT INTO t2 VALUES ($i, $i, REPEAT("a", 200));
73+ eval INSERT INTO t3 VALUES ($i, $i, REPEAT("a", 200));
74+ dec $i;
75+}
76+
77+--echo Querying
78+--disable_result_log
79+let $i=200;
80+while ($i)
81+{
82+ SELECT b FROM t1 WHERE a=1;
83+ SELECT a FROM t1 WHERE b=1;
84+ SELECT b FROM t2 WHERE a=2;
85+ SELECT a FROM t2 WHERE b=2;
86+ SELECT b FROM t3 WHERE a=3;
87+ SELECT a FROM t3 WHERE b=3;
88+ dec $i;
89+}
90+--enable_result_log
91+--enable_query_log
92+
93+# Some buffer pool pages should be hashed
94+SELECT COUNT >= 6 as should_be_1 FROM INFORMATION_SCHEMA.INNODB_METRICS WHERE NAME = 'adaptive_hash_pages_added';
95+# Some rows should be hashed
96+SELECT COUNT >= 6 as should_be_1 FROM INFORMATION_SCHEMA.INNODB_METRICS WHERE NAME = 'adaptive_hash_rows_added';
97+# AHI should have been used for queries, but the exact lower bound is hard to determine
98+SELECT COUNT > 0 as should_be_1 FROM INFORMATION_SCHEMA.INNODB_METRICS WHERE NAME = 'adaptive_hash_searches';
99+
100+# Buffer pool must contain AHI pages now
101+SELECT COUNT(*) > 0 AS should_be_1 FROM INFORMATION_SCHEMA.INNODB_BUFFER_PAGE
102+ WHERE PAGE_STATE LIKE "MEMORY";
103+
104+# Buffer pool must contain no less than the number of index trees hashed pages now
105+SELECT COUNT(*) >= 6 AS should_be_1 FROM INFORMATION_SCHEMA.INNODB_BUFFER_PAGE
106+ WHERE IS_HASHED LIKE "YES";
107+
108+SET GLOBAL innodb_monitor_disable=module_adaptive_hash;
109+
110+DROP TABLE t1, t2, t3;
111+
112+--disable_warnings
113+SET GLOBAL innodb_monitor_enable=default;
114+SET GLOBAL innodb_monitor_disable=default;
115+--enable_warnings
116
117=== added file 'Percona-Server/mysql-test/suite/sys_vars/r/innodb_adaptive_hash_index_partitions_basic.result'
118--- Percona-Server/mysql-test/suite/sys_vars/r/innodb_adaptive_hash_index_partitions_basic.result 1970-01-01 00:00:00 +0000
119+++ Percona-Server/mysql-test/suite/sys_vars/r/innodb_adaptive_hash_index_partitions_basic.result 2013-08-29 17:11:28 +0000
120@@ -0,0 +1,9 @@
121+SELECT @@GLOBAL.innodb_adaptive_hash_index_partitions;
122+@@GLOBAL.innodb_adaptive_hash_index_partitions
123+1
124+SET @@GLOBAL.innodb_adaptive_hash_index_partitions=1;
125+ERROR HY000: Variable 'innodb_adaptive_hash_index_partitions' is a read only variable
126+SELECT @@LOCAL.innodb_adaptive_hash_index_partitions;
127+ERROR HY000: Variable 'innodb_adaptive_hash_index_partitions' is a GLOBAL variable
128+SELECT @@SESSION.innodb_adaptive_hash_index_partitions;
129+ERROR HY000: Variable 'innodb_adaptive_hash_index_partitions' is a GLOBAL variable
130
131=== added file 'Percona-Server/mysql-test/suite/sys_vars/t/innodb_adaptive_hash_index_partitions_basic.test'
132--- Percona-Server/mysql-test/suite/sys_vars/t/innodb_adaptive_hash_index_partitions_basic.test 1970-01-01 00:00:00 +0000
133+++ Percona-Server/mysql-test/suite/sys_vars/t/innodb_adaptive_hash_index_partitions_basic.test 2013-08-29 17:11:28 +0000
134@@ -0,0 +1,14 @@
135+# A sys_vars suite test for innodb_adaptive_hash_index_partitions.
136+
137+--source include/have_innodb.inc
138+
139+SELECT @@GLOBAL.innodb_adaptive_hash_index_partitions;
140+
141+--error ER_INCORRECT_GLOBAL_LOCAL_VAR
142+SET @@GLOBAL.innodb_adaptive_hash_index_partitions=1;
143+
144+--error ER_INCORRECT_GLOBAL_LOCAL_VAR
145+SELECT @@LOCAL.innodb_adaptive_hash_index_partitions;
146+
147+--error ER_INCORRECT_GLOBAL_LOCAL_VAR
148+SELECT @@SESSION.innodb_adaptive_hash_index_partitions;
149
150=== modified file 'Percona-Server/storage/innobase/btr/btr0cur.cc'
151--- Percona-Server/storage/innobase/btr/btr0cur.cc 2013-08-14 03:57:21 +0000
152+++ Percona-Server/storage/innobase/btr/btr0cur.cc 2013-08-29 17:11:28 +0000
153@@ -536,7 +536,8 @@
154 # ifdef UNIV_SEARCH_PERF_STAT
155 info->n_searches++;
156 # endif
157- if (rw_lock_get_writer(&btr_search_latch) == RW_LOCK_NOT_LOCKED
158+ if ((rw_lock_get_writer(btr_search_get_latch(cursor->index->id))
159+ == RW_LOCK_NOT_LOCKED)
160 && latch_mode <= BTR_MODIFY_LEAF
161 && info->last_hash_succ
162 && !estimate
163@@ -572,7 +573,7 @@
164
165 if (has_search_latch) {
166 /* Release possible search latch to obey latching order */
167- rw_lock_s_unlock(&btr_search_latch);
168+ rw_lock_s_unlock(btr_search_get_latch(cursor->index->id));
169 }
170
171 /* Store the position of the tree latch we push to mtr so that we
172@@ -895,7 +896,7 @@
173
174 if (has_search_latch) {
175
176- rw_lock_s_lock(&btr_search_latch);
177+ rw_lock_s_lock(btr_search_get_latch(cursor->index->id));
178 }
179 }
180
181@@ -2162,13 +2163,13 @@
182 btr_search_update_hash_on_delete(cursor);
183 }
184
185- rw_lock_x_lock(&btr_search_latch);
186+ rw_lock_x_lock(btr_search_get_latch(cursor->index->id));
187 }
188
189 row_upd_rec_in_place(rec, index, offsets, update, page_zip);
190
191 if (is_hashed) {
192- rw_lock_x_unlock(&btr_search_latch);
193+ rw_lock_x_unlock(btr_search_get_latch(cursor->index->id));
194 }
195
196 btr_cur_update_in_place_log(flags, rec, index, update,
197
198=== modified file 'Percona-Server/storage/innobase/btr/btr0sea.cc'
199--- Percona-Server/storage/innobase/btr/btr0sea.cc 2013-08-06 15:16:34 +0000
200+++ Percona-Server/storage/innobase/btr/btr0sea.cc 2013-08-29 17:11:28 +0000
201@@ -47,6 +47,9 @@
202 Protected by btr_search_latch. */
203 UNIV_INTERN char btr_search_enabled = TRUE;
204
205+/** Number of adaptive hash index partitions */
206+UNIV_INTERN ulint btr_search_index_num;
207+
208 /** A dummy variable to fool the compiler */
209 UNIV_INTERN ulint btr_search_this_is_zero = 0;
210
211@@ -68,9 +71,9 @@
212 being updated in-place! We can use fact (1) to perform unique searches to
213 indexes. */
214
215-/* We will allocate the latch from dynamic memory to get it to the
216+/* We will allocate the latches from dynamic memory to get them to the
217 same DRAM page as other hotspot semaphores */
218-UNIV_INTERN rw_lock_t* btr_search_latch_temp;
219+UNIV_INTERN rw_lock_t** btr_search_latch_arr;
220
221 /** padding to prevent other memory update hotspots from residing on
222 the same memory cache line */
223@@ -122,18 +125,19 @@
224 will not guarantee success. */
225 static
226 void
227-btr_search_check_free_space_in_heap(void)
228-/*=====================================*/
229+btr_search_check_free_space_in_heap(
230+/*================================*/
231+ index_id_t key) /*!<in: id of the hashed index tree */
232 {
233 hash_table_t* table;
234 mem_heap_t* heap;
235
236 #ifdef UNIV_SYNC_DEBUG
237- ut_ad(!rw_lock_own(&btr_search_latch, RW_LOCK_SHARED));
238- ut_ad(!rw_lock_own(&btr_search_latch, RW_LOCK_EX));
239+ ut_ad(!rw_lock_own(btr_search_get_latch(key), RW_LOCK_SHARED));
240+ ut_ad(!rw_lock_own(btr_search_get_latch(key), RW_LOCK_EX));
241 #endif /* UNIV_SYNC_DEBUG */
242
243- table = btr_search_sys->hash_index;
244+ table = btr_search_get_hash_index(key);
245
246 heap = table->heap;
247
248@@ -144,7 +148,7 @@
249 if (heap->free_block == NULL) {
250 buf_block_t* block = buf_block_alloc(NULL);
251
252- rw_lock_x_lock(&btr_search_latch);
253+ rw_lock_x_lock(btr_search_get_latch(key));
254
255 if (heap->free_block == NULL) {
256 heap->free_block = block;
257@@ -152,7 +156,7 @@
258 buf_block_free(block);
259 }
260
261- rw_lock_x_unlock(&btr_search_latch);
262+ rw_lock_x_unlock(btr_search_get_latch(key));
263 }
264 }
265
266@@ -164,23 +168,47 @@
267 /*==================*/
268 ulint hash_size) /*!< in: hash index hash table size */
269 {
270+ ulint i;
271+
272+ /* PS bug lp:1018264 - Multiple hash index partitions causes overly
273+ large hash index: When multiple adaptive hash index partitions are
274+ specified, _each_ partition was being created with hash_size which
275+ should be 1/64 of the total size of all buffer pools which is
276+ incorrect and can cause overly high memory usage. hash_size
277+ should be representing the _total_ size of all partitions, not the
278+ individual size of each partition. */
279+ hash_size /= btr_search_index_num;
280+
281 /* We allocate the search latch from dynamic memory:
282 see above at the global variable definition */
283
284- btr_search_latch_temp = (rw_lock_t*) mem_alloc(sizeof(rw_lock_t));
285+ /* btr_search_index_num should be no greater than bits of
286+ trx->has_search_latch, which is ulint. */
287+ ut_ad(btr_search_index_num <= sizeof(ulint));
288
289- rw_lock_create(btr_search_latch_key, &btr_search_latch,
290- SYNC_SEARCH_SYS);
291+ btr_search_latch_arr = (rw_lock_t**)
292+ mem_alloc(sizeof(rw_lock_t *) * btr_search_index_num);
293
294 btr_search_sys = (btr_search_sys_t*)
295 mem_alloc(sizeof(btr_search_sys_t));
296
297- btr_search_sys->hash_index = ha_create(hash_size, 0,
298- MEM_HEAP_FOR_BTR_SEARCH, 0);
299+ btr_search_sys->hash_index = (hash_table_t **)
300+ mem_alloc(sizeof(hash_table_t *) * btr_search_index_num);
301+
302+ for (i = 0; i < btr_search_index_num; i++) {
303+ btr_search_latch_arr[i] = (rw_lock_t *)
304+ mem_alloc(sizeof(rw_lock_t));
305+
306+ rw_lock_create(btr_search_latch_key, btr_search_latch_arr[i],
307+ SYNC_SEARCH_SYS);
308+
309+ btr_search_sys->hash_index[i]
310+ = ha_create(hash_size, 0, MEM_HEAP_FOR_BTR_SEARCH, 0);
311+
312 #if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG
313- btr_search_sys->hash_index->adaptive = TRUE;
314+ btr_search_sys->hash_index[i]->adaptive = TRUE;
315 #endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */
316-
317+ }
318 }
319
320 /*****************************************************************//**
321@@ -190,11 +218,25 @@
322 btr_search_sys_free(void)
323 /*=====================*/
324 {
325- rw_lock_free(&btr_search_latch);
326- mem_free(btr_search_latch_temp);
327- btr_search_latch_temp = NULL;
328- mem_heap_free(btr_search_sys->hash_index->heap);
329- hash_table_free(btr_search_sys->hash_index);
330+ ulint i;
331+
332+ for (i = 0; i < btr_search_index_num; i++) {
333+
334+ rw_lock_free(btr_search_latch_arr[i]);
335+
336+ mem_free(btr_search_latch_arr[i]);
337+
338+ mem_heap_free(btr_search_sys->hash_index[i]->heap);
339+
340+ hash_table_free(btr_search_sys->hash_index[i]);
341+
342+ }
343+
344+ mem_free(btr_search_latch_arr);
345+ btr_search_latch_arr = NULL;
346+
347+ mem_free(btr_search_sys->hash_index);
348+
349 mem_free(btr_search_sys);
350 btr_search_sys = NULL;
351 }
352@@ -210,13 +252,14 @@
353 dict_index_t* index;
354
355 ut_ad(mutex_own(&dict_sys->mutex));
356-#ifdef UNIV_SYNC_DEBUG
357- ut_ad(rw_lock_own(&btr_search_latch, RW_LOCK_EX));
358-#endif /* UNIV_SYNC_DEBUG */
359
360 for (index = dict_table_get_first_index(table); index;
361 index = dict_table_get_next_index(index)) {
362
363+#ifdef UNIV_SYNC_DEBUG
364+ ut_ad(rw_lock_own(btr_search_get_latch(index->id),
365+ RW_LOCK_EX));
366+#endif /* UNIV_SYNC_DEBUG */
367 index->search_info->ref_count = 0;
368 }
369 }
370@@ -229,9 +272,10 @@
371 /*====================*/
372 {
373 dict_table_t* table;
374+ ulint i;
375
376 mutex_enter(&dict_sys->mutex);
377- rw_lock_x_lock(&btr_search_latch);
378+ btr_search_x_lock_all();
379
380 btr_search_enabled = FALSE;
381
382@@ -255,10 +299,12 @@
383 buf_pool_clear_hash_index();
384
385 /* Clear the adaptive hash index. */
386- hash_table_clear(btr_search_sys->hash_index);
387- mem_heap_empty(btr_search_sys->hash_index->heap);
388+ for (i = 0; i < btr_search_index_num; i++) {
389+ hash_table_clear(btr_search_sys->hash_index[i]);
390+ mem_heap_empty(btr_search_sys->hash_index[i]->heap);
391+ }
392
393- rw_lock_x_unlock(&btr_search_latch);
394+ btr_search_x_unlock_all();
395 }
396
397 /********************************************************************//**
398@@ -268,11 +314,11 @@
399 btr_search_enable(void)
400 /*====================*/
401 {
402- rw_lock_x_lock(&btr_search_latch);
403+ btr_search_x_lock_all();
404
405 btr_search_enabled = TRUE;
406
407- rw_lock_x_unlock(&btr_search_latch);
408+ btr_search_x_unlock_all();
409 }
410
411 /*****************************************************************//**
412@@ -324,20 +370,21 @@
413 ulint
414 btr_search_info_get_ref_count(
415 /*==========================*/
416- btr_search_t* info) /*!< in: search info. */
417+ btr_search_t* info, /*!< in: search info. */
418+ index_id_t key) /*!< in: id of the index owning search info */
419 {
420 ulint ret;
421
422 ut_ad(info);
423
424 #ifdef UNIV_SYNC_DEBUG
425- ut_ad(!rw_lock_own(&btr_search_latch, RW_LOCK_SHARED));
426- ut_ad(!rw_lock_own(&btr_search_latch, RW_LOCK_EX));
427+ ut_ad(!rw_lock_own(btr_search_get_latch(key), RW_LOCK_SHARED));
428+ ut_ad(!rw_lock_own(btr_search_get_latch(key), RW_LOCK_EX));
429 #endif /* UNIV_SYNC_DEBUG */
430
431- rw_lock_s_lock(&btr_search_latch);
432+ rw_lock_s_lock(btr_search_get_latch(key));
433 ret = info->ref_count;
434- rw_lock_s_unlock(&btr_search_latch);
435+ rw_lock_s_unlock(btr_search_get_latch(key));
436
437 return(ret);
438 }
439@@ -353,17 +400,15 @@
440 btr_search_t* info, /*!< in/out: search info */
441 btr_cur_t* cursor) /*!< in: cursor which was just positioned */
442 {
443- dict_index_t* index;
444+ dict_index_t* index = cursor->index;
445 ulint n_unique;
446 int cmp;
447
448 #ifdef UNIV_SYNC_DEBUG
449- ut_ad(!rw_lock_own(&btr_search_latch, RW_LOCK_SHARED));
450- ut_ad(!rw_lock_own(&btr_search_latch, RW_LOCK_EX));
451+ ut_ad(!rw_lock_own(btr_search_get_latch(index->id), RW_LOCK_SHARED));
452+ ut_ad(!rw_lock_own(btr_search_get_latch(index->id), RW_LOCK_EX));
453 #endif /* UNIV_SYNC_DEBUG */
454
455- index = cursor->index;
456-
457 if (dict_index_is_ibuf(index)) {
458 /* So many deletes are performed on an insert buffer tree
459 that we do not consider a hash index useful on it: */
460@@ -477,8 +522,10 @@
461 /*!< in: cursor */
462 {
463 #ifdef UNIV_SYNC_DEBUG
464- ut_ad(!rw_lock_own(&btr_search_latch, RW_LOCK_SHARED));
465- ut_ad(!rw_lock_own(&btr_search_latch, RW_LOCK_EX));
466+ ut_ad(!rw_lock_own(btr_search_get_latch(cursor->index->id),
467+ RW_LOCK_SHARED));
468+ ut_ad(!rw_lock_own(btr_search_get_latch(cursor->index->id),
469+ RW_LOCK_EX));
470 ut_ad(rw_lock_own(&block->lock, RW_LOCK_SHARED)
471 || rw_lock_own(&block->lock, RW_LOCK_EX));
472 #endif /* UNIV_SYNC_DEBUG */
473@@ -562,7 +609,8 @@
474
475 ut_ad(cursor->flag == BTR_CUR_HASH_FAIL);
476 #ifdef UNIV_SYNC_DEBUG
477- ut_ad(rw_lock_own(&btr_search_latch, RW_LOCK_EX));
478+ ut_ad(rw_lock_own(btr_search_get_latch(cursor->index->id),
479+ RW_LOCK_EX));
480 ut_ad(rw_lock_own(&(block->lock), RW_LOCK_SHARED)
481 || rw_lock_own(&(block->lock), RW_LOCK_EX));
482 #endif /* UNIV_SYNC_DEBUG */
483@@ -603,11 +651,13 @@
484 mem_heap_free(heap);
485 }
486 #ifdef UNIV_SYNC_DEBUG
487- ut_ad(rw_lock_own(&btr_search_latch, RW_LOCK_EX));
488+ ut_ad(rw_lock_own(btr_search_get_latch(cursor->index->id),
489+ RW_LOCK_EX));
490 #endif /* UNIV_SYNC_DEBUG */
491
492- ha_insert_for_fold(btr_search_sys->hash_index, fold,
493- block, rec);
494+ ha_insert_for_fold(
495+ btr_search_get_hash_index(cursor->index->id), fold,
496+ block, rec);
497
498 MONITOR_INC(MONITOR_ADAPTIVE_HASH_ROW_ADDED);
499 }
500@@ -628,8 +678,10 @@
501 ulint* params2;
502
503 #ifdef UNIV_SYNC_DEBUG
504- ut_ad(!rw_lock_own(&btr_search_latch, RW_LOCK_SHARED));
505- ut_ad(!rw_lock_own(&btr_search_latch, RW_LOCK_EX));
506+ ut_ad(!rw_lock_own(btr_search_get_latch(cursor->index->id),
507+ RW_LOCK_SHARED));
508+ ut_ad(!rw_lock_own(btr_search_get_latch(cursor->index->id),
509+ RW_LOCK_EX));
510 #endif /* UNIV_SYNC_DEBUG */
511
512 block = btr_cur_get_block(cursor);
513@@ -647,7 +699,7 @@
514
515 if (build_index || (cursor->flag == BTR_CUR_HASH_FAIL)) {
516
517- btr_search_check_free_space_in_heap();
518+ btr_search_check_free_space_in_heap(cursor->index->id);
519 }
520
521 if (cursor->flag == BTR_CUR_HASH_FAIL) {
522@@ -657,11 +709,11 @@
523 btr_search_n_hash_fail++;
524 #endif /* UNIV_SEARCH_PERF_STAT */
525
526- rw_lock_x_lock(&btr_search_latch);
527+ rw_lock_x_lock(btr_search_get_latch(cursor->index->id));
528
529 btr_search_update_hash_ref(info, block, cursor);
530
531- rw_lock_x_unlock(&btr_search_latch);
532+ rw_lock_x_unlock(btr_search_get_latch(cursor->index->id));
533 }
534
535 if (build_index) {
536@@ -906,17 +958,19 @@
537 cursor->flag = BTR_CUR_HASH;
538
539 if (UNIV_LIKELY(!has_search_latch)) {
540- rw_lock_s_lock(&btr_search_latch);
541+ rw_lock_s_lock(btr_search_get_latch(index_id));
542
543 if (UNIV_UNLIKELY(!btr_search_enabled)) {
544 goto failure_unlock;
545 }
546 }
547
548- ut_ad(rw_lock_get_writer(&btr_search_latch) != RW_LOCK_EX);
549- ut_ad(rw_lock_get_reader_count(&btr_search_latch) > 0);
550+ ut_ad(rw_lock_get_writer(btr_search_get_latch(index_id))
551+ != RW_LOCK_EX);
552+ ut_ad(rw_lock_get_reader_count(btr_search_get_latch(index_id)) > 0);
553
554- rec = (rec_t*) ha_search_and_get_data(btr_search_sys->hash_index, fold);
555+ rec = (rec_t*) ha_search_and_get_data(
556+ btr_search_get_hash_index(index_id), fold);
557
558 if (UNIV_UNLIKELY(!rec)) {
559 goto failure_unlock;
560@@ -934,7 +988,7 @@
561 goto failure_unlock;
562 }
563
564- rw_lock_s_unlock(&btr_search_latch);
565+ rw_lock_s_unlock(btr_search_get_latch(index_id));
566
567 buf_block_dbg_add_level(block, SYNC_TREE_NODE_FROM_HASH);
568 }
569@@ -1031,7 +1085,7 @@
570 /*-------------------------------------------*/
571 failure_unlock:
572 if (UNIV_LIKELY(!has_search_latch)) {
573- rw_lock_s_unlock(&btr_search_latch);
574+ rw_lock_s_unlock(btr_search_get_latch(index_id));
575 }
576 failure:
577 cursor->flag = BTR_CUR_HASH_FAIL;
578@@ -1079,12 +1133,9 @@
579 const dict_index_t* index;
580 ulint* offsets;
581 btr_search_t* info;
582-
583-#ifdef UNIV_SYNC_DEBUG
584- ut_ad(!rw_lock_own(&btr_search_latch, RW_LOCK_SHARED));
585- ut_ad(!rw_lock_own(&btr_search_latch, RW_LOCK_EX));
586-#endif /* UNIV_SYNC_DEBUG */
587-
588+ rw_lock_t* btr_search_latch;
589+
590+retry:
591 /* Do a dirty check on block->index, return if the block is
592 not in the adaptive hash index. This is to avoid acquiring
593 shared btr_search_latch for performance consideration. */
594@@ -1092,17 +1143,31 @@
595 return;
596 }
597
598-retry:
599- rw_lock_s_lock(&btr_search_latch);
600+ btr_search_latch = block->btr_search_latch;
601+
602+ if (UNIV_UNLIKELY(!btr_search_latch)) {
603+ return;
604+ }
605+
606+#ifdef UNIV_SYNC_DEBUG
607+ ut_ad(!rw_lock_own(btr_search_latch, RW_LOCK_SHARED));
608+ ut_ad(!rw_lock_own(btr_search_latch, RW_LOCK_EX));
609+#endif /* UNIV_SYNC_DEBUG */
610+
611+ rw_lock_s_lock(btr_search_latch);
612+ if (UNIV_UNLIKELY(btr_search_latch != block->btr_search_latch)) {
613+ rw_lock_s_unlock(btr_search_latch);
614+ goto retry;
615+ }
616+
617 index = block->index;
618-
619- if (UNIV_LIKELY(!index)) {
620-
621- rw_lock_s_unlock(&btr_search_latch);
622-
623+ if (UNIV_UNLIKELY(!index)) {
624+ rw_lock_s_unlock(btr_search_latch);
625 return;
626 }
627
628+ ut_ad(btr_search_latch == btr_search_get_latch(index->id));
629+
630 ut_a(!dict_index_is_ibuf(index));
631 #ifdef UNIV_DEBUG
632 switch (dict_index_get_online_status(index)) {
633@@ -1125,7 +1190,7 @@
634 }
635 #endif /* UNIV_DEBUG */
636
637- table = btr_search_sys->hash_index;
638+ table = btr_search_get_hash_index(index->id);
639
640 #ifdef UNIV_SYNC_DEBUG
641 ut_ad(rw_lock_own(&(block->lock), RW_LOCK_SHARED)
642@@ -1141,7 +1206,7 @@
643 releasing btr_search_latch, as the index page might only
644 be s-latched! */
645
646- rw_lock_s_unlock(&btr_search_latch);
647+ rw_lock_s_unlock(btr_search_latch);
648
649 ut_a(n_fields + n_bytes > 0);
650
651@@ -1192,7 +1257,7 @@
652 mem_heap_free(heap);
653 }
654
655- rw_lock_x_lock(&btr_search_latch);
656+ rw_lock_x_lock(btr_search_get_latch(index->id));
657
658 if (UNIV_UNLIKELY(!block->index)) {
659 /* Someone else has meanwhile dropped the hash index */
660@@ -1208,7 +1273,7 @@
661 /* Someone else has meanwhile built a new hash index on the
662 page, with different parameters */
663
664- rw_lock_x_unlock(&btr_search_latch);
665+ rw_lock_x_unlock(btr_search_get_latch(index->id));
666
667 mem_free(folds);
668 goto retry;
669@@ -1224,6 +1289,7 @@
670 info->ref_count--;
671
672 block->index = NULL;
673+ block->btr_search_latch = NULL;
674
675 MONITOR_INC(MONITOR_ADAPTIVE_HASH_PAGE_REMOVED);
676 MONITOR_INC_VALUE(MONITOR_ADAPTIVE_HASH_ROW_REMOVED, n_cached);
677@@ -1239,14 +1305,14 @@
678 "InnoDB: the hash index to a page of %s,"
679 " still %lu hash nodes remain.\n",
680 index->name, (ulong) block->n_pointers);
681- rw_lock_x_unlock(&btr_search_latch);
682+ rw_lock_x_unlock(btr_search_get_latch(index->id));
683
684 ut_ad(btr_search_validate());
685 } else {
686- rw_lock_x_unlock(&btr_search_latch);
687+ rw_lock_x_unlock(btr_search_get_latch(index->id));
688 }
689 #else /* UNIV_AHI_DEBUG || UNIV_DEBUG */
690- rw_lock_x_unlock(&btr_search_latch);
691+ rw_lock_x_unlock(btr_search_get_latch(index->id));
692 #endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */
693
694 mem_free(folds);
695@@ -1325,30 +1391,30 @@
696 ut_a(!dict_index_is_ibuf(index));
697
698 #ifdef UNIV_SYNC_DEBUG
699- ut_ad(!rw_lock_own(&btr_search_latch, RW_LOCK_EX));
700+ ut_ad(!rw_lock_own(btr_search_get_latch(index->id), RW_LOCK_EX));
701 ut_ad(rw_lock_own(&(block->lock), RW_LOCK_SHARED)
702 || rw_lock_own(&(block->lock), RW_LOCK_EX));
703 #endif /* UNIV_SYNC_DEBUG */
704
705- rw_lock_s_lock(&btr_search_latch);
706+ rw_lock_s_lock(btr_search_get_latch(index->id));
707
708 if (!btr_search_enabled) {
709- rw_lock_s_unlock(&btr_search_latch);
710+ rw_lock_s_unlock(btr_search_get_latch(index->id));
711 return;
712 }
713
714- table = btr_search_sys->hash_index;
715+ table = btr_search_get_hash_index(index->id);
716 page = buf_block_get_frame(block);
717
718 if (block->index && ((block->curr_n_fields != n_fields)
719 || (block->curr_n_bytes != n_bytes)
720 || (block->curr_left_side != left_side))) {
721
722- rw_lock_s_unlock(&btr_search_latch);
723+ rw_lock_s_unlock(btr_search_get_latch(index->id));
724
725 btr_search_drop_page_hash_index(block);
726 } else {
727- rw_lock_s_unlock(&btr_search_latch);
728+ rw_lock_s_unlock(btr_search_get_latch(index->id));
729 }
730
731 n_recs = page_get_n_recs(page);
732@@ -1442,9 +1508,9 @@
733 fold = next_fold;
734 }
735
736- btr_search_check_free_space_in_heap();
737+ btr_search_check_free_space_in_heap(index->id);
738
739- rw_lock_x_lock(&btr_search_latch);
740+ rw_lock_x_lock(btr_search_get_latch(index->id));
741
742 if (UNIV_UNLIKELY(!btr_search_enabled)) {
743 goto exit_func;
744@@ -1471,6 +1537,7 @@
745 block->curr_n_bytes = n_bytes;
746 block->curr_left_side = left_side;
747 block->index = index;
748+ block->btr_search_latch = btr_search_get_latch(index->id);
749
750 for (i = 0; i < n_cached; i++) {
751
752@@ -1480,7 +1547,7 @@
753 MONITOR_INC(MONITOR_ADAPTIVE_HASH_PAGE_ADDED);
754 MONITOR_INC_VALUE(MONITOR_ADAPTIVE_HASH_ROW_ADDED, n_cached);
755 exit_func:
756- rw_lock_x_unlock(&btr_search_latch);
757+ rw_lock_x_unlock(btr_search_get_latch(index->id));
758
759 mem_free(folds);
760 mem_free(recs);
761@@ -1515,7 +1582,7 @@
762 ut_ad(rw_lock_own(&(new_block->lock), RW_LOCK_EX));
763 #endif /* UNIV_SYNC_DEBUG */
764
765- rw_lock_s_lock(&btr_search_latch);
766+ rw_lock_s_lock(btr_search_get_latch(index->id));
767
768 ut_a(!new_block->index || new_block->index == index);
769 ut_a(!block->index || block->index == index);
770@@ -1524,7 +1591,7 @@
771
772 if (new_block->index) {
773
774- rw_lock_s_unlock(&btr_search_latch);
775+ rw_lock_s_unlock(btr_search_get_latch(index->id));
776
777 btr_search_drop_page_hash_index(block);
778
779@@ -1541,7 +1608,7 @@
780 new_block->n_bytes = block->curr_n_bytes;
781 new_block->left_side = left_side;
782
783- rw_lock_s_unlock(&btr_search_latch);
784+ rw_lock_s_unlock(btr_search_get_latch(index->id));
785
786 ut_a(n_fields + n_bytes > 0);
787
788@@ -1553,7 +1620,7 @@
789 return;
790 }
791
792- rw_lock_s_unlock(&btr_search_latch);
793+ rw_lock_s_unlock(btr_search_get_latch(index->id));
794 }
795
796 /********************************************************************//**
797@@ -1592,7 +1659,7 @@
798 ut_a(block->curr_n_fields + block->curr_n_bytes > 0);
799 ut_a(!dict_index_is_ibuf(index));
800
801- table = btr_search_sys->hash_index;
802+ table = btr_search_get_hash_index(cursor->index->id);
803
804 rec = btr_cur_get_rec(cursor);
805
806@@ -1603,7 +1670,7 @@
807 mem_heap_free(heap);
808 }
809
810- rw_lock_x_lock(&btr_search_latch);
811+ rw_lock_x_lock(btr_search_get_latch(cursor->index->id));
812
813 if (block->index) {
814 ut_a(block->index == index);
815@@ -1616,7 +1683,7 @@
816 }
817 }
818
819- rw_lock_x_unlock(&btr_search_latch);
820+ rw_lock_x_unlock(btr_search_get_latch(cursor->index->id));
821 }
822
823 /********************************************************************//**
824@@ -1653,7 +1720,7 @@
825 ut_a(cursor->index == index);
826 ut_a(!dict_index_is_ibuf(index));
827
828- rw_lock_x_lock(&btr_search_latch);
829+ rw_lock_x_lock(btr_search_get_latch(cursor->index->id));
830
831 if (!block->index) {
832
833@@ -1667,7 +1734,7 @@
834 && (cursor->n_bytes == block->curr_n_bytes)
835 && !block->curr_left_side) {
836
837- table = btr_search_sys->hash_index;
838+ table = btr_search_get_hash_index(cursor->index->id);
839
840 if (ha_search_and_update_if_found(
841 table, cursor->fold, rec, block,
842@@ -1676,9 +1743,9 @@
843 }
844
845 func_exit:
846- rw_lock_x_unlock(&btr_search_latch);
847+ rw_lock_x_unlock(btr_search_get_latch(cursor->index->id));
848 } else {
849- rw_lock_x_unlock(&btr_search_latch);
850+ rw_lock_x_unlock(btr_search_get_latch(cursor->index->id));
851
852 btr_search_update_hash_on_insert(cursor);
853 }
854@@ -1726,9 +1793,9 @@
855 return;
856 }
857
858- btr_search_check_free_space_in_heap();
859+ btr_search_check_free_space_in_heap(cursor->index->id);
860
861- table = btr_search_sys->hash_index;
862+ table = btr_search_get_hash_index(cursor->index->id);
863
864 rec = btr_cur_get_rec(cursor);
865
866@@ -1760,7 +1827,7 @@
867 } else {
868 if (left_side) {
869
870- rw_lock_x_lock(&btr_search_latch);
871+ rw_lock_x_lock(btr_search_get_latch(index->id));
872
873 locked = TRUE;
874
875@@ -1778,7 +1845,7 @@
876
877 if (!locked) {
878
879- rw_lock_x_lock(&btr_search_latch);
880+ rw_lock_x_lock(btr_search_get_latch(index->id));
881
882 locked = TRUE;
883
884@@ -1800,7 +1867,8 @@
885 if (!left_side) {
886
887 if (!locked) {
888- rw_lock_x_lock(&btr_search_latch);
889+ rw_lock_x_lock(btr_search_get_latch(
890+ index->id));
891
892 locked = TRUE;
893
894@@ -1819,7 +1887,7 @@
895
896 if (!locked) {
897
898- rw_lock_x_lock(&btr_search_latch);
899+ rw_lock_x_lock(btr_search_get_latch(index->id));
900
901 locked = TRUE;
902
903@@ -1846,18 +1914,19 @@
904 mem_heap_free(heap);
905 }
906 if (locked) {
907- rw_lock_x_unlock(&btr_search_latch);
908+ rw_lock_x_unlock(btr_search_get_latch(index->id));
909 }
910 }
911
912 #if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG
913 /********************************************************************//**
914-Validates the search system.
915+Validates one hash table in the search system.
916 @return TRUE if ok */
917-UNIV_INTERN
918+static
919 ibool
920-btr_search_validate(void)
921-/*=====================*/
922+btr_search_validate_one_table(
923+/*==========================*/
924+ ulint t)
925 {
926 ha_node_t* node;
927 ulint n_page_dumps = 0;
928@@ -1874,24 +1943,24 @@
929
930 rec_offs_init(offsets_);
931
932- rw_lock_x_lock(&btr_search_latch);
933 buf_pool_mutex_enter_all();
934
935- cell_count = hash_get_n_cells(btr_search_sys->hash_index);
936+ cell_count = hash_get_n_cells(btr_search_sys->hash_index[t]);
937
938 for (i = 0; i < cell_count; i++) {
939 /* We release btr_search_latch every once in a while to
940 give other queries a chance to run. */
941 if ((i != 0) && ((i % chunk_size) == 0)) {
942 buf_pool_mutex_exit_all();
943- rw_lock_x_unlock(&btr_search_latch);
944+ btr_search_x_unlock_all();
945 os_thread_yield();
946- rw_lock_x_lock(&btr_search_latch);
947+ btr_search_x_lock_all();
948 buf_pool_mutex_enter_all();
949 }
950
951 node = (ha_node_t*)
952- hash_get_nth_cell(btr_search_sys->hash_index, i)->node;
953+ hash_get_nth_cell(btr_search_sys->hash_index[t],
954+ i)->node;
955
956 for (; node != NULL; node = node->next) {
957 const buf_block_t* block
958@@ -2000,23 +2069,49 @@
959 give other queries a chance to run. */
960 if (i != 0) {
961 buf_pool_mutex_exit_all();
962- rw_lock_x_unlock(&btr_search_latch);
963+ btr_search_x_unlock_all();
964 os_thread_yield();
965- rw_lock_x_lock(&btr_search_latch);
966+ btr_search_x_lock_all();
967 buf_pool_mutex_enter_all();
968 }
969
970- if (!ha_validate(btr_search_sys->hash_index, i, end_index)) {
971+ if (!ha_validate(btr_search_sys->hash_index[t], i,
972+ end_index)) {
973 ok = FALSE;
974 }
975 }
976
977 buf_pool_mutex_exit_all();
978- rw_lock_x_unlock(&btr_search_latch);
979 if (UNIV_LIKELY_NULL(heap)) {
980 mem_heap_free(heap);
981 }
982
983 return(ok);
984 }
985+
986+/********************************************************************//**
987+Validates the search system.
988+@return TRUE if ok */
989+UNIV_INTERN
990+ibool
991+btr_search_validate(void)
992+/*=====================*/
993+{
994+ ulint i;
995+ ibool ok = TRUE;
996+
997+ btr_search_x_lock_all();
998+
999+ for (i = 0; i < btr_search_index_num; i++) {
1000+
1001+ if (!btr_search_validate_one_table(i))
1002+ ok = FALSE;
1003+ }
1004+
1005+ btr_search_x_unlock_all();
1006+
1007+ return(ok);
1008+}
1009+
1010+
1011 #endif /* defined UNIV_AHI_DEBUG || defined UNIV_DEBUG */
1012
1013=== modified file 'Percona-Server/storage/innobase/buf/buf0buf.cc'
1014--- Percona-Server/storage/innobase/buf/buf0buf.cc 2013-08-26 15:36:54 +0000
1015+++ Percona-Server/storage/innobase/buf/buf0buf.cc 2013-08-29 17:11:28 +0000
1016@@ -1013,6 +1013,7 @@
1017
1018 block->check_index_page_at_flush = FALSE;
1019 block->index = NULL;
1020+ block->btr_search_latch = NULL;
1021
1022 #ifdef UNIV_DEBUG
1023 block->page.in_page_hash = FALSE;
1024@@ -1484,7 +1485,7 @@
1025 ulint p;
1026
1027 #ifdef UNIV_SYNC_DEBUG
1028- ut_ad(rw_lock_own(&btr_search_latch, RW_LOCK_EX));
1029+ ut_ad(btr_search_own_all(RW_LOCK_EX));
1030 #endif /* UNIV_SYNC_DEBUG */
1031 ut_ad(!btr_search_enabled);
1032
1033@@ -2208,6 +2209,7 @@
1034 {
1035 block->check_index_page_at_flush = FALSE;
1036 block->index = NULL;
1037+ block->btr_search_latch = NULL;
1038
1039 block->n_hash_helps = 0;
1040 block->n_fields = 1;
1041
1042=== modified file 'Percona-Server/storage/innobase/dict/dict0dict.cc'
1043--- Percona-Server/storage/innobase/dict/dict0dict.cc 2013-08-14 03:57:21 +0000
1044+++ Percona-Server/storage/innobase/dict/dict0dict.cc 2013-08-29 17:11:28 +0000
1045@@ -1208,7 +1208,8 @@
1046
1047 See also: dict_index_remove_from_cache_low() */
1048
1049- if (btr_search_info_get_ref_count(info) > 0) {
1050+ if (btr_search_info_get_ref_count(info, index->id)
1051+ > 0) {
1052 return(FALSE);
1053 }
1054 }
1055@@ -2483,7 +2484,8 @@
1056 zero. See also: dict_table_can_be_evicted() */
1057
1058 do {
1059- ulint ref_count = btr_search_info_get_ref_count(info);
1060+ ulint ref_count = btr_search_info_get_ref_count(info,
1061+ index->id);
1062
1063 if (ref_count == 0) {
1064 break;
1065
1066=== modified file 'Percona-Server/storage/innobase/ha/ha0ha.cc'
1067--- Percona-Server/storage/innobase/ha/ha0ha.cc 2013-08-06 15:16:34 +0000
1068+++ Percona-Server/storage/innobase/ha/ha0ha.cc 2013-08-29 17:11:28 +0000
1069@@ -98,6 +98,33 @@
1070 return(table);
1071 }
1072
1073+#ifdef UNIV_SYNC_DEBUG
1074+/*************************************************************//**
1075+Verifies that the specified hash table is a part of adaptive hash index and
1076+that its corresponding latch is X-latched by the current thread. */
1077+static
1078+bool
1079+ha_assert_btr_x_locked(
1080+/*===================*/
1081+ const hash_table_t* table) /*!<in: hash table to check */
1082+{
1083+ ulint i;
1084+
1085+ ut_ad(table->adaptive);
1086+
1087+ for (i = 0; i < btr_search_index_num; i++) {
1088+ if (btr_search_sys->hash_index[i] == table) {
1089+ break;
1090+ }
1091+ }
1092+
1093+ ut_ad(i < btr_search_index_num);
1094+ ut_ad(rw_lock_own(btr_search_latch_arr[i], RW_LOCK_EX));
1095+
1096+ return(true);
1097+}
1098+#endif /* UNIV_SYNC_DEBUG */
1099+
1100 /*************************************************************//**
1101 Empties a hash table and frees the memory heaps. */
1102 UNIV_INTERN
1103@@ -112,8 +139,7 @@
1104 ut_ad(table);
1105 ut_ad(table->magic_n == HASH_TABLE_MAGIC_N);
1106 #ifdef UNIV_SYNC_DEBUG
1107- ut_ad(!table->adaptive
1108- || rw_lock_own(&btr_search_latch, RW_LOCK_EXCLUSIVE));
1109+ ut_ad(!table->adaptive || ha_assert_btr_x_locked(table));
1110 #endif /* UNIV_SYNC_DEBUG */
1111
1112 /* Free the memory heaps. */
1113@@ -274,7 +300,7 @@
1114 ut_ad(table);
1115 ut_ad(table->magic_n == HASH_TABLE_MAGIC_N);
1116 #ifdef UNIV_SYNC_DEBUG
1117- ut_ad(rw_lock_own(&btr_search_latch, RW_LOCK_EX));
1118+ ut_ad(ha_assert_btr_x_locked(table));
1119 #endif /* UNIV_SYNC_DEBUG */
1120 ut_ad(btr_search_enabled);
1121 #if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG
1122@@ -313,7 +339,7 @@
1123 ut_a(new_block->frame == page_align(new_data));
1124 #endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */
1125 #ifdef UNIV_SYNC_DEBUG
1126- ut_ad(rw_lock_own(&btr_search_latch, RW_LOCK_EX));
1127+ ut_ad(ha_assert_btr_x_locked(table));
1128 #endif /* UNIV_SYNC_DEBUG */
1129
1130 if (!btr_search_enabled) {
1131
1132=== modified file 'Percona-Server/storage/innobase/handler/ha_innodb.cc'
1133--- Percona-Server/storage/innobase/handler/ha_innodb.cc 2013-08-22 13:38:28 +0000
1134+++ Percona-Server/storage/innobase/handler/ha_innodb.cc 2013-08-29 17:11:28 +0000
1135@@ -16398,6 +16398,12 @@
1136 "Disable with --skip-innodb-adaptive-hash-index.",
1137 NULL, innodb_adaptive_hash_index_update, TRUE);
1138
1139+static MYSQL_SYSVAR_ULONG(adaptive_hash_index_partitions, btr_search_index_num,
1140+ PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
1141+ "Number of InnoDB adaptive hash index partitions (default 1: disable "
1142+ "partitioning)",
1143+ NULL, NULL, 1, 1, sizeof(ulint) * 8, 0);
1144+
1145 static MYSQL_SYSVAR_ULONG(replication_delay, srv_replication_delay,
1146 PLUGIN_VAR_RQCMDARG,
1147 "Replication thread delay (ms) on the slave server if "
1148@@ -17057,6 +17063,7 @@
1149 MYSQL_SYSVAR(stats_persistent_sample_pages),
1150 MYSQL_SYSVAR(stats_auto_recalc),
1151 MYSQL_SYSVAR(adaptive_hash_index),
1152+ MYSQL_SYSVAR(adaptive_hash_index_partitions),
1153 MYSQL_SYSVAR(stats_method),
1154 MYSQL_SYSVAR(replication_delay),
1155 MYSQL_SYSVAR(status_file),
1156
1157=== modified file 'Percona-Server/storage/innobase/handler/xtradb_i_s.cc'
1158--- Percona-Server/storage/innobase/handler/xtradb_i_s.cc 2012-09-11 06:54:10 +0000
1159+++ Percona-Server/storage/innobase/handler/xtradb_i_s.cc 2013-08-29 17:11:28 +0000
1160@@ -329,34 +329,34 @@
1161
1162 if (btr_search_sys)
1163 {
1164- ulint btr_search_sys_subtotal= 0;
1165-
1166- rw_lock_s_lock(&btr_search_latch);
1167- if (btr_search_sys->hash_index->heap) {
1168- btr_search_sys_subtotal = mem_heap_get_size(btr_search_sys->hash_index->heap);
1169- } else {
1170- btr_search_sys_subtotal = 0;
1171- for (unsigned int i=0;
1172- i < btr_search_sys->hash_index->n_sync_obj;
1173- i++) {
1174- btr_search_sys_subtotal += mem_heap_get_size(btr_search_sys->hash_index->heaps[i]);
1175- }
1176- }
1177- rw_lock_s_unlock(&btr_search_latch);
1178-
1179- OK(field_store_string(fields[INT_HASH_TABLES_NAME],
1180- "Adaptive hash index"));
1181- OK(field_store_ulint(fields[INT_HASH_TABLES_TOTAL],
1182- btr_search_sys_subtotal
1183- + (btr_search_sys->hash_index->n_cells
1184- * sizeof(hash_cell_t))));
1185- OK(field_store_ulint(fields[INT_HASH_TABLES_CONSTANT],
1186- (btr_search_sys->hash_index->n_cells
1187- * sizeof(hash_cell_t))));
1188- OK(field_store_ulint(fields[INT_HASH_TABLES_VARIABLE],
1189- btr_search_sys_subtotal));
1190- OK(schema_table_store_record(thd, table));
1191-
1192+ ulint btr_search_sys_subtotal;
1193+ const hash_table_t* hash_index_0
1194+ = btr_search_sys->hash_index[0];
1195+
1196+ if (hash_index_0->heap) {
1197+ btr_search_sys_subtotal
1198+ = mem_heap_get_size(hash_index_0->heap);
1199+ } else {
1200+ for (ulint i = 0; i < hash_index_0->n_sync_obj; i++) {
1201+ btr_search_sys_subtotal
1202+ += mem_heap_get_size(hash_index_0
1203+ ->heaps[i]);
1204+ }
1205+ }
1206+ btr_search_sys_subtotal *= btr_search_index_num;
1207+
1208+ OK(field_store_string(fields[INT_HASH_TABLES_NAME],
1209+ "Adaptive hash index"));
1210+ OK(field_store_ulint(fields[INT_HASH_TABLES_TOTAL],
1211+ btr_search_sys_subtotal
1212+ + (hash_index_0->n_cells
1213+ * sizeof(hash_cell_t))));
1214+ OK(field_store_ulint(fields[INT_HASH_TABLES_CONSTANT],
1215+ (hash_index_0->n_cells
1216+ * sizeof(hash_cell_t))));
1217+ OK(field_store_ulint(fields[INT_HASH_TABLES_VARIABLE],
1218+ btr_search_sys_subtotal));
1219+ OK(schema_table_store_record(thd, table));
1220 }
1221
1222 {
1223
1224=== modified file 'Percona-Server/storage/innobase/include/btr0sea.h'
1225--- Percona-Server/storage/innobase/include/btr0sea.h 2013-08-06 15:16:34 +0000
1226+++ Percona-Server/storage/innobase/include/btr0sea.h 2013-08-29 17:11:28 +0000
1227@@ -86,7 +86,8 @@
1228 ulint
1229 btr_search_info_get_ref_count(
1230 /*==========================*/
1231- btr_search_t* info); /*!< in: search info. */
1232+ btr_search_t* info, /*!< in: search info. */
1233+ index_id_t key); /*!< in: id of the index owning search info */
1234 /*********************************************************************//**
1235 Updates the search info. */
1236 UNIV_INLINE
1237@@ -193,6 +194,55 @@
1238 # define btr_search_validate() TRUE
1239 #endif /* defined UNIV_AHI_DEBUG || defined UNIV_DEBUG */
1240
1241+/********************************************************************//**
1242+Returns the adaptive hash index table for a given index key.
1243+@return the adaptive hash index table for a given index key */
1244+UNIV_INLINE
1245+hash_table_t*
1246+btr_search_get_hash_index(
1247+/*======================*/
1248+ index_id_t key) /*!< in: index key */
1249+ __attribute__((pure,warn_unused_result));
1250+
1251+/********************************************************************//**
1252+Returns the adaptive hash index latch for a given index key.
1253+@return the adaptive hash index latch for a given index key */
1254+UNIV_INLINE
1255+rw_lock_t*
1256+btr_search_get_latch(
1257+/*=================*/
1258+ index_id_t key) /*!< in: index key */
1259+ __attribute__((pure,warn_unused_result));
1260+
1261+/********************************************************************//**
1262+Latches all adaptive hash index latches in exclusive mode. */
1263+UNIV_INLINE
1264+void
1265+btr_search_x_lock_all(void);
1266+/*========================*/
1267+
1268+/********************************************************************//**
1269+Unlatches all adaptive hash index latches in exclusive mode. */
1270+UNIV_INLINE
1271+void
1272+btr_search_x_unlock_all(void);
1273+/*==========================*/
1274+
1275+#ifdef UNIV_SYNC_DEBUG
1276+/******************************************************************//**
1277+Checks if the thread has locked all the adaptive hash index latches in the
1278+specified mode.
1279+
1280+@return true if all latches are locked by the current thread, false
1281+otherwise. */
1282+UNIV_INLINE
1283+bool
1284+btr_search_own_all(
1285+/*===============*/
1286+ ulint lock_type)
1287+ __attribute__((warn_unused_result));
1288+#endif /* UNIV_SYNC_DEBUG */
1289+
1290 /** The search info struct in an index */
1291 struct btr_search_t{
1292 ulint ref_count; /*!< Number of blocks in this index tree
1293@@ -250,7 +300,7 @@
1294
1295 /** The hash index system */
1296 struct btr_search_sys_t{
1297- hash_table_t* hash_index; /*!< the adaptive hash index,
1298+ hash_table_t** hash_index; /*!< the adaptive hash index,
1299 mapping dtuple_fold values
1300 to rec_t pointers on index pages */
1301 };
1302
1303=== modified file 'Percona-Server/storage/innobase/include/btr0sea.ic'
1304--- Percona-Server/storage/innobase/include/btr0sea.ic 2013-08-06 15:16:34 +0000
1305+++ Percona-Server/storage/innobase/include/btr0sea.ic 2013-08-29 17:11:28 +0000
1306@@ -60,8 +60,8 @@
1307 btr_search_t* info;
1308
1309 #ifdef UNIV_SYNC_DEBUG
1310- ut_ad(!rw_lock_own(&btr_search_latch, RW_LOCK_SHARED));
1311- ut_ad(!rw_lock_own(&btr_search_latch, RW_LOCK_EX));
1312+ ut_ad(!rw_lock_own(btr_search_get_latch(index->id), RW_LOCK_SHARED));
1313+ ut_ad(!rw_lock_own(btr_search_get_latch(index->id), RW_LOCK_EX));
1314 #endif /* UNIV_SYNC_DEBUG */
1315
1316 info = btr_search_get_info(index);
1317@@ -80,3 +80,80 @@
1318
1319 btr_search_info_update_slow(info, cursor);
1320 }
1321+
1322+/********************************************************************//**
1323+Returns the adaptive hash index table for a given index key.
1324+@return the adaptive hash index table for a given index key */
1325+UNIV_INLINE
1326+hash_table_t*
1327+btr_search_get_hash_index(
1328+/*======================*/
1329+ index_id_t key) /*!< in: index key */
1330+{
1331+ return(btr_search_sys->hash_index[key % btr_search_index_num]);
1332+}
1333+
1334+/********************************************************************//**
1335+Returns the adaptive hash index latch for a given index key.
1336+@return the adaptive hash index latch for a given index key */
1337+UNIV_INLINE
1338+rw_lock_t*
1339+btr_search_get_latch(
1340+/*=================*/
1341+ index_id_t key) /*!< in: index key */
1342+{
1343+ return(btr_search_latch_arr[key % btr_search_index_num]);
1344+}
1345+
1346+/********************************************************************//**
1347+Latches all adaptive hash index latches in exclusive mode. */
1348+UNIV_INLINE
1349+void
1350+btr_search_x_lock_all(void)
1351+/*=======================*/
1352+{
1353+ ulint i;
1354+
1355+ for (i = 0; i < btr_search_index_num; i++) {
1356+ rw_lock_x_lock(btr_search_latch_arr[i]);
1357+ }
1358+}
1359+
1360+/********************************************************************//**
1361+Unlatches all adaptive hash index latches in exclusive mode. */
1362+UNIV_INLINE
1363+void
1364+btr_search_x_unlock_all(void)
1365+/*==========================*/
1366+{
1367+ ulint i;
1368+
1369+ for (i = 0; i < btr_search_index_num; i++) {
1370+ rw_lock_x_unlock(btr_search_latch_arr[i]);
1371+ }
1372+}
1373+
1374+#ifdef UNIV_SYNC_DEBUG
1375+/******************************************************************//**
1376+Checks if the thread has locked all the adaptive hash index latches in the
1377+specified mode.
1378+
1379+@return true if all latches are locked by the current thread, false
1380+otherwise. */
1381+UNIV_INLINE
1382+bool
1383+btr_search_own_all(
1384+/*===============*/
1385+ ulint lock_type)
1386+{
1387+ ulint i;
1388+
1389+ for (i = 0; i < btr_search_index_num; i++) {
1390+ if (!rw_lock_own(btr_search_latch_arr[i], lock_type)) {
1391+ return(false);
1392+ }
1393+ }
1394+
1395+ return(true);
1396+}
1397+#endif /* UNIV_SYNC_DEBUG */
1398
1399=== modified file 'Percona-Server/storage/innobase/include/btr0types.h'
1400--- Percona-Server/storage/innobase/include/btr0types.h 2013-08-06 15:16:34 +0000
1401+++ Percona-Server/storage/innobase/include/btr0types.h 2013-08-29 17:11:28 +0000
1402@@ -54,17 +54,17 @@
1403
1404 Bear in mind (3) and (4) when using the hash index.
1405 */
1406-extern rw_lock_t* btr_search_latch_temp;
1407+extern rw_lock_t** btr_search_latch_arr;
1408
1409 #endif /* UNIV_HOTBACKUP */
1410
1411-/** The latch protecting the adaptive search system */
1412-#define btr_search_latch (*btr_search_latch_temp)
1413-
1414 /** Flag: has the search system been enabled?
1415 Protected by btr_search_latch. */
1416 extern char btr_search_enabled;
1417
1418+/** Number of adaptive hash index partitions */
1419+extern ulint btr_search_index_num;
1420+
1421 #ifdef UNIV_BLOB_DEBUG
1422 # include "buf0types.h"
1423 /** An index->blobs entry for keeping track of off-page column references */
1424
1425=== modified file 'Percona-Server/storage/innobase/include/buf0buf.h'
1426--- Percona-Server/storage/innobase/include/buf0buf.h 2013-08-26 15:36:54 +0000
1427+++ Percona-Server/storage/innobase/include/buf0buf.h 2013-08-29 17:11:28 +0000
1428@@ -1700,6 +1700,8 @@
1429 complete, though: there may
1430 have been hash collisions,
1431 record deletions, etc. */
1432+ rw_lock_t* btr_search_latch;/*!< Adaptive hash index latch for the
1433+ index this block belongs to or NULL */
1434 /* @} */
1435 # ifdef UNIV_SYNC_DEBUG
1436 /** @name Debug fields */
1437
1438=== modified file 'Percona-Server/storage/innobase/include/mtr0log.ic'
1439--- Percona-Server/storage/innobase/include/mtr0log.ic 2013-08-06 15:16:34 +0000
1440+++ Percona-Server/storage/innobase/include/mtr0log.ic 2013-08-29 17:11:28 +0000
1441@@ -28,6 +28,7 @@
1442 #include "buf0buf.h"
1443 #include "buf0dblwr.h"
1444 #include "fsp0types.h"
1445+#include "btr0types.h"
1446 #include "trx0sys.h"
1447
1448 /********************************************************//**
1449
1450=== modified file 'Percona-Server/storage/innobase/include/que0que.h'
1451--- Percona-Server/storage/innobase/include/que0que.h 2013-08-06 15:16:34 +0000
1452+++ Percona-Server/storage/innobase/include/que0que.h 2013-08-29 17:11:28 +0000
1453@@ -29,6 +29,7 @@
1454 #include "univ.i"
1455 #include "data0data.h"
1456 #include "dict0types.h"
1457+#include "btr0sea.h"
1458 #include "trx0trx.h"
1459 #include "trx0roll.h"
1460 #include "srv0srv.h"
1461
1462=== modified file 'Percona-Server/storage/innobase/include/read0read.h'
1463--- Percona-Server/storage/innobase/include/read0read.h 2013-08-06 15:16:34 +0000
1464+++ Percona-Server/storage/innobase/include/read0read.h 2013-08-29 17:11:28 +0000
1465@@ -31,6 +31,7 @@
1466
1467 #include "ut0byte.h"
1468 #include "ut0lst.h"
1469+#include "btr0types.h"
1470 #include "trx0trx.h"
1471 #include "trx0sys.h"
1472 #include "read0types.h"
1473
1474=== modified file 'Percona-Server/storage/innobase/include/trx0roll.h'
1475--- Percona-Server/storage/innobase/include/trx0roll.h 2013-08-06 15:16:34 +0000
1476+++ Percona-Server/storage/innobase/include/trx0roll.h 2013-08-29 17:11:28 +0000
1477@@ -27,6 +27,7 @@
1478 #define trx0roll_h
1479
1480 #include "univ.i"
1481+#include "btr0types.h"
1482 #include "trx0trx.h"
1483 #include "trx0types.h"
1484 #include "mtr0mtr.h"
1485
1486=== modified file 'Percona-Server/storage/innobase/include/trx0trx.h'
1487--- Percona-Server/storage/innobase/include/trx0trx.h 2013-08-06 15:16:34 +0000
1488+++ Percona-Server/storage/innobase/include/trx0trx.h 2013-08-29 17:11:28 +0000
1489@@ -1136,10 +1136,7 @@
1490
1491 Bear in mind (3) and (4) when using the hash index.
1492 */
1493-extern rw_lock_t* btr_search_latch_temp;
1494-
1495-/** The latch protecting the adaptive search system */
1496-#define btr_search_latch (*btr_search_latch_temp)
1497+extern rw_lock_t** btr_search_latch_arr;
1498
1499 #ifndef UNIV_NONINL
1500 #include "trx0trx.ic"
1501
1502=== modified file 'Percona-Server/storage/innobase/include/trx0trx.ic'
1503--- Percona-Server/storage/innobase/include/trx0trx.ic 2013-08-06 15:16:34 +0000
1504+++ Percona-Server/storage/innobase/include/trx0trx.ic 2013-08-29 17:11:28 +0000
1505@@ -164,17 +164,21 @@
1506 }
1507
1508 /********************************************************************//**
1509-Releases the search latch if trx has reserved it. */
1510+Releases the search latches if trx has reserved them. */
1511 UNIV_INLINE
1512 void
1513 trx_search_latch_release_if_reserved(
1514 /*=================================*/
1515 trx_t* trx) /*!< in: transaction */
1516 {
1517- if (trx->has_search_latch) {
1518- rw_lock_s_unlock(&btr_search_latch);
1519+ ulint i;
1520
1521- trx->has_search_latch = FALSE;
1522+ for (i = 0; i < btr_search_index_num; i++) {
1523+ if (trx->has_search_latch & (1UL << i)) {
1524+ rw_lock_s_unlock(btr_search_latch_arr[i]);
1525+ }
1526 }
1527+
1528+ trx->has_search_latch = 0;
1529 }
1530
1531
1532=== modified file 'Percona-Server/storage/innobase/include/univ.i'
1533--- Percona-Server/storage/innobase/include/univ.i 2013-08-06 15:16:34 +0000
1534+++ Percona-Server/storage/innobase/include/univ.i 2013-08-29 17:11:28 +0000
1535@@ -179,7 +179,6 @@
1536 #define UNIV_COMPILE_TEST_FUNCS
1537 */
1538
1539-#undef UNIV_SYNC_DEBUG
1540 #if defined HAVE_VALGRIND
1541 # define UNIV_DEBUG_VALGRIND
1542 #endif /* HAVE_VALGRIND */
1543
1544=== modified file 'Percona-Server/storage/innobase/os/os0file.cc'
1545--- Percona-Server/storage/innobase/os/os0file.cc 2013-08-21 07:19:25 +0000
1546+++ Percona-Server/storage/innobase/os/os0file.cc 2013-08-29 17:11:28 +0000
1547@@ -43,6 +43,7 @@
1548 #include "srv0start.h"
1549 #include "fil0fil.h"
1550 #include "buf0buf.h"
1551+#include "btr0types.h"
1552 #include "trx0trx.h"
1553 #include "srv0mon.h"
1554 #ifndef UNIV_HOTBACKUP
1555
1556=== modified file 'Percona-Server/storage/innobase/row/row0sel.cc'
1557--- Percona-Server/storage/innobase/row/row0sel.cc 2013-08-14 03:57:21 +0000
1558+++ Percona-Server/storage/innobase/row/row0sel.cc 2013-08-29 17:11:28 +0000
1559@@ -1233,7 +1233,8 @@
1560 ut_ad(!plan->must_get_clust);
1561 #ifdef UNIV_SYNC_DEBUG
1562 if (search_latch_locked) {
1563- ut_ad(rw_lock_own(&btr_search_latch, RW_LOCK_SHARED));
1564+ ut_ad(rw_lock_own(btr_search_get_latch(index->id),
1565+ RW_LOCK_SHARED));
1566 }
1567 #endif /* UNIV_SYNC_DEBUG */
1568
1569@@ -1405,10 +1406,11 @@
1570 && !plan->must_get_clust
1571 && !plan->table->big_rows) {
1572 if (!search_latch_locked) {
1573- rw_lock_s_lock(&btr_search_latch);
1574+ rw_lock_s_lock(btr_search_get_latch(index->id));
1575
1576 search_latch_locked = TRUE;
1577- } else if (rw_lock_get_writer(&btr_search_latch) == RW_LOCK_WAIT_EX) {
1578+ } else if (rw_lock_get_writer(btr_search_get_latch(index->id))
1579+ == RW_LOCK_WAIT_EX) {
1580
1581 /* There is an x-latch request waiting: release the
1582 s-latch for a moment; as an s-latch here is often
1583@@ -1417,8 +1419,8 @@
1584 from acquiring an s-latch for a long time, lowering
1585 performance significantly in multiprocessors. */
1586
1587- rw_lock_s_unlock(&btr_search_latch);
1588- rw_lock_s_lock(&btr_search_latch);
1589+ rw_lock_s_unlock(btr_search_get_latch(index->id));
1590+ rw_lock_s_lock(btr_search_get_latch(index->id));
1591 }
1592
1593 found_flag = row_sel_try_search_shortcut(node, plan,
1594@@ -1443,7 +1445,7 @@
1595 }
1596
1597 if (search_latch_locked) {
1598- rw_lock_s_unlock(&btr_search_latch);
1599+ rw_lock_s_unlock(btr_search_get_latch(index->id));
1600
1601 search_latch_locked = FALSE;
1602 }
1603@@ -2019,7 +2021,7 @@
1604
1605 func_exit:
1606 if (search_latch_locked) {
1607- rw_lock_s_unlock(&btr_search_latch);
1608+ rw_lock_s_unlock(btr_search_get_latch(index->id));
1609 }
1610 if (UNIV_LIKELY_NULL(heap)) {
1611 mem_heap_free(heap);
1612@@ -3597,6 +3599,47 @@
1613 }
1614
1615 /********************************************************************//**
1616+Acquires an S latch for the adaptive hash index for a given index tree if is
1617+not acquired already. If the current transaction already owns a latch with
1618+a higher index in the latch array, release all the already-held S latches
1619+and reacquire them together with the desired latch to honor the latching
1620+order. */
1621+static
1622+void
1623+trx_search_latch_lock(
1624+/*==================*/
1625+ trx_t* trx, /*!< in: latching transcation */
1626+ ulint index_id) /*!< in: index to latch AHI for */
1627+{
1628+ ulint latch_mask = 1UL << (index_id % btr_search_index_num);
1629+
1630+ if (!(trx->has_search_latch & latch_mask)) {
1631+
1632+ if (trx->has_search_latch < latch_mask) {
1633+
1634+ rw_lock_s_lock(btr_search_get_latch(index_id));
1635+ trx->has_search_latch |= latch_mask;
1636+ } else {
1637+
1638+ ulint taken_latches = trx->has_search_latch;
1639+
1640+ trx_search_latch_release_if_reserved(trx);
1641+
1642+ trx->has_search_latch = taken_latches | latch_mask;
1643+
1644+ for (ulint i = 0; i < btr_search_index_num; i++) {
1645+ if (trx->has_search_latch & (1UL << i)) {
1646+
1647+ rw_lock_s_lock(
1648+ btr_search_latch_arr[i]);
1649+ }
1650+ }
1651+ }
1652+ }
1653+}
1654+
1655+
1656+/********************************************************************//**
1657 Searches for rows in the database. This is used in the interface to
1658 MySQL. This function opens a cursor, and also implements fetch next
1659 and fetch prev. NOTE that if we do a search with a full key value
1660@@ -3658,6 +3701,7 @@
1661 ulint* offsets = offsets_;
1662 ibool table_lock_waited = FALSE;
1663 byte* next_buf = 0;
1664+ bool should_release;
1665
1666 rec_offs_init(offsets_);
1667
1668@@ -3733,19 +3777,28 @@
1669 (ulong) trx->mysql_n_tables_locked);
1670 #endif
1671 /*-------------------------------------------------------------*/
1672- /* PHASE 0: Release a possible s-latch we are holding on the
1673- adaptive hash index latch if there is someone waiting behind */
1674-
1675- if (UNIV_UNLIKELY(rw_lock_get_writer(&btr_search_latch) != RW_LOCK_NOT_LOCKED)
1676- && trx->has_search_latch) {
1677+ /* PHASE 0: Release possible latches we are holding on the
1678+ adaptive hash index latches if there is someone waiting behind */
1679+
1680+ should_release = false;
1681+ for (ulint i = 0; i < btr_search_index_num; i++) {
1682+ /* we should check all latches (fix Bug#791030) */
1683+ if (UNIV_UNLIKELY(rw_lock_get_writer(btr_search_latch_arr[i])
1684+ != RW_LOCK_NOT_LOCKED)) {
1685+ should_release = true;
1686+ break;
1687+ }
1688+ }
1689+
1690+ if (UNIV_UNLIKELY(should_release)) {
1691
1692 /* There is an x-latch request on the adaptive hash index:
1693 release the s-latch to reduce starvation and wait for
1694 BTR_SEA_TIMEOUT rounds before trying to keep it again over
1695 calls from MySQL */
1696
1697- rw_lock_s_unlock(&btr_search_latch);
1698- trx->has_search_latch = FALSE;
1699+ /* We should release all s-latches (fix Bug#791030) */
1700+ trx_search_latch_release_if_reserved(trx);
1701
1702 trx->search_latch_timeout = BTR_SEA_TIMEOUT;
1703 }
1704@@ -3896,10 +3949,7 @@
1705 hash index semaphore! */
1706
1707 #ifndef UNIV_SEARCH_DEBUG
1708- if (!trx->has_search_latch) {
1709- rw_lock_s_lock(&btr_search_latch);
1710- trx->has_search_latch = TRUE;
1711- }
1712+ trx_search_latch_lock(trx, index->id);
1713 #endif
1714 switch (row_sel_try_search_shortcut_for_mysql(
1715 &rec, prebuilt, &offsets, &heap,
1716@@ -3969,8 +4019,8 @@
1717
1718 trx->search_latch_timeout--;
1719
1720- rw_lock_s_unlock(&btr_search_latch);
1721- trx->has_search_latch = FALSE;
1722+ trx_search_latch_release_if_reserved(
1723+ trx);
1724 }
1725
1726 /* NOTE that we do NOT store the cursor
1727@@ -3992,10 +4042,7 @@
1728 /*-------------------------------------------------------------*/
1729 /* PHASE 3: Open or restore index cursor position */
1730
1731- if (trx->has_search_latch) {
1732- rw_lock_s_unlock(&btr_search_latch);
1733- trx->has_search_latch = FALSE;
1734- }
1735+ trx_search_latch_release_if_reserved(trx);
1736
1737 /* The state of a running trx can only be changed by the
1738 thread that is currently serving the transaction. Because we
1739
1740=== modified file 'Percona-Server/storage/innobase/srv/srv0conc.cc'
1741--- Percona-Server/storage/innobase/srv/srv0conc.cc 2013-05-10 08:51:53 +0000
1742+++ Percona-Server/storage/innobase/srv/srv0conc.cc 2013-08-29 17:11:28 +0000
1743@@ -39,6 +39,7 @@
1744
1745 #include "srv0srv.h"
1746 #include "sync0sync.h"
1747+#include "btr0types.h"
1748 #include "trx0trx.h"
1749
1750 #include "mysql/plugin.h"
1751
1752=== modified file 'Percona-Server/storage/innobase/srv/srv0srv.cc'
1753--- Percona-Server/storage/innobase/srv/srv0srv.cc 2013-08-14 03:57:21 +0000
1754+++ Percona-Server/storage/innobase/srv/srv0srv.cc 2013-08-29 17:11:28 +0000
1755@@ -1308,17 +1308,20 @@
1756 os_atomic_increment_lint(&srv_read_views_memory, 0));
1757
1758 /* Calculate reserved memories */
1759- if (btr_search_sys && btr_search_sys->hash_index->heap) {
1760+ if (btr_search_sys && btr_search_sys->hash_index[0]->heap) {
1761 btr_search_sys_subtotal
1762- = mem_heap_get_size(btr_search_sys->hash_index->heap);
1763+ = mem_heap_get_size(btr_search_sys->hash_index[0]
1764+ ->heap);
1765 } else {
1766 btr_search_sys_subtotal = 0;
1767- for (i=0; i < btr_search_sys->hash_index->n_sync_obj; i++) {
1768+ for (i=0; i < btr_search_sys->hash_index[0]->n_sync_obj; i++) {
1769 btr_search_sys_subtotal
1770 += mem_heap_get_size(
1771- btr_search_sys->hash_index->heaps[i]);
1772+ btr_search_sys->hash_index[0]
1773+ ->heaps[i]);
1774 }
1775 }
1776+ btr_search_sys_subtotal *= btr_search_index_num;
1777
1778 lock_sys_subtotal = 0;
1779 if (trx_sys) {
1780@@ -1347,13 +1350,15 @@
1781 " Recovery system %lu \t(%lu + " ULINTPF ")\n",
1782
1783 (ulong) (btr_search_sys
1784- ? (btr_search_sys->hash_index->n_cells
1785- * sizeof(hash_cell_t))
1786+ ? (btr_search_sys->hash_index[0]->n_cells
1787+ * sizeof(hash_cell_t)
1788+ * btr_search_index_num)
1789 : 0)
1790 + btr_search_sys_subtotal,
1791 (ulong) (btr_search_sys
1792- ? (btr_search_sys->hash_index->n_cells
1793- * sizeof(hash_cell_t))
1794+ ? (btr_search_sys->hash_index[0]->n_cells
1795+ * sizeof(hash_cell_t)
1796+ * btr_search_index_num)
1797 : 0),
1798 btr_search_sys_subtotal,
1799
1800@@ -1504,21 +1509,23 @@
1801 buf_get_total_list_len(&LRU_len, &free_len, &flush_list_len);
1802 buf_get_total_list_size_in_bytes(&buf_pools_list_size);
1803
1804- if (btr_search_sys && btr_search_sys->hash_index->heap) {
1805+ if (btr_search_sys && btr_search_sys->hash_index[0]->heap) {
1806 mem_adaptive_hash
1807- = mem_heap_get_size(btr_search_sys->hash_index->heap);
1808+ = mem_heap_get_size(btr_search_sys
1809+ ->hash_index[0]->heap);
1810 } else {
1811 mem_adaptive_hash = 0;
1812- for (i=0; i < btr_search_sys->hash_index->n_sync_obj; i++) {
1813+ for (i=0; i < btr_search_sys->hash_index[0]->n_sync_obj; i++) {
1814 mem_adaptive_hash
1815 += mem_heap_get_size
1816- (btr_search_sys->hash_index->heaps[i]);
1817+ (btr_search_sys->hash_index[0]->heaps[i]);
1818 }
1819 }
1820 if (btr_search_sys) {
1821- mem_adaptive_hash += (btr_search_sys->hash_index->n_cells
1822+ mem_adaptive_hash += (btr_search_sys->hash_index[0]->n_cells
1823 * sizeof(hash_cell_t));
1824 }
1825+ mem_adaptive_hash *= btr_search_index_num;
1826
1827 mem_dictionary = (dict_sys ? ((dict_sys->table_hash->n_cells
1828 + dict_sys->table_id_hash->n_cells
1829
1830=== modified file 'Percona-Server/storage/innobase/sync/sync0sync.cc'
1831--- Percona-Server/storage/innobase/sync/sync0sync.cc 2013-08-06 15:16:34 +0000
1832+++ Percona-Server/storage/innobase/sync/sync0sync.cc 2013-08-29 17:11:28 +0000
1833@@ -38,6 +38,7 @@
1834 #include "sync0rw.h"
1835 #include "buf0buf.h"
1836 #include "srv0srv.h"
1837+#include "btr0types.h"
1838 #include "buf0types.h"
1839 #include "os0sync.h" /* for HAVE_ATOMIC_BUILTINS */
1840 #ifdef UNIV_SYNC_DEBUG
1841@@ -1149,7 +1150,6 @@
1842 case SYNC_ANY_LATCH:
1843 case SYNC_FILE_FORMAT_TAG:
1844 case SYNC_DOUBLEWRITE:
1845- case SYNC_SEARCH_SYS:
1846 case SYNC_THREADS:
1847 case SYNC_LOCK_SYS:
1848 case SYNC_LOCK_WAIT_SYS:
1849@@ -1182,6 +1182,24 @@
1850 ut_a(sync_thread_levels_contain(array, SYNC_LOCK_SYS));
1851 }
1852 break;
1853+ case SYNC_SEARCH_SYS: {
1854+ /* Verify the lock order inside the split btr_search_latch
1855+ array */
1856+ bool found_current = false;
1857+ for (ulint i = 0; i < btr_search_index_num; i++) {
1858+ if (btr_search_latch_arr[i] == latch) {
1859+ found_current = true;
1860+ } else if (found_current) {
1861+ ut_ad(!rw_lock_own(btr_search_latch_arr[i],
1862+ RW_LOCK_SHARED));
1863+ ut_ad(!rw_lock_own(btr_search_latch_arr[i],
1864+ RW_LOCK_EX));
1865+ }
1866+ }
1867+ ut_ad(found_current);
1868+
1869+ /* fallthrough */
1870+ }
1871 case SYNC_BUF_FLUSH_LIST:
1872 case SYNC_BUF_POOL:
1873 /* We can have multiple mutexes of this type therefore we
1874
1875=== modified file 'Percona-Server/storage/innobase/trx/trx0trx.cc'
1876--- Percona-Server/storage/innobase/trx/trx0trx.cc 2013-08-06 15:16:34 +0000
1877+++ Percona-Server/storage/innobase/trx/trx0trx.cc 2013-08-29 17:11:28 +0000
1878@@ -23,6 +23,7 @@
1879 Created 3/26/1996 Heikki Tuuri
1880 *******************************************************/
1881
1882+#include "btr0types.h"
1883 #include "trx0trx.h"
1884
1885 #ifdef UNIV_NONINL
1886
1887=== modified file 'Percona-Server/storage/innobase/ut/ut0ut.cc'
1888--- Percona-Server/storage/innobase/ut/ut0ut.cc 2013-08-06 15:16:34 +0000
1889+++ Percona-Server/storage/innobase/ut/ut0ut.cc 2013-08-29 17:11:28 +0000
1890@@ -39,6 +39,7 @@
1891 #include <ctype.h>
1892
1893 #ifndef UNIV_HOTBACKUP
1894+# include "btr0types.h"
1895 # include "trx0trx.h"
1896 # include "ha_prototypes.h"
1897 # include "mysql_com.h" /* NAME_LEN */

Subscribers

People subscribed via source and target branches