redis之ziplist

本文剖析redis的ziplist的实现。

ziplist是一个存储高效的双链表,存储的元素类型有字符串和整数;虽然存储高效,但每次插入或删除ziplist中的元素都会引起重新分配内存,所以,ziplist作为大型只读表非常高效,频繁的插入或删除ziplist不太合适;

ziplist的内部结构:

<zlbytes><zltail><zllen><entry><entry><zlend>

  1. zlbytes是一个unsigned int数字,表示整个ziplist占用的字节数;
  2. zltail是最后一个元素的偏移量,也是unsigned int;
  3. zllen是unsigned short数字,存储ziplist的元素个数,如果个数超过0xFFFF,需要遍历list才能得到元素个数;
  4. entry就是元素本身;
  5. zlend是0xFF,特殊标记;

entry内部结构:

<prelen><curlen><body>

  1. prelen表示上一个元素的大小;
  2. curlen表示当前元素的大小;
  3. body存储元素内容;

prelen有两种存储方式:

  1. 小于254时,直接用一个字节存储;
  2. 大于或等于254时,用五个字节存储,第一个字节存储254,接下来四个字节存储prelen;

curlen有六种存储方式:

元素为字符串类型:

  1. 字符串长度小于或等于0xFFFFFF(63),用一个字节表示,|00pppppp|,00是type,pppppp是值;
  2. 字符串长度大于0xFFFFFF(63)小于或等于0xFFFFFFFFFFFFFF(16383),用两个字节表示,|01pppppp|qqqqqqqq|,01是type,ppppppqqqqqqqq是值;
  3. 字符串长度大于0xFFFFFFFFFFFFFF(16383),用五个字节表示,|10______|qqqqqqqq|rrrrrrrr|ssssssss|tttttttt|,10是type,后面四个字节是值;

元素为整数类型:

  1. 一个字节表示,|1100____|表示整数用int16_t存储,隐含值为2;
  2. 一个字节表示,|1101____|表示整数用int32_t存储,隐含值为4;
  3. 一个字节表示,|1110____|表示整数用int64_t存储,隐含值为8;

因为ziplist是紧凑的存储方式,所有东西都存放在连续的内存中,所以,插入删除元素特别费劲,需要重新分配内存;

插入元素:

对字符串元素尝试压缩为整数;

需要的内存量:lensize(prevlen) + lensize(curlen) + curlen + nextdiff;

对于下一个entry来说,前一个entry发生变化,需要更新prelen;

因为prelen采用变长存储,所以lensize(prelen)可能发生变动,这样会导致下一个entry自身的大小也发生变化;

这个更新可能会继续下去直到链尾或者收敛;

nextdiff的含义就是下一个entry的大小变化情况,值为:<调整后大小> - <调整前大小>;

当nextdiff为0时,调整收敛;

删除元素:

元素被删除,需要move后续元素以保持内存紧凑;

对被删除元素的下一个entry来说,可能需要更新prelen,这个更新也是级联的;

元素的插入和删除都需要更新zltail;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值