1 /* Copyright (c) 2008, 2014, 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 Foundation,
21 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */
22
23 #include "my_global.h"
24 #include "my_pthread.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(16)") },
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
106 TABLE_FIELD_DEF
107 table_threads::m_field_def=
108 { 14, field_types };
109
110 PFS_engine_table_share
111 table_threads::m_share=
112 {
113 { C_STRING_WITH_LEN("threads") },
114 &pfs_updatable_acl,
115 &table_threads::create,
116 NULL, /* write_row */
117 NULL, /* delete_all_rows */
118 NULL, /* get_row_count */
119 1000, /* records */
120 sizeof(PFS_simple_index), /* ref length */
121 &m_table_lock,
122 &m_field_def,
123 false /* checked */
124 };
125
create()126 PFS_engine_table* table_threads::create()
127 {
128 return new table_threads();
129 }
130
table_threads()131 table_threads::table_threads()
132 : cursor_by_thread(& m_share),
133 m_row_exists(false)
134 {}
135
make_row(PFS_thread * pfs)136 void table_threads::make_row(PFS_thread *pfs)
137 {
138 pfs_lock lock;
139 pfs_lock session_lock;
140 pfs_lock stmt_lock;
141 PFS_stage_class *stage_class;
142 PFS_thread_class *safe_class;
143
144 m_row_exists= false;
145
146 /* Protect this reader against thread termination */
147 pfs->m_lock.begin_optimistic_lock(&lock);
148
149 safe_class= sanitize_thread_class(pfs->m_class);
150 if (unlikely(safe_class == NULL))
151 return;
152
153 m_row.m_thread_internal_id= pfs->m_thread_internal_id;
154 m_row.m_parent_thread_internal_id= pfs->m_parent_thread_internal_id;
155 m_row.m_processlist_id= pfs->m_processlist_id;
156 m_row.m_name= safe_class->m_name;
157 m_row.m_name_length= safe_class->m_name_length;
158
159 /* Protect this reader against session attribute changes */
160 pfs->m_session_lock.begin_optimistic_lock(&session_lock);
161
162 m_row.m_username_length= pfs->m_username_length;
163 if (unlikely(m_row.m_username_length > sizeof(m_row.m_username)))
164 return;
165 if (m_row.m_username_length != 0)
166 memcpy(m_row.m_username, pfs->m_username, m_row.m_username_length);
167
168 m_row.m_hostname_length= pfs->m_hostname_length;
169 if (unlikely(m_row.m_hostname_length > sizeof(m_row.m_hostname)))
170 return;
171 if (m_row.m_hostname_length != 0)
172 memcpy(m_row.m_hostname, pfs->m_hostname, m_row.m_hostname_length);
173
174 if (! pfs->m_session_lock.end_optimistic_lock(& session_lock))
175 {
176 /*
177 One of the columns:
178 - PROCESSLIST_USER
179 - PROCESSLIST_HOST
180 is being updated.
181 Do not discard the entire row.
182 Do not loop waiting for a stable value.
183 Just return NULL values.
184 */
185 m_row.m_username_length= 0;
186 m_row.m_hostname_length= 0;
187 }
188
189 /* Protect this reader against statement attributes changes */
190 pfs->m_stmt_lock.begin_optimistic_lock(&stmt_lock);
191
192 m_row.m_dbname_length= pfs->m_dbname_length;
193 if (unlikely(m_row.m_dbname_length > sizeof(m_row.m_dbname)))
194 return;
195 if (m_row.m_dbname_length != 0)
196 memcpy(m_row.m_dbname, pfs->m_dbname, m_row.m_dbname_length);
197
198 m_row.m_processlist_info_ptr= & pfs->m_processlist_info[0];
199 m_row.m_processlist_info_length= pfs->m_processlist_info_length;
200
201 if (! pfs->m_stmt_lock.end_optimistic_lock(& stmt_lock))
202 {
203 /*
204 One of the columns:
205 - PROCESSLIST_DB
206 - PROCESSLIST_INFO
207 is being updated.
208 Do not discard the entire row.
209 Do not loop waiting for a stable value.
210 Just return NULL values.
211 */
212 m_row.m_dbname_length= 0;
213 m_row.m_processlist_info_length= 0;
214 }
215
216 /* Dirty read, sanitize the command. */
217 m_row.m_command= pfs->m_command;
218 if ((m_row.m_command < 0) || (m_row.m_command > COM_END))
219 m_row.m_command= COM_END;
220
221 m_row.m_start_time= pfs->m_start_time;
222
223 stage_class= find_stage_class(pfs->m_stage);
224 if (stage_class != NULL)
225 {
226 m_row.m_processlist_state_ptr= stage_class->m_name + stage_class->m_prefix_length;
227 m_row.m_processlist_state_length= stage_class->m_name_length - stage_class->m_prefix_length;
228 }
229 else
230 {
231 m_row.m_processlist_state_length= 0;
232 }
233
234 m_row.m_enabled_ptr= pfs->m_disable_instrumentation ? NULL : &pfs->m_enabled;
235
236 if (pfs->m_lock.end_optimistic_lock(& lock))
237 m_row_exists= true;
238
239 if(pfs->m_disable_instrumentation)
240 m_row_exists= false;
241 }
242
read_row_values(TABLE * table,unsigned char * buf,Field ** fields,bool read_all)243 int table_threads::read_row_values(TABLE *table,
244 unsigned char *buf,
245 Field **fields,
246 bool read_all)
247 {
248 Field *f;
249
250 if (unlikely(! m_row_exists))
251 return HA_ERR_RECORD_DELETED;
252
253 /* Set the null bits */
254 DBUG_ASSERT(table->s->null_bytes == 2);
255 buf[0]= 0;
256 buf[1]= 0;
257
258 for (; (f= *fields) ; fields++)
259 {
260 if (read_all || bitmap_is_set(table->read_set, f->field_index))
261 {
262 switch(f->field_index)
263 {
264 case 0: /* THREAD_ID */
265 set_field_ulonglong(f, m_row.m_thread_internal_id);
266 break;
267 case 1: /* NAME */
268 set_field_varchar_utf8(f, m_row.m_name, m_row.m_name_length);
269 break;
270 case 2: /* TYPE */
271 if (m_row.m_processlist_id != 0)
272 set_field_varchar_utf8(f, "FOREGROUND", 10);
273 else
274 set_field_varchar_utf8(f, "BACKGROUND", 10);
275 break;
276 case 3: /* PROCESSLIST_ID */
277 if (m_row.m_processlist_id != 0)
278 set_field_ulonglong(f, m_row.m_processlist_id);
279 else
280 f->set_null();
281 break;
282 case 4: /* PROCESSLIST_USER */
283 if (m_row.m_username_length > 0)
284 set_field_varchar_utf8(f, m_row.m_username,
285 m_row.m_username_length);
286 else
287 f->set_null();
288 break;
289 case 5: /* PROCESSLIST_HOST */
290 if (m_row.m_hostname_length > 0)
291 set_field_varchar_utf8(f, m_row.m_hostname,
292 m_row.m_hostname_length);
293 else
294 f->set_null();
295 break;
296 case 6: /* PROCESSLIST_DB */
297 if (m_row.m_dbname_length > 0)
298 set_field_varchar_utf8(f, m_row.m_dbname,
299 m_row.m_dbname_length);
300 else
301 f->set_null();
302 break;
303 case 7: /* PROCESSLIST_COMMAND */
304 if (m_row.m_processlist_id != 0)
305 set_field_varchar_utf8(f, command_name[m_row.m_command].str,
306 command_name[m_row.m_command].length);
307 else
308 f->set_null();
309 break;
310 case 8: /* PROCESSLIST_TIME */
311 if (m_row.m_start_time)
312 {
313 time_t now= my_time(0);
314 ulonglong elapsed= (now > m_row.m_start_time ? now - m_row.m_start_time : 0);
315 set_field_ulonglong(f, elapsed);
316 }
317 else
318 f->set_null();
319 break;
320 case 9: /* PROCESSLIST_STATE */
321 if (m_row.m_processlist_state_length > 0)
322 {
323 /* This column's datatype is declared as varchar(64). But in current
324 code, there are few process state messages which are greater than
325 64 characters(Eg:stage_slave_has_read_all_relay_log).
326 In those cases, we will end up in 'data truncated'
327 warning/error (depends sql_mode setting) when server is updating
328 this column for those threads. Since 5.6 is GAed, neither the
329 metadata of this column can be changed, nor those state messages.
330 So server will silently truncate the state message to 64 characters
331 if it is longer. In Upper versions(5.7+), these state messages are
332 changed to less than or equal to 64 characters.
333 */
334 set_field_varchar_utf8(f, m_row.m_processlist_state_ptr,
335 std::min<uint>(m_row.m_processlist_state_length,
336 f->char_length()));
337 }
338 else
339 f->set_null();
340 break;
341 case 10: /* PROCESSLIST_INFO */
342 if (m_row.m_processlist_info_length > 0)
343 set_field_longtext_utf8(f, m_row.m_processlist_info_ptr,
344 m_row.m_processlist_info_length);
345 else
346 f->set_null();
347 break;
348 case 11: /* PARENT_THREAD_ID */
349 if (m_row.m_parent_thread_internal_id != 0)
350 set_field_ulonglong(f, m_row.m_parent_thread_internal_id);
351 else
352 f->set_null();
353 break;
354 case 12: /* ROLE */
355 f->set_null();
356 break;
357 case 13: /* INSTRUMENTED */
358 set_field_enum(f, (m_row.m_enabled_ptr && *m_row.m_enabled_ptr)
359 ? ENUM_YES : ENUM_NO);
360 break;
361 default:
362 DBUG_ASSERT(false);
363 }
364 }
365 }
366 return 0;
367 }
368
update_row_values(TABLE * table,const unsigned char * old_buf,unsigned char * new_buf,Field ** fields)369 int table_threads::update_row_values(TABLE *table,
370 const unsigned char *old_buf,
371 unsigned char *new_buf,
372 Field **fields)
373 {
374 Field *f;
375 enum_yes_no value;
376
377 for (; (f= *fields) ; fields++)
378 {
379 if (bitmap_is_set(table->write_set, f->field_index))
380 {
381 switch(f->field_index)
382 {
383 case 0: /* THREAD_ID */
384 case 1: /* NAME */
385 case 2: /* TYPE */
386 case 3: /* PROCESSLIST_ID */
387 case 4: /* PROCESSLIST_USER */
388 case 5: /* PROCESSLIST_HOST */
389 case 6: /* PROCESSLIST_DB */
390 case 7: /* PROCESSLIST_COMMAND */
391 case 8: /* PROCESSLIST_TIME */
392 case 9: /* PROCESSLIST_STATE */
393 case 10: /* PROCESSLIST_INFO */
394 case 11: /* PARENT_THREAD_ID */
395 case 12: /* ROLE */
396 return HA_ERR_WRONG_COMMAND;
397 case 13: /* INSTRUMENTED */
398 if(m_row.m_enabled_ptr == NULL) {
399 return HA_ERR_WRONG_COMMAND;
400 }
401 value= (enum_yes_no) get_field_enum(f);
402 *m_row.m_enabled_ptr= (value == ENUM_YES) ? true : false;
403 break;
404 default:
405 DBUG_ASSERT(false);
406 }
407 }
408 }
409 return 0;
410 }
411
412