1 /* Copyright (c) 2008, 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 Foundation,
21 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */
22
23 #include "my_global.h"
24 #include "my_thread.h"
25 #include "table_threads.h"
26 #include "sql_parse.h"
27 #include "pfs_instr_class.h"
28 #include "pfs_instr.h"
29
30 THR_LOCK table_threads::m_table_lock;
31
32 static const TABLE_FIELD_TYPE field_types[]=
33 {
34 {
35 { C_STRING_WITH_LEN("THREAD_ID") },
36 { C_STRING_WITH_LEN("bigint(20)") },
37 { NULL, 0}
38 },
39 {
40 { C_STRING_WITH_LEN("NAME") },
41 { C_STRING_WITH_LEN("varchar(128)") },
42 { NULL, 0}
43 },
44 {
45 { C_STRING_WITH_LEN("TYPE") },
46 { C_STRING_WITH_LEN("varchar(10)") },
47 { NULL, 0}
48 },
49 {
50 { C_STRING_WITH_LEN("PROCESSLIST_ID") },
51 { C_STRING_WITH_LEN("bigint(20)") },
52 { NULL, 0}
53 },
54 {
55 { C_STRING_WITH_LEN("PROCESSLIST_USER") },
56 { C_STRING_WITH_LEN("varchar(" USERNAME_CHAR_LENGTH_STR ")") },
57 { NULL, 0}
58 },
59 {
60 { C_STRING_WITH_LEN("PROCESSLIST_HOST") },
61 { C_STRING_WITH_LEN("varchar(60)") },
62 { NULL, 0}
63 },
64 {
65 { C_STRING_WITH_LEN("PROCESSLIST_DB") },
66 { C_STRING_WITH_LEN("varchar(64)") },
67 { NULL, 0}
68 },
69 {
70 { C_STRING_WITH_LEN("PROCESSLIST_COMMAND") },
71 { C_STRING_WITH_LEN("varchar(16)") },
72 { NULL, 0}
73 },
74 {
75 { C_STRING_WITH_LEN("PROCESSLIST_TIME") },
76 { C_STRING_WITH_LEN("bigint(20)") },
77 { NULL, 0}
78 },
79 {
80 { C_STRING_WITH_LEN("PROCESSLIST_STATE") },
81 { C_STRING_WITH_LEN("varchar(64)") },
82 { NULL, 0}
83 },
84 {
85 { C_STRING_WITH_LEN("PROCESSLIST_INFO") },
86 { C_STRING_WITH_LEN("longtext") },
87 { NULL, 0}
88 },
89 {
90 { C_STRING_WITH_LEN("PARENT_THREAD_ID") },
91 { C_STRING_WITH_LEN("bigint(20)") },
92 { NULL, 0}
93 },
94 {
95 { C_STRING_WITH_LEN("ROLE") },
96 { C_STRING_WITH_LEN("varchar(64)") },
97 { NULL, 0}
98 },
99 {
100 { C_STRING_WITH_LEN("INSTRUMENTED") },
101 { C_STRING_WITH_LEN("enum(\'YES\',\'NO\')") },
102 { NULL, 0}
103 },
104 {
105 { C_STRING_WITH_LEN("HISTORY") },
106 { C_STRING_WITH_LEN("enum(\'YES\',\'NO\')") },
107 { NULL, 0}
108 },
109 {
110 { C_STRING_WITH_LEN("CONNECTION_TYPE") },
111 { C_STRING_WITH_LEN("varchar(16)") },
112 { NULL, 0 }
113 },
114 {
115 { C_STRING_WITH_LEN("THREAD_OS_ID") },
116 { C_STRING_WITH_LEN("bigint(20)") },
117 { NULL, 0}
118 },
119 };
120
121 TABLE_FIELD_DEF
122 table_threads::m_field_def=
123 { 17, field_types };
124
125 PFS_engine_table_share
126 table_threads::m_share=
127 {
128 { C_STRING_WITH_LEN("threads") },
129 &pfs_updatable_acl,
130 table_threads::create,
131 NULL, /* write_row */
132 NULL, /* delete_all_rows */
133 cursor_by_thread::get_row_count,
134 sizeof(PFS_simple_index), /* ref length */
135 &m_table_lock,
136 &m_field_def,
137 false, /* checked */
138 false /* perpetual */
139 };
140
create()141 PFS_engine_table* table_threads::create()
142 {
143 return new table_threads();
144 }
145
table_threads()146 table_threads::table_threads()
147 : cursor_by_thread(& m_share),
148 m_row_exists(false)
149 {}
150
make_row(PFS_thread * pfs)151 void table_threads::make_row(PFS_thread *pfs)
152 {
153 pfs_optimistic_state lock;
154 pfs_optimistic_state session_lock;
155 pfs_optimistic_state stmt_lock;
156 PFS_stage_class *stage_class;
157 PFS_thread_class *safe_class;
158
159 m_row_exists= false;
160
161 /* Protect this reader against thread termination */
162 pfs->m_lock.begin_optimistic_lock(&lock);
163
164 safe_class= sanitize_thread_class(pfs->m_class);
165 if (unlikely(safe_class == NULL))
166 return;
167
168 m_row.m_thread_internal_id= pfs->m_thread_internal_id;
169 m_row.m_parent_thread_internal_id= pfs->m_parent_thread_internal_id;
170 m_row.m_processlist_id= pfs->m_processlist_id;
171 m_row.m_thread_os_id= pfs->m_thread_os_id;
172 m_row.m_name= safe_class->m_name;
173 m_row.m_name_length= safe_class->m_name_length;
174
175 /* Protect this reader against session attribute changes */
176 pfs->m_session_lock.begin_optimistic_lock(&session_lock);
177
178 m_row.m_username_length= pfs->m_username_length;
179 if (unlikely(m_row.m_username_length > sizeof(m_row.m_username)))
180 return;
181 if (m_row.m_username_length != 0)
182 memcpy(m_row.m_username, pfs->m_username, m_row.m_username_length);
183
184 m_row.m_hostname_length= pfs->m_hostname_length;
185 if (unlikely(m_row.m_hostname_length > sizeof(m_row.m_hostname)))
186 return;
187 if (m_row.m_hostname_length != 0)
188 memcpy(m_row.m_hostname, pfs->m_hostname, m_row.m_hostname_length);
189
190 if (! pfs->m_session_lock.end_optimistic_lock(& session_lock))
191 {
192 /*
193 One of the columns:
194 - PROCESSLIST_USER
195 - PROCESSLIST_HOST
196 is being updated.
197 Do not discard the entire row.
198 Do not loop waiting for a stable value.
199 Just return NULL values.
200 */
201 m_row.m_username_length= 0;
202 m_row.m_hostname_length= 0;
203 }
204
205 /* Protect this reader against statement attributes changes */
206 pfs->m_stmt_lock.begin_optimistic_lock(&stmt_lock);
207
208 m_row.m_dbname_length= pfs->m_dbname_length;
209 if (unlikely(m_row.m_dbname_length > sizeof(m_row.m_dbname)))
210 return;
211 if (m_row.m_dbname_length != 0)
212 memcpy(m_row.m_dbname, pfs->m_dbname, m_row.m_dbname_length);
213
214 m_row.m_processlist_info_ptr= & pfs->m_processlist_info[0];
215 m_row.m_processlist_info_length= pfs->m_processlist_info_length;
216
217 if (! pfs->m_stmt_lock.end_optimistic_lock(& stmt_lock))
218 {
219 /*
220 One of the columns:
221 - PROCESSLIST_DB
222 - PROCESSLIST_INFO
223 is being updated.
224 Do not discard the entire row.
225 Do not loop waiting for a stable value.
226 Just return NULL values.
227 */
228 m_row.m_dbname_length= 0;
229 m_row.m_processlist_info_length= 0;
230 }
231
232 /* Dirty read, sanitize the command. */
233 m_row.m_command= pfs->m_command;
234 if ((m_row.m_command < 0) || (m_row.m_command > COM_END))
235 m_row.m_command= COM_END;
236
237 m_row.m_start_time= pfs->m_start_time;
238
239 stage_class= find_stage_class(pfs->m_stage);
240 if (stage_class != NULL)
241 {
242 m_row.m_processlist_state_ptr= stage_class->m_name + stage_class->m_prefix_length;
243 m_row.m_processlist_state_length= stage_class->m_name_length - stage_class->m_prefix_length;
244 }
245 else
246 {
247 m_row.m_processlist_state_length= 0;
248 }
249 m_row.m_connection_type = pfs->m_connection_type;
250
251
252 m_row.m_enabled= !pfs->m_disable_instrumentation && pfs->m_enabled;
253 m_row.m_history= pfs->m_history;
254 m_row.m_psi= pfs;
255
256 if (pfs->m_lock.end_optimistic_lock(& lock))
257 m_row_exists= true;
258
259 if(pfs->m_disable_instrumentation)
260 m_row_exists= false;
261 }
262
read_row_values(TABLE * table,unsigned char * buf,Field ** fields,bool read_all)263 int table_threads::read_row_values(TABLE *table,
264 unsigned char *buf,
265 Field **fields,
266 bool read_all)
267 {
268 Field *f;
269 const char *str= NULL;
270 int len= 0;
271
272 if (unlikely(! m_row_exists))
273 return HA_ERR_RECORD_DELETED;
274
275 /* Set the null bits */
276 assert(table->s->null_bytes == 2);
277 buf[0]= 0;
278 buf[1]= 0;
279
280 for (; (f= *fields) ; fields++)
281 {
282 if (read_all || bitmap_is_set(table->read_set, f->field_index))
283 {
284 switch(f->field_index)
285 {
286 case 0: /* THREAD_ID */
287 set_field_ulonglong(f, m_row.m_thread_internal_id);
288 break;
289 case 1: /* NAME */
290 set_field_varchar_utf8(f, m_row.m_name, m_row.m_name_length);
291 break;
292 case 2: /* TYPE */
293 if (m_row.m_processlist_id != 0)
294 set_field_varchar_utf8(f, "FOREGROUND", 10);
295 else
296 set_field_varchar_utf8(f, "BACKGROUND", 10);
297 break;
298 case 3: /* PROCESSLIST_ID */
299 if (m_row.m_processlist_id != 0)
300 set_field_ulonglong(f, m_row.m_processlist_id);
301 else
302 f->set_null();
303 break;
304 case 4: /* PROCESSLIST_USER */
305 if (m_row.m_username_length > 0)
306 set_field_varchar_utf8(f, m_row.m_username,
307 m_row.m_username_length);
308 else
309 f->set_null();
310 break;
311 case 5: /* PROCESSLIST_HOST */
312 if (m_row.m_hostname_length > 0)
313 set_field_varchar_utf8(f, m_row.m_hostname,
314 m_row.m_hostname_length);
315 else
316 f->set_null();
317 break;
318 case 6: /* PROCESSLIST_DB */
319 if (m_row.m_dbname_length > 0)
320 set_field_varchar_utf8(f, m_row.m_dbname,
321 m_row.m_dbname_length);
322 else
323 f->set_null();
324 break;
325 case 7: /* PROCESSLIST_COMMAND */
326 if (m_row.m_processlist_id != 0)
327 set_field_varchar_utf8(f, command_name[m_row.m_command].str,
328 command_name[m_row.m_command].length);
329 else
330 f->set_null();
331 break;
332 case 8: /* PROCESSLIST_TIME */
333 if (m_row.m_start_time)
334 {
335 time_t now= my_time(0);
336 ulonglong elapsed= (now > m_row.m_start_time ? now - m_row.m_start_time : 0);
337 set_field_ulonglong(f, elapsed);
338 }
339 else
340 f->set_null();
341 break;
342 case 9: /* PROCESSLIST_STATE */
343 /* This column's datatype is declared as varchar(64). Thread's state
344 message cannot be more than 64 characters. Otherwise, we will end up
345 in 'data truncated' warning/error (depends sql_mode setting) when
346 server is updating this column for those threads. To prevent this
347 kind of issue, an assert is added.
348 */
349 assert(m_row.m_processlist_state_length <= f->char_length());
350 if (m_row.m_processlist_state_length > 0)
351 set_field_varchar_utf8(f, m_row.m_processlist_state_ptr,
352 m_row.m_processlist_state_length);
353 else
354 f->set_null();
355 break;
356 case 10: /* PROCESSLIST_INFO */
357 if (m_row.m_processlist_info_length > 0)
358 set_field_longtext_utf8(f, m_row.m_processlist_info_ptr,
359 m_row.m_processlist_info_length);
360 else
361 f->set_null();
362 break;
363 case 11: /* PARENT_THREAD_ID */
364 if (m_row.m_parent_thread_internal_id != 0)
365 set_field_ulonglong(f, m_row.m_parent_thread_internal_id);
366 else
367 f->set_null();
368 break;
369 case 12: /* ROLE */
370 f->set_null();
371 break;
372 case 13: /* INSTRUMENTED */
373 set_field_enum(f, m_row.m_enabled ? ENUM_YES : ENUM_NO);
374 break;
375 case 14: /* HISTORY */
376 set_field_enum(f, m_row.m_history ? ENUM_YES : ENUM_NO);
377 break;
378 case 15: /* CONNECTION_TYPE */
379 get_vio_type_name(m_row.m_connection_type, & str, & len);
380 if (len > 0)
381 set_field_varchar_utf8(f, str, len);
382 else
383 f->set_null();
384 break;
385 case 16: /* THREAD_OS_ID */
386 if (m_row.m_thread_os_id > 0)
387 set_field_ulonglong(f, m_row.m_thread_os_id);
388 else
389 f->set_null();
390 break;
391 default:
392 assert(false);
393 }
394 }
395 }
396 return 0;
397 }
398
update_row_values(TABLE * table,const unsigned char * old_buf,unsigned char * new_buf,Field ** fields)399 int table_threads::update_row_values(TABLE *table,
400 const unsigned char *old_buf,
401 unsigned char *new_buf,
402 Field **fields)
403 {
404 Field *f;
405 enum_yes_no value;
406
407 for (; (f= *fields) ; fields++)
408 {
409 if (bitmap_is_set(table->write_set, f->field_index))
410 {
411 switch(f->field_index)
412 {
413 case 0: /* THREAD_ID */
414 case 1: /* NAME */
415 case 2: /* TYPE */
416 case 3: /* PROCESSLIST_ID */
417 case 4: /* PROCESSLIST_USER */
418 case 5: /* PROCESSLIST_HOST */
419 case 6: /* PROCESSLIST_DB */
420 case 7: /* PROCESSLIST_COMMAND */
421 case 8: /* PROCESSLIST_TIME */
422 case 9: /* PROCESSLIST_STATE */
423 case 10: /* PROCESSLIST_INFO */
424 case 11: /* PARENT_THREAD_ID */
425 case 12: /* ROLE */
426 return HA_ERR_WRONG_COMMAND;
427 case 13: /* INSTRUMENTED */
428 value= (enum_yes_no) get_field_enum(f);
429 m_row.m_psi->set_enabled((value == ENUM_YES) ? true : false);
430 break;
431 case 14: /* HISTORY */
432 value= (enum_yes_no) get_field_enum(f);
433 m_row.m_psi->set_history((value == ENUM_YES) ? true : false);
434 break;
435 case 15: /* CONNECTION_TYPE */
436 case 16: /* THREAD_OS_ID */
437 return HA_ERR_WRONG_COMMAND;
438 default:
439 assert(false);
440 }
441 }
442 }
443 return 0;
444 }
445
446