💖 简介
redis 源码版本:3.05.04 如需源码,可官网下载或如下直接下载: 链接:https://pan.baidu.com/s/1vl_8UD30xZry4irsgmbdLQ 提取码:mpds
如有理解不对的地方,欢迎各位指出,大家共同交流和学习。 如有帮助,请点赞加支持! 送人玫瑰手有余香!🌹🌹🌹
💖源码学习
🏆 listInsertNode函数源码
💚 将给定值插入到指定节点💚
list *listInsertNode(list *list, listNode *old_node, void *value, int after) {
listNode *node;
if ((node = zmalloc(sizeof(*node))) == NULL)
return NULL;
node->value = value;
if (after) {
node->prev = old_node;
node->next = old_node->next;
if (list->tail == old_node) {
list->tail = node;
}
} else {
node->next = old_node;
node->prev = old_node->prev;
if (list->head == old_node) {
list->head = node;
}
}
if (node->prev != NULL) {
node->prev->next = node;
}
if (node->next != NULL) {
node->next->prev = node;
}
list->len++;
return list;
}
🏆 listDelNode函数源码
💚 删除指定节点💚
void listDelNode(list *list, listNode *node)
{
if (node->prev)
node->prev->next = node->next;
else
list->head = node->next;
if (node->next)
node->next->prev = node->prev;
else
list->tail = node->prev;
if (list->free) list->free(node->value);
zfree(node);
list->len--;
}
删除节点的三种情况示意图: 🟣 删除头节点
🟣 删除尾节点 🟣 删除中间节点
🏆 listGetIterator函数源码
💚 创建一个迭代器💚
listIter *listGetIterator(list *list, int direction)
{
listIter *iter;
if ((iter = zmalloc(sizeof(*iter))) == NULL) return NULL;
if (direction == AL_START_HEAD)
iter->next = list->head;
else
iter->next = list->tail;
iter->direction = direction;
return iter;
}
其中,AL_START_HEAD和AL_START_TAIL在头文件中定义。如下:
#define AL_START_HEAD 0
#define AL_START_TAIL 1
🏆 listReleaseIterator函数源码
💚 释放迭代器内存💚
void listReleaseIterator(listIter *iter) {
zfree(iter);
}
🏆 listRewind函数源码
💚 迭代器重新指向表头💚
void listRewind(list *list, listIter *li) {
li->next = list->head;
li->direction = AL_START_HEAD;
}
🏆 listRewindTail函数源码
💚 迭代器重新指向表尾💚
void listRewindTail(list *list, listIter *li) {
li->next = list->tail;
li->direction = AL_START_TAIL;
}
🏆 listNext函数源码
💚 返回迭代器的下一个元素💚
listNode *listNext(listIter *iter)
{
listNode *current = iter->next;
if (current != NULL) {
if (iter->direction == AL_START_HEAD)
iter->next = current->next;
else
iter->next = current->prev;
}
return current;
}
为什么要保存指针的下一个节点那?
因为,指针的下一个节点没被保存,当前节点被删除后,就会找不到下一个节点,导致节点丢失,程序异常。
🏆 listDup函数源码
💚 复制一个链表💚
list *listDup(list *orig)
{
list *copy;
listIter *iter;
listNode *node;
if ((copy = listCreate()) == NULL)
return NULL;
copy->dup = orig->dup;
copy->free = orig->free;
copy->match = orig->match;
iter = listGetIterator(orig, AL_START_HEAD);
while((node = listNext(iter)) != NULL) {
void *value;
if (copy->dup) {
value = copy->dup(node->value);
if (value == NULL) {
listRelease(copy);
listReleaseIterator(iter);
return NULL;
}
} else
value = node->value;
if (listAddNodeTail(copy, value) == NULL) {
listRelease(copy);
listReleaseIterator(iter);
return NULL;
}
}
listReleaseIterator(iter);
return copy;
}
注意,每次返回退出之前都要进行内存释放,避免内存泄漏。
🏆 listSearchKey函数源码
💚 查找链表中包含指定值的节点 💚
listNode *listSearchKey(list *list, void *key)
{
listIter *iter;
listNode *node;
iter = listGetIterator(list, AL_START_HEAD);
while((node = listNext(iter)) != NULL) {
if (list->match) {{
if (list->match(node->value, key)) {
listReleaseIterator(iter);
return node;
}
} else {
if (key == node->value) {
listReleaseIterator(iter);
return node;
}
}
}
listReleaseIterator(iter);
return NULL;
}
🏆 listIndex函数源码
💚 返回链表中指定索引的节点 💚
listNode *listIndex(list *list, PORT_LONG index) {
listNode *n;
if (index < 0) {
index = (-index)-1;
n = list->tail;
while(index-- && n) n = n->prev;
} else {
n = list->head;
while(index-- && n) n = n->next;
}
return n;
}
🏆 listRotate函数源码
💚 将链表的表尾节点弹出,然后将弹出的节点插入到表头,成为新的表头节点 💚
void listRotate(list *list) {
listNode *tail = list->tail;
if (listLength(list) <= 1) return;
list->tail = tail->prev;
list->tail->next = NULL;
list->head->prev = tail;
tail->prev = NULL;
tail->next = list->head;
list->head = tail;
}
💖 redis链表特点
🍀 双端:链表节点具有前置指针和后置指针。
🍀 无环:表头的前置指针和表尾的后置指针都指向NULL,不构成环路,对链表的访问以NULL为终点。
🍀 链表长度计数,使用含有len属性的list结构,对链表长度进行计算和保存。
🍀 多态:节点使用void *类型保存节点值,所以,可保保存各种不同类型的值。
🍀 灵活:可以通过list结构的dup、free、match三个属性为节点值设置类型特定函数。
💖 总结
redis链表实现还是不复杂的,希望继续努力,通过源码阅读发现自己知识盲点,提升知识储备,构建自己的知识体系。加油!
参考:
《Redis设计与实现》 《Redis学习之list底层链表源码分析》
|