redis 源代码之数据结构(5)--ziplist实现

上一篇分析了zipmap的源代码,zipmap在redis中比较鸡肋,实际上,在2.6版本中,并没有使用zipmap数据结构,zipmap可以用ziplist来进行替代。ziplist用字符串实现了双链表,非常节约内存,既可以存储字符串,也可以存储整型。对ziplist两端进行pop和push操作可以在O(1)时间内完成。但是,每次对ziplist的操作,可能会需要对list进行realloc,所以复杂度和ziplist占用的内存大小相关。

ziplist的内存布局:

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

<zlbytes>表示ziplist所占用的总字节数;<zltail>表示ziplist的最后一个entry的偏移(相对于开头),加入这个字段,主要是为pop操作可以在O(1)时间内完成。<zllen>表示entry的链表节点个数,但是,当节点数大于2^16-2,只能通过遍历得到链表长度。<zlend>是一个标志字节,等于255,暗示链表的结尾。

我们来看看ziplist的节点数据结构:

typedef struct zlentry {
    unsigned int prevrawlensize, prevrawlen;
    unsigned int lensize, len;
    unsigned int headersize;
    unsigned char encoding;
    unsigned char *p;
} zlentry;
prevrawlensize是存储前一个节点长度所需要的字节数 ,prevrawlen存储的是前一个节点的占用字节数,这样可以从后往前遍历(双向链表)。

lensize是存储当前节点长度所需要的字节数,len是当前节点占用的字节数。

headersize 当前节点 头部大小

encoding表示当前节点的len字段的编码类型。

指向当前节点的起始位置。

ziplist节点存储结构

<上一个节点占用的长度><当前链表节点占用的长度><当前节点数据>

<上一个节点占用的长度>   根据这个数值,可以往前遍历,实现双向链表。如果前节点小于254,就用1个字节表示之,否则就用5个字节表示上一个节点的长度,其中第一个字节数值是254,其余的四字节表示上一个节点的真正长度。

<当前链表节点占用的长度>  第一个字节的前两位表示数据类型。具体编码如下:

  |00pppppp| - 1 byte
       字符串编码类型,字符串最大长度是63字节
  |01pppppp|qqqqqqqq| - 2 bytes
      字符串编码类型, 最大长度是 16383 bytes (14 bits).
  |10______|qqqqqqqq|rrrrrrrr|ssssssss|tttttttt| - 5 bytes
       字符串编码模型,最小长度是16384。
  |11000000| - 1 byte
       整型编码,紧随其后的2字节是长度数值 int16_t (2 bytes).
  |11010000| - 1 byte
       整型编码,紧随其后的4字节是长度数值  encoded as int32_t (4 bytes).
  |11100000| - 1 byte
       整型编码,紧随其后的8字节是长度数值 encoded as int64_t (8 bytes).
  |11110000| - 1 byte
       整型编码,紧随其后的3字节是长度数值 encoded as 24 bit signed (3 bytes).
  |11111110| - 1 byte
       整型编码,紧随其后的2字节是长度数值 encoded as 8 bit signed (1 byte).
  |1111xxxx| - (with xxxx between 0000 and 1101) immediate 4 bit integer.
       Unsigned integer from 0 to 12. 我勒个去,这13个数还不放弃,实际上是从数值直接读取的是1~13,所以要减去1,才能得到编码值。
  |11111111| - 链表的结尾




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
bind 0.0.0.0 protected-mode no port 6379 tcp-backlog 511 timeout 0 tcp-keepalive 300 daemonize yes supervised no pidfile /var/run/redis_6379.pid loglevel notice logfile /var/log/redis/redis.log databases 16 always-show-logo yes save 900 1 save 300 10 save 60 10000 stop-writes-on-bgsave-error yes rdbcompression yes rdbchecksum yes dbfilename dump.rdb dir /var/lib/redis replica-serve-stale-data yes replica-read-only yes repl-diskless-sync no repl-diskless-sync-delay 5 repl-disable-tcp-nodelay no replica-priority 100 requirepass root@123 lazyfree-lazy-eviction no lazyfree-lazy-expire no lazyfree-lazy-server-del no replica-lazy-flush no appendonly no appendfilename "appendonly.aof" appendfsync everysec no-appendfsync-on-rewrite no auto-aof-rewrite-percentage 100 auto-aof-rewrite-min-size 64mb aof-load-truncated yes aof-use-rdb-preamble yes lua-time-limit 5000 slowlog-log-slower-than 10000 slowlog-max-len 128 latency-monitor-threshold 0 notify-keyspace-events "" hash-max-ziplist-entries 512 hash-max-ziplist-value 64 list-max-ziplist-size -2 list-compress-depth 0 set-max-intset-entries 512 zset-max-ziplist-entries 128 zset-max-ziplist-value 64 hll-sparse-max-bytes 3000 # value. stream-node-max-bytes 4096 stream-node-max-entries 100 activerehashing yes client-output-buffer-limit normal 0 0 0 client-output-buffer-limit replica 256mb 64mb 60 client-output-buffer-limit pubsub 32mb 8mb 60 hz 10 dynamic-hz yes aof-rewrite-incremental-fsync yes rdb-save-incremental-fsync yes
最新发布
07-22

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值