`
xpenxpen
  • 浏览: 725176 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

redis源码阅读笔记(13)——事务

阅读更多
1. 高层视角解读
redis的事务实现是比较简单的,支持CAS操作,watch命令可以锁定某个key,在事务执行时如果检测到watch的key被修改,事务失败。事务成功执行后,会unwatch掉所有观察的keys。
可以参考《Redis设计与实现》里的事务一章。
事务的实现

2. 底层代码选读
和事务相关的函数都集中在了multi.c文件中

2.1 数据结构
首先回忆一下,一个redis有很多数据库,每个数据库里有一个哈希表存储所有记录,一个哈希表存储所有记录的过期时间,还有一个哈希表存储记录的监控信息。
typedef struct redisDb {
    dict *dict;                 /* The keyspace for this DB */
    dict *expires;              /* Timeout of keys with a timeout set */
    dict *watched_keys;         /* WATCHED keys for MULTI/EXEC CAS */
} redisDb;


而客户端存储正在使用的数据库,待执行的事务的命令队列,还有监控信息。
typedef struct redisClient {
    redisDb *db;            // 当前正在使用的数据库
    multiState mstate;      /* MULTI/EXEC state */
    list *watched_keys;     /* Keys WATCHED for MULTI/EXEC CAS */
} redisClient;


注意redisDb和redisClient结构体里各有一个watched_keys,但是它们的类型是不同的
如果用java泛型来表示的话代码如下
class redisDb {
    Map<robj, redisClient> watched_keys;
}
class redisClient {
    List<watchedKey> watched_keys;
}


另外一些结构,watchedKey 里存着监控信息,multiCmd 存着待执行的命令,multiState 则存着一个命令的数组。
typedef struct watchedKey {
    // 被监视的键
    robj *key;
    // 键所在的数据库
    redisDb *db;

} watchedKey;

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;


2.2 watch和unwatch的代码
void watchForKey(redisClient *c, robj *key) {

    list *clients = NULL;
    listIter li;
    listNode *ln;
    watchedKey *wk;

    // 检查 key 是否存在于数据库的 watched_keys 字典中
    clients = dictFetchValue(c->db->watched_keys,key);
    // 如果不存在的话,添加它
    if (!clients) { 
        // 值为链表
        clients = listCreate();
        // 关联键值对到字典
        dictAdd(c->db->watched_keys,key,clients);
    }
    // 1.添加服务端的某个数据库的watched_keys链表中的key节点
    listAddNodeTail(clients,c);   //服务端的watched_keys里元素类型是redisClient

    wk = zmalloc(sizeof(*wk));
    wk->key = key;
    wk->db = c->db;
	
    // 2.将客户端添加到链表的末尾
    listAddNodeTail(c->watched_keys,wk);   //客户端的watched_keys里元素类型是watchedKey
}

void unwatchAllKeys(redisClient *c) {
    listIter li;
    listNode *ln;

    // 遍历链表中所有被客户端监视的键
    listRewind(c->watched_keys,&li);
    while((ln = listNext(&li))) {
        list *clients;
        watchedKey *wk;

        // 从数据库的 watched_keys 字典的 key 键中
        // 删除链表里包含的客户端节点
        wk = listNodeValue(ln);
        // 取出客户端链表
        clients = dictFetchValue(wk->db->watched_keys, wk->key);
		
        // 1.删除服务端的某个数据库的watched_keys链表中的key节点
        listDelNode(clients,listSearchKey(clients,c));

        // 2.删除客户端的watched_keys链表中的key节点
        listDelNode(c->watched_keys,ln);
    }
}

代码的各个struct之间你引用我,我引用你,有点绕。但也正是用了这个办法,才能够将struct关联起来,然后通过c->db->watched_keys这样的形式来设置一个值。
可以看到watch和unwatch要同时操作服务端和客户端的两个watched_keys。两个watched_keys类型是不一样的,所以代码有点绕。
由于C语言里没有泛型,所以代码看起来不直观,需要深层分析才能看清楚。一不小心编码错了编译没问题,要等运行时才会出错。
而C++则引入了模板,java和c#有泛型来使得代码看起来更直观,也更安全。
分享到:
评论

相关推荐

    redis源码阅读笔记(6)——ziplist

    Redis是一款高性能的键值对数据库,其内部使用了许多优化的数据结构来存储数据,其中ziplist是Redis为了节省内存而设计...在阅读Redis源码时,深入分析ziplist的实现细节将有助于我们更好地理解和调试Redis的内存管理。

    redis源码阅读笔记(10)——事件

    在Redis源码阅读笔记(10)——事件中,我们将探讨Redis如何利用事件模型来实现非阻塞I/O,以及相关的编程模型如Reactor模式和NIO。 Redis使用了一个基于epoll的事件处理器,epoll是Linux系统提供的一种高效I/O多路...

    redis源码阅读笔记(7)——对象

    这篇源码阅读笔记主要关注Redis中的对象系统,它是Redis实现高效数据操作的关键。 在Redis中,每个数据都有一个特定的对象类型,比如`OBJ_STRING`、`OBJ_HASH`等,这些类型定义了数据的存储方式和操作行为。对象...

    redis源码阅读笔记(1)——sds

    本篇笔记将聚焦于Redis源码中的“sds”(Simple Dynamic Strings,简单动态字符串)部分,这是Redis中处理字符串的基础数据结构。 首先,我们要明白sds是什么。在C语言中,字符串是以字符数组的形式存在的,而sds是...

    redis源码阅读中文分析注释

    redis源码阅读中文分析注释

    redis/phpredis源码及文档

    Redis是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。 附件里面包括redis源码,phpredis源码,redis指令及文档

    狂神redis源码笔记.rar

    通过阅读“狂神redis源码笔记”和解压的“redis-study”文件,你将能够深入理解Redis的内部运作,掌握Java客户端的使用技巧,提升在实际项目中运用Redis的能力。这包括但不限于了解Redis的设计模式、源码实现细节、...

    Redis全套学习笔记 (带章节目录) 完整版pdf

    Redis,即远程字典服务,是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。...本文适合Redis初学者和进阶者阅读,是一份全面而实用的学习笔记。

    redis安装遇到的问题——linux centos7.5

    Redis 安装遇到的问题——Linux Centos7.5 Redis 是一个开源的、基于内存的数据结构存储系统,常用于数据库、缓存、消息队列等场景。但是,在 Linux Centos7.5 环境中安装 Redis 时可能会遇到一些问题,这篇文章将...

    scala连接redis哨兵模式 demo 使用scala的redis库(csdn)————程序.pdf

    Redis具备数据复制、Lua脚本、事务、不同级别的持久化等多种功能,并通过发布/订阅模式支持消息系统。 哨兵模式是Redis的高可用解决方案之一。在哨兵模式下,一个或多个哨兵会监控主从服务器,并在指定的主服务器不...

    redis的可视化工具——redisdesktopmanager

    Redis是世界上最受欢迎的内存数据存储系统之一,常用于构建高性能、低延迟的数据缓存和数据库。Redis Desktop Manager是一款跨平台的图形用户界面(GUI)工具,专为方便开发者和管理员管理Redis实例而设计。它提供了...

    redis源码资源下载

    Redis(Remote Dictionary Server),即远程字典服务,是一个开源的、高性能的、基于内存的Key-Value数据库,它使用ANSI C语言编写,支持网络,并提供了多种语言的API。Redis以其丰富的数据结构、高性能、持久化特性...

    Redis全套学习笔记 完整版pdf.rar

    Redis全套学习笔记 完整版pdf.rar set:添加键值对 get:获取值 apend:追价值 strlen:获取值的长度 setnx:key不存在时,设置key的值 incr:原子递增1 decr:原子递减1 incrby/decrby:递增或者递减指定的数字 ...

    Redis全套学习笔记-带章节目录-114页.pdf

    Redis全套学习笔记 Redis是一种基于内存的NoSQL数据库,具有高性能、可扩展性和灵活性等特点。以下是Redis的详细知识点: 安装和启动 * 安装Redis可以通过下载软件包或使用yum、apt-get等安装工具进行安装。 * ...

    Redis Windows源码

    在Windows环境下,Redis的源码分析和部署对于开发者来说具有重要意义,尤其是在Windows服务端开发中。以下是对"Redis Windows源码"的详细解析: 1. Redis核心架构: Redis基于单线程模型,通过事件驱动机制处理...

    狂神说-Redis完整版笔记

    【Redis完整版笔记】深入解析Redis作为NoSQL数据库的关键特性 Redis是一款高性能的Key-Value内存数据库,广泛应用于缓存、消息队列、计数器等多个场景。在NoSQL数据库的大潮中,Redis以其出色的速度和灵活性...

    redis源码安装以及配置

    **一、Redis源码安装** 1. **下载源码** 首先,我们需要从Redis官方网站或者GitHub仓库下载源码。在这个例子中,我们使用的是`redis-2.8.9.tar.gz`。你可以通过命令行工具如`wget`或`curl`来下载,或者直接在网页...

    Redis全套学习笔记

    Redis 安装简单,可以通过源码编译或使用包管理器安装。启动Redis有前台和后台两种方式,后台启动更常见。Redis 可通过`redis-cli`命令行工具进行交互,提供一系列命令用于操作数据库。 2. Redis 数据类型: - **...

Global site tag (gtag.js) - Google Analytics