从源码深入理解Redis(redis源码深入理解)
从源码深入理解Redis
Redis是一个开源的内存数据结构存储系统,常用于缓存、消息队列、持久化存储等场景。它具有高性能、可扩展、支持丰富的数据类型等特点,被广泛应用于互联网领域。为了更好地理解Redis,我们需要从源码层面去探究Redis的实现。
Redis源码的目录结构
Redis的源码目录结构如下:
![](https://img-blog.csdnimg.cn/20220103232221984.png)
src目录下是Redis的核心代码,包含了Redis的命令实现、数据类型实现以及网络事件处理等核心代码。deps目录下是Redis所依赖的第三方库,如hiredis、Jemalloc等。tests目录下是Redis的测试代码,包含了Redis各个功能点的自动化测试用例。
Redis源码中的数据结构
Redis的内部实现主要依赖于数据结构,下面我们将介绍Redis源码中常见的四种数据结构:字符串、列表、哈希、集合。
1. 字符串
Redis中的字符串类型保存的是二进制安全的字符串。在Redis的源码中,字符串类型的操作可以在src/string.c文件中找到,其中最常用的操作为set、get。
set操作的主要实现如下:
“`c
void setCommand(client *c) {
setGenericCommand(c,SET_NO_FLAGS);
}
void setGenericCommand(client *c, int flags) {
robj *expire = getExpire(c->db,c->argv,flags);
int j;
c->argv[c->argc] = expire ? expire : &shared.nullbulk;
c->argc++;
/* Store the value */
setKey(c->db,c->argv[1],c->argv[2]);
/* Signal modified key */
signalModifiedKey(c,c->db,c->argv[1]);
/* Notify a generic string-key BL pop event */
notifyKeyspaceEvent(NOTIFY_STRING,”set”,c->argv[1],c->db->id);
if (expire) setExpire(c,c->db,c->argv[1],expire);
server.dirty++;
}
get操作的主要实现如下:
```cvoid getCommand(client *c) {
getGenericCommand(c);}
void getGenericCommand(client *c) { robj *o;
/* Try to get the value from the cache */ if ((o = lookupKeyReadOrReply(c,c->argv[1],shared.nullbulk)) == NULL ||
o == shared.sentinel) return;
addReplyBulk(c,o);}
2. 列表
Redis中的列表类型使用双向链表实现,支持在列表头部和列表尾部插入和删除元素。在Redis的源码中,列表类型的操作可以在src/adlist.c文件中找到,其中最常用的操作为listAddNodeHead、listAddNodeTl、listDelNode。
listAddNodeHead操作的主要实现如下:
“`c
list *listAddNodeHead(list *list, void *value) {
listNode *node;
if ((node = zmalloc(sizeof(*node))) == NULL)
return NULL;
node->value = value;
if (list->len == 0) {
list->head = list->tl = node;
node->prev = node->next = NULL;
} else {
node->prev = NULL;
node->next = list->head;
list->head->prev = node;
list->head = node;
}
list->len++;
return list;
}
listDelNode操作的主要实现如下:
```clist *listDelNode(list *list, listNode *node) {
/* Fix head pointer if needed. */ if (node->prev == NULL)
list->head = node->next; else
node->prev->next = node->next; /* Fix tl pointer if needed. */
if (node->next == NULL) list->tl = node->prev;
else node->next->prev = node->prev;
if (list->free) list->free(node->value); zfree(node);
list->len--; return list;
}
3. 哈希
Redis中的哈希类型使用字典结构实现,支持在哈希表中添加、删除、查找元素。在Redis的源码中,哈希类型的操作可以在src/dict.c文件中找到,其中最常用的操作为dictAdd、dictFind、dictDelete。
dictAdd操作的主要实现如下:
“`c
int dictAdd(dict *d, void *key, void *val)
{
dictht *ht;
dictEntry *entry;
if (dictIsRehashing(d)) _dictRehashStep(d);
/* Get the index of the new element, or -1 if
* the element already exists. */
if ((entry = dictFind(d,key)) == NULL) {
if (dictIsRehashing(d) && dictAdd(d->ht[1],key,val) == DICT_OK)
incrRefCount(key); /* Prevent ht[0] from freeing the key. */
else {
entry = dictCreateEntry(d,key);
dictSetEntryVal(entry,val);
dictHashTableInsert(d,entry);
}
return 1;
} else {
dictSetEntryVal(entry,val);
return 0;
}
}
dictDelete操作的主要实现如下:
```cint dictDelete(dict *ht, const void *key) {
unsigned int h, idx; dictEntry *he, *prevHe;
if (ht->size == 0) return DICT_ERR; if (dictIsRehashing(ht)) _dictRehashStep(ht);
h = dictHashKey(ht,key);
/* Search in both tables if we are rehashing. */ for (idx = 0; idx
he = ht->table[idx] + (h & ht->sizemask); prevHe = NULL;
while(he) { if (key==he->key || dictCompareKeys(ht,key,he->key)) {
/* Unlink the element from the list */ if (prevHe)
prevHe->next = he->next; else
ht->table[idx] = he->next;
if (ht->keyDestructor) { ht->keyDestructor(he->key);
}
if (ht->valDestructor) { ht->valDestructor(he->v.val);
}
zfree(he); ht->used--;
return DICT_OK; }
prevHe = he; he = he->next;
} if (!dictIsRehashing(ht)) break;
} return DICT_ERR; /* not found */
}
4. 集合
Redis中的集合类型使用intset或者dict结构实现,使用dict结构实现的集合称为hashset。在Redis的源码中,集合类型的操作可以在src/intset.c文件和src/dict.c文件中找到,其中最常用的操作为setAdd、setIsMember、setRemove。
setAdd操作的主要实现如下:
“`c
int setTypeAdd(robj *subject, robj *value) {
long long llval;
uint8_t success = 0;
if (subject->encoding == OBJ_INTSET) {
if (isObjectRepresentableAsLongLong(value,&llval) != C_OK)
return 0;
subject->ptr = intsetAdd((intset*)subject->ptr,llval,&success);
if (success) signalModifiedObject(subject);
return success;
} else if (subject->encoding == OBJ_HT) {
dict *ht = subject->ptr;
dictEntry *de;
de = dictAddOrFind(ht,value);
if (de == NULL)
return 0;
if (dictFind(ht,value) == NULL) {
incrRefCount(value);
dictSetKey(ht,de,value);
signalModifiedObject(subject);
}
return 1;
} else {
serverPanic(“Unknown set encoding”);
}
}
setRemove操作的主要实现如下:
```cint setTypeRemove(robj *setobj, robj *value) {
long long llval; dict *ht;
dictEntry *de;
if (setobj->encoding == OBJ_INTSET) { if (isObjectRepresentableAsLongLong(value,&llval) != C_OK) return 0;
if (intsetRemove((intset*)setobj->ptr,llval,NULL)) { if (intsetLen((intset*)setobj->ptr) == 0) {
setobj->ptr = intsetResize(setobj