redis6.0.5之dict阅读笔记1-dict之初识dict的数据结构和宏定义说明

redis6.0.5之dict阅读笔记1-dict之初识dict的数据结构和宏定义说明
Redis的全称是Remote Dictionary Server,所以dict在redis占据非常重要的位置
因为 redis = 远程通信 + dict +  服务 
remote 主要使用了远程通信
server 主要是提供了永真循环的接口调用
这个接口就是提供dict的接口服务,用于远程存储dict

如果只是本地dict单个服务,我们可以简化成如下模式
while(1)
{
    listen request: 
        when a set request: call setDit;
        when a get request:call getDict;
}

******************************************************************
为了测试dict,我们不想编译整个redis,所以如sds一样,只截取少部分内容,具体如下
D:\mysourcecode\mytestcode\dict>tree /f
卷 新加卷 的文件夹 PATH 列表
卷序列号为 BA81-13D2
D:.
    atomicvar.h
    dict.c
    dict.h
    fmacros.h
    redisassert.h
    sdsalloc.h
    siphash.c
    TestDict.c  
//从redis-cli.c拿到 _serverAssert定义 放到我们自己的测试文件TestDict.c中
/* _serverAssert is needed by dict */
void _serverAssert(const char *estr, const char *file, int line) {
    fprintf(stderr, "=== ASSERTION FAILED ===");
    fprintf(stderr, "==> %s:%d '%s' is not true",file,line,estr);
    *((char*)-1) = 'x';
}
    zmalloc.c //注释了 第45行 // #include "config.h"
    zmalloc.h  

没有子文件夹
******************************************************************
编译:gcc  zmalloc.c siphash.c    dict.c  TestDict.c   -o  TestDict 
因为我们采用文件夹映射,把Windows的文件夹映射到Linux下面,
所以在Windows阅读,在Linux编译执行

******************************************************************
定义了一个字典的实体结构
typedef struct dictEntry {
    void *key;    //指向关键字的指针
    union {
        void *val;  //可以用来存放各种类型,可以放字符串,或者其他各种数据结构
        uint64_t u64; //如果是无符号数,可以放在这里
        int64_t s64;//有符号,可以放在这里
        double d; //有小数的,可以放在这里
    } v;  //联合体,以最大的类型为其空间大小,只存取其中一个的值
    struct dictEntry *next;  //指向下一个结构体的指针
} dictEntry; //定义别名

我们环境中,各种类型的大小如下
sizeof( double ) 8 
sizeof( void * ) 8 
sizeof( struct dictEntry ) 24 
所以结构体的大小为24字节
******************************************************************
定义了一个处理字典的函数指针集合的结构体
typedef struct dictType {
    uint64_t (*hashFunction)(const void *key);  //获取hash值的函数指针,返回一个64位的无符号数
    void *(*keyDup)(void *privdata, const void *key); //深拷贝key的值的指针函数,返回一个指针
    void *(*valDup)(void *privdata, const void *obj); //深拷贝value的值的指针函数,返回一个指针
    int (*keyCompare)(void *privdata, const void *key1, const void *key2);//比较函数的指针函数,返回一个整型
    void (*keyDestructor)(void *privdata, void *key); //析构key函数的指针函数,无返回
    void (*valDestructor)(void *privdata, void *obj); //析构value函数的指针函数,无返回
} dictType; //定义别名

在我们的环境中,sizeof( struct dictType ) 为 48,因为刚好是6个指针,每个8,共计48个字节空间 
******************************************************************************
/* This is our hash table structure. Every dictionary has two of this as we
 * implement incremental rehashing, for the old to the new table. */
这个是我们的hash表结构。每个字典拥有两份内容,主要是为了方便做增量hash,从旧表迁移到新表
typedef struct dictht {
    dictEntry **table;   //指向二维数组的指针
    unsigned long size;  //hash表结构的大小
    unsigned long sizemask;//hash表结构的大小的标记
    unsigned long used;//已经使用的hash表结构的大小
} dictht; //定义别名
sizeof( struct dictht ) 32  =  一个指针8+  3 个长整型的无符号数8
******************************************************************************
定义字典
typedef struct dict {
    dictType *type;  //定义字典的操作函数集合指针
    void *privdata;  //定义字典的数据指针
    dictht ht[2];    //定义两个字典 hash table,如上所说是为了做渐进式hash使用的
    long rehashidx; /* rehashing not in progress if rehashidx == -1 */  若果rehashidx等于-1,那么就不在做渐进式hash
    //做渐进式hash的标志
    unsigned long iterators; /* number of iterators currently running */ 当前做渐进式hash迭代的数量
    //当前迭代数量
} dict;//定义别名

sizeof( struct dict ) 96 =  8 + 8 + 2 * 32 + 8 + 8
******************************************************************************
/* If safe is set to 1 this is a safe iterator, that means, you can call
 * dictAdd, dictFind, and other functions against the dictionary even while
 * iterating. Otherwise it is a non safe iterator, and only dictNext()
 * should be called while iterating. */
如果标志位safe为1的话,那么你就可以调用dictAdd, dictFind和其它字典操作函数即使在迭代中,
否则,如果在非安全模式,在迭代中只能调用dictNext这个函数
typedef struct dictIterator {
    dict *d;  //迭代的字典
    long index; //迭代的索引
    int table, safe; //迭代的标志
    dictEntry *entry, *nextEntry;  //迭代的内容和下一个内容
    /* unsafe iterator fingerprint for misuse detection. */ 不安全的迭代器指纹,为了错误的检测使用
    long long fingerprint; //指纹
} dictIterator; //定义别名
sizeof( struct dictIterator ) 48 =  8 + 8 + 2*4 + 2*8 + 8
******************************************************************************
上面我们基本上知道了dict的数据结构
从定义单个的dict实体列表开始,以及相关的处理函数,再到hash表结构(多个dict的实体列表),再到一个整体的dict定义结构
最后的dictIterator定义是关于dict的迭代器.

******************************************************************
#define  xxx  do{ code or nothing }while(0)
这种结构主要是方便宏定义展开的时候不会出现问题
******************************************************************
#define dictFreeVal(d, entry) \ (\符号是连接字符串)
    if ((d)->type->valDestructor) \
        (d)->type->valDestructor((d)->privdata, (entry)->v.val)

这个宏dictFreeVal(d, entry) 的功能是 
如果这种类型存在value析构函数,那么调用析构函数释放value资源
******************************************************************
#define dictSetVal(d, entry, _val_) do { \
    if ((d)->type->valDup) \
        (entry)->v.val = (d)->type->valDup((d)->privdata, _val_); \
    else \
        (entry)->v.val = (_val_); \
} while(0)

这个宏dictSetVal的功能是
如果这种类型存在赋值函数,那么调用赋值函数给实体entry的值赋值
不存在赋值函数,就直接赋值
******************************************************************
#define dictSetSignedIntegerVal(entry, _val_) \
    do { (entry)->v.s64 = _val_; } while(0)
赋值有符号的整型
******************************************************************
#define dictSetUnsignedIntegerVal(entry, _val_) \
    do { (entry)->v.u64 = _val_; } while(0)
赋值无符号的整型
******************************************************************
#define dictSetDoubleVal(entry, _val_) \
    do { (entry)->v.d = _val_; } while(0)
赋值Double类型的值
******************************************************************
#define dictFreeKey(d, entry) \
    if ((d)->type->keyDestructor) \
        (d)->type->keyDestructor((d)->privdata, (entry)->key)

******************************************************************
#define dictSetKey(d, entry, _key_) do { \
    if ((d)->type->keyDup) \
        (entry)->key = (d)->type->keyDup((d)->privdata, _key_); \
    else \
        (entry)->key = (_key_); \
} while(0)
如果这种类型存在key析构函数,那么调用析构函数释放key资源
******************************************************************
#define dictCompareKeys(d, key1, key2) \
    (((d)->type->keyCompare) ? \
        (d)->type->keyCompare((d)->privdata, key1, key2) : \
        (key1) == (key2))
三值运算符,如果存在键比较函数,就调用比较函数,否则直接使用键值比较
******************************************************************
#define dictHashKey(d, key) (d)->type->hashFunction(key)
调用hash函数获取key的hash值
******************************************************************
#define dictGetKey(he) ((he)->key)
获取key的值
******************************************************************
#define dictGetVal(he) ((he)->v.val)
获取value的值
******************************************************************
#define dictGetSignedIntegerVal(he) ((he)->v.s64) 
获取有符号的整型的值
******************************************************************
#define dictGetUnsignedIntegerVal(he) ((he)->v.u64) 
获取无符号的整型的值
******************************************************************
#define dictGetDoubleVal(he) ((he)->v.d) 
获取double类型的值
******************************************************************
#define dictSlots(d) ((d)->ht[0].size+(d)->ht[1].size) 
获取总空间大小
******************************************************************
#define dictSize(d) ((d)->ht[0].used+(d)->ht[1].used) 
获取已使用空间大小
******************************************************************
#define dictIsRehashing(d) ((d)->rehashidx != -1) 
获取是否正在进行Rehashing
******************************************************************

 

posted on 2020-08-03 18:44  子虚乌有  阅读(257)  评论(0)    收藏  举报