您好,欢迎访问一九零五行业门户网

InnoDB Memcached Plugin源码实现调研

背景 mysql 5.6版本,新增了一个nosql的接口,通过将memcached嵌入到mysql系统之中,用户可以直接使用memcached接口直接操作mysql中的innodb表,绕过mysql server层面的sql解析,优化,甚至绕过innodb handler层,直接操作innodb内部的方法,从而达到更优的
背景
mysql 5.6版本,新增了一个nosql的接口,通过将memcached嵌入到mysql系统之中,用户可以直接使用memcached接口直接操作mysql中的innodb表,绕过mysql server层面的sql解析,优化,甚至绕过innodb handler层,直接操作innodb内部的方法,从而达到更优的响应时间与效率。关于此功能的官方介绍,请见:innodb integration with memcached 。嵌入memcached之后,整个mysql的架构如下图所示:
本文接下来的部分,将从源码的角度,详细分析innodb integration with memcached的实现细节问题。
导读
innodb引擎为了支持memcached api,在handler层面进行的改动,请见(一);
memcached plugin的初始化流程,请见(二);innodb提供的callback方法在innodb handlerton中的data中以及memcached plugin的data中,是如何传递的呢?请见(三);innodb memcached engine提供的方法集合,请见(四);innodb memcached engine提供的方法,如何调用到innodb engine提供的方法,请见(五);innodb memcached engine中,存在两个engine实例:innodb engine vs default engine,二者的功能异同,请见(六);innodb memcached engine中,需要配置container table,container表详解,请见(七);innodb memcached engine的初始化与使用流程,可参考engine_testapp.c测试文件;(一) innodb handler层面改动
innodb为了支持memcached接口,在其handler层面提供了新的callback方法,这些方法的定义如下:
/** set up innodb api callback function array */
ib_cb_t innodb_api_cb[] = {
(ib_cb_t) ib_cursor_open_table,
(ib_cb_t) ib_cursor_read_row,
(ib_cb_t) ib_cursor_insert_row,
(ib_cb_t) ib_cursor_delete_row,
(ib_cb_t) ib_cursor_update_row,
(ib_cb_t) ib_cursor_next,
(ib_cb_t) ib_cursor_last,
(ib_cb_t) ib_tuple_get_n_cols,
(ib_cb_t) ib_col_set_value,
(ib_cb_t) ib_col_get_value,
(ib_cb_t) ib_col_get_meta,
(ib_cb_t) ib_trx_begin,
(ib_cb_t) ib_trx_commit,
(ib_cb_t) ib_trx_rollback,
(ib_cb_t) ib_trx_start,

};
同时,innodb_api_cb[]数组,被存储在innodb handlerton的data字段中,可以向上传递给innodb memcached engine。innodb memcached engine可以调用这些callback方法,达到直接操作innodb engine的目的。
ha_innodb.cc::innobase_init();

innobase_hton->data = &innodb_api_cb;
(二) memcached plugin的初始化流程
memcached plugin,同样注册为mysql的一个插件(memcached_mysql.cc),此插件的定义如下:
mysql_declare_plugin(daemon_memcached)
{
mysql_daemon_plugin,
&daemon_memcached_plugin,
”daemon_memcached”,
”oracle corporation”,
”memcached daemon”,
plugin_license_gpl,
daemon_memcached_plugin_init,/* plugin init */
daemon_memcached_plugin_deinit,/* plugin deinit */
0×0100 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?/* 1.0 */,
null, ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? /* status variables */
daemon_memcached_sys_var, ? ? ? ? ? ? ?/* system variables */
null ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?/* config options */
}
mysql_declare_plugin_end;
memcached plugin插件,初始化为daemon_memcached_plugin_init函数,该函数同样需要一个handlerton输入,初始化memcached plugin插件,尤其是初始化innodb memcached engine。详细的初始化流程如下所示:
struct mysql_memcached_context * con;
// plugin为innodb的handlerton,plugin->data指向innodb handlerton中的data,
// 在innodb的init函数中被初始化为innodb_api_cb数组。innodb_api_cb数组中,
// 注册了各种innodb提供的方法。

con->memcached_conf.m_innodb_api_cb = plugin->data;

// 创建memcached plugin后台线程,线程的主函数为daemon_memcached_main(),
// 线程传入参数,即为从innodb handlerton处获取的innodb提供的callback方法
pthread_create(&con->memcached_thread, &attr,
daemon_memcached_main, (void *)&con->memcached_conf);

// 创建、加载innodb memcached engine
engine_loader.c::load_engine();
// create innodb memcached engine
// 注册innodb memcached engine的各种方法,例如:
// 初始化方法:innodb_eng->engine.initialize = innodb_initialize;
innodb_engine.c::create_instance();

// 初始化innodb memcached engine
engine_loader.c::init_engine(engine_handle,engine_config…);
innodb_engine.c::innodb_initialize(engine, config_str);
// 注册innodb engine提供的内部方法至innodb memcached engine,
// 包括:读取、插入、删除、更新、事务创建/提交/回滚等操作。
// 至此,后续的innodb memcached engine的所有操作,均可被映射
// 为innodb storage engine提供的内部方法进行实际操作。
innodb_api.c::register_innodb_cb();
// fetch innodb specific settings
innodb_eng->meta_info = innodb_config(null, 0, &innodb_eng->meta_hash);
// find the table and column info that used for memcached data
// cantainers表:innodb内部存储元数据的系统表,
// mci_cfg_db_name;mci_cfg_container_table;…
innodb_config.c::innodb_config_container();

// 开启innodb memcached engine的后台自动提交线程
innodb_engine.c::innodb_bk_thread();


// 在innodb handlerton中存储更多memcached plugin所需要的信息
plugin->data = (void *)con;
(三) memcached plugin如何获取使用innodb handlerton中的innodb_api_cb?
// 在此函数中完成innodb_api_cb的传递
sql_plugin.cc::plugin_initialize();
// 此函数指针,直接调用到plugin注册的init方法
(*plugin_type_initialize[plugin->plugin->type])(plugin);

// 判断出当前是innodb引擎完成了初始化,则将innodb handlerton中
? ? // 的data拷贝到临时变量中
if (strcmp(plugin->name.str, “innodb”) == 0)
innodb_callback_data = ((handlerton *)plugin->data)->data;
// 判断出当前plugin为memcached plugin,则将临时变量赋值到memcached plugin
? ? // 的data中,完成innodb handlerton提供的callback方法的传递
else if (plugin->plugin->init)
if (strcmp(plugin->name.str, “daemon_memcached”) == 0)
plugin->data = (void *)innodb_callback_data;
// 初始化memcached plugin
plugin->plugin->init();
(四) innodb memcached plugin提供的方法集合
innodb_engine.c::create_instance();
innodb_eng->engine.interface.interface = 1;
innodb_eng->engine.get_info = innodb_get_info;
innodb_eng->engine.initialize = innodb_initialize;
innodb_eng->engine.destroy = innodb_destroy;
innodb_eng->engine.allocate = innodb_allocate;
innodb_eng->engine.remove = innodb_remove;
innodb_eng->engine.release = innodb_release;
innodb_eng->engine.clean_engine= innodb_clean_engine;
innodb_eng->engine.get = innodb_get;
innodb_eng->engine.get_stats = innodb_get_stats;
innodb_eng->engine.reset_stats = innodb_reset_stats;
innodb_eng->engine.store = innodb_store;
innodb_eng->engine.arithmetic = innodb_arithmetic;
innodb_eng->engine.flush = innodb_flush;
innodb_eng->engine.unknown_command = innodb_unknown_command;
innodb_eng->engine.item_set_cas = item_set_cas;
innodb_eng->engine.get_item_info = innodb_get_item_info;
innodb_eng->engine.get_stats_struct = null;
innodb_eng->engine.errinfo = null;
innodb_eng->engine.bind = innodb_bind;
所有innodb memcached engine提供的方法,都是类memcached方法。例如:get/remove/store方法等。
(五) 一个innodb memcached plugin的操作的流程
通过memcached plugin进行一个删除操作的函数处理流程,如下:
注1:删除操作,对应的innodb handlerton提供的方法为:remove()
注2:删除操作,对应的innodb memcached engine的方法为:ib_cursor_delete_row()
// 通过memcached接口删除操作的处理流程
memcached.c::process_delete_command();
settings.engine.v1->remove(settings.engine.v0, c, key, nkey, 0, 0);
// innodb memcached engine层面提供的删除方法
innodb_engine.c::innodb_remove(engine_handle*, cookie, key, nkey, …);

// 初始化innodb的连接,传入参数分析:
// conn_mode_write:当前为写操作
// ib_lock_x:当前操作需要对记录行加x锁
conn_data = innodb_conn_init(innodb_eng, cookie, conn_mode_write, …);
if (conn_option == conn_mode_write)
// 开始一个事务
innodb_api.c::innodb_cb_trx_begin();
ib_cb_trx_begin() -> api0api.cc::ib_trx_begin();
// 打开当前表,并设置游标
innodb_api.c::innodb_api_begin();

// 进行真正的删除操作
innodb_api.c::innodb_api_delete(innodb_eng, conn_data, key, nkey);
// 根据传入的key,将游标定位到正确的位置
innodb_api.c::innodb_api_search();

// 如果开启了binlog,则需要将定位到的记录拷贝出来
if (engine->enable_binlog)

// 删除记录
ib_cb_delete_row() -> api0api.cc::ib_cursor_delete_row();
// 记录binlog
handler_api.cc::handler_binlog_row();
// 删除构造出来的tuple对象
ib_cb_tuple_delete() -> api0api.cc::ib_tuple_delete();
(六) innodb engine vs default engine
在innodb engine结构的内部(innodb_engine.h::struct innodb_engine),有两个实例化的engine handle,分别为:
engine_handle_v1engine;
engine_handle*default_engine;
两个engine handle有何区别:
engine_handle_v1为innodb engine handle,封装了所有innodb引擎提供的方法;
engine_handle(default_engine)为memcached自带的默认engine,封装了所有标准memcached所提供的方案,包括:slab分配,数据的存取、失效等等。
innodb engine与default engine是否启用?是否同时启用?通过参数控制:
/** tells if we will used memcached default engine or innodb memcached engine to handle the request */
typedef enum meta_cache_opt {
meta_cache_opt_innodb = 1,/*!
meta_cache_opt_default, ? ? ? ? ? ? /*!
meta_cache_opt_mix, ? ? ? ? ? ? ? ? ? ? ? ?/*!
meta_cache_opt_disable, ? ? ? ? ? ? ? /*!
meta_cache_num_opt ? ? ? ? ? ? ? ? ? ? ? ?/*!
} meta_cache_opt_t;
默认的参数值为meta_cache_opt_innodb,仅仅启用innodb engine,数据通过innodb引擎提供的callback方法操作;若同时启用了memcached default engine(meta_cache_opt_mix),那么数据读取时,首先从default engine中读取;记录删除时,也需要先删除default engine中的记录;
(七) container表详解
innodb memcached engine,包含一个container table,用于存储memcached与innodb table之间的映射关系。
container table,必须包含9列,分别是:
/** columns in the “containers” system table, this maps the memcached
operation to a consistent innodb table */
typedef enum container {
container_name, ? ? ? ? /*!
container_db, ? ? ? ? ? ? ? ?/*!
container_table,/*!
container_key, ? ? ? ? ? ? /*!
container_value, ? ? ? /*!
container_flag, ? ? ? ? ?/*!
container_cas, ? ? ? ? ? ? /*!
container_exp, ? ? ? ? ? ? /*!
container_num_cols/*!
} container_t;
其中:
container_table为innodb表名,container_db为对应的database名;
container_key为memcached的key对应的innodb表中的列名(只能一列);
container_value为memcached的value对应的innodb表中的列名(可以有多列,以” ;,|\n”作为分隔符,详见innodb_config.c::innodb_config_parse_value_col()函数);
container table的最后一列,为container_key列对应的innodb表的唯一索引名(必须存在);
container table,在innodb_engine.cc::innodb_initialize函数被读取,将其中的每一项都解析并存储到innodb engine的meta_hash结构之中:
innodb_config.c::innodb_config(null, 0, &innodb_eng->meta_hash);
innodb_config_meta_hash_init();

// 打开container table
innodb_api.c::innodb_api_begin(…, mci_cfg_container_table, …);
innodb_api.c::innodb_cb_read_row();
innodb_config.c::innodb_config_add_item();

// 针对value列,需要解析此列对应于innodb table的哪些列
// innodb中的不同列,以” ;,|\n”作为分隔符
if (i == container_value)
innodb_config_parse_value_col();

在innodb_engine.cc::innodb_initialize函数,完成container table的读取以及meta hash的填充之后,后续的memcached方法,才可以根据规则操作,完成记录在memcached与innodb引擎间的传递。
背景   mysql 5.6版本,新增了一个nosql的接口,通过将memcached嵌入到mysql系统之中,用户可以直接使用memcached接口直接操作mysql中的innodb表,绕过mysql server层面的sql解析,优化,甚至绕过innodb handler层,直接操作innodb内部的方法,从而达到更优的响应时间与效率。关于此功能的官方介绍,请见:innodb integration with memcached 。嵌入memcached之后,整个mysql的架构如下图所示:     本文接下来的部分,将从源码的角度,详细分析innodb integration with memcached的实现细节问题。   导读   innodb引擎为了支持memcached api,在handler层面进行的改动,请见(一); memcached plugin的初始化流程,请见(二);   innodb提供的callback方法在innodb handlerton中的data中以及memcached plugin的data中,是如何传递的呢?请见(三);   innodb memcached engine提供的方法集合,请见(四);   innodb memcached engine提供的方法,如何调用到innodb engine提供的方法,请见(五);   innodb memcached engine中,存在两个engine实例:innodb … 继续阅读 →
其它类似信息

推荐信息