MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
pfs_account.cc
Go to the documentation of this file.
1 /* Copyright (c) 2010, 2013, 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_host.h"
28 #include "pfs_host.h"
29 #include "pfs_user.h"
30 #include "pfs_account.h"
31 #include "pfs_global.h"
32 #include "pfs_instr_class.h"
33 
39 ulong account_max;
40 ulong account_lost;
41 
42 PFS_account *account_array= NULL;
43 
44 static PFS_single_stat *account_instr_class_waits_array= NULL;
45 static PFS_stage_stat *account_instr_class_stages_array= NULL;
46 static PFS_statement_stat *account_instr_class_statements_array= NULL;
47 
48 LF_HASH account_hash;
49 static bool account_hash_inited= false;
50 
56 int init_account(const PFS_global_param *param)
57 {
58  uint index;
59 
60  account_max= param->m_account_sizing;
61 
62  account_array= NULL;
63  account_instr_class_waits_array= NULL;
64  account_instr_class_stages_array= NULL;
65  account_instr_class_statements_array= NULL;
66  uint waits_sizing= account_max * wait_class_max;
67  uint stages_sizing= account_max * stage_class_max;
68  uint statements_sizing= account_max * statement_class_max;
69 
70  if (account_max > 0)
71  {
72  account_array= PFS_MALLOC_ARRAY(account_max, PFS_account,
73  MYF(MY_ZEROFILL));
74  if (unlikely(account_array == NULL))
75  return 1;
76  }
77 
78  if (waits_sizing > 0)
79  {
80  account_instr_class_waits_array=
82  if (unlikely(account_instr_class_waits_array == NULL))
83  return 1;
84  }
85 
86  if (stages_sizing > 0)
87  {
88  account_instr_class_stages_array=
90  if (unlikely(account_instr_class_stages_array == NULL))
91  return 1;
92  }
93 
94  if (statements_sizing > 0)
95  {
96  account_instr_class_statements_array=
98  if (unlikely(account_instr_class_statements_array == NULL))
99  return 1;
100  }
101 
102  for (index= 0; index < account_max; index++)
103  {
104  account_array[index].m_instr_class_waits_stats=
105  &account_instr_class_waits_array[index * wait_class_max];
106  account_array[index].m_instr_class_stages_stats=
107  &account_instr_class_stages_array[index * stage_class_max];
108  account_array[index].m_instr_class_statements_stats=
109  &account_instr_class_statements_array[index * statement_class_max];
110  }
111 
112  return 0;
113 }
114 
116 void cleanup_account(void)
117 {
118  pfs_free(account_array);
119  account_array= NULL;
120  pfs_free(account_instr_class_waits_array);
121  account_instr_class_waits_array= NULL;
122  account_max= 0;
123 }
124 
125 C_MODE_START
126 static uchar *account_hash_get_key(const uchar *entry, size_t *length,
127  my_bool)
128 {
129  const PFS_account * const *typed_entry;
130  const PFS_account *account;
131  const void *result;
132  typed_entry= reinterpret_cast<const PFS_account* const *> (entry);
133  DBUG_ASSERT(typed_entry != NULL);
134  account= *typed_entry;
135  DBUG_ASSERT(account != NULL);
136  *length= account->m_key.m_key_length;
137  result= account->m_key.m_hash_key;
138  return const_cast<uchar*> (reinterpret_cast<const uchar*> (result));
139 }
140 C_MODE_END
141 
147 {
148  if ((! account_hash_inited) && (account_max > 0))
149  {
150  lf_hash_init(&account_hash, sizeof(PFS_account*), LF_HASH_UNIQUE,
151  0, 0, account_hash_get_key, &my_charset_bin);
152  account_hash.size= account_max;
153  account_hash_inited= true;
154  }
155  return 0;
156 }
157 
160 {
161  if (account_hash_inited)
162  {
163  lf_hash_destroy(&account_hash);
164  account_hash_inited= false;
165  }
166 }
167 
168 static LF_PINS* get_account_hash_pins(PFS_thread *thread)
169 {
170  if (unlikely(thread->m_account_hash_pins == NULL))
171  {
172  if (! account_hash_inited)
173  return NULL;
174  thread->m_account_hash_pins= lf_hash_get_pins(&account_hash);
175  }
176  return thread->m_account_hash_pins;
177 }
178 
179 static void set_account_key(PFS_account_key *key,
180  const char *user, uint user_length,
181  const char *host, uint host_length)
182 {
183  DBUG_ASSERT(user_length <= USERNAME_LENGTH);
184  DBUG_ASSERT(host_length <= HOSTNAME_LENGTH);
185 
186  char *ptr= &key->m_hash_key[0];
187  if (user_length > 0)
188  {
189  memcpy(ptr, user, user_length);
190  ptr+= user_length;
191  }
192  ptr[0]= 0;
193  ptr++;
194  if (host_length > 0)
195  {
196  memcpy(ptr, host, host_length);
197  ptr+= host_length;
198  }
199  ptr[0]= 0;
200  ptr++;
201  key->m_key_length= ptr - &key->m_hash_key[0];
202 }
203 
204 PFS_account *
205 find_or_create_account(PFS_thread *thread,
206  const char *username, uint username_length,
207  const char *hostname, uint hostname_length)
208 {
209  if (account_max == 0)
210  {
211  account_lost++;
212  return NULL;
213  }
214 
215  LF_PINS *pins= get_account_hash_pins(thread);
216  if (unlikely(pins == NULL))
217  {
218  account_lost++;
219  return NULL;
220  }
221 
222  PFS_account_key key;
223  set_account_key(&key, username, username_length,
224  hostname, hostname_length);
225 
226  PFS_account **entry;
227  uint retry_count= 0;
228  const uint retry_max= 3;
229 
230 search:
231  entry= reinterpret_cast<PFS_account**>
232  (lf_hash_search(&account_hash, pins,
233  key.m_hash_key, key.m_key_length));
234  if (entry && (entry != MY_ERRPTR))
235  {
236  PFS_account *pfs;
237  pfs= *entry;
238  pfs->inc_refcount();
239  lf_hash_search_unpin(pins);
240  return pfs;
241  }
242 
243  lf_hash_search_unpin(pins);
244 
245  PFS_scan scan;
246  uint random= randomized_index(username, account_max);
247 
248  for (scan.init(random, account_max);
249  scan.has_pass();
250  scan.next_pass())
251  {
252  PFS_account *pfs= account_array + scan.first();
253  PFS_account *pfs_last= account_array + scan.last();
254  for ( ; pfs < pfs_last; pfs++)
255  {
256  if (pfs->m_lock.is_free())
257  {
258  if (pfs->m_lock.free_to_dirty())
259  {
260  pfs->m_key= key;
261  if (username_length > 0)
262  pfs->m_username= &pfs->m_key.m_hash_key[0];
263  else
264  pfs->m_username= NULL;
265  pfs->m_username_length= username_length;
266 
267  if (hostname_length > 0)
268  pfs->m_hostname= &pfs->m_key.m_hash_key[username_length + 1];
269  else
270  pfs->m_hostname= NULL;
271  pfs->m_hostname_length= hostname_length;
272 
273  pfs->m_user= find_or_create_user(thread, username, username_length);
274  pfs->m_host= find_or_create_host(thread, hostname, hostname_length);
275 
276  pfs->init_refcount();
277  pfs->reset_stats();
278  pfs->m_disconnected_count= 0;
279 
280  int res;
281  res= lf_hash_insert(&account_hash, pins, &pfs);
282  if (likely(res == 0))
283  {
284  pfs->m_lock.dirty_to_allocated();
285  return pfs;
286  }
287 
288  if (pfs->m_user)
289  {
290  pfs->m_user->release();
291  pfs->m_user= NULL;
292  }
293  if (pfs->m_host)
294  {
295  pfs->m_host->release();
296  pfs->m_host= NULL;
297  }
298 
299  pfs->m_lock.dirty_to_free();
300 
301  if (res > 0)
302  {
303  if (++retry_count > retry_max)
304  {
305  account_lost++;
306  return NULL;
307  }
308  goto search;
309  }
310 
311  account_lost++;
312  return NULL;
313  }
314  }
315  }
316  }
317 
318  account_lost++;
319  return NULL;
320 }
321 
322 void PFS_account::aggregate(PFS_user *safe_user, PFS_host *safe_host)
323 {
324  aggregate_waits(safe_user, safe_host);
325  aggregate_stages(safe_user, safe_host);
326  aggregate_statements(safe_user, safe_host);
327  aggregate_stats(safe_user, safe_host);
328 }
329 
330 void PFS_account::aggregate_waits(PFS_user *safe_user, PFS_host *safe_host)
331 {
332  if (likely(safe_user != NULL && safe_host != NULL))
333  {
334  /*
335  Aggregate EVENTS_WAITS_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME to:
336  - EVENTS_WAITS_SUMMARY_BY_USER_BY_EVENT_NAME
337  - EVENTS_WAITS_SUMMARY_BY_HOST_BY_EVENT_NAME
338  in parallel.
339  */
340  aggregate_all_event_names(m_instr_class_waits_stats,
341  safe_user->m_instr_class_waits_stats,
342  safe_host->m_instr_class_waits_stats);
343  return;
344  }
345 
346  if (safe_user != NULL)
347  {
348  /*
349  Aggregate EVENTS_WAITS_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME to:
350  - EVENTS_WAITS_SUMMARY_BY_USER_BY_EVENT_NAME
351  */
352  aggregate_all_event_names(m_instr_class_waits_stats,
353  safe_user->m_instr_class_waits_stats);
354  return;
355  }
356 
357  if (safe_host != NULL)
358  {
359  /*
360  Aggregate EVENTS_WAITS_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME to:
361  - EVENTS_WAITS_SUMMARY_BY_HOST_BY_EVENT_NAME
362  */
363  aggregate_all_event_names(m_instr_class_waits_stats,
364  safe_host->m_instr_class_waits_stats);
365  return;
366  }
367 
368  /* Orphan account, no parent to aggregate to. */
370  return;
371 }
372 
373 void PFS_account::aggregate_stages(PFS_user *safe_user, PFS_host *safe_host)
374 {
375  if (likely(safe_user != NULL && safe_host != NULL))
376  {
377  /*
378  Aggregate EVENTS_STAGES_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME to:
379  - EVENTS_STAGES_SUMMARY_BY_USER_BY_EVENT_NAME
380  - EVENTS_STAGES_SUMMARY_BY_HOST_BY_EVENT_NAME
381  in parallel.
382  */
383  aggregate_all_stages(m_instr_class_stages_stats,
384  safe_user->m_instr_class_stages_stats,
385  safe_host->m_instr_class_stages_stats);
386  return;
387  }
388 
389  if (safe_user != NULL)
390  {
391  /*
392  Aggregate EVENTS_STAGES_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME to:
393  - EVENTS_STAGES_SUMMARY_BY_USER_BY_EVENT_NAME
394  - EVENTS_STAGES_SUMMARY_GLOBAL_BY_EVENT_NAME
395  in parallel.
396  */
397  aggregate_all_stages(m_instr_class_stages_stats,
398  safe_user->m_instr_class_stages_stats,
399  global_instr_class_stages_array);
400  return;
401  }
402 
403  if (safe_host != NULL)
404  {
405  /*
406  Aggregate EVENTS_STAGES_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME to:
407  - EVENTS_STAGES_SUMMARY_BY_HOST_BY_EVENT_NAME
408  */
409  aggregate_all_stages(m_instr_class_stages_stats,
410  safe_host->m_instr_class_stages_stats);
411  return;
412  }
413 
414  /*
415  Aggregate EVENTS_STAGES_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME to:
416  - EVENTS_STAGES_SUMMARY_GLOBAL_BY_EVENT_NAME
417  */
418  aggregate_all_stages(m_instr_class_stages_stats,
419  global_instr_class_stages_array);
420  return;
421 }
422 
423 void PFS_account::aggregate_statements(PFS_user *safe_user, PFS_host *safe_host)
424 {
425  if (likely(safe_user != NULL && safe_host != NULL))
426  {
427  /*
428  Aggregate EVENTS_STATEMENTS_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME to:
429  - EVENTS_STATEMENTS_SUMMARY_BY_USER_BY_EVENT_NAME
430  - EVENTS_STATEMENTS_SUMMARY_BY_HOST_BY_EVENT_NAME
431  in parallel.
432  */
433  aggregate_all_statements(m_instr_class_statements_stats,
435  safe_host->m_instr_class_statements_stats);
436  return;
437  }
438 
439  if (safe_user != NULL)
440  {
441  /*
442  Aggregate EVENTS_STATEMENTS_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME to:
443  - EVENTS_STATEMENTS_SUMMARY_BY_USER_BY_EVENT_NAME
444  - EVENTS_STATEMENTS_SUMMARY_GLOBAL_BY_EVENT_NAME
445  in parallel.
446  */
447  aggregate_all_statements(m_instr_class_statements_stats,
449  global_instr_class_statements_array);
450  return;
451  }
452 
453  if (safe_host != NULL)
454  {
455  /*
456  Aggregate EVENTS_STATEMENTS_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME to:
457  - EVENTS_STATEMENTS_SUMMARY_BY_HOST_BY_EVENT_NAME
458  */
459  aggregate_all_statements(m_instr_class_statements_stats,
460  safe_host->m_instr_class_statements_stats);
461  return;
462  }
463 
464  /*
465  Aggregate EVENTS_STATEMENTS_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME to:
466  - EVENTS_STATEMENTS_SUMMARY_GLOBAL_BY_EVENT_NAME
467  */
468  aggregate_all_statements(m_instr_class_statements_stats,
469  global_instr_class_statements_array);
470  return;
471 }
472 
473 void PFS_account::aggregate_stats(PFS_user *safe_user, PFS_host *safe_host)
474 {
475  if (likely(safe_user != NULL && safe_host != NULL))
476  {
477  safe_user->m_disconnected_count+= m_disconnected_count;
478  safe_host->m_disconnected_count+= m_disconnected_count;
479  m_disconnected_count= 0;
480  return;
481  }
482 
483  if (safe_user != NULL)
484  {
485  safe_user->m_disconnected_count+= m_disconnected_count;
486  m_disconnected_count= 0;
487  return;
488  }
489 
490  if (safe_host != NULL)
491  {
492  safe_host->m_disconnected_count+= m_disconnected_count;
493  m_disconnected_count= 0;
494  return;
495  }
496 
497  m_disconnected_count= 0;
498  return;
499 }
500 
501 void PFS_account::release()
502 {
503  dec_refcount();
504 }
505 
506 PFS_account *sanitize_account(PFS_account *unsafe)
507 {
508  if ((&account_array[0] <= unsafe) &&
509  (unsafe < &account_array[account_max]))
510  return unsafe;
511  return NULL;
512 }
513 
514 void purge_account(PFS_thread *thread, PFS_account *account,
515  PFS_user *safe_user, PFS_host *safe_host)
516 {
517  account->aggregate(safe_user, safe_host);
518 
519  LF_PINS *pins= get_account_hash_pins(thread);
520  if (unlikely(pins == NULL))
521  return;
522 
523  PFS_account **entry;
524  entry= reinterpret_cast<PFS_account**>
525  (lf_hash_search(&account_hash, pins,
526  account->m_key.m_hash_key,
527  account->m_key.m_key_length));
528  if (entry && (entry != MY_ERRPTR))
529  {
530  PFS_account *pfs;
531  pfs= *entry;
532  DBUG_ASSERT(pfs == account);
533  if (account->get_refcount() == 0)
534  {
535  lf_hash_delete(&account_hash, pins,
536  account->m_key.m_hash_key,
537  account->m_key.m_key_length);
538  if (account->m_user != NULL)
539  {
540  account->m_user->release();
541  account->m_user= NULL;
542  }
543  if (account->m_host != NULL)
544  {
545  account->m_host->release();
546  account->m_host= NULL;
547  }
548  account->m_lock.allocated_to_free();
549  }
550  }
551 
552  lf_hash_search_unpin(pins);
553 }
554 
557 {
558  PFS_thread *thread= PFS_thread::get_current_thread();
559  if (unlikely(thread == NULL))
560  return;
561 
562  PFS_account *pfs= account_array;
563  PFS_account *pfs_last= account_array + account_max;
564  PFS_user *user;
565  PFS_host *host;
566 
567  for ( ; pfs < pfs_last; pfs++)
568  {
569  if (pfs->m_lock.is_populated())
570  {
571  user= sanitize_user(pfs->m_user);
572  host= sanitize_host(pfs->m_host);
573  pfs->aggregate_stats(user, host);
574 
575  if (pfs->get_refcount() == 0)
576  purge_account(thread, pfs, user, host);
577  }
578  }
579 }
580