`

redis 字符串和列表实现

阅读更多
    Redis 虽说由 C 语言实现,但用户直接操作的字符串绝大多数情况下均非 C 语言中以空字符结尾的字符串,而是一种封装了 C 字符串的称作简单动态字符串(simple dynamic string, SDS)的抽象结构,并将其作为 Redis 的默认字符串表示。
    SDS 结构的定义如下:
struct sdshdr{
    int len;       // 记录 buf 数组中已使用的字节数,等于 SDS 所保存的字符串的长度
    int free;      // 记录 buf 数组中未使用的字节数
    char buf[];    // 保存真正的字节数据,长度为:len + free + 1(额外的一字节用于保存末尾的空字符)
};

    之所以采用 SDS 结构而非直接使用 C 风格字符串,主要是为了满足 Redis 对字符串在安全性、效率以及功能方面的要求。这主要表现在以下几方面。
    1、获取字符串长度的复杂度
    因为访问 C 字符串的长度则需要 O(N)(N 为字符串的长度),而根据 SDS 结构的定义可知,要获取其保存的字符串的长度,只需访问 len 属性即可,时间复杂度为 O(1),这避免了在 Redis 中反复执行 STRLEN 命令对系统性能造成的影响。
    2、杜绝缓冲区溢出
    SDS 的内存分配策略能保证在每次修改 SDS 底层存储的字符串时,buf 数组有足够的空间容纳新的字符串,从而避免了缓冲区溢出的可能。
    3、使用了空间预分配和惰性空间释放来优化内存分配
    当剩余的未使用空间 free 不能容纳修改后增长的字节长度时,使用空间预分配能减少连续执行字符串增长操作所需的内存重分配次数。具体的预分配策略算法如下:
    a)若修改后 SDS 的字符串长度 len 小于 1MB,则分配和 len 同样大小的未使用空间 free,此时 SDS 的属性 len 和 free 的值相同。
    b)若修改后 SDS 的字符串长度 len 不小于 1MB,则额外分配 free 为 1MB 的未使用空间。
    而使用惰性空间释放则是指:在需要缩短 SDS 保存的字符串时,程序并不立即释放缩短后多出来的空间,而是追加到 free 属性中,以备将来使用。
    4、二进制安全
    由于 C 字符串是以空字符来区分字符串是否结束,所以这使得其只能保存文本数据,而不能保存数据中可能含有空字符的二进制数据(如图片、音频、视频和压缩文件等)。为了确保 Redis 可以适用于多种场景,SDS 的 API 都是二进制安全的(binary-safe)。这也是将 buf 称为字节数组的原因,因为 Redis 不是用它来保存字符,而是用来保存一系列二进制数据。因此 SDS 是使用 len 属性而非空字符来判断字符串是否结束。
    5、兼容部分 C 字符串函数
    尽管 SDS 的 API 都是二进制安全的,但它们依然遵循 C 字符串以空字符串结尾的惯例,这主要是为了让那些保存文本数据的 SDS 可以重用一部分 C 中的字符串函数。

    Redis 中的列表结构是基于双端链表的,因此它既支持栈操作,也支持队列操作。除列表键值外,Redis 中的发布与订阅、慢查询、监视器等功能也都用到了链表结构。每个链表节点都使用一个 listNode 结构来表示,此外,为了方便操作,Redis 用了一个 list 结构来封装了 listNode 结构组成的链表。这两种结构的定义如下:
typedef struct listNode{
    struct listNode *prev;         // 前置节点
    struct listNode *next;         // 后置节点
    void *value;                   // 节点值
}listNode;

typedef struct list{
    listNode *head;                // 表头节点
    listNode *tail;                // 表尾节点
    unsigned long len;             // 列表所包含的节点数量
    void *(*dup)(void *ptr);               // 节点值复制函数
    void (*free)(void *ptr);               // 节点值释放函数
    int (*match)(void *ptr, void *key);    // 节点值对比函数
}list;

    为实现多态,以便链表可以用于保存各种不同类型的值,listNode 结构中使用了“void *”空指针来保存节点值,并通过 list 结构中的 dup、free 和 match 三个属性来为节点值设置类型特定函数。

参考:
1、《Redis 设计与实现》第二章——简单动态字符串。
2、《Redis 设计与实现》第三章——链表。
分享到:
评论

相关推荐

    使用SDS代码结构实现Redis字符串的编写.docx

    ### 使用SDS代码结构实现Redis字符串的编写 #### SDS简介 Redis是一款高性能的键值存储系统,因其出色的性能和灵活性而被广泛应用于多种场景。为了达到高性能的目标,Redis在很多方面都进行了精心设计,其中就包括...

    Redis中的动态字符串学习教程

    Redis作为一个键值对数据库,键和值可以是多种类型的对象,如字符串、集合或列表。对于存储字符串的字符串对象,它们内部就包含了一个`sds`值。例如,通过`SET`和`GET`命令创建的键值对,其键和值都是字符串对象,...

    Redis 字符串(String)

    Redis字符串的另一个重要特性是它可以作为计数器使用,通过INCR、INCRBY和DECR、DECRBY等命令进行原子性的递增或递减操作,这在分布式环境中非常有用,例如统计网站访问量或者实现限流策略。 需要注意的是,Redis的...

    Redis的字符串的速度与安全.docx

    SDS 是 Redis 为了提高字符串操作的效率和安全性而自定义的一种数据结构,它在 Redis 的各种操作中扮演着重要角色,包括作为键值对中的键和值,以及作为缓冲区(buffer)。 SDS 结构包含三个字段: 1. `len`:表示...

    Redis操作字符串工具类封装,Redis工具类封装

    它支持多种数据结构,包括字符串(String)、哈希(Hash)、列表(List)、集合(Set)和有序集合(Sorted Set)。在Java开发中,为了方便与Redis进行交互,通常会封装一个工具类,本文将详细介绍如何封装一个基于...

    Redis字符串原理的深入理解

    Redis字符串原理的深入理解 Redis作为一种高性能的Key-Value存储系统,其数据结构的设计和实现对于性能至关重要。本文主要探讨Redis中的字符串(String)数据结构,包括它的特性、内部实现以及编码格式,帮助读者...

    C#实现访问Redis数据库

    Redis支持多种数据结构,如字符串、哈希、列表、集合和有序集合。以下是一些基本操作的例子: 1. **字符串操作**: 设置键值对: ```csharp var db = redis.GetDatabase(); db.StringSet("key", "value"); ```...

    Redis工具类,工具类封装了基本的 Redis 操作,如字符串、哈希表、列表、集合的处理以及分布式锁的实现

    工具类封装了基本的 Redis 操作,如字符串、哈希表、列表、集合的处理,还包括了分布式锁的实现。这种封装不仅提高了代码的可读性和可维护性,还减少了重复代码的编写。 1、字符串操作 get(key)、set(key, value)、...

    《Redis设计和实现 黄建宏著》配套 Redis 3.0 中文注释版源码

    1. 数据类型:Redis支持五种基本数据类型,包括字符串(String)、哈希(Hash)、列表(List)、集合(Set)和有序集合(Sorted Set)。这些数据类型提供了丰富的操作,满足各种应用场景。 2. 主从复制:Redis支持主从复制,...

    java连接Linux上的redis,并用代码实现java操作redis的基本操作键(字符串,列表,哈希,散列,有序集合)

    简单来说就是用java实现远程操作redis,ip地址要找到自己linux上连网后的ip地址,在每个case文件中修改后就可以实现了,对应的test文件是实现操作文件,你可以自己写一个主程序把他们包括起来。哦,对了这里面包括了...

    tomcat-redis实现session共享

    而Redis则是一种高性能的键值对存储数据库,支持多种数据结构如字符串、哈希、列表、集合和有序集合,非常适合用来存储Session数据。 接下来,我们来具体实施Tomcat和Redis的集成步骤: 1. **安装Redis**:在开始...

    Redis读书笔记(设计实现PDF)

    Redis支持五种基本数据类型:字符串(Strings)、哈希(Hashes)、列表(Lists)、集合(Sets)和有序集合(Sorted Sets)。这些数据类型的灵活性使得Redis能应对多种应用场景,如存储用户信息、实现消息队列等。 2. **Redis...

    java 对Redis的导入和导出

    首先,要进行Redis数据的导入和导出,我们需要了解Redis的数据结构,包括字符串(Strings)、哈希(Hashes)、列表(Lists)、集合(Sets)和有序集合(Sorted Sets)。这些数据类型在Java中都有对应的客户端库支持,如Jedis和...

    SpringBoot中利用Redis实现消息队列,代码亲测可用, 可以传输字符串,或java对象都可以

    SpringBoot中利用Redis实现消息队列,代码亲测可用, 可以传输字符串,或java对象都可以

    Redis介绍与内部实现机制PPT

    字典结构在大多数脚本语言中都非常常见,其中键值对不仅限于简单的字符串,还可以是更复杂的数据类型如列表、集合等。通过TCP协议,应用程序可以轻松地对Redis中的数据进行读写操作。 **(二)内存存储与持久化** ...

    Redis发布订阅.net实现

    它支持多种数据类型的操作,如字符串、哈希、集合、有序集合等,同时包含发布订阅功能。通过这个库,我们可以在.NET应用中方便地实现Redis的发布订阅功能。 3. Key过期通知(Expiration Notifications): Redis...

    Tomcat8(Tomcat9)+redis实现Session共享(支持Redis集群)

    它支持丰富的数据结构,如字符串、哈希、列表、集合、有序集合,同时提供了丰富的API,使得与各种应用集成变得简单。在本示例中,我们将使用Redis作为Session的存储介质。 实现步骤如下: 1. **安装和配置Redis**...

    redis 缓存技术学习笔记

    与传统的键值存储系统Memcached相比,Redis支持更多的数据类型和丰富的操作,包括字符串(Strings)、列表(Lists)、集合(Sets)和有序集合(ZSets)等。 - **数据类型及其操作**:Redis支持的数据类型非常丰富,包括基本...

    Java 实现Redis存储复杂json格式数据并返回给前端

    2. **JSON字符串存储**:最简单的方式是将Java对象转换为JSON字符串,然后存储为Redis中的String类型。Fastjson库在这里被用到,其`toJSONString`方法可以将Java对象转化为JSON格式的字符串。获取时,直接返回JSON...

Global site tag (gtag.js) - Google Analytics