mysql程式碼閱讀-外掛載入及儲存引擎接入

liiinuuux發表於2015-12-11
初始化plugin流程

點選(此處)摺疊或開啟

  1. main()
  2.   -> mysqld_main()
  3.     -> init_server_components()
  4.       -> plugin_init()
  5.         -> plugin_initialize(struct st_plugin_int *plugin)

plugin_init從兩個plugin陣列裡提取plugin。
一個是mysql_mandatory_plugins,儲存強制外掛
第二個是mysql_optional_plugins,存放可選外掛
陣列的最後一個元素時0,這點很重要
sql/sql_builtin.cc:

點選(此處)摺疊或開啟

  1. struct st_mysql_plugin *mysql_optional_plugins[]=
  2. {
  3.    builtin_blackhole_plugin, builtin_innobase_plugin, builtin_federated_plugin, builtin_perfschema_plugin, builtin_archive_plugin, builtin_partition_plugin, 0
  4. };

  5. struct st_mysql_plugin *mysql_mandatory_plugins[]=
  6. {
  7.   builtin_binlog_plugin, builtin_mysql_password_plugin, builtin_myisam_plugin, builtin_csv_plugin, builtin_heap_plugin, builtin_myisammrg_plugin, 0
  8. }

plugin_init初始化外掛的程式碼

點選(此處)摺疊或開啟

  1. // 先迴圈mysql_mandatory_plugins
  2.   for (builtins= mysql_mandatory_plugins; *builtins || mandatory; builtins++)
  3.   {
  4.     /*
  5.     當迴圈到mysql_mandatory_plugins最後,遇到0,"!*builtins"就會成立,
  6.     此時將builtins指向mysql_optional_plugins並且將mandatory標記設為false。
  7.     這樣雖然builtins指向其它陣列了,但是最外層for的“builtins++”可以正常執行
  8.     由於mandatory變成false了,因此當遇到mysql_optional_plugins最後一個元素“0”的時候,
  9.     就不滿足最外層的“*builtins || mandatory”了,至此外掛載入順利結束。
  10.     */
  11.     if (!*builtins)
  12.     {
  13.       builtins= mysql_optional_plugins;
  14.       mandatory= false;
  15.       if (!*builtins)
  16.         break;
  17.     }
  18.     for (plugin= *builtins; plugin->info; plugin++)
  19.     {
  20.       ...
  21.       if (plugin_ptr->state != PLUGIN_IS_UNINITIALIZED ||
  22.           // 外掛的初始化工作由plugin_initialize函式來組織
  23.           plugin_initialize(plugin_ptr))
  24.         goto err_unlock;
  25.       ...

各類plugin的初始化函式被放到一個由這些函式的指標組成的陣列plugin_type_initialize裡
每個plugin的型別plugin->plugin->type是一個整數,用它作為下標訪問plugin_type_initialize,就能得到初始化這類plugin所需的函式。

點選(此處)摺疊或開啟

  1. plugin_type_init plugin_type_initialize[MYSQL_MAX_PLUGIN_TYPE_NUM]=
  2. {
  3.   0,ha_initialize_handlerton,0,0,initialize_schema_table,
  4.   initialize_audit_plugin,0,0,0
  5. };

plugin_initialize裡具體初始化plugin的地方,調的是函式指標

點選(此處)摺疊或開啟

  1. if (plugin_type_initialize[plugin->plugin->type])
  2.   {
  3.     if ((*plugin_type_initialize[plugin->plugin->type])(plugin))
  4.     {
  5.       sql_print_error("Plugin '%s' registration as a %s failed.",
  6.                       plugin->name.str, plugin_type_names[plugin->plugin->type].str);
  7.       goto err;
  8.     }
  9.     ...

如果plugin是儲存引擎,plugin->plugin->type的值就是1,初始化工作就是呼叫plugin_type_initialize[1],也就是ha_initialize_handlerton。
前面程式碼的(*plugin_type_initialize[plugin->plugin->type])(plugin)就等價於ha_initialize_handlerton(plugin)
plugin_type_initialize主要工作初始化handlerton,存到plugin->data裡。然後將儲存引擎的handlerton記錄下來。
以後使用儲存引擎需要用到handlerton裡的資訊。

每個儲存引擎還需要載入不同的handler,儲存引擎各自的“plugin->plugin->init”函式指標指向其handler的初始化函式。
ha_initialize_handlerton直接呼叫“plugin->plugin->init”

點選(此處)摺疊或開啟

  1. int ha_initialize_handlerton(st_plugin_int *plugin)
  2. {
  3.   handlerton *hton;
  4.   ...
  5.   hton= (handlerton *)my_malloc(sizeof(handlerton),
  6.                                 MYF(MY_WME | MY_ZEROFILL));
  7.   ...
  8.   plugin->data= hton; // shortcut for the future
  9.   if (plugin->plugin->init && plugin->plugin->init(hton))
  10.   {
  11.     sql_print_error("Plugin '%s' init function returned error.",
  12.                     plugin->name.str);
  13.     goto err;
  14.   }

以innodb為例plugin->plugin->init指向的是下面的innobase_init。每個儲存引擎有自己的xxx_init

點選(此處)摺疊或開啟

  1. static
  2. int
  3. innobase_init(
  4. /*==========*/
  5.   void *p) /*!< in: InnoDB handlerton */
  6. {
  7.   ...
  8.   /*
  9.   將建立innodb的handler的函式指標放到handlerton->create。
  10.   以後每次開啟一張innodb表都需要用它建立一個innodb handler。
  11.   */
  12.   innobase_hton->create = innobase_create_handler;
  13.   ...

innobase_create_handler內容很簡單,就是呼叫ha_innobase的建構函式。
其它的也類似比如myisam的就是調ha_myisam的建構函式

點選(此處)摺疊或開啟

  1. static
  2. handler*
  3. innobase_create_handler(
  4. /*====================*/
  5.   handlerton* hton, /*!< in: InnoDB handlerton */
  6.   TABLE_SHARE* table,
  7.   MEM_ROOT* mem_root)
  8. {
  9.   return(new (mem_root) ha_innobase(hton, table));
  10. }

ha_innobase繼承自mysql定義的handler類,handler裡規定了儲存引擎需要完成的各類操作
如:

點選(此處)摺疊或開啟

  1. virtual int update_row(const uchar *old_data __attribute__((unused)),
  2.                          uchar *new_data __attribute__((unused)))
  3.   {
  4.     return HA_ERR_WRONG_COMMAND;
  5.   }


  6.   virtual int delete_row(const uchar *buf __attribute__((unused)))
  7.   {
  8.     return HA_ERR_WRONG_COMMAND;
  9.   }
  10.   virtual int truncate()
  11.   { return HA_ERR_WRONG_COMMAND; }
  12. ...

因此mysql不需要知道innodb的細節,
只要將ha_innobase視為handler,呼叫handler的函式,就能使用innodb的功能

點選(此處)摺疊或開啟

  1. class ha_innobase: public handler
  2. {
  3.   ...
  4. }

這就是mysql與plugin形式的儲存引擎對接的方式

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/26239116/viewspace-1870316/,如需轉載,請註明出處,否則將追究法律責任。

相關文章