[转帖] MySQL:如何编写daemon plugin_MySQL, Oracle及数据库讨论区_Weblogic技术|Tuxedo技术|中间件技术|Oracle论坛|JAVA论坛|Linux/Unix技术|hadoop论坛_联动北方技术论坛  
网站首页 | 关于我们 | 服务中心 | 经验交流 | 公司荣誉 | 成功案例 | 合作伙伴 | 联系我们 |
联动北方-国内领先的云技术服务提供商
»  游客             当前位置:  论坛首页 »  自由讨论区 »  MySQL, Oracle及数据库讨论区 »
总帖数
1
每页帖数
101/1页1
返回列表
0
发起投票  发起投票 发新帖子
查看: 2325 | 回复: 0   主题: [转帖] MySQL:如何编写daemon plugin        下一篇 
shunzi
注册用户
等级:上尉
经验:782
发帖:133
精华:0
注册:2011-10-10
状态:离线
发送短消息息给shunzi 加好友    发送短消息息给shunzi 发消息
发表于: IP:您无权察看 2014-11-12 10:47:42 | [全部帖] [楼主帖] 楼主

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


结构体如下:

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


宏中参数描述如下:

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来定义:

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会自动给我们加上。

--转自 北京联动北方科技有限公司




赞(0)    操作        顶端 
总帖数
1
每页帖数
101/1页1
返回列表
发新帖子
请输入验证码: 点击刷新验证码
您需要登录后才可以回帖 登录 | 注册
技术讨论