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

来源:互联网 发布:乌龙山伯爵 知乎 编辑:程序博客网 时间:2024/06/04 18:28

版本

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])