链表的介绍
对于List链表,它的本质是一个双向链表的结构,每个元素都是一个结点。熟悉Java的同学,可以将Redis中的list列表结构,看做是Java中的LinkedList结构。
由于Redis的List结构的是双向链表结构,所以这也代表了它的插入和删除操作非常快,时间复杂度为 O(1),索引定位很慢,时间复杂度为 O(n)。
同时,Redis的List列表,也是可以作为队列和栈来使用的。下面就是List的具体指令了。
链表的用法
- rpush(key, value):在名称为key的list尾部添加一个值为value的元素,value可以是多个值
- lpush(key,value):在名称为key的list头添加一个值为value的 元素,value可以是多个值
- llen(key):返回名称为key的list的长度
- lrange(key, start, end):返回名称为key的list中start至end之间的元素(下标从0开始,下同)
- ltrim(key, start, end):截取名称为key的list,保留start至end之间的元素,可以为负数
- lindex(key, index):返回名称为key的list中index位置的元素
- lrem(key, count,value):删除count个名称为key的list中值为value的元素。count为0,删除所有值为value的元素,count>0从头至尾删除count个值为value的元素,count<0时,则从尾到头删除count绝对值的个数为value的元素。
- lpop(key):返回并删除名称为key的list中的首元素
- rpop(key):返回并删除名称为key的list中的尾元素
- blpop(key1, key2,… key N, timeout):lpop命令的block版本。即当timeout为0时,若遇到名称为key i的list不存在或该list为空,则命令结束。如果timeout>0,则遇到上述情况时,等待timeout秒,如果问题没有解决,则对 keyi+1开始的list执行pop操作。
- brpop(key1, key2,… key N, timeout):rpop的block版本。参考上一命令。
- rpoplpush(srckey, dstkey):返回并删除名称为srckey的list的尾元素,并将该元素添加到名称为dstkey的list的头部
链表的内部结构(部分源码)
在源码下的struct文件夹中,关于list的源文件有两个,一个是adlist.c,一个是t_list.c,前者是用于对list的定义,也就是下文中ziplist、linkedlist、quicklist的定义;后者是在Server/Client中的应答操作。主要通过redisObject进行类型转换。
链表内部结构的源码,主要是定义在Redis源码struct目录下的t_list.c文件中。
t_list对链表的描述不仅仅是双向链表那么简单,在早期Redis版本中,它描述了ziplist压缩表和linkedlist普通链表。在元素较少时,使用的是ziplist压缩表,在元素较多时,使用的则是linkedlist。
在Redis 3.2之后的版本中,由于链表的附加空间——prev和next指针,相对太高,需要两个指针大小。这两个指针在32位系统需要占据8个字节,64位更是16字节。所以在后期版本中,推出了quicklist来对ziplist和linkedlist的结构进行了优化。
quicklist 是 ziplist 和 linkedlist 的混合体,它将 linkedlist