mysql源码学习笔记:插件的安装和卸载

版本

CentOS release 6.7环境下mysql-5.7.16 社区版

概述

mysql支持插件的开发,以插件的方式实现mysql的附加功能,既可以减少对mysql服务器源码的入侵,也可以实现动态的插拔。可以较好的实现我们需要的功能。

mysql维护一套插件框架来保证所有插件可以有效的运行,源码分析如下。

源码分析

插件的种类

当前在使用的插件共11种,在plugin.h中以宏的方式定义。其中MYSQL_MAX_PLUGIN_TYPE_NUM为插件的数量。

#define MYSQL_UDF_PLUGIN             0  /* User-defined function        */
#define MYSQL_STORAGE_ENGINE_PLUGIN  1  /* Storage Engine               */
#define MYSQL_FTPARSER_PLUGIN        2  /* Full-text parser plugin      */
#define MYSQL_DAEMON_PLUGIN          3  /* The daemon/raw plugin type */
#define MYSQL_INFORMATION_SCHEMA_PLUGIN  4  /* The I_S plugin type */
#define MYSQL_AUDIT_PLUGIN           5  /* The Audit plugin type        */
#define MYSQL_REPLICATION_PLUGIN     6  /* The replication plugin type */
#define MYSQL_AUTHENTICATION_PLUGIN  7  /* The authentication plugin type */
#define MYSQL_VALIDATE_PASSWORD_PLUGIN  8   /* validate password plugin type */
#define MYSQL_GROUP_REPLICATION_PLUGIN  9  /* The Group Replication plugin */
#define MYSQL_KEYRING_PLUGIN         10  /* The Keyring plugin type   */
#define MYSQL_MAX_PLUGIN_TYPE_NUM    11  /* The number of plugin types   */

MySQL启动时插件初始化

...
init_server_components
   // 插件初始化以配置文件、命令行输入的变量设置为输入参数
   // 根据配置决定是否添加未装载的插件
| plugin_init(&remaining_argc, remaining_argv
    // 初始化打开插件so的句柄数组
    plugin_dl_array= new (std::nothrow) Prealloced_array<st_plugin_dl* ...
    // 初始化插件定义结构体的动态数组
    plugin_array= new (std::nothrow)  Prealloced_array<st_plugin_int* ....
    // 为每一种插件,初始化一个hash桶,用于存放该种类的插件
    for (i= 0; i < MYSQL_MAX_PLUGIN_TYPE_NUM; i++)
        if (my_hash_init(&plugin_hash[i], system_charset_info, 16, 0, 0,
    // 装载静态插件,见后续描述
    for (builtins= mysql_mandatory_plugins; *builtins || mandatory; builtins++)    
        ......
    // 装载动态插件,见后续描述
    while (NULL != (item= iter++))
        ......

装载静态插件

for (builtins= mysql_mandatory_plugins; *builtins || mandatory; builtins++)
{
    tmp.plugin= plugin;                                //定义插件结构体
    ....
    ....
    // 装载插件的系统变量
   if (test_plugin_options(&tmp_root, &tmp, argc, argv))
        | if (mysql_add_sys_var_chain(chain.first))          
   if (register_builtin(plugin, &tmp, &plugin_ptr))
        | if (plugin_array->push_back(tmp))                          // 将插件定义结构体,存入plugin_array中
        | if (my_hash_insert(&plugin_hash[plugin->type],(uchar*) *ptr))             //根据插件类型,将差价定义结构体,放入hash桶中       
   if(...plugin_initialize(plugin_ptr))
          // 调用插件自定义的初始化函数
        | plugin->plugin->init(plugin)
          // 如果插件有状态变量,将状态变量加入到全局链表中
        | if (add_status_vars(plugin->plugin->status_vars))
  }

mysql_mandatory_plugins为编译时生成,存放binlog、password、innodb等插件的插件定义结构体,定义如下

struct st_mysql_plugin *mysql_mandatory_plugins[]=
{
   builtin_binlog_plugin, builtin_mysql_password_plugin,   builtin_innobase_plugin,   
   builtin_csv_plugin,  builtin_heap_plugin,  builtin_myisammrg_plugin,  builtin_myisam_plugin,
   builtin_perfschema_plugin,
   0
};

装载动态插件

在装载静态插件之前,会优先装在系统变量early-plugin-load 声明的插件

 I_List_iterator<i_string> iter(opt_early_plugin_load_list);
 while (NULL != (item= iter++))
    plugin_load_list(&tmp_root, argc, argv, item->ptr);

装载静态插件之后,装载系统变量plugin-load和plugin-load-add声明的插件

I_List_iterator<i_string> iter(opt_plugin_load_list);             //系统变量
while (NULL != (item= iter++))
  plugin_load_list(&tmp_root, argc, argv, item->ptr);
    |while (list)               // 装载插件链表
    |plugin_dl_add(&dl, REPORT_TO_LOG)))                    
        // 动态的加载插件的so文件   
        // dl为插件的so名字,dlpath为的so全路径 
        plugin_dl.handle= dlopen(dlpath, RTLD_NOW)))    
        // plugin_interface_version_sym为字符串_mysql_plugin_interface_version_
        //  plugin_declarations_sym为字符串"_mysql_plugin_declarations_"      
        //  sizeof_st_plugin_sym为字符串"_mysql_sizeof_struct_st_plugin_"
        // 在dlopen插件的so后,读取固定的变量名来获取插件的相关信息
        if (!(sym= dlsym(plugin_dl.handle, plugin_interface_version_sym)))           // 读取版本变量
        if (!(sym= dlsym(plugin_dl.handle, plugin_declarations_sym)))                 //  读取
        if ((sym= dlsym(plugin_dl.handle, sizeof_st_plugin_sym)))
        // 将动态库的句柄保存到全局变量plugin_dl_array中
        plugin_dl_insert_or_reuse(&plugin_dl)
           |if (plugin_dl_array->push_back(plugin_dl))

    // 根据so中读取信息,装载插件   
    |plugin_add(tmp_root, &name, &dl, argc, argv, REPORT_TO_LOG))
        // 装载流程同装载静态插件流程相同
        for (builtins= mysql_mandatory_plugins; *builtins || mandatory; builtins++)
            tmp.plugin= plugin;                                //定义插件结构体
            ....
            ....
            if (test_plugin_options(&tmp_root, &tmp, argc, argv))
            if (register_builtin(plugin, &tmp, &plugin_ptr))
            if(...plugin_initialize(plugin_ptr))

命令行安装和卸载插件

使用命令行命令安装插件,插件的具体装载流程同启动时装载大体相同

......
mysql_execute_command
| case SQLCOM_INSTALL_PLUGIN:
| Sql_cmd_install_plugin::execute
    mysql_install_plugin
      // 初始化mysql.plugin表,为后续加入记录做准备
    | tables.init_one_table("mysql", 5, "plugin", 6, "plugin", TL_WRITE);
    | if (! (table = open_ltable(thd, &tables, TL_WRITE, ......
      // 这里调用相同的接口来装载插件
    | plugin_add(thd->mem_root, name, dl, &argc, argv, REPORT_TO_USER);
    | (plugin_initialize(tmp)
      // 在mysql.plugin表中增加一条记录
    | table->use_all_columns();
    | restore_record(table, s->default_values);
      ......
    | error= table->file->ha_write_row(table->record[0]);

命令行插件卸载

...
mysql_execute_command
| case SQLCOM_INSTALL_PLUGIN:
| Sql_cmd_uninstall_plugin::execute
   mysql_uninstall_plugin
      // 初始化mysql.plugin表,为后续删除记录做准备
    | tables.init_one_table("mysql", 5, "plugin", 6, "plugin", TL_WRITE);
    | if (! (table = open_ltable(thd, &tables, TL_WRITE, ......
      // 卸载插件
    | reap_plugins
        | plugin_deinitialize
             // 删除系统状态变量
             remove_status_vars(plugin->plugin->status_vars);
             // 如果存在系统定义的卸载函数,调用系统插件卸载函数
             // 部分类型的插件存在,如audit、
              if (plugin_type_deinitialize[plugin->plugin->type])
                  *plugin_type_deinitialize[plugin->plugin->type])(plugin)
             // 插件自定义卸载函数
             (plugin->plugin->deinit(plugin)
         | plugin_del(plugin)
             // 删除系统变量
             mysql_del_sys_var_chain(plugin->system_vars);
             ...
             plugin_vars_free_values(plugin->system_vars);
             // 在对应类型的hash桶中删除该插件          
             my_hash_delete(&plugin_hash[plugin->plugin->type], (uchar*)plugin);
             // 在全局数组plugin_dl_array中清理dlopen的句柄
             // 注意计数(存在多个插件使用一个so的情况)
             plugin_dl_del(&plugin->plugin_dl->dl);
    // 操作mysql.plugin表,将该插件对应的表记录删除
    | table->use_all_columns();
    | ......
    | table->file->ha_delete_row(table->record[0])
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值