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 Foundation,
21 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */
22
23 /**
24 @file storage/perfschema/pfs_setup_actor.cc
25 Performance schema setup actor (implementation).
26 */
27
28 #include "my_global.h"
29 #include "my_sys.h"
30 #include "my_base.h"
31 #include "pfs.h"
32 #include "pfs_stat.h"
33 #include "pfs_instr.h"
34 #include "pfs_setup_actor.h"
35 #include "pfs_global.h"
36
37 /**
38 @addtogroup Performance_schema_buffers
39 @{
40 */
41
42 /** Size of the setup_actor instances array. @sa setup_actor_array */
43 ulong setup_actor_max;
44
45 /**
46 Setup_actor instances array.
47 @sa setup_actor_max
48 */
49
50 PFS_setup_actor *setup_actor_array= NULL;
51
52 /** Hash table for setup_actor records. */
53 LF_HASH setup_actor_hash;
54 /** True if @c setup_actor_hash is initialized. */
55 static bool setup_actor_hash_inited= false;
56
57 /**
58 Initialize the setup actor buffers.
59 @param param sizing parameters
60 @return 0 on success
61 */
init_setup_actor(const PFS_global_param * param)62 int init_setup_actor(const PFS_global_param *param)
63 {
64 setup_actor_max= param->m_setup_actor_sizing;
65
66 setup_actor_array= NULL;
67
68 if (setup_actor_max > 0)
69 {
70 setup_actor_array= PFS_MALLOC_ARRAY(setup_actor_max, sizeof(PFS_setup_actor),
71 PFS_setup_actor, MYF(MY_ZEROFILL));
72 if (unlikely(setup_actor_array == NULL))
73 return 1;
74 }
75
76 return 0;
77 }
78
79 /** Cleanup all the setup actor buffers. */
cleanup_setup_actor(void)80 void cleanup_setup_actor(void)
81 {
82 pfs_free(setup_actor_array);
83 setup_actor_array= NULL;
84 setup_actor_max= 0;
85 }
86
87 C_MODE_START
setup_actor_hash_get_key(const uchar * entry,size_t * length,my_bool)88 static uchar *setup_actor_hash_get_key(const uchar *entry, size_t *length,
89 my_bool)
90 {
91 const PFS_setup_actor * const *typed_entry;
92 const PFS_setup_actor *setup_actor;
93 const void *result;
94 typed_entry= reinterpret_cast<const PFS_setup_actor* const *> (entry);
95 DBUG_ASSERT(typed_entry != NULL);
96 setup_actor= *typed_entry;
97 DBUG_ASSERT(setup_actor != NULL);
98 *length= setup_actor->m_key.m_key_length;
99 result= setup_actor->m_key.m_hash_key;
100 return const_cast<uchar*> (reinterpret_cast<const uchar*> (result));
101 }
102 C_MODE_END
103
104 /**
105 Initialize the setup actor hash.
106 @return 0 on success
107 */
init_setup_actor_hash(void)108 int init_setup_actor_hash(void)
109 {
110 if ((! setup_actor_hash_inited) && (setup_actor_max > 0))
111 {
112 lf_hash_init(&setup_actor_hash, sizeof(PFS_setup_actor*), LF_HASH_UNIQUE,
113 0, 0, setup_actor_hash_get_key, &my_charset_bin);
114 setup_actor_hash.size= setup_actor_max;
115 setup_actor_hash_inited= true;
116 }
117 return 0;
118 }
119
120 /** Cleanup the setup actor hash. */
cleanup_setup_actor_hash(void)121 void cleanup_setup_actor_hash(void)
122 {
123 if (setup_actor_hash_inited)
124 {
125 lf_hash_destroy(&setup_actor_hash);
126 setup_actor_hash_inited= false;
127 }
128 }
129
get_setup_actor_hash_pins(PFS_thread * thread)130 static LF_PINS* get_setup_actor_hash_pins(PFS_thread *thread)
131 {
132 if (unlikely(thread->m_setup_actor_hash_pins == NULL))
133 {
134 if (! setup_actor_hash_inited)
135 return NULL;
136 thread->m_setup_actor_hash_pins= lf_hash_get_pins(&setup_actor_hash);
137 }
138 return thread->m_setup_actor_hash_pins;
139 }
140
set_setup_actor_key(PFS_setup_actor_key * key,const char * user,uint user_length,const char * host,uint host_length,const char * role,uint role_length)141 static void set_setup_actor_key(PFS_setup_actor_key *key,
142 const char *user, uint user_length,
143 const char *host, uint host_length,
144 const char *role, uint role_length)
145 {
146 DBUG_ASSERT(user_length <= USERNAME_LENGTH);
147 DBUG_ASSERT(host_length <= HOSTNAME_LENGTH);
148
149 char *ptr= &key->m_hash_key[0];
150 memcpy(ptr, user, user_length);
151 ptr+= user_length;
152 ptr[0]= 0;
153 ptr++;
154 memcpy(ptr, host, host_length);
155 ptr+= host_length;
156 ptr[0]= 0;
157 ptr++;
158 memcpy(ptr, role, role_length);
159 ptr+= role_length;
160 ptr[0]= 0;
161 ptr++;
162 key->m_key_length= ptr - &key->m_hash_key[0];
163 }
164
insert_setup_actor(const String * user,const String * host,const String * role)165 int insert_setup_actor(const String *user, const String *host, const String *role)
166 {
167 if (setup_actor_max == 0)
168 return HA_ERR_RECORD_FILE_FULL;
169
170 PFS_thread *thread= PFS_thread::get_current_thread();
171 if (unlikely(thread == NULL))
172 return HA_ERR_OUT_OF_MEM;
173
174 LF_PINS *pins= get_setup_actor_hash_pins(thread);
175 if (unlikely(pins == NULL))
176 return HA_ERR_OUT_OF_MEM;
177
178 static uint PFS_ALIGNED setup_actor_monotonic_index= 0;
179 uint index;
180 uint attempts= 0;
181 PFS_setup_actor *pfs;
182
183 while (++attempts <= setup_actor_max)
184 {
185 /* See create_mutex() */
186 index= PFS_atomic::add_u32(& setup_actor_monotonic_index, 1) % setup_actor_max;
187 pfs= setup_actor_array + index;
188
189 if (pfs->m_lock.is_free())
190 {
191 if (pfs->m_lock.free_to_dirty())
192 {
193 set_setup_actor_key(&pfs->m_key,
194 user->ptr(), user->length(),
195 host->ptr(), host->length(),
196 role->ptr(), role->length());
197 pfs->m_username= &pfs->m_key.m_hash_key[0];
198 pfs->m_username_length= user->length();
199 pfs->m_hostname= pfs->m_username + pfs->m_username_length + 1;
200 pfs->m_hostname_length= host->length();
201 pfs->m_rolename= pfs->m_hostname + pfs->m_hostname_length + 1;
202 pfs->m_rolename_length= role->length();
203
204 int res;
205 res= lf_hash_insert(&setup_actor_hash, pins, &pfs);
206 if (likely(res == 0))
207 {
208 pfs->m_lock.dirty_to_allocated();
209 return 0;
210 }
211
212 pfs->m_lock.dirty_to_free();
213 if (res > 0)
214 return HA_ERR_FOUND_DUPP_KEY;
215 return HA_ERR_OUT_OF_MEM;
216 }
217 }
218 }
219
220 return HA_ERR_RECORD_FILE_FULL;
221 }
222
delete_setup_actor(const String * user,const String * host,const String * role)223 int delete_setup_actor(const String *user, const String *host, const String *role)
224 {
225 PFS_thread *thread= PFS_thread::get_current_thread();
226 if (unlikely(thread == NULL))
227 return HA_ERR_OUT_OF_MEM;
228
229 LF_PINS* pins= get_setup_actor_hash_pins(thread);
230 if (unlikely(pins == NULL))
231 return HA_ERR_OUT_OF_MEM;
232
233 PFS_setup_actor_key key;
234 set_setup_actor_key(&key,
235 user->ptr(), user->length(),
236 host->ptr(), host->length(),
237 role->ptr(), role->length());
238
239 PFS_setup_actor **entry;
240 entry= reinterpret_cast<PFS_setup_actor**>
241 (lf_hash_search(&setup_actor_hash, pins, key.m_hash_key, key.m_key_length));
242
243 if (entry && (entry != MY_ERRPTR))
244 {
245 PFS_setup_actor *pfs= *entry;
246 lf_hash_delete(&setup_actor_hash, pins, key.m_hash_key, key.m_key_length);
247 pfs->m_lock.allocated_to_free();
248 }
249
250 lf_hash_search_unpin(pins);
251
252 return 0;
253 }
254
reset_setup_actor()255 int reset_setup_actor()
256 {
257 PFS_thread *thread= PFS_thread::get_current_thread();
258 if (unlikely(thread == NULL))
259 return HA_ERR_OUT_OF_MEM;
260
261 LF_PINS* pins= get_setup_actor_hash_pins(thread);
262 if (unlikely(pins == NULL))
263 return HA_ERR_OUT_OF_MEM;
264
265 PFS_setup_actor *pfs= setup_actor_array;
266 PFS_setup_actor *pfs_last= setup_actor_array + setup_actor_max;
267
268 for ( ; pfs < pfs_last; pfs++)
269 {
270 if (pfs->m_lock.is_populated())
271 {
272 lf_hash_delete(&setup_actor_hash, pins,
273 pfs->m_key.m_hash_key, pfs->m_key.m_key_length);
274 pfs->m_lock.allocated_to_free();
275 }
276 }
277
278 return 0;
279 }
280
setup_actor_count()281 long setup_actor_count()
282 {
283 return setup_actor_hash.count;
284 }
285
286 /*
287 - '%' should be replaced by NULL in table SETUP_ACTOR
288 - add an ENABLED column to include/exclude patterns, more flexible
289 - the principle is similar to SETUP_OBJECTS
290 */
lookup_setup_actor(PFS_thread * thread,const char * user,uint user_length,const char * host,uint host_length,bool * enabled)291 void lookup_setup_actor(PFS_thread *thread,
292 const char *user, uint user_length,
293 const char *host, uint host_length,
294 bool *enabled)
295 {
296 PFS_setup_actor_key key;
297 PFS_setup_actor **entry;
298 int i;
299
300 LF_PINS* pins= get_setup_actor_hash_pins(thread);
301 if (unlikely(pins == NULL))
302 {
303 *enabled= false;
304 return;
305 }
306
307 for (i= 1; i<=4; i++)
308 {
309 /*
310 WL#988 Roles is not implemented, so we do not have a role name.
311 Looking up "%" in SETUP_ACTORS.ROLE.
312 */
313 switch(i)
314 {
315 case 1:
316 set_setup_actor_key(&key, user, user_length, host, host_length, "%", 1);
317 break;
318 case 2:
319 set_setup_actor_key(&key, user, user_length, "%", 1, "%", 1);
320 break;
321 case 3:
322 set_setup_actor_key(&key, "%", 1, host, host_length, "%", 1);
323 break;
324 case 4:
325 set_setup_actor_key(&key, "%", 1, "%", 1, "%", 1);
326 break;
327 }
328 entry= reinterpret_cast<PFS_setup_actor**>
329 (lf_hash_search(&setup_actor_hash, pins, key.m_hash_key, key.m_key_length));
330
331 if (entry && (entry != MY_ERRPTR))
332 {
333 lf_hash_search_unpin(pins);
334 *enabled= true;
335 return;
336 }
337
338 lf_hash_search_unpin(pins);
339 }
340 *enabled= false;
341 return;
342 }
343
344 /** @} */
345