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 | #ident "Copyright (c) 2006, 2015, Percona and/or its affiliates. All rights reserved." |
38 | |
39 | #pragma once |
40 | |
41 | // Overview: A partitioned_counter provides a counter that can be incremented and the running sum can be read at any time. |
42 | // We assume that increments are frequent, whereas reading is infrequent. |
43 | // Implementation hint: Use thread-local storage so each thread increments its own data. The increment does not require a lock or atomic operation. |
44 | // Reading the data can be performed by iterating over the thread-local versions, summing them up. |
45 | // The data structure also includes a sum for all the threads that have died. |
46 | // 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 |
47 | // into the sum_of_dead counter. |
48 | // 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 |
49 | // performance speedups by removing certain counters. Rather than removing those statistics, we would like to just make the counter fast. |
50 | // We generally increment the counters frequently, and want to fetch the values infrequently. |
51 | // The counters are monotonic. |
52 | // The counters can be split into many counters, which can be summed up at the end. |
53 | // 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 |
54 | // variable and incrementing. |
55 | // See tests/test_partitioned_counter.c for some performance measurements. |
56 | // Operations: |
57 | // create_partitioned_counter Create a counter initialized to zero. |
58 | // destroy_partitioned_counter Destroy it. |
59 | // increment_partitioned_counter Increment it. This is the frequent operation. |
60 | // read_partitioned_counter Get the current value. This is infrequent. |
61 | // See partitioned_counter.cc for the abstraction function and representation invariant. |
62 | // |
63 | // The google style guide says to avoid using constructors, and it appears that |
64 | // constructors may have broken all the tests, because they called |
65 | // pthread_key_create before the key was actually created. So the google style |
66 | // guide may have some wisdom there... |
67 | // |
68 | // This version does not use constructors, essentially reverrting to the google C++ style guide. |
69 | // |
70 | |
71 | // The old C interface. This required a bunch of explicit ___attribute__((__destructor__)) functions to remember to destroy counters at the end. |
72 | #if defined(__cplusplus) |
73 | extern "C" { |
74 | #endif |
75 | |
76 | typedef struct partitioned_counter *PARTITIONED_COUNTER; |
77 | PARTITIONED_COUNTER create_partitioned_counter(void); |
78 | // Effect: Create a counter, initialized to zero. |
79 | |
80 | void destroy_partitioned_counter(PARTITIONED_COUNTER); |
81 | // Effect: Destroy the counter. No operations on that counter are permitted after this. |
82 | |
83 | void increment_partitioned_counter(PARTITIONED_COUNTER, uint64_t amount); |
84 | // Effect: Increment the counter by amount. |
85 | // Requires: No overflows. This is a 64-bit unsigned counter. |
86 | |
87 | uint64_t read_partitioned_counter(PARTITIONED_COUNTER) __attribute__((__visibility__("default" ))); |
88 | // Effect: Return the current value of the counter. |
89 | |
90 | void partitioned_counters_init(void); |
91 | // Effect: Initialize any partitioned counters data structures that must be set up before any partitioned counters run. |
92 | |
93 | void partitioned_counters_destroy(void); |
94 | // Effect: Destroy any partitioned counters data structures. |
95 | |
96 | #if defined(__cplusplus) |
97 | }; |
98 | #endif |
99 | |
100 | #if 0 |
101 | #include <pthread.h> |
102 | #include "fttypes.h" |
103 | |
104 | // Used inside the PARTITIONED_COUNTER. |
105 | struct linked_list_head { |
106 | struct linked_list_element *first; |
107 | }; |
108 | |
109 | |
110 | class PARTITIONED_COUNTER { |
111 | public: |
112 | PARTITIONED_COUNTER(void); |
113 | // Effect: Construct a counter, initialized to zero. |
114 | |
115 | ~PARTITIONED_COUNTER(void); |
116 | // Effect: Destruct the counter. |
117 | |
118 | void increment(uint64_t amount); |
119 | // 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). |
120 | // Requires: Don't use this from a static constructor or destructor. |
121 | |
122 | uint64_t read(void); |
123 | // Effect: Read the sum. |
124 | // Requires: Don't use this from a static constructor or destructor. |
125 | |
126 | private: |
127 | uint64_t _sum_of_dead; // The sum of all thread-local counts from threads that have terminated. |
128 | pthread_key_t _key; // The pthread_key which gives us the hook to construct and destruct thread-local storage. |
129 | struct linked_list_head _ll_counter_head; // A linked list of all the thread-local information for this counter. |
130 | |
131 | // This function is used to destroy the thread-local part of the state when a thread terminates. |
132 | // 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. |
133 | friend void destroy_thread_local_part_of_partitioned_counters (void *); |
134 | }; |
135 | #endif |
136 | |