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