redis aof命令缓冲区的写入源码

 2023-09-15 阅读 18 评论 0

摘要:需要通过aof记录的命令主要为set命令和过期命令,这些命令在执行完毕后需要记录到aof缓冲区中以便写入到aof文件中。 sds aof_buf; /* AOF buffer, written before entering the event loop */ 在结构体redisServer中通过一个sds来作为aof的缓冲区。 Redis服务器在执行

需要通过aof记录的命令主要为set命令和过期命令,这些命令在执行完毕后需要记录到aof缓冲区中以便写入到aof文件中。

sds aof_buf;      /* AOF buffer, written before entering the event loop */

在结构体redisServer中通过一个sds来作为aof的缓冲区。

 

Redis服务器在执行完相应的命令的时候,如果开启了aof功能,就会在feedAppendOnlyFile()函数中准备将命令添加至aof缓冲区当中。

void feedAppendOnlyFile(struct redisCommand *cmd, int dictid, robj **argv, int argc) {sds buf = sdsempty();robj *tmpargv[3];/* The DB this command was targeting is not the same as the last command* we appended. To issue a SELECT command is needed. */if (dictid != server.aof_selected_db) {char seldb[64];snprintf(seldb,sizeof(seldb),"%d",dictid);buf = sdscatprintf(buf,"*2\r\n$6\r\nSELECT\r\n$%lu\r\n%s\r\n",(unsigned long)strlen(seldb),seldb);server.aof_selected_db = dictid;}if (cmd->proc == expireCommand || cmd->proc == pexpireCommand ||cmd->proc == expireatCommand) {/* Translate EXPIRE/PEXPIRE/EXPIREAT into PEXPIREAT */buf = catAppendOnlyExpireAtCommand(buf,cmd,argv[1],argv[2]);} else if (cmd->proc == setexCommand || cmd->proc == psetexCommand) {/* Translate SETEX/PSETEX to SET and PEXPIREAT */tmpargv[0] = createStringObject("SET",3);tmpargv[1] = argv[1];tmpargv[2] = argv[3];buf = catAppendOnlyGenericCommand(buf,3,tmpargv);decrRefCount(tmpargv[0]);buf = catAppendOnlyExpireAtCommand(buf,cmd,argv[1],argv[2]);} else if (cmd->proc == setCommand && argc > 3) {int i;robj *exarg = NULL, *pxarg = NULL;/* Translate SET [EX seconds][PX milliseconds] to SET and PEXPIREAT */buf = catAppendOnlyGenericCommand(buf,3,argv);for (i = 3; i < argc; i ++) {if (!strcasecmp(argv[i]->ptr, "ex")) exarg = argv[i+1];if (!strcasecmp(argv[i]->ptr, "px")) pxarg = argv[i+1];}serverAssert(!(exarg && pxarg));if (exarg)buf = catAppendOnlyExpireAtCommand(buf,server.expireCommand,argv[1],exarg);if (pxarg)buf = catAppendOnlyExpireAtCommand(buf,server.pexpireCommand,argv[1],pxarg);} else {/* All the other commands don't need translation or need the* same translation already operated in the command vector* for the replication itself. */buf = catAppendOnlyGenericCommand(buf,argc,argv);}/* Append to the AOF buffer. This will be flushed on disk just before* of re-entering the event loop, so before the client will get a* positive reply about the operation performed. */if (server.aof_state == AOF_ON)server.aof_buf = sdscatlen(server.aof_buf,buf,sdslen(buf));/* If a background append only file rewriting is in progress we want to* accumulate the differences between the child DB and the current one* in a buffer, so that when the child process will do its work we* can append the differences to the new append only file. */if (server.aof_child_pid != -1)aofRewriteBufferAppend((unsigned char*)buf,sdslen(buf));sdsfree(buf);
}

首先,判断该命令的执行dbid是否是和当前的dbid一致,如果不一致,需要额外写入select命令切换到命令所执行的dbid上。

 

而后,如果该命令属于expire,perpire, expireat这三个纯粹设置过期时间的命令,直接通过catAppendOnlyExpireAtCommand()方法转换成过期命令写到结果sds中。

 

对于setex和psetex两个存放和过期键同时设置的命令,首先根据这两条命令的格式:

SETEX key seconds value取到第一个和第三个参数,通过catAppendOnlyGenericCommand()方法转换成set命令写到aof缓冲区中,再根据第一个参数和第二个参数组成pexpireat命令写到结果sds中,在这里被转换成了两条命令。redisrdb,

 

而如果是set [ex seconds] [px millisecond] 形式的命令,则根据参数数数量来确定。

如果是这样的命令,也是拆分成set部分和pexpireat部分拆分为多段命令。

 

如果只是简单的set命令,就简单通过catAppendOnlyGenericCommand()方法插入结果sds。

 

 

在完成了上述操作后,判断如果开启了aof,那么则将结果sds写入到server的aof缓冲区中。

如果此时redis正有子进程进行重写操作,那么直接将新的sds加入到重写的内容中。

最后清空结果sds以节约空间。redis mset。

sds catAppendOnlyGenericCommand(sds dst, int argc, robj **argv) {char buf[32];int len, j;robj *o;buf[0] = '*';len = 1+ll2string(buf+1,sizeof(buf)-1,argc);buf[len++] = '\r';buf[len++] = '\n';dst = sdscatlen(dst,buf,len);for (j = 0; j < argc; j++) {o = getDecodedObject(argv[j]);buf[0] = '$';len = 1+ll2string(buf+1,sizeof(buf)-1,sdslen(o->ptr));buf[len++] = '\r';buf[len++] = '\n';dst = sdscatlen(dst,buf,len);dst = sdscatlen(dst,o->ptr,sdslen(o->ptr));dst = sdscatlen(dst,"\r\n",2);decrRefCount(o);}return dst;
}

catAppendOnlyGenericCommand()方法用来将set命令转换为sds以便写入到aof缓冲区中,每次在写命令的开头,都会计算包括命令和参数的个数总和,加上*号写在命令上一行。同时每次在写具体值之前,都要计算写入的参数的具体长度,使用$加在前一行。作为解析对象的o每次在使用玩一次,都会通过decrRefCount()方法减少一次引用次数便于回收。

版权声明:本站所有资料均为网友推荐收集整理而来,仅供学习和研究交流使用。

原文链接:https://hbdhgg.com/3/58195.html

发表评论:

本站为非赢利网站,部分文章来源或改编自互联网及其他公众平台,主要目的在于分享信息,版权归原作者所有,内容仅供读者参考,如有侵权请联系我们删除!

Copyright © 2022 匯編語言學習筆記 Inc. 保留所有权利。

底部版权信息