Redis基本数据结构(2)-adlist

本文深入解析Redis中adlist双向链表的结构与应用,重点介绍了节点数据结构、链表结构及三个关键函数指针的作用,展示了如何在C语言层面实现面向对象编程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

adlist是Redis中的双向链表。

双向链表的数据结构,和遍历算法有很多资料可以查到,这里不对其中的算法细节详细描述。

主要关注的是Redis利用双向链表结构,实现了什么样的精妙设计。

节点的数据结构

adlist首先是个链表,链表中的节点listNode定义在adlist.h中,

typedef struct listNode {
    struct listNode *prev;
    struct listNode *next;
    void *value;
} listNode;

每个节点都有个指针指向前后两个节点。

list的结构
typedef struct list {
    listNode *head;
    listNode *tail;
    void *(*dup)(void *ptr);
    void (*free)(void *ptr);
    int (*match)(void *ptr, void *key);
    unsigned long len;
} list;

list的前两个分别是指向list的头节点和尾结点,和一般的list结构没有大差异。

重点关注三个函数指针

void *(*dup)(void *ptr);
void (*free)(void *ptr);
int (*match)(void *ptr, void *key);

三个指针的作用,可以认为是高级语言中的接口,通过这三个接口可以实现多种不同的行为。

这种设计模式可以从高级语言的角度来理解,在这篇C语言实现类似Java接口的设计中有介绍。

list对节点的操作

以list的删除节点操作为例,

/* Remove the specified node from the specified list.
 * It's up to the caller to free the private value of the node.
 *
 * This function can't fail. */
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--;
}

删除过程分三个步骤,

· 获取待删除节点的前一个节点指针 prev,把prev的next指针改向待删除节点的下一个节点

· 获取待删除节点的下一个节点next,把next的prev指针改向待删除节点的前一个节点

· 释放待删除节点

从这里可以看到前面所说的list的三个函数指针的作用,

if (list->free) list->free(node->value);

这里调用了free函数指针,但这个指针具体指向谁,adlist并不关心,只需要知道有这个函数可以调用即可。

因此adlist可以有多种不同实现,每种实现可以用不同的free函数。

如在aof和rdb中,都通过listSetFreeMethod方法对他们所拥有的不同的adlist设置了不同的free函数实现。

aof.c: line 73

listSetFreeMethod(server.aof_rewrite_buf_blocks,zfree);

db.c:line 586

listSetFreeMethod(keys,decrRefCountVoid);

这里的zfree和decrRefCountVoid就是指向不同的函数的指针了。

adlist的应用

Redis中服务器就是用adlist来保存client的,
在redis.c的initServer()函数中可以看到下面的片段,

void initServer(void) {
    ...
    server.clients = listCreate();

具体在1664行。

这里通过listCreate()创建了双向链表,当有新的client连接发生时,把client(可以理解为对象)保存在 server.clients 列表中。

所以adlist其实不是用来存储原始数据(string,int这些)。

Redis的精妙之处在这里可以体现出来,在非常原始的C语言里设计 了一种结构,使得可以在C语言层面实现面向对象编程。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值