redis7源码分析:redis 单线程模型解析,一条get命令执行流程
有了下文的梳理后
redis 启动流程
再来解析redis 在单线程模式下解析并处理客户端发来的命令
1. 当 client fd 可读时,会回调readQueryFromClient
函数
void readQueryFromClient(connection *conn) {
client *c = connGetPrivateData(conn);
int nread, big_arg = 0;
size_t qblen, readlen;
/* Check if we want to read from the client later when exiting from
* the event loop. This is the case if threaded I/O is enabled. */
// 这里是多线程模型走的地方,被文分析单线程模式,不走这里
if (postponeClientRead(c)) return;
......
/* There is more data in the client input buffer, continue parsing it
* and check if there is a full command to execute. */
// 走到这里,开始处理客户端发来的命令
if (processInputBuffer(c) == C_ERR)
c = NULL;
}
2. 分析processInputBuffer
int processInputBuffer(client *c) {
/* Keep processing while there is something in the input buffer */
while(c->qb_pos < sdslen(c->querybuf)) {
if (c->flags & CLIENT_BLOCKED) break;
if (c->flags & CLIENT_PENDING_COMMAND) break;
if (isInsideYieldingLongCommand() && c->flags & CLIENT_MASTER) break;
if (c->flags & (CLIENT_CLOSE_AFTER_REPLY|CLIENT_CLOSE_ASAP)) break;
......
/* Multibulk processing could see a <= 0 length. */
if (c->argc == 0) {
resetClient(c);
} else {
if (io_threads_op != IO_THREADS_OP_IDLE) {
serverAssert(io_threads_op == IO_THREADS_OP_READ);
c->flags |= CLIENT_PENDING_COMMAND;
break;
}
/* We are finally ready to execute the command. */
// 最终在这里执行命令
if (processCommandAndResetClient(c) == C_ERR) {
return C_ERR;
}
}
}
......
return C_OK;
}
2.1 分析 processCommandAndResetClient
int processCommandAndResetClient(client *c) {
int deadclient = 0;
client *old_client = server.current_client;
server.current_client = c;
// 这里处理命令
if (processCommand(c) == C_OK) {
commandProcessed(c);
/* Update the client's memory to include output buffer growth following the
* processed command. */
updateClientMemUsageAndBucket(c);
}
if (server.current_client == NULL) deadclient = 1;
/*
* Restore the old client, this is needed because when a script
* times out, we will get into this code from processEventsWhileBlocked.
* Which will cause to set the server.current_client. If not restored
* we will return 1 to our caller which will falsely indicate the client
* is dead and will stop reading from its buffer.
*/
server.current_client = old_client;
/* performEvictions may flush slave output buffers. This may
* result in a slave, that may be the active client, to be
* freed. */
return deadclient ? C_ERR : C_OK;
}
2.2 分析 processCommand
int processCommand(client *c) {
......
/* Now lookup the command and check ASAP about trivial error conditions
* such as wrong arity, bad command name and so forth. */
// 这里搜索命令,sentinel的命令也是在这里处理
// 不像老版本,6.0以前,使用的是命令覆盖的方式,改用搜索
c->cmd = c->lastcmd = c->realcmd = lookupCommand(c->argv,c->argc);
......
/* Exec the command */
if (c->flags & CLIENT_MULTI &&
c->cmd->proc != execCommand &&
c->cmd->proc != discardCommand &&
c->cmd->proc != multiCommand &&
c->cmd->proc != watchCommand &&
c->cmd->proc != quitCommand &&
c->cmd->proc != resetCommand)
{
queueMultiCommand(c, cmd_flags);
addReply(c,shared.queued);
} else {
//最终普通命令调用 call函数执行
call(c,CMD_CALL_FULL);
c->woff = server.master_repl_offset;
if (listLength(server.ready_keys) && !isInsideYieldingLongCommand())
handleClientsBlockedOnKeys();
}
}
2.3 call函数在server.c中
void call(client *c, int flags) {
......
server.in_nested_call++;
c->cmd->proc(c);
server.in_nested_call--;
......
}
最终调用cmd 对应的proc
假设是get 请求,那么在lookupCommand
时就会找到对应的command 对象,由redisCommandTable
可知,对应方法为getCommand
t_string.c
void getCommand(client *c) {
getGenericCommand(c);
}
int getGenericCommand(client *c) {
robj *o;
// 搜索db中数据
if ((o = lookupKeyReadOrReply(c,c->argv[1],shared.null[c->resp])) == NULL)
return C_OK;
if (checkType(c,o,OBJ_STRING)) {
return C_ERR;
}
// 将数据写入到输出缓存中,待eventloop 发现可写后发送
addReplyBulk(c,o);
return C_OK;
}
redis7源码分析:redis 单线程模型解析,一条get命令执行流程的更多相关文章
- [源码分析] 带你梳理 Flink SQL / Table API内部执行流程
[源码分析] 带你梳理 Flink SQL / Table API内部执行流程 目录 [源码分析] 带你梳理 Flink SQL / Table API内部执行流程 0x00 摘要 0x01 Apac ...
- ThreadPoolExecutor源码分析-面试问烂了的Java线程池执行流程,如果要问你具体的执行细节,你还会吗?
Java版本:8u261. 对于Java中的线程池,面试问的最多的就是线程池中各个参数的含义,又或者是线程池执行的流程,彷佛这已成为了固定的模式与套路.但是假如我是面试官,现在我想问一些更细致的问题, ...
- Spring源码分析之AOP从解析到调用
正文: 在上一篇,我们对IOC核心部分流程已经分析完毕,相信小伙伴们有所收获,从这一篇开始,我们将会踏上新的旅程,即Spring的另一核心:AOP! 首先,为了让大家能更有效的理解AOP,先带大家过一 ...
- Memcached源码分析之线程模型
作者:Calix 一)模型分析 memcached到底是如何处理我们的网络连接的? memcached通过epoll(使用libevent,下面具体再讲)实现异步的服务器,但仍然使用多线程,主要有两种 ...
- springMVC源码分析--HandlerMethodReturnValueHandlerComposite返回值解析器集合(二)
在上一篇博客springMVC源码分析--HandlerMethodReturnValueHandler返回值解析器(一)我们介绍了返回值解析器HandlerMethodReturnValueHand ...
- 源码分析——从AIDL的使用开始理解Binder进程间通信的流程
源码分析——从AIDL的使用开始理解Binder进程间通信的流程 Binder通信是Android系统架构的基础.本文尝试从AIDL的使用开始理解系统的Binder通信. 0x00 一个AIDL的例子 ...
- 鸿蒙内核源码分析(调度机制篇) | 任务是如何被调度执行的 | 百篇博客分析OpenHarmony源码 | v7.07
百篇博客系列篇.本篇为: v07.xx 鸿蒙内核源码分析(调度机制篇) | 任务是如何被调度执行的 | 51.c.h .o 任务管理相关篇为: v03.xx 鸿蒙内核源码分析(时钟任务篇) | 触发调 ...
- 【Redis】事件驱动框架源码分析(单线程)
aeEventLoop初始化 在server.c文件的initServer函数中,对aeEventLoop进行了初始化: 调用aeCreateEventLoop函数创建aeEventLoop结构体,对 ...
- spring源码分析系列 (15) 设计模式解析
spring是目前使用最为广泛的Java框架之一.虽然spring最为核心是IOC和AOP,其中代码实现中很多设计模式得以应用,代码看起来简洁流畅,在日常的软件设计中很值得借鉴.以下是对一些设计模式的 ...
- jQuery 2.0.3 源码分析Sizzle引擎 - 词法解析
声明:本文为原创文章,如需转载,请注明来源并保留原文链接Aaron,谢谢! 浏览器从下载文档到显示页面的过程是个复杂的过程,这里包含了重绘和重排.各家浏览器引擎的工作原理略有差别,但也有一定规则. 简 ...
随机推荐
- Oracle process/session/cursor/tx/tm的简单学习
Oracle process/session/cursor/tx/tm的简单学习 Oracle的部署模式 Oracle安装时有专用模式和共享模式的区别 共享模式(Shared mode): 在共享模式 ...
- [转帖]通过 TiUP 部署 TiDB 集群的拓扑文件配置
https://docs.pingcap.com/zh/tidb/stable/tiup-cluster-topology-reference 通过 TiUP 部署或扩容 TiDB 集群时,需要提供一 ...
- [转帖]5. Tikv安装部署
5. Tikv安装部署 5.1. 概述 TiDB 是 PingCAP 公司自主设计.研发的开源分布式关系型数据库,是一款同时支持在线事务处理与在线分析处理 (Hybrid Transactiona ...
- [转帖]clickHouse单机模式安装部署(RPM安装)
关于版本和系统的选择 操作系统:Centos-7 ClickHouse: rpm 在安装,20.x 安装前的准备 CentOS7 打开文件数限 在 /etc/security/limits.conf ...
- [转帖]看6大国产CPU加速替代,谁才是“王者”选手?
https://baijiahao.baidu.com/s?id=1761150458273739276&wfr=spider&for=pc 2023-03-23 17:33湖北匠心计 ...
- [转帖][译]ARM大小核架构白皮书
https://zhuanlan.zhihu.com/p/33411449 ARM big.LITTLE Processing with ARM Cortex-A15 & Cortex-A7 ...
- postman中monitor的使用
monitor就是一个摸鱼的功能,我们把写好的接口部署到postman的web服务器中, 绑定自己的邮箱,运行结果会发送到自己的邮箱中,不用实时监控,是个非常方便 的功能(不安全) 1.crete a ...
- ES6 Array.fiill()的用法
简单使用 // arr.fill(value, start, end) // value填充的值 // start填充的起始位置包含 // end填充的结束值,不包含,如果省略这个参数,表示从起始位置 ...
- 【记录一个问题】vm-select和vm-storage均无法做并行查询
作者:张富春(ahfuzhang),转载时请注明作者和引用链接,谢谢! cnblogs博客 zhihu Github 公众号:一本正经的瞎扯 看我提的这个issue: need parallel qu ...
- 微信小程序网页嵌入开发
无脑开发 下载微信开发者工具 新建一个项目找到index开头的进去全选删除粘贴下面代码 <!-- html --> <!-- 指向嵌入外部链接的地址 --> <web-v ...