Redis学习——链表源码分析
0. 前言
Redis 中的链表是以通用链表的形式实现的,而对于链表的用途来说,主要的功能就是增删改查,所以对于查找来说,redis其提供了一个match函数指针,用户负责实现其具体的匹配操作,从而实现通用化。
涉及的文件:adlist.h/adlist.c
1. 数据结构
typedef struct listNode { struct listNode *prev; struct listNode *next; void *value; //通用实现,可以存放任意类型的数据 } listNode; typedef struct listIter { listNode *next; int direction; //用于控制链表遍历的方向 } listIter; typedef struct list { listNode *head; //表头 listNode *tail; //表尾 void *(*dup)(void *ptr); //用于复制ptr值,实现深度复制 void (*free)(void *ptr); //释放对应类型结构的内存 int (*match)(void *ptr, void *key); //自定义匹配key unsigned long len; //节点数量 } list;
#define listSetDupMethod(l,m) ((l)->dup = (m)) #define listSetFreeMethod(l,m) ((l)->free = (m)) #define listSetMatchMethod(l,m) ((l)->match = (m))
其中提供了dup,free,match的函数指针,用户可以通过设置该函数指针,来存取特定类型的数据。
2. API实现:
只提取几个主要的API,该文件完整的注释在GitHud上(用户名:jabnih)
a. listRelease
对于释放链表的操作,其中对于每个节点的释放会判断用户是否设置了free函数,若有则执行用户的操作,用以释放特定类型数据。例如:value为指向一个从堆分配的字符数组,在释放该节点的时候,就需要先释放value内存
对于free可以实现为:
1 void free(void * value) 2 { 3 if( value ) 4 free( (char *)value ); 5 }
1 //释放链表 2 void listRelease(list *list) 3 { 4 unsigned long len; 5 listNode *current, *next; 6 7 current = list->head; 8 len = list->len; 9 while(len--) { 10 next = current->next; 11 //若设置了free函数,则调用该自定义free函数 12 if (list->free) list->free(current->value); 13 14 zfree(current); 15 current = next; 16 } 17 zfree(list); 18 }
b. listDup
当执行复制的时候,对于设置了dup函数可以实现深度复制或自定义复制的功能。
1 //复制链表,若有链表有dup,则调用该函数进行深度复制,否则直接复制节点的值(浅复制) 2 list *listDup(list *orig) 3 { 4 list *copy; 5 listIter *iter; 6 listNode *node; 7 8 if ((copy = listCreate()) == NULL) 9 return NULL; 10 copy->dup = orig->dup; 11 copy->free = orig->free; 12 copy->match = orig->match; 13 iter = listGetIterator(orig, AL_START_HEAD); 14 while((node = listNext(iter)) != NULL) { 15 //遍历整个链表 16 void *value; 17 18 if (copy->dup) { 19 //深度复制 20 value = copy->dup(node->value); 21 if (value == NULL) { 22 //复制出错 23 listRelease(copy); 24 listReleaseIterator(iter); 25 return NULL; 26 } 27 } else 28 //浅复制 29 value = node->value; 30 31 //将复制后的节点添加的copy链表尾部 32 if (listAddNodeTail(copy, value) == NULL) { 33 listRelease(copy); 34 listReleaseIterator(iter); 35 return NULL; 36 } 37 } 38 listReleaseIterator(iter); 39 return copy; 40 }
c. listSearchKey
1 //查找节点,如果设置了match方法,则使用match方法比较,否则仅仅比较节点的value值 2 listNode *listSearchKey(list *list, void *key) 3 { 4 listIter *iter; 5 listNode *node; 6 7 iter = listGetIterator(list, AL_START_HEAD); 8 while((node = listNext(iter)) != NULL) { 9 if (list->match) { 10 if (list->match(node->value, key)) { 11 //这里可以将下面两条语句改为break(下同),最后return NULL改为 return node 12 listReleaseIterator(iter); 13 return node; 14 } 15 } else { 16 if (key == node->value) { 17 listReleaseIterator(iter); 18 return node; 19 } 20 } 21 } 22 listReleaseIterator(iter); 23 return NULL; 24 }
3. 总结
1. 通用链表实现
2. 对外提供扩展,用户可以自定义查找,复制,释放的功能。