Recently I had a need to determine the session value of a MySQL plugin variable in a core file. Here I use the word plugin variable to refer to MySQL system variables provided by plugins. While this is not a very difficult task, it is not as straight forward as printing a global variable. It took some time to figure out the layout of the plugin variables and get the needed information. This short article is to share this gdb tip with other interested MySQL developers and support engineers.
In this article, let us inspect the session value of the plugin variable innodb_strict_mode, which is of type boolean. Quite obviously, this plugin variable is provided by InnoDB storage engine.
The Quick Answer
This is what you can do to get the session value of the plugin variable innodb_strict_mode from the mysql server core file. For more details, refer to subsequent sections.
1 2 3 |
(gdb) p mysql_sysvar_strict_mode $80 = {flags = 8449, name = 0x3117de8 "innodb_strict_mode", comment = 0x163a800 "Use strict mode when evaluating create options.", check = 0xc6013c <check_func_bool(THD*, st_mysql_sys_var*, void*, st_mysql_value*)>, update = 0xc60bf9 <update_func_bool(THD*, st_mysql_sys_var*, void*, void const*)>, offset = 48, def_val = 0 '00', resolve = 0xc6189d <mysql_sys_var_char(THD*, int)>} (gdb) |
1 2 3 |
(gdb) x /tb (uchar *) trx->mysql_thd->variables.dynamic_variables_ptr + mysql_sysvar_strict_mode.offset 0x7f8b0400da80: 00000001 (gdb) |
According to the above output, innodb_strict_mode has been enabled.
MySQL System Variables
The global values of the MySQL system variables are available in the global object (refer to sql/mysqld.cc):
1 |
struct system_variables global_system_variables; |
Here we are interested in the session value of a system variable. So we will not make use of this global object. The session values of the MySQL system variables are available in the member variables of the THD object:
1 2 3 4 5 6 7 8 9 |
class THD :public MDL_context_owner, public Query_arena, public Open_tables_state { // ... public: struct system_variables variables; // ... }; |
There are two types of system variables — the system variables provided by the MySQL server, and the system variables provided by the plugins (also known as “plugin variables”). The system variables provided by the MySQL server will be proper members of the struct system_variables . But the plugin variables are kept opaque at the server layer. The plugin variables are dynamically allocated and are pointed to by the member dynamic_variables_ptr.
1 2 3 4 5 6 |
struct system_variables { // ... char* dynamic_variables_ptr; // ... }; |
All the session values of the plugin variables are available in this memory block. To access the session value of the plugin variables, we need to access it at a certain offset within the memory pointed to by THD::variables::dynamic_variables_ptr.
The memory for the session variables are allocated in the function alloc_and_copy_thd_dynamic_variables() , which is documented to “Allocate memory and copy dynamic variables from global system variables to per-thread system variables copy.”
Accessing Session Value of Plugin Variables
As mentioned in previous section, all session values of plugin variables are stored in a single block of memory. To access the session value of any particular plugin variable we need to know the offset within that block of memory. This information is provided by a global object for each plugin variable.
All MySQL plugin variables will need a global object pointing to their location. This global object is declared and defined using the macro MYSQL_THDVAR_BOOL , if the plugin variable is of type boolean. For plugin variables of different types, different macros are available. For the variable innodb_strict_mode this declaration is as follows:
1 2 3 |
static MYSQL_THDVAR_BOOL(strict_mode, PLUGIN_VAR_OPCMDARG, "Use strict mode when evaluating create options.", NULL, NULL, FALSE); |
This creates a global object of an anonymous struct type. There are a series of macros involved in expanding the above. All the related macros are given below for easy reference:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
define DECLARE_THDVAR_FUNC(type) \ type *(*resolve)(MYSQL_THD thd, int offset) #define MYSQL_SYSVAR_NAME(name) mysql_sysvar_ ## name #define MYSQL_SYSVAR(name) \ ((struct st_mysql_sys_var *)&(MYSQL_SYSVAR_NAME(name))) #define MYSQL_PLUGIN_VAR_HEADER \ int flags; \ const char *name; \ const char *comment; \ mysql_var_check_func check; \ mysql_var_update_func update #define DECLARE_MYSQL_THDVAR_BASIC(name, type) struct { \ MYSQL_PLUGIN_VAR_HEADER; \ int offset; \ const type def_val; \ DECLARE_THDVAR_FUNC(type); \ } MYSQL_SYSVAR_NAME(name) #define MYSQL_THDVAR_BOOL(name, opt, comment, check, update, def) \ DECLARE_MYSQL_THDVAR_BASIC(name, char) = { \ PLUGIN_VAR_BOOL | PLUGIN_VAR_THDLOCAL | ((opt) & PLUGIN_VAR_MASK), \ #name, comment, check, update, -1, def, NULL} |
When run through the pre-processor our declaration of “strict_mode” is expanded as follows:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
static struct { int flags; const char* name; const char* comment; mysql_var_check_func check; mysql_var_update_func update; int offset; const char def_val; char *(*resolve) (MYSQL_THD thd, int offset); } mysql_sysvar_strict_mode = { PLUGIN_VAR_BOOL | PLUGIN_VAR_THDLOCAL | ((PLUGIN_VAR_OPCMDARG) & PLUGIN_VAR_MASK), "strict_mode", "Use strict mode when evaluating create options.", NULL, NULL, -1, FALSE, NULL }; |
A global object of an anonymous struct type has been defined by the macro MYSQL_THDVAR_BOOL . As seen above, the offset is initialized to an invalid value of -1. The offset will be set to the correct value at process run time, when a plugin variable is registered with the server process (refer to register_var() ). Using this offset we can access the session value of the plugin variable. If you look at the Quick Answer section now, it might be more clear.
1 2 3 |
(gdb) x /tb (uchar *) trx->mysql_thd->variables.dynamic_variables_ptr + mysql_sysvar_strict_mode.offset 0x7f8b0400da80: 00000001 (gdb) |
If we want to inspect the session value of another plugin variable innodb_optimize_point_storage then the following gdb command can be used:
1 2 3 |
(gdb) x /tb (uchar *) trx->mysql_thd->variables.dynamic_variables_ptr + mysql_sysvar_optimize_point_storage.offset 0x7f8b0400da84: 00000000 (gdb) |
The above output indicates that innodb_optimize_point_storage is disabled. I’ll leave it as an exercise for the reader to inspect innodb_support_xa.
The THDVAR macro
The previous sections explained the layout of the plugin variables and provided information to access their session value manually through a debugger like gdb. If you are a MySQL developer and writing code, then you need to make use of the THDVAR() macro to access a session value of the plugin variable. To access innodb_strict_mode value, one will use code as follows:
1 2 3 4 5 6 7 8 9 10 |
/**********************************************************************//** Determines if the currently running transaction is in strict mode. @return TRUE if strict */ ibool trx_is_strict( /*==========*/ trx_t* trx) /*!< in: transaction */ { return(trx && trx->mysql_thd && THDVAR(trx->mysql_thd, strict_mode)); } |
Conclusion
This article provided information to help in quickly identifying the session value of a plugin variable within a mysqld core file. It also provided some details regarding the layout of the plugin variables and the macros to use when you declare, define, and access them. Comments and feedback are always welcome. Thank you for using MySQL!