美文网首页我爱编程
redis源码阅读-adlist

redis源码阅读-adlist

作者: 装正经的正经人 | 来源:发表于2018-04-01 18:32 被阅读0次

    adlist 阅读

    author: Pei Xingxin (xingxinpei@gmail.com)

    background

    这里其实想谈谈为什么要做redis的source code reading & analysing。动机有点尴尬,因为在大厂的工作中,开源的工具使用较少,时间长了竟然会成为一个被外部人员低看一眼的理由。当然,对于面试应该考察什么这个话题,我也一肚子槽想吐,找个机会会一并写出。

    话不多说,言归正传

    adlist是什么

    adlist - A generic doubly linked list implementation,就是一个通用的双向列表实现。

    adlist的数据结构

    一个典型的list,一定会有node,这个实现比较完备,同时提供了iterator。于是这里至少有三个数据结构

    listNode

    Node是链表中的每个节点的定义与抽象,其中value可以是更丰富的类型

    typedef struct listNode {
        struct listNode *prev;
        struct listNode *next;
        void *value;
    } listNode;
    

    listIter

    迭代器用于遍历整个list

    typedef struct listIter {
        listNode *next;
        int direction;
    } listIter;
    

    list

    list是真正对外操作的数据结构,有几个重要的参数,head,tail用于分别表示头节点和尾节点,len是用于记录当前的链表长度,这样length操作就是O(1)的时间复杂度。另外,为了使链表更有通用性,即基于value的复杂性,提供了dup,free,match三个特殊的函数指针用于专门操作value部分

    typedef struct list {
        listNode *head;
        listNode *tail;
        void *(*dup)(void *ptr);
        void (*free)(void *ptr);
        int (*match)(void *ptr, void *key);
        unsigned long len;
    } list;
    

    list操作部分,宏部分

    这部分操作是可以根据list的成员变量直接获得的,定义函数的好处是,接口更统一易读

        /* Functions implemented as macros */
        #define listLength(l) ((l)->len)
        #define listFirst(l) ((l)->head)
        #define listLast(l) ((l)->tail)
        #define listPrevNode(n) ((n)->prev)
        #define listNextNode(n) ((n)->next)
        #define listNodeValue(n) ((n)->value)
        
        #define listSetDupMethod(l,m) ((l)->dup = (m))
        #define listSetFreeMethod(l,m) ((l)->free = (m))
        #define listSetMatchMethod(l,m) ((l)->match = (m))
        
        #define listGetDupMethod(l) ((l)->dup)
        #define listGetFree(l) ((l)->free)
        #define listGetMatchMethod(l) ((l)->match)
    

    iterator的操作方向,也是宏定义

    /* Directions for iterators */
    #define AL_START_HEAD 0
    #define AL_START_TAIL 1
    

    函数操作的部分,需要代码实现部分的对于接口定义

    接口的定义基本上都非常的通俗易懂,大部分其意自明。这里重点描述一下几个函数

    listRewind,  表示把迭代器指向头部,并且从头部开始遍历
    listRewindTail,把迭代器指向尾部,遍历方向设置为从尾部开始
    listRotate,表示把最后一个元素挪到第一个去
    listSearchKey,表示在链表中找到value = key 的节点
    listIndex,表示链表从头或者从尾部,找到第index个节点
    
    /* Prototypes */
    list *listCreate(void);
    void listRelease(list *list);
    list *listAddNodeHead(list *list, void *value);
    list *listAddNodeTail(list *list, void *value);
    list *listInsertNode(list *list, listNode *old_node, void *value, int after);
    void listDelNode(list *list, listNode *node);
    listIter *listGetIterator(list *list, int direction);
    listNode *listNext(listIter *iter);
    void listReleaseIterator(listIter *iter);
    list *listDup(list *orig);
    listNode *listSearchKey(list *list, void *key);
    listNode *listIndex(list *list, long index);
    void listRewind(list *list, listIter *li);
    void listRewindTail(list *list, listIter *li);
    void listRotate(list *list);
    

    函数操作的实现部分

    这部分都在adlist.c中,代码实现很优美,建议日常的链表操作都可以参考这里代码实现。举一个实现比较优雅的例子

    listNode *listNext(listIter *iter)
    {
        listNode *current = iter->next;
    
        if (current != NULL) {
            if (iter->direction == AL_START_HEAD)
                iter->next = current->next;
            else
                iter->next = current->prev;
        }
        return current;
    }
    

    相关文章

      网友评论

        本文标题:redis源码阅读-adlist

        本文链接:https://www.haomeiwen.com/subject/ubjacftx.html