Merge lp:~vlad-lesin/percona-server/5.6-bug-1038940-table_cache_speed_up into lp:percona-server/5.6

Proposed by Vlad Lesin on 2013-02-25
Status: Work in progress
Proposed branch: lp:~vlad-lesin/percona-server/5.6-bug-1038940-table_cache_speed_up
Merge into: lp:percona-server/5.6
Diff against target: 346 lines (+118/-40)
10 files modified
Percona-Server/storage/myisam/ha_myisam.cc (+3/-0)
Percona-Server/storage/myisam/mi_close.c (+4/-7)
Percona-Server/storage/myisam/mi_dbug.c (+3/-3)
Percona-Server/storage/myisam/mi_keycache.c (+3/-3)
Percona-Server/storage/myisam/mi_open.c (+66/-13)
Percona-Server/storage/myisam/mi_panic.c (+24/-8)
Percona-Server/storage/myisam/mi_static.c (+1/-1)
Percona-Server/storage/myisam/myisamchk.c (+6/-0)
Percona-Server/storage/myisam/myisamdef.h (+3/-3)
Percona-Server/storage/myisam/myisampack.c (+5/-2)
To merge this branch: bzr merge lp:~vlad-lesin/percona-server/5.6-bug-1038940-table_cache_speed_up
Reviewer Review Type Date Requested Status
Laurynas Biveinis (community) 2013-02-25 Needs Fixing on 2013-03-25
Review via email: mp+150263@code.launchpad.net

Description of the change

This MP is port of this http://lists.mysql.com/commits/121507 patch to 5.6(see issue #25137). The main idea of this patch is to replace linked list of opened tables with hash-table to improve performance of open table lookup mechanism.

Jenkins tests:
http://jenkins.percona.com/view/PS%205.6/job/percona-server-5.6-param/43

To post a comment you must log in.

Spurious (C) change in diff lines 19-20.

The patch is OK, but I'll have to ask you to redo it as a GCA involving all three 5.1/5.5/5.6.

review: Needs Fixing

Unmerged revisions

317. By Vlad Lesin on 2013-02-24

As the number of open tables is increased, table lookup
(testing if a table is already open) and (in particular)
the case when a table is not open, became increasingly more
expensive.

The problem was caused by the open table lookup mechanism,
which was based on traversing a linked list comparing the
file names.

As the list was replaced by a hash table, the lookup
time dropped significantly when used on systems with
a large number of open tables.

The original patch can be found here:
http://lists.mysql.com/commits/121507

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'Percona-Server/storage/myisam/ha_myisam.cc'
2--- Percona-Server/storage/myisam/ha_myisam.cc 2013-01-18 04:53:12 +0000
3+++ Percona-Server/storage/myisam/ha_myisam.cc 2013-02-25 04:28:26 +0000
4@@ -2179,6 +2179,9 @@
5 myisam_hton->flags= HTON_CAN_RECREATE | HTON_SUPPORT_LOG_TABLES;
6 myisam_hton->is_supported_system_table= myisam_is_supported_system_table;
7
8+ if (mi_init_open_table_hash(table_cache_size))
9+ return 1;
10+
11 return 0;
12 }
13
14
15=== modified file 'Percona-Server/storage/myisam/mi_close.c'
16--- Percona-Server/storage/myisam/mi_close.c 2012-08-29 12:49:37 +0000
17+++ Percona-Server/storage/myisam/mi_close.c 2013-02-25 04:28:26 +0000
18@@ -1,4 +1,4 @@
19-/* Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
20+/* Copyright (c) 2001, 2011, Oracle and/or its affiliates. All rights reserved.
21
22 This program is free software; you can redistribute it and/or modify
23 it under the terms of the GNU General Public License as published by
24@@ -31,8 +31,7 @@
25 (long) info, (uint) share->reopen,
26 (uint) share->tot_locks));
27
28- if (info->open_list.data)
29- mysql_mutex_lock(&THR_LOCK_myisam);
30+ mysql_mutex_lock(&THR_LOCK_myisam);
31 if (info->lock_type == F_EXTRA_LCK)
32 info->lock_type=F_UNLCK; /* HA_EXTRA_NO_USER_CHANGE */
33
34@@ -55,8 +54,7 @@
35 info->opt_flag&= ~(READ_CACHE_USED | WRITE_CACHE_USED);
36 }
37 flag= !--share->reopen;
38- if (info->open_list.data)
39- myisam_open_list= list_delete(myisam_open_list, &info->open_list);
40+ my_hash_delete(&myisam_open_table_hash, (uchar *) info);
41 mysql_mutex_unlock(&share->intern_lock);
42
43 my_free(mi_get_rec_buff_ptr(info, info->rec_buff));
44@@ -110,8 +108,7 @@
45 }
46 my_free(info->s);
47 }
48- if (info->open_list.data)
49- mysql_mutex_unlock(&THR_LOCK_myisam);
50+ mysql_mutex_unlock(&THR_LOCK_myisam);
51 if (info->ftparser_param)
52 {
53 my_free(info->ftparser_param);
54
55=== modified file 'Percona-Server/storage/myisam/mi_dbug.c'
56--- Percona-Server/storage/myisam/mi_dbug.c 2012-03-06 14:29:42 +0000
57+++ Percona-Server/storage/myisam/mi_dbug.c 2013-02-25 04:28:26 +0000
58@@ -181,14 +181,14 @@
59 my_bool check_table_is_closed(const char *name, const char *where)
60 {
61 char filename[FN_REFLEN];
62- LIST *pos;
63+ uint idx;
64 DBUG_ENTER("check_table_is_closed");
65
66 (void) fn_format(filename,name,"",MI_NAME_IEXT,4+16+32);
67 mysql_mutex_lock(&THR_LOCK_myisam);
68- for (pos=myisam_open_list ; pos ; pos=pos->next)
69+ for (idx= 0; idx < myisam_open_table_hash.records; ++idx)
70 {
71- MI_INFO *info=(MI_INFO*) pos->data;
72+ MI_INFO *info=(MI_INFO*) my_hash_element(&myisam_open_table_hash, idx);
73 MYISAM_SHARE *share=info->s;
74 if (!strcmp(share->unique_file_name,filename))
75 {
76
77=== modified file 'Percona-Server/storage/myisam/mi_keycache.c'
78--- Percona-Server/storage/myisam/mi_keycache.c 2011-09-07 10:08:09 +0000
79+++ Percona-Server/storage/myisam/mi_keycache.c 2013-02-25 04:28:26 +0000
80@@ -138,16 +138,16 @@
81 void mi_change_key_cache(KEY_CACHE *old_key_cache,
82 KEY_CACHE *new_key_cache)
83 {
84- LIST *pos;
85+ uint idx;
86 DBUG_ENTER("mi_change_key_cache");
87
88 /*
89 Lock list to ensure that no one can close the table while we manipulate it
90 */
91 mysql_mutex_lock(&THR_LOCK_myisam);
92- for (pos=myisam_open_list ; pos ; pos=pos->next)
93+ for (idx= 0; idx < myisam_open_table_hash.records; ++idx)
94 {
95- MI_INFO *info= (MI_INFO*) pos->data;
96+ MI_INFO *info=(MI_INFO*) my_hash_element(&myisam_open_table_hash, idx);
97 MYISAM_SHARE *share= info->s;
98 if (share->key_cache == old_key_cache)
99 mi_assign_to_key_cache(info, (ulonglong) ~0, new_key_cache);
100
101=== modified file 'Percona-Server/storage/myisam/mi_open.c'
102--- Percona-Server/storage/myisam/mi_open.c 2012-11-14 11:44:35 +0000
103+++ Percona-Server/storage/myisam/mi_open.c 2013-02-25 04:28:26 +0000
104@@ -48,23 +48,76 @@
105 }
106
107
108-/******************************************************************************
109-** Return the shared struct if the table is already open.
110-** In MySQL the server will handle version issues.
111-******************************************************************************/
112-
113+/*
114+ Get the value used as hash key (helper function for the
115+ open table hash). Function is used as a callback
116+ from the hash table
117+*/
118+static uchar *mi_open_table_hash_key(const uchar *record, size_t *length,
119+ my_bool not_used __attribute__((unused)))
120+{
121+ MI_INFO *info= (MI_INFO *) record;
122+ *length= info->s->unique_name_length;
123+ return (uchar*) info->s->unique_file_name;
124+}
125+
126+/**
127+ Initialize open table hash
128+
129+ Function is normally called from myisam_init
130+ with the system variable table_cache_size used
131+ as hash_size.
132+
133+ @param[in] hash_size Initial has size (elements)
134+ @return inidicates success or failure of initialization
135+ @retval 0 success
136+ @retval 1 failure
137+
138+*/
139+int mi_init_open_table_hash(ulong hash_size)
140+{
141+ if (hash_size == 0)
142+ hash_size= 32; /* default hash size */
143+
144+ if (my_hash_init(&myisam_open_table_hash, &my_charset_filename,
145+ hash_size, 0, 0, mi_open_table_hash_key, 0, 0))
146+ return 1; /* error */
147+
148+ return 0;
149+}
150+
151+
152+/**
153+ Retrieve the shared struct if the table is already
154+ open (i.e in the open table hash)
155+
156+ @param[in] filename table file name
157+ @return shared struct, 0 if not in the cache
158+*/
159 MI_INFO *test_if_reopen(char *filename)
160 {
161- LIST *pos;
162+ HASH_SEARCH_STATE current_record;
163+ int len= strlen(filename);
164
165- for (pos=myisam_open_list ; pos ; pos=pos->next)
166+ MI_INFO *info= (MI_INFO*) my_hash_first(&myisam_open_table_hash,
167+ (uchar *) filename,
168+ len, &current_record);
169+ /*
170+ There might be more than one instance of a table share for
171+ a given table in the hash table. We're interested in the one with
172+ last_version set, so we iterate until we find it
173+ */
174+ while (info)
175 {
176- MI_INFO *info=(MI_INFO*) pos->data;
177 MYISAM_SHARE *share=info->s;
178- if (!strcmp(share->unique_file_name,filename) && share->last_version)
179- return info;
180+ if (share->last_version)
181+ break;
182+
183+ info= (MI_INFO*) my_hash_next(&myisam_open_table_hash,
184+ (uchar *) filename,
185+ len, &current_record);
186 }
187- return 0;
188+ return info;
189 }
190
191
192@@ -649,8 +702,8 @@
193
194 if (!internal_table)
195 {
196- m_info->open_list.data= (void*) m_info;
197- myisam_open_list= list_add(myisam_open_list, &m_info->open_list);
198+ if (my_hash_insert(&myisam_open_table_hash, (uchar *) m_info))
199+ goto err;
200 mysql_mutex_unlock(&THR_LOCK_myisam);
201 }
202
203
204=== modified file 'Percona-Server/storage/myisam/mi_panic.c'
205--- Percona-Server/storage/myisam/mi_panic.c 2011-09-07 10:08:09 +0000
206+++ Percona-Server/storage/myisam/mi_panic.c 2013-02-25 04:28:26 +0000
207@@ -27,22 +27,36 @@
208 int mi_panic(enum ha_panic_function flag)
209 {
210 int error=0;
211- LIST *list_element,*next_open;
212 MI_INFO *info;
213+ uint idx;
214 DBUG_ENTER("mi_panic");
215
216 mysql_mutex_lock(&THR_LOCK_myisam);
217- for (list_element=myisam_open_list ; list_element ; list_element=next_open)
218+
219+ if (!my_hash_inited(&myisam_open_table_hash))
220+ goto finish;
221+
222+ if (flag == HA_PANIC_CLOSE)
223 {
224- next_open=list_element->next; /* Save if close */
225- info=(MI_INFO*) list_element->data;
226- switch (flag) {
227- case HA_PANIC_CLOSE:
228+ while (myisam_open_table_hash.records)
229+ {
230+ /*
231+ As long as there are records in the hash, fetch the
232+ first, and close it.
233+ */
234+ info=(MI_INFO*) my_hash_element(&myisam_open_table_hash, 0);
235 mysql_mutex_unlock(&THR_LOCK_myisam); /* Not exactly right... */
236 if (mi_close(info))
237- error=my_errno;
238+ error= my_errno;
239 mysql_mutex_lock(&THR_LOCK_myisam);
240- break;
241+ }
242+ }
243+
244+ for (idx= 0; idx < myisam_open_table_hash.records; ++idx)
245+ {
246+ info=(MI_INFO*) my_hash_element(&myisam_open_table_hash, idx);
247+ switch (flag) {
248+ case HA_PANIC_CLOSE: break;
249 case HA_PANIC_WRITE: /* Do this to free databases */
250 #ifdef CANT_OPEN_FILES_TWICE
251 if (info->s->options & HA_OPTION_READ_ONLY_DATA)
252@@ -111,6 +125,8 @@
253 (void) mi_log(0); /* Close log if neaded */
254 ft_free_stopwords();
255 }
256+
257+finish:
258 mysql_mutex_unlock(&THR_LOCK_myisam);
259 if (!error)
260 DBUG_RETURN(0);
261
262=== modified file 'Percona-Server/storage/myisam/mi_static.c'
263--- Percona-Server/storage/myisam/mi_static.c 2011-12-09 21:08:37 +0000
264+++ Percona-Server/storage/myisam/mi_static.c 2013-02-25 04:28:26 +0000
265@@ -22,7 +22,7 @@
266 #include "myisamdef.h"
267 #endif
268
269-LIST *myisam_open_list=0;
270+HASH myisam_open_table_hash;
271 uchar myisam_file_magic[]=
272 { (uchar) 254, (uchar) 254,'\007', '\001', };
273 uchar myisam_pack_file_magic[]=
274
275=== modified file 'Percona-Server/storage/myisam/myisamchk.c'
276--- Percona-Server/storage/myisam/myisamchk.c 2013-01-18 04:53:12 +0000
277+++ Percona-Server/storage/myisam/myisamchk.c 2013-02-25 04:28:26 +0000
278@@ -89,6 +89,12 @@
279 get_options(&argc,(char***) &argv);
280 myisam_quick_table_bits=decode_bits;
281 error=0;
282+ if (mi_init_open_table_hash(0))
283+ {
284+ fprintf(stderr, "Can't initialize MyISAM storage engine\n");
285+ exit(-1);
286+ }
287+
288 while (--argc >= 0)
289 {
290 int new_error=myisamchk(&check_param, *(argv++));
291
292=== modified file 'Percona-Server/storage/myisam/myisamdef.h'
293--- Percona-Server/storage/myisam/myisamdef.h 2012-03-06 14:29:42 +0000
294+++ Percona-Server/storage/myisam/myisamdef.h 2013-02-25 04:28:26 +0000
295@@ -22,6 +22,7 @@
296 #include <my_pthread.h>
297 #include <thr_lock.h>
298 #include <mysql/psi/mysql_file.h>
299+#include "hash.h"
300
301 /* undef map from my_nosys; We need test-if-disk full */
302 #if defined(my_write)
303@@ -284,7 +285,6 @@
304 uint data_changed; /* Somebody has changed data */
305 uint save_update; /* When using KEY_READ */
306 int save_lastinx;
307- LIST open_list;
308 IO_CACHE rec_cache; /* When cacheing records */
309 uint preload_buff_size; /* When preloading indexes */
310 myf lock_wait; /* is 0 or MY_DONT_WAIT */
311@@ -471,8 +471,7 @@
312 #endif
313
314 /* Some extern variables */
315-
316-extern LIST *myisam_open_list;
317+extern HASH myisam_open_table_hash;
318 extern uchar myisam_file_magic[], myisam_pack_file_magic[];
319 extern uint myisam_read_vec[], myisam_readnext_vec[];
320 extern uint myisam_quick_table_bits;
321@@ -754,6 +753,7 @@
322 void mi_disable_non_unique_index(MI_INFO *info, ha_rows rows);
323
324 extern MI_INFO *test_if_reopen(char *filename);
325+extern int mi_init_open_table_hash(ulong size);
326 my_bool check_table_is_closed(const char *name, const char *where);
327 int mi_open_datafile(MI_INFO *info, MYISAM_SHARE *share, const char *orn_name,
328 File file_to_dup);
329
330=== modified file 'Percona-Server/storage/myisam/myisampack.c'
331--- Percona-Server/storage/myisam/myisampack.c 2013-02-12 07:47:19 +0000
332+++ Percona-Server/storage/myisam/myisampack.c 2013-02-25 04:28:26 +0000
333@@ -208,9 +208,12 @@
334 char **default_argv;
335 MY_INIT(argv[0]);
336
337- if (load_defaults("my",load_default_groups,&argc,&argv))
338+ if (load_defaults("my",load_default_groups,&argc,&argv) ||
339+ mi_init_open_table_hash(0))
340+ {
341+ fputs("Can't initialize MyISAM storage engine", stderr);
342 exit(1);
343-
344+ }
345 default_argv= argv;
346 get_options(&argc,&argv);
347

Subscribers

People subscribed via source and target branches