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