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