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

Proposed by Laurynas Biveinis
Status: Superseded
Proposed branch: lp:~laurynas-biveinis/percona-server/ahi-partitions-5.6-5.6
Merge into: lp:percona-server/5.6
Diff against target: 1940 lines (+722/-217)
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 (+213/-124)
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 (+28/-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 (+66/-2)
Percona-Server/storage/innobase/include/btr0sea.ic (+107/-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/-2)
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 (+72/-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 (+21/-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) Needs Fixing
Review via email: mp+182101@code.launchpad.net

This proposal has been superseded by a proposal from 2013-08-28.

Description of the change

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 :

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 :

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 :

> 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 :

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.

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-28 08:09:39 +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-28 08:09:39 +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-28 08:09:39 +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-28 08:09:39 +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-28 08:09:39 +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-28 08:09:39 +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-28 08:09:39 +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_temp_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,48 @@
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 <= 32. (bits of
286+ trx->has_search_latch) */
287+ ut_ad(btr_search_index_num <= 32);
288
289- rw_lock_create(btr_search_latch_key, &btr_search_latch,
290- SYNC_SEARCH_SYS);
291+ btr_search_latch_temp_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_temp_arr[i] = (rw_lock_t *)
304+ mem_alloc(sizeof(rw_lock_t));
305+
306+ rw_lock_create(btr_search_latch_key,
307+ btr_search_latch_temp_arr[i],
308+ SYNC_SEARCH_SYS);
309+
310+ btr_search_sys->hash_index[i]
311+ = ha_create(hash_size, 0, MEM_HEAP_FOR_BTR_SEARCH, 0);
312+
313 #if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG
314- btr_search_sys->hash_index->adaptive = TRUE;
315+ btr_search_sys->hash_index[i]->adaptive = TRUE;
316 #endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */
317-
318+ }
319 }
320
321 /*****************************************************************//**
322@@ -190,11 +219,25 @@
323 btr_search_sys_free(void)
324 /*=====================*/
325 {
326- rw_lock_free(&btr_search_latch);
327- mem_free(btr_search_latch_temp);
328- btr_search_latch_temp = NULL;
329- mem_heap_free(btr_search_sys->hash_index->heap);
330- hash_table_free(btr_search_sys->hash_index);
331+ ulint i;
332+
333+ for (i = 0; i < btr_search_index_num; i++) {
334+
335+ rw_lock_free(btr_search_latch_temp_arr[i]);
336+
337+ mem_free(btr_search_latch_temp_arr[i]);
338+
339+ mem_heap_free(btr_search_sys->hash_index[i]->heap);
340+
341+ hash_table_free(btr_search_sys->hash_index[i]);
342+
343+ }
344+
345+ mem_free(btr_search_latch_temp_arr);
346+ btr_search_latch_temp_arr = NULL;
347+
348+ mem_free(btr_search_sys->hash_index);
349+
350 mem_free(btr_search_sys);
351 btr_search_sys = NULL;
352 }
353@@ -210,13 +253,14 @@
354 dict_index_t* index;
355
356 ut_ad(mutex_own(&dict_sys->mutex));
357-#ifdef UNIV_SYNC_DEBUG
358- ut_ad(rw_lock_own(&btr_search_latch, RW_LOCK_EX));
359-#endif /* UNIV_SYNC_DEBUG */
360
361 for (index = dict_table_get_first_index(table); index;
362 index = dict_table_get_next_index(index)) {
363
364+#ifdef UNIV_SYNC_DEBUG
365+ ut_ad(rw_lock_own(btr_search_get_latch(index->id),
366+ RW_LOCK_EX));
367+#endif /* UNIV_SYNC_DEBUG */
368 index->search_info->ref_count = 0;
369 }
370 }
371@@ -229,9 +273,10 @@
372 /*====================*/
373 {
374 dict_table_t* table;
375+ ulint i;
376
377 mutex_enter(&dict_sys->mutex);
378- rw_lock_x_lock(&btr_search_latch);
379+ btr_search_x_lock_all();
380
381 btr_search_enabled = FALSE;
382
383@@ -255,10 +300,12 @@
384 buf_pool_clear_hash_index();
385
386 /* Clear the adaptive hash index. */
387- hash_table_clear(btr_search_sys->hash_index);
388- mem_heap_empty(btr_search_sys->hash_index->heap);
389+ for (i = 0; i < btr_search_index_num; i++) {
390+ hash_table_clear(btr_search_sys->hash_index[i]);
391+ mem_heap_empty(btr_search_sys->hash_index[i]->heap);
392+ }
393
394- rw_lock_x_unlock(&btr_search_latch);
395+ btr_search_x_unlock_all();
396 }
397
398 /********************************************************************//**
399@@ -268,11 +315,11 @@
400 btr_search_enable(void)
401 /*====================*/
402 {
403- rw_lock_x_lock(&btr_search_latch);
404+ btr_search_x_lock_all();
405
406 btr_search_enabled = TRUE;
407
408- rw_lock_x_unlock(&btr_search_latch);
409+ btr_search_x_unlock_all();
410 }
411
412 /*****************************************************************//**
413@@ -324,20 +371,21 @@
414 ulint
415 btr_search_info_get_ref_count(
416 /*==========================*/
417- btr_search_t* info) /*!< in: search info. */
418+ btr_search_t* info, /*!< in: search info. */
419+ index_id_t key) /*!< in: id of the index owning search info */
420 {
421 ulint ret;
422
423 ut_ad(info);
424
425 #ifdef UNIV_SYNC_DEBUG
426- ut_ad(!rw_lock_own(&btr_search_latch, RW_LOCK_SHARED));
427- ut_ad(!rw_lock_own(&btr_search_latch, RW_LOCK_EX));
428+ ut_ad(!rw_lock_own(btr_search_get_latch(key), RW_LOCK_SHARED));
429+ ut_ad(!rw_lock_own(btr_search_get_latch(key), RW_LOCK_EX));
430 #endif /* UNIV_SYNC_DEBUG */
431
432- rw_lock_s_lock(&btr_search_latch);
433+ rw_lock_s_lock(btr_search_get_latch(key));
434 ret = info->ref_count;
435- rw_lock_s_unlock(&btr_search_latch);
436+ rw_lock_s_unlock(btr_search_get_latch(key));
437
438 return(ret);
439 }
440@@ -353,17 +401,15 @@
441 btr_search_t* info, /*!< in/out: search info */
442 btr_cur_t* cursor) /*!< in: cursor which was just positioned */
443 {
444- dict_index_t* index;
445+ dict_index_t* index = cursor->index;
446 ulint n_unique;
447 int cmp;
448
449 #ifdef UNIV_SYNC_DEBUG
450- ut_ad(!rw_lock_own(&btr_search_latch, RW_LOCK_SHARED));
451- ut_ad(!rw_lock_own(&btr_search_latch, RW_LOCK_EX));
452+ ut_ad(!rw_lock_own(btr_search_get_latch(index->id), RW_LOCK_SHARED));
453+ ut_ad(!rw_lock_own(btr_search_get_latch(index->id), RW_LOCK_EX));
454 #endif /* UNIV_SYNC_DEBUG */
455
456- index = cursor->index;
457-
458 if (dict_index_is_ibuf(index)) {
459 /* So many deletes are performed on an insert buffer tree
460 that we do not consider a hash index useful on it: */
461@@ -477,8 +523,10 @@
462 /*!< in: cursor */
463 {
464 #ifdef UNIV_SYNC_DEBUG
465- ut_ad(!rw_lock_own(&btr_search_latch, RW_LOCK_SHARED));
466- ut_ad(!rw_lock_own(&btr_search_latch, RW_LOCK_EX));
467+ ut_ad(!rw_lock_own(btr_search_get_latch(cursor->index->id),
468+ RW_LOCK_SHARED));
469+ ut_ad(!rw_lock_own(btr_search_get_latch(cursor->index->id),
470+ RW_LOCK_EX));
471 ut_ad(rw_lock_own(&block->lock, RW_LOCK_SHARED)
472 || rw_lock_own(&block->lock, RW_LOCK_EX));
473 #endif /* UNIV_SYNC_DEBUG */
474@@ -562,7 +610,8 @@
475
476 ut_ad(cursor->flag == BTR_CUR_HASH_FAIL);
477 #ifdef UNIV_SYNC_DEBUG
478- ut_ad(rw_lock_own(&btr_search_latch, RW_LOCK_EX));
479+ ut_ad(rw_lock_own(btr_search_get_latch(cursor->index->id),
480+ RW_LOCK_EX));
481 ut_ad(rw_lock_own(&(block->lock), RW_LOCK_SHARED)
482 || rw_lock_own(&(block->lock), RW_LOCK_EX));
483 #endif /* UNIV_SYNC_DEBUG */
484@@ -603,11 +652,13 @@
485 mem_heap_free(heap);
486 }
487 #ifdef UNIV_SYNC_DEBUG
488- ut_ad(rw_lock_own(&btr_search_latch, RW_LOCK_EX));
489+ ut_ad(rw_lock_own(btr_search_get_latch(cursor->index->id),
490+ RW_LOCK_EX));
491 #endif /* UNIV_SYNC_DEBUG */
492
493- ha_insert_for_fold(btr_search_sys->hash_index, fold,
494- block, rec);
495+ ha_insert_for_fold(
496+ btr_search_get_hash_index(cursor->index->id), fold,
497+ block, rec);
498
499 MONITOR_INC(MONITOR_ADAPTIVE_HASH_ROW_ADDED);
500 }
501@@ -628,8 +679,10 @@
502 ulint* params2;
503
504 #ifdef UNIV_SYNC_DEBUG
505- ut_ad(!rw_lock_own(&btr_search_latch, RW_LOCK_SHARED));
506- ut_ad(!rw_lock_own(&btr_search_latch, RW_LOCK_EX));
507+ ut_ad(!rw_lock_own(btr_search_get_latch(cursor->index->id),
508+ RW_LOCK_SHARED));
509+ ut_ad(!rw_lock_own(btr_search_get_latch(cursor->index->id),
510+ RW_LOCK_EX));
511 #endif /* UNIV_SYNC_DEBUG */
512
513 block = btr_cur_get_block(cursor);
514@@ -647,7 +700,7 @@
515
516 if (build_index || (cursor->flag == BTR_CUR_HASH_FAIL)) {
517
518- btr_search_check_free_space_in_heap();
519+ btr_search_check_free_space_in_heap(cursor->index->id);
520 }
521
522 if (cursor->flag == BTR_CUR_HASH_FAIL) {
523@@ -657,11 +710,11 @@
524 btr_search_n_hash_fail++;
525 #endif /* UNIV_SEARCH_PERF_STAT */
526
527- rw_lock_x_lock(&btr_search_latch);
528+ rw_lock_x_lock(btr_search_get_latch(cursor->index->id));
529
530 btr_search_update_hash_ref(info, block, cursor);
531
532- rw_lock_x_unlock(&btr_search_latch);
533+ rw_lock_x_unlock(btr_search_get_latch(cursor->index->id));
534 }
535
536 if (build_index) {
537@@ -906,17 +959,19 @@
538 cursor->flag = BTR_CUR_HASH;
539
540 if (UNIV_LIKELY(!has_search_latch)) {
541- rw_lock_s_lock(&btr_search_latch);
542+ rw_lock_s_lock(btr_search_get_latch(index_id));
543
544 if (UNIV_UNLIKELY(!btr_search_enabled)) {
545 goto failure_unlock;
546 }
547 }
548
549- ut_ad(rw_lock_get_writer(&btr_search_latch) != RW_LOCK_EX);
550- ut_ad(rw_lock_get_reader_count(&btr_search_latch) > 0);
551+ ut_ad(rw_lock_get_writer(btr_search_get_latch(index_id))
552+ != RW_LOCK_EX);
553+ ut_ad(rw_lock_get_reader_count(btr_search_get_latch(index_id)) > 0);
554
555- rec = (rec_t*) ha_search_and_get_data(btr_search_sys->hash_index, fold);
556+ rec = (rec_t*) ha_search_and_get_data(
557+ btr_search_get_hash_index(index_id), fold);
558
559 if (UNIV_UNLIKELY(!rec)) {
560 goto failure_unlock;
561@@ -934,7 +989,7 @@
562 goto failure_unlock;
563 }
564
565- rw_lock_s_unlock(&btr_search_latch);
566+ rw_lock_s_unlock(btr_search_get_latch(index_id));
567
568 buf_block_dbg_add_level(block, SYNC_TREE_NODE_FROM_HASH);
569 }
570@@ -1031,7 +1086,7 @@
571 /*-------------------------------------------*/
572 failure_unlock:
573 if (UNIV_LIKELY(!has_search_latch)) {
574- rw_lock_s_unlock(&btr_search_latch);
575+ rw_lock_s_unlock(btr_search_get_latch(index_id));
576 }
577 failure:
578 cursor->flag = BTR_CUR_HASH_FAIL;
579@@ -1079,12 +1134,9 @@
580 const dict_index_t* index;
581 ulint* offsets;
582 btr_search_t* info;
583-
584-#ifdef UNIV_SYNC_DEBUG
585- ut_ad(!rw_lock_own(&btr_search_latch, RW_LOCK_SHARED));
586- ut_ad(!rw_lock_own(&btr_search_latch, RW_LOCK_EX));
587-#endif /* UNIV_SYNC_DEBUG */
588-
589+ rw_lock_t* btr_search_latch;
590+
591+retry:
592 /* Do a dirty check on block->index, return if the block is
593 not in the adaptive hash index. This is to avoid acquiring
594 shared btr_search_latch for performance consideration. */
595@@ -1092,17 +1144,31 @@
596 return;
597 }
598
599-retry:
600- rw_lock_s_lock(&btr_search_latch);
601+ btr_search_latch = block->btr_search_latch;
602+
603+ if (UNIV_UNLIKELY(!btr_search_latch)) {
604+ return;
605+ }
606+
607+#ifdef UNIV_SYNC_DEBUG
608+ ut_ad(!rw_lock_own(btr_search_latch, RW_LOCK_SHARED));
609+ ut_ad(!rw_lock_own(btr_search_latch, RW_LOCK_EX));
610+#endif /* UNIV_SYNC_DEBUG */
611+
612+ rw_lock_s_lock(btr_search_latch);
613+ if (UNIV_UNLIKELY(btr_search_latch != block->btr_search_latch)) {
614+ rw_lock_s_unlock(btr_search_latch);
615+ goto retry;
616+ }
617+
618 index = block->index;
619-
620- if (UNIV_LIKELY(!index)) {
621-
622- rw_lock_s_unlock(&btr_search_latch);
623-
624+ if (UNIV_UNLIKELY(!index)) {
625+ rw_lock_s_unlock(btr_search_latch);
626 return;
627 }
628
629+ ut_a(btr_search_latch == btr_search_get_latch(index->id));
630+
631 ut_a(!dict_index_is_ibuf(index));
632 #ifdef UNIV_DEBUG
633 switch (dict_index_get_online_status(index)) {
634@@ -1125,7 +1191,7 @@
635 }
636 #endif /* UNIV_DEBUG */
637
638- table = btr_search_sys->hash_index;
639+ table = btr_search_get_hash_index(index->id);
640
641 #ifdef UNIV_SYNC_DEBUG
642 ut_ad(rw_lock_own(&(block->lock), RW_LOCK_SHARED)
643@@ -1141,7 +1207,7 @@
644 releasing btr_search_latch, as the index page might only
645 be s-latched! */
646
647- rw_lock_s_unlock(&btr_search_latch);
648+ rw_lock_s_unlock(btr_search_latch);
649
650 ut_a(n_fields + n_bytes > 0);
651
652@@ -1192,7 +1258,7 @@
653 mem_heap_free(heap);
654 }
655
656- rw_lock_x_lock(&btr_search_latch);
657+ rw_lock_x_lock(btr_search_get_latch(index->id));
658
659 if (UNIV_UNLIKELY(!block->index)) {
660 /* Someone else has meanwhile dropped the hash index */
661@@ -1208,7 +1274,7 @@
662 /* Someone else has meanwhile built a new hash index on the
663 page, with different parameters */
664
665- rw_lock_x_unlock(&btr_search_latch);
666+ rw_lock_x_unlock(btr_search_get_latch(index->id));
667
668 mem_free(folds);
669 goto retry;
670@@ -1224,6 +1290,7 @@
671 info->ref_count--;
672
673 block->index = NULL;
674+ block->btr_search_latch = NULL;
675
676 MONITOR_INC(MONITOR_ADAPTIVE_HASH_PAGE_REMOVED);
677 MONITOR_INC_VALUE(MONITOR_ADAPTIVE_HASH_ROW_REMOVED, n_cached);
678@@ -1239,14 +1306,14 @@
679 "InnoDB: the hash index to a page of %s,"
680 " still %lu hash nodes remain.\n",
681 index->name, (ulong) block->n_pointers);
682- rw_lock_x_unlock(&btr_search_latch);
683+ rw_lock_x_unlock(btr_search_get_latch(index->id));
684
685 ut_ad(btr_search_validate());
686 } else {
687- rw_lock_x_unlock(&btr_search_latch);
688+ rw_lock_x_unlock(btr_search_get_latch(index->id));
689 }
690 #else /* UNIV_AHI_DEBUG || UNIV_DEBUG */
691- rw_lock_x_unlock(&btr_search_latch);
692+ rw_lock_x_unlock(btr_search_get_latch(index->id));
693 #endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */
694
695 mem_free(folds);
696@@ -1325,30 +1392,30 @@
697 ut_a(!dict_index_is_ibuf(index));
698
699 #ifdef UNIV_SYNC_DEBUG
700- ut_ad(!rw_lock_own(&btr_search_latch, RW_LOCK_EX));
701+ ut_ad(!rw_lock_own(btr_search_get_latch(index->id), RW_LOCK_EX));
702 ut_ad(rw_lock_own(&(block->lock), RW_LOCK_SHARED)
703 || rw_lock_own(&(block->lock), RW_LOCK_EX));
704 #endif /* UNIV_SYNC_DEBUG */
705
706- rw_lock_s_lock(&btr_search_latch);
707+ rw_lock_s_lock(btr_search_get_latch(index->id));
708
709 if (!btr_search_enabled) {
710- rw_lock_s_unlock(&btr_search_latch);
711+ rw_lock_s_unlock(btr_search_get_latch(index->id));
712 return;
713 }
714
715- table = btr_search_sys->hash_index;
716+ table = btr_search_get_hash_index(index->id);
717 page = buf_block_get_frame(block);
718
719 if (block->index && ((block->curr_n_fields != n_fields)
720 || (block->curr_n_bytes != n_bytes)
721 || (block->curr_left_side != left_side))) {
722
723- rw_lock_s_unlock(&btr_search_latch);
724+ rw_lock_s_unlock(btr_search_get_latch(index->id));
725
726 btr_search_drop_page_hash_index(block);
727 } else {
728- rw_lock_s_unlock(&btr_search_latch);
729+ rw_lock_s_unlock(btr_search_get_latch(index->id));
730 }
731
732 n_recs = page_get_n_recs(page);
733@@ -1442,9 +1509,9 @@
734 fold = next_fold;
735 }
736
737- btr_search_check_free_space_in_heap();
738+ btr_search_check_free_space_in_heap(index->id);
739
740- rw_lock_x_lock(&btr_search_latch);
741+ rw_lock_x_lock(btr_search_get_latch(index->id));
742
743 if (UNIV_UNLIKELY(!btr_search_enabled)) {
744 goto exit_func;
745@@ -1471,6 +1538,7 @@
746 block->curr_n_bytes = n_bytes;
747 block->curr_left_side = left_side;
748 block->index = index;
749+ block->btr_search_latch = btr_search_get_latch(index->id);
750
751 for (i = 0; i < n_cached; i++) {
752
753@@ -1480,7 +1548,7 @@
754 MONITOR_INC(MONITOR_ADAPTIVE_HASH_PAGE_ADDED);
755 MONITOR_INC_VALUE(MONITOR_ADAPTIVE_HASH_ROW_ADDED, n_cached);
756 exit_func:
757- rw_lock_x_unlock(&btr_search_latch);
758+ rw_lock_x_unlock(btr_search_get_latch(index->id));
759
760 mem_free(folds);
761 mem_free(recs);
762@@ -1515,7 +1583,7 @@
763 ut_ad(rw_lock_own(&(new_block->lock), RW_LOCK_EX));
764 #endif /* UNIV_SYNC_DEBUG */
765
766- rw_lock_s_lock(&btr_search_latch);
767+ rw_lock_s_lock(btr_search_get_latch(index->id));
768
769 ut_a(!new_block->index || new_block->index == index);
770 ut_a(!block->index || block->index == index);
771@@ -1524,7 +1592,7 @@
772
773 if (new_block->index) {
774
775- rw_lock_s_unlock(&btr_search_latch);
776+ rw_lock_s_unlock(btr_search_get_latch(index->id));
777
778 btr_search_drop_page_hash_index(block);
779
780@@ -1541,7 +1609,7 @@
781 new_block->n_bytes = block->curr_n_bytes;
782 new_block->left_side = left_side;
783
784- rw_lock_s_unlock(&btr_search_latch);
785+ rw_lock_s_unlock(btr_search_get_latch(index->id));
786
787 ut_a(n_fields + n_bytes > 0);
788
789@@ -1553,7 +1621,7 @@
790 return;
791 }
792
793- rw_lock_s_unlock(&btr_search_latch);
794+ rw_lock_s_unlock(btr_search_get_latch(index->id));
795 }
796
797 /********************************************************************//**
798@@ -1592,7 +1660,7 @@
799 ut_a(block->curr_n_fields + block->curr_n_bytes > 0);
800 ut_a(!dict_index_is_ibuf(index));
801
802- table = btr_search_sys->hash_index;
803+ table = btr_search_get_hash_index(cursor->index->id);
804
805 rec = btr_cur_get_rec(cursor);
806
807@@ -1603,7 +1671,7 @@
808 mem_heap_free(heap);
809 }
810
811- rw_lock_x_lock(&btr_search_latch);
812+ rw_lock_x_lock(btr_search_get_latch(cursor->index->id));
813
814 if (block->index) {
815 ut_a(block->index == index);
816@@ -1616,7 +1684,7 @@
817 }
818 }
819
820- rw_lock_x_unlock(&btr_search_latch);
821+ rw_lock_x_unlock(btr_search_get_latch(cursor->index->id));
822 }
823
824 /********************************************************************//**
825@@ -1653,7 +1721,7 @@
826 ut_a(cursor->index == index);
827 ut_a(!dict_index_is_ibuf(index));
828
829- rw_lock_x_lock(&btr_search_latch);
830+ rw_lock_x_lock(btr_search_get_latch(cursor->index->id));
831
832 if (!block->index) {
833
834@@ -1667,7 +1735,7 @@
835 && (cursor->n_bytes == block->curr_n_bytes)
836 && !block->curr_left_side) {
837
838- table = btr_search_sys->hash_index;
839+ table = btr_search_get_hash_index(cursor->index->id);
840
841 if (ha_search_and_update_if_found(
842 table, cursor->fold, rec, block,
843@@ -1676,9 +1744,9 @@
844 }
845
846 func_exit:
847- rw_lock_x_unlock(&btr_search_latch);
848+ rw_lock_x_unlock(btr_search_get_latch(cursor->index->id));
849 } else {
850- rw_lock_x_unlock(&btr_search_latch);
851+ rw_lock_x_unlock(btr_search_get_latch(cursor->index->id));
852
853 btr_search_update_hash_on_insert(cursor);
854 }
855@@ -1726,9 +1794,9 @@
856 return;
857 }
858
859- btr_search_check_free_space_in_heap();
860+ btr_search_check_free_space_in_heap(cursor->index->id);
861
862- table = btr_search_sys->hash_index;
863+ table = btr_search_get_hash_index(cursor->index->id);
864
865 rec = btr_cur_get_rec(cursor);
866
867@@ -1760,7 +1828,7 @@
868 } else {
869 if (left_side) {
870
871- rw_lock_x_lock(&btr_search_latch);
872+ rw_lock_x_lock(btr_search_get_latch(index->id));
873
874 locked = TRUE;
875
876@@ -1778,7 +1846,7 @@
877
878 if (!locked) {
879
880- rw_lock_x_lock(&btr_search_latch);
881+ rw_lock_x_lock(btr_search_get_latch(index->id));
882
883 locked = TRUE;
884
885@@ -1800,7 +1868,8 @@
886 if (!left_side) {
887
888 if (!locked) {
889- rw_lock_x_lock(&btr_search_latch);
890+ rw_lock_x_lock(btr_search_get_latch(
891+ index->id));
892
893 locked = TRUE;
894
895@@ -1819,7 +1888,7 @@
896
897 if (!locked) {
898
899- rw_lock_x_lock(&btr_search_latch);
900+ rw_lock_x_lock(btr_search_get_latch(index->id));
901
902 locked = TRUE;
903
904@@ -1846,18 +1915,19 @@
905 mem_heap_free(heap);
906 }
907 if (locked) {
908- rw_lock_x_unlock(&btr_search_latch);
909+ rw_lock_x_unlock(btr_search_get_latch(index->id));
910 }
911 }
912
913 #if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG
914 /********************************************************************//**
915-Validates the search system.
916+Validates one hash table in the search system.
917 @return TRUE if ok */
918-UNIV_INTERN
919+static
920 ibool
921-btr_search_validate(void)
922-/*=====================*/
923+btr_search_validate_one_table(
924+/*==========================*/
925+ ulint t)
926 {
927 ha_node_t* node;
928 ulint n_page_dumps = 0;
929@@ -1874,24 +1944,20 @@
930
931 rec_offs_init(offsets_);
932
933- rw_lock_x_lock(&btr_search_latch);
934- buf_pool_mutex_enter_all();
935-
936- cell_count = hash_get_n_cells(btr_search_sys->hash_index);
937+ cell_count = hash_get_n_cells(btr_search_sys->hash_index[t]);
938
939 for (i = 0; i < cell_count; i++) {
940 /* We release btr_search_latch every once in a while to
941 give other queries a chance to run. */
942 if ((i != 0) && ((i % chunk_size) == 0)) {
943- buf_pool_mutex_exit_all();
944- rw_lock_x_unlock(&btr_search_latch);
945+ btr_search_x_unlock_all();
946 os_thread_yield();
947- rw_lock_x_lock(&btr_search_latch);
948- buf_pool_mutex_enter_all();
949+ btr_search_x_lock_all();
950 }
951
952 node = (ha_node_t*)
953- hash_get_nth_cell(btr_search_sys->hash_index, i)->node;
954+ hash_get_nth_cell(btr_search_sys->hash_index[t],
955+ i)->node;
956
957 for (; node != NULL; node = node->next) {
958 const buf_block_t* block
959@@ -1999,24 +2065,47 @@
960 /* We release btr_search_latch every once in a while to
961 give other queries a chance to run. */
962 if (i != 0) {
963- buf_pool_mutex_exit_all();
964- rw_lock_x_unlock(&btr_search_latch);
965+ btr_search_x_unlock_all();
966 os_thread_yield();
967- rw_lock_x_lock(&btr_search_latch);
968- buf_pool_mutex_enter_all();
969+ btr_search_x_lock_all();
970 }
971
972- if (!ha_validate(btr_search_sys->hash_index, i, end_index)) {
973+ if (!ha_validate(btr_search_sys->hash_index[t], i,
974+ end_index)) {
975 ok = FALSE;
976 }
977 }
978
979- buf_pool_mutex_exit_all();
980- rw_lock_x_unlock(&btr_search_latch);
981 if (UNIV_LIKELY_NULL(heap)) {
982 mem_heap_free(heap);
983 }
984
985 return(ok);
986 }
987+
988+/********************************************************************//**
989+Validates the search system.
990+@return TRUE if ok */
991+UNIV_INTERN
992+ibool
993+btr_search_validate(void)
994+/*=====================*/
995+{
996+ ulint i;
997+ ibool ok = TRUE;
998+
999+ btr_search_x_lock_all();
1000+
1001+ for (i = 0; i < btr_search_index_num; i++) {
1002+
1003+ if (!btr_search_validate_one_table(i))
1004+ ok = FALSE;
1005+ }
1006+
1007+ btr_search_x_unlock_all();
1008+
1009+ return(ok);
1010+}
1011+
1012+
1013 #endif /* defined UNIV_AHI_DEBUG || defined UNIV_DEBUG */
1014
1015=== modified file 'Percona-Server/storage/innobase/buf/buf0buf.cc'
1016--- Percona-Server/storage/innobase/buf/buf0buf.cc 2013-08-26 15:36:54 +0000
1017+++ Percona-Server/storage/innobase/buf/buf0buf.cc 2013-08-28 08:09:39 +0000
1018@@ -1013,6 +1013,7 @@
1019
1020 block->check_index_page_at_flush = FALSE;
1021 block->index = NULL;
1022+ block->btr_search_latch = NULL;
1023
1024 #ifdef UNIV_DEBUG
1025 block->page.in_page_hash = FALSE;
1026@@ -1484,7 +1485,7 @@
1027 ulint p;
1028
1029 #ifdef UNIV_SYNC_DEBUG
1030- ut_ad(rw_lock_own(&btr_search_latch, RW_LOCK_EX));
1031+ ut_ad(btr_search_own_all(RW_LOCK_EX));
1032 #endif /* UNIV_SYNC_DEBUG */
1033 ut_ad(!btr_search_enabled);
1034
1035@@ -2208,6 +2209,7 @@
1036 {
1037 block->check_index_page_at_flush = FALSE;
1038 block->index = NULL;
1039+ block->btr_search_latch = NULL;
1040
1041 block->n_hash_helps = 0;
1042 block->n_fields = 1;
1043
1044=== modified file 'Percona-Server/storage/innobase/dict/dict0dict.cc'
1045--- Percona-Server/storage/innobase/dict/dict0dict.cc 2013-08-14 03:57:21 +0000
1046+++ Percona-Server/storage/innobase/dict/dict0dict.cc 2013-08-28 08:09:39 +0000
1047@@ -1208,7 +1208,8 @@
1048
1049 See also: dict_index_remove_from_cache_low() */
1050
1051- if (btr_search_info_get_ref_count(info) > 0) {
1052+ if (btr_search_info_get_ref_count(info, index->id)
1053+ > 0) {
1054 return(FALSE);
1055 }
1056 }
1057@@ -2483,7 +2484,8 @@
1058 zero. See also: dict_table_can_be_evicted() */
1059
1060 do {
1061- ulint ref_count = btr_search_info_get_ref_count(info);
1062+ ulint ref_count = btr_search_info_get_ref_count(info,
1063+ index->id);
1064
1065 if (ref_count == 0) {
1066 break;
1067
1068=== modified file 'Percona-Server/storage/innobase/ha/ha0ha.cc'
1069--- Percona-Server/storage/innobase/ha/ha0ha.cc 2013-08-06 15:16:34 +0000
1070+++ Percona-Server/storage/innobase/ha/ha0ha.cc 2013-08-28 08:09:39 +0000
1071@@ -98,6 +98,31 @@
1072 return(table);
1073 }
1074
1075+#ifdef UNIV_SYNC_DEBUG
1076+/*************************************************************//**
1077+Verifies that the specified hash table is a part of adaptive hash index and
1078+that its corresponding latch is X-latched by the current thread. */
1079+static
1080+bool
1081+ha_assert_btr_x_locked(
1082+/*===================*/
1083+ const hash_table_t* table) /*!<in: hash table to check */
1084+{
1085+ ulint i;
1086+
1087+ ut_ad(table->adaptive);
1088+
1089+ for (i = 0; i < btr_search_index_num; i++)
1090+ if (btr_search_sys->hash_index[i] == table)
1091+ break;
1092+
1093+ ut_ad(i < btr_search_index_num);
1094+ ut_ad(rw_lock_own(btr_search_latch_temp_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 +137,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 +298,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 +337,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-28 08:09:39 +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-28 08:09:39 +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-28 08:09:39 +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,69 @@
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+/********************************************************************//**
1276+Latches all adaptive hash index latches in shared mode. */
1277+UNIV_INLINE
1278+void
1279+btr_search_s_lock_all(void);
1280+/*========================*/
1281+
1282+/********************************************************************//**
1283+Unlatches all adaptive hash index latches in shared mode. */
1284+UNIV_INLINE
1285+void
1286+btr_search_s_unlock_all(void);
1287+/*==========================*/
1288+
1289+#ifdef UNIV_SYNC_DEBUG
1290+/******************************************************************//**
1291+Checks if the thread has locked all the adaptive hash index latches in the
1292+specified mode.
1293+
1294+@return true if all latches are locked by the current thread, false
1295+otherwise. */
1296+UNIV_INLINE
1297+bool
1298+btr_search_own_all(
1299+/*===============*/
1300+ ulint lock_type)
1301+ __attribute__((warn_unused_result));
1302+#endif /* UNIV_SYNC_DEBUG */
1303+
1304 /** The search info struct in an index */
1305 struct btr_search_t{
1306 ulint ref_count; /*!< Number of blocks in this index tree
1307@@ -250,7 +314,7 @@
1308
1309 /** The hash index system */
1310 struct btr_search_sys_t{
1311- hash_table_t* hash_index; /*!< the adaptive hash index,
1312+ hash_table_t** hash_index; /*!< the adaptive hash index,
1313 mapping dtuple_fold values
1314 to rec_t pointers on index pages */
1315 };
1316
1317=== modified file 'Percona-Server/storage/innobase/include/btr0sea.ic'
1318--- Percona-Server/storage/innobase/include/btr0sea.ic 2013-08-06 15:16:34 +0000
1319+++ Percona-Server/storage/innobase/include/btr0sea.ic 2013-08-28 08:09:39 +0000
1320@@ -60,8 +60,8 @@
1321 btr_search_t* info;
1322
1323 #ifdef UNIV_SYNC_DEBUG
1324- ut_ad(!rw_lock_own(&btr_search_latch, RW_LOCK_SHARED));
1325- ut_ad(!rw_lock_own(&btr_search_latch, RW_LOCK_EX));
1326+ ut_ad(!rw_lock_own(btr_search_get_latch(index->id), RW_LOCK_SHARED));
1327+ ut_ad(!rw_lock_own(btr_search_get_latch(index->id), RW_LOCK_EX));
1328 #endif /* UNIV_SYNC_DEBUG */
1329
1330 info = btr_search_get_info(index);
1331@@ -80,3 +80,108 @@
1332
1333 btr_search_info_update_slow(info, cursor);
1334 }
1335+
1336+/********************************************************************//**
1337+Returns the adaptive hash index table for a given index key.
1338+@return the adaptive hash index table for a given index key */
1339+UNIV_INLINE
1340+hash_table_t*
1341+btr_search_get_hash_index(
1342+/*======================*/
1343+ index_id_t key) /*!< in: index key */
1344+{
1345+ return(btr_search_sys->hash_index[key % btr_search_index_num]);
1346+}
1347+
1348+/********************************************************************//**
1349+Returns the adaptive hash index latch for a given index key.
1350+@return the adaptive hash index latch for a given index key */
1351+UNIV_INLINE
1352+rw_lock_t*
1353+btr_search_get_latch(
1354+/*=================*/
1355+ index_id_t key) /*!< in: index key */
1356+{
1357+ return(btr_search_latch_temp_arr[key % btr_search_index_num]);
1358+}
1359+
1360+/********************************************************************//**
1361+Latches all adaptive hash index latches in exclusive mode. */
1362+UNIV_INLINE
1363+void
1364+btr_search_x_lock_all(void)
1365+/*=======================*/
1366+{
1367+ ulint i;
1368+
1369+ for (i = 0; i < btr_search_index_num; i++) {
1370+ rw_lock_x_lock(btr_search_latch_temp_arr[i]);
1371+ }
1372+}
1373+
1374+/********************************************************************//**
1375+Unlatches all adaptive hash index latches in exclusive mode. */
1376+UNIV_INLINE
1377+void
1378+btr_search_x_unlock_all(void)
1379+/*==========================*/
1380+{
1381+ ulint i;
1382+
1383+ for (i = 0; i < btr_search_index_num; i++) {
1384+ rw_lock_x_unlock(btr_search_latch_temp_arr[i]);
1385+ }
1386+}
1387+
1388+/********************************************************************//**
1389+Latches all adaptive hash index latches in shared mode. */
1390+UNIV_INLINE
1391+void
1392+btr_search_s_lock_all(void)
1393+/*=======================*/
1394+{
1395+ ulint i;
1396+
1397+ for (i = 0; i < btr_search_index_num; i++) {
1398+ rw_lock_s_lock(btr_search_latch_temp_arr[i]);
1399+ }
1400+}
1401+
1402+/********************************************************************//**
1403+Unlatches all adaptive hash index latches in shared mode. */
1404+UNIV_INLINE
1405+void
1406+btr_search_s_unlock_all(void)
1407+/*=========================*/
1408+{
1409+ ulint i;
1410+
1411+ for (i = 0; i < btr_search_index_num; i++) {
1412+ rw_lock_s_unlock(btr_search_latch_temp_arr[i]);
1413+ }
1414+}
1415+
1416+#ifdef UNIV_SYNC_DEBUG
1417+/******************************************************************//**
1418+Checks if the thread has locked all the adaptive hash index latches in the
1419+specified mode.
1420+
1421+@return true if all latches are locked by the current thread, false
1422+otherwise. */
1423+UNIV_INLINE
1424+bool
1425+btr_search_own_all(
1426+/*===============*/
1427+ ulint lock_type)
1428+{
1429+ ulint i;
1430+
1431+ for (i = 0; i < btr_search_index_num; i++) {
1432+ if (!rw_lock_own(btr_search_latch_temp_arr[i], lock_type)) {
1433+ return(false);
1434+ }
1435+ }
1436+
1437+ return(true);
1438+}
1439+#endif /* UNIV_SYNC_DEBUG */
1440
1441=== modified file 'Percona-Server/storage/innobase/include/btr0types.h'
1442--- Percona-Server/storage/innobase/include/btr0types.h 2013-08-06 15:16:34 +0000
1443+++ Percona-Server/storage/innobase/include/btr0types.h 2013-08-28 08:09:39 +0000
1444@@ -54,17 +54,17 @@
1445
1446 Bear in mind (3) and (4) when using the hash index.
1447 */
1448-extern rw_lock_t* btr_search_latch_temp;
1449+extern rw_lock_t** btr_search_latch_temp_arr;
1450
1451 #endif /* UNIV_HOTBACKUP */
1452
1453-/** The latch protecting the adaptive search system */
1454-#define btr_search_latch (*btr_search_latch_temp)
1455-
1456 /** Flag: has the search system been enabled?
1457 Protected by btr_search_latch. */
1458 extern char btr_search_enabled;
1459
1460+/** Number of adaptive hash index partitions */
1461+extern ulint btr_search_index_num;
1462+
1463 #ifdef UNIV_BLOB_DEBUG
1464 # include "buf0types.h"
1465 /** An index->blobs entry for keeping track of off-page column references */
1466
1467=== modified file 'Percona-Server/storage/innobase/include/buf0buf.h'
1468--- Percona-Server/storage/innobase/include/buf0buf.h 2013-08-26 15:36:54 +0000
1469+++ Percona-Server/storage/innobase/include/buf0buf.h 2013-08-28 08:09:39 +0000
1470@@ -1700,6 +1700,8 @@
1471 complete, though: there may
1472 have been hash collisions,
1473 record deletions, etc. */
1474+ rw_lock_t* btr_search_latch;/*!< Adaptive hash index latch for the
1475+ index this block belongs to or NULL */
1476 /* @} */
1477 # ifdef UNIV_SYNC_DEBUG
1478 /** @name Debug fields */
1479
1480=== modified file 'Percona-Server/storage/innobase/include/mtr0log.ic'
1481--- Percona-Server/storage/innobase/include/mtr0log.ic 2013-08-06 15:16:34 +0000
1482+++ Percona-Server/storage/innobase/include/mtr0log.ic 2013-08-28 08:09:39 +0000
1483@@ -28,6 +28,7 @@
1484 #include "buf0buf.h"
1485 #include "buf0dblwr.h"
1486 #include "fsp0types.h"
1487+#include "btr0types.h"
1488 #include "trx0sys.h"
1489
1490 /********************************************************//**
1491
1492=== modified file 'Percona-Server/storage/innobase/include/que0que.h'
1493--- Percona-Server/storage/innobase/include/que0que.h 2013-08-06 15:16:34 +0000
1494+++ Percona-Server/storage/innobase/include/que0que.h 2013-08-28 08:09:39 +0000
1495@@ -29,6 +29,7 @@
1496 #include "univ.i"
1497 #include "data0data.h"
1498 #include "dict0types.h"
1499+#include "btr0sea.h"
1500 #include "trx0trx.h"
1501 #include "trx0roll.h"
1502 #include "srv0srv.h"
1503
1504=== modified file 'Percona-Server/storage/innobase/include/read0read.h'
1505--- Percona-Server/storage/innobase/include/read0read.h 2013-08-06 15:16:34 +0000
1506+++ Percona-Server/storage/innobase/include/read0read.h 2013-08-28 08:09:39 +0000
1507@@ -31,6 +31,7 @@
1508
1509 #include "ut0byte.h"
1510 #include "ut0lst.h"
1511+#include "btr0types.h"
1512 #include "trx0trx.h"
1513 #include "trx0sys.h"
1514 #include "read0types.h"
1515
1516=== modified file 'Percona-Server/storage/innobase/include/trx0roll.h'
1517--- Percona-Server/storage/innobase/include/trx0roll.h 2013-08-06 15:16:34 +0000
1518+++ Percona-Server/storage/innobase/include/trx0roll.h 2013-08-28 08:09:39 +0000
1519@@ -27,6 +27,7 @@
1520 #define trx0roll_h
1521
1522 #include "univ.i"
1523+#include "btr0types.h"
1524 #include "trx0trx.h"
1525 #include "trx0types.h"
1526 #include "mtr0mtr.h"
1527
1528=== modified file 'Percona-Server/storage/innobase/include/trx0trx.h'
1529--- Percona-Server/storage/innobase/include/trx0trx.h 2013-08-06 15:16:34 +0000
1530+++ Percona-Server/storage/innobase/include/trx0trx.h 2013-08-28 08:09:39 +0000
1531@@ -1136,10 +1136,7 @@
1532
1533 Bear in mind (3) and (4) when using the hash index.
1534 */
1535-extern rw_lock_t* btr_search_latch_temp;
1536-
1537-/** The latch protecting the adaptive search system */
1538-#define btr_search_latch (*btr_search_latch_temp)
1539+extern rw_lock_t** btr_search_latch_temp_arr;
1540
1541 #ifndef UNIV_NONINL
1542 #include "trx0trx.ic"
1543
1544=== modified file 'Percona-Server/storage/innobase/include/trx0trx.ic'
1545--- Percona-Server/storage/innobase/include/trx0trx.ic 2013-08-06 15:16:34 +0000
1546+++ Percona-Server/storage/innobase/include/trx0trx.ic 2013-08-28 08:09:39 +0000
1547@@ -164,7 +164,7 @@
1548 }
1549
1550 /********************************************************************//**
1551-Releases the search latch if trx has reserved it. */
1552+Releases the search latches if trx has reserved them. */
1553 UNIV_INLINE
1554 void
1555 trx_search_latch_release_if_reserved(
1556@@ -172,7 +172,13 @@
1557 trx_t* trx) /*!< in: transaction */
1558 {
1559 if (trx->has_search_latch) {
1560- rw_lock_s_unlock(&btr_search_latch);
1561+ ulint i;
1562+
1563+ for (i = 0; i < btr_search_index_num; i++) {
1564+ if (trx->has_search_latch & (1UL << i)) {
1565+ rw_lock_s_unlock(btr_search_latch_temp_arr[i]);
1566+ }
1567+ }
1568
1569 trx->has_search_latch = FALSE;
1570 }
1571
1572=== modified file 'Percona-Server/storage/innobase/include/univ.i'
1573--- Percona-Server/storage/innobase/include/univ.i 2013-08-06 15:16:34 +0000
1574+++ Percona-Server/storage/innobase/include/univ.i 2013-08-28 08:09:39 +0000
1575@@ -179,7 +179,6 @@
1576 #define UNIV_COMPILE_TEST_FUNCS
1577 */
1578
1579-#undef UNIV_SYNC_DEBUG
1580 #if defined HAVE_VALGRIND
1581 # define UNIV_DEBUG_VALGRIND
1582 #endif /* HAVE_VALGRIND */
1583
1584=== modified file 'Percona-Server/storage/innobase/os/os0file.cc'
1585--- Percona-Server/storage/innobase/os/os0file.cc 2013-08-21 07:19:25 +0000
1586+++ Percona-Server/storage/innobase/os/os0file.cc 2013-08-28 08:09:39 +0000
1587@@ -43,6 +43,7 @@
1588 #include "srv0start.h"
1589 #include "fil0fil.h"
1590 #include "buf0buf.h"
1591+#include "btr0types.h"
1592 #include "trx0trx.h"
1593 #include "srv0mon.h"
1594 #ifndef UNIV_HOTBACKUP
1595
1596=== modified file 'Percona-Server/storage/innobase/row/row0sel.cc'
1597--- Percona-Server/storage/innobase/row/row0sel.cc 2013-08-14 03:57:21 +0000
1598+++ Percona-Server/storage/innobase/row/row0sel.cc 2013-08-28 08:09:39 +0000
1599@@ -1233,7 +1233,8 @@
1600 ut_ad(!plan->must_get_clust);
1601 #ifdef UNIV_SYNC_DEBUG
1602 if (search_latch_locked) {
1603- ut_ad(rw_lock_own(&btr_search_latch, RW_LOCK_SHARED));
1604+ ut_ad(rw_lock_own(btr_search_get_latch(index->id),
1605+ RW_LOCK_SHARED));
1606 }
1607 #endif /* UNIV_SYNC_DEBUG */
1608
1609@@ -1405,10 +1406,11 @@
1610 && !plan->must_get_clust
1611 && !plan->table->big_rows) {
1612 if (!search_latch_locked) {
1613- rw_lock_s_lock(&btr_search_latch);
1614+ rw_lock_s_lock(btr_search_get_latch(index->id));
1615
1616 search_latch_locked = TRUE;
1617- } else if (rw_lock_get_writer(&btr_search_latch) == RW_LOCK_WAIT_EX) {
1618+ } else if (rw_lock_get_writer(btr_search_get_latch(index->id))
1619+ == RW_LOCK_WAIT_EX) {
1620
1621 /* There is an x-latch request waiting: release the
1622 s-latch for a moment; as an s-latch here is often
1623@@ -1417,8 +1419,8 @@
1624 from acquiring an s-latch for a long time, lowering
1625 performance significantly in multiprocessors. */
1626
1627- rw_lock_s_unlock(&btr_search_latch);
1628- rw_lock_s_lock(&btr_search_latch);
1629+ rw_lock_s_unlock(btr_search_get_latch(index->id));
1630+ rw_lock_s_lock(btr_search_get_latch(index->id));
1631 }
1632
1633 found_flag = row_sel_try_search_shortcut(node, plan,
1634@@ -1443,7 +1445,7 @@
1635 }
1636
1637 if (search_latch_locked) {
1638- rw_lock_s_unlock(&btr_search_latch);
1639+ rw_lock_s_unlock(btr_search_get_latch(index->id));
1640
1641 search_latch_locked = FALSE;
1642 }
1643@@ -2019,7 +2021,7 @@
1644
1645 func_exit:
1646 if (search_latch_locked) {
1647- rw_lock_s_unlock(&btr_search_latch);
1648+ rw_lock_s_unlock(btr_search_get_latch(index->id));
1649 }
1650 if (UNIV_LIKELY_NULL(heap)) {
1651 mem_heap_free(heap);
1652@@ -3597,6 +3599,47 @@
1653 }
1654
1655 /********************************************************************//**
1656+Acquires an S latch for the adaptive hash index for a given index tree if is
1657+not acquired already. If the current transaction already owns a latch with
1658+a higher index in the latch array, release all the already-held S latches
1659+and reacquire them together with the desired latch to honor the latching
1660+order. */
1661+static
1662+void
1663+trx_search_latch_lock(
1664+/*==================*/
1665+ trx_t* trx, /*!< in: latching transcation */
1666+ ulint index_id) /*!< in: index to latch AHI for */
1667+{
1668+ ulint latch_mask = 1UL << (index_id % btr_search_index_num);
1669+
1670+ if (!(trx->has_search_latch & latch_mask)) {
1671+
1672+ if (trx->has_search_latch < latch_mask) {
1673+
1674+ rw_lock_s_lock(btr_search_get_latch(index_id));
1675+ trx->has_search_latch |= latch_mask;
1676+ } else {
1677+
1678+ ibool taken_latches = trx->has_search_latch;
1679+
1680+ trx_search_latch_release_if_reserved(trx);
1681+
1682+ trx->has_search_latch = taken_latches | latch_mask;
1683+
1684+ for (ulint i = 0; i < btr_search_index_num; i++) {
1685+ if (trx->has_search_latch & (1UL << i)) {
1686+
1687+ rw_lock_s_lock(
1688+ btr_search_latch_temp_arr[i]);
1689+ }
1690+ }
1691+ }
1692+ }
1693+}
1694+
1695+
1696+/********************************************************************//**
1697 Searches for rows in the database. This is used in the interface to
1698 MySQL. This function opens a cursor, and also implements fetch next
1699 and fetch prev. NOTE that if we do a search with a full key value
1700@@ -3658,6 +3701,7 @@
1701 ulint* offsets = offsets_;
1702 ibool table_lock_waited = FALSE;
1703 byte* next_buf = 0;
1704+ bool should_release;
1705
1706 rec_offs_init(offsets_);
1707
1708@@ -3733,19 +3777,29 @@
1709 (ulong) trx->mysql_n_tables_locked);
1710 #endif
1711 /*-------------------------------------------------------------*/
1712- /* PHASE 0: Release a possible s-latch we are holding on the
1713- adaptive hash index latch if there is someone waiting behind */
1714-
1715- if (UNIV_UNLIKELY(rw_lock_get_writer(&btr_search_latch) != RW_LOCK_NOT_LOCKED)
1716- && trx->has_search_latch) {
1717+ /* PHASE 0: Release possible latches we are holding on the
1718+ adaptive hash index latches if there is someone waiting behind */
1719+
1720+ should_release = false;
1721+ for (ulint i = 0; i < btr_search_index_num; i++) {
1722+ /* we should check all latches (fix Bug#791030) */
1723+ if (UNIV_UNLIKELY(rw_lock_get_writer(
1724+ btr_search_latch_temp_arr[i])
1725+ != RW_LOCK_NOT_LOCKED)) {
1726+ should_release = true;
1727+ break;
1728+ }
1729+ }
1730+
1731+ if (UNIV_UNLIKELY(should_release)) {
1732
1733 /* There is an x-latch request on the adaptive hash index:
1734 release the s-latch to reduce starvation and wait for
1735 BTR_SEA_TIMEOUT rounds before trying to keep it again over
1736 calls from MySQL */
1737
1738- rw_lock_s_unlock(&btr_search_latch);
1739- trx->has_search_latch = FALSE;
1740+ /* We should release all s-latches (fix Bug#791030) */
1741+ trx_search_latch_release_if_reserved(trx);
1742
1743 trx->search_latch_timeout = BTR_SEA_TIMEOUT;
1744 }
1745@@ -3896,10 +3950,7 @@
1746 hash index semaphore! */
1747
1748 #ifndef UNIV_SEARCH_DEBUG
1749- if (!trx->has_search_latch) {
1750- rw_lock_s_lock(&btr_search_latch);
1751- trx->has_search_latch = TRUE;
1752- }
1753+ trx_search_latch_lock(trx, index->id);
1754 #endif
1755 switch (row_sel_try_search_shortcut_for_mysql(
1756 &rec, prebuilt, &offsets, &heap,
1757@@ -3969,8 +4020,8 @@
1758
1759 trx->search_latch_timeout--;
1760
1761- rw_lock_s_unlock(&btr_search_latch);
1762- trx->has_search_latch = FALSE;
1763+ trx_search_latch_release_if_reserved(
1764+ trx);
1765 }
1766
1767 /* NOTE that we do NOT store the cursor
1768@@ -3992,10 +4043,7 @@
1769 /*-------------------------------------------------------------*/
1770 /* PHASE 3: Open or restore index cursor position */
1771
1772- if (trx->has_search_latch) {
1773- rw_lock_s_unlock(&btr_search_latch);
1774- trx->has_search_latch = FALSE;
1775- }
1776+ trx_search_latch_release_if_reserved(trx);
1777
1778 /* The state of a running trx can only be changed by the
1779 thread that is currently serving the transaction. Because we
1780
1781=== modified file 'Percona-Server/storage/innobase/srv/srv0conc.cc'
1782--- Percona-Server/storage/innobase/srv/srv0conc.cc 2013-05-10 08:51:53 +0000
1783+++ Percona-Server/storage/innobase/srv/srv0conc.cc 2013-08-28 08:09:39 +0000
1784@@ -39,6 +39,7 @@
1785
1786 #include "srv0srv.h"
1787 #include "sync0sync.h"
1788+#include "btr0types.h"
1789 #include "trx0trx.h"
1790
1791 #include "mysql/plugin.h"
1792
1793=== modified file 'Percona-Server/storage/innobase/srv/srv0srv.cc'
1794--- Percona-Server/storage/innobase/srv/srv0srv.cc 2013-08-14 03:57:21 +0000
1795+++ Percona-Server/storage/innobase/srv/srv0srv.cc 2013-08-28 08:09:39 +0000
1796@@ -1308,17 +1308,20 @@
1797 os_atomic_increment_lint(&srv_read_views_memory, 0));
1798
1799 /* Calculate reserved memories */
1800- if (btr_search_sys && btr_search_sys->hash_index->heap) {
1801+ if (btr_search_sys && btr_search_sys->hash_index[0]->heap) {
1802 btr_search_sys_subtotal
1803- = mem_heap_get_size(btr_search_sys->hash_index->heap);
1804+ = mem_heap_get_size(btr_search_sys->hash_index[0]
1805+ ->heap);
1806 } else {
1807 btr_search_sys_subtotal = 0;
1808- for (i=0; i < btr_search_sys->hash_index->n_sync_obj; i++) {
1809+ for (i=0; i < btr_search_sys->hash_index[0]->n_sync_obj; i++) {
1810 btr_search_sys_subtotal
1811 += mem_heap_get_size(
1812- btr_search_sys->hash_index->heaps[i]);
1813+ btr_search_sys->hash_index[0]
1814+ ->heaps[i]);
1815 }
1816 }
1817+ btr_search_sys_subtotal *= btr_search_index_num;
1818
1819 lock_sys_subtotal = 0;
1820 if (trx_sys) {
1821@@ -1347,13 +1350,15 @@
1822 " Recovery system %lu \t(%lu + " ULINTPF ")\n",
1823
1824 (ulong) (btr_search_sys
1825- ? (btr_search_sys->hash_index->n_cells
1826- * sizeof(hash_cell_t))
1827+ ? (btr_search_sys->hash_index[0]->n_cells
1828+ * sizeof(hash_cell_t)
1829+ * btr_search_index_num)
1830 : 0)
1831 + btr_search_sys_subtotal,
1832 (ulong) (btr_search_sys
1833- ? (btr_search_sys->hash_index->n_cells
1834- * sizeof(hash_cell_t))
1835+ ? (btr_search_sys->hash_index[0]->n_cells
1836+ * sizeof(hash_cell_t)
1837+ * btr_search_index_num)
1838 : 0),
1839 btr_search_sys_subtotal,
1840
1841@@ -1504,21 +1509,23 @@
1842 buf_get_total_list_len(&LRU_len, &free_len, &flush_list_len);
1843 buf_get_total_list_size_in_bytes(&buf_pools_list_size);
1844
1845- if (btr_search_sys && btr_search_sys->hash_index->heap) {
1846+ if (btr_search_sys && btr_search_sys->hash_index[0]->heap) {
1847 mem_adaptive_hash
1848- = mem_heap_get_size(btr_search_sys->hash_index->heap);
1849+ = mem_heap_get_size(btr_search_sys
1850+ ->hash_index[0]->heap);
1851 } else {
1852 mem_adaptive_hash = 0;
1853- for (i=0; i < btr_search_sys->hash_index->n_sync_obj; i++) {
1854+ for (i=0; i < btr_search_sys->hash_index[0]->n_sync_obj; i++) {
1855 mem_adaptive_hash
1856 += mem_heap_get_size
1857- (btr_search_sys->hash_index->heaps[i]);
1858+ (btr_search_sys->hash_index[0]->heaps[i]);
1859 }
1860 }
1861 if (btr_search_sys) {
1862- mem_adaptive_hash += (btr_search_sys->hash_index->n_cells
1863+ mem_adaptive_hash += (btr_search_sys->hash_index[0]->n_cells
1864 * sizeof(hash_cell_t));
1865 }
1866+ mem_adaptive_hash *= btr_search_index_num;
1867
1868 mem_dictionary = (dict_sys ? ((dict_sys->table_hash->n_cells
1869 + dict_sys->table_id_hash->n_cells
1870
1871=== modified file 'Percona-Server/storage/innobase/sync/sync0sync.cc'
1872--- Percona-Server/storage/innobase/sync/sync0sync.cc 2013-08-06 15:16:34 +0000
1873+++ Percona-Server/storage/innobase/sync/sync0sync.cc 2013-08-28 08:09:39 +0000
1874@@ -38,6 +38,7 @@
1875 #include "sync0rw.h"
1876 #include "buf0buf.h"
1877 #include "srv0srv.h"
1878+#include "btr0types.h"
1879 #include "buf0types.h"
1880 #include "os0sync.h" /* for HAVE_ATOMIC_BUILTINS */
1881 #ifdef UNIV_SYNC_DEBUG
1882@@ -1149,7 +1150,6 @@
1883 case SYNC_ANY_LATCH:
1884 case SYNC_FILE_FORMAT_TAG:
1885 case SYNC_DOUBLEWRITE:
1886- case SYNC_SEARCH_SYS:
1887 case SYNC_THREADS:
1888 case SYNC_LOCK_SYS:
1889 case SYNC_LOCK_WAIT_SYS:
1890@@ -1182,6 +1182,26 @@
1891 ut_a(sync_thread_levels_contain(array, SYNC_LOCK_SYS));
1892 }
1893 break;
1894+ case SYNC_SEARCH_SYS: {
1895+ /* Verify the lock order inside the split btr_search_latch
1896+ array */
1897+ bool found_current = false;
1898+ for (ulint i = 0; i < btr_search_index_num; i++) {
1899+ if (btr_search_latch_temp_arr[i] == latch) {
1900+ found_current = true;
1901+ } else if (found_current) {
1902+ ut_ad(!rw_lock_own(
1903+ btr_search_latch_temp_arr[i],
1904+ RW_LOCK_SHARED));
1905+ ut_ad(!rw_lock_own(
1906+ btr_search_latch_temp_arr[i],
1907+ RW_LOCK_EX));
1908+ }
1909+ }
1910+ ut_ad(found_current);
1911+
1912+ /* fallthrough */
1913+ }
1914 case SYNC_BUF_FLUSH_LIST:
1915 case SYNC_BUF_POOL:
1916 /* We can have multiple mutexes of this type therefore we
1917
1918=== modified file 'Percona-Server/storage/innobase/trx/trx0trx.cc'
1919--- Percona-Server/storage/innobase/trx/trx0trx.cc 2013-08-06 15:16:34 +0000
1920+++ Percona-Server/storage/innobase/trx/trx0trx.cc 2013-08-28 08:09:39 +0000
1921@@ -23,6 +23,7 @@
1922 Created 3/26/1996 Heikki Tuuri
1923 *******************************************************/
1924
1925+#include "btr0types.h"
1926 #include "trx0trx.h"
1927
1928 #ifdef UNIV_NONINL
1929
1930=== modified file 'Percona-Server/storage/innobase/ut/ut0ut.cc'
1931--- Percona-Server/storage/innobase/ut/ut0ut.cc 2013-08-06 15:16:34 +0000
1932+++ Percona-Server/storage/innobase/ut/ut0ut.cc 2013-08-28 08:09:39 +0000
1933@@ -39,6 +39,7 @@
1934 #include <ctype.h>
1935
1936 #ifndef UNIV_HOTBACKUP
1937+# include "btr0types.h"
1938 # include "trx0trx.h"
1939 # include "ha_prototypes.h"
1940 # include "mysql_com.h" /* NAME_LEN */

Subscribers

People subscribed via source and target branches