文章目录
四个数据结构
dictEntry
dictEntry 的结构如下(Redis 7.0):
typedef struct dictEntry {
void *key; // 键
union {
void *val;
uint64_t u64;
int64_t s64;
double d;
} v; // 值
struct dictEntry *next; /* Next entry in the same hash bucket.即下一个节点 */
void *metadata[]; /* An arbitrary number of bytes (starting at a
* pointer-aligned address) of size as returned
* by dictType's dictEntryMetadataBytes(). */
} dictEntry;
可以对比 《Redis 设计与实现》中的 dictEntry 结构,发现联合结构 v 中多了一个 double 的浮点数表示,metadata 是一块任意长度的数据,具体的长度由 dictType 中的 dictEntryMetadataBytes() 返回,作用相当于 privdata
dictType
dictType 是一系列操作字典的键和值的操作:
typedef struct dictType {
uint64_t (*hashFunction)(const void *key); // 哈希函数
void *(*keyDup)(dict *d, const void *key); // 复制键的函数
void *(*valDup)(dict *d, const void *obj); // 复制值的函数
int (*keyCompare)(dict *d, const void *key1, const void *key2); // 键的比较
void (*keyDestructor)(dict *d, void *key); // 键的销毁
void (*valDestructor)(dict *d, void *obj); // 值的销毁
int (*expandAllowed)(size_t moreMem, double usedRatio); // 字典里的哈希表是否允许扩容
/* Allow a dictEntry to carry extra caller-defined metadata. The
* extra memory is initialized to 0 when a dictEntry is allocated. */
/* 允许调用者向条目 (dictEntry) 中添加额外的元信息.
* 这段额外信息的内存会在条目分配时被零初始化. */
size_t (*dictEntryMetadataBytes)(dict *d);
} dictType;
该结构是为了实现字典的多态。
dict
7.0 版本的字典结构如下:
struct dict {
dictType *type;
dictEntry **ht_table[2];
unsigned long ht_used[2];
long rehashidx; /* rehashing not in progress if rehashidx == -1 */
/* Keep small vars at end for optimal (minimal) struct padding */
int16_t pauserehash; /* If >0 rehashing is paused (<0 indicates coding error) */
signed char ht_size_exp[2]; /* exponent of size. (size = 1<<exp) */
};
相比于 《Redis 设计与实现》中的字典实现,改动较大,7.0中去掉了 dictht 结构,即去掉了哈希结构。接下来介绍每个成员:
/* type 上面已经解释过了;
* ht_table 即哈希表数组
* ht_used 分别表示哈希表数组中各自已经存放键值对的个数
* rehashidx 是 rehash 时用的,没有 rehash 时值为1
* pauserehash 则是表示 rehash 的状态,大于0时表示 rehash 暂停了,小于0表示出错了
* ht_size_exp 则是表示两个哈希表数组的大小,通过 1 << ht_size_exp[0/1] 来计算
*/
我们可以看到一行注释:/* Keep small vars at end for optimal (minimal) struct padding */
,将小变量放在结构体的后面,为了最佳或最小的填充,即节省空间。
dictIterator
dictIterator 是字典的迭代器
/* 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. */
typedef struct dictIterator {
dict *d;
long index;
int table, safe;
dictEntry *entry, *nextEntry;
/* unsafe i