最新文章专题视频专题问答1问答10问答100问答1000问答2000关键字专题1关键字专题50关键字专题500关键字专题1500TAG最新视频文章推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37视频文章20视频文章30视频文章40视频文章50视频文章60 视频文章70视频文章80视频文章90视频文章100视频文章120视频文章140 视频2关键字专题关键字专题tag2tag3文章专题文章专题2文章索引1文章索引2文章索引3文章索引4文章索引5123456789101112131415文章专题3
问答文章1 问答文章501 问答文章1001 问答文章1501 问答文章2001 问答文章2501 问答文章3001 问答文章3501 问答文章4001 问答文章4501 问答文章5001 问答文章5501 问答文章6001 问答文章6501 问答文章7001 问答文章7501 问答文章8001 问答文章8501 问答文章9001 问答文章9501
当前位置: 首页 - 科技 - 知识百科 - 正文

redis源代码分析21–事务

来源:懂视网 责编:小采 时间:2020-11-09 13:32:25
文档

redis源代码分析21–事务

redis源代码分析21–事务:redis的事务较简单,并不具备事务的acid的全部特征。主要原因之一是redis事务中的命令并不是立即执行的,会一直排队到发布exec命令才执行所有的命令;另一个主要原因是它不支持回滚,事务中的命令可以部分成功,部分失败,命令失败时跟不在事务上下文执行时
推荐度:
导读redis源代码分析21–事务:redis的事务较简单,并不具备事务的acid的全部特征。主要原因之一是redis事务中的命令并不是立即执行的,会一直排队到发布exec命令才执行所有的命令;另一个主要原因是它不支持回滚,事务中的命令可以部分成功,部分失败,命令失败时跟不在事务上下文执行时

redis的事务较简单,并不具备事务的acid的全部特征。主要原因之一是redis事务中的命令并不是立即执行的,会一直排队到发布exec命令才执行所有的命令;另一个主要原因是它不支持回滚,事务中的命令可以部分成功,部分失败,命令失败时跟不在事务上下文执行时

redis的事务较简单,并不具备事务的acid的全部特征。主要原因之一是redis事务中的命令并不是立即执行的,会一直排队到发布exec命令才执行所有的命令;另一个主要原因是它不支持回滚,事务中的命令可以部分成功,部分失败,命令失败时跟不在事务上下文执行时返回的信息类似。不知道在未来会不会提供更好的支持。

我们且来看看现在redis事务的实现。

redis中跟事务相关的主要结构如下所示。每个redisClient的multiState保存了事务上下文要执行的命令。

/* Client MULTI/EXEC state */
typedef struct multiCmd {
 robj **argv;
 int argc;
 struct redisCommand *cmd;
} multiCmd;
typedef struct multiState {
 multiCmd *commands; /* Array of MULTI commands */
 int count; /* Total number of MULTI commands */
} multiState;
typedef struct redisClient {
 ---
 multiState mstate; /* MULTI/EXEC state */
 ---
} redisClient;

client通过发布multi命令进入事务上下文。处于事务上下文的client会设置REDIS_MULTI标志,multi命令会立即返回。

static void multiCommand(redisClient *c) {
 c->flags |= REDIS_MULTI;
 addReply(c,shared.ok);
}

处于事务上下文中的client会将在exec命令前发布的命令排队到mstate,并不立即执行相应命令且立即返回 shared.queued(如果之前参数检查不正确,则会返回出错信息,那就不会排队到mstate中),这在processCommand函数中反映出来(对processCommand的详细解释可参看前面命令处理章节)。queueMultiCommand只是简单的扩大mstate数组,并将当前命令加入其中。

static int processCommand(redisClient *c) {
 ---
 /* Exec the command */
 if (c->flags & REDIS_MULTI && cmd->proc != execCommand && cmd->proc != discardCommand) {
 queueMultiCommand(c,cmd);
 addReply(c,shared.queued);
 } else {
 if (server.vm_enabled && server.vm_max_threads > 0 &&
 blockClientOnSwappedKeys(c,cmd)) return 1;
 call(c,cmd);
 }
 ---
}

当client发布exec命令时,则redis会调用execCommand来执行事务上下文中的命令集合。注意,在此之前,redis会使用execBlockClientOnSwappedKeys提前加载其命令集所需的key(该函数最终是调用前面介绍过的 waitForMultipleSwappedKeys来加载key)。因为这在命令表cmdTable是这样设置的:

{"exec",execCommand,1,REDIS_CMD_INLINE|REDIS_CMD_DENYOOM,execBlockClientOnSwappedKeys,0,0,0},

execCommand会检查是不是处于事务上下文,然后使用execCommandReplicateMulti向 slave/monitor/aof(前提是使用这些功能)发送/写入multi命令字,因为multi命令本身没有排队,而execCommand会在执行完后写入exec命令的,必须让exec和multi命令配对,这之后就是调用call依次执行每个命令了。从这里没有检查call的返回就可以看出,如果命令执行失败了,只能由call命令本身返回出错信息,这里并不检查命令执行的成功与否,最后就是清空mstate中的命令字并取消 REDIS_MULTI状态了。

static void execCommand(redisClient *c) {
 int j;
 robj **orig_argv;
 int orig_argc;
 if (!(c->flags & REDIS_MULTI)) {
 addReplySds(c,sdsnew("-ERR EXEC without MULTI\r\n"));
 return;
 }
 /* Replicate a MULTI request now that we are sure the block is executed.
 * This way we'll deliver the MULTI/..../EXEC block as a whole and
 * both the AOF and the replication link will have the same consistency
 * and atomicity guarantees. */
 execCommandReplicateMulti(c);
 /* Exec all the queued commands */
 orig_argv = c->argv;
 orig_argc = c->argc;
 addReplySds(c,sdscatprintf(sdsempty(),"*%d\r\n",c->mstate.count));
 for (j = 0; j < c->mstate.count; j++) {
 c->argc = c->mstate.commands[j].argc;
 c->argv = c->mstate.commands[j].argv;
 call(c,c->mstate.commands[j].cmd);
 }
 c->argv = orig_argv;
 c->argc = orig_argc;
 freeClientMultiState(c);
 initClientMultiState(c);
 c->flags &= (~REDIS_MULTI);
 /* Make sure the EXEC command is always replicated / AOF, since we
 * always send the MULTI command (we can't know beforehand if the
 * next operations will contain at least a modification to the DB). */
 server.dirty++;
}

最后稍微提一下,如果事务上下文执行过程中,redis突然down掉,也就是最后的exec命令没有写入,此时会让 slave/monitor/aof处于不正确的状态。redis会在重启后会检查到这一情况,这是在loadAppendOnlyFile中完成的。当然这一检测执行的前提是down掉前和重启后都使用aof进行持久化。redis在检测到这一情况后,会退出程序。用户可调用用redis-check- aof工具进行修复。

声明:本网页内容旨在传播知识,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。TEL:177 7030 7066 E-MAIL:11247931@qq.com

文档

redis源代码分析21–事务

redis源代码分析21–事务:redis的事务较简单,并不具备事务的acid的全部特征。主要原因之一是redis事务中的命令并不是立即执行的,会一直排队到发布exec命令才执行所有的命令;另一个主要原因是它不支持回滚,事务中的命令可以部分成功,部分失败,命令失败时跟不在事务上下文执行时
推荐度:
标签: 简单 re 21
  • 热门焦点

最新推荐

猜你喜欢

热门推荐

专题
Top