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_user.cc
25   Performance schema user (implementation).
26 */
27 
28 #include "my_global.h"
29 #include "my_sys.h"
30 #include "pfs.h"
31 #include "pfs_stat.h"
32 #include "pfs_instr.h"
33 #include "pfs_setup_actor.h"
34 #include "pfs_user.h"
35 #include "pfs_global.h"
36 #include "pfs_instr_class.h"
37 #include "pfs_buffer_container.h"
38 
39 /**
40   @addtogroup Performance_schema_buffers
41   @{
42 */
43 
44 LF_HASH user_hash;
45 static bool user_hash_inited= false;
46 
47 /**
48   Initialize the user buffers.
49   @param param                        sizing parameters
50   @return 0 on success
51 */
init_user(const PFS_global_param * param)52 int init_user(const PFS_global_param *param)
53 {
54   if (global_user_container.init(param->m_user_sizing))
55     return 1;
56 
57   return 0;
58 }
59 
60 /** Cleanup all the user buffers. */
cleanup_user(void)61 void cleanup_user(void)
62 {
63   global_user_container.cleanup();
64 }
65 
66 C_MODE_START
user_hash_get_key(const uchar * entry,size_t * length,my_bool)67 static uchar *user_hash_get_key(const uchar *entry, size_t *length,
68                                 my_bool)
69 {
70   const PFS_user * const *typed_entry;
71   const PFS_user *user;
72   const void *result;
73   typed_entry= reinterpret_cast<const PFS_user* const *> (entry);
74   assert(typed_entry != NULL);
75   user= *typed_entry;
76   assert(user != NULL);
77   *length= user->m_key.m_key_length;
78   result= user->m_key.m_hash_key;
79   return const_cast<uchar*> (reinterpret_cast<const uchar*> (result));
80 }
81 C_MODE_END
82 
83 /**
84   Initialize the user hash.
85   @return 0 on success
86 */
init_user_hash(const PFS_global_param * param)87 int init_user_hash(const PFS_global_param *param)
88 {
89   if ((! user_hash_inited) && (param->m_user_sizing != 0))
90   {
91     lf_hash_init(&user_hash, sizeof(PFS_user*), LF_HASH_UNIQUE,
92                  0, 0, user_hash_get_key, &my_charset_bin);
93     user_hash_inited= true;
94   }
95   return 0;
96 }
97 
98 /** Cleanup the user hash. */
cleanup_user_hash(void)99 void cleanup_user_hash(void)
100 {
101   if (user_hash_inited)
102   {
103     lf_hash_destroy(&user_hash);
104     user_hash_inited= false;
105   }
106 }
107 
get_user_hash_pins(PFS_thread * thread)108 static LF_PINS* get_user_hash_pins(PFS_thread *thread)
109 {
110   if (unlikely(thread->m_user_hash_pins == NULL))
111   {
112     if (! user_hash_inited)
113       return NULL;
114     thread->m_user_hash_pins= lf_hash_get_pins(&user_hash);
115   }
116   return thread->m_user_hash_pins;
117 }
118 
set_user_key(PFS_user_key * key,const char * user,uint user_length)119 static void set_user_key(PFS_user_key *key,
120                          const char *user, uint user_length)
121 {
122   assert(user_length <= USERNAME_LENGTH);
123 
124   char *ptr= &key->m_hash_key[0];
125   if (user_length > 0)
126   {
127     memcpy(ptr, user, user_length);
128     ptr+= user_length;
129   }
130   ptr[0]= 0;
131   ptr++;
132   key->m_key_length= ptr - &key->m_hash_key[0];
133 }
134 
135 PFS_user *
find_or_create_user(PFS_thread * thread,const char * username,uint username_length)136 find_or_create_user(PFS_thread *thread,
137                     const char *username, uint username_length)
138 {
139   LF_PINS *pins= get_user_hash_pins(thread);
140   if (unlikely(pins == NULL))
141   {
142     global_user_container.m_lost++;
143     return NULL;
144   }
145 
146   PFS_user_key key;
147   set_user_key(&key, username, username_length);
148 
149   PFS_user **entry;
150   PFS_user *pfs;
151   uint retry_count= 0;
152   const uint retry_max= 3;
153   pfs_dirty_state dirty_state;
154 
155 search:
156   entry= reinterpret_cast<PFS_user**>
157     (lf_hash_search(&user_hash, pins,
158                     key.m_hash_key, key.m_key_length));
159   if (entry && (entry != MY_ERRPTR))
160   {
161     pfs= *entry;
162     pfs->inc_refcount();
163     lf_hash_search_unpin(pins);
164     return pfs;
165   }
166 
167   lf_hash_search_unpin(pins);
168 
169   pfs= global_user_container.allocate(& dirty_state);
170   if (pfs != NULL)
171   {
172     pfs->m_key= key;
173     if (username_length > 0)
174       pfs->m_username= &pfs->m_key.m_hash_key[0];
175     else
176       pfs->m_username= NULL;
177     pfs->m_username_length= username_length;
178 
179     pfs->init_refcount();
180     pfs->reset_stats();
181     pfs->m_disconnected_count= 0;
182 
183     int res;
184     pfs->m_lock.dirty_to_allocated(& dirty_state);
185     res= lf_hash_insert(&user_hash, pins, &pfs);
186     if (likely(res == 0))
187     {
188       return pfs;
189     }
190 
191     global_user_container.deallocate(pfs);
192 
193     if (res > 0)
194     {
195       if (++retry_count > retry_max)
196       {
197         global_user_container.m_lost++;
198         return NULL;
199       }
200       goto search;
201     }
202 
203     global_user_container.m_lost++;
204     return NULL;
205   }
206 
207   return NULL;
208 }
209 
aggregate(bool alive)210 void PFS_user::aggregate(bool alive)
211 {
212   aggregate_waits();
213   aggregate_stages();
214   aggregate_statements();
215   aggregate_transactions();
216   aggregate_memory(alive);
217   aggregate_status();
218   aggregate_stats();
219 }
220 
aggregate_waits()221 void PFS_user::aggregate_waits()
222 {
223   /* No parent to aggregate to, clean the stats */
224   reset_waits_stats();
225 }
226 
aggregate_stages()227 void PFS_user::aggregate_stages()
228 {
229   /* No parent to aggregate to, clean the stats */
230   reset_stages_stats();
231 }
232 
aggregate_statements()233 void PFS_user::aggregate_statements()
234 {
235   /* No parent to aggregate to, clean the stats */
236   reset_statements_stats();
237 }
238 
aggregate_transactions()239 void PFS_user::aggregate_transactions()
240 {
241   /* No parent to aggregate to, clean the stats */
242   reset_transactions_stats();
243 }
244 
aggregate_memory(bool alive)245 void PFS_user::aggregate_memory(bool alive)
246 {
247   /* No parent to aggregate to, clean the stats */
248   rebase_memory_stats();
249 }
250 
aggregate_status()251 void PFS_user::aggregate_status()
252 {
253   /* No parent to aggregate to, clean the stats */
254   reset_status_stats();
255 }
256 
aggregate_stats()257 void PFS_user::aggregate_stats()
258 {
259   /* No parent to aggregate to, clean the stats */
260   m_disconnected_count= 0;
261 }
262 
release()263 void PFS_user::release()
264 {
265   dec_refcount();
266 }
267 
carry_memory_stat_delta(PFS_memory_stat_delta * delta,uint index)268 void PFS_user::carry_memory_stat_delta(PFS_memory_stat_delta *delta, uint index)
269 {
270   PFS_memory_stat *event_name_array;
271   PFS_memory_stat *stat;
272   PFS_memory_stat_delta delta_buffer;
273 
274   event_name_array= write_instr_class_memory_stats();
275   stat= & event_name_array[index];
276   (void) stat->apply_delta(delta, &delta_buffer);
277 }
278 
sanitize_user(PFS_user * unsafe)279 PFS_user *sanitize_user(PFS_user *unsafe)
280 {
281   return global_user_container.sanitize(unsafe);
282 }
283 
purge_user(PFS_thread * thread,PFS_user * user)284 void purge_user(PFS_thread *thread, PFS_user *user)
285 {
286   LF_PINS *pins= get_user_hash_pins(thread);
287   if (unlikely(pins == NULL))
288     return;
289 
290   PFS_user **entry;
291   entry= reinterpret_cast<PFS_user**>
292     (lf_hash_search(&user_hash, pins,
293                     user->m_key.m_hash_key, user->m_key.m_key_length));
294   if (entry && (entry != MY_ERRPTR))
295   {
296     assert(*entry == user);
297     if (user->get_refcount() == 0)
298     {
299       lf_hash_delete(&user_hash, pins,
300                      user->m_key.m_hash_key, user->m_key.m_key_length);
301       user->aggregate(false);
302       global_user_container.deallocate(user);
303     }
304   }
305 
306   lf_hash_search_unpin(pins);
307 }
308 
309 class Proc_purge_user
310   : public PFS_buffer_processor<PFS_user>
311 {
312 public:
Proc_purge_user(PFS_thread * thread)313   Proc_purge_user(PFS_thread *thread)
314     : m_thread(thread)
315   {}
316 
operator ()(PFS_user * pfs)317   virtual void operator()(PFS_user *pfs)
318   {
319     pfs->aggregate(true);
320     if (pfs->get_refcount() == 0)
321       purge_user(m_thread, pfs);
322   }
323 
324 private:
325   PFS_thread *m_thread;
326 };
327 
328 /** Purge non connected users, reset stats of connected users. */
purge_all_user(void)329 void purge_all_user(void)
330 {
331   PFS_thread *thread= PFS_thread::get_current_thread();
332   if (unlikely(thread == NULL))
333     return;
334 
335   Proc_purge_user proc(thread);
336   global_user_container.apply(proc);
337 }
338 
339 /** @} */
340