1 /* Copyright (c) 2010, 2020, Oracle and/or its affiliates. All rights reserved.
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 St, Fifth Floor, Boston, MA 02110-1301 USA
22 */
23
24 /**
25 @file storage/perfschema/pfs_host.cc
26 Performance schema host (implementation).
27 */
28
29 #include "storage/perfschema/pfs_host.h"
30
31 #include "my_compiler.h"
32 #include "my_dbug.h"
33 #include "my_sys.h"
34 #include "sql/mysqld.h" // global_status_var
35 #include "storage/perfschema/pfs.h"
36 #include "storage/perfschema/pfs_buffer_container.h"
37 #include "storage/perfschema/pfs_global.h"
38 #include "storage/perfschema/pfs_instr.h"
39 #include "storage/perfschema/pfs_instr_class.h"
40 #include "storage/perfschema/pfs_setup_actor.h"
41 #include "storage/perfschema/pfs_stat.h"
42
43 /**
44 @addtogroup performance_schema_buffers
45 @{
46 */
47
48 LF_HASH host_hash;
49 static bool host_hash_inited = false;
50
51 /**
52 Initialize the host buffers.
53 @param param sizing parameters
54 @return 0 on success
55 */
init_host(const PFS_global_param * param)56 int init_host(const PFS_global_param *param) {
57 if (global_host_container.init(param->m_host_sizing)) {
58 return 1;
59 }
60
61 return 0;
62 }
63
64 /** Cleanup all the host buffers. */
cleanup_host(void)65 void cleanup_host(void) { global_host_container.cleanup(); }
66
host_hash_get_key(const uchar * entry,size_t * length)67 static const uchar *host_hash_get_key(const uchar *entry, size_t *length) {
68 const PFS_host *const *typed_entry;
69 const PFS_host *host;
70 const void *result;
71 typed_entry = reinterpret_cast<const PFS_host *const *>(entry);
72 DBUG_ASSERT(typed_entry != nullptr);
73 host = *typed_entry;
74 DBUG_ASSERT(host != nullptr);
75 *length = host->m_key.m_key_length;
76 result = host->m_key.m_hash_key;
77 return reinterpret_cast<const uchar *>(result);
78 }
79
80 /**
81 Initialize the host hash.
82 @return 0 on success
83 */
init_host_hash(const PFS_global_param * param)84 int init_host_hash(const PFS_global_param *param) {
85 if ((!host_hash_inited) && (param->m_host_sizing != 0)) {
86 lf_hash_init(&host_hash, sizeof(PFS_host *), LF_HASH_UNIQUE, 0, 0,
87 host_hash_get_key, &my_charset_bin);
88 host_hash_inited = true;
89 }
90 return 0;
91 }
92
93 /** Cleanup the host hash. */
cleanup_host_hash(void)94 void cleanup_host_hash(void) {
95 if (host_hash_inited) {
96 lf_hash_destroy(&host_hash);
97 host_hash_inited = false;
98 }
99 }
100
get_host_hash_pins(PFS_thread * thread)101 static LF_PINS *get_host_hash_pins(PFS_thread *thread) {
102 if (unlikely(thread->m_host_hash_pins == nullptr)) {
103 if (!host_hash_inited) {
104 return nullptr;
105 }
106 thread->m_host_hash_pins = lf_hash_get_pins(&host_hash);
107 }
108 return thread->m_host_hash_pins;
109 }
110
set_host_key(PFS_host_key * key,const char * host,uint host_length)111 static void set_host_key(PFS_host_key *key, const char *host,
112 uint host_length) {
113 DBUG_ASSERT(host_length <= HOSTNAME_LENGTH);
114
115 char *ptr = &key->m_hash_key[0];
116 if (host_length > 0) {
117 memcpy(ptr, host, host_length);
118 ptr += host_length;
119 }
120 ptr[0] = 0;
121 ptr++;
122 key->m_key_length = ptr - &key->m_hash_key[0];
123 }
124
find_or_create_host(PFS_thread * thread,const char * hostname,uint hostname_length)125 PFS_host *find_or_create_host(PFS_thread *thread, const char *hostname,
126 uint hostname_length) {
127 LF_PINS *pins = get_host_hash_pins(thread);
128 if (unlikely(pins == nullptr)) {
129 global_host_container.m_lost++;
130 return nullptr;
131 }
132
133 PFS_host_key key;
134 set_host_key(&key, hostname, hostname_length);
135
136 PFS_host **entry;
137 PFS_host *pfs;
138 uint retry_count = 0;
139 const uint retry_max = 3;
140 pfs_dirty_state dirty_state;
141
142 search:
143 entry = reinterpret_cast<PFS_host **>(
144 lf_hash_search(&host_hash, pins, key.m_hash_key, key.m_key_length));
145 if (entry && (entry != MY_LF_ERRPTR)) {
146 PFS_host *pfs;
147 pfs = *entry;
148 pfs->inc_refcount();
149 lf_hash_search_unpin(pins);
150 return pfs;
151 }
152
153 lf_hash_search_unpin(pins);
154
155 pfs = global_host_container.allocate(&dirty_state);
156 if (pfs != nullptr) {
157 pfs->m_key = key;
158 if (hostname_length > 0) {
159 pfs->m_hostname = &pfs->m_key.m_hash_key[0];
160 } else {
161 pfs->m_hostname = nullptr;
162 }
163 pfs->m_hostname_length = hostname_length;
164
165 pfs->init_refcount();
166 pfs->reset_stats();
167 pfs->m_disconnected_count = 0;
168
169 int res;
170 pfs->m_lock.dirty_to_allocated(&dirty_state);
171 res = lf_hash_insert(&host_hash, pins, &pfs);
172 if (likely(res == 0)) {
173 return pfs;
174 }
175
176 global_host_container.deallocate(pfs);
177
178 if (res > 0) {
179 if (++retry_count > retry_max) {
180 global_host_container.m_lost++;
181 return nullptr;
182 }
183 goto search;
184 }
185
186 global_host_container.m_lost++;
187 return nullptr;
188 }
189
190 return nullptr;
191 }
192
aggregate(bool alive)193 void PFS_host::aggregate(bool alive) {
194 aggregate_waits();
195 aggregate_stages();
196 aggregate_statements();
197 aggregate_transactions();
198 aggregate_errors();
199 aggregate_memory(alive);
200 aggregate_status();
201 aggregate_stats();
202 }
203
aggregate_waits()204 void PFS_host::aggregate_waits() {
205 /* No parent to aggregate to, clean the stats */
206 reset_waits_stats();
207 }
208
aggregate_stages()209 void PFS_host::aggregate_stages() {
210 if (read_instr_class_stages_stats() == nullptr) {
211 return;
212 }
213
214 /*
215 Aggregate EVENTS_STAGES_SUMMARY_BY_HOST_BY_EVENT_NAME to:
216 - EVENTS_STAGES_SUMMARY_GLOBAL_BY_EVENT_NAME
217 */
218 aggregate_all_stages(write_instr_class_stages_stats(),
219 global_instr_class_stages_array);
220 }
221
aggregate_statements()222 void PFS_host::aggregate_statements() {
223 if (read_instr_class_statements_stats() == nullptr) {
224 return;
225 }
226
227 /*
228 Aggregate EVENTS_STATEMENTS_SUMMARY_BY_HOST_BY_EVENT_NAME to:
229 - EVENTS_STATEMENTS_SUMMARY_GLOBAL_BY_EVENT_NAME
230 */
231 aggregate_all_statements(write_instr_class_statements_stats(),
232 global_instr_class_statements_array);
233 }
234
aggregate_transactions()235 void PFS_host::aggregate_transactions() {
236 if (read_instr_class_transactions_stats() == nullptr) {
237 return;
238 }
239
240 /*
241 Aggregate EVENTS_TRANSACTIONS_SUMMARY_BY_HOST_BY_EVENT_NAME to:
242 - EVENTS_TRANSACTIONS_SUMMARY_GLOBAL_BY_EVENT_NAME
243 */
244 aggregate_all_transactions(write_instr_class_transactions_stats(),
245 &global_transaction_stat);
246 }
247
aggregate_errors()248 void PFS_host::aggregate_errors() {
249 if (read_instr_class_errors_stats() == nullptr) {
250 return;
251 }
252
253 /*
254 Aggregate EVENTS_ERRORS_SUMMARY_BY_HOST_BY_ERROR to:
255 - EVENTS_ERRORS_SUMMARY_GLOBAL_BY_ERROR
256 */
257 aggregate_all_errors(write_instr_class_errors_stats(), &global_error_stat);
258 }
259
aggregate_memory(bool alive)260 void PFS_host::aggregate_memory(bool alive) {
261 if (read_instr_class_memory_stats() == nullptr) {
262 return;
263 }
264
265 /*
266 Aggregate MEMORY_SUMMARY_BY_HOST_BY_EVENT_NAME to:
267 - MEMORY_SUMMARY_GLOBAL_BY_EVENT_NAME
268 */
269 aggregate_all_memory(alive, write_instr_class_memory_stats(),
270 global_instr_class_memory_array);
271 }
272
aggregate_status()273 void PFS_host::aggregate_status() {
274 /* No parent to aggregate to, clean the stats */
275 m_status_stats.reset();
276 }
277
aggregate_stats()278 void PFS_host::aggregate_stats() {
279 /* No parent to aggregate to, clean the stats */
280 m_disconnected_count = 0;
281 }
282
release()283 void PFS_host::release() { dec_refcount(); }
284
rebase_memory_stats()285 void PFS_host::rebase_memory_stats() {
286 PFS_memory_shared_stat *stat = m_instr_class_memory_stats;
287 PFS_memory_shared_stat *stat_last = stat + memory_class_max;
288 for (; stat < stat_last; stat++) {
289 stat->reset();
290 }
291 }
292
carry_memory_stat_delta(PFS_memory_stat_delta * delta,uint index)293 void PFS_host::carry_memory_stat_delta(PFS_memory_stat_delta *delta,
294 uint index) {
295 PFS_memory_shared_stat *event_name_array;
296 PFS_memory_shared_stat *stat;
297 PFS_memory_stat_delta delta_buffer;
298 PFS_memory_stat_delta *remaining_delta;
299
300 event_name_array = write_instr_class_memory_stats();
301 stat = &event_name_array[index];
302 remaining_delta = stat->apply_delta(delta, &delta_buffer);
303
304 if (remaining_delta != nullptr) {
305 carry_global_memory_stat_delta(remaining_delta, index);
306 }
307 }
308
sanitize_host(PFS_host * unsafe)309 PFS_host *sanitize_host(PFS_host *unsafe) {
310 return global_host_container.sanitize(unsafe);
311 }
312
purge_host(PFS_thread * thread,PFS_host * host)313 static void purge_host(PFS_thread *thread, PFS_host *host) {
314 LF_PINS *pins = get_host_hash_pins(thread);
315 if (unlikely(pins == nullptr)) {
316 return;
317 }
318
319 PFS_host **entry;
320 entry = reinterpret_cast<PFS_host **>(lf_hash_search(
321 &host_hash, pins, host->m_key.m_hash_key, host->m_key.m_key_length));
322 if (entry && (entry != MY_LF_ERRPTR)) {
323 DBUG_ASSERT(*entry == host);
324 if (host->get_refcount() == 0) {
325 lf_hash_delete(&host_hash, pins, host->m_key.m_hash_key,
326 host->m_key.m_key_length);
327 host->aggregate(false);
328 global_host_container.deallocate(host);
329 }
330 }
331
332 lf_hash_search_unpin(pins);
333 }
334
335 class Proc_purge_host : public PFS_buffer_processor<PFS_host> {
336 public:
Proc_purge_host(PFS_thread * thread)337 Proc_purge_host(PFS_thread *thread) : m_thread(thread) {}
338
operator ()(PFS_host * pfs)339 virtual void operator()(PFS_host *pfs) {
340 pfs->aggregate(true);
341 if (pfs->get_refcount() == 0) {
342 purge_host(m_thread, pfs);
343 }
344 }
345
346 private:
347 PFS_thread *m_thread;
348 };
349
350 /** Purge non connected hosts, reset stats of connected hosts. */
purge_all_host(void)351 void purge_all_host(void) {
352 PFS_thread *thread = PFS_thread::get_current_thread();
353 if (unlikely(thread == nullptr)) {
354 return;
355 }
356
357 Proc_purge_host proc(thread);
358 global_host_container.apply(proc);
359 }
360
361 /** @} */
362