我们使用redis , 其中经常需要得到一个list长度,那么这个list长度是否存储了还是每次都需要遍历整个list呢?
看了下源码
78 unsigned long listTypeLength(robj *subject) {
79 if (subject->encoding == REDIS_ENCODING_ZIPLIST) {
80 return ziplistLen(subject->ptr);
81 } else if (subject->encoding == REDIS_ENCODING_LINKEDLIST) {
82 return listLength((list*)subject->ptr);
83 } else {
84 redisPanic("Unknown list encoding");
85 }
86 }
list 采用两种实现方式,一个ziplist,另外一个linkedlist
我们先来看看这个ziplist
732 /* Return length of ziplist. */
733 unsigned int ziplistLen(unsigned char *zl) {
734 unsigned int len = 0;
735 if (ZIPLIST_LENGTH(zl) < UINT16_MAX) {
736 len = ZIPLIST_LENGTH(zl);
737 } else {
738 unsigned char *p = zl+ZIPLIST_HEADER_SIZE;
739 while (*p != ZIP_END) {
740 p += zipRawEntryLength(p);
741 len++;
742 }
743
744 /* Re-store length if small enough */
745 if (len < UINT16_MAX) ZIPLIST_LENGTH(zl) = len;
746 }
747 return len;
748 }
使用固定地方存放list长度,但是如果超过了最大值,那么就需要遍历
所以使用ziplist,最好长度不要超过 2^16 -2 = 65534 ,否则严重影响效率
我们再来看看linkedlist,实现在 adlist.c中
47 typedef struct list {
48 listNode *head;
49 listNode *tail;
50 void *(*dup)(void *ptr);
51 void (*free)(void *ptr);
52 int (*match)(void *ptr, void *key);
53 unsigned int len;
54 } list;
55
56 /* Functions implemented as macros */
57 #define listLength(l) ((l)->len)
从上面的代码可以看出,在list结构体中有个len字段,得到长度的时候,直接返回这个字段。