1 /* Copyright (c) 2015, 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 #ifndef PFS_VARIABLE_H
24 #define PFS_VARIABLE_H
25
26 /**
27 @file storage/perfschema/pfs_variable.h
28 Performance schema system and status variables (declarations).
29 */
30
31 /**
32 OVERVIEW
33 --------
34 Status and system variables are implemented differently in the server, but the
35 steps to process them in the Performance Schema are essentially the same:
36
37 1. INITIALIZE - Build or acquire a sorted list of variables to use for input.
38 Use the SHOW_VAR struct as an intermediate format common to system, status
39 and user vars:
40
41 SHOW_VAR
42 Name - Text string
43 Value - Pointer to memory location, function, subarray structure
44 Type - Scalar, function, or subarray
45 Scope - SESSION, GLOBAL, BOTH
46
47 Steps:
48 - Register the server's internal buffer with the class. Acquire locks
49 if necessary, then scan the contents of the input buffer.
50 - For system variables, convert each element to SHOW_VAR format, store in
51 a temporary array.
52 - For status variables, copy existing global status array into a local
53 array that can be used without locks. Expand nested subarrays, indicated
54 by a type of SHOW_ARRAY.
55
56 2. MATERIALIZE - Convert the list of SHOW_VAR variables to string format,
57 store in a local cache:
58 - Resolve each variable according to the type.
59 - Recursively process unexpanded nested arrays and callback functions.
60 - Aggregate values across threads for global status.
61 - Convert numeric values to a string.
62 - Prefix variable name with the plugin name.
63
64 3. OUTPUT - Iterate the cache for the SHOW command or table query.
65
66 CLASS OVERVIEW
67 --------------
68 1. System_variable - A materialized system variable
69 2. Status_variable - A materialized status variable
70 3. PFS_variable_cache - Base class that defines the interface for the operations above.
71 public
72 init_show_var_array() - Build SHOW_VAR list of variables for processing
73 materialize_global() - Materialize global variables, aggregate across sessions
74 materialize_session() - Materialize variables for a given PFS_thread or THD
75 materialize_user() - Materialize variables for a user, aggregate across related threads.
76 materialize_host() - Materialize variables for a host, aggregate across related threads.
77 materialize_account() - Materialize variables for a account, aggregate across related threads.
78 private
79 m_show_var_array - Prealloc_array of SHOW_VARs for input to Materialize
80 m_cache - Prealloc_array of materialized variables for output
81 do_materialize_global() - Implementation of materialize_global()
82 do_materialize_session() - Implementation of materialize_session()
83 do_materialize_client() - Implementation of materialize_user/host/account()
84
85 4. PFS_system_variable_cache - System variable implementation of PFS_variable_cache
86 5. PFS_status_variable_cache - Status variable implementation of PFS_variable_cache
87 6. Find_THD_variable - Used by the thread manager to find and lock a THD.
88
89 GLOSSARY
90 --------
91 Status variable - Server or plugin status counter. Not dynamic.
92 System variable - Server or plugin configuration variable. Usually dynamic.
93 GLOBAL scope - Associated with the server, no context at thread level.
94 SESSION scope - Associated with a connection or thread, but no global context.
95 BOTH scope - Globally defined but applies at the session level.
96 Initialize - Build list of variables in SHOW_VAR format.
97 Materialize - Convert variables in SHOW_VAR list to string, cache for output.
98 Manifest - Substep of Materialize. Resolve variable values according to
99 type. This includes SHOW_FUNC types which are resolved by
100 executing a callback function (possibly recursively), and
101 SHOW_ARRAY types that expand into nested subarrays.
102 LOCK PRIORITIES
103 ---------------
104 System Variables
105 LOCK_plugin_delete (block plugin delete)
106 LOCK_system_variables_hash
107 LOCK_thd_data (block THD delete)
108 LOCK_thd_sysvar (block system variable updates, alloc_and_copy_thd_dynamic_variables)
109 LOCK_global_system_variables (very briefly held)
110
111 Status Variables
112 LOCK_status
113 LOCK_thd_data (block THD delete)
114 */
115
116 /* Iteration on THD from the sql layer. */
117 #include "mysqld_thd_manager.h"
118 #define PFS_VAR
119 /* Class sys_var */
120 #include "set_var.h"
121 /* convert_value_to_string */
122 #include "sql_show.h"
123 /* PFS_thread */
124 #include "pfs_instr.h"
125 #include "pfs_user.h"
126 #include "pfs_host.h"
127 #include "pfs_account.h"
128
129 /* Global array of all server and plugin-defined status variables. */
130 extern Status_var_array all_status_vars;
131 extern bool status_vars_inited;
132 static const uint SYSVAR_MEMROOT_BLOCK_SIZE = 4096;
133
134 extern mysql_mutex_t LOCK_plugin_delete;
135
136 class Find_THD_Impl;
137 class Find_THD_variable;
138 typedef PFS_connection_slice PFS_client;
139
140 /**
141 CLASS System_variable - System variable derived from sys_var object.
142 */
143 class System_variable
144 {
145 public:
146 System_variable();
147 System_variable(THD *target_thd, const SHOW_VAR *show_var,
148 enum_var_type query_scope, bool ignore);
~System_variable()149 ~System_variable() {}
150
is_null()151 bool is_null() const { return !m_initialized; }
is_ignored()152 bool is_ignored() const { return m_ignore; }
153
154 public:
155 const char *m_name;
156 size_t m_name_length;
157 char m_value_str[SHOW_VAR_FUNC_BUFF_SIZE+1];
158 size_t m_value_length;
159 enum_mysql_show_type m_type;
160 int m_scope;
161 bool m_ignore;
162 const CHARSET_INFO *m_charset;
163
164 private:
165 bool m_initialized;
166 void init(THD *thd, const SHOW_VAR *show_var, enum_var_type query_scope);
167 };
168
169
170 /**
171 CLASS Status_variable - Status variable derived from SHOW_VAR.
172 */
173 class Status_variable
174 {
175 public:
Status_variable()176 Status_variable() : m_name(NULL), m_name_length(0), m_value_length(0),
177 m_type(SHOW_UNDEF), m_scope(SHOW_SCOPE_UNDEF),
178 m_charset(NULL), m_initialized(false) {}
179
180 Status_variable(const SHOW_VAR *show_var, STATUS_VAR *status_array, enum_var_type query_scope);
181
~Status_variable()182 ~Status_variable() {}
183
is_null()184 bool is_null() const {return !m_initialized;};
185
186 public:
187 const char *m_name;
188 size_t m_name_length;
189 char m_value_str[SHOW_VAR_FUNC_BUFF_SIZE+1];
190 size_t m_value_length;
191 SHOW_TYPE m_type;
192 SHOW_SCOPE m_scope;
193 const CHARSET_INFO *m_charset;
194 private:
195 bool m_initialized;
196 void init(const SHOW_VAR *show_var, STATUS_VAR *status_array, enum_var_type query_scope);
197 };
198
199
200 /**
201 CLASS Find_THD_variable - Get and lock a validated THD from the thread manager.
202 */
203 class Find_THD_variable : public Find_THD_Impl
204 {
205 public:
Find_THD_variable()206 Find_THD_variable() : m_unsafe_thd(NULL) {}
Find_THD_variable(THD * unsafe_thd)207 Find_THD_variable(THD *unsafe_thd) : m_unsafe_thd(unsafe_thd) {}
208
operator()209 virtual bool operator()(THD *thd)
210 {
211 //TODO: filter bg threads?
212 if (thd != m_unsafe_thd)
213 return false;
214
215 /* Hold this lock to keep THD during materialization. */
216 mysql_mutex_lock(&thd->LOCK_thd_data);
217 return true;
218 }
set_unsafe_thd(THD * unsafe_thd)219 void set_unsafe_thd(THD *unsafe_thd) { m_unsafe_thd= unsafe_thd; }
220 private:
221 THD *m_unsafe_thd;
222 };
223
224 /**
225 CLASS PFS_variable_cache - Base class for a system or status variable cache.
226 */
227 template <class Var_type>
228 class PFS_variable_cache
229 {
230 public:
231 typedef Prealloced_array<Var_type, SHOW_VAR_PREALLOC, false> Variable_array;
232
PFS_variable_cache(bool external_init)233 PFS_variable_cache(bool external_init)
234 : m_safe_thd(NULL),
235 m_unsafe_thd(NULL),
236 m_current_thd(current_thd),
237 m_pfs_thread(NULL),
238 m_pfs_client(NULL),
239 m_thd_finder(),
240 m_cache(PSI_INSTRUMENT_ME),
241 m_initialized(false),
242 m_external_init(external_init),
243 m_materialized(false),
244 m_show_var_array(PSI_INSTRUMENT_ME),
245 m_version(0),
246 m_query_scope(OPT_DEFAULT),
247 m_use_mem_root(false),
248 m_aggregate(false)
249 { }
250
251 virtual ~PFS_variable_cache()= 0;
252
253 /**
254 Build array of SHOW_VARs from the external variable source.
255 Filter using session scope.
256 */
257 bool initialize_session(void);
258
259 /**
260 Build array of SHOW_VARs suitable for aggregation by user, host or account.
261 Filter using session scope.
262 */
263 bool initialize_client_session(void);
264
265 /**
266 Build cache of GLOBAL system or status variables.
267 Aggregate across threads if applicable.
268 */
269 int materialize_global();
270
271 /**
272 Build cache of GLOBAL and SESSION variables for a non-instrumented thread.
273 */
274 int materialize_all(THD *thd);
275
276 /**
277 Build cache of SESSION variables for a non-instrumented thread.
278 */
279 int materialize_session(THD *thd);
280
281 /**
282 Build cache of SESSION variables for an instrumented thread.
283 */
284 int materialize_session(PFS_thread *pfs_thread, bool use_mem_root= false);
285
286 /**
287 Cache a single SESSION variable for an instrumented thread.
288 */
289 int materialize_session(PFS_thread *pfs_thread, uint index);
290
291 /**
292 Build cache of SESSION status variables for a user.
293 */
294 int materialize_user(PFS_user *pfs_user);
295
296 /**
297 Build cache of SESSION status variables for a host.
298 */
299 int materialize_host(PFS_host *pfs_host);
300
301 /**
302 Build cache of SESSION status variables for an account.
303 */
304 int materialize_account(PFS_account *pfs_account);
305
306 /**
307 True if variables have been materialized.
308 */
is_materialized(void)309 bool is_materialized(void)
310 {
311 return m_materialized;
312 }
313
314 /**
315 True if variables have been materialized for given THD.
316 */
is_materialized(THD * unsafe_thd)317 bool is_materialized(THD *unsafe_thd)
318 {
319 return (unsafe_thd == m_unsafe_thd && m_materialized);
320 }
321
322 /**
323 True if variables have been materialized for given PFS_thread.
324 */
is_materialized(PFS_thread * pfs_thread)325 bool is_materialized(PFS_thread *pfs_thread)
326 {
327 return (pfs_thread == m_pfs_thread && m_materialized);
328 }
329
330 /**
331 True if variables have been materialized for given PFS_user.
332 */
is_materialized(PFS_user * pfs_user)333 bool is_materialized(PFS_user *pfs_user)
334 {
335 return (static_cast<PFS_client *>(pfs_user) == m_pfs_client && m_materialized);
336 }
337
338 /**
339 True if variables have been materialized for given PFS_host.
340 */
is_materialized(PFS_host * pfs_host)341 bool is_materialized(PFS_host *pfs_host)
342 {
343 return (static_cast<PFS_client *>(pfs_host) == m_pfs_client && m_materialized);
344 }
345
346 /**
347 True if variables have been materialized for given PFS_account.
348 */
is_materialized(PFS_account * pfs_account)349 bool is_materialized(PFS_account *pfs_account)
350 {
351 return (static_cast<PFS_client *>(pfs_account) == m_pfs_client && m_materialized);
352 }
353
354 /**
355 True if variables have been materialized for given PFS_user/host/account.
356 */
is_materialized(PFS_client * pfs_client)357 bool is_materialized(PFS_client *pfs_client)
358 {
359 return (static_cast<PFS_client *>(pfs_client) == m_pfs_client && m_materialized);
360 }
361
362 /**
363 Get a validated THD from the thread manager. Execute callback function while
364 inside of the thread manager locks.
365 */
366 THD *get_THD(THD *thd);
367 THD *get_THD(PFS_thread *pfs_thread);
368
369 /**
370 Get a single variable from the cache.
371 Get the first element in the cache by default.
372 */
373 const Var_type *get(uint index= 0) const
374 {
375 if (index >= m_cache.size())
376 return NULL;
377
378 const Var_type *p= &m_cache.at(index);
379 return p;
380 }
381
382 /**
383 Number of elements in the cache.
384 */
size()385 uint size()
386 {
387 return (uint)m_cache.size();
388 }
389
390 private:
do_initialize_global(void)391 virtual bool do_initialize_global(void) { return true; }
do_initialize_session(void)392 virtual bool do_initialize_session(void) { return true; }
do_materialize_global(void)393 virtual int do_materialize_global(void) { return 1; }
do_materialize_all(THD * thd)394 virtual int do_materialize_all(THD *thd) { return 1; }
do_materialize_session(THD * thd)395 virtual int do_materialize_session(THD *thd) { return 1; }
do_materialize_session(PFS_thread *)396 virtual int do_materialize_session(PFS_thread *) { return 1; }
do_materialize_session(PFS_thread *,uint index)397 virtual int do_materialize_session(PFS_thread *, uint index) { return 1; }
398
399 protected:
400 /* Validated THD */
401 THD *m_safe_thd;
402
403 /* Unvalidated THD */
404 THD *m_unsafe_thd;
405
406 /* Current THD */
407 THD *m_current_thd;
408
409 /* Current PFS_thread. */
410 PFS_thread *m_pfs_thread;
411
412 /* Current PFS_user, host or account. */
413 PFS_client *m_pfs_client;
414
415 /* Callback for thread iterator. */
416 Find_THD_variable m_thd_finder;
417
418 /* Cache of materialized variables. */
419 Variable_array m_cache;
420
421 /* True when list of SHOW_VAR is complete. */
422 bool m_initialized;
423
424 /*
425 True if the SHOW_VAR array must be initialized externally from the
426 materialization step, such as with aggregations and queries by thread.
427 */
428 bool m_external_init;
429
430 /* True when cache is complete. */
431 bool m_materialized;
432
433 /* Array of variables to be materialized. Last element must be null. */
434 Show_var_array m_show_var_array;
435
436 /* Version of global hash/array. Changes when vars added/removed. */
437 ulonglong m_version;
438
439 /* Query scope: GLOBAL or SESSION. */
440 enum_var_type m_query_scope;
441
442 /* True if temporary mem_root should be used for materialization. */
443 bool m_use_mem_root;
444
445 /* True if summarizing across users, hosts or accounts. */
446 bool m_aggregate;
447
448 };
449
450 /**
451 Required implementation for pure virtual destructor of a template class.
452 */
453 template <class Var_type>
~PFS_variable_cache()454 PFS_variable_cache<Var_type>::~PFS_variable_cache()
455 {
456 }
457
458 /**
459 Get a validated THD from the thread manager. Execute callback function while
460 while inside the thread manager lock.
461 */
462 template <class Var_type>
get_THD(THD * unsafe_thd)463 THD *PFS_variable_cache<Var_type>::get_THD(THD *unsafe_thd)
464 {
465 if (unsafe_thd == NULL)
466 {
467 /*
468 May happen, precisely because the pointer is unsafe
469 (THD just disconnected for example).
470 No need to walk Global_THD_manager for that.
471 */
472 return NULL;
473 }
474
475 m_thd_finder.set_unsafe_thd(unsafe_thd);
476 THD* safe_thd= Global_THD_manager::get_instance()->find_thd(&m_thd_finder);
477 return safe_thd;
478 }
479
480 template <class Var_type>
get_THD(PFS_thread * pfs_thread)481 THD *PFS_variable_cache<Var_type>::get_THD(PFS_thread *pfs_thread)
482 {
483 assert(pfs_thread != NULL);
484 return get_THD(pfs_thread->m_thd);
485 }
486
487 /**
488 Build array of SHOW_VARs from external source of system or status variables.
489 Filter using session scope.
490 */
491 template <class Var_type>
initialize_session(void)492 bool PFS_variable_cache<Var_type>::initialize_session(void)
493 {
494 if (m_initialized)
495 return 0;
496
497 return do_initialize_session();
498 }
499
500 /**
501 Build array of SHOW_VARs suitable for aggregation by user, host or account.
502 Filter using session scope.
503 */
504 template <class Var_type>
initialize_client_session(void)505 bool PFS_variable_cache<Var_type>::initialize_client_session(void)
506 {
507 if (m_initialized)
508 return 0;
509
510 /* Requires aggregation by user, host or account. */
511 m_aggregate= true;
512
513 return do_initialize_session();
514 }
515
516 /**
517 Build cache of all GLOBAL variables.
518 */
519 template <class Var_type>
materialize_global()520 int PFS_variable_cache<Var_type>::materialize_global()
521 {
522 if (is_materialized())
523 return 0;
524
525 return do_materialize_global();
526 }
527
528 /**
529 Build cache of GLOBAL and SESSION variables for a non-instrumented thread.
530 */
531 template <class Var_type>
materialize_all(THD * unsafe_thd)532 int PFS_variable_cache<Var_type>::materialize_all(THD *unsafe_thd)
533 {
534 if (!unsafe_thd)
535 return 1;
536
537 if (is_materialized(unsafe_thd))
538 return 0;
539
540 return do_materialize_all(unsafe_thd);
541 }
542
543 /**
544 Build cache of SESSION variables for a non-instrumented thread.
545 */
546 template <class Var_type>
materialize_session(THD * unsafe_thd)547 int PFS_variable_cache<Var_type>::materialize_session(THD *unsafe_thd)
548 {
549 if (!unsafe_thd)
550 return 1;
551
552 if (is_materialized(unsafe_thd))
553 return 0;
554
555 return do_materialize_session(unsafe_thd);
556 }
557
558 /**
559 Build cache of SESSION variables for a thread.
560 */
561 template <class Var_type>
materialize_session(PFS_thread * pfs_thread,bool use_mem_root)562 int PFS_variable_cache<Var_type>::materialize_session(PFS_thread *pfs_thread, bool use_mem_root)
563 {
564 if (!pfs_thread)
565 return 1;
566
567 if (is_materialized(pfs_thread))
568 return 0;
569
570 if (!pfs_thread->m_lock.is_populated() || pfs_thread->m_thd == NULL)
571 return 1;
572
573 m_use_mem_root= use_mem_root;
574
575 return do_materialize_session(pfs_thread);
576 }
577
578 /**
579 Materialize a single variable for a thread.
580 */
581 template <class Var_type>
materialize_session(PFS_thread * pfs_thread,uint index)582 int PFS_variable_cache<Var_type>::materialize_session(PFS_thread *pfs_thread, uint index)
583 {
584 /* No check for is_materialized(). */
585
586 if (!pfs_thread)
587 return 1;
588
589 if (!pfs_thread->m_lock.is_populated() || pfs_thread->m_thd == NULL)
590 return 1;
591
592 return do_materialize_session(pfs_thread, index);
593 }
594
595 /**
596 CLASS PFS_system_variable_cache - System variable cache.
597 */
598 class PFS_system_variable_cache : public PFS_variable_cache<System_variable>
599 {
600 public:
PFS_system_variable_cache(bool external_init)601 PFS_system_variable_cache(bool external_init) :
602 PFS_variable_cache<System_variable>(external_init),
603 m_mem_thd(NULL), m_mem_thd_save(NULL),
604 m_mem_sysvar_ptr(NULL) { }
605 bool match_scope(int scope);
get_sysvar_hash_version(void)606 ulonglong get_sysvar_hash_version(void) { return m_version; }
~PFS_system_variable_cache()607 ~PFS_system_variable_cache() { free_mem_root(); }
608
609 private:
610 /* Build SHOW_var array. */
611 bool init_show_var_array(enum_var_type scope, bool strict);
612 bool do_initialize_session(void);
613
614 /* Global */
615 int do_materialize_global(void);
616 /* Global and Session - THD */
617 int do_materialize_all(THD* thd);
618 /* Session - THD */
619 int do_materialize_session(THD* thd);
620 /* Session - PFS_thread */
621 int do_materialize_session(PFS_thread *thread);
622 /* Single variable - PFS_thread */
623 int do_materialize_session(PFS_thread *pfs_thread, uint index);
624
625 /* Temporary mem_root to use for materialization. */
626 MEM_ROOT m_mem_sysvar;
627 /* Pointer to THD::mem_root. */
628 MEM_ROOT **m_mem_thd;
629 /* Save THD::mem_root. */
630 MEM_ROOT *m_mem_thd_save;
631 /* Pointer to temporary mem_root. */
632 MEM_ROOT *m_mem_sysvar_ptr;
633 /* Allocate and/or assign temporary mem_root. */
634 void set_mem_root(void);
635 /* Mark all memory blocks as free in temporary mem_root. */
636 void clear_mem_root(void);
637 /* Free mem_root memory. */
638 void free_mem_root(void);
639 };
640
641
642 /**
643 CLASS PFS_status_variable_cache - Status variable cache
644 */
645 class PFS_status_variable_cache : public PFS_variable_cache<Status_variable>
646 {
647 public:
648 PFS_status_variable_cache(bool external_init);
649
650 int materialize_user(PFS_user *pfs_user);
651 int materialize_host(PFS_host *pfs_host);
652 int materialize_account(PFS_account *pfs_account);
653
get_status_array_version(void)654 ulonglong get_status_array_version(void) { return m_version; }
655
656 protected:
657 /* Get PFS_user, account or host associated with a PFS_thread. Implemented by table class. */
get_pfs(PFS_thread * pfs_thread)658 virtual PFS_client *get_pfs(PFS_thread *pfs_thread) { return NULL; }
659
660 /* True if query is a SHOW command. */
661 bool m_show_command;
662
663 private:
664 bool do_initialize_session(void);
665
666 int do_materialize_global(void);
667 /* Global and Session - THD */
668 int do_materialize_all(THD* thd);
669 int do_materialize_session(THD *thd);
670 int do_materialize_session(PFS_thread *thread);
do_materialize_session(PFS_thread * thread,uint index)671 int do_materialize_session(PFS_thread *thread, uint index) { return 0; }
672 int do_materialize_client(PFS_client *pfs_client);
673
674 /* Callback to sum user, host or account status variables. */
675 void (*m_sum_client_status)(PFS_client *pfs_client, STATUS_VAR *status_totals);
676
677 /* Build SHOW_VAR array from external source. */
678 bool init_show_var_array(enum_var_type scope, bool strict);
679
680 /* Recursively expand nested SHOW_VAR arrays. */
681 void expand_show_var_array(const SHOW_VAR *show_var_array, const char *prefix, bool strict);
682
683 /* Exclude unwanted variables from the query. */
684 bool filter_show_var(const SHOW_VAR *show_var, bool strict);
685
686 /* Check the variable scope against the query scope. */
687 bool match_scope(SHOW_SCOPE variable_scope, bool strict);
688
689 /* Exclude specific status variables by name or prefix. */
690 bool filter_by_name(const SHOW_VAR *show_var);
691
692 /* Check if a variable has an aggregatable type. */
693 bool can_aggregate(enum_mysql_show_type variable_type);
694
695 /* Build status variable name with prefix. Return in the buffer provided. */
696 char *make_show_var_name(const char* prefix, const char* name, char *name_buf, size_t buf_len);
697
698 /* Build status variable name with prefix. Return copy of the string. */
699 char *make_show_var_name(const char* prefix, const char* name);
700
701 /* For the current THD, use initial_status_vars taken from before the query start. */
702 STATUS_VAR *set_status_vars(void);
703
704 /* Build the list of status variables from SHOW_VAR array. */
705 void manifest(THD *thd, const SHOW_VAR *show_var_array,
706 STATUS_VAR *status_var_array, const char *prefix, bool nested_array, bool strict);
707 };
708
709 /* Callback functions to sum status variables for a given user, host or account. */
710 void sum_user_status(PFS_client *pfs_user, STATUS_VAR *status_totals);
711 void sum_host_status(PFS_client *pfs_host, STATUS_VAR *status_totals);
712 void sum_account_status(PFS_client *pfs_account, STATUS_VAR *status_totals);
713
714
715 /** @} */
716 #endif
717
718