微尘 - redis
type: channel
link: https://www.guiwenfeng.com/index.php/category/redis/
items: redis 响应处理流程
items: redis 请求处理流程

redis 响应处理流程
type: item
date: 2020-04-29T15:26:03+00:00
description: 相关资料networking.c请求处理完成后，通过调用 addReply 函数族来完成响应。 void addReply(redisClient *c, robj *obj); void addReplySds(redisClient *c, sds s); void addReplyString(redisClient *c, char *s, size_t len);void addReplyString(redisClient *c, char *s, size_t len) { if (prepareClientToWrite(c) != REDIS_OK) return; if (_addReplyToBuffer(c,s,len) != REDIS_OK) _addReplyStringToList(c,s,len); }以 addReplyString 为例，在 addReply 函数中： 首先调用 prepareClientToWrite 函数，完成准备工作。 然后向客户端缓存写入响应内容，写入响应内容时，总是先尝试写入到固定 buf，如果写入失败，再写入到动态分配的链表中。客户端缓存由两部分组成：固定大小的 buf 和动态分配的 reply（链表）。 #define REDIS_REPLY_CHUNK_BYTES (16*1024) /* 16k output buffer */ char buf[REDIS_REPLY_CHUNK_BYTES]; c->reply = listCreate();1. 写入响应内容之前，完成准备工作/* This function is called every time we are going to transmit new data * to the client. The behavior is the following: * * If the client should receive new data (normal clients will) the function * returns REDIS_OK, and make sure to install the write handler in our event * loop so that when the socket is writable new data gets written. * * If the client should not receive new data, because it is a fake client, * a master, a slave not yet online, or because the setup of the write handler * failed, the function returns REDIS_ERR. * * Typically gets called every time a reply is built, before adding more * data to the clients output buffers. If the function returns REDIS_ERR no * data should be appended to the output buffers. */ int prepareClientToWrite(redisClient *c) { if (c->flags & REDIS_LUA_CLIENT) return REDIS_OK; if ((c->flags & REDIS_MASTER) && !(c->flags & REDIS_MASTER_FORCE_REPLY)) return REDIS_ERR; if (c->fd <= 0) return REDIS_ERR; /* Fake client */ if (c->bufpos == 0 && listLength(c->reply) == 0 && (c->replstate == REDIS_REPL_NONE || c->replstate == REDIS_REPL_ONLINE) && aeCreateFileEvent(server.el, c->fd, AE_WRITABLE, sendReplyToClient, c) == AE_ERR) return REDIS_ERR; return REDIS_OK; }在向客户端缓存写入响应内容之前，先向事件处理程序注册写事件，回调函数是：sendReplyToClient()。 此时，客户端缓存为空：c->bufpos == 0 && listLength(c…

redis 请求处理流程
type: item
date: 2020-04-29T15:24:22+00:00
description: 相关资料redis.c networking.c1. 建立连接/* Create an event handler for accepting new connections in TCP and Unix * domain sockets. */ for (j = 0; j < server.ipfd_count; j++) { if (aeCreateFileEvent(server.el, server.ipfd[j], AE_READABLE, acceptTcpHandler,NULL) == AE_ERR) { redisPanic( "Unrecoverable error creating server.ipfd file event."); } } if (server.sofd > 0 && aeCreateFileEvent(server.el,server.sofd,AE_READABLE, acceptUnixHandler,NULL) == AE_ERR) redisPanic("Unrecoverable error creating server.sofd file event.");当客户端请求连接时，对应的事件处理函数是：acceptTcpHandler、acceptUnixHandler，其中： acceptTcpHandler 接受 tcp 连接请求； acceptUnixHandler 接受 unix 域连接请求。void acceptTcpHandler(aeEventLoop *el, int fd, void *privdata, int mask) { int cport, cfd, max = MAX_ACCEPTS_PER_CALL; char cip[REDIS_IP_STR_LEN]; REDIS_NOTUSED(el); REDIS_NOTUSED(mask); REDIS_NOTUSED(privdata); while(max--) { cfd = anetTcpAccept(server.neterr, fd, cip, sizeof(cip), &cport); if (cfd == ANET_ERR) { if (errno != EWOULDBLOCK) redisLog(REDIS_WARNING, "Accepting client connection: %s", server.neterr); return; } redisLog(REDIS_VERBOSE,"Accepted %s:%d", cip, cport); acceptCommonHandler(cfd,0); } }anetTcpAccept 接受 tcp 连接，同时返回连接套接字cfd。 acceptCommonHandler 对连接套接字cfd及对应的客户端结构进行初始化。c = createClient(fd)) 初始化主要在 createClient 函数中进行，其中，通过注册事件处理函数 readQueryFromClient 来读取请求。 aeCreateFileEvent(server.el,fd,AE_READABLE,readQueryFromClient, c)2. 请求处理请求处理可以分为3个步骤： 1. 读取请求 2. 解析请求 3. 执行请求readQueryFromClient 函数是请求处理的起点，该函数将请求读取到 c->querybuf 中，然后调用 processInputBuffer 函数。void processInputBuffer(redisClient *c) { /* Keep processing while there is something in the input buffer */ while(sdslen(c->querybuf)) { /* Immediately abort if the client is in the middle of something. */ if (c->flags & REDIS_BLOCKED) return; /* REDIS_CLOSE_AFTER_REPLY closes the connection once the reply is * written to the client. Make sure to not let the reply grow after * this flag has been set (i.e. don't process more commands). */ if (c->flags & REDIS_CLOSE_AFTER_REPLY) retu…