MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
pfs_user.cc
Go to the documentation of this file.
1 /* Copyright (c) 2010, 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
14  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */
15 
21 #include "my_global.h"
22 #include "my_sys.h"
23 #include "pfs.h"
24 #include "pfs_stat.h"
25 #include "pfs_instr.h"
26 #include "pfs_setup_actor.h"
27 #include "pfs_user.h"
28 #include "pfs_global.h"
29 #include "pfs_instr_class.h"
30 
36 ulong user_max;
37 ulong user_lost;
38 
39 PFS_user *user_array= NULL;
40 
41 static PFS_single_stat *user_instr_class_waits_array= NULL;
42 static PFS_stage_stat *user_instr_class_stages_array= NULL;
43 static PFS_statement_stat *user_instr_class_statements_array= NULL;
44 
45 LF_HASH user_hash;
46 static bool user_hash_inited= false;
47 
53 int init_user(const PFS_global_param *param)
54 {
55  uint index;
56 
57  user_max= param->m_user_sizing;
58 
59  user_array= NULL;
60  user_instr_class_waits_array= NULL;
61  user_instr_class_stages_array= NULL;
62  user_instr_class_statements_array= NULL;
63  uint waits_sizing= user_max * wait_class_max;
64  uint stages_sizing= user_max * stage_class_max;
65  uint statements_sizing= user_max * statement_class_max;
66 
67  if (user_max > 0)
68  {
69  user_array= PFS_MALLOC_ARRAY(user_max, PFS_user,
70  MYF(MY_ZEROFILL));
71  if (unlikely(user_array == NULL))
72  return 1;
73  }
74 
75  if (waits_sizing > 0)
76  {
77  user_instr_class_waits_array=
79  if (unlikely(user_instr_class_waits_array == NULL))
80  return 1;
81  }
82 
83  if (stages_sizing > 0)
84  {
85  user_instr_class_stages_array=
87  if (unlikely(user_instr_class_stages_array == NULL))
88  return 1;
89  }
90 
91  if (statements_sizing > 0)
92  {
93  user_instr_class_statements_array=
95  if (unlikely(user_instr_class_statements_array == NULL))
96  return 1;
97  }
98 
99  for (index= 0; index < user_max; index++)
100  {
101  user_array[index].m_instr_class_waits_stats=
102  &user_instr_class_waits_array[index * wait_class_max];
103  user_array[index].m_instr_class_stages_stats=
104  &user_instr_class_stages_array[index * stage_class_max];
106  &user_instr_class_statements_array[index * statement_class_max];
107  }
108 
109  return 0;
110 }
111 
113 void cleanup_user(void)
114 {
115  pfs_free(user_array);
116  user_array= NULL;
117  pfs_free(user_instr_class_waits_array);
118  user_instr_class_waits_array= NULL;
119  pfs_free(user_instr_class_stages_array);
120  user_instr_class_stages_array= NULL;
121  pfs_free(user_instr_class_statements_array);
122  user_instr_class_statements_array= NULL;
123  user_max= 0;
124 }
125 
126 C_MODE_START
127 static uchar *user_hash_get_key(const uchar *entry, size_t *length,
128  my_bool)
129 {
130  const PFS_user * const *typed_entry;
131  const PFS_user *user;
132  const void *result;
133  typed_entry= reinterpret_cast<const PFS_user* const *> (entry);
134  DBUG_ASSERT(typed_entry != NULL);
135  user= *typed_entry;
136  DBUG_ASSERT(user != NULL);
137  *length= user->m_key.m_key_length;
138  result= user->m_key.m_hash_key;
139  return const_cast<uchar*> (reinterpret_cast<const uchar*> (result));
140 }
141 C_MODE_END
142 
147 int init_user_hash(void)
148 {
149  if ((! user_hash_inited) && (user_max > 0))
150  {
151  lf_hash_init(&user_hash, sizeof(PFS_user*), LF_HASH_UNIQUE,
152  0, 0, user_hash_get_key, &my_charset_bin);
153  user_hash.size= user_max;
154  user_hash_inited= true;
155  }
156  return 0;
157 }
158 
161 {
162  if (user_hash_inited)
163  {
164  lf_hash_destroy(&user_hash);
165  user_hash_inited= false;
166  }
167 }
168 
169 static LF_PINS* get_user_hash_pins(PFS_thread *thread)
170 {
171  if (unlikely(thread->m_user_hash_pins == NULL))
172  {
173  if (! user_hash_inited)
174  return NULL;
175  thread->m_user_hash_pins= lf_hash_get_pins(&user_hash);
176  }
177  return thread->m_user_hash_pins;
178 }
179 
180 static void set_user_key(PFS_user_key *key,
181  const char *user, uint user_length)
182 {
183  DBUG_ASSERT(user_length <= USERNAME_LENGTH);
184 
185  char *ptr= &key->m_hash_key[0];
186  if (user_length > 0)
187  {
188  memcpy(ptr, user, user_length);
189  ptr+= user_length;
190  }
191  ptr[0]= 0;
192  ptr++;
193  key->m_key_length= ptr - &key->m_hash_key[0];
194 }
195 
196 PFS_user *
197 find_or_create_user(PFS_thread *thread,
198  const char *username, uint username_length)
199 {
200  if (user_max == 0)
201  {
202  user_lost++;
203  return NULL;
204  }
205 
206  LF_PINS *pins= get_user_hash_pins(thread);
207  if (unlikely(pins == NULL))
208  {
209  user_lost++;
210  return NULL;
211  }
212 
213  PFS_user_key key;
214  set_user_key(&key, username, username_length);
215 
216  PFS_user **entry;
217  uint retry_count= 0;
218  const uint retry_max= 3;
219 
220 search:
221  entry= reinterpret_cast<PFS_user**>
222  (lf_hash_search(&user_hash, pins,
223  key.m_hash_key, key.m_key_length));
224  if (entry && (entry != MY_ERRPTR))
225  {
226  PFS_user *pfs;
227  pfs= *entry;
228  pfs->inc_refcount();
229  lf_hash_search_unpin(pins);
230  return pfs;
231  }
232 
233  lf_hash_search_unpin(pins);
234 
235  PFS_scan scan;
236  uint random= randomized_index(username, user_max);
237 
238  for (scan.init(random, user_max);
239  scan.has_pass();
240  scan.next_pass())
241  {
242  PFS_user *pfs= user_array + scan.first();
243  PFS_user *pfs_last= user_array + scan.last();
244  for ( ; pfs < pfs_last; pfs++)
245  {
246  if (pfs->m_lock.is_free())
247  {
248  if (pfs->m_lock.free_to_dirty())
249  {
250  pfs->m_key= key;
251  if (username_length > 0)
252  pfs->m_username= &pfs->m_key.m_hash_key[0];
253  else
254  pfs->m_username= NULL;
255  pfs->m_username_length= username_length;
256 
257  pfs->init_refcount();
258  pfs->reset_stats();
259  pfs->m_disconnected_count= 0;
260 
261  int res;
262  res= lf_hash_insert(&user_hash, pins, &pfs);
263  if (likely(res == 0))
264  {
265  pfs->m_lock.dirty_to_allocated();
266  return pfs;
267  }
268 
269  pfs->m_lock.dirty_to_free();
270 
271  if (res > 0)
272  {
273  if (++retry_count > retry_max)
274  {
275  user_lost++;
276  return NULL;
277  }
278  goto search;
279  }
280 
281  user_lost++;
282  return NULL;
283  }
284  }
285  }
286  }
287 
288  user_lost++;
289  return NULL;
290 }
291 
292 void PFS_user::aggregate()
293 {
294  aggregate_waits();
295  aggregate_stages();
296  aggregate_statements();
297  aggregate_stats();
298 }
299 
300 void PFS_user::aggregate_waits()
301 {
302  /* No parent to aggregate to, clean the stats */
304 }
305 
306 void PFS_user::aggregate_stages()
307 {
308  /* No parent to aggregate to, clean the stats */
310 }
311 
312 void PFS_user::aggregate_statements()
313 {
314  /* No parent to aggregate to, clean the stats */
316 }
317 
318 void PFS_user::aggregate_stats()
319 {
320  /* No parent to aggregate to, clean the stats */
321  m_disconnected_count= 0;
322 }
323 
324 void PFS_user::release()
325 {
326  dec_refcount();
327 }
328 
329 PFS_user *sanitize_user(PFS_user *unsafe)
330 {
331  if ((&user_array[0] <= unsafe) &&
332  (unsafe < &user_array[user_max]))
333  return unsafe;
334  return NULL;
335 }
336 
337 void purge_user(PFS_thread *thread, PFS_user *user)
338 {
339  LF_PINS *pins= get_user_hash_pins(thread);
340  if (unlikely(pins == NULL))
341  return;
342 
343  PFS_user **entry;
344  entry= reinterpret_cast<PFS_user**>
345  (lf_hash_search(&user_hash, pins,
346  user->m_key.m_hash_key, user->m_key.m_key_length));
347  if (entry && (entry != MY_ERRPTR))
348  {
349  PFS_user *pfs;
350  pfs= *entry;
351  DBUG_ASSERT(pfs == user);
352  if (user->get_refcount() == 0)
353  {
354  lf_hash_delete(&user_hash, pins,
355  user->m_key.m_hash_key, user->m_key.m_key_length);
356  user->m_lock.allocated_to_free();
357  }
358  }
359 
360  lf_hash_search_unpin(pins);
361 }
362 
364 void purge_all_user(void)
365 {
366  PFS_thread *thread= PFS_thread::get_current_thread();
367  if (unlikely(thread == NULL))
368  return;
369 
370  PFS_user *pfs= user_array;
371  PFS_user *pfs_last= user_array + user_max;
372 
373  for ( ; pfs < pfs_last; pfs++)
374  {
375  if (pfs->m_lock.is_populated())
376  {
377  pfs->aggregate();
378  if (pfs->get_refcount() == 0)
379  purge_user(thread, pfs);
380  }
381  }
382 }
383