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