热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

从源码角度看MySQLmemcachedplugin——1.系统结构和引擎初始化

本章尝试回答两个问题:一、memcachedplugin与MySQL的关系;二、MySQL系统如何启动memcachedplugin。1.memcachedplugin与MySQL的关

本章尝试回答两个问题:
一、memcached plugin与MySQL的关系;
二、MySQL系统如何启动memcached plugin。

1. memcached plugin与MySQL的关系

该图是从MySQL官方文档里对memcached的介绍图片。从图中可以看出,memcached的结构是由三个部份组成:memcached plugin、innodb_memcached和Innodb API。

在源码中,memcached plugin部份的代码会被编译成libmemcached.so;innodb_memcache和InnoDB API会被编译成innodb_engine.so。

memcached plugin层通过一组回调函数调用libmemcached.so提供的接口实现为App服务。

InnoDB API层同样也是通过一组回调函数调用InnoDB层的接口实现,功能类似于图中左侧的Handler API。而innodb_memcache通过包装这组回调函数为memcached plugin提供接口实现。

2. MySQL系统如何启动memcached plugin

在MySQL中,InnoDB存储引擎和memcached都是以插件的形式实现。memcached最底层的回调函数是由InnoDB存储引擎提供,于是在插件初始化的顺序上是InnoDB插件先于memcached插件。

InnoDB存储引擎插件调用plugin_initialize函数初始化时将一组回调函数数组的地址传给全局指针变量innodb_callback_data。memcached引擎插件调用plugin_initialize函数初始化时将innodb_callback_data作为自己的参数传入。

插件初始化使用的函数plugin_initialize的函数原型是int plugin_initialize(st_plugin_int *plugin);
参数类型为st_plugin_int的结构体。MySQL使用该结构体描述一个插件。其中有两个变量,data和plugin。plugin变量存放了插件的init和deinit回调函数,这是插件初始化时真实调用的函数;data作为plugin中的回调函数的参数存在。

int plugin_initialize(st_plugin_int *plugin);

/* A handle of a plugin */
struct st_plugin_int
{
  ...
  st_mysql_plugin *plugin;
  void *data;                   /* plugin type specific, e.g. handlerton */
  ...
};

struct st_mysql_plugin
{
  ...
  int (*init)(MYSQL_PLUGIN);  /* the function to invoke when plugin is loaded */
  int (*deinit)(MYSQL_PLUGIN);/* the function to invoke when plugin is unloaded */
  ...
};

3.1 InnoDB如何将回调函数传给全局变量innodb_callback_data

InnoDB层提供的回调函数是个数组,数组名为innodb_api_cb。

ib_cb_t innodb_api_cb[] = {
    (ib_cb_t) ib_cursor_open_table,
    ...
};

在plugin_initialize函数里,调用plugin->plugin->init函数(innobase_init函数)。如上图:

  1. 将innodb_api_cb数组的地址赋值到在plugin->data->data中。
  2. 将plugin->data->data赋值到innodb_callback_data。

到此可以看到innodb_callback_data已经指向了一个回调函数数组的地址。

3.2 memcached如何将innodb_callback_data赋值给innodb_engine.so中的回调函数

初始化memcached插件同样调用的是plugin_initialize函数,将innodb_callback_data赋值给plugin->data之后,调用plugin->plugin->init函数(daemon_memcached_plugin_init函数)。

完成了插件初始化的基本操作之后,开启一个新的线程daemon_memcached_main,这个线程是memcached插件系统的daemon线程。

void daemon_memcached_main(memcached_context_t* p);

struct memcached_context
{
    char*       m_engine_library;
    char*       m_mem_option;
    void*       m_innodb_api_cb;
    unsigned int    m_r_batch_size;
    unsigned int    m_w_batch_size;
    bool        m_enable_binlog;
};

在开启线程daemon_memcached_main之前,会将plugin->data(innodb_callback_data)赋值给p->m_innodb_api_cb。

daemon_memcached_main在进入守护状态之前,还有两个重要的操作要做,分别是load engine和init engine函数。而这两个函数分别做了什么?

  1. load engine: 连接libmemcached.so的回调函数与innodb_engine.so的实现。
  2. init engine: 连接innodb_engine.so的innodb_callback_API的回调函数与InnoDB层的实现。

3.2.1 load engine

load_engine(engine, get_server_api,settings.extensions.logger,
 &engine_handle);

load_engine的函数原型如上。在这个过程中,会load两个引擎。一个innodb_engine,一个是default_engine。
过程如下:

  1. 调用dlopen打开innodb_engine.so。
  2. 调用dlsym函数获得create_instance函数的地址。
  3. 调用create_instance,malloc一个struct innodb_engine的结构体innodb_engine,为innodb_engine回调函数赋值。
  4. 调用create_instance|create_my_default_instance为默认引擎的回调函数赋值。

load engine之后,lib_memcached.so中的回调函数会被赋值,实现是在innodb_engine.so中。

InnoDB Engine与Default Engine是否启用?是否同时启用?

/** Cache options, 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_INNODB,仅仅启用InnoDB Engine,数据通过InnoDB引擎提供的Callback方法操作;若同时启用了Memcached Default Engine(META_CACHE_OPT_MIX),那么数据读取时,首先从Default Engine中读取;记录删除时,也需要先删除Default Engine中的记录。

3.3.2 init engine

init engine调用的函数是

innodb_eng->engine.v1->initialize

实际上调用的是实现在在innodb_engine.so的innodb_initialize函数。

在这个innodb_initialize函数中调用register_innodb_cb函数为innodb_memcached_api数组赋值。两个数组的指针顺序要一一对应。

innnodb_memcached_api数组是innodb_engine.so中调用innodb层操作的回调函数数组。

以下这图是这个过程中innodb的函数指针一路传递到memcached的innodb_engine.so中的函数指针的过程。


推荐阅读
  • 先看官方文档TheJavaTutorialshavebeenwrittenforJDK8.Examplesandpracticesdescribedinthispagedontta ... [详细]
  • JDK源码学习之HashTable(附带面试题)的学习笔记
    本文介绍了JDK源码学习之HashTable(附带面试题)的学习笔记,包括HashTable的定义、数据类型、与HashMap的关系和区别。文章提供了干货,并附带了其他相关主题的学习笔记。 ... [详细]
  • 本文介绍了设计师伊振华受邀参与沈阳市智慧城市运行管理中心项目的整体设计,并以数字赋能和创新驱动高质量发展的理念,建设了集成、智慧、高效的一体化城市综合管理平台,促进了城市的数字化转型。该中心被称为当代城市的智能心脏,为沈阳市的智慧城市建设做出了重要贡献。 ... [详细]
  • 计算机存储系统的层次结构及其优势
    本文介绍了计算机存储系统的层次结构,包括高速缓存、主存储器和辅助存储器三个层次。通过分层存储数据可以提高程序的执行效率。计算机存储系统的层次结构将各种不同存储容量、存取速度和价格的存储器有机组合成整体,形成可寻址存储空间比主存储器空间大得多的存储整体。由于辅助存储器容量大、价格低,使得整体存储系统的平均价格降低。同时,高速缓存的存取速度可以和CPU的工作速度相匹配,进一步提高程序执行效率。 ... [详细]
  • Java在运行已编译完成的类时,是通过java虚拟机来装载和执行的,java虚拟机通过操作系统命令JAVA_HOMEbinjava–option来启 ... [详细]
  • 深入理解Kafka服务端请求队列中请求的处理
    本文深入分析了Kafka服务端请求队列中请求的处理过程,详细介绍了请求的封装和放入请求队列的过程,以及处理请求的线程池的创建和容量设置。通过场景分析、图示说明和源码分析,帮助读者更好地理解Kafka服务端的工作原理。 ... [详细]
  • 微软头条实习生分享深度学习自学指南
    本文介绍了一位微软头条实习生自学深度学习的经验分享,包括学习资源推荐、重要基础知识的学习要点等。作者强调了学好Python和数学基础的重要性,并提供了一些建议。 ... [详细]
  • LeetCode笔记:剑指Offer 41. 数据流中的中位数(Java、堆、优先队列、知识点)
    本文介绍了LeetCode剑指Offer 41题的解题思路和代码实现,主要涉及了Java中的优先队列和堆排序的知识点。优先队列是Queue接口的实现,可以对其中的元素进行排序,采用小顶堆的方式进行排序。本文还介绍了Java中queue的offer、poll、add、remove、element、peek等方法的区别和用法。 ... [详细]
  • 本文讨论了使用差分约束系统求解House Man跳跃问题的思路与方法。给定一组不同高度,要求从最低点跳跃到最高点,每次跳跃的距离不超过D,并且不能改变给定的顺序。通过建立差分约束系统,将问题转化为图的建立和查询距离的问题。文章详细介绍了建立约束条件的方法,并使用SPFA算法判环并输出结果。同时还讨论了建边方向和跳跃顺序的关系。 ... [详细]
  • 本文介绍了解决二叉树层序创建问题的方法。通过使用队列结构体和二叉树结构体,实现了入队和出队操作,并提供了判断队列是否为空的函数。详细介绍了解决该问题的步骤和流程。 ... [详细]
  • 本文介绍了Web学习历程记录中关于Tomcat的基本概念和配置。首先解释了Web静态Web资源和动态Web资源的概念,以及C/S架构和B/S架构的区别。然后介绍了常见的Web服务器,包括Weblogic、WebSphere和Tomcat。接着详细讲解了Tomcat的虚拟主机、web应用和虚拟路径映射的概念和配置过程。最后简要介绍了http协议的作用。本文内容详实,适合初学者了解Tomcat的基础知识。 ... [详细]
  • 本文介绍了在使用Python中的aiohttp模块模拟服务器时出现的连接失败问题,并提供了相应的解决方法。文章中详细说明了出错的代码以及相关的软件版本和环境信息,同时也提到了相关的警告信息和函数的替代方案。通过阅读本文,读者可以了解到如何解决Python连接服务器失败的问题,并对aiohttp模块有更深入的了解。 ... [详细]
  • 前景:当UI一个查询条件为多项选择,或录入多个条件的时候,比如查询所有名称里面包含以下动态条件,需要模糊查询里面每一项时比如是这样一个数组条件:newstring[]{兴业银行, ... [详细]
  • 本文讨论了clone的fork与pthread_create创建线程的不同之处。进程是一个指令执行流及其执行环境,其执行环境是一个系统资源的集合。在调用系统调用fork创建一个进程时,子进程只是完全复制父进程的资源,这样得到的子进程独立于父进程,具有良好的并发性。但是二者之间的通讯需要通过专门的通讯机制,另外通过fork创建子进程系统开销很大。因此,在某些情况下,使用clone或pthread_create创建线程可能更加高效。 ... [详细]
  • Java中包装类的设计原因以及操作方法
    本文主要介绍了Java中设计包装类的原因以及操作方法。在Java中,除了对象类型,还有八大基本类型,为了将基本类型转换成对象,Java引入了包装类。文章通过介绍包装类的定义和实现,解答了为什么需要包装类的问题,并提供了简单易用的操作方法。通过本文的学习,读者可以更好地理解和应用Java中的包装类。 ... [详细]
author-avatar
手机用户2502883075
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有