Skip to content

Commit f173bcf

Browse files
Dmitry LenevDmitry Lenev
Dmitry Lenev
authored and
Dmitry Lenev
committed
Merged fix for bug #16396598 "MDL HASH CAN STILL BE
CONCURRENCY BOTTLENECK" into mysql-trunk.
2 parents 8600a39 + dfbe3ed commit f173bcf

File tree

9 files changed

+339
-14
lines changed

9 files changed

+339
-14
lines changed

include/hash.h

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
1+
/* Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
22
33
This program is free software; you can redistribute it and/or modify
44
it under the terms of the GNU General Public License as published by
@@ -45,9 +45,19 @@ extern "C" {
4545
/* flags for hash_init */
4646
#define HASH_UNIQUE 1 /* hash_insert fails on duplicate key */
4747

48+
struct st_hash;
4849
typedef uint my_hash_value_type;
4950
typedef uchar *(*my_hash_get_key)(const uchar *,size_t*,my_bool);
5051
typedef void (*my_hash_free_key)(void *);
52+
/**
53+
Function type representing a hash function to be used with the HASH
54+
container.
55+
Should accept pointer to HASH, pointer to key buffer and key length
56+
as parameters.
57+
*/
58+
typedef my_hash_value_type (*my_hash_function)(const struct st_hash *,
59+
const uchar *,
60+
size_t);
5161

5262
typedef struct st_hash {
5363
size_t key_offset,key_length; /* Length of key if const length */
@@ -58,16 +68,20 @@ typedef struct st_hash {
5868
my_hash_get_key get_key;
5969
void (*free)(void *);
6070
CHARSET_INFO *charset;
71+
my_hash_function hash_function;
6172
} HASH;
6273

6374
/* A search iterator state */
6475
typedef uint HASH_SEARCH_STATE;
6576

6677
#define my_hash_init(A,B,C,D,E,F,G,H) \
67-
_my_hash_init(A,0,B,C,D,E,F,G,H)
78+
_my_hash_init(A,0,B,NULL,C,D,E,F,G,H)
6879
#define my_hash_init2(A,B,C,D,E,F,G,H,I) \
69-
_my_hash_init(A,B,C,D,E,F,G,H,I)
80+
_my_hash_init(A,B,C,NULL,D,E,F,G,H,I)
81+
#define my_hash_init3(A,B,C,D,E,F,G,H,I,J) \
82+
_my_hash_init(A,B,C,D,E,F,G,H,I,J)
7083
my_bool _my_hash_init(HASH *hash, uint growth_size, CHARSET_INFO *charset,
84+
my_hash_function hash_function,
7185
ulong default_array_elements, size_t key_offset,
7286
size_t key_length, my_hash_get_key get_key,
7387
void (*free_element)(void*),
@@ -100,7 +114,7 @@ my_bool my_hash_check(HASH *hash); /* Only in debug library */
100114
#define my_hash_clear(H) memset((H), 0, sizeof(*(H)))
101115
#define my_hash_inited(H) ((H)->blength != 0)
102116
#define my_hash_init_opt(A,B,C,D,E,F,G,H) \
103-
(!my_hash_inited(A) && _my_hash_init(A,0,B,C,D,E,F,G,H))
117+
(!my_hash_inited(A) && _my_hash_init(A,0,B,NULL,C,D,E,F,G,H))
104118

105119
#ifdef __cplusplus
106120
}

include/my_murmur3.h

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
#ifndef MY_MURMUR3_INCLUDED
2+
#define MY_MURMUR3_INCLUDED
3+
4+
/* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
5+
6+
This program is free software; you can redistribute it and/or modify
7+
it under the terms of the GNU General Public License as published by
8+
the Free Software Foundation; version 2 of the License.
9+
10+
This program is distributed in the hope that it will be useful,
11+
but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
GNU General Public License for more details.
14+
15+
You should have received a copy of the GNU General Public License
16+
along with this program; if not, write to the Free Software
17+
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */
18+
19+
#include <my_global.h>
20+
21+
C_MODE_START
22+
23+
uint32 murmur3_32(const uchar * key, size_t len, uint32 seed);
24+
25+
C_MODE_END
26+
27+
#endif /* MY_MURMUR3_INCLUDED */

mysql-test/suite/perfschema/r/mdl_func.result

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -268,7 +268,7 @@ OPERATION metadata lock
268268
execute dump_waits_history_long;
269269
THREAD_ID USER2
270270
EVENT_NAME wait/lock/metadata/sql/mdl
271-
SOURCE mdl.cc:2254
271+
SOURCE mdl.cc:2275
272272
TIMER_START_SET 1
273273
TIMER_END_SET 1
274274
OBJECT_TYPE TABLE
@@ -425,7 +425,7 @@ execute dump_waits_current;
425425
execute dump_waits_history_long;
426426
THREAD_ID USER2
427427
EVENT_NAME wait/lock/metadata/sql/mdl
428-
SOURCE mdl.cc:2254
428+
SOURCE mdl.cc:2275
429429
TIMER_START_SET 1
430430
TIMER_END_SET 1
431431
OBJECT_TYPE TABLE
@@ -498,7 +498,7 @@ OPERATION metadata lock
498498
execute dump_waits_history_long;
499499
THREAD_ID USER2
500500
EVENT_NAME wait/lock/metadata/sql/mdl
501-
SOURCE mdl.cc:2254
501+
SOURCE mdl.cc:2275
502502
TIMER_START_SET 1
503503
TIMER_END_SET 1
504504
OBJECT_TYPE TABLE
@@ -541,7 +541,7 @@ execute dump_waits_current;
541541
execute dump_waits_history_long;
542542
THREAD_ID USER2
543543
EVENT_NAME wait/lock/metadata/sql/mdl
544-
SOURCE mdl.cc:2254
544+
SOURCE mdl.cc:2275
545545
TIMER_START_SET 1
546546
TIMER_END_SET 1
547547
OBJECT_TYPE TABLE
@@ -551,7 +551,7 @@ INDEX_NAME NULL
551551
OPERATION metadata lock
552552
THREAD_ID USER1
553553
EVENT_NAME wait/lock/metadata/sql/mdl
554-
SOURCE mdl.cc:2254
554+
SOURCE mdl.cc:2275
555555
TIMER_START_SET 1
556556
TIMER_END_SET 1
557557
OBJECT_TYPE TABLE
@@ -594,7 +594,7 @@ execute dump_waits_current;
594594
execute dump_waits_history_long;
595595
THREAD_ID USER2
596596
EVENT_NAME wait/lock/metadata/sql/mdl
597-
SOURCE mdl.cc:2254
597+
SOURCE mdl.cc:2275
598598
TIMER_START_SET 1
599599
TIMER_END_SET 1
600600
OBJECT_TYPE TABLE
@@ -604,7 +604,7 @@ INDEX_NAME NULL
604604
OPERATION metadata lock
605605
THREAD_ID USER1
606606
EVENT_NAME wait/lock/metadata/sql/mdl
607-
SOURCE mdl.cc:2254
607+
SOURCE mdl.cc:2275
608608
TIMER_START_SET 1
609609
TIMER_END_SET 1
610610
OBJECT_TYPE TABLE

mysys/hash.c

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,12 +41,26 @@ static int hashcmp(const HASH *hash, HASH_LINK *pos, const uchar *key,
4141

4242
static my_hash_value_type calc_hash(const HASH *hash,
4343
const uchar *key, size_t length)
44+
{
45+
return hash->hash_function(hash, key, length);
46+
}
47+
48+
49+
/**
50+
Adaptor function which allows to use hash function from character
51+
set with HASH.
52+
*/
53+
54+
static my_hash_value_type cset_hash_sort_adapter(const HASH *hash,
55+
const uchar *key,
56+
size_t length)
4457
{
4558
ulong nr1=1, nr2=4;
4659
hash->charset->coll->hash_sort(hash->charset,(uchar*) key,length,&nr1,&nr2);
4760
return (my_hash_value_type)nr1;
4861
}
4962

63+
5064
/**
5165
@brief Initialize the hash
5266
@@ -60,6 +74,9 @@ static my_hash_value_type calc_hash(const HASH *hash,
6074
6175
@param[in,out] hash The hash that is initialized
6276
@param[in] charset The charater set information
77+
@param[in] hash_function Hash function to be used. NULL -
78+
use standard hash from character
79+
set.
6380
@param[in] size The hash size
6481
@param[in] key_offest The key offset for the hash
6582
@param[in] key_length The length of the key used in
@@ -74,6 +91,7 @@ static my_hash_value_type calc_hash(const HASH *hash,
7491
*/
7592
my_bool
7693
_my_hash_init(HASH *hash, uint growth_size, CHARSET_INFO *charset,
94+
my_hash_function hash_function,
7795
ulong size, size_t key_offset, size_t key_length,
7896
my_hash_get_key get_key,
7997
void (*free_element)(void*), uint flags)
@@ -89,6 +107,7 @@ _my_hash_init(HASH *hash, uint growth_size, CHARSET_INFO *charset,
89107
hash->free=free_element;
90108
hash->flags=flags;
91109
hash->charset=charset;
110+
hash->hash_function= hash_function ? hash_function : cset_hash_sort_adapter;
92111
DBUG_RETURN(my_init_dynamic_array_ci(&hash->array,
93112
sizeof(HASH_LINK), size, growth_size));
94113
}

mysys_ssl/CMakeLists.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
1+
# Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
22
#
33
# This program is free software; you can redistribute it and/or modify
44
# it under the terms of the GNU General Public License as published by
@@ -43,6 +43,7 @@ SET(MYSYS_SSL_SOURCES
4343
my_sha2.cc
4444
my_md5.cc
4545
my_rnd.cc
46+
my_murmur3.cc
4647
)
4748

4849
ADD_CONVENIENCE_LIBRARY(mysys_ssl ${MYSYS_SSL_SOURCES})

mysys_ssl/my_murmur3.cc

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
/* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
2+
3+
This program is free software; you can redistribute it and/or modify
4+
it under the terms of the GNU General Public License as published by
5+
the Free Software Foundation; version 2 of the License.
6+
7+
This program is distributed in the hope that it will be useful,
8+
but WITHOUT ANY WARRANTY; without even the implied warranty of
9+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10+
GNU General Public License for more details.
11+
12+
You should have received a copy of the GNU General Public License
13+
along with this program; if not, write to the Free Software
14+
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */
15+
16+
/*
17+
Implementation of 32-bit version of MurmurHash3 - fast non-cryptographic
18+
hash function with good statistical properties, which is based on public
19+
domain code by Austin Appleby.
20+
*/
21+
22+
#include <my_murmur3.h>
23+
24+
25+
/*
26+
Platform-specific implementations of ROTL32 helper.
27+
*/
28+
29+
#if defined(_MSC_VER)
30+
31+
/* Microsoft Visual Studio supports intrinsic for rotate left. */
32+
33+
#include <stdlib.h>
34+
35+
#define ROTL32(x, y) _rotl(x, y)
36+
37+
/*
38+
Force inlining of intrinsic even though /Oi option is turned off
39+
in release builds.
40+
*/
41+
#pragma intrinsic(_rotl)
42+
43+
#else // !defined(_MSC_VER)
44+
45+
/*
46+
Many other compilers should be able to optimize the below
47+
function to single instruction.
48+
*/
49+
50+
inline uint32 rotl32 (uint32 x, char r)
51+
{
52+
return (x << r) | (x >> (32 - r));
53+
}
54+
55+
#define ROTL32(x,y) rotl32(x,y)
56+
57+
#endif // !defined(_MSC_VER)
58+
59+
60+
/**
61+
Compute 32-bit version of MurmurHash3 hash for the key.
62+
63+
@param key Key for which hash value to be computed.
64+
@param len Key length.
65+
@param seed Seed for hash computation.
66+
67+
@note WARNING! Since MurmurHash3 is known to be susceptible to "hash DoS"
68+
attack it should not be used in any situation where attacker has
69+
control over key being hashed and thus can cause performance problems
70+
due to degradation of hash lookup to linear list search.
71+
72+
@returns Hash value for the key.
73+
*/
74+
75+
uint32 murmur3_32(const uchar *key, size_t len, uint32 seed)
76+
{
77+
const uchar *tail= key + (len - len % 4);
78+
79+
uint32 h1= seed;
80+
81+
/* Constants for magic numbers that are used more than once. */
82+
const uint32 c1= 0xcc9e2d51;
83+
const uint32 c2= 0x1b873593;
84+
85+
/* Body: process all 32-bit blocks in the key. */
86+
87+
for (const uchar *data= key; data != tail; data+= 4)
88+
{
89+
uint32 k1= uint4korr(data);
90+
91+
k1*= c1;
92+
k1= ROTL32(k1, 15);
93+
k1*= c2;
94+
95+
h1^= k1;
96+
h1= ROTL32(h1, 13);
97+
h1= h1 * 5 + 0xe6546b64;
98+
}
99+
100+
/* Tail: handle remaining len % 4 bytes. */
101+
102+
uint32 k1= 0;
103+
104+
switch(len % 4)
105+
{
106+
case 3:
107+
k1^= static_cast<uint32>(tail[2]) << 16;
108+
/* Fall through. */
109+
case 2:
110+
k1^= static_cast<uint32>(tail[1]) << 8;
111+
/* Fall through. */
112+
case 1:
113+
k1^= tail[0];
114+
k1*= c1;
115+
k1= ROTL32(k1, 15);
116+
k1*= c2;
117+
h1^= k1;
118+
};
119+
120+
/*
121+
Finalization mix:
122+
Add length and force all bits of a hash block to avalanche.
123+
*/
124+
125+
h1^= len;
126+
127+
h1^= h1 >> 16;
128+
h1*= 0x85ebca6b;
129+
h1^= h1 >> 13;
130+
h1*= 0xc2b2ae35;
131+
h1^= h1 >> 16;
132+
133+
return h1;
134+
}

sql/mdl.cc

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include <mysql/psi/mysql_mdl.h>
2626
#include <pfs_stage_provider.h>
2727
#include <mysql/psi/mysql_stage.h>
28+
#include <my_murmur3.h>
2829

2930
static PSI_memory_key key_memory_MDL_context_acquire_locks;
3031

@@ -730,13 +731,33 @@ void MDL_map::init()
730731
}
731732

732733

734+
/**
735+
Adapter function which allows to use murmur3 with our HASH implementation.
736+
*/
737+
738+
extern "C" my_hash_value_type murmur3_adapter(const HASH*, const uchar *key,
739+
size_t length)
740+
{
741+
return murmur3_32(key, length, 0);
742+
}
743+
744+
733745
/** Initialize the partition in the container with all MDL locks. */
734746

735747
MDL_map_partition::MDL_map_partition()
736748
{
737749
mysql_mutex_init(key_MDL_map_mutex, &m_mutex, NULL);
738-
my_hash_init(&m_locks, &my_charset_bin, 16 /* FIXME */, 0, 0,
739-
mdl_locks_key, 0, 0);
750+
/*
751+
Lower bits of values produced by hash function which is used in 'm_locks'
752+
HASH container are also to select specific MDL_map_partition instance.
753+
This means that this hash function needs to hash key value in such
754+
a way that lower bits in result are sufficiently random. Since standard
755+
hash function from 'my_charset_bin' doesn't satisfy this criteria we use
756+
MurmurHash3 instead.
757+
*/
758+
my_hash_init3(&m_locks, 0, &my_charset_bin, murmur3_adapter,
759+
16 /* FIXME */, 0, 0, mdl_locks_key,
760+
0, 0);
740761
};
741762

742763

0 commit comments

Comments
 (0)