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