Redis深度歷險-快速列表 Redis深度歷險-快速列表

Redis深度歷險-快速列表

快速列表就是爲了實現list的功能,是基於壓縮列表和雙向鏈表的集合實現,主要是規避普通雙向鏈表的前後指針分配和內存碎片問題

列表

void listTypePush(robj *subject, robj *value, int where) {
    //list只有快速列表一種存儲方式了
    if (subject->encoding == OBJ_ENCODING_QUICKLIST) {
        int pos = (where == LIST_HEAD) ? QUICKLIST_HEAD : QUICKLIST_TAIL;
        //將數據插入到快速列表中 
        if (value->encoding == OBJ_ENCODING_INT) {
            char buf[32];
            ll2string(buf, 32, (long)value->ptr);
            quicklistPush(subject->ptr, buf, strlen(buf), pos);
        } else {
            quicklistPush(subject->ptr, value->ptr, sdslen(value->ptr), pos);
        }
    } else {
        serverPanic("Unknown list encoding");
    }
}

列表只使用了快速列表存儲數據

快速列表

快速列表的結構很簡單,快速列表就是一個雙向鏈表,只不過鏈表中每一個節點都是一個壓縮列表

結構體

快速列表

typedef struct quicklist {
    quicklistNode *head;
    quicklistNode *tail;                //快速列表的頭尾節點
    unsigned long count;        //所有元素的個數
    unsigned long len;          //快速列表節點個數
    int fill : QL_FILL_BITS;                        //和壓縮有關的參數,不必關注
    unsigned int compress : QL_COMP_BITS;   
    unsigned int bookmark_count: QL_BM_BITS;
    quicklistBookmark bookmarks[];
} quicklist;

壓縮列表可以進行壓縮以節省空間,暫時不必關注

快速列表節點

typedef struct quicklistNode {
    struct quicklistNode *prev;             
    struct quicklistNode *next;             //雙向鏈表前一個節點和後一個節點
    unsigned char *zl;                              //壓縮列表
    unsigned int sz;                        //壓縮列表字節長度
    unsigned int count : 16;                //壓縮列表中元素個數? 壓縮列表中不是有嗎???
    unsigned int encoding : 2;              //編碼方式,原生的還是壓縮的
    unsigned int container : 2;             
    unsigned int recompress : 1;                
    unsigned int attempted_compress : 1; 
    unsigned int extra : 10;                            //爲將來預留的標誌位
} quicklistNode;

頭部插入元素

int quicklistPushHead(quicklist *quicklist, void *value, size_t sz) {
    quicklistNode *orig_head = quicklist->head;
    //目前快速列表的頭節點是否還允許插入元素
    if (likely(
            _quicklistNodeAllowInsert(quicklist->head, quicklist->fill, sz))) {
        //在快速列表頭節點中插入元素
        quicklist->head->zl =
            ziplistPush(quicklist->head->zl, value, sz, ZIPLIST_HEAD);
        //更新頭節點中壓縮列表的字節長度
        quicklistNodeUpdateSz(quicklist->head);
    } else {
        //創建一個新的快速列表節點,並把元素插入到此節點中
        quicklistNode *node = quicklistCreateNode();
        node->zl = ziplistPush(ziplistNew(), value, sz, ZIPLIST_HEAD);
                
        //更新快速列表中壓縮列表字節長度
        quicklistNodeUpdateSz(node);
        //將這個新創建的快速列表節點插入在快速列表頭部
        _quicklistInsertNodeBefore(quicklist, quicklist->head, node);
    }
    //更新數量統計
    quicklist->count++;
    quicklist->head->count++;
    return (orig_head != quicklist->head);
}

因爲列表只支持頭部、尾部插入數據,所以整個代碼還是比較清晰的

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章