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
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 DBUG_ASSERT(typed_entry != NULL);
75 user= *typed_entry;
76 DBUG_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 DBUG_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 DBUG_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