redisソース分析-adlist(チェーンテーブル)

23413 ワード

一、紹介
   ,   sds  ,       redis adlist(    ).redis               ,    src/adlist.h、src/adlist.c .

二、データ構造
C                (listNode)、   (listIterator)、  (list)  ,redis    。
  • ノード
    typedef struct listNode {
        struct listNode *prev;
        struct listNode *next;
        void *value;
    } listNode;
    value:ノードのコンテンツprevおよびnextは、それぞれ、前のノードと次のノードを指すポインタを表す.
  • 反復器
    typedef struct listIter {
         listNode *next;
         int direction;
    } listIter;
    next:次のノードポインタdirection:遍歴方向
  • コンテナ
    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;
    head:ヘッダポインタtailテーブルテールポインタdup:コピー関数free:リリース関数match:遍歴ルックアップ関数len:チェーンテーブル長
  • 三、チェーンテーブルの操作方法
                  ,            。       ,     C           ,        。
    
  • listCreate:listを作成して初期化し、listオブジェクトに戻ります.
    list *listCreate(void)
    {
        struct list *list;
    
        if ((list = zmalloc(sizeof(*list))) == NULL)
            return NULL;
        list->head = list->tail = NULL;
        list->len = 0;
        list->dup = NULL;
        list->free = NULL;
        list->match = NULL;
        return list;
    }
  • listRelease:チェーンテーブル解放機能を実現するlistCreateに対応します.
    void listRelease(list *list)
    {
        unsigned long len;
        listNode *current, *next;
    
        current = list->head;
        len = list->len;
        while(len--) {
            next = current->next;
            if (list->free) list->free(current->value);
            zfree(current);
            current = next;
        }
        zfree(list);
    }
    注意深い読者はlist->free関数に気づくかもしれないが、この関数はノードコンテンツを解放するための空間である.
  • listAddNodeHead:ヘッダー
    list *listAddNodeHead(list *list, void *value)
    {
        listNode *node;
        //    
        if ((node = zmalloc(sizeof(*node))) == NULL)
            return NULL;
        node->value = value;
        if (list->len == 0) {
            //    
            list->head = list->tail = node;
            node->prev = node->next = NULL;
        } else {
            //    
            node->prev = NULL;
            node->next = list->head;
            list->head->prev = node;
            list->head = node;
        }
        list->len++;
        return list;
    }
  • にデータを追加
  • listAddNodeTail:listAddNodeHead機能と同様に、テーブルの最後にデータを追加します.
    list *listAddNodeTail(list *list, void *value)
    {
        listNode *node;
    
        if ((node = zmalloc(sizeof(*node))) == NULL)
            return NULL;
        node->value = value;
        if (list->len == 0) {
            list->head = list->tail = node;
            node->prev = node->next = NULL;
        } else {
            node->prev = list->tail;
            node->next = NULL;
            list->tail->next = node;
            list->tail = node;
        }
        list->len++;
        return list;
    }
  • listInsertNode:指定したノードの前/後
    // after=0 ,        old_node   。
    // after=1 ,        old_node   。
    list *listInsertNode(list *list, listNode *old_node, void *value, int after) {
        listNode *node;
    
        if ((node = zmalloc(sizeof(*node))) == NULL)
            return NULL;
        node->value = value;
        //  node      
        if (after) {
            node->prev = old_node;
            node->next = old_node->next;
            if (list->tail == old_node) {
                list->tail = node;
            }
        } else {
            node->next = old_node;
            node->prev = old_node->prev;
            if (list->head == old_node) {
                list->head = node;
            }
        }
        //             ,       next    
        if (node->prev != NULL) {
            node->prev->next = node;
        }
        //             ,       prev    
        if (node->next != NULL) {
            node->next->prev = node;
        }
        list->len++;
        return list;
    }
  • に新しいノードを追加します.
  • listDelNode:指定ノードを削除する操作
    void listDelNode(list *list, listNode *node)
    {
    
        //  node    next  
        if (node->prev)
            node->prev->next = node->next;
        else
            list->head = node->next;
        //  node    prev  
        if (node->next)
            node->next->prev = node->prev;
        else
            list->tail = node->prev;
        //  node  
        if (list->free) list->free(node->value);
        zfree(node);
        //len-1
        list->len--;
    }
  • listGetIterator:取得反復器
    //direction:    
    //AL_START_HEAD :           
    //AL_START_TAIL :           
    listIter *listGetIterator(list *list, int direction)
    {
        listIter *iter;
    
        if ((iter = zmalloc(sizeof(*iter))) == NULL) return NULL;
        if (direction == AL_START_HEAD)
            iter->next = list->head;
        else
            iter->next = list->tail;
        iter->direction = direction;
        return iter;
    }
  • listRewind:チェーンテーブルポインタをテーブルヘッダにリセットします.これに対応してlistRewindTailの機能は、ポインタをテーブルの最後にリセットすることです.
    
    void listRewind(list *list, listIter *li) 
    {
        li->next = list->head;
        li->direction = AL_START_HEAD;
    }
  • listNext:この関数は非常に重要で、多くのチェーンテーブル操作で使用され、チェーンテーブル遍歴の機能を実現しています.
    
    listNode *listNext(listIter *iter)
    {
        //       
        listNode *current = iter->next;
        //  current  ,   direction ,  iter->next  
        if (current != NULL) {
            if (iter->direction == AL_START_HEAD)
                iter->next = current->next;
            else
                iter->next = current->prev;
        }
        return current;
    }
  • listDup:レプリケーションチェーンテーブル機能
    
    list *listDup(list *orig)
    {
        list *copy;
        listIter iter;
        listNode *node;
        //       
        if ((copy = listCreate()) == NULL)
            return NULL;
        copy->dup = orig->dup;
        copy->free = orig->free;
        copy->match = orig->match;
        //  orig     
        listRewind(orig, &iter);
        //  orig
        while((node = listNext(&iter)) != NULL) {
            void *value;
            //           
            if (copy->dup) {
                value = copy->dup(node->value);
                if (value == NULL) {
                    listRelease(copy);
                    return NULL;
                }
            } else
                value = node->value;
            //       
            if (listAddNodeTail(copy, value) == NULL) {
                listRelease(copy);
                return NULL;
            }
        }
        return copy;
    }
  • listSearchKey:与えられたkeyに基づいてチェーンテーブルを検索する
    
    listNode *listSearchKey(list *list, void *key)
    {
        listIter iter;
        listNode *node;
        //    
        listRewind(list, &iter);
        //  
        while((node = listNext(&iter)) != NULL) {
            //  value
            if (list->match) {
                if (list->match(node->value, key)) {
                    return node;
                }
            } else {
                if (key == node->value) {
                    return node;
                }
            }
        }
        return NULL;
    }
  • listIndex:与えられた下付き記号に基づいて、対応するノードを検索します.
    //           
    //index>=0:     ,          
    //index<0:     ,          
    listNode *listIndex(list *list, long index) {
        listNode *n;
    
        if (index < 0) {
            index = (-index)-1;
            n = list->tail;
            while(index-- && n) n = n->prev;
        } else {
            n = list->head;
            while(index-- && n) n = n->next;
        }
        return n;
    }
    

  • 四、まとめ
    1. redis               。
    2. redis            , C              。