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