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