您好,欢迎来到三六零分类信息网!老站,搜索引擎当天收录,欢迎发信息

MySQL:如何编写daemon plugin_MySQL

2024/2/26 0:39:57发布25次查看
bitscn.com
1.什么是daemonplugin
顾名思义,daemon plugin就是一种用来在后台运行的插件,在插件中,我们可以创建一些后台线程来做些有趣的事情。大名鼎鼎的handlesocket就是一个daemon plugin。而在mysql5.6中,也是通过daemon plugin来实现了memcached功能。
2.为什么使用daemonplugin
就像handlersocket,大胆的想象力能够创造无限的可能。mysql plugin的诱人之处在于其与mysqld处于同一进程空间中,可以利用任何mysql内核的函数。handlersocket在实现时,构造出相关参数并直接调用存储引擎的接口,从而穿越了语法解析和优化部分,对于逻辑简单的查询而言,可以极大的提高效率。
另外所有的plugin都提供了showstatus和show variables 命令的接口,因此我们可以利用plugin来显示一些我们想要的信息,例如mysql内部的全局变量值。
总的来说,daemon plugin可以做到以下几点:
1) 创建后台线程,扩展mysql功能
2)扩展status和variables信息
deamon plugin在mysqld启动时进行初始化,执行完init函数, 因此并不适用于与服务器进行通信的情形,mysql也没有提供任何相关的api
3.如何编写daemonplugin
这里涉及到的一些结构体,对其他类型的plugin而言也是通用的
1)st_mysql_plugin
无论声明哪种plugin,至少要包含该结构体
字段
类型
描述
type
int
用于描述plugin的类型,随着版本更新,越来越多,在5.5中包含8种类型:
mysql_udf_plugin
mysql_storage_engine_plugin
mysql_ftparser_plugin
mysql_daemon_plugin
mysql_information_schema_plugin
mysql_audit_plugin
mysql_replication_plugin
mysql_authentication_plugin
info
void*
用于指向特定的plugin描述符结构体,在daemon plugin中结构体为st_mysql_daemon,一般第一个字段都是插件接口的版本号
name
const char*
plugin的名字,需要和安装时的名字一致
author
const char*
plugin的作者信息,会在i_s.plugins表中显示
descry
const char*
描述插件
license
ubt
插件许可证:plugin_license_proprietary
plugin_license_gpl
plugin_license_bsd
init
int (*init)(void *)
当插件被加载时或者mysqld重启时会执行该函数,一般我们会在这里创建好后台线程
deinit
int (*deinit)(void *);
当插件被卸载时做的工作,例如取消线程,清理内存等
version
unsigned int
plugin的版本信息
status_vars
st_mysql_show_var*
描述在执行show status时显示的信息
system_vars
st_mysql_sys_var **
描述在执行show variables显示的信息
__reserved1
void*
注释说为检查依赖而保留,不太明白,直接设为null即可
flags
unsigned long
5.5之后增加的字段,plugin的flag:0、
plugin_opt_no_install(不可动态加载)、plugin_opt_no_uninstall(不可动态加载)
在plugin.h里提供了宏,我们可以通过宏来声明插件:
mysql_declare_plugin(my_plugin)
{},
{},
……
mysql_declare_plugin_end;
在两个宏之间,我们可以声明多个插件,也就是说在一个文件里,我们可以定义多个plugin。
上面提到三个结构体,需要在plugin里单独进行定义:
a. st_mysql_daemon
该结构体只包含一个字段,用于声明daemon plugin的版本信息
字段
类型
描述
interface_version
int
一般值为
mysql_daemon_interface_version
也许有同学注意到了,这上面提到了两个version,即st_mysql_plugin里的version和st_mysql_daemon里的version,这两者是不相同的。
st_mysql_plugin.version记录的是该plugin的版本号,使用16进制表示,低8位存储副版本号,其他存储主版本号。
而st_mysql_daemon里存储的是daemonplugin接口的版本号,针对不同的mysql版本,其接口可能会发生变化。
b. st_mysql_show_var
结构体如下:
字段
类型
描述
name
const char*
字段名
value
char*
字段值,我们可以将指针绑定到一个全局变量上
type
enum enum_mysql_show_type
数据类型,包括(括号里对应value的指针类型):
show_bool (bool *)
show_int   (unsigned int *)
show_long (long *)
show_longlong (long long*)
show_double (double *)
show_char   (char *)
show_char_ptr (char **)
show_array(st_mysql_show_var * )
show_func(
int (*)(mysql_thd, struct st_mysql_show_var*, char *) )
该结构体用于定义show status时显示的值,可以看出在type字段最后两个相对其他比较特殊。
当type类型为show_array时,表明name字段并不是一个值,而是指向一个st_mysql_show_var类型的数组,数组以{0,0,0}结束,当前元素的name会成为引用数组元素name的前缀。
当type类型为show_func时,value值为一个函数指针,参数包括当前线程的thd,st_mysql_show_var* 以及一个大小为1024字节的内存区域头指针;函数的目的是为了填充第二个字段的值,而buf作为存储构建结构体的内存空间;这样可以允许我们先做一些计算,然后显示计算的结果。
c. st_mysql_sys_var
该结构体内包含一个宏mysql_plugin_var_header,包含了变量结构体的公共部分。
在这里,mysql巧妙的使用了c的宏定义,例如,当我们定义一个variable:
struct st_mysql_sys_var* my_sysvars[]= {
mysql_sysvar(my_var),
null}
展开mysql_sysvar看看:
#define mysql_sysvar_name(name)mysql_sysvar_ ## name
#define mysql_sysvar(name) /
 ((struct st_mysql_sys_var *)&(mysql_sysvar_name(name)))
那么mysql_sysvar(my_var)被转换为:
((struct st_mysql_sys_var *)mysql_sysvar_my_var
因此,在这之前,我们首先要先创建好结构体。针对不同的数据类型,提供了许多宏来创建,分为两种:一种以mysql_sysvar开头的全局变量(可以set global),另外一种是mysql_thdvar开头的session变量
mysql_sysvar_bool(name, varname, opt, comment, check, update, def)
char
mysql_sysvar_str(name, varname, opt, comment, check, update, def)
char*
mysql_sysvar_int(name, varname, opt, comment, check, update, def, min, max, blk)
int
mysql_sysvar_uint(name, varname, opt, comment, check, update, def, min, max, blk)
unsigned int
mysql_sysvar_long(name, varname, opt, comment, check, update, def, min, max, blk)
long
mysql_sysvar_ulong(name, varname, opt, comment, check, update, def, min, max, blk)
unsigned long
mysql_sysvar_longlong(name, varname, opt, comment, check, update, def, min, max, blk)
long long
mysql_sysvar_ulonglong(name, varname, opt, comment, check, update, def, min, max, blk)
unsigned long long
mysql_sysvar_enum(name, varname, opt, comment, check, update, def, typelib)
unsigned long
mysql_sysvar_set(name, varname, opt, comment, check, update, def, typelib)
unsigned long long
以下是session变量定义宏
mysql_thdvar_bool(name, opt, comment, check, update, def)
char
mysql_thdvar_str(name, opt, comment, check, update, def)
char*
mysql_thdvar_int(name, opt, comment, check, update, def, min, max, blk)
int
mysql_thdvar_uint(name, opt, comment, check, update, def, min, max, blk)
unsigned int
mysql_thdvar_long(name, opt, comment, check, update, def, min, max, blk)
long
mysql_thdvar_ulong(name, opt, comment, check, update, def, min, max, blk)
unsigned long
mysql_thdvar_longlong(name, opt, comment, check, update, def, min, max, blk)
long long
mysql_thdvar_ulonglong(name, opt, comment, check, update, def, min, max, blk)
unsigned long long
mysql_thdvar_enum(name, opt, comment, check, update, def, typelib)
unsigned long
mysql_thdvar_set(name, opt, comment, check, update, def, typelib)
unsigned long long
宏中参数描述如下:
参数名
描述
name
变量名,通过show variables显示的变量名,
varname
c/c++变量,用来给name赋值
opt
变量选项:
plugin_var_readonly (变量只读)
plugin_var_nosysvar (不是系统变量,只能在启动时命令行加上)
plugin_var_nocmdopt (与上述相反)
plugin_var_nocmdarg (命令行,必须没有参数)
plugin_var_rqcmdarg (命令行,不需有参数)
plugin_var_opcmdarg (命令行,参数可选)
plugin_var_memalloc (如果被设置,会分配内存存储字符串的值,否则只能通过命令行来分配)
comment
变量的描述信息
check
函数指针,用来检查参数是否有效,如果无效,则拒绝修改,函数原型为:
int check(mysql_thd thd, struct st_mysql_sys_var *var, void *save, struct st_mysql_value *value);
其中thd为当前线程,var是我们定义的系统变量,save指针用来存储数据,value是传递给函数的值,我们可以从value中获取值,并将其保存到save中。
update
函数指针,当发生更新时,可以调用该函数做一些额外处理,函数原型为:
void update(mysql_thd thd, struct st_mysql_sys_var *var, void *var_ptr, const void *save);
def
变量的默认值
min
最小值 (min及以下两个需要为数值类型)
max
最大值
blk
块大小,变量值需要是blk的整数倍
typelib
当变量类型为enum和set类型时,使用该结构体定义:st_typelib
在check函数里,我们从var中提取出新的值,并存储到save指针中。在update函数中,我们可以从save指针提取出新值,st_mysql_value正是用于提取新值的结构体,成员为函数指针,如下:
函数指针
描述
int (*value_type)(struct st_mysql_value *)
用于获取值的类型:
mysql_value_type_string 0
mysql_value_type_real   1
mysql_value_type_int    2
const char *(*val_str)(struct st_mysql_value *, char *buffer, int *length);
获取字符串
int (*val_int)(struct st_mysql_value *, long long *intbuf);
获取整数
例如:
int a ;
var->val_int(var, &a);
一些系统变量允许为set或者enum类型,这时候,需要通过额外的结构体st_typelib来定义:
字段
类型
描述
count
unsigned int
type_names里的元素个数
name
const char*
plugin无需设置
type_names
const char**
存储集合内的元素值
type_lengths
unsigned int*
plugin无需设置
举个简单的例子,比如我们想定义一个int变量,该变量为只读类型,即不允许通过set命令修改,最大为1000000,最小为0 ,默认值为 256:
static int xx
static mysql_sysvar_int(xx_var, xx , plugin_var_readonly , “a read onlyint var”, null, null,256, 0, 1000000, 10)
例如,如果plugin的名字为name,则变量的全名为name_xx_var。我们可以将系统变量通过命令行来赋值,也可以写在配置文件中,变量名为name-xx-var,赋值必须能被10整除,否则将被mysql拒绝。
定义一个枚举类型,session变量
static const char *mode_names[] = {
normal, turbo,super, hyper, mega
};
static typelib modes = { 5, null,mode_names, null };
static mysql_thdvar_enum(mode,plugin_var_nocmdopt,
one of normal, turbo, super, hyper,mega,
null, null, 0, &modes);
该变量属于枚举类型,每个session拥有自己的值,并且可在运行时修改;注意,当为session变量时,我们需要通过thdvar(thd,mode)这样一个宏来获取相应的变量值
另外,对于plugin中的系统变量无需加互斥锁,mysql会自动给我们加上。
实例:启动一个后台线程,每隔5秒监控当前进程的状态(记录到log中),使用系统变量来控制是否记录log,并在show status显示记录的次数
#include  
#include  
#include 
#include  
#include  
#include 
#include
#define monitoring_buffer1024
/*以下三个变量在sql/mysqld.cc中声明,因此需要extern*/ 
extern ulong thread_id;  //当前最大线程id 
extern uint thread_count;  //当前线程数 
extern ulong max_connections;//最大允许连接数
static pthread_tmonitoring_thread; //线程id 
static int monitoring_file;         //日志文件fd
static my_bool monitor_state= 1;   //为1表示记录日志,为0则否 
static ulong monitor_num     = 0;   //后台线程循环次数 
static struct rusage usage;
/*创建系统变量,可以通过配置文件或set global来修改*/ 
mysql_sysvar_bool(monitors_state,monitor_state, 
              plugin_var_opcmdarg, 
              disable monitor  if 0,default true, 
              null, null, true);
struct st_mysql_sys_var*vars_system_var[] = { 
        mysql_sysvar(monitors_state), 
            null 
};
/*创建status变量,可通过showstatus查看*/ 
static structst_mysql_show_var sys_status_var[] = 

    {monitor_num, (char *)&monitor_num, show_long}, 
    {0, 0, 0} 
};
/*线程函数,后台线程启动后,会持续执行该函数*/ 
pthread_handler_tmonitoring(void *p) 

    char buffer[monitoring_buffer]; 
    char time_str[20];
while(1) {
/*每隔5秒记录一次,我们也可以把5修改为一个可配置的系统变量*/ 
        sleep(5);
if (!monitor_state) 
            continue;
monitor_num++; 
/*获取当前时间,mysql自有函数*/ 
        get_date(time_str, getdate_date_time,0); 
        snprintf(buffer, monitoring_buffer,%s: %u of %lu clients connected,  
                %lu connections made/n, 
                time_str, thread_count, 
                max_connections, thread_id);
/*使用getrusage函数来获得当前进程的运行状态,具体man getrusage*/ 
        if (getrusage(rusage_self, &usage)== 0){ 
            snprintf(buffer+strlen(buffer) , 
monitoring_buffer, user time:%d,system time:%d, 
                                                maxrss:%d,ixrss:%d,idrss:%d, 
                                                isrss:%d, minflt:%d, majflt:%d, 
                                       &nbs
该用户其它信息

VIP推荐

免费发布信息,免费发布B2B信息网站平台 - 三六零分类信息网 沪ICP备09012988号-2
企业名录 Product