1 /* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 // vim: ft=cpp:expandtab:ts=8:sw=4:softtabstop=4:
3 #ident "$Id$"
4 /*======
5 This file is part of PerconaFT.
6 
7 
8 Copyright (c) 2006, 2015, Percona and/or its affiliates. All rights reserved.
9 
10     PerconaFT is free software: you can redistribute it and/or modify
11     it under the terms of the GNU General Public License, version 2,
12     as published by the Free Software Foundation.
13 
14     PerconaFT 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 for more details.
18 
19     You should have received a copy of the GNU General Public License
20     along with PerconaFT.  If not, see <http://www.gnu.org/licenses/>.
21 
22 ----------------------------------------
23 
24     PerconaFT is free software: you can redistribute it and/or modify
25     it under the terms of the GNU Affero General Public License, version 3,
26     as published by the Free Software Foundation.
27 
28     PerconaFT is distributed in the hope that it will be useful,
29     but WITHOUT ANY WARRANTY; without even the implied warranty of
30     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
31     GNU Affero General Public License for more details.
32 
33     You should have received a copy of the GNU Affero General Public License
34     along with PerconaFT.  If not, see <http://www.gnu.org/licenses/>.
35 
36 ----------------------------------------
37 
38    Licensed under the Apache License, Version 2.0 (the "License");
39    you may not use this file except in compliance with the License.
40    You may obtain a copy of the License at
41 
42        http://www.apache.org/licenses/LICENSE-2.0
43 
44    Unless required by applicable law or agreed to in writing, software
45    distributed under the License is distributed on an "AS IS" BASIS,
46    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
47    See the License for the specific language governing permissions and
48    limitations under the License.
49 ======= */
50 
51 #ident "Copyright (c) 2006, 2015, Percona and/or its affiliates. All rights reserved."
52 
53 #pragma once
54 
55 // Overview: A partitioned_counter provides a counter that can be incremented and the running sum can be read at any time.
56 //  We assume that increments are frequent, whereas reading is infrequent.
57 // Implementation hint: Use thread-local storage so each thread increments its own data.  The increment does not require a lock or atomic operation.
58 //  Reading the data can be performed by iterating over the thread-local versions, summing them up.
59 //  The data structure also includes a sum for all the threads that have died.
60 //  Use a pthread_key to create the thread-local versions.  When a thread finishes, the system calls pthread_key destructor which can add that thread's copy
61 //  into the sum_of_dead counter.
62 // Rationale: For statistics such as are found in engine status, we need a counter that requires no cache misses to increment.  We've seen significant
63 //  performance speedups by removing certain counters.  Rather than removing those statistics, we would like to just make the counter fast.
64 //  We generally increment the counters frequently, and want to fetch the values infrequently.
65 //  The counters are monotonic.
66 //  The counters can be split into many counters, which can be summed up at the end.
67 //  We don't care if we get slightly out-of-date counter sums when we read the counter.  We don't care if there is a race on reading the a counter
68 //   variable and incrementing.
69 //  See tests/test_partitioned_counter.c for some performance measurements.
70 // Operations:
71 //   create_partitioned_counter    Create a counter initialized to zero.
72 //   destroy_partitioned_counter   Destroy it.
73 //   increment_partitioned_counter Increment it.  This is the frequent operation.
74 //   read_partitioned_counter      Get the current value.  This is infrequent.
75 // See partitioned_counter.cc for the abstraction function and representation invariant.
76 //
77 // The google style guide says to avoid using constructors, and it appears that
78 // constructors may have broken all the tests, because they called
79 // pthread_key_create before the key was actually created.  So the google style
80 // guide may have some wisdom there...
81 //
82 // This version does not use constructors, essentially reverrting to the google C++ style guide.
83 //
84 
85 // The old C interface.  This required a bunch of explicit ___attribute__((__destructor__)) functions to remember to destroy counters at the end.
86 #if defined(__cplusplus)
87 extern "C" {
88 #endif
89 
90 typedef struct partitioned_counter *PARTITIONED_COUNTER;
91 PARTITIONED_COUNTER create_partitioned_counter(void);
92 // Effect: Create a counter, initialized to zero.
93 
94 void destroy_partitioned_counter(PARTITIONED_COUNTER);
95 // Effect: Destroy the counter.  No operations on that counter are permitted after this.
96 
97 void increment_partitioned_counter(PARTITIONED_COUNTER, uint64_t amount);
98 // Effect: Increment the counter by amount.
99 // Requires: No overflows.  This is a 64-bit unsigned counter.
100 
101 uint64_t read_partitioned_counter(PARTITIONED_COUNTER) __attribute__((__visibility__("default")));
102 // Effect: Return the current value of the counter.
103 
104 void partitioned_counters_init(void);
105 // Effect: Initialize any partitioned counters data structures that must be set up before any partitioned counters run.
106 
107 void partitioned_counters_destroy(void);
108 // Effect: Destroy any partitioned counters data structures.
109 
110 #if defined(__cplusplus)
111 };
112 #endif
113 
114 #if 0
115 #include <pthread.h>
116 #include "fttypes.h"
117 
118 // Used inside the PARTITIONED_COUNTER.
119 struct linked_list_head {
120     struct linked_list_element *first;
121 };
122 
123 
124 class PARTITIONED_COUNTER {
125 public:
126     PARTITIONED_COUNTER(void);
127     // Effect: Construct a counter, initialized to zero.
128 
129     ~PARTITIONED_COUNTER(void);
130     // Effect: Destruct the counter.
131 
132     void increment(uint64_t amount);
133     // Effect: Increment the counter by amount.  This is a 64-bit unsigned counter, and if you overflow it, you will get overflowed results (that is mod 2^64).
134     // Requires: Don't use this from a static constructor or destructor.
135 
136     uint64_t read(void);
137     // Effect: Read the sum.
138     // Requires: Don't use this from a static constructor or destructor.
139 
140 private:
141     uint64_t       _sum_of_dead;             // The sum of all thread-local counts from threads that have terminated.
142     pthread_key_t   _key;                     // The pthread_key which gives us the hook to construct and destruct thread-local storage.
143     struct linked_list_head _ll_counter_head; // A linked list of all the thread-local information for this counter.
144 
145     // This function is used to destroy the thread-local part of the state when a thread terminates.
146     // But it's not the destructor for the local part of the counter, it's a destructor on a "dummy" key just so that we get a notification when a thread ends.
147     friend void destroy_thread_local_part_of_partitioned_counters (void *);
148 };
149 #endif
150