Mysql原始碼分析(5): Plugin架構介紹–轉載

來源:互聯網
上載者:User
文章目錄
  • 主要資料結構和定義

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的初始化函數。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.