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