MySQL外掛呼叫

gaopengtttt發表於2018-08-13

簡單記錄以備學習,如果有誤請指出。


一、核心類

  • Observer_info:觀察者 rpl_handler.h

class Observer_info {  //外掛觀察者public:  void *observer; //這個void指標是具體的觀察者,使用指標函式實現多型
  st_plugin_int *plugin_int;  plugin_ref plugin  Observer_info(void *ob, st_plugin_int *p);
};
  • 實際觀察者
    及void* 指向的物件,其中全部都是函式指標,這裡透過函式指標指向了具體的函式,實現了外掛的功能。其中的函式指標指向的實際函式就是需要使用者自己實現的。

Trans_observer 結構體
Server_state_observer 結構體
Binlog_transmit_observer 結構體
Binlog_relay_IO_observer 結構體

實際上看具體實現的時候,搜尋這些結構的名字,外掛中如果實現會定義實際的函式名。如MGR中如下:

Trans_observer trans_observer = {  sizeof(Trans_observer),
  group_replication_trans_before_dml,
  group_replication_trans_before_commit,
  group_replication_trans_before_rollback,
  group_replication_trans_after_commit,
  group_replication_trans_after_rollback,
};
  • Delegate:委託者基類
    其中包含

  Observer_info_list observer_info_list; //觀察者連結串列,也就是Observer_info的一個連結串列
  mysql_rwlock_t lock;//讀寫鎖
  MEM_ROOT memroot;//記憶體空間
  bool inited;//是否初始化

並且實現了一些通用的函式,比如增加和刪除外掛

  • 具體的委託者繼承自Delegate

Trans_delegate :事物相關 typedef Trans_observer Observer; 
Server_state_delegate :伺服器相關 typedef Server_state_observer Observer;
Binlog_transmit_delegate  :傳輸相關 typedef Binlog_transmit_observer Observer;
Binlog_relay_IO_delegate  :slave 相關typedef Binlog_relay_IO_observer Observer;

二、註冊函式

舉例rpl_handler.cc中

int register_trans_observer(Trans_observer *observer, void *p){  return transaction_delegate->add_observer(observer, (st_plugin_int *)p);
}

observer已經初始化完成,註冊即可。這裡加入到了觀察者佇列。一旦加入這個連結串列則,在實際使用的時候就會遍歷整個連結串列執行相應的函式。

三、重要的宏

  • RUN_HOOK 宏
    定義如下:

#define RUN_HOOK(group, hook, args)             \
  (group ##_delegate->is_empty() ?              \
   0 : group ##_delegate->hook args)#define NO_HOOK(group) (group ##_delegate->is_empty())

這個宏會在MySQL中程式碼的相應合適的位置進行呼叫,進入外掛定義的邏輯。

  • FOREACH_OBSERVER 宏
    定義如下:

#define FOREACH_OBSERVER(r, f, thd, args)                               \
  /*
     Use a struct to make sure that they are allocated adjacent, check
     delete_dynamic().
  */                                                                    \
  Prealloced_array<plugin_ref, 8> plugins(PSI_NOT_INSTRUMENTED);        \ //定義一個外掛陣列
  read_lock();                                                          \
  Observer_info_iterator iter= observer_info_iter();                    \ //迭代器
  Observer_info *info= iter++;                                          \ //
  for (; info; info= iter++)                                            \
  {                                                                     \
    plugin_ref plugin=                                                  \
      my_plugin_lock(0, &info->plugin);                                 \    if (!plugin)                                                        \
    {                                                                   \      /* plugin is not intialized or deleted, this is not an error */   \
      r= 0;                                                             \      break;                                                            \
    }                                                                   \
    plugins.push_back(plugin);                                          \    if (((Observer *)info->observer)->f                                 \
        && ((Observer *)info->observer)->f args)                        \
    {                                                                   \
      r= 1;                                                             \
      sql_print_error("Run function '" #f "' in plugin '%s' failed",    \
                      info->plugin_int->name.str);                      \      break;                                                            \
    }                                                                   \
  }                                                                     \

實際上可以看到是在遍歷相應的實際委託者的連結串列observer_info_list,執行相應的回表函式。

四、一個實際的列子

RUN_HOOK(transaction,
                 before_commit,
                 (thd, all,
                  thd_get_cache_mngr(thd)->get_binlog_cache_log(true),
                  thd_get_cache_mngr(thd)->get_binlog_cache_log(false),
                  max<my_off_t>(max_binlog_cache_size,
                                max_binlog_stmt_cache_size))

根據RUN_HOOK定義 group ##_delegate->hook args 轉換為:

transaction_delegate->before_commit(thd, all,
                  thd_get_cache_mngr(thd)->get_binlog_cache_log(true),
                  thd_get_cache_mngr(thd)->get_binlog_cache_log(false),
                  max<my_off_t>(max_binlog_cache_size,
                                max_binlog_stmt_cache_size)

此處的transaction_delegate是一個已經初始化的並且已經有外掛註冊的Trans_delegate類的全域性物件。因為Trans_delegate繼承來自Delegate,而在Trans_delegate中實現了before_commit的邏輯。其中包含的宏呼叫

FOREACH_OBSERVER(ret, before_commit, thd, (&param)); //這裡會執行回撥函式宏定義:(#define FOREACH_OBSERVER(r, f, thd, args)  )

做回撥,實際上他會遍歷整個transaction_delegate中的觀察者,這些觀察者就是每一個外掛實現的特定的GROUP的功能,所以FOREACH_OBSERVER宏的這一句

((Observer *)info->observer)->f args

就裝換為了(Trans_observer *)info->observer)->before_commit(&param) 其中info是一個Observer_info物件其中包含了一個VOID指標observer,可以轉換為需要的型別,而Trans_observer是一個結構體其中全部都是函式指標before_commit是一個函式指標指向了group_replication_trans_before_commit,整個回撥過程完成。

五、一張呼叫圖

呼叫圖如下:


MySQL外掛呼叫

RUN_HOOK.png

作者微信:


MySQL外掛呼叫

微信.jpg


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

相關文章