Redis 6.2 的链表(官方命名为 adlist,A generic doubly linked list)是通用双向循环链表的工业级实现,作为 Redis 核心底层数据结构之一,支撑了列表键、发布订阅、慢查询日志、AOF 重写缓冲区等核心功能。相较于 C 标准库无通用链表实现,Redis 自研的链表具备「双向循环、O (1) 长度、类型无关、安全迭代」等特性,兼顾性能与灵活性。
核心结构体(源码位于 src/adlist.h)
链表节点(listNode)
/* 链表节点结构体:双向节点,存储值指针 + 前驱/后继指针 */
typedef struct listNode {
struct listNode *prev; // 前驱节点指针(双向特性核心)
struct listNode *next; // 后继节点指针
void *value; // 节点值:void* 类型,支持任意数据(类型无关)
} listNode;
链表迭代器(listIter)
/* 链表迭代器:支持安全遍历,区分正向/反向迭代 */
typedef struct listIter {
listNode *next; // 下一个要访问的节点
int direction; // 迭代方向:AL_START_HEAD(正向)/AL_START_TAIL(反向)
} listIter;
/* 迭代方向常量 */
#define AL_START_HEAD 0 // 从表头到表尾(next 指向 head->next)
#define AL_START_TAIL 1 // 从表尾到表头(next 指向 tail->prev)
链表本体(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; // 链表长度(节点总数):O(1) 获取
} list;
函数指针的作用(类型无关核心)
Redis 链表通过 dup/free/match 函数指针,实现「同一链表结构支持任意类型值」:
- 示例 1:存储 SDS 时,
free设为sdsfree,match设为sdscmp; - 示例 2:存储整数时,
free设为NULL(无需释放),match设为整数比较函数; - 示例 3:存储自定义结构体时,自定义
dup/free/match函数。