1 /* Copyright (c) 2010, 2015, 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, version 2.0,
5 as published by the Free Software Foundation.
6
7 This program is also distributed with certain software (including
8 but not limited to OpenSSL) that is licensed under separate terms,
9 as designated in a particular file or component or in included license
10 documentation. The authors of MySQL hereby grant you an additional
11 permission to link the program and your derivative works with the
12 separately licensed software that they have included with MySQL.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License, version 2.0, for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */
22
23 /**
24 @file storage/perfschema/pfs_setup_object.cc
25 Performance schema setup object (implementation).
26 */
27
28 #include "my_global.h"
29 #include "my_sys.h"
30 #include "my_base.h"
31 #include "sql_string.h"
32 #include "pfs.h"
33 #include "pfs_stat.h"
34 #include "pfs_instr.h"
35 #include "pfs_setup_object.h"
36 #include "pfs_global.h"
37
38 /**
39 @addtogroup Performance_schema_buffers
40 @{
41 */
42
43 uint setup_objects_version= 0;
44
45 ulong setup_object_max;
46
47 PFS_setup_object *setup_object_array= NULL;
48
49 LF_HASH setup_object_hash;
50 static bool setup_object_hash_inited= false;
51
52 /**
53 Initialize the setup object buffers.
54 @param param sizing parameters
55 @return 0 on success
56 */
init_setup_object(const PFS_global_param * param)57 int init_setup_object(const PFS_global_param *param)
58 {
59 setup_object_max= param->m_setup_object_sizing;
60
61 setup_object_array= NULL;
62
63 if (setup_object_max > 0)
64 {
65 setup_object_array= PFS_MALLOC_ARRAY(setup_object_max, sizeof(PFS_setup_object),
66 PFS_setup_object, MYF(MY_ZEROFILL));
67 if (unlikely(setup_object_array == NULL))
68 return 1;
69 }
70
71 return 0;
72 }
73
74 /** Cleanup all the setup object buffers. */
cleanup_setup_object(void)75 void cleanup_setup_object(void)
76 {
77 pfs_free(setup_object_array);
78 setup_object_array= NULL;
79 setup_object_max= 0;
80 }
81
82 C_MODE_START
setup_object_hash_get_key(const uchar * entry,size_t * length,my_bool)83 static uchar *setup_object_hash_get_key(const uchar *entry, size_t *length,
84 my_bool)
85 {
86 const PFS_setup_object * const *typed_entry;
87 const PFS_setup_object *setup_object;
88 const void *result;
89 typed_entry= reinterpret_cast<const PFS_setup_object* const *> (entry);
90 DBUG_ASSERT(typed_entry != NULL);
91 setup_object= *typed_entry;
92 DBUG_ASSERT(setup_object != NULL);
93 *length= setup_object->m_key.m_key_length;
94 result= setup_object->m_key.m_hash_key;
95 return const_cast<uchar*> (reinterpret_cast<const uchar*> (result));
96 }
97 C_MODE_END
98
99 /**
100 Initialize the setup objects hash.
101 @return 0 on success
102 */
init_setup_object_hash(void)103 int init_setup_object_hash(void)
104 {
105 if ((! setup_object_hash_inited) && (setup_object_max > 0))
106 {
107 lf_hash_init(&setup_object_hash, sizeof(PFS_setup_object*), LF_HASH_UNIQUE,
108 0, 0, setup_object_hash_get_key, &my_charset_bin);
109 setup_object_hash.size= setup_object_max;
110 setup_object_hash_inited= true;
111 }
112 return 0;
113 }
114
115 /** Cleanup the setup objects hash. */
cleanup_setup_object_hash(void)116 void cleanup_setup_object_hash(void)
117 {
118 if (setup_object_hash_inited)
119 {
120 lf_hash_destroy(&setup_object_hash);
121 setup_object_hash_inited= false;
122 }
123 }
124
get_setup_object_hash_pins(PFS_thread * thread)125 static LF_PINS* get_setup_object_hash_pins(PFS_thread *thread)
126 {
127 if (unlikely(thread->m_setup_object_hash_pins == NULL))
128 {
129 if (! setup_object_hash_inited)
130 return NULL;
131 thread->m_setup_object_hash_pins= lf_hash_get_pins(&setup_object_hash);
132 }
133 return thread->m_setup_object_hash_pins;
134 }
135
set_setup_object_key(PFS_setup_object_key * key,enum_object_type object_type,const char * schema,uint schema_length,const char * object,uint object_length)136 static void set_setup_object_key(PFS_setup_object_key *key,
137 enum_object_type object_type,
138 const char *schema, uint schema_length,
139 const char *object, uint object_length)
140 {
141 DBUG_ASSERT(schema_length <= NAME_LEN);
142 DBUG_ASSERT(object_length <= NAME_LEN);
143
144 char *ptr= &key->m_hash_key[0];
145 ptr[0]= (char) object_type;
146 ptr++;
147 memcpy(ptr, schema, schema_length);
148 ptr+= schema_length;
149 ptr[0]= 0;
150 ptr++;
151 memcpy(ptr, object, object_length);
152 ptr+= object_length;
153 ptr[0]= 0;
154 ptr++;
155 key->m_key_length= ptr - &key->m_hash_key[0];
156 }
157
insert_setup_object(enum_object_type object_type,const String * schema,const String * object,bool enabled,bool timed)158 int insert_setup_object(enum_object_type object_type, const String *schema,
159 const String *object, bool enabled, bool timed)
160 {
161 if (setup_object_max == 0)
162 return HA_ERR_RECORD_FILE_FULL;
163
164 PFS_thread *thread= PFS_thread::get_current_thread();
165 if (unlikely(thread == NULL))
166 return HA_ERR_OUT_OF_MEM;
167
168 LF_PINS* pins= get_setup_object_hash_pins(thread);
169 if (unlikely(pins == NULL))
170 return HA_ERR_OUT_OF_MEM;
171
172 static uint PFS_ALIGNED setup_object_monotonic_index= 0;
173 uint index;
174 uint attempts= 0;
175 PFS_setup_object *pfs;
176
177 while (++attempts <= setup_object_max)
178 {
179 /* See create_mutex() */
180 index= PFS_atomic::add_u32(& setup_object_monotonic_index, 1) % setup_object_max;
181 pfs= setup_object_array + index;
182
183 if (pfs->m_lock.is_free())
184 {
185 if (pfs->m_lock.free_to_dirty())
186 {
187 set_setup_object_key(&pfs->m_key, object_type,
188 schema->ptr(), schema->length(),
189 object->ptr(), object->length());
190 pfs->m_schema_name= &pfs->m_key.m_hash_key[1];
191 pfs->m_schema_name_length= schema->length();
192 pfs->m_object_name= pfs->m_schema_name + pfs->m_schema_name_length + 1;
193 pfs->m_object_name_length= object->length();
194 pfs->m_enabled= enabled;
195 pfs->m_timed= timed;
196
197 int res;
198 res= lf_hash_insert(&setup_object_hash, pins, &pfs);
199 if (likely(res == 0))
200 {
201 pfs->m_lock.dirty_to_allocated();
202 setup_objects_version++;
203 return 0;
204 }
205
206 pfs->m_lock.dirty_to_free();
207 if (res > 0)
208 return HA_ERR_FOUND_DUPP_KEY;
209 /* OOM in lf_hash_insert */
210 return HA_ERR_OUT_OF_MEM;
211 }
212 }
213 }
214
215 return HA_ERR_RECORD_FILE_FULL;
216 }
217
delete_setup_object(enum_object_type object_type,const String * schema,const String * object)218 int delete_setup_object(enum_object_type object_type, const String *schema,
219 const String *object)
220 {
221 PFS_thread *thread= PFS_thread::get_current_thread();
222 if (unlikely(thread == NULL))
223 return HA_ERR_OUT_OF_MEM;
224
225 LF_PINS* pins= get_setup_object_hash_pins(thread);
226 if (unlikely(pins == NULL))
227 return HA_ERR_OUT_OF_MEM;
228
229 PFS_setup_object_key key;
230 set_setup_object_key(&key, object_type,
231 schema->ptr(), schema->length(),
232 object->ptr(), object->length());
233
234 PFS_setup_object **entry;
235 entry= reinterpret_cast<PFS_setup_object**>
236 (lf_hash_search(&setup_object_hash, pins, key.m_hash_key, key.m_key_length));
237
238 if (entry && (entry != MY_ERRPTR))
239 {
240 PFS_setup_object *pfs= *entry;
241 lf_hash_delete(&setup_object_hash, pins, key.m_hash_key, key.m_key_length);
242 pfs->m_lock.allocated_to_free();
243 }
244
245 lf_hash_search_unpin(pins);
246
247 setup_objects_version++;
248 return 0;
249 }
250
reset_setup_object()251 int reset_setup_object()
252 {
253 PFS_thread *thread= PFS_thread::get_current_thread();
254 if (unlikely(thread == NULL))
255 return HA_ERR_OUT_OF_MEM;
256
257 LF_PINS* pins= get_setup_object_hash_pins(thread);
258 if (unlikely(pins == NULL))
259 return HA_ERR_OUT_OF_MEM;
260
261 PFS_setup_object *pfs= setup_object_array;
262 PFS_setup_object *pfs_last= setup_object_array + setup_object_max;
263
264 for ( ; pfs < pfs_last; pfs++)
265 {
266 if (pfs->m_lock.is_populated())
267 {
268 lf_hash_delete(&setup_object_hash, pins,
269 pfs->m_key.m_hash_key, pfs->m_key.m_key_length);
270 pfs->m_lock.allocated_to_free();
271 }
272 }
273
274 setup_objects_version++;
275 return 0;
276 }
277
setup_object_count()278 long setup_object_count()
279 {
280 return setup_object_hash.count;
281 }
282
lookup_setup_object(PFS_thread * thread,enum_object_type object_type,const char * schema_name,int schema_name_length,const char * object_name,int object_name_length,bool * enabled,bool * timed)283 void lookup_setup_object(PFS_thread *thread,
284 enum_object_type object_type,
285 const char *schema_name, int schema_name_length,
286 const char *object_name, int object_name_length,
287 bool *enabled, bool *timed)
288 {
289 PFS_setup_object_key key;
290 PFS_setup_object **entry;
291 PFS_setup_object *pfs;
292 int i;
293
294 /*
295 The table io instrumentation uses "TABLE" and "TEMPORARY TABLE".
296 SETUP_OBJECT uses "TABLE" for both concepts.
297 There is no way to provide a different setup for:
298 - TABLE foo.bar
299 - TEMPORARY TABLE foo.bar
300 */
301 DBUG_ASSERT(object_type != OBJECT_TYPE_TEMPORARY_TABLE);
302
303 LF_PINS* pins= get_setup_object_hash_pins(thread);
304 if (unlikely(pins == NULL))
305 {
306 *enabled= false;
307 *timed= false;
308 return;
309 }
310
311 for (i= 1; i<=3; i++)
312 {
313 switch(i)
314 {
315 case 1:
316 /* Lookup OBJECT_TYPE + OBJECT_SCHEMA + OBJECT_NAME in SETUP_OBJECTS */
317 set_setup_object_key(&key,
318 object_type,
319 schema_name, schema_name_length,
320 object_name, object_name_length);
321 break;
322 case 2:
323 /* Lookup OBJECT_TYPE + OBJECT_SCHEMA + "%" in SETUP_OBJECTS */
324 set_setup_object_key(&key,
325 object_type,
326 schema_name, schema_name_length, "%", 1);
327 break;
328 case 3:
329 /* Lookup OBJECT_TYPE + "%" + "%" in SETUP_OBJECTS */
330 set_setup_object_key(&key, object_type, "%", 1, "%", 1);
331 break;
332 }
333 entry= reinterpret_cast<PFS_setup_object**>
334 (lf_hash_search(&setup_object_hash, pins, key.m_hash_key, key.m_key_length));
335
336 if (entry && (entry != MY_ERRPTR))
337 {
338 pfs= *entry;
339 *enabled= pfs->m_enabled;
340 *timed= pfs->m_timed;
341 lf_hash_search_unpin(pins);
342 return;
343 }
344
345 lf_hash_search_unpin(pins);
346 }
347 *enabled= false;
348 *timed= false;
349 return;
350 }
351
352 /** @} */
353