Redis设计与实现(一~五整合版)(4)

那么,怎样实现呢?很简单,通过 encoding + length 就可以搞定。encoding 占2位,00,01,10,11表示不明的类型,只有11代表的是节点中存放的是整型,其他3个代表节点中存放的都是字符串。而根据这2位的不同,又对应着不同的长度。

所以,由 encoding 可以知道元素的类型和这个元素的范围(比如 encoding 为01,包括 encoding 在内的2byte 代表长度,所以最长是214 - 1;如果 encoding 为00,包括 encoding 在内的1byte 代表元素的长度,所以最大值为26 -1 )

然后添加元素大概是下面酱紫滴(对于列表来说,添加元素默认是加在列表尾巴的):

首先通过压缩列表的head信息,找到压缩列表的尾巴到head的偏移量(因为可能重新分配内存,所以指针的话会失效)

根据要插入的值,计算出编码类型和插入值的长度。然后还有前一个节点所用的空间、然后对压缩列表进行内存充分配

初始化entry节点的所有相关信息:pre_entry_length、encoding、length、content

更新head中的长度啦、尾偏移啦、压缩列表总字节啦

上面吐槽了压缩列表没有next指针,现在发现有了= =,但是不是指针,因为压缩列表会进行内存充分配,所以指针代表的内存地址需要一直维护,而当使用偏移量的话,就不需要更改一次维护一次。向后遍历是通过头指针+节点的大小(pre_entry_length+encoding+length的总大小)就可以跳到下一个节点了

不过,说实话,压缩列表这个设计的好处我还没有看到,可能还需要和后面的东西结合吧。

重读之后看到了,(^__^) 嘻嘻……

本质上面已经说的很清楚了——节省内存。所以它不像上一章讲到的那种分配固定的大小,而 intset 和 ziplist 完全是根据内存定做的,一个字节也不多(当然,有些操作还是会有浪费的)。

三 前言

这一章主要是讲redis内部的数据结构是如何实现的,可以说是redis的根基,前面2章介绍了redis的内部数据结构:

redis的内存映射数据结构:

而这一章,就是具体将这些数据结构是如何在redis中工作的。

1. 总观redis内部实现

一张图说明问题的本质:

Screen Shot 2014-09-02 at 23.11.30.png

之后,我们再根据这张图来说明redis中的数据架构为什么是酱紫滴。前面我们已经说过,redis中有5种数据结构,而它们的底层实现都不是唯一的,所以怎样选择对应的底层数据支撑呢?这就需要“多态”的思想,但是因为redis是C开发的。所以通过结构体来模仿对象的“多态”(当然,本质来说这是为了让自己能更好的理解)。

为了完成这个任务,redis是这样设计的:

redisObject对象

基于redisObject对象的类型检查

基于redisObject对象的显式多态函数

对redisObject进行分配、共享和销毁的机制

下面看下redisObject的定义:

/* * Redis 对象 */ typedef struct redisObject { // 类型 unsigned type:4; // 对齐位 unsigned notused:2; // 编码方式 unsigned encoding:4; // LRU 时间(相对于 server.lruclock) unsigned lru:22; // 引用计数 int refcount; // 指向对象的值 void *ptr; } robj;

其中type、encoding、ptr是最重要的3个属性:

type:redisObject的类型,字符串、列表、集合、有序集、哈希表

encoding:底层实现结构,字符串、整数、跳跃表、压缩列表等

ptr:实际指向保存值的数据结构

举个例子就是:

如果一个 redisObject 的 type 属性为 REDIS_LIST , encoding 属性为 REDIS_ENCODING_LINKEDLIST ,那么这个对象就是一个 Redis 列表,它的值保存在一个双端链表内,而 ptr 指针就指向这个双端链表;
如果一个 redisObject 的 type 属性为 REDIS_HASH , encoding 属性为 REDIS_ENCODING_ZIPMAP ,那么这个对象就是一个 Redis 哈希表,它的值保存在一个 zipmap 里,而 ptr 指针就指向这个 zipmap ;诸如此类。

所以,当执行一个操作时,redis是这么干的:

根据key,查看数据库中是否存在对应的redisObject,没有就返回null

查看redisObject的type是否和要执行的操作相符

根据redisObject的encoding属性选择对应的数据结构

返回处理结果

然后reids还搞了一个内存共享,这个挺赞的:

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/6be4ac5bc3f297e5261a68427fc4282e.html