MYSQL DAEMON PLUGIN EXAMPLE

5.1 版本开始MySQL开始支持plugin API,允许在mysqld运行时载入或者卸载组件,而不需要重启mysqld。

plugin API涵盖了UDF、full-text、advanced schema等功能,其中的daemon plugin个人认为是非常的有用。其功能是在plugin载入后可以创建额外的后台线程于mysqld主线程一同协同工作。

plugin API的具体实现在sql/sql_plugin.h 和sql/sql_plugin.cc两个文件中。载入plugin使用dl_open系的动态加载共享库的方法打开so文件,获得需要执行的加载函数和卸载函数的指针。daemon plugin 的启动和storage plugin 启动一样,由init_server_components(sql/mysqld.cc) 里的plugin_init函数来启动。

开发的plugin的时候,只需要关心API接口文件include/plugin.h(我把mysql安装在/usr/local/mysql,所以这个文件在/usr/local/mysql/include/mysql/plugin.h),里面可以看到一些API函数和宏。

plugin的几个相关命令

show plugins 可查询系统内所有的激活的plugin,也包括storage plugin。

mysql>show plugins;
+------------+--------+----------------+--------------+---------+
| Name       | Status | Type           | Library      | License |
+------------+--------+----------------+--------------+---------+
| binlog     | ACTIVE | STORAGE ENGINE | NULL         | GPL     |
| CSV        | ACTIVE | STORAGE ENGINE | NULL         | GPL     |
| MEMORY     | ACTIVE | STORAGE ENGINE | NULL         | GPL     |
| InnoDB     | ACTIVE | STORAGE ENGINE | NULL         | GPL     |
| MyISAM     | ACTIVE | STORAGE ENGINE | NULL         | GPL     |
| MRG_MYISAM | ACTIVE | STORAGE ENGINE | NULL         | GPL     |
+------------+--------+----------------+--------------+---------+

mysql.plugin 表也可以获得目前的plugin,但不包括storage plugin,加载错误的plugin也会包含在内,例如so不存在。

plugin_dir参数用于告知系统plugin的目录,这个参数必须在mysqld启动前指定,如果不设置,默认目录为/usr/local/mysql/lib/mysql/plugin/(/usr/local/mysql是我的MySQL安装目录)。

1
2
3
4
5
6
mysql> show variables like 'plugin_dir';
+---------------+-------------------------+
| Variable_name | Value                   |
+---------------+-------------------------+
| plugin_dir    | /usr/local/mysql/plugin |
+---------------+------------------------

加载plugin

1
mysql>INSTALL PLUGIN plugin_name SONAME 'plugin_library'

这里的plugin_name后面会讲到,plugin_library即为要加载的共享库so文件的名字,目录必须是上面的plugin_dir。

加载插件后,通过前面的show plugins、mysql.plugin 可以看到你的plugin。

卸载plugin

1
mysql>UNINSTALL PLUGIN plugin_name

编写plugin

plugin模式的软件领域分明是oop继承、重载的用武之地,MySQL却使用了预编译宏和函数指针不是那么优雅的完成了这个任务(个人很喜欢这种方法,虽然代码丑陋了点)。另外说几句MySQL虽然看起来是c++写的,但实际上较少的使用c++的一些特性,只在内部几个模块用到模板类。跑题了,开始写plugin。

下面编写一个plugin,作用是加载后创建一个线程在后台持续的把MySQL内的一些信息打印到err.log日志。

首先介绍一下include/plugin.h里的st_mysql_plugin这个结构体,所有的plugin 都必须是基于这个结构体,填充必须的内容。

struct st_mysql_plugin
{
    int type;                    /* 插件类型,这里填MYSQL_DAEMON_PLUGIN 即可 */
    void *info;                 /* 插件类型描述符,对于daemon类来说没用,指向一个常量即可   */
    const char *name;          /* 插件名,这个就是前面的install 命令里的plugin_name  */
    const char *author;       /* 插件作者,随意 */
    const char *descr;        /* 插件描述,随意  */
    int license;                /* PLUGIN_LICENSE_GPL */
    int (*init)(void);           /* install 命令之后调用的函数 */
    int (*deinit)(void);       /* uninstall 命令之后调用的函数 */
    unsigned int version;     /* 插件版本,随意*/
    struct st_mysql_show_var   /* 指向的show_var,可不填*/
    struct st_mysql_sys_var     /* 指向的sys_var,可不填*/
    void * __reserved1;        /* 不填*/
};

声明plugin需要使用2个预编译宏,你可以在include/plugin.h 查看mysql_declare_plugin,mysql_declare_plugin_end两个宏的具体内容。

struct st_mysql_daemon monitor_plugin =
{
    MYSQL_DAEMON_INTERFACE_VERSION
};

mysql_declare_plugin(monitor_plugin)
{
    MYSQL_DAEMON_PLUGIN,
    &monitor_plugin,
    "monitor",
    "hoterran",
    "test",
    PLUGIN_LICENSE_GPL,
    monitor_plugin_init,
    monitor_plugin_deinit,
    0x0100,
    NULL,
    NULL,
    NULL,
}
mysql_declare_plugin_end;

结构体中的monitor_plugin_init和monitor_plugin_deinit就是接下来要编写的加载和卸载对应的函数。

下面是全部代码monitor.c

#include <string.h>
#include <unistd.h>
#include <stdio.h>
#include <plugin.h>
#include <mysql_version.h>
#include <my_global.h>
#include <my_sys.h>
#include <pthread.h>

extern ulong		thread_id;
extern uint		thread_count;
extern ulong		max_connections;

static pthread_t	G_thread;

pthread_handler_t func(void *p)
{
    while(1) {
         sleep(5);
         fprintf(stderr, "Thread id [%ld] Thread_count: %u Max_connections:%lu\n",
             thread_id, thread_count, max_connections);
         }
}

static int monitor_plugin_init(void *p)
{
    if (pthread_create(&amp;G_thread, NULL, func, NULL) != 0) {
        fprintf(stderr, "Monitor plugin init failure");
        return 1;
    }

    fprintf(stderr, "%s", "Monitor plugin init\n");
    return 0;
}

static int monitor_plugin_deinit(void *p)
{
    pthread_cancel(G_thread);
    pthread_join(G_thread, NULL);
    fprintf(stderr, "%s", "Monitor_plugin deinit\n");

    return 0;
}

struct st_mysql_daemon monitor_plugin =
{
    MYSQL_DAEMON_INTERFACE_VERSION
};

mysql_declare_plugin(monitor_plugin)
{
    MYSQL_DAEMON_PLUGIN,
    &monitor_plugin,
    "monitor",
    "hoterran",
    "test",
    PLUGIN_LICENSE_GPL,
    monitor_plugin_init,
    monitor_plugin_deinit,
    0x0100,
    NULL,
    NULL,
    NULL,
}
mysql_declare_plugin_end;

编译

1
2
3
gcc -g -Wall -I/usr/local/mysql/include/mysql -DMYSQL_DYNAMIC_PLUGIN   -c -o monitor.o monitor.c
gcc -shared -o libmonitor.so monitor.o
sudo cp libmonitor.so /usr/local/mysql/plugin/

加载

1
2
mysql&gt;install plugin monitor soname 'libmonitor.so';
Query OK, 0 rows affected (0.01 sec)

观察日志可以看到具体的输出。

1
2
3
4
5
6
7
8
....
[New Thread 0xb4296b70 (LWP 3895)]
[New Thread 0xb1e34b70 (LWP 4042)]
Monitor plugin init
Thread id [2] Thread_count: 1 Max_connections:151
Thread id [2] Thread_count: 1 Max_connections:151
Thread id [2] Thread_count: 1 Max_connections:151
....
1
2
3
4
5
6
7
8
9
10
11
12
13
14
mysql&gt;show plugins;
+------------+--------+----------------+---------------+---------+
| Name       | Status | Type           | Library       | License |
+------------+--------+----------------+---------------+---------+
| monitor    | ACTIVE | DAEMON         | libmonitor.so | GPL     |
+------------+--------+----------------+---------------+---------+
 
mysql&gt; select * from mysql.plugin;
+------------+---------------+
| name       | dl            |
+------------+---------------+
....
| monitor    | libmonitor.so |
+------------+---------------+

好了,插件的编写工作就完成了,够简单吧。

在MySQL的附带demo里有个heartbeat的例子,MySQL的ref里面也有另外一个full-text的例子。

 

如何使用daemon plugin ,时还没想好,淘宝的同事 @ningoo有把zookeeper client 作为deamon plugin 想法。

 

觉得文章有用?立即: 和朋友一起 共学习 共进步!

猜您喜欢

发表评论

电子邮件地址不会被公开。 必填项已用 * 标注

*

您可以使用这些 HTML 标签和属性: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>