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 ******************************************************************