redis源码之set key(一)
简介
这里介绍了redis的set命令执行流程,大致了解redis的设计。
源码
调用堆栈
# 函数名 文件
# set命令的入口函数,参数key,val就是对应的kv
setGenericCommand t_string.c
# 向hash表中插入kv
genericSetKey db.c
# 在hash表中查找key对应的value
lookupKeyWrite db.c
# 向hash表插入kv
dbAdd db.c
dictAdd dict.c
dictAddRaw dict.c
dictSetVal dict.h
相关数据结构
// 数据库
typedef struct redisDb {
// 存放kv的hash表
dict *dict; /* The keyspace for this DB */
// 存放ttl相关信息的hash表
dict *expires; /* Timeout of keys with a timeout set */
dict *blocking_keys; /* Keys with clients waiting for data (BLPOP)*/
dict *ready_keys; /* Blocked keys that received a PUSH */
dict *watched_keys; /* WATCHED keys for MULTI/EXEC CAS */
int id; /* Database ID */
long long avg_ttl; /* Average TTL, just for stats */
unsigned long expires_cursor; /* Cursor of the active expire cycle. */
list *defrag_later; /* List of key names to attempt to defrag one by one, gradually. */
} redisDb;
// hash字典
typedef struct dict {
// 功能函数列表,如计算key的hash值的hash函数
dictType *type;
void *privdata;
// 在rehash的时候会逐步将数据从ht[0]迁移到ht[1]
dictht ht[2];
// 当前rehash到哪个hash桶了
long rehashidx; /* rehashing not in progress if rehashidx == -1 */
int16_t pauserehash; /* If >0 rehashing is paused (<0 indicates coding error) */
} dict;
// kv数据存放的表
typedef struct dictht {
dictEntry **table;
unsigned long size;
unsigned long sizemask;
unsigned long used;
} dictht;
// 键值对
typedef struct dictEntry {
void *key;
union {
void *val;
uint64_t u64;
int64_t s64;
double d;
} v;
// redis使用链表的方式处理hash冲突,这里next就是用来连接存在hash冲突的kv
struct dictEntry *next;
} dictEntry;
重要函数
// 在字典dict中查找key对应的dictEntry
dictEntry *dictFind(dict *d, const void *key)
{
dictEntry *he;
uint64_t h, idx, table;
if (dictSize(d) == 0) return NULL; /* dict is empty */
if (dictIsRehashing(d)) _dictRehashStep(d);
// 调用函数siphash计算hash值
h = dictHashKey(d, key);
for (table = 0; table <= 1; table++) {
idx = h & d->ht[table].sizemask;
he = d->ht[table].table[idx];
// 遍历链表, 比较是否和key相等
while(he) {
if (key==he->key || dictCompareKeys(d, key, he->key))
return he;
he = he->next;
}
if (!dictIsRehashing(d)) return NULL;
}
return NULL;
}
// 设置值
// 如果字典有valDup函数,就使用valDup函数拷贝_val_?
// 否则就是简单的指针拷贝
#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)
总结
- redis使用siphash计算key的hash值,然后放入hash表中
- redis使用链表处理hash冲突的情况

浙公网安备 33010602011771号