MySQL插件(二)源码分析-InnoDB储存引擎插件定义和初始化过程

InnoDB储存引擎插件定义和初始化过程


在MySQL中,储存引擎也是作为一种插件实现的,其插件类型为
#define MYSQL_STORAGE_ENGINE_PLUGIN 1 /* Storage Engine */

InnoDB 储存引擎插件

而 InnoDB 作为 MySQL 的默认储存引擎,也是实现了功能最全面的储存引擎。

在 MySQL 中,每一个插件都是利用 mysql_declare_plugin 和 mysql_declare_plugin_endinclude/mysql/plugin.h文件中)两个宏定义组合声明的,通过宏展开可以发现,其实是定义了一个 struct st_mysql_plugin 的结构体。

InnoDB 充分利用了插件的结构,除了储存引擎相关的,还将 INFORMATION_SCHEMA 下的一系列信息表给插件化了,从而定了一个struct st_mysql_plugin结构体数组(通过 show plugins 可以查到所有与 InnoDB 有关的插件):

mysql> show plugins;
+----------------------------+----------+--------------------+---------------+---------+
| Name                       | Status   | Type               | Library       | License |
+----------------------------+----------+--------------------+---------------+---------+
| InnoDB                     | ACTIVE   | STORAGE ENGINE     | NULL          | GPL     |
| INNODB_TRX                 | ACTIVE   | INFORMATION SCHEMA | NULL          | GPL     |
| INNODB_LOCKS               | ACTIVE   | INFORMATION SCHEMA | NULL          | GPL     |
| INNODB_LOCK_WAITS          | ACTIVE   | INFORMATION SCHEMA | NULL          | GPL     |
| INNODB_CMP                 | ACTIVE   | INFORMATION SCHEMA | NULL          | GPL     |
| INNODB_CMP_RESET           | ACTIVE   | INFORMATION SCHEMA | NULL          | GPL     |
| INNODB_CMPMEM              | ACTIVE   | INFORMATION SCHEMA | NULL          | GPL     |
| INNODB_CMPMEM_RESET        | ACTIVE   | INFORMATION SCHEMA | NULL          | GPL     |
| INNODB_CMP_PER_INDEX       | ACTIVE   | INFORMATION SCHEMA | NULL          | GPL     |
| INNODB_CMP_PER_INDEX_RESET | ACTIVE   | INFORMATION SCHEMA | NULL          | GPL     |
| INNODB_BUFFER_PAGE         | ACTIVE   | INFORMATION SCHEMA | NULL          | GPL     |
| INNODB_BUFFER_PAGE_LRU     | ACTIVE   | INFORMATION SCHEMA | NULL          | GPL     |
| INNODB_BUFFER_POOL_STATS   | ACTIVE   | INFORMATION SCHEMA | NULL          | GPL     |
| INNODB_TEMP_TABLE_INFO     | ACTIVE   | INFORMATION SCHEMA | NULL          | GPL     |
| INNODB_METRICS             | ACTIVE   | INFORMATION SCHEMA | NULL          | GPL     |
| INNODB_FT_DEFAULT_STOPWORD | ACTIVE   | INFORMATION SCHEMA | NULL          | GPL     |
| INNODB_FT_DELETED          | ACTIVE   | INFORMATION SCHEMA | NULL          | GPL     |
| INNODB_FT_BEING_DELETED    | ACTIVE   | INFORMATION SCHEMA | NULL          | GPL     |
| INNODB_FT_CONFIG           | ACTIVE   | INFORMATION SCHEMA | NULL          | GPL     |
| INNODB_FT_INDEX_CACHE      | ACTIVE   | INFORMATION SCHEMA | NULL          | GPL     |
| INNODB_FT_INDEX_TABLE      | ACTIVE   | INFORMATION SCHEMA | NULL          | GPL     |
| INNODB_SYS_TABLES          | ACTIVE   | INFORMATION SCHEMA | NULL          | GPL     |
| INNODB_SYS_TABLESTATS      | ACTIVE   | INFORMATION SCHEMA | NULL          | GPL     |
| INNODB_SYS_INDEXES         | ACTIVE   | INFORMATION SCHEMA | NULL          | GPL     |
| INNODB_SYS_COLUMNS         | ACTIVE   | INFORMATION SCHEMA | NULL          | GPL     |
| INNODB_SYS_FIELDS          | ACTIVE   | INFORMATION SCHEMA | NULL          | GPL     |
| INNODB_SYS_FOREIGN         | ACTIVE   | INFORMATION SCHEMA | NULL          | GPL     |
| INNODB_SYS_FOREIGN_COLS    | ACTIVE   | INFORMATION SCHEMA | NULL          | GPL     |
| INNODB_SYS_TABLESPACES     | ACTIVE   | INFORMATION SCHEMA | NULL          | GPL     |
| INNODB_SYS_DATAFILES       | ACTIVE   | INFORMATION SCHEMA | NULL          | GPL     |
| INNODB_SYS_VIRTUAL         | ACTIVE   | INFORMATION SCHEMA | NULL          | GPL     |
+----------------------------+----------+--------------------+---------------+---------+

在 MySQL 源码文件 storage/innobase/handler/ha_innodb.cc 中,有 InnoDB 插件的定义:

mysql_declare_plugin(innobase)
{
  MYSQL_STORAGE_ENGINE_PLUGIN,
  &innobase_storage_engine,
  innobase_hton_name,
  plugin_author,
  "Supports transactions, row-level locking, and foreign keys",
  PLUGIN_LICENSE_GPL,
  innobase_init, /* Plugin Init */
  NULL, /* Plugin Deinit */
  INNODB_VERSION_SHORT,
  innodb_status_variables_export,/* status variables             */
  innobase_system_variables, /* system variables */
  NULL, /* reserved */
  0,    /* flags */
},
i_s_innodb_trx,
i_s_innodb_locks,
......
i_s_innodb_sys_tables,
i_s_innodb_sys_tablestats,
i_s_innodb_sys_indexes,
i_s_innodb_sys_columns,
i_s_innodb_sys_fields,
......
i_s_innodb_sys_tablespaces,
i_s_innodb_sys_datafiles,
i_s_innodb_sys_virtual

mysql_declare_plugin_end;

因为所有的插件都是定义了一个struct st_mysql_plugin 结构体,首先看看结构体:

/* Plugin description structure. */
struct st_mysql_plugin
{
  int type;             /* the plugin type (a MYSQL_XXX_PLUGIN value)   */
  void *info;           /* pointer to type-specific plugin descriptor   */
  const char *name;     /* plugin name                                  */
  const char *author;   /* plugin author (for I_S.PLUGINS)              */
  const char *descr;    /* general descriptive text (for I_S.PLUGINS)   */
  int license;          /* the plugin license (PLUGIN_LICENSE_XXX)      */
  int (*init)(MYSQL_PLUGIN);  /* the function to invoke when plugin is loaded */
  int (*deinit)(MYSQL_PLUGIN);/* the function to invoke when plugin is unloaded */
  unsigned int version; /* plugin version (for I_S.PLUGINS)             */
  struct st_mysql_show_var *status_vars;
  struct st_mysql_sys_var **system_vars;
  void * __reserved1;   /* reserved for dependency checking             */
  unsigned long flags;  /* flags for plugin */
};

struct st_mysql_plugin 结构体中,需要每一个插件定义指定其各自的属性:
例如:插件类型,插件名称,作者,描述,初始化函数,版本,插件系统变量等信息;
这些信息最终会通过information_schema.plugins中展示出来。

mysql> select * from information_schema.plugins where plugin_name='innodb';
+-------------+----------------+---------------+----------------+---------------------+----------------+------------------------+--------------------+------------------------------------------------------------+----------------+-------------+
| PLUGIN_NAME | PLUGIN_VERSION | PLUGIN_STATUS | PLUGIN_TYPE    | PLUGIN_TYPE_VERSION | PLUGIN_LIBRARY | PLUGIN_LIBRARY_VERSION | PLUGIN_AUTHOR      | PLUGIN_DESCRIPTION                                         | PLUGIN_LICENSE | LOAD_OPTION |
+-------------+----------------+---------------+----------------+---------------------+----------------+------------------------+--------------------+------------------------------------------------------------+----------------+-------------+
| InnoDB      | 5.7            | ACTIVE        | STORAGE ENGINE | 50725.0             | NULL           | NULL                   | Oracle Corporation | Supports transactions, row-level locking, and foreign keys | GPL            | FORCE       |
+-------------+----------------+---------------+----------------+---------------------+----------------+------------------------+--------------------+------------------------------------------------------------+----------------+-------------+
1 row in set (0.01 sec)

为了更清晰直观的看 InnoDB 插件的定义,将宏mysql_declare_plugin(innobase)展开,其定义与information_schema.plugins展示的是一一对应的:

struct st_mysql_plugin builtin_innobase_plugin[]= {//定义了一个数组
  //第一个元素为 Innodb Storage engine
  {
    1, //PLUGIN_TYPE, 类型为储存引擎,MYSQL_STORAGE_ENGINE_PLUGIN
    &innobase_storage_engine,  //
    "InnoDB",//PLUGIN_NAME 
    "Oracle Corporation", //PLUGIN_AUTHOR
    "Supports transactions, row-level locking, and foreign keys",//PLUGIN_DESCRIPTION                                         
    1, //PLUGIN_LICENSE_GPL
    innobase_init, //init
    NULL,
    MYSQL_VERSION_MAJOR<<8|MYSQL_VERSION_MINOR,//PLUGIN_VERSION
    { {"Innodb", 
       (char*) &show_innodb_vars,
       SHOW_FUNC,
       SHOW_SCOPE_GLOBAL
      },
      { NullS,
        NullS,
        SHOW_LONG,
        SHOW_SCOPE_GLOBAL
      }
    },//status_vars[]
    innobase_system_variables[],//InnoDB引擎的一系列系统变量;
    NULL,//reserved
    0,   //flags
  },//第一个元素为 Innodb Storage engine结束
  {},//第二个元素
  {}...
}

再看看builtin_innobase_plugin[]数组的二个元素,为 InnoDB 一个 INFORMATION_SCHEMA 插件的定义:

i_s_innodb_trx
{
  type = 4,//PLUGIN_TYPE,INFORMATION_SCHEMA 插件
  info = &i_s_info,
  name = "INNODB_TRX", //PLUGIN_NAME 
  author ="Oracle Corporation", //PLUGIN_AUTHOR
  descr = "InnoDB transactions",//PLUGIN_DESCRIPTION   
  license = 1,
  init = innodb_trx_init(void*), 
  deinit = i_s_common_deinit(void*),
  version = INNODB_VERSION_SHORT,
  status_vars = NULL,
  system_vars = NULL, 
  __reserved1 = NULL,
  flags = 0,
}

MySQL 插件初始化大致流程

MySQL 源码编译过程中,cmake 之后,将插件分为必备和可选的两大类插件,builtin_innobase_plugin 即为上述定义的 InnoDB 的引擎:

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

st_mysql_plugin *mysql_optional_plugins[] = {
  builtin_archive_plugin, 
  builtin_blackhole_plugin, 
  builtin_federated_plugin, 
  builtin_partition_plugin, 
  builtin_ngram_parser_plugin, 
  0x0
}

MySQL 服务器启动后,初始化这两类的插件,下面为 InnoDB 的初始化简要流程:

>main
  >mysqld_main(argc, argv)
    >init_server_components
      /*Load early plugins */
      if (plugin_register_early_plugins(&remaining_argc, remaining_argv, opt_help ?
          PLUGIN_INIT_SKIP_INITIALIZATION : 0)); THEN
      fi
      /* Load builtin plugins, initialize MyISAM, CSV and InnoDB */
      if (plugin_register_builtin_and_init_core_se(&remaining_argc, remaining_argv)); THEN
        for (struct st_mysql_plugin **builtins= mysql_mandatory_plugins; *builtins || mandatory; builtins++)
        do
          for (struct st_mysql_plugin *plugin= *builtins; plugin->info; plugin++)
          do
            struct st_plugin_int tmp
            memset(&tmp, 0, sizeof(tmp))
            struct st_plugin_int *plugin_ptr
            if (plugin_ptr->state != PLUGIN_IS_UNINITIALIZED || plugin_initialize(plugin_ptr)); THEN
              >plugin_initialize()
                if (plugin_type_initialize[plugin->plugin->type]); THEN//InnoDB为储存引擎,type=1(storage engine)
                  >ha_initialize_handlerton(st_plugin_int *plugin)     //所以此处调用的是initialize_handerton
                    hton= (handlerton *)my_malloc(key_memory_handlerton,  //申请了一个handlerton的内存块,为一个储存引擎的handlerton
                           sizeof(handlerton),
                           MYF(MY_WME | MY_ZEROFILL)); 
                    plugin->data= hton  // plugin的data地址指向了储存引擎的handlerton的地址,用以通过plugin寻找到handlerton头地址
                    if (plugin->plugin->init && plugin->plugin->init(hton));THEN //调用InnoDB handlerton的init函数来初始化
                      >innobase_init(hton)  //上文介绍到,builtin_innobase_plugin[0]为InnoDB储存引擎的定义,init函数赋值了innobase_init
                        handlerton* innobase_hton= (handlerton*) p  //实例化了InnoDB的handlerton并进行初始化
                        innodb_hton_ptr = innobase_hton
                        
                        innobase_hton->state = SHOW_OPTION_YES
                        innobase_hton->db_type = DB_TYPE_INNODB
                        innobase_hton->savepoint_offset = sizeof(trx_named_savept_t)
                        innobase_hton->close_connection = innobase_close_connection
                        ......
                        innobase_hton->commit = innobase_commit
                        innobase_hton->rollback = innobase_rollback
                        ......
                        
                      <innobase_init()
                    fi
                  <ha_initialize_handlerton
                fi
              <plugin_initialize()
            fi
          done
        done
      fi
      if (plugin_register_dynamic_and_init_all(&remaining_argc, remaining_argv,
         (opt_noacl ? PLUGIN_INIT_SKIP_PLUGIN_TABLE : 0) | (opt_help ?
         (PLUGIN_INIT_SKIP_INITIALIZATION | PLUGIN_INIT_SKIP_PLUGIN_TABLE) : 0))); THEN
      fi      
    <init_server_components
    ...
  <mysqld_main(argc, argv)
<main

可以看到,InnoDB 插件初始化最终实例出了一个hanlderton,从而进入到了储存引擎,关于handlerton可以参考(MySQL如何创建自定义储存引擎(一)

  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

抡着鼠标扛大旗

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值