从源码深入理解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操作的主要实现如下:

```c
void 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操作的主要实现如下:

```c
list *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操作的主要实现如下:

```c
int 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操作的主要实现如下:

```c
int 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

数据运维技术 » 从源码深入理解Redis(redis源码深入理解)