• 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. 对外提供扩展,用户可以自定义查找,复制,释放的功能。

  • 相关阅读:
    计算机故障
    线程池&进程池
    机箱-网卡-声卡-显卡-显示器
    scrapy请求传参-BOSS反爬
    计算机硬件-主板
    计算机硬件-内存
    计算机硬件-硬盘
    计算机硬件-CPU
    ZJNU 1223
    ZJNU 1217
  • 原文地址:https://www.cnblogs.com/jabnih/p/4734446.html
Copyright © 2020-2023  润新知