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);
}
因爲列表只支持頭部、尾部插入數據,所以整個代碼還是比較清晰的