熟悉python的开发者应该对字典结构非常了解,
字典通常泛指这类高层数据结构,
dict: {“name”:“Jack”}
更广泛意义上可以理解为 key-value 结构的都是 dict。
在进一步地了解Redis的dict之前,需要清空对dict的刻板思维。
不要认为它只是一个存储数据的数据结构。否则会对源码分析造成很大困难。
Redis的dict设计非常精妙,不仅实现key-value的功能,还拓展了非常丰富的数据存储方式。在Redis的架构中,dict起到了数据库的作用,而且支持了string,list,set,map多种数据格式。
dict的基本数据单元-dictEntry
entry是dict结构的最基本数据单元,每个entry保存着一个key-value结构,还有一个指向下一个entry的next指针。
typedef struct dictEntry {
void *key;
union {
void *val;
uint64_t u64;
int64_t s64;
double d;
} v;
struct dictEntry *next;
} dictEntry;
key是一个void类型,虽然没有指定是什么特定种类,在Redis中大部分情况都可以把key当做sds。
dict的哈希表- dictht
entry只是单个的数据单元,dictht则是保存大量entry的数据结构。
/* This is our hash table structure. Every dictionary has two of this as we
* implement incremental rehashing, for the old to the new table. */
typedef struct dictht {
dictEntry **table;
unsigned long size;
unsigned long sizemask;
unsigned long used;
} dictht;
非常简洁的结构,可以看出它保存了一个指针数组table,并且还有三个用于指示当前列表内存使用情况的 size, sizemask, used。
dict主数据单元-dict
上面的entry和dictht是为了介绍dict所做的铺垫。在Redis中,dict是非常重要的数据结构,包括数据库等对象都是用dict来存储的。
typedef struct dict {
dictType *type;
void *privdata;
dictht ht[2];
long rehashidx; /* rehashing not in progress if rehashidx == -1 */
int iterators; /* number of iterators currently running */
} dict;
dict的结构如上代码所示。
ht[2]
首先看第三个成员 dictht ht[2],这个是上面说到的dictht哈希表,存储真正数据的地方。
两个哈希表保存的数据是一样的,他们互为备份,为了防止在迭代的时候发生异常情况所设计。
dictType *type
dictType 结构是另外一个结构体,它定义了一串不同的函数指针,
typedef 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);
} dictType;
类似之前介绍的adlist中的函数指针,这些也起了同样的作用。
具体的作用可以参考[C语言实现类似Java接口的设计]。
dict结构
结合上面几个数据结构可以得到下面的结构,
小结
dict结构还有很多其他的精妙设计。
像迭代器,重哈希,很多在高级语言中的简单api,在Redis的dict源码中都可以找到最本质的实现。
这些部分到后面会结合Redis的其他模块一起解析。单独解析这些部分会影响对数据结构的梳理,而转移了注意力。