summaryrefslogtreecommitdiffstats
path: root/storage/perfschema/pfs_variable.h
blob: d3ad4c7f9006e45a52f0fad2b24a7491ffa11b0f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
/* Copyright (c) 2015, 2023, Oracle and/or its affiliates.

  This program is free software; you can redistribute it and/or modify
  it under the terms of the GNU General Public License, version 2.0,
  as published by the Free Software Foundation.

  This program is also distributed with certain software (including
  but not limited to OpenSSL) that is licensed under separate terms,
  as designated in a particular file or component or in included license
  documentation.  The authors of MySQL hereby grant you an additional
  permission to link the program and your derivative works with the
  separately licensed software that they have included with MySQL.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License, version 2.0, for more details.

  You should have received a copy of the GNU General Public License
  along with this program; if not, write to the Free Software
  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */

#ifndef PFS_VARIABLE_H
#define PFS_VARIABLE_H

/**
  @file storage/perfschema/pfs_variable.h
  Performance schema system and status variables (declarations).
*/

/**
  OVERVIEW
  --------
  Status and system variables are implemented differently in the server, but the
  steps to process them in the Performance Schema are essentially the same:

  1. INITIALIZE - Build or acquire a sorted list of variables to use for input.
     Use the SHOW_VAR struct as an intermediate format common to system, status
     and user vars:

     SHOW_VAR
       Name  - Text string
       Value - Pointer to memory location, function, subarray structure
       Type  - Scalar, function, or subarray
       Scope - SESSION, GLOBAL, BOTH

     Steps:
     - Register the server's internal buffer with the class. Acquire locks
       if necessary, then scan the contents of the input buffer.
     - For system variables, convert each element to SHOW_VAR format, store in
       a temporary array.
     - For status variables, copy existing global status array into a local
       array that can be used without locks. Expand nested subarrays, indicated
       by a type of SHOW_ARRAY.

  2. MATERIALIZE - Convert the list of SHOW_VAR variables to string format,
     store in a local cache:
     - Resolve each variable according to the type.
     - Recursively process unexpanded nested arrays and callback functions.
     - Aggregate values across threads for global status.
     - Convert numeric values to a string.
     - Prefix variable name with the plugin name.

  3. OUTPUT - Iterate the cache for the SHOW command or table query.

  CLASS OVERVIEW
  --------------
  1. System_variable - A materialized system variable
  2. Status_variable - A materialized status variable
  3. PFS_variable_cache - Base class that defines the interface for the operations above.
     public
       init_show_var_array() - Build SHOW_VAR list of variables for processing
       materialize_global()  - Materialize global variables, aggregate across sessions
       materialize_session() - Materialize variables for a given PFS_thread or THD
       materialize_user()    - Materialize variables for a user, aggregate across related threads.
       materialize_host()    - Materialize variables for a host, aggregate across related threads.
       materialize_account() - Materialize variables for a account, aggregate across related threads.
     private
       m_show_var_array         - Prealloc_array of SHOW_VARs for input to Materialize
       m_cache                  - Prealloc_array of materialized variables for output
       do_materialize_global()  - Implementation of materialize_global()
       do_materialize_session() - Implementation of materialize_session()
       do_materialize_client()  - Implementation of materialize_user/host/account()

  4. PFS_system_variable_cache - System variable implementation of PFS_variable_cache
  5. PFS_status_variable_cache - Status variable implementation of PFS_variable_cache
  6. Find_THD_variable         - Used by the thread manager to find and lock a THD.

  GLOSSARY
  --------
  Status variable - Server or plugin status counter. Not dynamic.
  System variable - Server or plugin configuration variable. Usually dynamic.
  GLOBAL scope    - Associated with the server, no context at thread level.
  SESSION scope   - Associated with a connection or thread, but no global context.
  BOTH scope      - Globally defined but applies at the session level.
  Initialize      - Build list of variables in SHOW_VAR format.
  Materialize     - Convert variables in SHOW_VAR list to string, cache for output.
  Manifest        - Substep of Materialize. Resolve variable values according to
                    type. This includes SHOW_FUNC types which are resolved by
                    executing a callback function (possibly recursively), and
                    SHOW_ARRAY types that expand into nested subarrays.
  LOCK PRIORITIES
  ---------------
  System Variables
    LOCK_plugin_delete              (block plugin delete)
     LOCK_system_variables_hash
     LOCK_thd_data                  (block THD delete)
     LOCK_thd_sysvar                (block system variable updates, alloc_and_copy_thd_dynamic_variables)
       LOCK_global_system_variables (very briefly held)

  Status Variables
    LOCK_status
      LOCK_thd_data                 (block THD delete)
*/

/* Iteration on THD from the sql layer. */
#include "mysqld_thd_manager.h"
#define PFS_VAR
/* Class sys_var */
#include "set_var.h"
/* convert_value_to_string */
#include "sql_show.h"
/* PFS_thread */
#include "pfs_instr.h"
#include "pfs_user.h"
#include "pfs_host.h"
#include "pfs_account.h"

/* Global array of all server and plugin-defined status variables. */
extern DYNAMIC_ARRAY all_status_vars;
extern bool status_vars_inited;
static const uint SYSVAR_MEMROOT_BLOCK_SIZE = 4096;

extern mysql_mutex_t LOCK_plugin_delete;

class Find_THD_Impl;
class Find_THD_variable;
typedef PFS_connection_slice PFS_client;

/**
  CLASS System_variable - System variable derived from sys_var object.
*/
class System_variable
{
public:
  System_variable();
  System_variable(THD *target_thd, const SHOW_VAR *show_var,
                  enum_var_type query_scope, bool ignore);
  ~System_variable() {}

  bool is_null() const { return !m_initialized; }
  bool is_ignored() const { return m_ignore; }

public:
  const char *m_name;
  size_t m_name_length;
  char m_value_str[SHOW_VAR_FUNC_BUFF_SIZE+1];
  size_t m_value_length;
  enum_mysql_show_type m_type;
  int m_scope;
  bool m_ignore;
  const CHARSET_INFO *m_charset;

private:
  bool m_initialized;
  void init(THD *thd, const SHOW_VAR *show_var, enum_var_type query_scope);
};


/**
  CLASS Status_variable - Status variable derived from SHOW_VAR.
*/
class Status_variable
{
public:
  Status_variable() : m_name(NULL), m_name_length(0), m_value_length(0),
                      m_type(SHOW_UNDEF),
                      m_charset(NULL), m_initialized(false) {}

  Status_variable(const SHOW_VAR *show_var, STATUS_VAR *status_array, enum_var_type query_scope);

  ~Status_variable() {}

  bool is_null() const {return !m_initialized;};

public:
  const char *m_name;
  size_t m_name_length;
  char m_value_str[SHOW_VAR_FUNC_BUFF_SIZE+1];
  size_t m_value_length;
  SHOW_TYPE  m_type;
  const CHARSET_INFO *m_charset;
private:
  bool m_initialized;
  void init(const SHOW_VAR *show_var, STATUS_VAR *status_array, enum_var_type query_scope);
};


/**
  CLASS Find_THD_variable - Get and lock a validated THD from the thread manager.
*/
class Find_THD_variable : public Find_THD_Impl
{
public:
  Find_THD_variable() : m_unsafe_thd(NULL) {}
  Find_THD_variable(THD *unsafe_thd) : m_unsafe_thd(unsafe_thd) {}

  virtual bool operator()(THD *thd)
  {
    //TODO: filter bg threads?
    if (thd != m_unsafe_thd)
      return false;

    /* Hold this lock to keep THD during materialization. */
    mysql_mutex_lock(&thd->LOCK_thd_data);
    return true;
  }
  void set_unsafe_thd(THD *unsafe_thd) { m_unsafe_thd= unsafe_thd; }
private:
  THD *m_unsafe_thd;
};

/**
  CLASS PFS_variable_cache - Base class for a system or status variable cache.
*/
template <class Var_type>
class PFS_variable_cache
{
public:
  typedef Dynamic_array<Var_type> Variable_array;

  PFS_variable_cache(bool external_init)
    : m_safe_thd(NULL),
      m_unsafe_thd(NULL),
      m_current_thd(current_thd),
      m_pfs_thread(NULL),
      m_pfs_client(NULL),
      m_thd_finder(),
      m_cache(PSI_INSTRUMENT_MEM),
      m_initialized(false),
      m_external_init(external_init),
      m_materialized(false),
      m_show_var_array(PSI_INSTRUMENT_MEM),
      m_version(0),
      m_query_scope(OPT_DEFAULT),
      m_use_mem_root(false),
      m_aggregate(false)
  { }

  virtual ~PFS_variable_cache()= 0;

  /**
    Build array of SHOW_VARs from the external variable source.
    Filter using session scope.
  */
  bool initialize_session(void);

  /**
    Build array of SHOW_VARs suitable for aggregation by user, host or account.
    Filter using session scope.
  */
  bool initialize_client_session(void);

  /**
    Build cache of GLOBAL system or status variables.
    Aggregate across threads if applicable.
  */
  int materialize_global();

  /**
    Build cache of GLOBAL and SESSION variables for a non-instrumented thread.
  */
  int materialize_all(THD *thd);

  /**
    Build cache of SESSION variables for a non-instrumented thread.
  */
  int materialize_session(THD *thd);

  /**
    Build cache of SESSION variables for an instrumented thread.
  */
  int materialize_session(PFS_thread *pfs_thread, bool use_mem_root= false);

  /**
    Cache a single SESSION variable for an instrumented thread.
  */
  int materialize_session(PFS_thread *pfs_thread, uint index);

  /**
    Build cache of SESSION status variables for a user.
  */
  int materialize_user(PFS_user *pfs_user);

  /**
    Build cache of SESSION status variables for a host.
  */
  int materialize_host(PFS_host *pfs_host);

  /**
    Build cache of SESSION status variables for an account.
  */
  int materialize_account(PFS_account *pfs_account);

  /**
    True if variables have been materialized.
  */
  bool is_materialized(void)
  {
    return m_materialized;
  }

  /**
    True if variables have been materialized for given THD.
  */
  bool is_materialized(THD *unsafe_thd)
  {
    return (unsafe_thd == m_unsafe_thd && m_materialized);
  }

  /**
    True if variables have been materialized for given PFS_thread.
  */
  bool is_materialized(PFS_thread *pfs_thread)
  {
    return (pfs_thread == m_pfs_thread && m_materialized);
  }

  /**
    True if variables have been materialized for given PFS_user.
  */
  bool is_materialized(PFS_user *pfs_user)
  {
    return (static_cast<PFS_client *>(pfs_user) == m_pfs_client && m_materialized);
  }

  /**
    True if variables have been materialized for given PFS_host.
  */
  bool is_materialized(PFS_host *pfs_host)
  {
    return (static_cast<PFS_client *>(pfs_host) == m_pfs_client && m_materialized);
  }

  /**
    True if variables have been materialized for given PFS_account.
  */
  bool is_materialized(PFS_account *pfs_account)
  {
    return (static_cast<PFS_client *>(pfs_account) == m_pfs_client && m_materialized);
  }

  /**
    True if variables have been materialized for given PFS_user/host/account.
  */
  bool is_materialized(PFS_client *pfs_client)
  {
    return (static_cast<PFS_client *>(pfs_client) == m_pfs_client && m_materialized);
  }

  /**
    Get a validated THD from the thread manager. Execute callback function while
    inside of the thread manager locks.
  */
  THD *get_THD(THD *thd);
  THD *get_THD(PFS_thread *pfs_thread);

  /**
    Get a single variable from the cache.
    Get the first element in the cache by default.
  */
  const Var_type *get(uint index= 0) const
  {
    if (index >= m_cache.elements())
      return NULL;

    const Var_type *p= &m_cache.at(index);
    return p;
  }

  /**
    Number of elements in the cache.
  */
  uint size()
  {
    return (uint)m_cache.elements();
  }

private:
  virtual bool do_initialize_global(void) { return true; }
  virtual bool do_initialize_session(void) { return true; }
  virtual int do_materialize_global(void) { return 1; }
  virtual int do_materialize_all(THD *thd) { return 1; }
  virtual int do_materialize_session(THD *thd) { return 1; }
  virtual int do_materialize_session(PFS_thread *) { return 1; }
  virtual int do_materialize_session(PFS_thread *, uint index) { return 1; }

protected:
  /* Validated THD */
  THD *m_safe_thd;

  /* Unvalidated THD */
  THD *m_unsafe_thd;

  /* Current THD */
  THD *m_current_thd;

  /* Current PFS_thread. */
  PFS_thread *m_pfs_thread;

  /* Current PFS_user, host or account. */
  PFS_client *m_pfs_client;

  /* Callback for thread iterator. */
  Find_THD_variable m_thd_finder;

  /* Cache of materialized variables. */
  Variable_array m_cache;

  /* True when list of SHOW_VAR is complete. */
  bool m_initialized;

  /*
    True if the SHOW_VAR array must be initialized externally from the
    materialization step, such as with aggregations and queries by thread.
  */
  bool m_external_init;

  /* True when cache is complete. */
  bool m_materialized;

  /* Array of variables to be materialized. Last element must be null. */
  Dynamic_array<SHOW_VAR> m_show_var_array;

  /* Version of global hash/array. Changes when vars added/removed. */
  ulonglong m_version;

  /* Query scope: GLOBAL or SESSION. */
  enum_var_type m_query_scope;

  /* True if temporary mem_root should be used for materialization. */
  bool m_use_mem_root;

  /* True if summarizing across users, hosts or accounts. */
  bool m_aggregate;

};

/**
  Required implementation for pure virtual destructor of a template class.
*/
template <class Var_type>
PFS_variable_cache<Var_type>::~PFS_variable_cache()
{
}

/**
  Get a validated THD from the thread manager. Execute callback function while
  while inside the thread manager lock.
*/
template <class Var_type>
THD *PFS_variable_cache<Var_type>::get_THD(THD *unsafe_thd)
{
  if (unsafe_thd == NULL)
  {
    /*
      May happen, precisely because the pointer is unsafe
      (THD just disconnected for example).
      No need to walk Global_THD_manager for that.
    */
    return NULL;
  }

  m_thd_finder.set_unsafe_thd(unsafe_thd);
  THD* safe_thd= Global_THD_manager::get_instance()->find_thd(&m_thd_finder);
  return safe_thd;
}

template <class Var_type>
THD *PFS_variable_cache<Var_type>::get_THD(PFS_thread *pfs_thread)
{
  assert(pfs_thread != NULL);
  return get_THD(pfs_thread->m_thd);
}

/**
  Build array of SHOW_VARs from external source of system or status variables.
  Filter using session scope.
*/
template <class Var_type>
bool PFS_variable_cache<Var_type>::initialize_session(void)
{
  if (m_initialized)
    return 0;

  return do_initialize_session();
}

/**
  Build array of SHOW_VARs suitable for aggregation by user, host or account.
  Filter using session scope.
*/
template <class Var_type>
bool PFS_variable_cache<Var_type>::initialize_client_session(void)
{
  if (m_initialized)
    return 0;

  /* Requires aggregation by user, host or account. */
  m_aggregate= true;

  return do_initialize_session();
}

/**
  Build cache of all GLOBAL variables.
*/
template <class Var_type>
int PFS_variable_cache<Var_type>::materialize_global()
{
  if (is_materialized())
    return 0;

  return do_materialize_global();
}

/**
  Build cache of GLOBAL and SESSION variables for a non-instrumented thread.
*/
template <class Var_type>
int PFS_variable_cache<Var_type>::materialize_all(THD *unsafe_thd)
{
  if (!unsafe_thd)
    return 1;

  if (is_materialized(unsafe_thd))
    return 0;

  return do_materialize_all(unsafe_thd);
}

/**
  Build cache of SESSION variables for a non-instrumented thread.
*/
template <class Var_type>
int PFS_variable_cache<Var_type>::materialize_session(THD *unsafe_thd)
{
  if (!unsafe_thd)
    return 1;

  if (is_materialized(unsafe_thd))
    return 0;

  return do_materialize_session(unsafe_thd);
}

/**
  Build cache of SESSION variables for a thread.
*/
template <class Var_type>
int PFS_variable_cache<Var_type>::materialize_session(PFS_thread *pfs_thread, bool use_mem_root)
{
  if (!pfs_thread)
    return 1;

  if (is_materialized(pfs_thread))
    return 0;

  if (!pfs_thread->m_lock.is_populated() || pfs_thread->m_thd == NULL)
    return 1;

  m_use_mem_root= use_mem_root;

  return do_materialize_session(pfs_thread);
}

/**
  Materialize a single variable for a thread.
*/
template <class Var_type>
int PFS_variable_cache<Var_type>::materialize_session(PFS_thread *pfs_thread, uint index)
{
  /* No check for is_materialized(). */

  if (!pfs_thread)
    return 1;

  if (!pfs_thread->m_lock.is_populated() || pfs_thread->m_thd == NULL)
    return 1;

  return do_materialize_session(pfs_thread, index);
}

/**
  CLASS PFS_system_variable_cache - System variable cache.
*/
class PFS_system_variable_cache : public PFS_variable_cache<System_variable>
{
public:
  PFS_system_variable_cache(bool external_init) :
                            PFS_variable_cache<System_variable>(external_init),
                            m_mem_thd(NULL), m_mem_thd_save(NULL),
                            m_mem_sysvar_ptr(NULL) { }
  bool match_scope(int scope);
  ulonglong get_sysvar_hash_version(void) { return m_version; }
  ~PFS_system_variable_cache() { free_mem_root(); }

private:
  /* Build SHOW_var array. */
  bool init_show_var_array(enum_var_type scope, bool strict);
  bool do_initialize_session(void);

  /* Global */
  int do_materialize_global(void);
  /* Global and Session - THD */
  int do_materialize_all(THD* thd);
  /* Session - THD */
  int do_materialize_session(THD* thd);
  /* Session -  PFS_thread */
  int do_materialize_session(PFS_thread *thread);
  /* Single variable -  PFS_thread */
  int do_materialize_session(PFS_thread *pfs_thread, uint index);

  /* Temporary mem_root to use for materialization. */
  MEM_ROOT m_mem_sysvar;
  /* Pointer to THD::mem_root. */
  MEM_ROOT **m_mem_thd;
  /* Save THD::mem_root. */
  MEM_ROOT *m_mem_thd_save;
  /* Pointer to temporary mem_root. */
  MEM_ROOT *m_mem_sysvar_ptr;
  /* Allocate and/or assign temporary mem_root. */
  void set_mem_root(void);
  /* Mark all memory blocks as free in temporary mem_root. */
  void clear_mem_root(void);
  /* Free mem_root memory. */
  void free_mem_root(void);
};


/**
  CLASS PFS_status_variable_cache - Status variable cache
*/
class PFS_status_variable_cache : public PFS_variable_cache<Status_variable>
{
public:
  PFS_status_variable_cache(bool external_init);

  int materialize_user(PFS_user *pfs_user);
  int materialize_host(PFS_host *pfs_host);
  int materialize_account(PFS_account *pfs_account);

  ulonglong get_status_array_version(void) { return m_version; }

protected:
  /* Get PFS_user, account or host associated with a PFS_thread. Implemented by table class. */
  virtual PFS_client *get_pfs(PFS_thread *pfs_thread) { return NULL; }

  /* True if query is a SHOW command. */
  bool m_show_command;

private:
  bool do_initialize_session(void);

  int do_materialize_global(void);
  /* Global and Session - THD */
  int do_materialize_all(THD* thd);
  int do_materialize_session(THD *thd);
  int do_materialize_session(PFS_thread *thread);
  int do_materialize_session(PFS_thread *thread, uint index) { return 0; }
  int do_materialize_client(PFS_client *pfs_client);

  /* Callback to sum user, host or account status variables. */
  void (*m_sum_client_status)(PFS_client *pfs_client, STATUS_VAR *status_totals);

  /* Build SHOW_VAR array from external source. */
  bool init_show_var_array(enum_var_type scope, bool strict);

  /* Recursively expand nested SHOW_VAR arrays. */
  void expand_show_var_array(const SHOW_VAR *show_var_array, const char *prefix, bool strict);

  /* Exclude unwanted variables from the query. */
  bool filter_show_var(const SHOW_VAR *show_var, bool strict);

  /* Check the variable scope against the query scope. */
  bool match_scope(SHOW_SCOPE variable_scope, bool strict);

  /* Exclude specific status variables by name or prefix. */
  bool filter_by_name(const SHOW_VAR *show_var);

  /* Check if a variable has an aggregatable type. */
  bool can_aggregate(enum_mysql_show_type variable_type);

  /* Build status variable name with prefix. Return in the buffer provided. */
  char *make_show_var_name(const char* prefix, const char* name, char *name_buf, size_t buf_len);

  /* Build status variable name with prefix. Return copy of the string. */
  char *make_show_var_name(const char* prefix, const char* name);

  /* For the current THD, use initial_status_vars taken from before the query start. */
  STATUS_VAR *set_status_vars(void);

  /* Build the list of status variables from SHOW_VAR array. */
  void manifest(THD *thd, const SHOW_VAR *show_var_array,
                STATUS_VAR *status_var_array, const char *prefix, bool nested_array, bool strict);
};

/* Callback functions to sum status variables for a given user, host or account. */
void sum_user_status(PFS_client *pfs_user, STATUS_VAR *status_totals);
void sum_host_status(PFS_client *pfs_host, STATUS_VAR *status_totals);
void sum_account_status(PFS_client *pfs_account, STATUS_VAR *status_totals);


/** @} */
#endif