久久精品人人爽,华人av在线,亚洲性视频网站,欧美专区一二三

MySQL中如何編寫Information Schema Plugin

156次閱讀
沒有評論

共計 9338 個字符,預計需要花費 24 分鐘才能閱讀完成。

MySQL 中如何編寫 Information Schema Plugin,相信很多沒有經驗的人對此束手無策,為此本文總結了問題出現的原因和解決方法,通過這篇文章希望你能解決這個問題。

1. 什么是 i_s plugin

在 mysql 里面,默認會有一個 information schema(以下簡寫為 i_s),用于記錄一些與元數據或表的模式相關的信息,與其他數據庫不一樣,在 data 目錄下,并沒有為 i_s 建立文件夾,這說明,i_s 并不是物理存在的,而是在需要的時候,才會臨時創建。這就可以解釋為什么 i_s 庫中的表的記錄總是無法刪除或修改。

2. 為什么使用 i_s plugin

雖然 i_s 中定義了豐富的表,但通過 i_s plugin,我們可以將其功能進行擴展,豐富其中的信息,比如,我們可以把關心信息以表的形式展現出來,可以通過引入 MySQL 的內核代碼,來監控內核的運行狀態,例如鎖資源狀態、線程狀態、table cache 狀態等信息。客戶端可以通過 sql 來過濾想要的內容,甚至,我們可以在 plugin 中通過 cond 來進行過濾,而無需在層處理。

3. 如何編寫 i_s plugin

1) 之前已經介紹過的,這里不在贅述,在 plugin 間通用的包括:

a. plugin 的聲明;

b. 添加系統變量 (show /setvariables)

c. 添加狀態變量 (show status)

2) 初始化 I_S 插件

函數原型:name_init(void *p)

函數用于初始化插件,包括指定表的模式、創建表、構造表的函數指針等信息,指針 p 會指向一個結構體 st_schema_table,如下表:

初始化的目的是為了填充結構體 st_schema_table,從而確定表的定義,在查詢表的時候,調用相應的函數進行記錄填充。由于該結構體與內建的 i_s 表是公用的,因此一些字段我們可以直接忽略掉。在編寫 plugin 的時候,我們需要填充的內容包括:

Oslash;  Fields_info

Oslash;  Fill_table

2). 初始化表結構 fields_info

Fields_info 結構體為 st_field_info

通常我們會預定義數組,以 NULL 列結束:

ST_FIELD_INFO  is_field[] = {

  {hellip; hellip;},

  hellip; hellip;

{0, 0, MYSQL_TYPE_NULL, 0, 0, 0, 0}

}

3)fill_table()

函數原型:int fill_table(THD *thd, TABLE_LIST *tables, COND *cond);

參數描述:

為了將記錄保存到 i_s 表中,這里不的不提到兩個函數:field 類的成員函數 store_系列函數和 schema_table_store_record(),前者用來存儲數據到表結構體追蹤,后者用來將一行存儲好的數據放入到臨時表中。

store 函數是 Field 類的方法,有 5 個:

其中 my_declimal 類型或者 MYSQL_TIME 等 MySQL 代碼內特有的類型,我們都可以通過引入相應的代碼來構建結構體。

注意當列被聲明為 MY_I_S_MAYBE_NULL 時,需要做一些額外的處理,見之前關于 st_field_info 結構體的介紹。

當 store 數據到 Field 結構體后,我們還需要將其存儲到表中,API 函數如下:

boolschema_table_store_record(THD *thd, TABLE *table);

其中 thd 為當前線程,table 為 tables- table

為了包含這兩個函數,我們需要引入如下頭文件:

#include mysql_priv.h

4) 使用 COND 進行優化

從 fill_table 的函數原型中,我們可以看到結構體 COND,這在 MySQL 層用作對條件進行記錄過濾,實際上在 plugin 里,我們可以直接進行過濾,只返回到 MYSQL 層需要的數據。如下圖所示:

如果你接觸過源代碼,會發現 COND 是一個相當復雜的類型,如果由我們自己編寫代碼來操作顯然要耗費大量的精力,我們可以依葫蘆畫瓢,找到源代碼里是如何使用該結構體的,構造相應的參數,就可以直接調用了,這也是 Plugin 的誘人之處,我們可以根據需求引用已有的代碼。

MySQL 層代碼大多定義在 sql 文件夾下,我們在編譯時指定相應的目錄即可。

當我們的操作對系統影響比較大時,需要盡快的得到結果,例如,內建的 I_S 表 COLUMNS,在填充數據時需要打開所有的表,如果在 Plugin 層做過濾,那么當我們找到一個不符合條件的表時,盡快關閉,而不是等到 MYSQL 層來過濾后關閉。

例如函數:

bool calc_lookup_values_from_cond(THD *thd,COND *cond, TABLE_LIST *table, LOOKUP_FIELD_VALUES *lookups);

其中 LOOPUP_FIEDL_VALUES 結構體為:

sql/sql_show.cc:

typedef struct st_lookup_field_values

{

LEX_STRING value1, value2;

bool value1_is_wildcard, value2_is_wildcard;

} LOOKUP_FIELD_VALUES;

這個函數用于處理等值的情況,函數將尋找類似 field1 = constant1 和 field2 = constant2 這樣的條件, 如果找到了,將被存儲在 LOOKUP_FIELD_VALUES 結構體的 value1 和 value2 中:

lookups.value1.str

lookups.value2.str

當我們找到了在 COND 中定義的條件后,就可以進行字符串匹配了。

該函數用于支持 INFORMATION_SCHEMA.TABLES, INFORMATION_ SCHEMA.COLUMNS, 和其他類型的內建 I_S 表,主要用來存儲表名和數據庫名,也就是說,value 值為 string 類型,并且只支持兩個等值操作,如果想實現更復雜的 cond 遍歷,我們需要自己來實現。

示例如下(參考自《mysql plugin development》):

view plain

#include mysql_priv.h  

/* 聲明相關的結構體和函數 */ 

typedef struct st_lookup_field_values 

LEX_STRING value1, value2; 

bool value1_is_wildcard,value2_is_wildcard; 

} LOOKUP_FIELD_VALUES; 

bool calc_lookup_values_from_cond(THD *thd,COND *cond, 

TABLE_LIST *table, LOOKUP_FIELD_VALUES*lookups); 

bool schema_table_store_record(THD *thd,TABLE *table); 

/* 定義列類型

* 包括一個整型和一個字符串型

*/ 

ST_FIELD_INFO cond_push_fields[] = 

{NUMBER ,10, MYSQL_TYPE_LONG, 0, 0, 0, 0}, 

{TEXT ,100, MYSQL_TYPE_STRING, 0, 0, 0, 0}, 

{0, 0,MYSQL_TYPE_NULL, 0, 0, 0, 0} 

int fill_cond_push(THD *thd, TABLE_LIST*tables, COND *cond) 

  /* 系統默認字符集:utf-8*/ 

CHARSET_INFO *cs= system_charset_info; 

TABLE *table =tables- table; 

/* 字符串數組 output,用于測試只返回符合條件的字符串 */ 

const char**ptr, *output[] = { hello , world , this , is , a , test , 0}; 

int num; 

/* 聲明變量 */ 

LOOKUP_FIELD_VALUESlookups; 

bzero((char*) lookups, sizeof(lookups)); 

/* 調用函數獲得 COND 中定義的條件 */ 

if (calc_lookup_values_from_cond(thd, cond, tables, lookups)) 

return 0; 

for (num = 0,ptr = output; *ptr; ptr++) 

if (lookups.value1.str  

my_strnncoll(cs, (const uchar*)*ptr, strlen(*ptr), 

(const uchar*)lookups.value1.str, 

lookups.value1.length)) 

continue; 

  /* 只有滿足條件的字符串才會被存儲到 table 中 */ 

table- field[0]- store(++num); 

table- field[1]- store(*ptr, strlen(*ptr), cs); 

if (schema_table_store_record(thd, table)) 

return 1; 

return 0; 

/* 初始化 i_s plugin*/ 

int cond_push_init(void *p) 

ST_SCHEMA_TABLE*schema = (ST_SCHEMA_TABLE*) p; 

/* 指定表定義 */ 

schema- fields_info= cond_push_fields; 

/* 指定記錄填充函數 */ 

schema- fill_table= fill_cond_push; 

schema- idx_field1= 1; 

return 0; 

struct st_mysql_information_schemacond_push= 

{MYSQL_INFORMATION_SCHEMA_INTERFACE_VERSION}; 

mysql_declare_plugin(cond_push) 

MYSQL_INFORMATION_SCHEMA_PLUGIN, 

cond_push, 

COND_PUSH , 

AndrewHutchings (Andrew.Hutchings@Sun.COM) , 

A simplecondition pushdown demo table , 

PLUGIN_LICENSE_GPL, 

cond_push_init, 

NULL, 

0x0010, 

NULL, 

NULL, 

NULL 

mysql_declare_plugin_end; 

5) 例子:獲取當前 query cache 中的 QUERY 信息(摘自網絡,略改)

Query_cache 中的 query 存儲在 query_cache- queries 結構體中,這是一個 hash 表,我們可以遍歷其中的記錄還獲得想要的數據,代碼如下:

view plain

#include stdlib.h  

#include ctype.h  

/* 內核中一些代碼定義在 MYSQL_SERVER 宏中 */ 

#ifndef MYSQL_SERVER 

#define MYSQL_SERVER 

#endif 

/*sql_cache.cc 中包含了全部跟 querycache 相關的代碼 */ 

#include sql_cache.cc  

#include mysql_priv.h  

#include mysql/plugin.h  

#include my_global.h  

#include mysql_version.h  

#include my_dir.h  

/* 創建一個子類,query_cache 的成員 queries 為私有變量

class Accessible_Query_Cache : privateQuery_cache {

public:

 HASH *get_queries()

  {

  return this- queries; // query_cache.queries;

  }

};

bool schema_table_store_record(THD *thd,TABLE *table);

#define MAX_STATEMENT_TEXT_LENGTH 32767

#define COLUMN_STATEMENT_ID 0

#define COLUMN_SCHEMA_NAME 1

#define COLUMN_STATEMENT_TEXT 2

#define COLUMN_RESULT_BLOCKS_COUNT 3

#define COLUMN_RESULT_BLOCKS_SIZE 4

#define COLUMN_RESULT_BLOCKS_SIZE_USED 5

/* 定義表結構 */ 

ST_FIELD_INFOmysql_is_cached_queries_fields[]= 

 {STATEMENT_ID , 21, MYSQL_TYPE_LONG, 0, 0, Id}, 

 {SCHEMA_NAME , 64, MYSQL_TYPE_STRING, 0, 0, Schema}, 

 {STATEMENT_TEXT , MAX_STATEMENT_TEXT_LENGTH,MYSQL_TYPE_STRING, 0, 0, Statment text}, 

 {RESULT_BLOCKS_COUNT , 21, MYSQL_TYPE_LONG, 0, 0, CountResult Blocks}, 

 {RESULT_BLOCKS_SIZE , 21, MYSQL_TYPE_LONGLONG, 0, 0, Size Result Blocks}, 

 {RESULT_BLOCKS_SIZE_USED , 21, MYSQL_TYPE_LONGLONG, 0, 0, Size Used Result Blocks}, 

  {0,0, MYSQL_TYPE_STRING, 0, 0, 0} 

}; 

/* 填充數據函數 */ 

static intmysql_is_cached_queries_fill_table(THD *thd, TABLE_LIST *tables, COND *cond) 

  intstatus; 

 CHARSET_INFO *scs= system_charset_info;  /* need this to store field into table */ 

 TABLE *table= (TABLE *)tables- table; 

 Accessible_Query_Cache *qc; 

 HASH *queries; 

 const uchar *query_cache_block_raw; 

 Query_cache_block* query_cache_block; 

 Query_cache_query* query_cache_query; 

 uint result_blocks_count; 

 ulonglong result_blocks_size; 

 ulonglong result_blocks_size_used; 

 Query_cache_block *first_result_block; 

 Query_cache_block *result_block; 

 const char *statement_text; 

 size_t statement_text_length; 

 const char *key; 

 size_t key_length; 

/* 引用 query_cache 全局變量 */ 

  qc= (Accessible_Query_Cache *) query_cache; 

/* 對 query_cache 加鎖 */ 

  query_cache.lock(); 

/* 獲取 hash*/ 

 queries = qc- get_queries(); 

  /* 遍歷 hash 中的所有記錄 /

  for(uint i= 0; i queries- records; i++)

  {

  /* 根據索引號獲取記錄 */ 

  query_cache_block_raw = hash_element(queries, i); 

  query_cache_block = (Query_cache_block*)query_cache_block_raw; 

query_cache_query= query_cache_block- query(); 

  table- field[COLUMN_STATEMENT_ID]- store(i+1, 0); 

  /* 獲取 sql 語句 */ 

  statement_text = (const char*)query_cache_query- query(); 

  statement_text_length = strlen(statement_text); 

/* 當超出長度時需要截斷 hellip;*/ 

  table- field[COLUMN_STATEMENT_TEXT]- store(  (char*)statement_text 

   ,statement_text_length MAX_STATEMENT_TEXT_LENGTH? 

MAX_STATEMENT_TEXT_LENGTH 

  :statement_text_length 

  , scs 

  ); 

  /* 獲取該查詢的 key*/ 

  key = (const char*)query_cache_query_get_key(  query_cache_block_raw 

  , key_length  , 0 ); 

key_length =strlen(key+statement_text_length+1)-1; 

  /* 數據庫名是 key 的一部分,適當的偏移 key 指針可以得到數據庫名 */ 

  table- field[COLUMN_SCHEMA_NAME]- store((char*)key+statement_text_length+1 

  , key_length 

  ,scs  ); 

  /* 獲得結果集所占塊的個數 */ 

  first_result_block= query_cache_query- result(); 

  if(first_result_block) 

  { 

  /* initialize so we can loop over the result blocks*/ 

  result_block= first_result_block; 

  result_blocks_count = 1; 

  result_blocks_size = result_block- length; 

  result_blocks_size_used = result_block- used; 

  /* loop over the result blocks*/ 

  while((result_block= result_block- next)!=first_result_block) 

  { 

  /* calculate total number of result blocks */ 

  result_blocks_count++; 

  /* calculate total size of result blocks */ 

  result_blocks_size += result_block- length; 

  /* calculate total of used size of result blocks */ 

  result_blocks_size_used += result_block- used; 

  } 

  } 

  else 

  { 

  result_blocks_count = 0; 

  result_blocks_size = 0; 

  result_blocks_size_used = 0; 

  } 

  /* 存儲塊的個數 */ 

  table- field[COLUMN_RESULT_BLOCKS_COUNT]- store(result_blocks_count ,0); 

  /* 存儲總的所占有塊的大小 */ 

  table- field[COLUMN_RESULT_BLOCKS_SIZE]- store(result_blocks_size  , 0); 

  /* 存儲總的已使用塊的大小 */ 

  table- field[COLUMN_RESULT_BLOCKS_SIZE_USED]- store(result_blocks_size_used , 0); 

  /* 將記錄存儲到表中 */ 

  status = schema_table_store_record(thd, table); 

  if (status) { 

  status= 1; 

  goto cleanup; 

  } 

 status = 0; 

cleanup: 

  query_cache.unlock(); 

 return status; 

static intmysql_is_cached_queries_plugin_init(void *p) 

 ST_SCHEMA_TABLE *schema= (ST_SCHEMA_TABLE *)p; 

 schema- fields_info= mysql_is_cached_queries_fields; 

 schema- fill_table= mysql_is_cached_queries_fill_table; 

 return 0; 

static int mysql_is_cached_queries_plugin_deinit(void*p) 

  return0; 

struct st_mysql_information_schemamysql_is_cached_queries_plugin= 

{MYSQL_INFORMATION_SCHEMA_INTERFACE_VERSION}; 

/*

 Plugin library descriptor

*/ 

mysql_declare_plugin(mysql_is_cached_queries) 

 MYSQL_INFORMATION_SCHEMA_PLUGIN, 

  mysql_is_cached_queries_plugin, 

  MYSQL_CACHED_QUERIES , 

  Roland Bouman , 

  Lists all queries in the query cache. , 

 PLUGIN_LICENSE_GPL, 

 mysql_is_cached_queries_plugin_init, /* Plugin Init */ 

 mysql_is_cached_queries_plugin_deinit, /* Plugin Deinit */ 

 0x0010 /* 1.0 */, 

 NULL,  /*status variables  */ 

 NULL,  /*system variables  */ 

 NULL  /*config options  */ 

mysql_declare_plugin_end; 

view plain

/pre pre name= code >

view plain

看完上述內容,你們掌握 MySQL 中如何編寫 Information Schema Plugin 的方法了嗎?如果還想學到更多技能或想了解更多相關內容,歡迎關注丸趣 TV 行業資訊頻道,感謝各位的閱讀!

正文完
 
丸趣
版權聲明:本站原創文章,由 丸趣 2023-07-28發表,共計9338字。
轉載說明:除特殊說明外本站除技術相關以外文章皆由網絡搜集發布,轉載請注明出處。
評論(沒有評論)
主站蜘蛛池模板: 依安县| 克什克腾旗| 荣昌县| 抚松县| 泸溪县| 徐闻县| 孝昌县| 巧家县| 余姚市| 遂宁市| 泊头市| 富裕县| 绥德县| 探索| 崇左市| 陆良县| 茂名市| 马关县| 平和县| 隆化县| 青岛市| 侯马市| 西乌珠穆沁旗| 宣恩县| 临泉县| 凤台县| 喀喇沁旗| 南宫市| 黄骅市| 济南市| 肇源县| 桐柏县| 潜山县| 冷水江市| 上饶市| 大城县| 修文县| 即墨市| 利津县| 纳雍县| 富蕴县|