"I had highlighted Global_THD_manager singleton also as during my next gdb sessions I had found out that simple global list of threads is also gone and in 5.7 everything is done via that Global_THD_manager. This is a topic for some other post, though."In that post and many times later when I had to deal with MySQL 5.7+ I just checked OS threads one by one in gdb using thread 1 ... thread N commands. This is not efficient at best, as I also hit numerous background threads that I often do not care about. So, a couple of weeks ago I finally decided to get back to this topic and find out how to check just user threads one by one in recent MySQL versions. I had a nice hint by Shane Bester on how to get information about $i-th thread (that he shared in one of his comments to my Facebook post):
set $value = (THD**)(Global_THD_manager::thd_manager->thd_list.m_buff.data + (sizeof(THD**) * $i))I've attached gdb to an instance of Percona Server 5.7.x that I had running in my CentOS 6.9 VM and tried few commands to check types and content of the Global_THD_manager elements:
(gdb) p Global_THD_manager::thd_managerSo, we see that internally there is some array of elements thd_list with m_size items (2 in my case) probably stored in some pre-allocated buffer of m_capacity (500) elements, stored in m_buff.data. The type of elements is not clear, but we can try Shane's hint and assume that they are of type THD**. Let's try to check what we see there after type castings:
$1 = (Global_THD_manager *) 0x7fab087fd000
(gdb) p Global_THD_manager::thd_manager->thd_list
$2 = {m_size = 2, m_capacity = 500, m_buff = {{
data = "\000\060b\344\252\177\000\000\000\220i\344\252\177\000\000\000\200x\344\252\177", '\000' <repeats 3977 times>, align = {<No data fields>}}},
m_array_ptr = 0x7fab087fd010, m_psi_key = 0}
(gdb) p (THD**)(Global_THD_manager::thd_manager->thd_list.m_buff.data)So, we get reasonable addresses and when we dereference the resulting THD** pointer twice we indeed get a structure that looks like THD of MySQL 5.7+ (it's very different, say, in MariaDB 10.1.x), with reasonable content (that is huge and skipped above).
$4 = (THD **) 0x7fab087fd010
(gdb) p *(THD**)(Global_THD_manager::thd_manager->thd_list.m_buff.data)
$5 = (THD *) 0x7faae4623000
(gdb) p **(THD**)(Global_THD_manager::thd_manager->thd_list.m_buff.data)
$6 = {<MDL_context_owner> = {
_vptr.MDL_context_owner = 0x1c51f50}, <Query_arena> = {
...
I've tried to get processlist id of thread based on findings of that post using intermediate gdb variables:
(gdb) set $ppthd = (THD**)(Global_THD_manager::thd_manager->thd_list.m_buff.data)and then directly, using offsets and checking for security contexts of threads:
(gdb) p *($ppthd)
$7 = (THD *) 0x7faae4623000
...
(gdb) set $pthd = *($ppthd)
(gdb) p $pthd->m_thread_id
$10 = 5
(gdb) p (**(THD**)(Global_THD_manager::thd_manager->thd_list.m_buff.data)).m_main_security_ctx.m_userto confirm that I correctly get user names and thread ids for both 2 user threads I had in that "list". As usual Shane Bester was right!
$14 = {m_ptr = 0x7faae463b060 "myuser", m_length = 6, m_charset = 0x1d21760,
m_alloced_length = 8, m_is_alloced = true}
(gdb) p (**(THD**)(Global_THD_manager::thd_manager->thd_list.m_buff.data + (sizeof(THD**)))).m_main_security_ctx.m_user
$15 = {m_ptr = 0x7faae46b1090 "root", m_length = 4, m_charset = 0x1d21760,
m_alloced_length = 8, m_is_alloced = true}
(gdb) p (**(THD**)(Global_THD_manager::thd_manager->thd_list.m_buff.data + (sizeof(THD**)))).m_thread_id
$16 = 9
Now, if you want to get more details about Global_THD_manager, you can just check the sql/mysqld_thd_manager.h file. I was interested mostly in the following:
int get_num_thread_running() const { return num_thread_running; }First of all, how consistent it is to use both int and uint data types for values that are always >=0... The fact that our thd_list elements is actually some template-based container, Prealloced_array, it also interesting, as it would be useful to find out how it is implemented. We can find all relevant details in the include/prealloced_array.h file. I'd like to highlight the following here:
uint get_thd_count() const { return global_thd_count; }
static Global_THD_manager *thd_manager;
// Array of current THDs. Protected by LOCK_thd_list.
typedef Prealloced_array<THD*, 500, true> THD_array;
THD_array thd_list;
// Array of thread ID in current use. Protected by LOCK_thread_ids.
typedef Prealloced_array<my_thread_id, 1000, true> Thread_id_array;
Thread_id_array thread_ids;
"The interface is chosen to be similar to std::vector."To summarize, MySQL 5.7+ uses more C++ now, with templates, singletons, iterators and more, but still Oracle prefers to implement their own container types instead of using some standard ones. One of these generic types, Prealloced_array, is widely used and is easy to deal with in gdb, as long as you know the element type.
...
private:
size_t m_size;
size_t m_capacity;
// This buffer must be properly aligned.
my_aligned_storage<Prealloc * sizeof(Element_type), MY_ALIGNOF(double)>m_buff;
Element_type *m_array_ptr;
No comments:
Post a Comment