1 /* Copyright (c) 2008, 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 Foundation,
21   51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */
22 
23 #ifndef PFS_STAT_H
24 #define PFS_STAT_H
25 
26 #include <algorithm>
27 #include "sql_const.h"
28 /* memcpy */
29 #include "string.h"
30 
31 /**
32   @file storage/perfschema/pfs_stat.h
33   Statistics (declarations).
34 */
35 
36 /**
37   @addtogroup Performance_schema_buffers
38   @{
39 */
40 
41 /** Single statistic. */
42 struct PFS_single_stat
43 {
44   /** Count of values. */
45   ulonglong m_count;
46   /** Sum of values. */
47   ulonglong m_sum;
48   /** Minimum value. */
49   ulonglong m_min;
50   /** Maximum value. */
51   ulonglong m_max;
52 
PFS_single_statPFS_single_stat53   PFS_single_stat()
54   {
55     m_count= 0;
56     m_sum= 0;
57     m_min= ULLONG_MAX;
58     m_max= 0;
59   }
60 
resetPFS_single_stat61   inline void reset(void)
62   {
63     m_count= 0;
64     m_sum= 0;
65     m_min= ULLONG_MAX;
66     m_max= 0;
67   }
68 
has_timed_statsPFS_single_stat69   inline bool has_timed_stats() const
70   {
71     return (m_min <= m_max);
72   }
73 
aggregatePFS_single_stat74   inline void aggregate(const PFS_single_stat *stat)
75   {
76     if (stat->m_count != 0)
77     {
78       m_count+= stat->m_count;
79       m_sum+= stat->m_sum;
80       if (unlikely(m_min > stat->m_min))
81         m_min= stat->m_min;
82       if (unlikely(m_max < stat->m_max))
83         m_max= stat->m_max;
84     }
85   }
86 
aggregate_no_checkPFS_single_stat87   inline void aggregate_no_check(const PFS_single_stat *stat)
88   {
89     m_count+= stat->m_count;
90     m_sum+= stat->m_sum;
91     if (unlikely(m_min > stat->m_min))
92       m_min= stat->m_min;
93     if (unlikely(m_max < stat->m_max))
94       m_max= stat->m_max;
95   }
96 
aggregate_countedPFS_single_stat97   inline void aggregate_counted()
98   {
99     m_count++;
100   }
101 
aggregate_countedPFS_single_stat102   inline void aggregate_counted(ulonglong count)
103   {
104     m_count+= count;
105   }
106 
aggregate_valuePFS_single_stat107   inline void aggregate_value(ulonglong value)
108   {
109     m_count++;
110     m_sum+= value;
111     if (unlikely(m_min > value))
112       m_min= value;
113     if (unlikely(m_max < value))
114       m_max= value;
115   }
116 
aggregate_many_valuePFS_single_stat117   inline void aggregate_many_value(ulonglong value, ulonglong count)
118   {
119     m_count+= count;
120     m_sum+= value;
121     if (unlikely(m_min > value))
122       m_min= value;
123     if (unlikely(m_max < value))
124       m_max= value;
125   }
126 };
127 
128 /** Combined statistic. */
129 struct PFS_byte_stat : public PFS_single_stat
130 {
131   /** Byte count statistics */
132   ulonglong m_bytes;
133 
134   /** Aggregate wait stats, event count and byte count */
aggregatePFS_byte_stat135   inline void aggregate(const PFS_byte_stat *stat)
136   {
137     if (stat->m_count != 0)
138     {
139       PFS_single_stat::aggregate_no_check(stat);
140       m_bytes+= stat->m_bytes;
141     }
142   }
143 
144   /** Aggregate wait stats, event count and byte count */
aggregate_no_checkPFS_byte_stat145   inline void aggregate_no_check(const PFS_byte_stat *stat)
146   {
147     PFS_single_stat::aggregate_no_check(stat);
148     m_bytes+= stat->m_bytes;
149   }
150 
151   /** Aggregate individual wait time, event count and byte count */
aggregatePFS_byte_stat152   inline void aggregate(ulonglong wait, ulonglong bytes)
153   {
154     aggregate_value(wait);
155     m_bytes+= bytes;
156   }
157 
158   /** Aggregate wait stats and event count */
aggregate_waitsPFS_byte_stat159   inline void aggregate_waits(const PFS_byte_stat *stat)
160   {
161     PFS_single_stat::aggregate(stat);
162   }
163 
164   /** Aggregate event count and byte count */
aggregate_countedPFS_byte_stat165   inline void aggregate_counted()
166   {
167     PFS_single_stat::aggregate_counted();
168   }
169 
170   /** Aggregate event count and byte count */
aggregate_countedPFS_byte_stat171   inline void aggregate_counted(ulonglong bytes)
172   {
173     PFS_single_stat::aggregate_counted();
174     m_bytes+= bytes;
175   }
176 
PFS_byte_statPFS_byte_stat177   PFS_byte_stat()
178   {
179     reset();
180   }
181 
resetPFS_byte_stat182   inline void reset(void)
183   {
184     PFS_single_stat::reset();
185     m_bytes= 0;
186   }
187 };
188 
189 /** Statistics for mutex usage. */
190 struct PFS_mutex_stat
191 {
192   /** Wait statistics. */
193   PFS_single_stat m_wait_stat;
194 #ifdef PFS_LATER
195   /**
196     Lock statistics.
197     This statistic is not exposed in user visible tables yet.
198   */
199   PFS_single_stat m_lock_stat;
200 #endif
201 
aggregatePFS_mutex_stat202   inline void aggregate(const PFS_mutex_stat *stat)
203   {
204     m_wait_stat.aggregate(&stat->m_wait_stat);
205 #ifdef PFS_LATER
206     m_lock_stat.aggregate(&stat->m_lock_stat);
207 #endif
208   }
209 
resetPFS_mutex_stat210   inline void reset(void)
211   {
212     m_wait_stat.reset();
213 #ifdef PFS_LATER
214     m_lock_stat.reset();
215 #endif
216   }
217 };
218 
219 /** Statistics for rwlock usage. */
220 struct PFS_rwlock_stat
221 {
222   /** Wait statistics. */
223   PFS_single_stat m_wait_stat;
224 #ifdef PFS_LATER
225   /**
226     RWLock read lock usage statistics.
227     This statistic is not exposed in user visible tables yet.
228   */
229   PFS_single_stat m_read_lock_stat;
230   /**
231     RWLock write lock usage statistics.
232     This statistic is not exposed in user visible tables yet.
233   */
234   PFS_single_stat m_write_lock_stat;
235 #endif
236 
aggregatePFS_rwlock_stat237   inline void aggregate(const PFS_rwlock_stat *stat)
238   {
239     m_wait_stat.aggregate(&stat->m_wait_stat);
240 #ifdef PFS_LATER
241     m_read_lock_stat.aggregate(&stat->m_read_lock_stat);
242     m_write_lock_stat.aggregate(&stat->m_write_lock_stat);
243 #endif
244   }
245 
resetPFS_rwlock_stat246   inline void reset(void)
247   {
248     m_wait_stat.reset();
249 #ifdef PFS_LATER
250     m_read_lock_stat.reset();
251     m_write_lock_stat.reset();
252 #endif
253   }
254 };
255 
256 /** Statistics for COND usage. */
257 struct PFS_cond_stat
258 {
259   /** Wait statistics. */
260   PFS_single_stat m_wait_stat;
261 #ifdef PFS_LATER
262   /**
263     Number of times a condition was signalled.
264     This statistic is not exposed in user visible tables yet.
265   */
266   ulonglong m_signal_count;
267   /**
268     Number of times a condition was broadcast.
269     This statistic is not exposed in user visible tables yet.
270   */
271   ulonglong m_broadcast_count;
272 #endif
273 
aggregatePFS_cond_stat274   inline void aggregate(const PFS_cond_stat *stat)
275   {
276     m_wait_stat.aggregate(&stat->m_wait_stat);
277 #ifdef PFS_LATER
278     m_signal_count+= stat->m_signal_count;
279     m_broadcast_count+= stat->m_broadcast_count;
280 #endif
281   }
282 
resetPFS_cond_stat283   inline void reset(void)
284   {
285     m_wait_stat.reset();
286 #ifdef PFS_LATER
287     m_signal_count= 0;
288     m_broadcast_count= 0;
289 #endif
290   }
291 };
292 
293 /** Statistics for FILE IO. Used for both waits and byte counts. */
294 struct PFS_file_io_stat
295 {
296   /** READ statistics */
297   PFS_byte_stat m_read;
298   /** WRITE statistics */
299   PFS_byte_stat m_write;
300   /** Miscellaneous statistics */
301   PFS_byte_stat m_misc;
302 
resetPFS_file_io_stat303   inline void reset(void)
304   {
305     m_read.reset();
306     m_write.reset();
307     m_misc.reset();
308   }
309 
aggregatePFS_file_io_stat310   inline void aggregate(const PFS_file_io_stat *stat)
311   {
312     m_read.aggregate(&stat->m_read);
313     m_write.aggregate(&stat->m_write);
314     m_misc.aggregate(&stat->m_misc);
315   }
316 
317   /* Sum waits and byte counts */
sumPFS_file_io_stat318   inline void sum(PFS_byte_stat *stat)
319   {
320     stat->aggregate(&m_read);
321     stat->aggregate(&m_write);
322     stat->aggregate(&m_misc);
323   }
324 
325   /* Sum waits only */
sum_waitsPFS_file_io_stat326   inline void sum_waits(PFS_single_stat *stat)
327   {
328     stat->aggregate(&m_read);
329     stat->aggregate(&m_write);
330     stat->aggregate(&m_misc);
331   }
332 };
333 
334 /** Statistics for FILE usage. */
335 struct PFS_file_stat
336 {
337   /** Number of current open handles. */
338   ulong m_open_count;
339   /** File IO statistics. */
340   PFS_file_io_stat m_io_stat;
341 
aggregatePFS_file_stat342   inline void aggregate(const PFS_file_stat *stat)
343   {
344     m_io_stat.aggregate(&stat->m_io_stat);
345   }
346 
347   /** Reset file statistics. */
resetPFS_file_stat348   inline void reset(void)
349   {
350     m_io_stat.reset();
351   }
352 };
353 
354 /** Statistics for stage usage. */
355 struct PFS_stage_stat
356 {
357   PFS_single_stat m_timer1_stat;
358 
resetPFS_stage_stat359   inline void reset(void)
360   { m_timer1_stat.reset(); }
361 
aggregate_countedPFS_stage_stat362   inline void aggregate_counted()
363   { m_timer1_stat.aggregate_counted(); }
364 
aggregate_valuePFS_stage_stat365   inline void aggregate_value(ulonglong value)
366   { m_timer1_stat.aggregate_value(value); }
367 
aggregatePFS_stage_stat368   inline void aggregate(const PFS_stage_stat *stat)
369   { m_timer1_stat.aggregate(& stat->m_timer1_stat); }
370 };
371 
372 /** Statistics for stored program usage. */
373 struct PFS_sp_stat
374 {
375   PFS_single_stat m_timer1_stat;
376 
resetPFS_sp_stat377   inline void reset(void)
378   { m_timer1_stat.reset(); }
379 
aggregate_countedPFS_sp_stat380   inline void aggregate_counted()
381   { m_timer1_stat.aggregate_counted(); }
382 
aggregate_valuePFS_sp_stat383   inline void aggregate_value(ulonglong value)
384   { m_timer1_stat.aggregate_value(value); }
385 
aggregatePFS_sp_stat386   inline void aggregate(const PFS_stage_stat *stat)
387   { m_timer1_stat.aggregate(& stat->m_timer1_stat); }
388 };
389 
390 /** Statistics for prepared statement usage. */
391 struct PFS_prepared_stmt_stat
392 {
393   PFS_single_stat m_timer1_stat;
394 
resetPFS_prepared_stmt_stat395   inline void reset(void)
396   { m_timer1_stat.reset(); }
397 
aggregate_countedPFS_prepared_stmt_stat398   inline void aggregate_counted()
399   { m_timer1_stat.aggregate_counted(); }
400 
aggregate_valuePFS_prepared_stmt_stat401   inline void aggregate_value(ulonglong value)
402   { m_timer1_stat.aggregate_value(value); }
403 
aggregatePFS_prepared_stmt_stat404   inline void aggregate(PFS_stage_stat *stat)
405   { m_timer1_stat.aggregate(& stat->m_timer1_stat); }
406 };
407 
408 /**
409   Statistics for statement usage.
410   This structure uses lazy initialization,
411   controlled by member @c m_timer1_stat.m_count.
412 */
413 struct PFS_statement_stat
414 {
415   PFS_single_stat m_timer1_stat;
416   ulonglong m_error_count;
417   ulonglong m_warning_count;
418   ulonglong m_rows_affected;
419   ulonglong m_lock_time;
420   ulonglong m_rows_sent;
421   ulonglong m_rows_examined;
422   ulonglong m_created_tmp_disk_tables;
423   ulonglong m_created_tmp_tables;
424   ulonglong m_select_full_join;
425   ulonglong m_select_full_range_join;
426   ulonglong m_select_range;
427   ulonglong m_select_range_check;
428   ulonglong m_select_scan;
429   ulonglong m_sort_merge_passes;
430   ulonglong m_sort_range;
431   ulonglong m_sort_rows;
432   ulonglong m_sort_scan;
433   ulonglong m_no_index_used;
434   ulonglong m_no_good_index_used;
435 
PFS_statement_statPFS_statement_stat436   PFS_statement_stat()
437   {
438     reset();
439   }
440 
resetPFS_statement_stat441   inline void reset()
442   {
443     m_timer1_stat.m_count= 0;
444   }
445 
mark_usedPFS_statement_stat446   inline void mark_used()
447   {
448     delayed_reset();
449   }
450 
451 private:
delayed_resetPFS_statement_stat452   inline void delayed_reset(void)
453   {
454     if (m_timer1_stat.m_count == 0)
455     {
456       m_timer1_stat.reset();
457       m_error_count= 0;
458       m_warning_count= 0;
459       m_rows_affected= 0;
460       m_lock_time= 0;
461       m_rows_sent= 0;
462       m_rows_examined= 0;
463       m_created_tmp_disk_tables= 0;
464       m_created_tmp_tables= 0;
465       m_select_full_join= 0;
466       m_select_full_range_join= 0;
467       m_select_range= 0;
468       m_select_range_check= 0;
469       m_select_scan= 0;
470       m_sort_merge_passes= 0;
471       m_sort_range= 0;
472       m_sort_rows= 0;
473       m_sort_scan= 0;
474       m_no_index_used= 0;
475       m_no_good_index_used= 0;
476     }
477   }
478 
479 public:
aggregate_countedPFS_statement_stat480   inline void aggregate_counted()
481   {
482     delayed_reset();
483     m_timer1_stat.aggregate_counted();
484   }
485 
aggregate_valuePFS_statement_stat486   inline void aggregate_value(ulonglong value)
487   {
488     delayed_reset();
489     m_timer1_stat.aggregate_value(value);
490   }
491 
aggregatePFS_statement_stat492   inline void aggregate(const PFS_statement_stat *stat)
493   {
494     if (stat->m_timer1_stat.m_count != 0)
495     {
496       delayed_reset();
497       m_timer1_stat.aggregate_no_check(& stat->m_timer1_stat);
498 
499       m_error_count+= stat->m_error_count;
500       m_warning_count+= stat->m_warning_count;
501       m_rows_affected+= stat->m_rows_affected;
502       m_lock_time+= stat->m_lock_time;
503       m_rows_sent+= stat->m_rows_sent;
504       m_rows_examined+= stat->m_rows_examined;
505       m_created_tmp_disk_tables+= stat->m_created_tmp_disk_tables;
506       m_created_tmp_tables+= stat->m_created_tmp_tables;
507       m_select_full_join+= stat->m_select_full_join;
508       m_select_full_range_join+= stat->m_select_full_range_join;
509       m_select_range+= stat->m_select_range;
510       m_select_range_check+= stat->m_select_range_check;
511       m_select_scan+= stat->m_select_scan;
512       m_sort_merge_passes+= stat->m_sort_merge_passes;
513       m_sort_range+= stat->m_sort_range;
514       m_sort_rows+= stat->m_sort_rows;
515       m_sort_scan+= stat->m_sort_scan;
516       m_no_index_used+= stat->m_no_index_used;
517       m_no_good_index_used+= stat->m_no_good_index_used;
518     }
519   }
520 };
521 
522 /** Statistics for transaction usage. */
523 struct PFS_transaction_stat
524 {
525   PFS_single_stat m_read_write_stat;
526   PFS_single_stat m_read_only_stat;
527 
528   ulonglong m_savepoint_count;
529   ulonglong m_rollback_to_savepoint_count;
530   ulonglong m_release_savepoint_count;
531 
PFS_transaction_statPFS_transaction_stat532   PFS_transaction_stat()
533   {
534     m_savepoint_count= 0;
535     m_rollback_to_savepoint_count= 0;
536     m_release_savepoint_count= 0;
537   }
538 
countPFS_transaction_stat539   ulonglong count(void)
540   {
541     return (m_read_write_stat.m_count + m_read_only_stat.m_count);
542   }
543 
resetPFS_transaction_stat544   inline void reset(void)
545   {
546     m_read_write_stat.reset();
547     m_read_only_stat.reset();
548     m_savepoint_count= 0;
549     m_rollback_to_savepoint_count= 0;
550     m_release_savepoint_count= 0;
551   }
552 
aggregatePFS_transaction_stat553   inline void aggregate(const PFS_transaction_stat *stat)
554   {
555     m_read_write_stat.aggregate(&stat->m_read_write_stat);
556     m_read_only_stat.aggregate(&stat->m_read_only_stat);
557     m_savepoint_count+= stat->m_savepoint_count;
558     m_rollback_to_savepoint_count+= stat->m_rollback_to_savepoint_count;
559     m_release_savepoint_count+= stat->m_release_savepoint_count;
560   }
561 };
562 
563 /** Single table io statistic. */
564 struct PFS_table_io_stat
565 {
566   bool m_has_data;
567   /** FETCH statistics */
568   PFS_single_stat m_fetch;
569   /** INSERT statistics */
570   PFS_single_stat m_insert;
571   /** UPDATE statistics */
572   PFS_single_stat m_update;
573   /** DELETE statistics */
574   PFS_single_stat m_delete;
575 
PFS_table_io_statPFS_table_io_stat576   PFS_table_io_stat()
577   {
578     m_has_data= false;
579   }
580 
resetPFS_table_io_stat581   inline void reset(void)
582   {
583     m_has_data= false;
584     m_fetch.reset();
585     m_insert.reset();
586     m_update.reset();
587     m_delete.reset();
588   }
589 
aggregatePFS_table_io_stat590   inline void aggregate(const PFS_table_io_stat *stat)
591   {
592     if (stat->m_has_data)
593     {
594       m_has_data= true;
595       m_fetch.aggregate(&stat->m_fetch);
596       m_insert.aggregate(&stat->m_insert);
597       m_update.aggregate(&stat->m_update);
598       m_delete.aggregate(&stat->m_delete);
599     }
600   }
601 
sumPFS_table_io_stat602   inline void sum(PFS_single_stat *result)
603   {
604     if (m_has_data)
605     {
606       result->aggregate(& m_fetch);
607       result->aggregate(& m_insert);
608       result->aggregate(& m_update);
609       result->aggregate(& m_delete);
610     }
611   }
612 };
613 
614 enum PFS_TL_LOCK_TYPE
615 {
616   /* Locks from enum thr_lock */
617   PFS_TL_READ= 0,
618   PFS_TL_READ_WITH_SHARED_LOCKS= 1,
619   PFS_TL_READ_HIGH_PRIORITY= 2,
620   PFS_TL_READ_NO_INSERT= 3,
621   PFS_TL_WRITE_ALLOW_WRITE= 4,
622   PFS_TL_WRITE_CONCURRENT_INSERT= 5,
623   PFS_TL_WRITE_LOW_PRIORITY= 6,
624   PFS_TL_WRITE= 7,
625 
626   /* Locks for handler::ha_external_lock() */
627   PFS_TL_READ_EXTERNAL= 8,
628   PFS_TL_WRITE_EXTERNAL= 9,
629 
630   PFS_TL_NONE= 99
631 };
632 
633 #define COUNT_PFS_TL_LOCK_TYPE 10
634 
635 /** Statistics for table locks. */
636 struct PFS_table_lock_stat
637 {
638   PFS_single_stat m_stat[COUNT_PFS_TL_LOCK_TYPE];
639 
resetPFS_table_lock_stat640   inline void reset(void)
641   {
642     PFS_single_stat *pfs= & m_stat[0];
643     PFS_single_stat *pfs_last= & m_stat[COUNT_PFS_TL_LOCK_TYPE];
644     for ( ; pfs < pfs_last ; pfs++)
645       pfs->reset();
646   }
647 
aggregatePFS_table_lock_stat648   inline void aggregate(const PFS_table_lock_stat *stat)
649   {
650     PFS_single_stat *pfs= & m_stat[0];
651     PFS_single_stat *pfs_last= & m_stat[COUNT_PFS_TL_LOCK_TYPE];
652     const PFS_single_stat *pfs_from= & stat->m_stat[0];
653     for ( ; pfs < pfs_last ; pfs++, pfs_from++)
654       pfs->aggregate(pfs_from);
655   }
656 
sumPFS_table_lock_stat657   inline void sum(PFS_single_stat *result)
658   {
659     PFS_single_stat *pfs= & m_stat[0];
660     PFS_single_stat *pfs_last= & m_stat[COUNT_PFS_TL_LOCK_TYPE];
661     for ( ; pfs < pfs_last ; pfs++)
662       result->aggregate(pfs);
663   }
664 };
665 
666 /** Statistics for TABLE usage. */
667 struct PFS_table_stat
668 {
669   /**
670     Statistics, per index.
671     Each index stat is in [0, MAX_INDEXES-1],
672     stats when using no index are in [MAX_INDEXES].
673   */
674   PFS_table_io_stat m_index_stat[MAX_INDEXES + 1];
675 
676   /**
677     Statistics, per lock type.
678   */
679   PFS_table_lock_stat m_lock_stat;
680 
681   /** Reset table io statistic. */
reset_ioPFS_table_stat682   inline void reset_io(void)
683   {
684     PFS_table_io_stat *stat= & m_index_stat[0];
685     PFS_table_io_stat *stat_last= & m_index_stat[MAX_INDEXES + 1];
686     for ( ; stat < stat_last ; stat++)
687       stat->reset();
688   }
689 
690   /** Reset table lock statistic. */
reset_lockPFS_table_stat691   inline void reset_lock(void)
692   {
693     m_lock_stat.reset();
694   }
695 
696   /** Reset table statistic. */
resetPFS_table_stat697   inline void reset(void)
698   {
699     reset_io();
700     reset_lock();
701   }
702 
fast_reset_ioPFS_table_stat703   inline void fast_reset_io(void)
704   {
705     memcpy(& m_index_stat, & g_reset_template.m_index_stat, sizeof(m_index_stat));
706   }
707 
fast_reset_lockPFS_table_stat708   inline void fast_reset_lock(void)
709   {
710     memcpy(& m_lock_stat, & g_reset_template.m_lock_stat, sizeof(m_lock_stat));
711   }
712 
fast_resetPFS_table_stat713   inline void fast_reset(void)
714   {
715     memcpy(this, & g_reset_template, sizeof(*this));
716   }
717 
aggregate_ioPFS_table_stat718   inline void aggregate_io(const PFS_table_stat *stat, uint key_count)
719   {
720     PFS_table_io_stat *to_stat;
721     PFS_table_io_stat *to_stat_last;
722     const PFS_table_io_stat *from_stat;
723 
724     assert(key_count <= MAX_INDEXES);
725 
726     /* Aggregate stats for each index, if any */
727     to_stat= & m_index_stat[0];
728     to_stat_last= to_stat + key_count;
729     from_stat= & stat->m_index_stat[0];
730     for ( ; to_stat < to_stat_last ; from_stat++, to_stat++)
731       to_stat->aggregate(from_stat);
732 
733     /* Aggregate stats for the table */
734     to_stat= & m_index_stat[MAX_INDEXES];
735     from_stat= & stat->m_index_stat[MAX_INDEXES];
736     to_stat->aggregate(from_stat);
737   }
738 
aggregate_lockPFS_table_stat739   inline void aggregate_lock(const PFS_table_stat *stat)
740   {
741     m_lock_stat.aggregate(& stat->m_lock_stat);
742   }
743 
aggregatePFS_table_stat744   inline void aggregate(const PFS_table_stat *stat, uint key_count)
745   {
746     aggregate_io(stat, key_count);
747     aggregate_lock(stat);
748   }
749 
sum_ioPFS_table_stat750   inline void sum_io(PFS_single_stat *result, uint key_count)
751   {
752     PFS_table_io_stat *stat;
753     PFS_table_io_stat *stat_last;
754 
755     assert(key_count <= MAX_INDEXES);
756 
757     /* Sum stats for each index, if any */
758     stat= & m_index_stat[0];
759     stat_last= stat + key_count;
760     for ( ; stat < stat_last ; stat++)
761       stat->sum(result);
762 
763     /* Sum stats for the table */
764     m_index_stat[MAX_INDEXES].sum(result);
765   }
766 
sum_lockPFS_table_stat767   inline void sum_lock(PFS_single_stat *result)
768   {
769     m_lock_stat.sum(result);
770   }
771 
sumPFS_table_stat772   inline void sum(PFS_single_stat *result, uint key_count)
773   {
774     sum_io(result, key_count);
775     sum_lock(result);
776   }
777 
778   static struct PFS_table_stat g_reset_template;
779 };
780 
781 /** Statistics for SOCKET IO. Used for both waits and byte counts. */
782 struct PFS_socket_io_stat
783 {
784   /** READ statistics */
785   PFS_byte_stat m_read;
786   /** WRITE statistics */
787   PFS_byte_stat m_write;
788   /** Miscellaneous statistics */
789   PFS_byte_stat m_misc;
790 
resetPFS_socket_io_stat791   inline void reset(void)
792   {
793     m_read.reset();
794     m_write.reset();
795     m_misc.reset();
796   }
797 
aggregatePFS_socket_io_stat798   inline void aggregate(const PFS_socket_io_stat *stat)
799   {
800     m_read.aggregate(&stat->m_read);
801     m_write.aggregate(&stat->m_write);
802     m_misc.aggregate(&stat->m_misc);
803   }
804 
805   /* Sum waits and byte counts */
sumPFS_socket_io_stat806   inline void sum(PFS_byte_stat *stat)
807   {
808     stat->aggregate(&m_read);
809     stat->aggregate(&m_write);
810     stat->aggregate(&m_misc);
811   }
812 
813   /* Sum waits only */
sum_waitsPFS_socket_io_stat814   inline void sum_waits(PFS_single_stat *stat)
815   {
816     stat->aggregate(&m_read);
817     stat->aggregate(&m_write);
818     stat->aggregate(&m_misc);
819   }
820 };
821 
822 /** Statistics for SOCKET usage. */
823 struct PFS_socket_stat
824 {
825   /** Socket timing and byte count statistics per operation */
826   PFS_socket_io_stat m_io_stat;
827 
828   /** Reset socket statistics. */
resetPFS_socket_stat829   inline void reset(void)
830   {
831     m_io_stat.reset();
832   }
833 };
834 
835 struct PFS_memory_stat_delta
836 {
837   size_t m_alloc_count_delta;
838   size_t m_free_count_delta;
839   size_t m_alloc_size_delta;
840   size_t m_free_size_delta;
841 
resetPFS_memory_stat_delta842   void reset()
843   {
844     m_alloc_count_delta= 0;
845     m_free_count_delta= 0;
846     m_alloc_size_delta= 0;
847     m_free_size_delta= 0;
848   }
849 };
850 
851 /**
852   Memory statistics.
853   Conceptually, the following statistics are maintained:
854   - CURRENT_COUNT_USED,
855   - LOW_COUNT_USED,
856   - HIGH_COUNT_USED
857   - CURRENT_SIZE_USED,
858   - LOW_SIZE_USED,
859   - HIGH_SIZE_USED
860   Now, the implementation keeps different counters,
861   which are easier (less overhead) to maintain while
862   collecting statistics.
863   Invariants are as follows:
864   CURRENT_COUNT_USED = @c m_alloc_count - @c m_free_count
865   LOW_COUNT_USED + @c m_free_count_capacity = CURRENT_COUNT_USED
866   CURRENT_COUNT_USED + @c m_alloc_count_capacity = HIGH_COUNT_USED
867   CURRENT_SIZE_USED = @c m_alloc_size - @c m_free_size
868   LOW_SIZE_USED + @c m_free_size_capacity = CURRENT_SIZE_USED
869   CURRENT_SIZE_USED + @c m_alloc_size_capacity = HIGH_SIZE_USED
870 
871 */
872 struct PFS_memory_stat
873 {
874   bool m_used;
875   size_t m_alloc_count;
876   size_t m_free_count;
877   size_t m_alloc_size;
878   size_t m_free_size;
879 
880   size_t m_alloc_count_capacity;
881   size_t m_free_count_capacity;
882   size_t m_alloc_size_capacity;
883   size_t m_free_size_capacity;
884 
resetPFS_memory_stat885   inline void reset(void)
886   {
887     m_used= false;
888     m_alloc_count= 0;
889     m_free_count= 0;
890     m_alloc_size= 0;
891     m_free_size= 0;
892 
893     m_alloc_count_capacity= 0;
894     m_free_count_capacity= 0;
895     m_alloc_size_capacity= 0;
896     m_free_size_capacity= 0;
897   }
898 
rebasePFS_memory_stat899   inline void rebase(void)
900   {
901     if (! m_used)
902       return;
903 
904     size_t base;
905 
906     base= std::min<size_t>(m_alloc_count, m_free_count);
907     m_alloc_count-= base;
908     m_free_count-= base;
909 
910     base= std::min<size_t>(m_alloc_size, m_free_size);
911     m_alloc_size-= base;
912     m_free_size-= base;
913 
914     m_alloc_count_capacity= 0;
915     m_free_count_capacity= 0;
916     m_alloc_size_capacity= 0;
917     m_free_size_capacity= 0;
918   }
919 
partial_aggregate_toPFS_memory_stat920   inline void partial_aggregate_to(PFS_memory_stat *stat)
921   {
922     if (! m_used)
923       return;
924 
925     size_t base;
926 
927     stat->m_used= true;
928 
929     base= std::min<size_t>(m_alloc_count, m_free_count);
930     if (base != 0)
931     {
932       stat->m_alloc_count+= base;
933       stat->m_free_count+= base;
934       m_alloc_count-= base;
935       m_free_count-= base;
936     }
937 
938     base= std::min<size_t>(m_alloc_size, m_free_size);
939     if (base != 0)
940     {
941       stat->m_alloc_size+= base;
942       stat->m_free_size+= base;
943       m_alloc_size-= base;
944       m_free_size-= base;
945     }
946 
947     stat->m_alloc_count_capacity+= m_alloc_count_capacity;
948     stat->m_free_count_capacity+= m_free_count_capacity;
949     stat->m_alloc_size_capacity+= m_alloc_size_capacity;
950     stat->m_free_size_capacity+= m_free_size_capacity;
951 
952     m_alloc_count_capacity= 0;
953     m_free_count_capacity= 0;
954     m_alloc_size_capacity= 0;
955     m_free_size_capacity= 0;
956   }
957 
full_aggregate_toPFS_memory_stat958   inline void full_aggregate_to(PFS_memory_stat *stat) const
959   {
960     if (! m_used)
961       return;
962 
963     stat->m_used= true;
964 
965     stat->m_alloc_count+= m_alloc_count;
966     stat->m_free_count+= m_free_count;
967     stat->m_alloc_size+= m_alloc_size;
968     stat->m_free_size+= m_free_size;
969 
970     stat->m_alloc_count_capacity+= m_alloc_count_capacity;
971     stat->m_free_count_capacity+= m_free_count_capacity;
972     stat->m_alloc_size_capacity+= m_alloc_size_capacity;
973     stat->m_free_size_capacity+= m_free_size_capacity;
974   }
975 
partial_aggregate_toPFS_memory_stat976   inline void partial_aggregate_to(PFS_memory_stat *stat1, PFS_memory_stat *stat2)
977   {
978     if (! m_used)
979       return;
980 
981     size_t base;
982 
983     stat1->m_used= true;
984     stat2->m_used= true;
985 
986     base= std::min<size_t>(m_alloc_count, m_free_count);
987     if (base != 0)
988     {
989       stat1->m_alloc_count+= base;
990       stat2->m_alloc_count+= base;
991       stat1->m_free_count+= base;
992       stat2->m_free_count+= base;
993       m_alloc_count-= base;
994       m_free_count-= base;
995     }
996 
997     base= std::min<size_t>(m_alloc_size, m_free_size);
998     if (base != 0)
999     {
1000       stat1->m_alloc_size+= base;
1001       stat2->m_alloc_size+= base;
1002       stat1->m_free_size+= base;
1003       stat2->m_free_size+= base;
1004       m_alloc_size-= base;
1005       m_free_size-= base;
1006     }
1007 
1008     stat1->m_alloc_count_capacity+= m_alloc_count_capacity;
1009     stat2->m_alloc_count_capacity+= m_alloc_count_capacity;
1010     stat1->m_free_count_capacity+= m_free_count_capacity;
1011     stat2->m_free_count_capacity+= m_free_count_capacity;
1012     stat1->m_alloc_size_capacity+= m_alloc_size_capacity;
1013     stat2->m_alloc_size_capacity+= m_alloc_size_capacity;
1014     stat1->m_free_size_capacity+= m_free_size_capacity;
1015     stat2->m_free_size_capacity+= m_free_size_capacity;
1016 
1017     m_alloc_count_capacity= 0;
1018     m_free_count_capacity= 0;
1019     m_alloc_size_capacity= 0;
1020     m_free_size_capacity= 0;
1021   }
1022 
full_aggregate_toPFS_memory_stat1023   inline void full_aggregate_to(PFS_memory_stat *stat1, PFS_memory_stat *stat2) const
1024   {
1025     if (! m_used)
1026       return;
1027 
1028     stat1->m_used= true;
1029     stat2->m_used= true;
1030 
1031     stat1->m_alloc_count+= m_alloc_count;
1032     stat2->m_alloc_count+= m_alloc_count;
1033     stat1->m_free_count+= m_free_count;
1034     stat2->m_free_count+= m_free_count;
1035     stat1->m_alloc_size+= m_alloc_size;
1036     stat2->m_alloc_size+= m_alloc_size;
1037     stat1->m_free_size+= m_free_size;
1038     stat2->m_free_size+= m_free_size;
1039 
1040     stat1->m_alloc_count_capacity+= m_alloc_count_capacity;
1041     stat2->m_alloc_count_capacity+= m_alloc_count_capacity;
1042     stat1->m_free_count_capacity+= m_free_count_capacity;
1043     stat2->m_free_count_capacity+= m_free_count_capacity;
1044     stat1->m_alloc_size_capacity+= m_alloc_size_capacity;
1045     stat2->m_alloc_size_capacity+= m_alloc_size_capacity;
1046     stat1->m_free_size_capacity+= m_free_size_capacity;
1047     stat2->m_free_size_capacity+= m_free_size_capacity;
1048   }
1049 
count_builtin_allocPFS_memory_stat1050   void count_builtin_alloc(size_t size)
1051   {
1052     m_used= true;
1053 
1054     m_alloc_count++;
1055     m_free_count_capacity++;
1056     m_alloc_size+= size;
1057     m_free_size_capacity+= size;
1058 
1059     if (m_alloc_count_capacity >= 1)
1060     {
1061       m_alloc_count_capacity--;
1062     }
1063 
1064     if (m_alloc_size_capacity >= size)
1065     {
1066       m_alloc_size_capacity-= size;
1067     }
1068 
1069     return;
1070   }
1071 
count_builtin_freePFS_memory_stat1072   void count_builtin_free(size_t size)
1073   {
1074     m_used= true;
1075 
1076     m_free_count++;
1077     m_alloc_count_capacity++;
1078     m_free_size+= size;
1079     m_alloc_size_capacity+= size;
1080 
1081     if (m_free_count_capacity >= 1)
1082     {
1083       m_free_count_capacity--;
1084     }
1085 
1086     if (m_free_size_capacity >= size)
1087     {
1088       m_free_size_capacity-= size;
1089     }
1090 
1091     return;
1092   }
1093 
count_allocPFS_memory_stat1094   inline PFS_memory_stat_delta *count_alloc(size_t size,
1095                                             PFS_memory_stat_delta *delta)
1096   {
1097     m_used= true;
1098 
1099     m_alloc_count++;
1100     m_free_count_capacity++;
1101     m_alloc_size+= size;
1102     m_free_size_capacity+= size;
1103 
1104     if ((m_alloc_count_capacity >= 1) &&
1105         (m_alloc_size_capacity >= size))
1106     {
1107       m_alloc_count_capacity--;
1108       m_alloc_size_capacity-= size;
1109       return NULL;
1110     }
1111 
1112     delta->reset();
1113 
1114     if (m_alloc_count_capacity >= 1)
1115     {
1116       m_alloc_count_capacity--;
1117     }
1118     else
1119     {
1120       delta->m_alloc_count_delta= 1;
1121     }
1122 
1123     if (m_alloc_size_capacity >= size)
1124     {
1125       m_alloc_size_capacity-= size;
1126     }
1127     else
1128     {
1129       delta->m_alloc_size_delta= size - m_alloc_size_capacity;
1130       m_alloc_size_capacity= 0;
1131     }
1132 
1133     return delta;
1134   }
1135 
count_reallocPFS_memory_stat1136   inline PFS_memory_stat_delta *count_realloc(size_t old_size, size_t new_size,
1137                                               PFS_memory_stat_delta *delta)
1138   {
1139     m_used= true;
1140 
1141     size_t size_delta= new_size - old_size;
1142     m_alloc_count++;
1143     m_alloc_size+= new_size;
1144     m_free_count++;
1145     m_free_size+= old_size;
1146 
1147     if (new_size == old_size)
1148     {
1149       return NULL;
1150     }
1151 
1152     if (new_size > old_size)
1153     {
1154       /* Growing */
1155       size_delta= new_size - old_size;
1156       m_free_size_capacity+= size_delta;
1157 
1158       if (m_alloc_size_capacity >= size_delta)
1159       {
1160         m_alloc_size_capacity-= size_delta;
1161         return NULL;
1162       }
1163 
1164       delta->reset();
1165       delta->m_alloc_size_delta= size_delta - m_alloc_size_capacity;
1166       m_alloc_size_capacity= 0;
1167     }
1168     else
1169     {
1170       /* Shrinking */
1171       size_delta= old_size - new_size;
1172       m_alloc_size_capacity+= size_delta;
1173 
1174       if (m_free_size_capacity >= size_delta)
1175       {
1176         m_free_size_capacity-= size_delta;
1177         return NULL;
1178       }
1179 
1180       delta->reset();
1181       delta->m_free_size_delta= size_delta - m_free_size_capacity;
1182       m_free_size_capacity= 0;
1183     }
1184 
1185     return delta;
1186   }
1187 
count_freePFS_memory_stat1188   inline PFS_memory_stat_delta *count_free(size_t size, PFS_memory_stat_delta *delta)
1189   {
1190     m_used= true;
1191 
1192     m_free_count++;
1193     m_alloc_count_capacity++;
1194     m_free_size+= size;
1195     m_alloc_size_capacity+= size;
1196 
1197     if ((m_free_count_capacity >= 1) &&
1198         (m_free_size_capacity >= size))
1199     {
1200       m_free_count_capacity--;
1201       m_free_size_capacity-= size;
1202       return NULL;
1203     }
1204 
1205     delta->reset();
1206 
1207     if (m_free_count_capacity >= 1)
1208     {
1209       m_free_count_capacity--;
1210     }
1211     else
1212     {
1213       delta->m_free_count_delta= 1;
1214     }
1215 
1216     if (m_free_size_capacity >= size)
1217     {
1218       m_free_size_capacity-= size;
1219     }
1220     else
1221     {
1222       delta->m_free_size_delta= size - m_free_size_capacity;
1223       m_free_size_capacity= 0;
1224     }
1225 
1226     return delta;
1227   }
1228 
apply_deltaPFS_memory_stat1229   inline PFS_memory_stat_delta *apply_delta(const PFS_memory_stat_delta *delta,
1230                                             PFS_memory_stat_delta *delta_buffer)
1231   {
1232     size_t val;
1233     size_t remaining_alloc_count;
1234     size_t remaining_alloc_size;
1235     size_t remaining_free_count;
1236     size_t remaining_free_size;
1237     bool has_remaining= false;
1238 
1239     m_used= true;
1240 
1241     val= delta->m_alloc_count_delta;
1242     if (val <= m_alloc_count_capacity)
1243     {
1244       m_alloc_count_capacity-= val;
1245       remaining_alloc_count= 0;
1246     }
1247     else
1248     {
1249       remaining_alloc_count= val - m_alloc_count_capacity;
1250       m_alloc_count_capacity= 0;
1251       has_remaining= true;
1252     }
1253 
1254     val= delta->m_alloc_size_delta;
1255     if (val <= m_alloc_size_capacity)
1256     {
1257       m_alloc_size_capacity-= val;
1258       remaining_alloc_size= 0;
1259     }
1260     else
1261     {
1262       remaining_alloc_size= val - m_alloc_size_capacity;
1263       m_alloc_size_capacity= 0;
1264       has_remaining= true;
1265     }
1266 
1267     val= delta->m_free_count_delta;
1268     if (val <= m_free_count_capacity)
1269     {
1270       m_free_count_capacity-= val;
1271       remaining_free_count= 0;
1272     }
1273     else
1274     {
1275       remaining_free_count= val - m_free_count_capacity;
1276       m_free_count_capacity= 0;
1277       has_remaining= true;
1278     }
1279 
1280     val= delta->m_free_size_delta;
1281     if (val <= m_free_size_capacity)
1282     {
1283       m_free_size_capacity-= val;
1284       remaining_free_size= 0;
1285     }
1286     else
1287     {
1288       remaining_free_size= val - m_free_size_capacity;
1289       m_free_size_capacity= 0;
1290       has_remaining= true;
1291     }
1292 
1293     if (! has_remaining)
1294       return NULL;
1295 
1296     delta_buffer->m_alloc_count_delta= remaining_alloc_count;
1297     delta_buffer->m_alloc_size_delta= remaining_alloc_size;
1298     delta_buffer->m_free_count_delta= remaining_free_count;
1299     delta_buffer->m_free_size_delta= remaining_free_size;
1300     return delta_buffer;
1301   }
1302 };
1303 
1304 #define PFS_MEMORY_STAT_INITIALIZER { false, 0, 0, 0, 0, 0, 0, 0, 0}
1305 
1306 /** Connections statistics. */
1307 struct PFS_connection_stat
1308 {
PFS_connection_statPFS_connection_stat1309   PFS_connection_stat()
1310   : m_current_connections(0),
1311     m_total_connections(0)
1312   {}
1313 
1314   ulonglong m_current_connections;
1315   ulonglong m_total_connections;
1316 
aggregate_activePFS_connection_stat1317   inline void aggregate_active(ulonglong active)
1318   {
1319     m_current_connections+= active;
1320     m_total_connections+= active;
1321   }
1322 
aggregate_disconnectedPFS_connection_stat1323   inline void aggregate_disconnected(ulonglong disconnected)
1324   {
1325     m_total_connections+= disconnected;
1326   }
1327 };
1328 
1329 /** @} */
1330 #endif
1331 
1332