1/* Copyright (c) 2010, 2015, 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 as published by
5 the Free Software Foundation; version 2 of the License.
6
7 This program is distributed in the hope that it will be useful,
8 but WITHOUT ANY WARRANTY; without even the implied warranty of
9 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 GNU General Public License for more details.
11
12 You should have received a copy of the GNU General Public License
13 along with this program; if not, write to the Free Software
14 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */
15
16/**
17 @file storage/perfschema/pfs_host.cc
18 Performance schema host (implementation).
19*/
20
21#include "my_global.h"
22#include "my_sys.h"
23#include "pfs.h"
24#include "pfs_stat.h"
25#include "pfs_instr.h"
26#include "pfs_setup_actor.h"
27#include "pfs_host.h"
28#include "pfs_global.h"
29#include "pfs_instr_class.h"
30
31/**
32 @addtogroup Performance_schema_buffers
33 @{
34*/
35
36ulong host_max;
37ulong host_lost;
38
39PFS_host *host_array= NULL;
40
41static PFS_single_stat *host_instr_class_waits_array= NULL;
42static PFS_stage_stat *host_instr_class_stages_array= NULL;
43static PFS_statement_stat *host_instr_class_statements_array= NULL;
44
45LF_HASH host_hash;
46static bool host_hash_inited= false;
47
48/**
49 Initialize the host buffers.
50 @param param sizing parameters
51 @return 0 on success
52*/
53int init_host(const PFS_global_param *param)
54{
55 uint index;
56
57 host_max= param->m_host_sizing;
58
59 host_array= NULL;
60 host_instr_class_waits_array= NULL;
61 host_instr_class_stages_array= NULL;
62 host_instr_class_statements_array= NULL;
63 uint waits_sizing= host_max * wait_class_max;
64 uint stages_sizing= host_max * stage_class_max;
65 uint statements_sizing= host_max * statement_class_max;
66
67 if (host_max > 0)
68 {
69 host_array= PFS_MALLOC_ARRAY(host_max, sizeof(PFS_host), PFS_host,
70 MYF(MY_ZEROFILL));
71 if (unlikely(host_array == NULL))
72 return 1;
73 }
74
75 if (waits_sizing > 0)
76 {
77 host_instr_class_waits_array=
78 PFS_connection_slice::alloc_waits_slice(waits_sizing);
79 if (unlikely(host_instr_class_waits_array == NULL))
80 return 1;
81 }
82
83 if (stages_sizing > 0)
84 {
85 host_instr_class_stages_array=
86 PFS_connection_slice::alloc_stages_slice(stages_sizing);
87 if (unlikely(host_instr_class_stages_array == NULL))
88 return 1;
89 }
90
91 if (statements_sizing > 0)
92 {
93 host_instr_class_statements_array=
94 PFS_connection_slice::alloc_statements_slice(statements_sizing);
95 if (unlikely(host_instr_class_statements_array == NULL))
96 return 1;
97 }
98
99 for (index= 0; index < host_max; index++)
100 {
101 host_array[index].m_instr_class_waits_stats=
102 &host_instr_class_waits_array[index * wait_class_max];
103 host_array[index].m_instr_class_stages_stats=
104 &host_instr_class_stages_array[index * stage_class_max];
105 host_array[index].m_instr_class_statements_stats=
106 &host_instr_class_statements_array[index * statement_class_max];
107 }
108
109 return 0;
110}
111
112/** Cleanup all the host buffers. */
113void cleanup_host(void)
114{
115 pfs_free(host_array);
116 host_array= NULL;
117 pfs_free(host_instr_class_waits_array);
118 host_instr_class_waits_array= NULL;
119 pfs_free(host_instr_class_stages_array);
120 host_instr_class_stages_array= NULL;
121 pfs_free(host_instr_class_statements_array);
122 host_instr_class_statements_array= NULL;
123 host_max= 0;
124}
125
126C_MODE_START
127static uchar *host_hash_get_key(const uchar *entry, size_t *length,
128 my_bool)
129{
130 const PFS_host * const *typed_entry;
131 const PFS_host *host;
132 const void *result;
133 typed_entry= reinterpret_cast<const PFS_host* const *> (entry);
134 DBUG_ASSERT(typed_entry != NULL);
135 host= *typed_entry;
136 DBUG_ASSERT(host != NULL);
137 *length= host->m_key.m_key_length;
138 result= host->m_key.m_hash_key;
139 return const_cast<uchar*> (reinterpret_cast<const uchar*> (result));
140}
141C_MODE_END
142
143/**
144 Initialize the host hash.
145 @return 0 on success
146*/
147int init_host_hash(void)
148{
149 if ((! host_hash_inited) && (host_max > 0))
150 {
151 lf_hash_init(&host_hash, sizeof(PFS_host*), LF_HASH_UNIQUE,
152 0, 0, host_hash_get_key, &my_charset_bin);
153 /* host_hash.size= host_max; */
154 host_hash_inited= true;
155 }
156 return 0;
157}
158
159/** Cleanup the host hash. */
160void cleanup_host_hash(void)
161{
162 if (host_hash_inited)
163 {
164 lf_hash_destroy(&host_hash);
165 host_hash_inited= false;
166 }
167}
168
169static LF_PINS* get_host_hash_pins(PFS_thread *thread)
170{
171 if (unlikely(thread->m_host_hash_pins == NULL))
172 {
173 if (! host_hash_inited)
174 return NULL;
175 thread->m_host_hash_pins= lf_hash_get_pins(&host_hash);
176 }
177 return thread->m_host_hash_pins;
178}
179
180static void set_host_key(PFS_host_key *key,
181 const char *host, uint host_length)
182{
183 DBUG_ASSERT(host_length <= HOSTNAME_LENGTH);
184
185 char *ptr= &key->m_hash_key[0];
186 if (host_length > 0)
187 {
188 memcpy(ptr, host, host_length);
189 ptr+= host_length;
190 }
191 ptr[0]= 0;
192 ptr++;
193 key->m_key_length= (uint)(ptr - &key->m_hash_key[0]);
194}
195
196PFS_host *find_or_create_host(PFS_thread *thread,
197 const char *hostname, uint hostname_length)
198{
199 if (host_max == 0)
200 {
201 host_lost++;
202 return NULL;
203 }
204
205 LF_PINS *pins= get_host_hash_pins(thread);
206 if (unlikely(pins == NULL))
207 {
208 host_lost++;
209 return NULL;
210 }
211
212 PFS_host_key key;
213 set_host_key(&key, hostname, hostname_length);
214
215 PFS_host **entry;
216 uint retry_count= 0;
217 const uint retry_max= 3;
218
219search:
220 entry= reinterpret_cast<PFS_host**>
221 (lf_hash_search(&host_hash, pins,
222 key.m_hash_key, key.m_key_length));
223 if (entry && (entry != MY_ERRPTR))
224 {
225 PFS_host *pfs;
226 pfs= *entry;
227 pfs->inc_refcount();
228 lf_hash_search_unpin(pins);
229 return pfs;
230 }
231
232 lf_hash_search_unpin(pins);
233
234 PFS_scan scan;
235 uint random= randomized_index(hostname, host_max);
236
237 for (scan.init(random, host_max);
238 scan.has_pass();
239 scan.next_pass())
240 {
241 PFS_host *pfs= host_array + scan.first();
242 PFS_host *pfs_last= host_array + scan.last();
243 for ( ; pfs < pfs_last; pfs++)
244 {
245 if (pfs->m_lock.is_free())
246 {
247 if (pfs->m_lock.free_to_dirty())
248 {
249 pfs->m_key= key;
250 if (hostname_length > 0)
251 pfs->m_hostname= &pfs->m_key.m_hash_key[0];
252 else
253 pfs->m_hostname= NULL;
254 pfs->m_hostname_length= hostname_length;
255
256 pfs->init_refcount();
257 pfs->reset_stats();
258 pfs->m_disconnected_count= 0;
259
260 int res;
261 res= lf_hash_insert(&host_hash, pins, &pfs);
262 if (likely(res == 0))
263 {
264 pfs->m_lock.dirty_to_allocated();
265 return pfs;
266 }
267
268 pfs->m_lock.dirty_to_free();
269
270 if (res > 0)
271 {
272 if (++retry_count > retry_max)
273 {
274 host_lost++;
275 return NULL;
276 }
277 goto search;
278 }
279
280 host_lost++;
281 return NULL;
282 }
283 }
284 }
285 }
286
287 host_lost++;
288 return NULL;
289}
290
291void PFS_host::aggregate()
292{
293 aggregate_waits();
294 aggregate_stages();
295 aggregate_statements();
296 aggregate_stats();
297}
298
299void PFS_host::aggregate_waits()
300{
301 /* No parent to aggregate to, clean the stats */
302 reset_waits_stats();
303}
304
305void PFS_host::aggregate_stages()
306{
307 /*
308 Aggregate EVENTS_STAGES_SUMMARY_BY_HOST_BY_EVENT_NAME to:
309 - EVENTS_STAGES_SUMMARY_GLOBAL_BY_EVENT_NAME
310 */
311 aggregate_all_stages(m_instr_class_stages_stats,
312 global_instr_class_stages_array);
313}
314
315void PFS_host::aggregate_statements()
316{
317 /*
318 Aggregate EVENTS_STATEMENTS_SUMMARY_BY_HOST_BY_EVENT_NAME to:
319 - EVENTS_STATEMENTS_SUMMARY_GLOBAL_BY_EVENT_NAME
320 */
321 aggregate_all_statements(m_instr_class_statements_stats,
322 global_instr_class_statements_array);
323}
324
325void PFS_host::aggregate_stats()
326{
327 /* No parent to aggregate to, clean the stats */
328 m_disconnected_count= 0;
329}
330
331void PFS_host::release()
332{
333 dec_refcount();
334}
335
336PFS_host *sanitize_host(PFS_host *unsafe)
337{
338 if ((&host_array[0] <= unsafe) &&
339 (unsafe < &host_array[host_max]))
340 return unsafe;
341 return NULL;
342}
343
344void purge_host(PFS_thread *thread, PFS_host *host)
345{
346 LF_PINS *pins= get_host_hash_pins(thread);
347 if (unlikely(pins == NULL))
348 return;
349
350 PFS_host **entry;
351 entry= reinterpret_cast<PFS_host**>
352 (lf_hash_search(&host_hash, pins,
353 host->m_key.m_hash_key, host->m_key.m_key_length));
354 if (entry && (entry != MY_ERRPTR))
355 {
356 DBUG_ASSERT(*entry == host);
357 if (host->get_refcount() == 0)
358 {
359 lf_hash_delete(&host_hash, pins,
360 host->m_key.m_hash_key, host->m_key.m_key_length);
361 host->m_lock.allocated_to_free();
362 }
363 }
364
365 lf_hash_search_unpin(pins);
366}
367
368/** Purge non connected hosts, reset stats of connected hosts. */
369void purge_all_host(void)
370{
371 PFS_thread *thread= PFS_thread::get_current_thread();
372 if (unlikely(thread == NULL))
373 return;
374
375 PFS_host *pfs= host_array;
376 PFS_host *pfs_last= host_array + host_max;
377
378 for ( ; pfs < pfs_last; pfs++)
379 {
380 if (pfs->m_lock.is_populated())
381 {
382 pfs->aggregate();
383 if (pfs->get_refcount() == 0)
384 purge_host(thread, pfs);
385 }
386 }
387}
388
389/** @} */
390