Redis 的 RPUSH
和 LPUSH
命令用于在列表(list)数据结构的尾部或头部添加一个或多个元素。这两个命令的底层实现体现了Redis对列表操作的高效设计。下面是对它们实现学习的概述:
源码位置
- 这两个命令的实现可以在Redis源代码的
t_list.c
文件中找到,具体函数为rpushCommand
和lpushCommand
。
实现逻辑
-
命令解析与参数处理:首先,Redis解析客户端发送的命令和参数,确定操作的键名和待插入的元素。
-
键存在性检查与类型验证:通过
lookupKeyWriteOrReply
函数查找键是否存在,并检查其是否为列表类型。如果键不存在,则会创建一个新的列表;如果键存在但不是列表类型,则会返回一个错误。 -
编码选择:Redis的列表可以使用两种编码:
ziplist
(压缩列表)和linkedlist
(双端链表)。当满足特定条件(如元素数量少、元素长度短)时,会优先使用ziplist
以节省内存。随着列表的增长或元素复杂度的增加,Redis可能会自动将编码转换为linkedlist
。 -
元素添加:
RPUSH
:通过调用listTypePush
函数,传入REDIS_TAIL
参数,将元素添加到列表的尾部。LPUSH
:同样调用listTypePush
函数,但传入REDIS_HEAD
参数,将元素添加到列表的头部。
-
返回值:成功执行后,命令会返回操作后列表的长度。
代码示例
void rpushCommand(redisClient *c) {
listTypePush(c, c->argv[1], c->argv+2, c->argc-2, REDIS_TAIL);
}
void lpushCommand(redisClient *c) {
listTypePush(c, c->argv[1], c->argv+2, c->argc-2, REDIS_HEAD);
}
注意事项
listTypePush
函数是RPUSH
和LPUSH
共享的核心逻辑,它负责实际的元素添加操作,同时考虑到编码转换的逻辑。- Redis通过编码的选择和转换策略,在内存使用和操作性能之间寻找平衡。
- 源码学习时,注意观察如何处理元素的批量添加,以及如何维护列表的内部结构和元数据(如长度)。
通过深入阅读这些源码部分,可以了解到Redis如何高效地实现列表的尾部和头部添加操作,以及它如何在内部管理数据结构以适应不同的使用场景。