美文网首页基础知识
Redis源码研究之底层数据结构

Redis源码研究之底层数据结构

作者: wenmingxing | 来源:发表于2018-04-25 22:06 被阅读23次

    本文主要介绍Redis的几种底层数据结构的数据结构部分,其接口部分以后会分别说明。

    建议阅读:
    1、Redis的几种数据结构的理论说明见:Redis中的对象底层实现

    I、dict

    字典是数据库最基本的数据类型,因为数据库几乎都是以key-value形式存储的。

    // 字典数据结构,Redis 的所有键值对都会存储在这里。其中包含两个哈希表,为了应对rehash。
    /*src/dict.h/dict*/
    typedef struct dict {
        // 哈希表的类型,包括哈希函数,比较函数,键值的内存释放函数
        dictType *type;
        // 存储一些额外的数据
        void *privdata;
        // 两个哈希表,ht[1]用于完成rehash
        dictht ht[2];
        // 哈希表重置下标,指定的是哈希数组的数组下标
        int rehashidx; /* rehashing not in progress if rehashidx == -1 */
        // 绑定到哈希表的迭代器个数
        int iterators; /* number of iterators currently running */
    } dict;
    

    II、redisObject

    在Redis的数据库存储结构中,每个value都会被包装为一个redisObject(其中包含了指定value的类型,编码方式等属性):

    /*src/redis.h/redisObject*/
    typedef struct redisObject {
        // 刚刚好32 bits
        // 对象的类型,字符串/列表/集合/哈希表
        unsigned type:4;
    
        // 编码的方式,Redis 为了节省空间,提供多种方式来保存一个数据
        // 譬如:“123456789” 会被存储为整数123456789
        unsigned encoding:4;
    
        // 当内存紧张,淘汰数据的时候用到
        unsigned lru:22; /* lru time (relative to server.lruclock) */
    
        // 引用计数,用于整型字符串,为节省空间实现了共享内存
        int refcount;
    
        // 数据指针,指向实际的value
        void *ptr;
    } robj;  
    

    III、zset

    zset为有序集合,主要为一个skiplist+dict,其是一种AVL树的替代品,实现简单:

    /*src/redis.h/zset*/
    typedef struct zset {
        // 哈希表
        dict *dict;  //为了在O(1)时间查找
        // 跳表
        zskiplist *zsl;    //为了有序,并顺序查找
    } zset;  
    
    /* src/redis.h/zskiplist */
    typedef struct zskiplist {
    
        // 表头节点和表尾节点
        struct zskiplistNode *header, *tail;
    
        // 表中节点的数量
        unsigned long length;
    
        // 表中层数最大的节点的层数
        int level;
    
    } zskiplist;
    
    /* ZSETs use a specialized version of Skiplists */
    /* src/redis.h/zskiplistNode */
    typedef struct zskiplistNode {
    
        // 成员对象
        robj *obj;
    
        // 分值
        double score;
    
        // 后退指针
        struct zskiplistNode *backward;
    
        // 层
        struct zskiplistLevel {
    
            // 前进指针
            struct zskiplistNode *forward;
    
            // 跨度
            unsigned int span;
    
        } level[];
    
    } zskiplistNode;
    

    IV、 adlist

    一个双向链表结构:

    /*src/adlist.h/list*/
     typedef struct list {
        // 头指针
        listNode *head;
        // 尾指针
        listNode *tail;
        // 数据拷贝函数指针
        void *(*dup)(void *ptr);
        // 析构函数指针
        void (*free)(void *ptr);
        // 数据比较指针
        int (*match)(void *ptr, void *key);
        // 链表长度
        unsigned long len;
    } list;  
    

    V、ziplist

    为了优化内存而实现的压缩链表,其实是一个数组,这样能快速的导入到CPU cache中:

    /* 保存 ziplist 节点信息的结构 */
    /*src/ziplist.c/zlentry*/
    typedef struct zlentry {
    
        // prevrawlen :前置节点的长度
        // prevrawlensize :编码 prevrawlen 所需的字节大小
        unsigned int prevrawlensize, prevrawlen;
    
        // len :当前节点值的长度
        // lensize :编码 len 所需的字节大小
        unsigned int lensize, len;
    
        // 当前节点 header 的大小
        // 等于 prevrawlensize + lensize
        unsigned int headersize;
    
        // 当前节点值所使用的编码类型
        unsigned char encoding;
    
        // 指向当前节点的指针
        unsigned char *p;
    
    } zlentry;  
    

    VI、intset

    表示整数集合:

    /*src/intset.h/intset*/
    typedef struct intset {
        // 每个整数的类型
        uint32_t encoding;
        // intset 长度
        uint32_t length;
        // 整数数组
        int8_t contents[];
    } intset;  
    

    VII、sds

    二进制安全的动态字符串:

    /*src/sds.h/sds*/  
    typedef char *sds;
    

    【参考】
    [1] 《Redis设计与实现》
    [2] 《Redis源码日志》

    相关文章

      网友评论

        本文标题:Redis源码研究之底层数据结构

        本文链接:https://www.haomeiwen.com/subject/phkulftx.html