redis中的事务

redis页支持事务。redis的事务是在MULTI 和 EXEC 命令之间的一条或者多条命令.
从redis.c 中可以知道MULTI 命令的实现如下:
    {"multi",multiCommand,1,"rs",0,NULL,0,0,0,0,0},

void multiCommand(redisClient *c) {

    // REDIS_MULTI 表示当前正在进行事务操作,从这里可以看到事务不能进行嵌套。
    if (c->flags & REDIS_MULTI) {
        addReplyError(c,"MULTI calls can not be nested");
        return;
    }

    //表示开始进行事务操作
    c->flags |= REDIS_MULTI;

    addReply(c,shared.ok);
}
从这里可以知道不能在MULTI 中再次执行MULTI 命令.
当打开REDIS_MULTI 这个flag后,传入Redis的命令会被queueMultiCommand 添加到一个数组里存储起来,
int processCommand(redisClient *c) {
..............
 /* Exec the command */
 // 可以看到在事务中不回将EXEC/DISCARD/MULTI/WATCH 这四个命令让入队列中
    if (c->flags & REDIS_MULTI &&
        c->cmd->proc != execCommand && c->cmd->proc != discardCommand &&
        c->cmd->proc != multiCommand && c->cmd->proc != watchCommand)
    {
        
        queueMultiCommand(c);
        addReply(c,shared.queued);
    } else {
        // 在事务中直接执行EXEC/DISCARD/MULTI/WATCH  这四个命令
        call(c,REDIS_CALL_FULL);

        c->woff = server.master_repl_offset;

        if (listLength(server.ready_keys))
            handleClientsBlockedOnLists();
    }

    return REDIS_OK;
}
	
从这里看到看到在事务中是通过queueMultiCommand 将命令保存在数组中
void queueMultiCommand(redisClient *c) {
    multiCmd *mc;
    int j;

    // 为将要保存的命令分配空间
    c->mstate.commands = zrealloc(c->mstate.commands,
            sizeof(multiCmd)*(c->mstate.count+1));

    // 指向新的命令
    mc = c->mstate.commands+c->mstate.count;

    //保存命令和明亮的参数
    mc->cmd = c->cmd;
    mc->argc = c->argc;
    mc->argv = zmalloc(sizeof(robj*)*c->argc);
    memcpy(mc->argv,c->argv,sizeof(robj*)*c->argc);
    for (j = 0; j < c->argc; j++)
        incrRefCount(mc->argv[j]);

    // 事务中保存的命令的个数加1
    c->mstate.count++;
}
从这里可以知道事务中的命令是保存在redisClient.mstate.command 这个数组的尾部,这里可以将数组看做一个FIFO
当用户最终在执行EXEC时调用的会执行所有保存在redisClient.mstate.command 中的命令,这里是按顺序执行
void execCommand(redisClient *c) {
    int j;
    robj **orig_argv;
    int orig_argc;
    struct redisCommand *orig_cmd;
    int must_propagate = 0; /* Need to propagate MULTI/EXEC to AOF / slaves? */

    // 可见exec和MULTI是配对的,如果之前没有执行multi,就报错
    if (!(c->flags & REDIS_MULTI)) {
        addReplyError(c,"EXEC without MULTI");
        return;
    }

    
    // c->mstate.count 保存了在事务中总的命令,因此这里用for循环遍历
    for (j = 0; j < c->mstate.count; j++) {

        // redisClient *c 表示将要执行的命令,这里恢复命令和其对应的参数
        c->argc = c->mstate.commands[j].argc;
        c->argv = c->mstate.commands[j].argv;
        c->cmd = c->mstate.commands[j].cmd;


        // 执行这个c命令
        call(c,REDIS_CALL_FULL);


    }

    // 清理事务状态
    discardTransaction(c);

    /* Make sure the EXEC command will be propagated as well if MULTI
     * was already propagated. */
    // 将服务器设为脏,确保 EXEC 命令也会被传播
    if (must_propagate) server.dirty++;

handle_monitor:
    /* Send EXEC to clients waiting data from MONITOR. We do it here
     * since the natural order of commands execution is actually:
     * MUTLI, EXEC, ... commands inside transaction ...
     * Instead EXEC is flagged as REDIS_CMD_SKIP_MONITOR in the command
     * table, and we do it here with correct ordering. */
    if (listLength(server.monitors) && !server.loading)
        replicationFeedMonitors(c,server.monitors,c->db->id,c->argv,c->argc);
}








  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值