iis服务器助手广告广告
返回顶部
首页 > 资讯 > 前端开发 > VUE >如何理解Redis 代码库源码
  • 637
分享到

如何理解Redis 代码库源码

2024-04-02 19:04:59 637人浏览 泡泡鱼
摘要

本篇文章给大家分享的是有关如何理解Redis 代码库源码,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。Redis是一个用ANSI C &nbs

本篇文章给大家分享的是有关如何理解Redis 代码库源码,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。

Redis是一个用ANSI C  编写的开源数据结构服务器。“数据结构服务器”只是对灵巧的key-value存储服务的另外一种称谓。你不仅仅可以存储简单的字符串,还可以存储包括 hash(或者map,甚至dicts),list,set,sorted set。我们在Top10 中 大量应用了Redis,大部分为了根据用户搜索的日期和酒店的空房情况和价格建立索引。我发现Redis的代码非常容易读懂,甚至是对于像我这样的新手。 代码写的很整洁,并且代码量相对较小(4.5万行左右),大部分都是单线程的,依赖也很少。所有的依赖都跟源代码放在一起了,这中做法让编译它变得非常简 单:clone它的库,然后输入make即可。

我决定通过为它增加一条命令来深入代码。而这简单的事情可以让我知道Redis怎么处理一条命令并调度响应它。命令rand,接收一个整型值作为 max,并随机返回0到max(不包含max)之间的一个整数。这不是使用键值存储的思路,但是实现它将会很有启发性。而我也肯定不会提交一个pull  request。

免责声明:如我之前所说,我绝对不是一个C语言的专家,因此这里所有的代码和其解释都符合这个条款。而且,我链接了Redis的一个不稳定分支,所以它是不稳定的。如果你自己去获取Redis源码,用你喜欢的编辑器来查看时,你将发现更多本文的不同,特别是如果你编译并运行时会发现不同。

命令表在src/redis.c文件的靠顶部的位置。它是一个数组,数组的元素类型是redisCommand结构体。redisCommand是在src/redis.h中定义的。在redisCommandTable的上方有一块比较详细的注释,对它的每一个field做了解释。下面是get命令的定义:

{"get",getCommand,2,"r",0,NULL,1,1,1,0,0},

第一个field是命令的名字“get”。第二个field是一个函数指针,指向这个命令的具体实现(你可以查看实现细节t_string.c)。

第三个field是命令的参数数量限制(命令接收的参数个数)。指定这个,意味着在调用函数指针之前,查找和执行命令的代码可以做一个预先验证。这 种做法减少了在每个命令函数必须的错误处理代码。参数的个数算上了命令名字本身,所以它只接受两个参数:它自己的名字,key的名字(我们要获取它的 值)。

第四个field,被设为”r”,用来指明这个命令是只读的,不能修改这个key的value或状态。有一大堆的字母标志,你都可以用在这个位置。 而且在附近的注释块中,每个字母标志都有详细的解释。紧跟这个field的field总是被设置为0,后面会用来计算。它只是第四个field的字符串包 含信息的位掩码。

第六个field是NULL,因为它只有在你要用复杂的逻辑去告诉Redis哪个参数才是真正的key的时候才需要。一个key指向一个存储在 Redis中的值的引用,对应简单的参数,例如我们的max参数。这种机制,允许Redis在调用命令的实现之前,提取key的值(并且校验key是否存 在)。如果这个field被设置了值,那么它将会是一个函数指针,指向的函数会返回一个参数索引的整型数组(db.c中 的zuNIOnInterGeTKEys是一个示例)。在get命令(其他大部分命令)的场景下,这个数组的信息传达的信息跟后面三个field的一样。 get命令只有一个参数,而它就是key。因此,***个参数(key)在位置1上,***一个参数(也是key)在位置1上,从***个参数到***一个参数的 增量也是1(译者注:源码注释是:intkeystep;)。

redisCommand的***两个field是命令的度量项,由Redis来设置,并且总是初始化为0。

在命令表的底部加上我们的命令:

{"rand",randCommand,2,"rRl",0,NULL,0,0,0,0,0}

命令的名字是“rand”,randCommand指向实现的指针(还未实现),它接收2个参数(命令名字和max)。至于标志,它是只读的(r),返回随机的,不确定的输出(R),而且它可以在Redis还在加载数据的时候使用(l)。它没有关键参数。

下一步是在src/redis.h中增加randCommand的函数原型。Redis命令的函数接收一个参数,一个redisClient的结构体,作为命令的参数同时也用来向实际的客户端发送响应。

void randCommand(redisClient *c);

这个原型应该放在src/redis.h中与其他所有命令的原型一起。搜索下面的一行:

这将帮你找到正确的位置。

我们在src/redis.c中加一个空实现:

void randCommand(redisClient *c) {    }

我将它加在了infoCommand定义的旁边。现在,我们执行make命令。

make

然后,启动我们刚刚编译成共的Redis服务(如果你已经有一个Redis服务在本地运行,你应该停掉它):

> src/redis-server

接着我们在另外的终端中运行Redis客户端,并试着运行我们的命令:

>redis-cli

首先,我们试一试我们的异常处理:

redis 127.0.0.1:6379> rand  (error) ERR wrong number of arguments for 'rand' command

很好,参数数量限制检查是正常的。这一次我们指定一个参数:

redis 127.0.0.1:6379> rand 1

Redis卡住了。这正是我预期的,因为我在randCommand函数中没有任何响应。将服务停掉,我们接着回去看代码。

我们想返回一个整数,因此我在代码里翻找例子,***在src/t_zset.c中找到了zcardCommand。这个命令用addReplyLongLong来向客户端返回一个64位(long long)的整数。我们也试一下:

void randCommand(redisClient *c) {      addReplyLongLong(c,3);  }

然后,我们在make一次,并测试命令:

redis 127.0.0.1:6379> rand 1  (integer) 3    redis 127.0.0.1:6379> rand 2  (integer) 3    redis 127.0.0.1:6379> rand 3  (integer) 3

好吧,结果不是太随机,但这只是个开始。我们从命令里获取参数max,并返回一个由max限制的随机数:

void randCommand(redisClient *c) {      long max;        if (getLongFromObjectOrReply(c,c->argv[1],&max,NULL) != REDIS_OK)          return;        addReplyLongLong(c,random() % max);  }

尽管Redis在整个代码库中都用原始类型和C型字符串,但它同时也拥有自己的以更通用的方式存在的内部对象系统,用来表示字符串,长整 型和更复杂的类型。一个利用这种类型的例子就是:每个命令的参数。每一个命令的参数都作为一个Redis对象被存在redisClient实例c的 field,数组argv里。(译注:在源码src/redis.c里面redisClient是一个结构体,argv是一个redisObject指针 的指针)。在src/t_string.c里面有一个从Redis对象获取长整型的例子:getrangeCommand,它调用了src/object.c中的getLongFromObjectOrReply函数。

getLongFromObjectOrReply函数接收一个redisClient实例作参数,并检查它的第二个参数是否是一个长整型, 如果是则将第二个参数的指针赋给第三个参数(这个参数是一个指针类型),并且返回REDIS_OK。如果第二个参数不是长整型(或溢出了),函数返回 REDIS_ERR。这个方法的美丽之处在于:如果我们从我们的randCommand函数得到的返回值是REDIS_ERR,所有必须的错误响应已经被 发送给客户端了。我们再试一下我们的命令:

redis 127.0.0.1:6379> rand 10  (integer) 9  redis 127.0.0.1:6379> rand notanumber  (error) ERR value is not an integer or out of range  redis 127.0.0.1:6379> rand 10  (integer) 3  redis 127.0.0.1:6379> rand 10  (integer) 1  redis 127.0.0.1:6379> rand 100  (integer) 43  redis 127.0.0.1:6379> rand 100  (integer) 55  redis 127.0.0.1:6379> rand 100  (integer) 86

看起来不错!rand看起来是一个没有多少意义的命令,但是从实现它的过程中学到很多关于Redis的东西,我希望你跟着做下来也同样学到很多。请在评论 里告诉我这篇文章里是否明显的错误。我也很高兴知道这篇文章对你很有用或者你很喜欢它。我考虑写一些类似的东西,关于Redis或者其他的开源的代码库。

以上就是如何理解Redis 代码库源码,小编相信有部分知识点可能是我们日常工作会见到或用到的。希望你能通过这篇文章学到更多知识。更多详情敬请关注编程网VUE频道。

--结束END--

本文标题: 如何理解Redis 代码库源码

本文链接: https://www.lsjlt.com/news/86292.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • 如何理解Redis 代码库源码
    本篇文章给大家分享的是有关如何理解Redis 代码库源码,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。Redis是一个用ANSI C &nbs...
    99+
    2022-10-19
  • 如何理解Java SynDemo对象源代码
    本篇文章为大家展示了如何理解Java SynDemo对象源代码,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。Java SynDemo对象一直在我们的语言使用中使用,其实在不断的学习中我们还是在源代码...
    99+
    2023-06-17
  • Redis命令处理过程源码解析
    本文基于社区版Redis 4.0.8 1、命令解析 Redis服务器接收到的命令请求首先存储在客户端对象的querybuf输入缓冲区,然后解析命令请求的各个参数,并存储在客户端对象...
    99+
    2022-11-13
  • 如何理解Mybatis源码
    本篇内容介绍了“如何理解Mybatis源码”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!为什么纠结因为面试...
    99+
    2022-10-18
  • 如何理解ArrayList源码
    本篇内容主要讲解“如何理解ArrayList源码”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“如何理解ArrayList源码”吧!ArrayList类图如下:A...
    99+
    2022-10-19
  • 如何理解Python解释器源码
    这篇文章主要介绍“如何理解Python解释器源码”,在日常操作中,相信很多人在如何理解Python解释器源码问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”如何理解Python解释器源码”的疑惑有所帮助!接下来...
    99+
    2023-06-15
  • Spring源码如何实现动态代理
    小编给大家分享一下Spring源码如何实现动态代理,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧!注:这里不阐述Spring和AOP的一些基本概念和用法,直接进入正题。流程  Spring所管理的对象大体会经过确定实例化对象...
    99+
    2023-06-14
  • 如何理解Typescript代码
    这篇文章主要介绍“如何理解Typescript代码”,在日常操作中,相信很多人在如何理解Typescript代码问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”如何理解Type...
    99+
    2022-10-19
  • 如何通过源码安装redis-3.0.5
    这篇文章给大家分享的是有关如何通过源码安装redis-3.0.5的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。##### 安装redis-server ###### 创建运行用户...
    99+
    2022-10-19
  • Libtask源码解析之如何理解锁
    这篇文章主要讲解了“Libtask源码解析之如何理解锁”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Libtask源码解析之如何理解锁”吧!libtask中...
    99+
    2022-10-19
  • 教你如何搭建android源代码repo仓库
    目录1 repo是如何管理仓库的?1.1 repo如何工作的?1.2 搭建repo服务需要做哪些事情?2 部署工具仓库git-repo.git3 部署清单仓库manifests.gi...
    99+
    2022-11-13
  • 如何理解LevelDB源码中的SSTable
    如何理解LevelDB源码中的SSTable,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。MemTable是内存表,而当内存表...
    99+
    2022-10-19
  • 如何理解Ubuntu编译源码包
    如何理解Ubuntu编译源码包,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。学习编译时,你可能会遇到Ubuntu编译问题,这里将介绍Ubuntu编译问题的解决方法,在这里拿...
    99+
    2023-06-17
  • 如何使用gitee源代码
    Gitee是一个国内开源项目管理平台,支持Git代码托管,团队协作,代码审查等功能。本文将介绍如何使用Gitee源代码。注册Gitee账户首先,你需要在Gitee上注册一个账户。打开Gitee官网(https://gitee.com/),点...
    99+
    2023-10-22
  • 如何编写ipclear.vbs源代码
    本篇内容介绍了“如何编写ipclear.vbs源代码”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!复制代码 代码如下:Option ...
    99+
    2023-06-08
  • 如何进行C++代码的资源管理?
    如何进行C++代码的资源管理以C++为例,资源管理是程序开发中非常重要的一环。良好的资源管理可以提高程序的性能和稳定性,减少内存泄漏和资源浪费。本文将介绍一些常用的C++资源管理技术和最佳实践。1.使用智能指针:C++11引入了智能指针的概...
    99+
    2023-11-02
    内存管理 资源分配 C++资源管理
  • redis如何处理乱码
    在Redis中处理乱码需要注意以下几个方面:1. 字符编码:Redis默认使用UTF-8编码,可以在配置文件中设置字符编码。如果出现...
    99+
    2023-09-06
    redis
  • Mango Cache缓存管理库TinyLFU源码解析
    目录介绍整体架构初始化流程读流程写流程事件处理机制主流程write清理工作缓存管理什么是LRU什么是SLRU什么是TinyLFUmango Cache中的TinyLFUcounter...
    99+
    2022-11-11
  • MyBatis源码剖析之Mapper代理方式详解
    目录源码剖析-getmapper()源码剖析-invoke()具体代码如下: //前三步都相同 InputStream resourceAsStream = Resources.ge...
    99+
    2022-11-13
  • JDK动态代理步骤详解(源码分析)
    动态代理步骤 1.创建一个实现接口InvocationHandler的类,它必须实现invoke方法 2.创建被代理的类以及接口 3.通过Proxy的静态方法 通过Proxy的静态方...
    99+
    2022-11-12
软考高级职称资格查询
推荐阅读
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作