Redis设计与实现 - chapter1-6

Chapter1 引言

略。。。

Chapter2 简单动态字符串

Simple Dynamic String,简称SDS。Redis中,C字符串只作为字符串字面量(string literal)用于字符串常量,其他地方都用SDS作为字符串的默认实现。

数据结构:

sds.h:

struct sdshdr {
    int len;    // 使用量 (应该是unsigned int)
    int free;    // 空闲大小,初始为0 (应该是unsigned int)
    char buf[];    // 实际存储,大小为len+free+1(末尾空白字符,便于兼容C的字符串函数)
}

优点(相对于C字符串):

  • 灵活方便,API安全:O(1)取长度,自动扩展空间大小,无缓冲区溢出问题;

  • 减少重分配:预留空闲区;

    • 预分配策略:

      • 惰性分配:需要时才分配(修改后的len' > len + free)

      • len' < 1M ==> free = len'

      • len' >= 1M ==> free = 1M

  • 二进制安全:以二进制方式处理数据,不对数据做任何限制和假设(不以'\0'分割字符串);

  • 兼容部分C字符串函数:保留末尾的空白字符'\0';

Chapter3 链表

列表键(list)的底层实现之一(元素较多,或元素都是较长的字符串时)。及,发布与订阅、慢查询、监视器、客户端状态信息、客户端输出缓冲区等功能。

数据结构:

adlist.h:

struct listNode {
    struct listNode *prev;
    struct listNode *next;
    void *value;
}

struct list {
    listNode *head;
    listNode *tail;
    unsigned long len;
    void *(*dup)(void *ptr);    // 节点值复制函数
    void (*free)(void *ptr);    // 节点值释放函数
    int (*match)(void *ptr, void *key);    // 节点值对比函数,用于比较ptr->value和key
}

优点:

  • 灵活方便:双向链表,表头表尾,链长计数器;

  • 多态:节点值value使用void*类型,使用可配置的指针函数来处理节点值;

Chapter4 字典

底层数据库和hash键的底层实现之一。

数据结构:

dict.h:

// 哈希表
struct dictht {
    dictEntry **table;
    unsigned long size;
    unsigned long sizemask; // = size - 1
    unsigned long used;
}

// 哈希键
struct dictEntry {
    void *key;
    union {
        void *val;
        uint64_t u64;
        int64_t s64;
    } v;
    struct dictEntry *next;
}

// 字典
struct dict {
    dictType *type;
    void *privdata;
    dictht ht[2];    // ??为什么不是dictht* ht[2]??
    int rehashidx;    // 无rehash时,=-1
}

struct dictType {
    unsigned int (*hashFunction)(const void *key);
    void *(*keyDup)(void *privdata, const void *key);
    void *(*valDup)(void *privdata, const void *obj);
    int (*keyCompare)(void *privdata, const void *key1, const void *key2);
    void (*keyDestructor)(void *privdata, void *key);
    void (*valDestructor)(void *privdata, void *obj);
}

要点:

  • 为<key, value>计算hash index的方式:

    • hash = dict->type->hashFunction(key);
      index= hash & dict->ht[x].sizemask;
  • hash算法:字典用于底层数据库和哈希键时,采用MurmurHash2算法(http://code.google.com/p/smhasher/ );

  • 冲突collision:拉链的方式,新元素总被插在表头(性能考虑);

  • rehash:

    • load_factor = used / size

    • 扩展

      • 时机:

        • no BGSAVE/BGREWRITEAOF && load_factor >= 1

        • do BGSAVE/BGREWRITEAOF && load_factor >= 5

      • 大小:>=used * 2的第一个2^n

    • 收缩

      • 时机:load_factor <= 0.1

      • 大小:>= used的第一个2^n

    • 渐进式(性能考虑,非一次性、集中式)

      • 开始时,为ht[1]分配空间,设置rehashidx=0;

      • 每次增删查改操作时,首先迭代rehashidx,直到在ht[0]上找到第一个对应索引有数据的rehashidx,然后将ht[0]上对应索引的所有键值对rehash到ht[1]上,最后更新rehashidx++;

      • 整个rehash过程直至ht[0]->used=0,然后更新ht[0],并重置ht[1]和rehashidx=-1;

    • rehash过程中,删查改操作会在ht[0]和ht[1]上同时进行,但是增加新数据操作只在ht[1]上进行,所以ht[0]上的数据会只减不增,并最终变成空。

Chapter5 跳跃表

有序,平均O(logN)、最坏O(N)的查找,效率可以和平衡树媲美,但实现更简单。

有序集合键(zset)的实现之一(有序集合元素较多,或元素是较长的字符串)。

基本定义和算法参考:

  • William Push:《Skip Lists: A Probabilistic Alternative to Balanced Trees》

  • 《算法:C语言实现》13.5节

数据结构:

redis.h:

struct zskiplistNode {
    struct zskiplistLevel {
        struct zskiplistNode *forward;
        unsigned int span;
    } level[];    // 根据幂次定律随机生成一个介于1和32之间的值作为层数
    struct zskiplistNode *backward;
    double score;
    robj *obj;
}

struct zskiplist {
    struct zskiplistNode *header, *tail;    // 表头节点不记录数据,仅记录32层的跳跃指针
    unsigned long length;    // 节点数,不算表头
    int level;    // 表中层数最大的节点的层数
}

Chapter6 整数集合

集合键的底层实现之一(元素都是整数,且数量不多)

数据结构:

intset.h

struct intset {
    uint32_t encoding;
    uint32_t length;
    int8_t contents[];
}

要点:

  • encoding:编码方式,包括INSET_ENC_INT16,INSET_ENC_INT32,INSET_ENC_INT64;

  • contents保存每个元素对应编码下的每个byte,整个数组大小=size(encoding) * length;

    • 有序放置所有元素,将元素按照encoding拆成几个byte依次排放;

  • encoding升级:

    • 添加新元素时,新元素有可能超出encoding的表示范围(过大或过小),则升级;

    • 扩展contents空间

      • 将每个元素扩展到新encoding表示的字节长度,然后重新放置各个byte;

      • 依然保持集合内元素有序;

    • 新元素要么大于所有元素,要么小于所有元素,所以放在contents开头或末尾;

    • 好处:

      • 灵活:不必指定集合中元素类型,且能自动升级,避免类型出错;

      • 节约内存;

  • 不支持降级;


你可能感兴趣的:(Redis设计与实现 - chapter1-6)