Mysql源代码分析(5): Plugin架构介绍

Mysql现在很多模块都是通过plugin的方式连接到Mysql核心中的,除了大家熟悉的存储引擎都是Plugin之外,Mysql还支持其他类型的plugin。本文将对相关内容做一些简单介绍。主要还是以架构性的介绍为主,具体细节会提到一点,但是肯定不会包括所有的细节。 

主要数据结构和定义 
大部分的数据接口,宏和常量都定义在include/mysql/plugin.h中,我们来慢慢看。 

先看plugin的类型: 

#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 */ 
开发者开发的plugin必须指定上述类型之一。类型包括用户自定义函数,存储引擎,全文解析,原声plugin和information schema plugin。最常见的是前三个,daemon plugin一般用来在mysqld中启动一个线程,在某些时候干活儿。 

一个plugin的描述数据接口是: 
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 SHOW PLUGINS)             */ 
  const char *descr;    /* general descriptive text (for SHOW PLUGINS ) */ 
  int license;          /* the plugin license (PLUGIN_LICENSE_XXX)      */ 
  int (*init)(void *);  /* the function to invoke when plugin is loaded */ 
  int (*deinit)(void *);/* the function to invoke when plugin is unloaded */ 
  unsigned int version; /* plugin version (for SHOW PLUGINS)            */ 
  struct st_mysql_show_var *status_vars; 
  struct st_mysql_sys_var **system_vars; 
  void * __reserved1;   /* reserved for dependency checking             */ 
}; 
主要内容包括类型,名字,初始化/清理函数,状态变量和系统变量的定义等等。但是在使用的时候一般不是直接使用这个数据结构,而是使用大量的宏来辅助。 

一个plugin的开始: 
#define mysql_declare_plugin(NAME) \ 
__MYSQL_DECLARE_PLUGIN(NAME, \ 
                 builtin_ ## NAME ## _plugin_interface_version, \ 
                 builtin_ ## NAME ## _sizeof_struct_st_plugin, \ 
                 builtin_ ## NAME ## _plugin) 
plugin定义结束: 
#define mysql_declare_plugin_end ,{0,0,0,0,0,0,0,0,0,0,0,0}} 

__MYSQL_DECLARE_PLUGIN根据plugin是动态链接plugin还是静态链接plugin有不同的定义: 

#ifndef MYSQL_DYNAMIC_PLUGIN 
#define __MYSQL_DECLARE_PLUGIN(NAME, VERSION, PSIZE, DECLS)                   \ 
int VERSION= MYSQL_PLUGIN_INTERFACE_VERSION;                                  \ 
int PSIZE= sizeof(struct st_mysql_plugin);                                    \ 
struct st_mysql_plugin DECLS[]= { 
#else 
#define __MYSQL_DECLARE_PLUGIN(NAME, VERSION, PSIZE, DECLS)                   \ 
int _mysql_plugin_interface_version_= MYSQL_PLUGIN_INTERFACE_VERSION;         \ 
int _mysql_sizeof_struct_st_plugin_= sizeof(struct st_mysql_plugin);          \ 
struct st_mysql_plugin _mysql_plugin_declarations_[]= { 
#endif 

特别要注意的是“#ifndef MYSQL_DYNAMIC_PLUGIN”,如果你要写的plugin是动态加载的话,需要在编译的时候定义这个宏。 
总体而言,mysql_declare_plugin申明了一个struct st_mysql_plugin数组,开发者需要在该宏之后填写plugin自定义的st_mysql_plugin各个成员,并通过mysql_declare_plugin_end结束这个数组。 

看个例子plugin/daemon_example/daemon_example.cc,这是个动态MYSQL_DAEMON_PLUGIN类型的plugin,注意到plugin/daemon_example/Makefile.am里面有-DMYSQL_DYNAMIC_PLUGIN。具体定义如下: 
mysql_declare_plugin(daemon_example) 

  MYSQL_DAEMON_PLUGIN, 
  &daemon_example_plugin, 
  "daemon_example", 
  "Brian Aker", 
  "Daemon example, creates a heartbeat beat file in mysql-heartbeat.log", 
  PLUGIN_LICENSE_GPL, 
  daemon_example_plugin_init, /* Plugin Init */                          // plugin初始化入口 
  daemon_example_plugin_deinit, /* Plugin Deinit */                   // plugin清理函数 
  0x0100 /* 1.0 */, 
  NULL,                       /* status variables                */ 
  NULL,                       /* system variables                */ 
  NULL                        /* config options                  */ 

mysql_declare_plugin_end; 

这个定义经过preprocess被展开后定义为: 
int _mysql_plugin_interface_version_= MYSQL_PLUGIN_INTERFACE_VERSION;         \ 
int _mysql_sizeof_struct_st_plugin_= sizeof(struct st_mysql_plugin);          \ 
struct st_mysql_plugin _mysql_plugin_declarations_[]= { 
  { MYSQL_DAEMON_PLUGIN, 
  &daemon_example_plugin, 
  "daemon_example", 
  "Brian Aker", 
  "Daemon example, creates a heartbeat beat file in mysql-heartbeat.log", 
  PLUGIN_LICENSE_GPL, 
  daemon_example_plugin_init, /* Plugin Init */                          // plugin初始化入口 
  daemon_example_plugin_deinit, /* Plugin Deinit */                   // plugin清理函数 
  0x0100 /* 1.0 */, 
  NULL,                       /* status variables                */ 
  NULL,                       /* system variables                */ 
  NULL                        /* config options                  */ 
} , {0,0,0,0,0,0,0,0,0,0,0,0}}; 

静态链接plugin也类似,只不过plugin宏展开出来的变量都有自己的名字,对于myisam,生成了一个叫builtin_myisam_plugin的plugin数组。 

plugin可以定义自己的变量,包括系统变量和状态变量。具体的例子可以看看storage/innobase/handler/ha_innodb.cc里面对于innodb插件的申明,结合plugin.h,还是比较容易看懂的。 

在mysql的源代码里面grep一把mysql_declare_plugin,看看都有哪些plugin: 
$grep "mysql_declare_plugin(" --include=*.cc -rni * 

plugin/daemon_example/daemon_example.cc:187:mysql_declare_plugin(daemon_example) 
sql/ha_partition.cc:6269:mysql_declare_plugin(partition) 
sql/log.cc:5528:mysql_declare_plugin(binlog) 
sql/ha_ndbcluster.cc:10533:mysql_declare_plugin(ndbcluster) 
storage/csv/ha_tina.cc:1603:mysql_declare_plugin(csv) 
storage/example/ha_example.cc:893:mysql_declare_plugin(example) 
storage/myisam/ha_myisam.cc:2057:mysql_declare_plugin(myisam) 
storage/heap/ha_heap.cc:746:mysql_declare_plugin(heap) 
storage/innobase/handler/ha_innodb.cc:8231:mysql_declare_plugin(innobase) 
storage/myisammrg/ha_myisammrg.cc:1186:mysql_declare_plugin(myisammrg) 
storage/blackhole/ha_blackhole.cc:356:mysql_declare_plugin(blackhole) 
storage/federated/ha_federated.cc:3368:mysql_declare_plugin(federated) 
storage/archive/ha_archive.cc:1627:mysql_declare_plugin(archive) 
呵呵,连binlog都是plugin哦,不过还是storage plugin占大多数。 

Plugin初始化 
在见面的介绍main函数的文章中我也提到了其中有个函数plugin_init()是初始化的一部分,这个东东就是所有静态链接初始化plugin的初始化入口。该函数定义在"sql/sql_plugin.cc"中。 

int plugin_init(int *argc, char **argv, int flags) { 

  // 初始化内存分配pool。 

  init_alloc_root(&plugin_mem_root, 4096, 4096); 

  init_alloc_root(&tmp_root, 4096, 4096); 

  // hash结构初始化 

  ... 

  // 初始化运行时plugin数组,plugin_dl_array用来保存动态加载plugin,plugin_array保存静态链接plugin。而且最多各自能有16个plugin。 

  my_init_dynamic_array(&plugin_dl_array, sizeof(struct st_plugin_dl *),16,16); 

  my_init_dynamic_array(&plugin_array, sizeof(struct st_plugin_int *),16,16); 
  // 初始化静态链接plugin 
  for (builtins= mysqld_builtins; *builtins; builtins++) { 
    // 每一个plugin还可以有多个子plugin,参见见面的plugin申明。 
    for (plugin= *builtins; plugin->info; plugin++) { 
      register_builtin(plugin, &tmp, &plugin_ptr); // 将plugin放到plugin_array和plugin_hash中。 
      // 这个时候只初始化csv或者myisam plugin。 
      plugin_initialize(plugin_ptr);    // 初始化plugin,调用plugin的初始化函数,将plugin的状态变量加入到状态变量列表中,将系统变量的plugin成员指向当前的活动plugin。 
    } 
  } 
  // 根据用户选项初始化动态加载plugin 
  if (!(flags & PLUGIN_INIT_SKIP_DYNAMIC_LOADING)) 
  { 
    if (opt_plugin_load) 
      plugin_load_list(&tmp_root, argc, argv, opt_plugin_load);        // 根据配置加载制定的plugin。包括找到dll,加载,寻找符号并设置plugin结构。 
    if (!(flags & PLUGIN_INIT_SKIP_PLUGIN_TABLE)) 
      plugin_load(&tmp_root, argc, argv);          // 加载系统plugin table中的plugin。 
  } 
  // 初始化剩下的plugin。 
  for (i= 0; i < plugin_array.elements; i++) { 
    plugin_ptr= *dynamic_element(&plugin_array, i, struct st_plugin_int **); 
    if (plugin_ptr->state == PLUGIN_IS_UNINITIALIZED) 
    { 
      if (plugin_initialize(plugin_ptr)) 
      { 
        plugin_ptr->state= PLUGIN_IS_DYING; 
        *(reap++)= plugin_ptr; 
      } 
    } 
  } 
  ... 



这个函数执行结束以后,在plugin_array,plugin_dl_array,plugin_hash中保存了当前加载了的所有的plugin。到此plugin初始化结束。 


在plugin_initialize函数里面,调用了每个plugin自己的init函数(参见前面的内容)。特别要提到的是对于各种不同类型的plugin,初始化函数的参数也不一样,这是通过一个全局的plugin_type_initialize间接层来实现的。这个数组对于每种类型的plugin定义了一个函数,比如对于storage plugin对应的是ha_initialize_handlerton,对于information scheme对应的是initialize_schema_table,然后在这些函数中再调用plugin的初始化函数。暂时对于其他类型的plugin没有定义这个中间层初始化函数,所以就直接调用了plugin的初始化函数。 


上文来自:http://blog.csdn.net/saylerboxer/article/details/6989222

你可能感兴趣的:(数据库,mysql,源代码,调试)