1 /* Copyright (c) 2010, 2020, 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 St, Fifth Floor, Boston, MA 02110-1301  USA
22   */
23 
24 /**
25   @file storage/perfschema/pfs_account.cc
26   Performance schema account (implementation).
27 */
28 
29 #include "storage/perfschema/pfs_account.h"
30 
31 #include "my_compiler.h"
32 #include "my_dbug.h"
33 #include "my_sys.h"
34 #include "sql/mysqld.h"  // global_status_var
35 #include "storage/perfschema/pfs.h"
36 #include "storage/perfschema/pfs_buffer_container.h"
37 #include "storage/perfschema/pfs_global.h"
38 #include "storage/perfschema/pfs_host.h"
39 #include "storage/perfschema/pfs_instr.h"
40 #include "storage/perfschema/pfs_instr_class.h"
41 #include "storage/perfschema/pfs_setup_actor.h"
42 #include "storage/perfschema/pfs_stat.h"
43 #include "storage/perfschema/pfs_user.h"
44 
45 /**
46   @addtogroup performance_schema_buffers
47   @{
48 */
49 
50 LF_HASH account_hash;
51 static bool account_hash_inited = false;
52 
53 /**
54   Initialize the user buffers.
55   @param param                        sizing parameters
56   @return 0 on success
57 */
init_account(const PFS_global_param * param)58 int init_account(const PFS_global_param *param) {
59   if (global_account_container.init(param->m_account_sizing)) {
60     return 1;
61   }
62 
63   return 0;
64 }
65 
66 /** Cleanup all the account buffers. */
cleanup_account(void)67 void cleanup_account(void) { global_account_container.cleanup(); }
68 
account_hash_get_key(const uchar * entry,size_t * length)69 static const uchar *account_hash_get_key(const uchar *entry, size_t *length) {
70   const PFS_account *const *typed_entry;
71   const PFS_account *account;
72   const void *result;
73   typed_entry = reinterpret_cast<const PFS_account *const *>(entry);
74   DBUG_ASSERT(typed_entry != nullptr);
75   account = *typed_entry;
76   DBUG_ASSERT(account != nullptr);
77   *length = account->m_key.m_key_length;
78   result = account->m_key.m_hash_key;
79   return reinterpret_cast<const uchar *>(result);
80 }
81 
82 /**
83   Initialize the user hash.
84   @return 0 on success
85 */
init_account_hash(const PFS_global_param * param)86 int init_account_hash(const PFS_global_param *param) {
87   if ((!account_hash_inited) && (param->m_account_sizing != 0)) {
88     lf_hash_init(&account_hash, sizeof(PFS_account *), LF_HASH_UNIQUE, 0, 0,
89                  account_hash_get_key, &my_charset_bin);
90     account_hash_inited = true;
91   }
92   return 0;
93 }
94 
95 /** Cleanup the user hash. */
cleanup_account_hash(void)96 void cleanup_account_hash(void) {
97   if (account_hash_inited) {
98     lf_hash_destroy(&account_hash);
99     account_hash_inited = false;
100   }
101 }
102 
get_account_hash_pins(PFS_thread * thread)103 static LF_PINS *get_account_hash_pins(PFS_thread *thread) {
104   if (unlikely(thread->m_account_hash_pins == nullptr)) {
105     if (!account_hash_inited) {
106       return nullptr;
107     }
108     thread->m_account_hash_pins = lf_hash_get_pins(&account_hash);
109   }
110   return thread->m_account_hash_pins;
111 }
112 
set_account_key(PFS_account_key * key,const char * user,uint user_length,const char * host,uint host_length)113 static void set_account_key(PFS_account_key *key, const char *user,
114                             uint user_length, const char *host,
115                             uint host_length) {
116   DBUG_ASSERT(user_length <= USERNAME_LENGTH);
117   DBUG_ASSERT(host_length <= HOSTNAME_LENGTH);
118 
119   char *ptr = &key->m_hash_key[0];
120   if (user_length > 0) {
121     memcpy(ptr, user, user_length);
122     ptr += user_length;
123   }
124   ptr[0] = 0;
125   ptr++;
126   if (host_length > 0) {
127     memcpy(ptr, host, host_length);
128     ptr += host_length;
129   }
130   ptr[0] = 0;
131   ptr++;
132   key->m_key_length = ptr - &key->m_hash_key[0];
133 }
134 
find_or_create_account(PFS_thread * thread,const char * username,uint username_length,const char * hostname,uint hostname_length)135 PFS_account *find_or_create_account(PFS_thread *thread, const char *username,
136                                     uint username_length, const char *hostname,
137                                     uint hostname_length) {
138   LF_PINS *pins = get_account_hash_pins(thread);
139   if (unlikely(pins == nullptr)) {
140     global_account_container.m_lost++;
141     return nullptr;
142   }
143 
144   PFS_account_key key;
145   set_account_key(&key, username, username_length, hostname, hostname_length);
146 
147   PFS_account **entry;
148   PFS_account *pfs;
149   uint retry_count = 0;
150   const uint retry_max = 3;
151   pfs_dirty_state dirty_state;
152 
153 search:
154   entry = reinterpret_cast<PFS_account **>(
155       lf_hash_search(&account_hash, pins, key.m_hash_key, key.m_key_length));
156   if (entry && (entry != MY_LF_ERRPTR)) {
157     pfs = *entry;
158     pfs->inc_refcount();
159     lf_hash_search_unpin(pins);
160     return pfs;
161   }
162 
163   lf_hash_search_unpin(pins);
164 
165   pfs = global_account_container.allocate(&dirty_state);
166   if (pfs != nullptr) {
167     pfs->m_key = key;
168     if (username_length > 0) {
169       pfs->m_username = &pfs->m_key.m_hash_key[0];
170     } else {
171       pfs->m_username = nullptr;
172     }
173     pfs->m_username_length = username_length;
174 
175     if (hostname_length > 0) {
176       pfs->m_hostname = &pfs->m_key.m_hash_key[username_length + 1];
177     } else {
178       pfs->m_hostname = nullptr;
179     }
180     pfs->m_hostname_length = hostname_length;
181 
182     pfs->m_user = find_or_create_user(thread, username, username_length);
183     pfs->m_host = find_or_create_host(thread, hostname, hostname_length);
184 
185     pfs->init_refcount();
186     pfs->reset_stats();
187     pfs->m_disconnected_count = 0;
188 
189     if (username_length > 0 && hostname_length > 0) {
190       lookup_setup_actor(thread, username, username_length, hostname,
191                          hostname_length, &pfs->m_enabled, &pfs->m_history);
192     } else {
193       pfs->m_enabled = true;
194       pfs->m_history = true;
195     }
196 
197     int res;
198     pfs->m_lock.dirty_to_allocated(&dirty_state);
199     res = lf_hash_insert(&account_hash, pins, &pfs);
200     if (likely(res == 0)) {
201       return pfs;
202     }
203 
204     if (pfs->m_user) {
205       pfs->m_user->release();
206       pfs->m_user = nullptr;
207     }
208     if (pfs->m_host) {
209       pfs->m_host->release();
210       pfs->m_host = nullptr;
211     }
212 
213     global_account_container.deallocate(pfs);
214 
215     if (res > 0) {
216       if (++retry_count > retry_max) {
217         global_account_container.m_lost++;
218         return nullptr;
219       }
220       goto search;
221     }
222 
223     global_account_container.m_lost++;
224     return nullptr;
225   }
226 
227   return nullptr;
228 }
229 
aggregate(bool alive,PFS_user * safe_user,PFS_host * safe_host)230 void PFS_account::aggregate(bool alive, PFS_user *safe_user,
231                             PFS_host *safe_host) {
232   aggregate_waits(safe_user, safe_host);
233   aggregate_stages(safe_user, safe_host);
234   aggregate_statements(safe_user, safe_host);
235   aggregate_transactions(safe_user, safe_host);
236   aggregate_errors(safe_user, safe_host);
237   aggregate_memory(alive, safe_user, safe_host);
238   aggregate_status(safe_user, safe_host);
239   aggregate_stats(safe_user, safe_host);
240 }
241 
aggregate_waits(PFS_user * safe_user,PFS_host * safe_host)242 void PFS_account::aggregate_waits(PFS_user *safe_user, PFS_host *safe_host) {
243   if (read_instr_class_waits_stats() == nullptr) {
244     return;
245   }
246 
247   if (likely(safe_user != nullptr && safe_host != nullptr)) {
248     /*
249       Aggregate EVENTS_WAITS_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME to:
250       -  EVENTS_WAITS_SUMMARY_BY_USER_BY_EVENT_NAME
251       -  EVENTS_WAITS_SUMMARY_BY_HOST_BY_EVENT_NAME
252       in parallel.
253     */
254     aggregate_all_event_names(write_instr_class_waits_stats(),
255                               safe_user->write_instr_class_waits_stats(),
256                               safe_host->write_instr_class_waits_stats());
257     return;
258   }
259 
260   if (safe_user != nullptr) {
261     /*
262       Aggregate EVENTS_WAITS_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME to:
263       -  EVENTS_WAITS_SUMMARY_BY_USER_BY_EVENT_NAME
264     */
265     aggregate_all_event_names(write_instr_class_waits_stats(),
266                               safe_user->write_instr_class_waits_stats());
267     return;
268   }
269 
270   if (safe_host != nullptr) {
271     /*
272       Aggregate EVENTS_WAITS_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME to:
273       -  EVENTS_WAITS_SUMMARY_BY_HOST_BY_EVENT_NAME
274     */
275     aggregate_all_event_names(write_instr_class_waits_stats(),
276                               safe_host->write_instr_class_waits_stats());
277     return;
278   }
279 
280   /* Orphan account, no parent to aggregate to. */
281   reset_waits_stats();
282   return;
283 }
284 
aggregate_stages(PFS_user * safe_user,PFS_host * safe_host)285 void PFS_account::aggregate_stages(PFS_user *safe_user, PFS_host *safe_host) {
286   if (read_instr_class_stages_stats() == nullptr) {
287     return;
288   }
289 
290   if (likely(safe_user != nullptr && safe_host != nullptr)) {
291     /*
292       Aggregate EVENTS_STAGES_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME to:
293       -  EVENTS_STAGES_SUMMARY_BY_USER_BY_EVENT_NAME
294       -  EVENTS_STAGES_SUMMARY_BY_HOST_BY_EVENT_NAME
295       in parallel.
296     */
297     aggregate_all_stages(write_instr_class_stages_stats(),
298                          safe_user->write_instr_class_stages_stats(),
299                          safe_host->write_instr_class_stages_stats());
300     return;
301   }
302 
303   if (safe_user != nullptr) {
304     /*
305       Aggregate EVENTS_STAGES_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME to:
306       -  EVENTS_STAGES_SUMMARY_BY_USER_BY_EVENT_NAME
307       -  EVENTS_STAGES_SUMMARY_GLOBAL_BY_EVENT_NAME
308       in parallel.
309     */
310     aggregate_all_stages(write_instr_class_stages_stats(),
311                          safe_user->write_instr_class_stages_stats(),
312                          global_instr_class_stages_array);
313     return;
314   }
315 
316   if (safe_host != nullptr) {
317     /*
318       Aggregate EVENTS_STAGES_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME to:
319       -  EVENTS_STAGES_SUMMARY_BY_HOST_BY_EVENT_NAME
320     */
321     aggregate_all_stages(write_instr_class_stages_stats(),
322                          safe_host->write_instr_class_stages_stats());
323     return;
324   }
325 
326   /*
327     Aggregate EVENTS_STAGES_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME to:
328     -  EVENTS_STAGES_SUMMARY_GLOBAL_BY_EVENT_NAME
329   */
330   aggregate_all_stages(write_instr_class_stages_stats(),
331                        global_instr_class_stages_array);
332   return;
333 }
334 
aggregate_statements(PFS_user * safe_user,PFS_host * safe_host)335 void PFS_account::aggregate_statements(PFS_user *safe_user,
336                                        PFS_host *safe_host) {
337   if (read_instr_class_statements_stats() == nullptr) {
338     return;
339   }
340 
341   if (likely(safe_user != nullptr && safe_host != nullptr)) {
342     /*
343       Aggregate EVENTS_STATEMENTS_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME to:
344       -  EVENTS_STATEMENTS_SUMMARY_BY_USER_BY_EVENT_NAME
345       -  EVENTS_STATEMENTS_SUMMARY_BY_HOST_BY_EVENT_NAME
346       in parallel.
347     */
348     aggregate_all_statements(write_instr_class_statements_stats(),
349                              safe_user->write_instr_class_statements_stats(),
350                              safe_host->write_instr_class_statements_stats());
351     return;
352   }
353 
354   if (safe_user != nullptr) {
355     /*
356       Aggregate EVENTS_STATEMENTS_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME to:
357       -  EVENTS_STATEMENTS_SUMMARY_BY_USER_BY_EVENT_NAME
358       -  EVENTS_STATEMENTS_SUMMARY_GLOBAL_BY_EVENT_NAME
359       in parallel.
360     */
361     aggregate_all_statements(write_instr_class_statements_stats(),
362                              safe_user->write_instr_class_statements_stats(),
363                              global_instr_class_statements_array);
364     return;
365   }
366 
367   if (safe_host != nullptr) {
368     /*
369       Aggregate EVENTS_STATEMENTS_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME to:
370       -  EVENTS_STATEMENTS_SUMMARY_BY_HOST_BY_EVENT_NAME
371     */
372     aggregate_all_statements(write_instr_class_statements_stats(),
373                              safe_host->write_instr_class_statements_stats());
374     return;
375   }
376 
377   /*
378     Aggregate EVENTS_STATEMENTS_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME to:
379     -  EVENTS_STATEMENTS_SUMMARY_GLOBAL_BY_EVENT_NAME
380   */
381   aggregate_all_statements(write_instr_class_statements_stats(),
382                            global_instr_class_statements_array);
383   return;
384 }
385 
aggregate_transactions(PFS_user * safe_user,PFS_host * safe_host)386 void PFS_account::aggregate_transactions(PFS_user *safe_user,
387                                          PFS_host *safe_host) {
388   if (read_instr_class_transactions_stats() == nullptr) {
389     return;
390   }
391 
392   if (likely(safe_user != nullptr && safe_host != nullptr)) {
393     /*
394       Aggregate EVENTS_TRANSACTIONS_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME to:
395       -  EVENTS_TRANSACTIONS_SUMMARY_BY_USER_BY_EVENT_NAME
396       -  EVENTS_TRANSACTIONS_SUMMARY_BY_HOST_BY_EVENT_NAME
397       in parallel.
398     */
399     aggregate_all_transactions(
400         write_instr_class_transactions_stats(),
401         safe_user->write_instr_class_transactions_stats(),
402         safe_host->write_instr_class_transactions_stats());
403     return;
404   }
405 
406   if (safe_user != nullptr) {
407     /*
408       Aggregate EVENTS_TRANSACTIONS_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME to:
409       -  EVENTS_TRANSACTIONS_SUMMARY_BY_USER_BY_EVENT_NAME
410       -  EVENTS_TRANSACTIONS_SUMMARY_GLOBAL_BY_EVENT_NAME
411       in parallel.
412     */
413     aggregate_all_transactions(
414         write_instr_class_transactions_stats(),
415         safe_user->write_instr_class_transactions_stats(),
416         &global_transaction_stat);
417     return;
418   }
419 
420   if (safe_host != nullptr) {
421     /*
422       Aggregate EVENTS_TRANSACTIONS_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME to:
423       -  EVENTS_TRANSACTIONS_SUMMARY_BY_HOST_BY_EVENT_NAME
424     */
425     aggregate_all_transactions(
426         write_instr_class_transactions_stats(),
427         safe_host->write_instr_class_transactions_stats());
428     return;
429   }
430 
431   /*
432     Aggregate EVENTS_TRANSACTIONS_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME to:
433     -  EVENTS_TRANSACTIONS_SUMMARY_GLOBAL_BY_EVENT_NAME
434   */
435   aggregate_all_transactions(write_instr_class_transactions_stats(),
436                              &global_transaction_stat);
437   return;
438 }
439 
aggregate_errors(PFS_user * safe_user,PFS_host * safe_host)440 void PFS_account::aggregate_errors(PFS_user *safe_user, PFS_host *safe_host) {
441   if (read_instr_class_errors_stats() == nullptr) {
442     return;
443   }
444 
445   if (likely(safe_user != nullptr && safe_host != nullptr)) {
446     /*
447       Aggregate EVENTS_ERRORS_SUMMARY_BY_ACCOUNT_BY_ERROR to:
448       -  EVENTS_ERRORS_SUMMARY_BY_USER_BY_ERROR
449       -  EVENTS_ERRORS_SUMMARY_BY_HOST_BY_ERROR
450       in parallel.
451     */
452     aggregate_all_errors(write_instr_class_errors_stats(),
453                          safe_user->write_instr_class_errors_stats(),
454                          safe_host->write_instr_class_errors_stats());
455     return;
456   }
457 
458   if (safe_user != nullptr) {
459     /*
460       Aggregate EVENTS_ERRORS_SUMMARY_BY_ACCOUNT_BY_ERROR to:
461       -  EVENTS_ERRORS_SUMMARY_BY_USER_BY_ERROR
462       -  EVENTS_ERRORS_SUMMARY_GLOBAL_BY_ERROR
463       in parallel.
464     */
465     aggregate_all_errors(write_instr_class_errors_stats(),
466                          safe_user->write_instr_class_errors_stats(),
467                          &global_error_stat);
468     return;
469   }
470 
471   if (safe_host != nullptr) {
472     /*
473       Aggregate EVENTS_ERRORS_SUMMARY_BY_ACCOUNT_BY_ERROR to:
474       -  EVENTS_ERRORS_SUMMARY_BY_HOST_BY_ERROR
475     */
476     aggregate_all_errors(write_instr_class_errors_stats(),
477                          safe_host->write_instr_class_errors_stats());
478     return;
479   }
480 
481   /*
482     Aggregate EVENTS_ERRORS_SUMMARY_BY_ACCOUNT_BY_ERROR to:
483     -  EVENTS_ERRORS_SUMMARY_GLOBAL_BY_ERROR
484   */
485   aggregate_all_errors(write_instr_class_errors_stats(), &global_error_stat);
486   return;
487 }
488 
aggregate_memory(bool alive,PFS_user * safe_user,PFS_host * safe_host)489 void PFS_account::aggregate_memory(bool alive, PFS_user *safe_user,
490                                    PFS_host *safe_host) {
491   if (read_instr_class_memory_stats() == nullptr) {
492     return;
493   }
494 
495   if (likely(safe_user != nullptr && safe_host != nullptr)) {
496     /*
497       Aggregate MEMORY_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME to:
498       - MEMORY_SUMMARY_BY_USER_BY_EVENT_NAME
499       - MEMORY_SUMMARY_BY_HOST_BY_EVENT_NAME
500       in parallel.
501     */
502     aggregate_all_memory(alive, write_instr_class_memory_stats(),
503                          safe_user->write_instr_class_memory_stats(),
504                          safe_host->write_instr_class_memory_stats());
505     return;
506   }
507 
508   if (safe_user != nullptr) {
509     /*
510       Aggregate MEMORY_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME to:
511       - MEMORY_SUMMARY_BY_USER_BY_EVENT_NAME
512       - MEMORY_SUMMARY_GLOBAL_BY_EVENT_NAME
513       in parallel.
514     */
515     aggregate_all_memory(alive, write_instr_class_memory_stats(),
516                          safe_user->write_instr_class_memory_stats(),
517                          global_instr_class_memory_array);
518     return;
519   }
520 
521   if (safe_host != nullptr) {
522     /*
523       Aggregate MEMORY_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME to:
524       - MEMORY_SUMMARY_BY_HOST_BY_EVENT_NAME
525     */
526     aggregate_all_memory(alive, write_instr_class_memory_stats(),
527                          safe_host->write_instr_class_memory_stats());
528     return;
529   }
530 
531   /*
532     Aggregate MEMORY_SUMMARY_BY_ACCOUNT_BY_EVENT_NAME to:
533     - MEMORY_SUMMARY_GLOBAL_BY_EVENT_NAME
534   */
535   aggregate_all_memory(alive, write_instr_class_memory_stats(),
536                        global_instr_class_memory_array);
537   return;
538 }
539 
aggregate_status(PFS_user * safe_user,PFS_host * safe_host)540 void PFS_account::aggregate_status(PFS_user *safe_user, PFS_host *safe_host) {
541   if (likely(safe_user != nullptr && safe_host != nullptr)) {
542     /*
543       Aggregate STATUS_BY_ACCOUNT to:
544       - STATUS_BY_USER
545       - STATUS_BY_HOST
546     */
547     safe_user->m_status_stats.aggregate(&m_status_stats);
548     safe_host->m_status_stats.aggregate(&m_status_stats);
549     m_status_stats.reset();
550     return;
551   }
552 
553   if (safe_user != nullptr) {
554     /*
555       Aggregate STATUS_BY_ACCOUNT to:
556       - STATUS_BY_USER
557       - GLOBAL_STATUS
558     */
559     safe_user->m_status_stats.aggregate(&m_status_stats);
560     m_status_stats.aggregate_to(&global_status_var);
561     m_status_stats.reset();
562     return;
563   }
564 
565   if (safe_host != nullptr) {
566     /*
567       Aggregate STATUS_BY_ACCOUNT to:
568       - STATUS_BY_HOST
569     */
570     safe_host->m_status_stats.aggregate(&m_status_stats);
571     m_status_stats.reset();
572     return;
573   }
574 
575   /*
576     Aggregate STATUS_BY_ACCOUNT to:
577     - GLOBAL_STATUS
578   */
579   m_status_stats.aggregate_to(&global_status_var);
580   m_status_stats.reset();
581   return;
582 }
583 
aggregate_stats(PFS_user * safe_user,PFS_host * safe_host)584 void PFS_account::aggregate_stats(PFS_user *safe_user, PFS_host *safe_host) {
585   if (likely(safe_user != nullptr && safe_host != nullptr)) {
586     safe_user->m_disconnected_count += m_disconnected_count;
587     safe_host->m_disconnected_count += m_disconnected_count;
588     m_disconnected_count = 0;
589     return;
590   }
591 
592   if (safe_user != nullptr) {
593     safe_user->m_disconnected_count += m_disconnected_count;
594     m_disconnected_count = 0;
595     return;
596   }
597 
598   if (safe_host != nullptr) {
599     safe_host->m_disconnected_count += m_disconnected_count;
600     m_disconnected_count = 0;
601     return;
602   }
603 
604   m_disconnected_count = 0;
605   return;
606 }
607 
release()608 void PFS_account::release() { dec_refcount(); }
609 
rebase_memory_stats()610 void PFS_account::rebase_memory_stats() {
611   PFS_memory_shared_stat *stat = m_instr_class_memory_stats;
612   PFS_memory_shared_stat *stat_last = stat + memory_class_max;
613   for (; stat < stat_last; stat++) {
614     stat->reset();
615   }
616 }
617 
carry_memory_stat_delta(PFS_memory_stat_delta * delta,uint index)618 void PFS_account::carry_memory_stat_delta(PFS_memory_stat_delta *delta,
619                                           uint index) {
620   PFS_memory_shared_stat *event_name_array;
621   PFS_memory_shared_stat *stat;
622   PFS_memory_stat_delta delta_buffer;
623   PFS_memory_stat_delta *remaining_delta;
624 
625   event_name_array = write_instr_class_memory_stats();
626   stat = &event_name_array[index];
627   remaining_delta = stat->apply_delta(delta, &delta_buffer);
628 
629   if (remaining_delta == nullptr) {
630     return;
631   }
632 
633   if (m_user != nullptr) {
634     m_user->carry_memory_stat_delta(remaining_delta, index);
635     /* do not return, need to process m_host below */
636   }
637 
638   if (m_host != nullptr) {
639     m_host->carry_memory_stat_delta(remaining_delta, index);
640     return;
641   }
642 
643   carry_global_memory_stat_delta(remaining_delta, index);
644 }
645 
sanitize_account(PFS_account * unsafe)646 PFS_account *sanitize_account(PFS_account *unsafe) {
647   return global_account_container.sanitize(unsafe);
648 }
649 
purge_account(PFS_thread * thread,PFS_account * account)650 static void purge_account(PFS_thread *thread, PFS_account *account) {
651   LF_PINS *pins = get_account_hash_pins(thread);
652   if (unlikely(pins == nullptr)) {
653     return;
654   }
655 
656   PFS_account **entry;
657   entry = reinterpret_cast<PFS_account **>(
658       lf_hash_search(&account_hash, pins, account->m_key.m_hash_key,
659                      account->m_key.m_key_length));
660   if (entry && (entry != MY_LF_ERRPTR)) {
661     DBUG_ASSERT(*entry == account);
662     if (account->get_refcount() == 0) {
663       lf_hash_delete(&account_hash, pins, account->m_key.m_hash_key,
664                      account->m_key.m_key_length);
665       account->aggregate(false, account->m_user, account->m_host);
666       if (account->m_user != nullptr) {
667         account->m_user->release();
668         account->m_user = nullptr;
669       }
670       if (account->m_host != nullptr) {
671         account->m_host->release();
672         account->m_host = nullptr;
673       }
674       global_account_container.deallocate(account);
675     }
676   }
677 
678   lf_hash_search_unpin(pins);
679 }
680 
681 class Proc_purge_account : public PFS_buffer_processor<PFS_account> {
682  public:
Proc_purge_account(PFS_thread * thread)683   Proc_purge_account(PFS_thread *thread) : m_thread(thread) {}
684 
operator ()(PFS_account * pfs)685   virtual void operator()(PFS_account *pfs) {
686     PFS_user *user = sanitize_user(pfs->m_user);
687     PFS_host *host = sanitize_host(pfs->m_host);
688     pfs->aggregate(true, user, host);
689 
690     if (pfs->get_refcount() == 0) {
691       purge_account(m_thread, pfs);
692     }
693   }
694 
695  private:
696   PFS_thread *m_thread;
697 };
698 
699 /** Purge non connected accounts, reset stats of connected account. */
purge_all_account(void)700 void purge_all_account(void) {
701   PFS_thread *thread = PFS_thread::get_current_thread();
702   if (unlikely(thread == nullptr)) {
703     return;
704   }
705 
706   Proc_purge_account proc(thread);
707   global_account_container.apply(proc);
708 }
709 
710 class Proc_update_accounts_derived_flags
711     : public PFS_buffer_processor<PFS_account> {
712  public:
Proc_update_accounts_derived_flags(PFS_thread * thread)713   Proc_update_accounts_derived_flags(PFS_thread *thread) : m_thread(thread) {}
714 
operator ()(PFS_account * pfs)715   virtual void operator()(PFS_account *pfs) {
716     if (pfs->m_username_length > 0 && pfs->m_hostname_length > 0) {
717       lookup_setup_actor(m_thread, pfs->m_username, pfs->m_username_length,
718                          pfs->m_hostname, pfs->m_hostname_length,
719                          &pfs->m_enabled, &pfs->m_history);
720     } else {
721       pfs->m_enabled = true;
722       pfs->m_history = true;
723     }
724   }
725 
726  private:
727   PFS_thread *m_thread;
728 };
729 
update_accounts_derived_flags(PFS_thread * thread)730 void update_accounts_derived_flags(PFS_thread *thread) {
731   Proc_update_accounts_derived_flags proc(thread);
732   global_account_container.apply(proc);
733 }
734 
735 /** @} */
736