zoukankan      html  css  js  c++  java
  • Redis设计与实现第一部分:第7章:Redis-压缩列表

      压缩列表(ziplist)是列表键和哈希键的底层实现之一。

      当一个列表键只包含少量列表项,并且每个列表项要么就是小得整数值,或者是长度表较短的字符串,那么Redis就会使用压缩列表来做列表键的底层实现。

      当一个哈希键只包含少量键值对,并且每个键值对的键和值要么是小得整数值,或者是长度表较短的字符串,那么Redis就会使用压缩列表作为哈希键的底层实现。

      压缩列表构成:

      压缩列表是为了Redis节约内存而开发的,是由一系列特殊编码的内存块组成的顺序型(sequential)数据结构。一个压缩列表可以包含任意多个节点,一个节点可以保存一个字节数组或者一个整数值。

      压缩列表组成部分(各个组成部分的类型、长度和用途):  

      

      zlbytes:unit32_t类型,4字节:记录整个一搜索列表占用的内存字节数,对压缩列表进行内存重新分配,活着计算zlend的位置时使用。

      zltail:unit32_t类型,4字节:记录压缩列表表尾节点距离要锁列表的起始地址有多少个字节:通过这个偏移量,程序无须遍历整个压缩列表就可以了确定表尾节点的地址。

      zllen:unit16_t类型,2字节:记录压缩列表包含的节点数量,当这个属性的值小于UNIT16_MAX(65535)时,这个属性的值就是压缩列表包含节点的数量;当这个属性的值等于UNIT16_MAX(65535)时,节点的真实数量需需要遍历整个压缩列表才可以计算得出。

      entryX:列表节点:,不定:压缩列表的各个节点,节点的长度由节点保存的内容决定。

      zlend:unit8_t,1字节:特殊值0xFF(十进制255),用于标记压缩列表的末端。

      压缩表示例:

      

      zlbytes:属性值为0xd2(十进制210),表示压缩列表总裁为210字节;

      zltail:属性值为0xb3(十进制为179),这表示一个指向压缩列表起始地址的指针p,那么只要指针p加上偏移量179,就可以了计算出表尾节点entry5的地址。

      zllen:属性值为0x5(十进制5),表示压缩列表的5个节点。

      压缩列表节点的构成:

      已知每个压缩列表节点的构成是一个字节数组或者是一个整数值,其中字节数组可以是以下三种长度之一:

      1.长度小于等于63(2^6-1)字节的字节数组;

      2.长度小于等于16383(2^14-1)字节的字节数组;

      3.长度小于等于4294967195(2^32-1)字节的字节数组;

      而整数值可以是以下六种长度之一:

      1. 4位长,介于0到12之间的无符号整数;

      2. 1字节长的有符号整数;  

      3. 3字节长的有符号整数;

      4. int16_t类型整数;

      5. int32_t类型整数;

      6. int64_t类型整数;

      每个压缩列表节点都是由三个部分组成:

      

      1. previous_entry_length:以字节为单位,记录压缩列表中前一个节点的长度,长度可以是1字节或者5字节;

        a. 如果前一个及节点的长度小于254字节,则该属性长度为1字节:前一个节点的长度保存在这一个字节里面;

        b. 如果前一个节点的长度大于254字节,则该属性长度为5字节,其中属性的第一字节被设置为 0xFE(十进制254),而之后的四个字节保存前一个节点的长度。

      因为节点previous_entry_length属性记录了前一个节点的长度,所以程序可以通过指针运算,根据当前节点的起始地址计算出前一个节点的起始地址。

      压缩列表的从表尾指向表头遍历操作就是使用这个原理实现的,只要我们拥有了一个指向某个节点起始地址的指针,就可以了通过这个指针以及这个节点的previous_entry_length属性,程序就可以一直向前一个节点回溯,最终到达压缩列表的表头结点。

      2. encoding:记录节点content属性所保存数据的类型记及长度:

      1字节、2字节或者5字节长:值得最高位为00,01或者10的是字节数组编码,这种编码表示节点的content属性保存着字节数组,数组的长度由编码除去最高2位之后的其它记录。

      1字节长:值得最高位以11开头的整数编码,这种编码表示节点的content属性保存着整数值,整数值的类型和长度由编码除去最高2位之后的其它记录。

      3. content:节点的content属性负责保存节点的值,节点值可以是一个字节数组或者整数,值得类型和长度由节点的encoding属性决定。

      压缩列表节点示例:

      

      连锁更新:

      假设从e1到eN的所有节点的长度都小于254字节,所以记录这些节点的长度只需要1字节长的previous_entry_length属性。这时,入股哟将一个长度大于等于254字节的新节点new设置为压缩列表的表头节点,那么new将成为e1的前置节点。

      因为e1的previous_entry_length属性仅长为1字节,它没办法保存新节点new的长度,所以程序将对压缩列表执行空间重分配操作,并将e1节点的previous_entry_length属性从原来的1字节长罗占为5字节长。然而这将会导致e1的长度大于254字节,从而又导致e2的产长度大于254字节,循环往复,会让每个节点的长度大于254字节。

      Redis将这种特殊情况下产生的连续多次空间扩展操作称之为“连锁更新”。

      除了添加新节点会导致连锁更新,删除节点也可能引发连锁更新。

  • 相关阅读:
    Add Two Numbers
    Reverse Linked List II
    Reverse Linked List
    Remove Duplicates from Sorted List
    Remove Duplicates from Sorted List II
    Partition List
    Intersection of Two Linked Lists
    4Sum
    3Sum
    2Sum
  • 原文地址:https://www.cnblogs.com/luoshengjie/p/10232514.html
Copyright © 2011-2022 走看看