结合redis设计与实现的redis源码学习-7-ziplist(压缩列表)

来源:互联网 发布:js数组包含另一个数组 编辑:程序博客网 时间:2024/05/20 11:32

压缩列表是列表件和哈希键的底层实现之一,当一个列表件只包含少量列表项,并且每个列表项要么就是小整数值,要么就是长度比较短的字符串,那么redis就会使用压缩列表来做列表键的底层实现。
压缩列表的特点:
1、压缩列表是由一系列特殊编码的连续内存块组成的顺序型数据结构。
2、一个压缩列表可以包含任意多个节点,每个节点可以保存一个字节数组或者一个整数值。
3、添加新节点到压缩列表,或者从压缩列表中删除节点,可能会引发连锁更新操邹,但是出现的几率不高。
redis设计与实现中介绍了压缩列表的各个组成部分的详细说明:
zlbytes:uint32_t,4字节长度,记录整个压缩列表占用的内存字节数:在对压缩列表进行内存重分配或者计算zlend的位置时使用。
zltail:uint32_t,4字节长度,记录压缩列表表尾节点距离压缩列表的起始地址有多少字节:通过这个值可以直接确定表尾节点的地址。
zllen:uint16_t,2字节长度,记录了压缩列表的节点数量:当值小于65535时,这个值就是节点数;当这个值大于65535时,真实数量需要遍历整个压缩列表才能得出。
entryX:列表节点:长度不定:由节点保存的内容决定。
zlend:uint8_t:1字节长度:为0xFF,表示压缩列表的末端。
ziplist.h中定义了压缩列表的方法,ziplist.c中定义了压缩列表的结构及方法实现。

#ifndef _ZIPLIST_H#define _ZIPLIST_H#define ZIPLIST_HEAD 0#define ZIPLIST_TAIL 1unsigned char *ziplistNew(void);unsigned char *ziplistMerge(unsigned char **first, unsigned char **second);unsigned char *ziplistPush(unsigned char *zl, unsigned char *s, unsigned int slen, int where);unsigned char *ziplistIndex(unsigned char *zl, int index);unsigned char *ziplistNext(unsigned char *zl, unsigned char *p);unsigned char *ziplistPrev(unsigned char *zl, unsigned char *p);unsigned int ziplistGet(unsigned char *p, unsigned char **sval, unsigned int *slen, long long *lval);unsigned char *ziplistInsert(unsigned char *zl, unsigned char *p, unsigned char *s, unsigned int slen);unsigned char *ziplistDelete(unsigned char *zl, unsigned char **p);unsigned char *ziplistDeleteRange(unsigned char *zl, int index, unsigned int num);unsigned int ziplistCompare(unsigned char *p, unsigned char *s, unsigned int slen);unsigned char *ziplistFind(unsigned char *p, unsigned char *vstr, unsigned int vlen, unsigned int skip);unsigned int ziplistLen(unsigned char *zl);size_t ziplistBlobLen(unsigned char *zl);#ifdef REDIS_TESTint ziplistTest(int argc, char *argv[]);#endif#endif /* _ZIPLIST_H */

ziplist.c

#include <stdio.h>#include <stdlib.h>#include <string.h>#include <stdint.h>#include <limits.h>#include "zmalloc.h"#include "util.h"#include "ziplist.h"#include "endianconv.h"#include "redisassert.h"#define ZIP_END 255#define ZIP_BIGLEN 254/* Different encoding/length possibilities 不同可能的长度*/#define ZIP_STR_MASK 0xc0#define ZIP_INT_MASK 0x30#define ZIP_STR_06B (0 << 6)#define ZIP_STR_14B (1 << 6)#define ZIP_STR_32B (2 << 6)#define ZIP_INT_16B (0xc0 | 0<<4)#define ZIP_INT_32B (0xc0 | 1<<4)#define ZIP_INT_64B (0xc0 | 2<<4)#define ZIP_INT_24B (0xc0 | 3<<4)#define ZIP_INT_8B 0xfe/* 4 bit integer immediate encoding 4位长的整形编码*/#define ZIP_INT_IMM_MASK 0x0f#define ZIP_INT_IMM_MIN 0xf1    /* 11110001 */#define ZIP_INT_IMM_MAX 0xfd    /* 11111101 */#define ZIP_INT_IMM_VAL(v) (v & ZIP_INT_IMM_MASK)//定义int24的最大最小值#define INT24_MAX 0x7fffff#define INT24_MIN (-INT24_MAX - 1)/* Macro to determine type 返回类型定义*/#define ZIP_IS_STR(enc) (((enc) & ZIP_STR_MASK) < ZIP_STR_MASK)/* Utility macros 一些工具定义*/#define ZIPLIST_BYTES(zl)       (*((uint32_t*)(zl)))#define ZIPLIST_TAIL_OFFSET(zl) (*((uint32_t*)((zl)+sizeof(uint32_t))))#define ZIPLIST_LENGTH(zl)      (*((uint16_t*)((zl)+sizeof(uint32_t)*2)))#define ZIPLIST_HEADER_SIZE     (sizeof(uint32_t)*2+sizeof(uint16_t))#define ZIPLIST_END_SIZE        (sizeof(uint8_t))#define ZIPLIST_ENTRY_HEAD(zl)  ((zl)+ZIPLIST_HEADER_SIZE)#define ZIPLIST_ENTRY_TAIL(zl)  ((zl)+intrev32ifbe(ZIPLIST_TAIL_OFFSET(zl)))#define ZIPLIST_ENTRY_END(zl)   ((zl)+intrev32ifbe(ZIPLIST_BYTES(zl))-1)/* We know a positive increment can only be 1 because entries can only be * pushed one at a time. ziplist的增加每次只会是1*/#define ZIPLIST_INCR_LENGTH(zl,incr) { \    if (ZIPLIST_LENGTH(zl) < UINT16_MAX) \        ZIPLIST_LENGTH(zl) = intrev16ifbe(intrev16ifbe(ZIPLIST_LENGTH(zl))+incr); \}//存放数据的节点定义typedef struct zlentry {    unsigned int prevrawlensize/*记录上一个节点长度的长度*/, prevrawlen;/*上一个节点长度*/    unsigned int lensize/*当前节点长度*/, len/*保存当前长度所需要的长度*/;    unsigned int headersize;//数据节点头部信息长度的字节数    unsigned char encoding;//编码方式    unsigned char *p;//数据} zlentry;//初始化一个节点#define ZIPLIST_ENTRY_ZERO(zle) { \    (zle)->prevrawlensize = (zle)->prevrawlen = 0; \    (zle)->lensize = (zle)->len = (zle)->headersize = 0; \    (zle)->encoding = 0; \    (zle)->p = NULL; \}/* Extract the encoding from the byte pointed by 'ptr' and set it into 返回编码方式 * 'encoding'. */#define ZIP_ENTRY_ENCODING(ptr, encoding) do {  \    (encoding) = (ptr[0]); \    if ((encoding) < ZIP_STR_MASK) (encoding) &= ZIP_STR_MASK; \} while(0)/* Return bytes needed to store integer encoded by 'encoding' 返回不同编码的存储长度*/unsigned int zipIntSize(unsigned char encoding) {    switch(encoding) {    case ZIP_INT_8B:  return 1;    case ZIP_INT_16B: return 2;    case ZIP_INT_24B: return 3;    case ZIP_INT_32B: return 4;    case ZIP_INT_64B: return 8;    default: return 0; /* 4 bit immediate */    }    assert(NULL);    return 0;}//编码rawlen到p中,如果p是空的,那么就返回所需要的长度unsigned int zipEncodeLength(unsigned char *p, unsigned char encoding, unsigned int rawlen) {    unsigned char len = 1, buf[5];    if (ZIP_IS_STR(encoding)) {        /* Although encoding is given it may not be set for strings,         * so we determine it here using the raw length. */        if (rawlen <= 0x3f) {            if (!p) return len;            buf[0] = ZIP_STR_06B | rawlen;        } else if (rawlen <= 0x3fff) {            len += 1;            if (!p) return len;            buf[0] = ZIP_STR_14B | ((rawlen >> 8) & 0x3f);            buf[1] = rawlen & 0xff;        } else {            len += 4;            if (!p) return len;            buf[0] = ZIP_STR_32B;            buf[1] = (rawlen >> 24) & 0xff;            buf[2] = (rawlen >> 16) & 0xff;            buf[3] = (rawlen >> 8) & 0xff;            buf[4] = rawlen & 0xff;        }    } else {        /* Implies integer encoding, so length is always 1. */        if (!p) return len;        buf[0] = encoding;    }    /* Store this length at p */    memcpy(p,buf,len);    return len;}/* Encode the length of the previous entry and write it to "p". Return the * number of bytes needed to encode this length if "p" is NULL. 返回前一个编码的长度*/unsigned int zipPrevEncodeLength(unsigned char *p, unsigned int len) {    if (p == NULL) {        return (len < ZIP_BIGLEN) ? 1 : sizeof(len)+1;    } else {        if (len < ZIP_BIGLEN) {            p[0] = len;            return 1;        } else {            p[0] = ZIP_BIGLEN;            memcpy(p+1,&len,sizeof(len));            memrev32ifbe(p+1);            return 1+sizeof(len);        }    }}/* Encode the length of the previous entry and write it to "p". This only * uses the larger encoding (required in __ziplistCascadeUpdate). 只处理大编码*/void zipPrevEncodeLengthForceLarge(unsigned char *p, unsigned int len) {    if (p == NULL) return;    p[0] = ZIP_BIGLEN;    memcpy(p+1,&len,sizeof(len));    memrev32ifbe(p+1);}/* Decode the number of bytes required to store the length of the previous * element, from the perspective of the entry pointed to by 'ptr'. 返回保存前一节点长度的值的长度*/#define ZIP_DECODE_PREVLENSIZE(ptr, prevlensize) do {                          \    if ((ptr)[0] < ZIP_BIGLEN) {                                               \        (prevlensize) = 1;                                                     \    } else {                                                                   \        (prevlensize) = 5;                                                     \    }                                                                          \} while(0);/* Decode the length of the previous element, from the perspective of the entry * pointed to by 'ptr'. 解码前一节点的长度*/#define ZIP_DECODE_PREVLEN(ptr, prevlensize, prevlen) do {                     \    ZIP_DECODE_PREVLENSIZE(ptr, prevlensize);                                  \    if ((prevlensize) == 1) {                                                  \        (prevlen) = (ptr)[0];                                                  \    } else if ((prevlensize) == 5) {                                           \        assert(sizeof((prevlensize)) == 4);                                    \        memcpy(&(prevlen), ((char*)(ptr)) + 1, 4);                             \        memrev32ifbe(&prevlen);                                                \    }                                                                          \} while(0);/* Return the difference in number of bytes needed to store the length of the * previous element 'len', in the entry pointed to by 'p'. 返回当前节点到前一节点的p的差值*/int zipPrevLenByteDiff(unsigned char *p, unsigned int len) {    unsigned int prevlensize;    ZIP_DECODE_PREVLENSIZE(p, prevlensize);    return zipPrevEncodeLength(NULL, len) - prevlensize;}/* Return the total number of bytes used by the entry pointed to by 'p'. 返回总计使用的长度*/unsigned int zipRawEntryLength(unsigned char *p) {    unsigned int prevlensize, encoding, lensize, len;    ZIP_DECODE_PREVLENSIZE(p, prevlensize);    ZIP_DECODE_LENGTH(p + prevlensize, encoding, lensize, len);    return prevlensize + lensize + len;}/* Check if string pointed to by 'entry' can be encoded as an integer. * Stores the integer value in 'v' and its encoding in 'encoding'. */int zipTryEncoding(unsigned char *entry, unsigned int entrylen, long long *v, unsigned char *encoding) {    long long value;    //判断节点长度是否符合规则    if (entrylen >= 32 || entrylen == 0) return 0;    if (string2ll((char*)entry,entrylen,&value)) {        /* Great, the string can be encoded. Check what's the smallest         * of our encoding types that can hold this value. 返回编码类型*/        if (value >= 0 && value <= 12) {            *encoding = ZIP_INT_IMM_MIN+value;        } else if (value >= INT8_MIN && value <= INT8_MAX) {            *encoding = ZIP_INT_8B;        } else if (value >= INT16_MIN && value <= INT16_MAX) {            *encoding = ZIP_INT_16B;        } else if (value >= INT24_MIN && value <= INT24_MAX) {            *encoding = ZIP_INT_24B;        } else if (value >= INT32_MIN && value <= INT32_MAX) {            *encoding = ZIP_INT_32B;        } else {            *encoding = ZIP_INT_64B;        }        *v = value;        return 1;    }    return 0;}/* Store integer 'value' at 'p', encoded as 'encoding' 按编码方式保存整数到p中*/void zipSaveInteger(unsigned char *p, int64_t value, unsigned char encoding) {    int16_t i16;    int32_t i32;    int64_t i64;    if (encoding == ZIP_INT_8B) {        ((int8_t*)p)[0] = (int8_t)value;    } else if (encoding == ZIP_INT_16B) {        i16 = value;        memcpy(p,&i16,sizeof(i16));        memrev16ifbe(p);    } else if (encoding == ZIP_INT_24B) {        i32 = value<<8;        memrev32ifbe(&i32);        memcpy(p,((uint8_t*)&i32)+1,sizeof(i32)-sizeof(uint8_t));    } else if (encoding == ZIP_INT_32B) {        i32 = value;        memcpy(p,&i32,sizeof(i32));        memrev32ifbe(p);    } else if (encoding == ZIP_INT_64B) {        i64 = value;        memcpy(p,&i64,sizeof(i64));        memrev64ifbe(p);    } else if (encoding >= ZIP_INT_IMM_MIN && encoding <= ZIP_INT_IMM_MAX) {        /* Nothing to do, the value is stored in the encoding itself. */    } else {        assert(NULL);    }}/* Read integer encoded as 'encoding' from 'p' 按编码方式在p中读取整数*/int64_t zipLoadInteger(unsigned char *p, unsigned char encoding) {    int16_t i16;    int32_t i32;    int64_t i64, ret = 0;    if (encoding == ZIP_INT_8B) {        ret = ((int8_t*)p)[0];    } else if (encoding == ZIP_INT_16B) {        memcpy(&i16,p,sizeof(i16));        memrev16ifbe(&i16);        ret = i16;    } else if (encoding == ZIP_INT_32B) {        memcpy(&i32,p,sizeof(i32));        memrev32ifbe(&i32);        ret = i32;    } else if (encoding == ZIP_INT_24B) {        i32 = 0;        memcpy(((uint8_t*)&i32)+1,p,sizeof(i32)-sizeof(uint8_t));        memrev32ifbe(&i32);        ret = i32>>8;    } else if (encoding == ZIP_INT_64B) {        memcpy(&i64,p,sizeof(i64));        memrev64ifbe(&i64);        ret = i64;    } else if (encoding >= ZIP_INT_IMM_MIN && encoding <= ZIP_INT_IMM_MAX) {        ret = (encoding & ZIP_INT_IMM_MASK)-1;    } else {        assert(NULL);    }    return ret;}/* Return a struct with all information about an entry.返回一个条目的所有信息*/void zipEntry(unsigned char *p, zlentry *e) {    ZIP_DECODE_PREVLEN(p, e->prevrawlensize, e->prevrawlen);    ZIP_DECODE_LENGTH(p + e->prevrawlensize, e->encoding, e->lensize, e->len);    e->headersize = e->prevrawlensize + e->lensize;    e->p = p;}/* Create a new empty ziplist. 创建一个空的压缩列表*/unsigned char *ziplistNew(void) {    unsigned int bytes = ZIPLIST_HEADER_SIZE+1;//创始化长度为头长度    unsigned char *zl = zmalloc(bytes);    ZIPLIST_BYTES(zl) = intrev32ifbe(bytes);    ZIPLIST_TAIL_OFFSET(zl) = intrev32ifbe(ZIPLIST_HEADER_SIZE);//初始化偏移量为头长度    ZIPLIST_LENGTH(zl) = 0;//长度置为0    zl[bytes-1] = ZIP_END;//压缩列表结束符    return zl;}/* Resize the ziplist. 重新分配压缩列表的大小*/unsigned char *ziplistResize(unsigned char *zl, unsigned int len) {    zl = zrealloc(zl,len);    ZIPLIST_BYTES(zl) = intrev32ifbe(len);    zl[len-1] = ZIP_END;    return zl;}/* Insert item at "p". 在p里插入新条目*/unsigned char *__ziplistInsert(unsigned char *zl, unsigned char *p, unsigned char *s, unsigned int slen) {    size_t curlen = intrev32ifbe(ZIPLIST_BYTES(zl)), reqlen;    unsigned int prevlensize, prevlen = 0;    size_t offset;    int nextdiff = 0;    unsigned char encoding = 0;    long long value = 123456789; /* initialized to avoid warning. Using a value                                    that is easy to see if for some reason                                    we use it uninitialized. */    zlentry tail;    /* Find out prevlen for the entry that is inserted. */    if (p[0] != ZIP_END) {        ZIP_DECODE_PREVLEN(p, prevlensize, prevlen);    } else {        unsigned char *ptail = ZIPLIST_ENTRY_TAIL(zl);        if (ptail[0] != ZIP_END) {            prevlen = zipRawEntryLength(ptail);        }    }    /* See if the entry can be encoded */    if (zipTryEncoding(s,slen,&value,&encoding)) {        /* 'encoding' is set to the appropriate integer encoding */        reqlen = zipIntSize(encoding);    } else {        /* 'encoding' is untouched, however zipEncodeLength will use the         * string length to figure out how to encode it. */        reqlen = slen;    }    /* We need space for both the length of the previous entry and     * the length of the payload. */    reqlen += zipPrevEncodeLength(NULL,prevlen);    reqlen += zipEncodeLength(NULL,encoding,slen);    /* When the insert position is not equal to the tail, we need to     * make sure that the next entry can hold this entry's length in     * its prevlen field. */    int forcelarge = 0;    nextdiff = (p[0] != ZIP_END) ? zipPrevLenByteDiff(p,reqlen) : 0;    if (nextdiff == -4 && reqlen < 4) {        nextdiff = 0;        forcelarge = 1;    }    /* Store offset because a realloc may change the address of zl. */    offset = p-zl;    zl = ziplistResize(zl,curlen+reqlen+nextdiff);    p = zl+offset;    /* Apply memory move when necessary and update tail offset. */    if (p[0] != ZIP_END) {        /* Subtract one because of the ZIP_END bytes */        memmove(p+reqlen,p-nextdiff,curlen-offset-1+nextdiff);        /* Encode this entry's raw length in the next entry. */        if (forcelarge)            zipPrevEncodeLengthForceLarge(p+reqlen,reqlen);        else            zipPrevEncodeLength(p+reqlen,reqlen);        /* Update offset for tail */        ZIPLIST_TAIL_OFFSET(zl) =            intrev32ifbe(intrev32ifbe(ZIPLIST_TAIL_OFFSET(zl))+reqlen);        /* When the tail contains more than one entry, we need to take         * "nextdiff" in account as well. Otherwise, a change in the         * size of prevlen doesn't have an effect on the *tail* offset. */        zipEntry(p+reqlen, &tail);        if (p[reqlen+tail.headersize+tail.len] != ZIP_END) {            ZIPLIST_TAIL_OFFSET(zl) =                intrev32ifbe(intrev32ifbe(ZIPLIST_TAIL_OFFSET(zl))+nextdiff);        }    } else {        /* This element will be the new tail. */        ZIPLIST_TAIL_OFFSET(zl) = intrev32ifbe(p-zl);    }    /* When nextdiff != 0, the raw length of the next entry has changed, so     * we need to cascade the update throughout the ziplist */    if (nextdiff != 0) {        offset = p-zl;        zl = __ziplistCascadeUpdate(zl,p+reqlen);        p = zl+offset;    }    /* Write the entry */    p += zipPrevEncodeLength(p,prevlen);    p += zipEncodeLength(p,encoding,slen);    if (ZIP_IS_STR(encoding)) {        memcpy(p,s,slen);    } else {        zipSaveInteger(p,value,encoding);    }    ZIPLIST_INCR_LENGTH(zl,1);    return zl;}//创建一个包含给定值的新节点,并将这个新节点添加到压缩列表的表头或者表尾unsigned char *ziplistPush(unsigned char *zl, unsigned char *s, unsigned int slen, int where) {    unsigned char *p;    p = (where == ZIPLIST_HEAD) ? ZIPLIST_ENTRY_HEAD(zl) : ZIPLIST_ENTRY_END(zl);    return __ziplistInsert(zl,p,s,slen);}/* Returns an offset to use for iterating with ziplistNext. When the given * index is negative, the list is traversed back to front. When the list * doesn't contain an element at the provided index, NULL is returned. 返回压缩列表给定索引上的节点*/unsigned char *ziplistIndex(unsigned char *zl, int index) {    unsigned char *p;    unsigned int prevlensize, prevlen = 0;    if (index < 0) {//判断索引正负        index = (-index)-1;        p = ZIPLIST_ENTRY_TAIL(zl);//从尾开始        if (p[0] != ZIP_END) {            ZIP_DECODE_PREVLEN(p, prevlensize, prevlen);            while (prevlen > 0 && index--) {                p -= prevlen;                ZIP_DECODE_PREVLEN(p, prevlensize, prevlen);            }        }    } else {        p = ZIPLIST_ENTRY_HEAD(zl);        while (p[0] != ZIP_END && index--) {            p += zipRawEntryLength(p);        }    }    return (p[0] == ZIP_END || index > 0) ? NULL : p;}/* Find pointer to the entry equal to the specified entry. Skip 'skip' entries * between every comparison. Returns NULL when the field could not be found. 在压缩列表中查找并返回包含了给定值得节点*/unsigned char *ziplistFind(unsigned char *p, unsigned char *vstr, unsigned int vlen, unsigned int skip) {    int skipcnt = 0;    unsigned char vencoding = 0;    long long vll = 0;    while (p[0] != ZIP_END) {        unsigned int prevlensize, encoding, lensize, len;        unsigned char *q;        ZIP_DECODE_PREVLENSIZE(p, prevlensize);        ZIP_DECODE_LENGTH(p + prevlensize, encoding, lensize, len);        q = p + prevlensize + lensize;        if (skipcnt == 0) {            /* Compare current entry with specified entry */            if (ZIP_IS_STR(encoding)) {                if (len == vlen && memcmp(q, vstr, vlen) == 0) {                    return p;                }            } else {                /* Find out if the searched field can be encoded. Note that                 * we do it only the first time, once done vencoding is set                 * to non-zero and vll is set to the integer value. */                if (vencoding == 0) {                    if (!zipTryEncoding(vstr, vlen, &vll, &vencoding)) {                        /* If the entry can't be encoded we set it to                         * UCHAR_MAX so that we don't retry again the next                         * time. */                        vencoding = UCHAR_MAX;                    }                    /* Must be non-zero by now */                    assert(vencoding);                }                /* Compare current entry with specified entry, do it only                 * if vencoding != UCHAR_MAX because if there is no encoding                 * possible for the field it can't be a valid integer. */                if (vencoding != UCHAR_MAX) {                    long long ll = zipLoadInteger(q, encoding);                    if (ll == vll) {                        return p;                    }                }            }            /* Reset skip count */            skipcnt = skip;        } else {            /* Skip entry */            skipcnt--;        }        /* Move to next entry */        p = q + len;    }    return NULL;}/* Return pointer to next entry in ziplist. * zl is the pointer to the ziplist * p is the pointer to the current element * The element after 'p' is returned, otherwise NULL if we are at the end. 返回给定节点得下一个节点*/unsigned char *ziplistNext(unsigned char *zl, unsigned char *p) {    ((void) zl);    /* "p" could be equal to ZIP_END, caused by ziplistDelete,     * and we should return NULL. Otherwise, we should return NULL     * when the *next* element is ZIP_END (there is no next entry). */    if (p[0] == ZIP_END) {        return NULL;    }    p += zipRawEntryLength(p);    if (p[0] == ZIP_END) {        return NULL;    }    return p;}/* Return pointer to previous entry in ziplist. 返回给定节点的前一个节点*/unsigned char *ziplistPrev(unsigned char *zl, unsigned char *p) {    unsigned int prevlensize, prevlen = 0;    /* Iterating backwards from ZIP_END should return the tail. When "p" is     * equal to the first element of the list, we're already at the head,     * and should return NULL. */    if (p[0] == ZIP_END) {        p = ZIPLIST_ENTRY_TAIL(zl);        return (p[0] == ZIP_END) ? NULL : p;    } else if (p == ZIPLIST_ENTRY_HEAD(zl)) {        return NULL;    } else {        ZIP_DECODE_PREVLEN(p, prevlensize, prevlen);        assert(prevlen > 0);        return p-prevlen;    }}/* Get entry pointed to by 'p' and store in either '*sstr' or 'sval' depending * on the encoding of the entry. '*sstr' is always set to NULL to be able * to find out whether the string pointer or the integer value was set. * Return 0 if 'p' points to the end of the ziplist, 1 otherwise. 获取给定节点所保存的值*/unsigned int ziplistGet(unsigned char *p, unsigned char **sstr, unsigned int *slen, long long *sval) {    zlentry entry;    if (p == NULL || p[0] == ZIP_END) return 0;    if (sstr) *sstr = NULL;    zipEntry(p, &entry);    if (ZIP_IS_STR(entry.encoding)) {        if (sstr) {            *slen = entry.len;            *sstr = p+entry.headersize;        }    } else {        if (sval) {            *sval = zipLoadInteger(p+entry.headersize,entry.encoding);        }    }    return 1;}/* Delete "num" entries, starting at "p". Returns pointer to the ziplist. 删除指定索引的节点*/unsigned char *__ziplistDelete(unsigned char *zl, unsigned char *p, unsigned int num) {    unsigned int i, totlen, deleted = 0;    size_t offset;    int nextdiff = 0;    zlentry first, tail;    zipEntry(p, &first);    for (i = 0; p[0] != ZIP_END && i < num; i++) {        p += zipRawEntryLength(p);        deleted++;    }    totlen = p-first.p;    if (totlen > 0) {        if (p[0] != ZIP_END) {            /* Storing `prevrawlen` in this entry may increase or decrease the             * number of bytes required compare to the current `prevrawlen`.             * There always is room to store this, because it was previously             * stored by an entry that is now being deleted. */            nextdiff = zipPrevLenByteDiff(p,first.prevrawlen);            p -= nextdiff;            zipPrevEncodeLength(p,first.prevrawlen);            /* Update offset for tail */            ZIPLIST_TAIL_OFFSET(zl) =                intrev32ifbe(intrev32ifbe(ZIPLIST_TAIL_OFFSET(zl))-totlen);            /* When the tail contains more than one entry, we need to take             * "nextdiff" in account as well. Otherwise, a change in the             * size of prevlen doesn't have an effect on the *tail* offset. */            zipEntry(p, &tail);            if (p[tail.headersize+tail.len] != ZIP_END) {                ZIPLIST_TAIL_OFFSET(zl) =                   intrev32ifbe(intrev32ifbe(ZIPLIST_TAIL_OFFSET(zl))+nextdiff);            }            /* Move tail to the front of the ziplist */            memmove(first.p,p,                intrev32ifbe(ZIPLIST_BYTES(zl))-(p-zl)-1);        } else {            /* The entire tail was deleted. No need to move memory. */            ZIPLIST_TAIL_OFFSET(zl) =                intrev32ifbe((first.p-zl)-first.prevrawlen);        }        /* Resize and update length */        offset = first.p-zl;        zl = ziplistResize(zl, intrev32ifbe(ZIPLIST_BYTES(zl))-totlen+nextdiff);        ZIPLIST_INCR_LENGTH(zl,-deleted);        p = zl+offset;        /* When nextdiff != 0, the raw length of the next entry has changed, so         * we need to cascade the update throughout the ziplist */        if (nextdiff != 0)            zl = __ziplistCascadeUpdate(zl,p);    }    return zl;}/* Delete a single entry from the ziplist, pointed to by *p. * Also update *p in place, to be able to iterate over the * ziplist, while deleting entries. 从压缩列表中删除给定的节点*/unsigned char *ziplistDelete(unsigned char *zl, unsigned char **p) {    size_t offset = *p-zl;    zl = __ziplistDelete(zl,*p,1);    /* Store pointer to current element in p, because ziplistDelete will     * do a realloc which might result in a different "zl"-pointer.     * When the delete direction is back to front, we might delete the last     * entry and end up with "p" pointing to ZIP_END, so check this. */    *p = zl+offset;    return zl;}/* Delete a range of entries from the ziplist. 从压缩列表中删除给定索引的多个连续节点*/unsigned char *ziplistDeleteRange(unsigned char *zl, int index, unsigned int num) {    unsigned char *p = ziplistIndex(zl,index);    return (p == NULL) ? zl : __ziplistDelete(zl,p,num);}/* Return ziplist blob size in bytes. 返回压缩列表占用的内存字节数*/size_t ziplistBlobLen(unsigned char *zl) {    return intrev32ifbe(ZIPLIST_BYTES(zl));}/* Return length of ziplist. 返回压缩列表的节点数量,节点数小于65535时为O(1),大于时时O(N)*/unsigned int ziplistLen(unsigned char *zl) {    unsigned int len = 0;    if (intrev16ifbe(ZIPLIST_LENGTH(zl)) < UINT16_MAX) {        len = intrev16ifbe(ZIPLIST_LENGTH(zl));    } else {        unsigned char *p = zl+ZIPLIST_HEADER_SIZE;        while (*p != ZIP_END) {            p += zipRawEntryLength(p);            len++;        }        /* Re-store length if small enough */        if (len < UINT16_MAX) ZIPLIST_LENGTH(zl) = intrev16ifbe(len);    }    return len;}
阅读全文
0 0
原创粉丝点击