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