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