ziplist

ziplist结构

ziplist的布局如下,所有的字符默认使用小端序保存:

+--------+--------+--------+--------+-------+-------+-------+
|zlbytes | zltail | zllen | entry | ... | entry | zlend |
+--------+--------+--------+--------+-------+-------+-------+
  • uint32_t zlbytes:为一个无符号整数。保存了ziplist占用的字节数,包含zlbytes字段本身占用的4个字节。主要用于调整数据结构的大小。

  • uint32_t zltail:最后一个entry的字节偏移量(非zlend)。用于从list的另一端执行pop操作(即倒序遍历)

  • uint16_t zllen:entry的数目。当保存的entry大于216-2个entry时,则将该值设置为216-1,此时需要遍历整个entry list来计算list中的entry数目

  • uint8_t zlend:表示ziplist中的最后一个entry。字节编码等同于255(即FF)。表示ziplist的结束符

ziplist中的每个entry都使用一个元数据作为前缀,该元数据包含两部分的信息:首先保存了前一个entry的长度,用于倒序查找;再者保存了entry的编码类型,表示entry的类型,如整数或字符串,当编码类型为字符串时,该字段也表示了字符串的长度。字符串的entry-data的长度就等同于该字符串的长度,而整数的entry-data的长度需要根据编码类型进行判断,并不一定等同于其entry-data字符串的长度(见下文encoding)。一个完整的entry为:

+--------+--------+----------+
|prevlen |encoding|entry-data|
+--------+--------+----------+

有时编码类型即表示entry本身(例如小的整数),这种情况下会忽略entry-data字段,此时entry变为:

+--------+--------+
|prevlen |encoding|
+--------+--------+

prevlen

prevlen表示前一个entry的长度,使用如下方式进行编码:当前一个entry的长度小于254(255是个特殊字符,被zlend使用)字节时,该字段会使用一个字节(即8 bit)表示长度;当长度大于或等于254时,将会使用5个字节,此时第一个字节会被设置为254(FE)来表示一个较大的数值,后续4个字节表示前面一个entry的长度。

因此,prevlen的编码为:

  • 如果前一个entry的长度小于254,编码为:

    +-------+--------+-----+
    |prevlen|encoding|entry|
    +-------+--------+-----+
  • 如果前一个entry的长度大于254,编码如下:

    +----+---------------+--------+-----+
    |0xFE|4 bytes prevlen|encoding|entry|
    +----+---------------+--------+-----+

encoding

entryencoding字段取决于entry的内容。当entry为字符串时,encoding的第一个字节的前2bit保存了编码类型,剩余的bit位表示字符串的长度。当entry为整数时,encoding仅占用1个字节,encoding的前2bit都设置为1,后续的2bit用于指定整数的类型,如int16_t,int32_t。encoding中的第一个字节总是用于判定entry的类型。举例如下:

 * |00pppppp| - 1 byte
* 字符串的长度小于或等于63字节(6 bits).
* "pppppp" 表示6bit长度的无符号整数.
* |01pppppp|qqqqqqqq| - 2 bytes
* 字符串的长度小于或等于16383字节(14 bits).
* IMPORTANT: 14 bit的数字使用大端序保存.
* |10000000|qqqqqqqq|rrrrrrrr|ssssssss|tttttttt| - 5 bytes
* 字符串的长度大于或等于16384字节,只使用第1个字节之后的4个字节表示长度,最大为32^2-1,第一个
* 字节的低6位没有使用,设置为0。因此entry的最大长度为32
* IMPORTANT: 32 bit的数字使用大端序保存.
* |11000000| - 3 bytes
* 整数编码为int16_t (2 bytes).
* |11010000| - 5 bytes
* 整数编码为int32_t (4 bytes).
* |11100000| - 9 bytes
* I整数编码为int64_t (8 bytes).
* |11110000| - 4 bytes
* 编码为24 bit的有符号整数 (3 bytes).
* |11111110| - 2 bytes
* 编码为8 bit的有符号整数 (1 byte).
* |1111xxxx| - (xxxx 取值为 0000 到 1101) 表示4bit的整数
* 无符号整数的取值为0到12,由于无法使用0000(被|11110000|编码占用)和1111(被zlend占用),因此取值
* 为1到13,因此需要从低4位的整数减去1获得entry的值.
* |11111111| - 表示ziplist的终止entry,即zlend

举例

整数编码

如下ziplist包含2个元素,表示字符串"2"和"5",长度为15字节,可以看到由于数值小于13,其编码和数值放在了一个字节中。

 [0f 00 00 00] [0c 00 00 00] [02 00] [00 f3] [02 f6] [ff]
| | | | | |
zlbytes zltail entries "2" "5" end

前4个字节(zlbytes)表示15,即整个ziplist包含的字节数;第2个4字节(zltail)最后一个entry的字节偏移,即字符串为"5"的entry的位置,偏移量为12字节;接下来的16bit(entries)表示ziplist中的entry的数目,为2;"00 f3"表示list中的第一个entry "2",它包含了前一个entry的长度(prevlen),为0,"f3"对应的编码为"|1111xxxx|","xxxx"的取值为0001到1101,去除前4个bit "1111",并减去1,得到entry的值为2。下一个entry的prevlen为2,表示前一个entry占用了2字节."f6"的编码与前一个相同,去除前4个bit,并减去1,得到entry的值为5;最后的"ff"表示ziplist的结束(zlend)。

字符串编码

在上述ziplist中追加一个"Hello World"的entry的编码。第一个字节表示前面entry的长度,第二个字节表示encoding,二进制为"|00pppppp|",因此"0b"表示一个11字节的字符串。从第3个字节(48)到最后一个字节(64)表示ASCII编码的字符串"Hello World"。

[02] [0b] [48 65 6c 6c 6f 20 57 6f 72 6c 64]

源码解析参见:ziplist.c

redis 6源码解析之 ziplist的更多相关文章

  1. Redis源码解析之ziplist

    Ziplist是用字符串来实现的双向链表,对于容量较小的键值对,为其创建一个结构复杂的哈希表太浪费内存,所以redis 创建了ziplist来存放这些键值对,这可以减少存放节点指针的空间,因此它被用来 ...

  2. Redis系列(十):数据结构Set源码解析和SADD、SINTER、SDIFF、SUNION、SPOP命令

    1.介绍 Hash是以K->V形式存储,而Set则是K存储,空间节省了很多 Redis中Set是String类型的无序集合:集合成员是唯一的. 这就意味着集合中不能出现重复的数据.可根据应用场景 ...

  3. .Net Core缓存组件(Redis)源码解析

    上一篇文章已经介绍了MemoryCache,MemoryCache存储的数据类型是Object,也说了Redis支持五中数据类型的存储,但是微软的Redis缓存组件只实现了Hash类型的存储.在分析源 ...

  4. Redis系列(九):数据结构Hash源码解析和HSET、HGET命令

    2.源码解析 1.相关命令如下: {"hset",hsetCommand,,"wmF",,NULL,,,,,}, {"hsetnx",hse ...

  5. Redis 源码解析之通用双向链表(adlist)

    Redis 源码解析之通用双向链表(adlist) 概述 Redis源码中广泛使用 adlist(A generic doubly linked list),作为一种通用的双向链表,用于简单的数据集合 ...

  6. Redis 动态字符串 SDS 源码解析

    本文作者: Pushy 本文链接: http://pushy.site/2019/12/21/redis-sds/ 版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 3.0 许可 ...

  7. Ocelot简易教程(七)之配置文件数据库存储插件源码解析

    作者:依乐祝 原文地址:https://www.cnblogs.com/yilezhu/p/9852711.html 上篇文章给大家分享了如何集成我写的一个Ocelot扩展插件把Ocelot的配置存储 ...

  8. t-io 集群解决方案以及源码解析

    t-io 集群解决方案以及源码解析 0x01 概要说明 本博客是基于老谭t-io showcase中的tio-websocket-showcase 示例来实现集群.看showcase 入门还是挺容易的 ...

  9. .Net Core缓存组件(MemoryCache)源码解析

    一.介绍 由于CPU从内存中读取数据的速度比从磁盘读取快几个数量级,并且存在内存中,减小了数据库访问的压力,所以缓存几乎每个项目都会用到.一般常用的有MemoryCache.Redis.MemoryC ...

  10. Spring-Session实现Session共享实现原理以及源码解析

    知其然,还要知其所以然 ! 本篇介绍Spring-Session的整个实现的原理.以及对核心的源码进行简单的介绍! 实现原理介绍 实现原理这里简单说明描述: 就是当Web服务器接收到http请求后,当 ...

随机推荐

  1. 一文详解什么是可解释AI

    摘要:本文带来什么是可解释AI,如何使用可解释AI能力来更好理解图片分类模型的预测结果,获取作为分类预测依据的关键特征区域,从而判断得到分类结果的合理性和正确性,加速模型调优. 1. 为什么需要可解释 ...

  2. 获取全国GeoJSON和各省市GeoJSON数据下载

    第一,从阿里云下载: http://datav.aliyun.com/tools/atlas/#&lat=33.50475906922609&lng=104.2822265625&am ...

  3. 【辅助工具】Postman使用

    Postman使用 批量处理 https://www.bbsmax.com/A/A7zglyjoJ4/ pm.test("测试结果成功", function () {     pm ...

  4. VSCode一键调用DOSBox运行MASM/TASM代码的自定义任务

    在学习汇编的时候,发现很多教程都未使用 VSC 进行开发,今天在 Gitee 看有意思的项目时候发现了这个 DOS汇编/VSC-ASMtasks 通过配置VSCode的自定义任务来实现调用dosbox ...

  5. IntelliJ IDEA项目导入时报错:The import javax.servlet.http.HttpServletRequest cannot be resolved

    IntelliJ IDEA项目导入时报错: The import javax.servlet.http.HttpServletRequest cannot be resolved 翻译一下错误信息是说 ...

  6. (组合游戏)SG函数与SG定理详解

    有一段时间没记录知识类的博客了,这篇博客就说一下SG函数和SG定理吧 SG函数是用于解决博弈论中公平组合游戏(Impartial Combinatorial Games,ICG)问题的一种方法. 什么 ...

  7. 数字孪生 3D 风电场,智慧风电之海上风电

    前言 截止 2021 年,全球已有 127 个国家做出了"碳中和"的承诺,能源低碳转型和实现碳中和已经成为全球共同的战略目标.根据权威机构预测,到 2050 年,可再生能源发电将占 ...

  8. windows 系统关闭占用端口的应用

    开发中有时候开发工具把程序关闭了,但是后台并没有真正关闭程序,导致再次启动相同端口的程序时报端口已经被使用的错误,这时如何强制关闭已占用的端口 1.打开dos对话框 2.查找被占用的端口的进程号 ne ...

  9. vue 状态管理 三、Mutations和Getters用法

    系列导航 vue 状态管理 一.状态管理概念和基本结构 vue 状态管理 二.状态管理的基本使用 vue 状态管理 三.Mutations和Getters用法 vue 状态管理 四.Action用法 ...

  10. vue-awesome-swiper swiper/dist/css/swiper.css 报not found错误

    解决办法删除package-lock.json文件写死package.json版本号  "vue-awesome-swiper": "^3.1.3", 删除no ...