Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >在 libevent 中使用 MariaDB(MySQL)

在 libevent 中使用 MariaDB(MySQL)

原创
作者头像
amc
修改于 2018-09-27 01:53:15
修改于 2018-09-27 01:53:15
2.5K0
举报
文章被收录于专栏:后台全栈之路后台全栈之路

在之前我翻译的官方文档中提到了 MariaDB 提供了对异步 I/O 的支持。那篇文章是一个比较简要的介绍。不过实际适配中,官方也提供了一个完整适配 libevent 的示例代码。本文算是对我上述示例代码的阅读笔记吧。

阅读本文之前,作者假设读者已经有了 libevent 的相关知识。如果没有的话,可以参见我的系列文章:

此外本文内容也适合其他的异步 I/O 库,如:


基本流程

传统的 MySQL client 在请求 DB 查询的时候,API 调用流程为:

代码语言:txt
AI代码解释
复制
mysql_real_connect()
mysql_real_query()
mysql_use_result()
mysql_fetch_row()
mysql_close()

不过,在异步 socket 模型中,根据官方介绍文档中也提及了,对于会产生阻塞的函数调用 XXX,需要分开 XXX_start()XXX_cont() 进行调用。上述流程中,除了 mysql_use_result() 不是阻塞调用之外,其他的函数均需要如此区分。


流程状态图

异步服务器经常是以状态图模式进行设计开发的,官方 demo 是基于 libevent 设计的,也一样。下面是简化版的流程装态图(流程图 + 状态图):

上图主要是正常流程,异常流程暂未列出。实线表示该状态的流转需要经过异步 I/O 等待(libevent 调用 event_add())后才能获取相应的状态码或返回值进行检查后才可以进行的状态流转,虚线表示在该状态下即已有足够的变量可进行状态流转。


详细流程

Connect 阶段

该阶段包含三个状态,其中两个状态分别是 mysql_real_connect_start()mysql_real_connect_cont() 函数的调用状态。这两个函数之间的流转,后文 “阻塞函数改造” 小节中再做说明。

mysql_real_connect 系列函数返回 status == 0 之后,程序就可以流转到该阶段的第三个状态,在代码中的状态码是 9。这个状态中,程序只进行异常判断,如果正常,则流转至下一流程 query 阶段。如果在状态 9 检测到异常,程序中直接调用 exit() ,因此可以认为这个状态极少出错。当然对于正式的程序,还是需要捕捉这个错误的。

Query 阶段

该阶段包含两个状态,分别是 mysql_real_query_start()mysql_real_query_cont() 函数的调用状态。这两个状态的代码就是非常典型的 _start + _cont 阶段。后文将会说明相关内容。

另外,在 mysql_real_query_start() 处,还会检查当前是否有新的查询请求。如果没有请求,则会直接进入 close 阶段。这与普通的 MySQL 流程无异,因此不展开讲。

Use Result 阶段

这个阶段调用的是 muysql_use_result() 函数。由于该函数不是阻塞函数,因此该阶段只需要一个状态,并且状态的流转不需要等待,直接流转即可。

Fetch Row 阶段

该阶段向数据库获取结果的行,同样有相应的 _start()_cont() 状态,这两个阶段同样后文再讲述。在 _cont() 状态中如果 status 值为 0,则直接进入 39 状态使用获得的数据进行操作。

39 状态中,如果数据未获取完,则继续回到该阶段的 _start() 状态;如果当前叉裙已经结束,则回到 query 阶段。

Close 阶段

如前文所述,该阶段的入口是从 query 阶段而来。和普通的 socket close 不同,MySQL client 的 close 操作是阻塞的,需要将这个阶段的代码改造成异步模式。和 query 阶段类似,该阶段只需要 _start()_cont() 两个状态即可

Exit 阶段

这个阶段其实不是 MySQL 的请求流程之一,而是整个应用程序的流程阶段。在这个阶段,应用程序需要调用其所使用的异步 I/O 框架的退出机制。对于 libevent,则是 event_loopbreak()


阻塞函数改造

状态机函数

上文所提及的几个阶段中,有四个阶段是对原有阻塞函数的改造,需要将阻塞函数分为同名的 _start()_cont() 两个函数。以 mysql_real_connect() 函数为例,该函数需要改造为 mysql_real_connect_start()mysql_real_connect_cont() 两个函数。其中 _start 发起流程,而 _cont 表示 “continue”,则是处理异步 I/O 过程中的一些(不需要程序员关心)的中间状态,同时判断异步 I/O 是否已经完成。

这里需要的两个函数分别是:

代码语言:txt
AI代码解释
复制
// 仅声明异步改造的关键变量

// _start 状态
int status;
MYSQL mysql;
MYSQL *mysql_ret;
status = mysql_real_connect_start(&mysql_ret, host, user, passwd, db_name, port, unix_sock, 0);

// _cont 状态
int status;
MYSQL mysql;
MYSQL *mysql_ret;
status = mysql_real_connect_cont(&mysql_ret, &MYSQL, _libevent_to_mysql_status(libevent_what));

// _libevent_to_mysql_status 转换函数
static int _libevent_to_mysql_status(short event)
{
    int status= 0;
    if (event & EV_READ)
        status|= MYSQL_WAIT_READ;
    if (event & EV_WRITE)
        status|= MYSQL_WAIT_WRITE;
    if (event & EV_TIMEOUT)
        status|= MYSQL_WAIT_TIMEOUT;
    return status;
}

其中 start 函数的后七个参数,与原本 mysql_real_query 相同。而第一个参数 &mysql_ret ,则替代了原函数的返回值的作用。而 _start() 函数的返回值,则换成一个 int 类型的变量,用于适配异步 I/O。该 int 变量是一个位掩码变量,与 libevent 事件回调函数中的 short what 变量的位掩码一一对应(参见上文 _libevent_to_mysql_status() 函数,等同于官方 demo 中的 mysql_status() 函数)

状态机流转

状态机中写好了基本的调用函数之后,接下来就需要判断状态机的流转条件了。参见下图:

流转条件集中针对两个 “返回值” 的状态进行流转:

  • 异步 MySQL API 的 int 类型返回值 status:如果返回零,则表示当前操作正常完成,可走入下一步;如果非零,则表示下一步需要的事件掩码,在 _cont() 函数上继续等待
  • 原阻塞函数的返回值,也即异步 API 的第一个参数:处理方式以原阻塞式函数的处理方式相同。

转换为 libevent 掩码

状态流转时,如果需要等待 I/O 操作,那么需要使用异步 I/O 框架的事件函数进行操作。在 MySQL 异步 API 中,其状态值与 libevent 的掩码值是一一对应的。在前文 _libevent_to_mysql_status() 函数中已经体现了,对应关系如下:

类型

含义

MySQL 值或类型

libevent 值或类型

位掩码

读事件

MYSQL_WAIT_READ

EV_READ

位掩码

写事件

MYSQL_WAIT_WRITE

EV_WRITE

位掩码

超时时间

MYSQL_WAIT_TIMEOUT

EV_TIMEOUT

变量

socket 文件描述符

mysql_get_socket(&mysql)

evutil_socket_t fd

变量

超时事件

mysql_get_timeout_value(&mysql)

struct timeval

有了上述对应关系,已经足以将 MySQL 的变量转为 event_set()event_add() 函数调用了。

这样,一个完整的基于异步 I/O 框架的 MySQL client 过程,就建立起来了。


完整状态图

下面附上完整的状态图,能够更加直观地浏览整个异步状态:


参考资料


本文章采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。

原文发布于:https://cloud.tencent.com/developer/article/1346966

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
在 C/C++ 异步 I/O 中使用 MariaDB 的非阻塞接口
对 C/C++,MySQL 提供的库传统上都是阻塞操作,因此适合多线程 / 进程服务器架构编程。但是如果用 C/C++ 编写服务器,往往对性能会有极致要求,此时采用非阻塞的异步 I/O 才是更好的框架。
amc
2018/09/12
3.4K0
在 C/C++ 异步 I/O 中使用 MariaDB 的非阻塞接口
使用 libevent 和 libev 提高网络应用性能——I/O模型演进变化史
http://blog.csdn.net/hguisu/article/details/38638183(牛逼100多名)
bear_fish
2018/09/20
2.1K0
使用 libevent 和 libev 提高网络应用性能——I/O模型演进变化史
linux下libevent的安装和使用例子:数据回显
http://blog.csdn.net/fall221/article/details/9045353 (安装)
bear_fish
2018/09/20
3.4K0
linux下libevent的安装和使用例子:数据回显
高性能网络编程 - select、 poll 、epoll 、libevent
总之,这些是用于编程的工具和库,用于高效地处理多个 I/O 操作,特别是在网络通信的背景下。Select 和 poll 是较旧、性能较低的选项,而 epoll 是一种高性能的替代方案。Libevent 是一个库,简化了使用这些机制的工作,同时提供了跨不同平台的可移植性。
小小工匠
2023/11/09
6380
几种服务器端IO模型的简单介绍及实现(下)
5、使用事件驱动库libevent的服务器模型 Libevent 是一种高性能事件循环/事件驱动库。 为了实际处理每个请求,libevent 库提供一种事件机制,它作为底层网络后端的包装器。事件系统让为连接添加处理函数变得非常简便,同时降低了底层IO复杂性。这是 libevent 系统的核心。 创建 libevent 服务器的基本方法是,注册当发生某一操作(比如接受来自客户端的连接)时应该执行的函数,然后调用主事件循环 event_dispatch()。执行过程的控制现在由 libevent 系统处理。注册
李海彬
2018/03/23
6940
几种服务器端IO模型的简单介绍及实现(下)
libevent源码深度剖析三 libevent基本使用场景和事件流程
(1)libevent源码深度剖析一 序 (2)libevent源码深度剖析二 Reactor模式 (3)libevent源码深度剖析三 libevent基本使用场景和事件流程 (4)libevent源码深度剖析四 libevent源代码文件组织 (5)libevent源码深度剖析五 libevent的核心:事件event (6)libevent源码深度剖析六 初见事件处理框架 (7)libevent源码深度剖析七 事件主循环 (8)libevent源码深度剖析八 集成信号处理 (9)libevent源码深度剖析九 集成定时器事件 (10)libevent源码深度剖析十 支持I/O多路复用技术 (11)libevent源码深度剖析十一 时间管理 (12)libevent源码深度剖析十二 让libevent支持多线程 (13)libevent源码深度剖析十三 libevent信号处理注意点
范蠡
2018/07/25
2K1
libevent源码深度剖析三 libevent基本使用场景和事件流程
libevent源码深度剖析八 集成信号处理
(1)libevent源码深度剖析一 序 (2)libevent源码深度剖析二 Reactor模式 (3)libevent源码深度剖析三 libevent基本使用场景和事件流程 (4)libevent源码深度剖析四 libevent源代码文件组织 (5)libevent源码深度剖析五 libevent的核心:事件event (6)libevent源码深度剖析六 初见事件处理框架 (7)libevent源码深度剖析七 事件主循环 (8)libevent源码深度剖析八 集成信号处理 (9)libevent源码深度剖析九 集成定时器事件 (10)libevent源码深度剖析十 支持I/O多路复用技术 (11)libevent源码深度剖析十一 时间管理 (12)libevent源码深度剖析十二 让libevent支持多线程 (13)libevent源码深度剖析十三 libevent信号处理注意点
范蠡
2018/07/25
8550
libevent源码深度剖析八 集成信号处理
libevent介绍
libevent是一款事件驱动的网络开发包 由于采用 c 语言开发 体积小巧,跨平台,速度极快。
Java架构师必看
2021/03/22
2K0
libevent源码深度剖析七 事件主循环
(1)libevent源码深度剖析一 序 (2)libevent源码深度剖析二 Reactor模式 (3)libevent源码深度剖析三 libevent基本使用场景和事件流程 (4)libevent源码深度剖析四 libevent源代码文件组织 (5)libevent源码深度剖析五 libevent的核心:事件event (6)libevent源码深度剖析六 初见事件处理框架 (7)libevent源码深度剖析七 事件主循环 (8)libevent源码深度剖析八 集成信号处理 (9)libevent源码深度剖析九 集成定时器事件 (10)libevent源码深度剖析十 支持I/O多路复用技术 (11)libevent源码深度剖析十一 时间管理 (12)libevent源码深度剖析十二 让libevent支持多线程 (13)libevent源码深度剖析十三 libevent信号处理注意点
范蠡
2018/07/25
9710
libevent源码深度剖析七 事件主循环
libevent源码深度剖析(五) libevent的核心:事件event
(1)libevent源码深度剖析一 序 (2)libevent源码深度剖析二 Reactor模式 (3)libevent源码深度剖析三 libevent基本使用场景和事件流程 (4)libevent源码深度剖析四 libevent源代码文件组织 (5)libevent源码深度剖析五 libevent的核心:事件event (6)libevent源码深度剖析六 初见事件处理框架 (7)libevent源码深度剖析七 事件主循环 (8)libevent源码深度剖析八 集成信号处理 (9)libevent源码深度剖析九 集成定时器事件 (10)libevent源码深度剖析十 支持I/O多路复用技术 (11)libevent源码深度剖析十一 时间管理 (12)libevent源码深度剖析十二 让libevent支持多线程 (13)libevent源码深度剖析十三 libevent信号处理注意点
范蠡
2018/07/25
1.2K0
libevent源码深度剖析(五) libevent的核心:事件event
memcached源码阅读----使用libevent和多线程模型
本篇文章主要是我今天阅读memcached源码关于进程启动,在网络这块做了哪些事情。
ctree
2019/02/24
1.4K0
使用事件驱动模型实现高效稳定的网络服务器程序
http://www.cnblogs.com/hnrainll/p/3625597.html
bear_fish
2018/09/20
1.9K0
使用事件驱动模型实现高效稳定的网络服务器程序
libevent源码深度剖析九 集成定时器事件
(1)libevent源码深度剖析一 序 (2)libevent源码深度剖析二 Reactor模式 (3)libevent源码深度剖析三 libevent基本使用场景和事件流程 (4)libevent源码深度剖析四 libevent源代码文件组织 (5)libevent源码深度剖析五 libevent的核心:事件event (6)libevent源码深度剖析六 初见事件处理框架 (7)libevent源码深度剖析七 事件主循环 (8)libevent源码深度剖析八 集成信号处理 (9)libevent源码深度剖析九 集成定时器事件 (10)libevent源码深度剖析十 支持I/O多路复用技术 (11)libevent源码深度剖析十一 时间管理 (12)libevent源码深度剖析十二 让libevent支持多线程 (13)libevent源码深度剖析十三 libevent信号处理注意点
范蠡
2018/07/25
1.3K0
libevent源码深度剖析九 集成定时器事件
Memcached启动分析
在文本协议的memcached中,我们nc/telent后输入stats命令,会很快地输出一些当前memcached的信息的。这些就是stats信息。并不是输入stats的时候才遍历统计出来的。而是已经保存好了这份信息。代码调用在main函数中的:
tunsuy
2022/10/27
6400
蛋疼的mysql_ping()以及MYSQL_OPT_RECONNECT
From: https://www.felix021.com/blog/read.php?2102 昨天@Zind同学找到我之前的一篇blog(已经修改),里面提到了mysql_ping和MYSQL_
1850810
2021/06/07
1.7K0
深入剖析Chrome Base库中的异步I/O利器:揭秘WatchFileDescriptor
在现代计算机系统中,I/O操作是非常重要的一部分,它们通常包括读取或写入文件、网络通信等。然而,由于I/O操作通常涉及到硬件设备,其速度远远低于CPU和内存的处理速度,因此,如何高效地处理I/O操作,是一个重要的问题。
陆业聪
2024/07/23
1010
深入剖析Chrome Base库中的异步I/O利器:揭秘WatchFileDescriptor
MariaDB Galera Cluster部署实战
背景 项目中使用的mariadb+gelera集群模式部署,之前一直用的是mysql的master/slave方式部署数据库的,这种集群模式以前没怎么搞过,这里研究并记录一下。 MariaDB Galera Cluster 介绍 MariaDB 集群是 MariaDB 同步多主机集群。它仅支持 XtraDB/ InnoDB 存储引擎(虽然有对 MyISAM 实验支持 - 看 wsrep_replicate_myisam 系统变量)。 主要功能: 同步复制 真正的 multi-master,即所有节点可以同时
jeremyxu
2018/05/10
6.8K0
源码分析MySQL mysql_real_query函数
Review一同事的C++代码,发现其中有一个拼接而成的多记录INSERT语句可能超大(预计最大可超过1M,甚至10M也有可能,视实际记录条数而定)。担心包大存隐患,所以特意分析一下mysql_real_query函数的实现,以确保使用是否安全。研究对象为MySQL-8.0.14,其它版本可能有小许差异,但估计差异不会太大。
一见
2019/03/14
4.4K0
几种经典的网络服务器架构模型的分析与比较
前言 事件驱动为广大的程序员所熟悉,其最为人津津乐道的是在图形化界面编程中的应用;事实上,在网络编程中事件驱动也被广泛使用,并大规模部署在高连接数高吞吐量的服务器程序中,如 http 服务器程序、ftp 服务器程序等。相比于传统的网络编程方式,事件驱动能够极大的降低资源占用,增大服务接待能力,并提高网络传输效率。 关于本文提及的服务器模型,搜索网络可以查阅到很多的实现代码,所以,本文将不拘泥于源代码的陈列与分析,而侧重模型的介绍和比较。使用 libev 事件驱动库的服务器模型将给出实现代码。 本文涉及到线程
小小科
2018/05/02
2K0
几种经典的网络服务器架构模型的分析与比较
玩转 PHP 网络编程全套之 libevent 框架首篇
此框架的扩展是LIBEVENT,php手册地址libevent,该框架了封装I/O事件,定时事件,中断信号事件,内核I/O复用函数支持EPOLL,POLL,SELECT,DEVPOLL,KQUEUE。框架官方网站libvent官网以下项目使用了该框架
桶哥
2020/05/22
7970
玩转 PHP 网络编程全套之 libevent 框架首篇
推荐阅读
相关推荐
在 C/C++ 异步 I/O 中使用 MariaDB 的非阻塞接口
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文