此篇為對redis五大數(shù)據(jù)類型中l(wèi)ist的分析,希望能有所幫助
?List API
listTypePush函數(shù)
void listTypePush(robj *subject, robj *value, int where) {
/* 檢查編碼類型是否為 quicklist (快速列表) */
if (subject->encoding == OBJ_ENCODING_QUICKLIST) {
/* 根據(jù)參數(shù) where 選擇插入位置,由 pos 保存插入位置信息 */
int pos = (where == LIST_HEAD) ? QUICKLIST_HEAD : QUICKLIST_TAIL;
/* value 為整數(shù)編碼 */
if (value->encoding == OBJ_ENCODING_INT) {
/* 將 value 先轉(zhuǎn)換為字符串 */
char buf[32];
ll2string(buf, 32, (long)value->ptr);
/* 將元素插入列表 */
quicklistPush(subject->ptr, buf, strlen(buf), pos);
/* value 為字符串編碼 */
} else {
quicklistPush(subject->ptr, value->ptr, sdslen(value->ptr), pos);
}
} else {
serverPanic("Unknown list encoding");
}
}
分析:
該函數(shù)將一個元素插入到指定的列表對象 'subject',?插入位置由 'where' 決定是在列表頭部還是尾部插入,調(diào)用者不需要自己來增加 'value' 的 refcount,該函數(shù)會負(fù)責(zé)處理。
作用:
實現(xiàn)命令函數(shù)pushGenericCommand中會用到
/* 讀取輸入的元素,并向列表插入元素 */
for (j = 2; j < c->argc; j++) {
listTypePush(lobj,c->argv[j],where);
/* 臟數(shù)據(jù) + 1,即緩存中未保存到本地的數(shù)據(jù) */
server.dirty++;
}
實現(xiàn) lmove 命令中向目的列表(destination)插入元素中會用到
/* 向列表中插入元素 */
listTypePush(dstobj,value,where);
listPopSaver函數(shù)(用于給列表彈出的元素創(chuàng)建副本的函數(shù))
void *listPopSaver(unsigned char *data, size_t sz) {
return createStringObject((char*)data,sz);
}
示例:
給quicklistPopCustom傳參用到
/* 從列表中彈出元素 */
if (quicklistPopCustom(subject->ptr, ql_where, (unsigned char **)&value,
NULL, &vlong, listPopSaver))
listTypePop函數(shù)(彈出列表元素的通用實現(xiàn)函數(shù))
robj *listTypePop(robj *subject, int where) {
long long vlong;
robj *value = NULL;
/* 根據(jù)參數(shù) where 選擇插入位置,由 ql_where 保存插入位置信息 */
int ql_where = where == LIST_HEAD ? QUICKLIST_HEAD : QUICKLIST_TAIL;
/* 檢查編碼類型是否為 quicklist (快速列表) */
if (subject->encoding == OBJ_ENCODING_QUICKLIST) {
/* 從列表中彈出元素 */
if (quicklistPopCustom(subject->ptr, ql_where, (unsigned char **)&value,
NULL, &vlong, listPopSaver)) {
/* 如果 value 為 NULL ,則彈出元素被保存在 vlong 中(若不為 NULL 則說明保存在 value 中)
* 則用 vlong 創(chuàng)建一個字符串對象并讓 value 對其引用 */
if (!value)
value = createStringObjectFromLongLong(vlong);
}
} else {
serverPanic("Unknown list encoding");
}
return value;
}
示例:
?popGenericCommand函數(shù),彈出一個元素
/* 彈出一個元素,這是 pop 的原始操作,會向客戶端回復(fù)一個字符串 */
value = listTypePop(o,where);
listTypeLength函數(shù)(獲取列表長度(元素總數(shù)))
unsigned long listTypeLength(const robj *subject) {
if (subject->encoding == OBJ_ENCODING_QUICKLIST) {
return quicklistCount(subject->ptr);
} else {
serverPanic("Unknown list encoding");
}
}
listTypeInitIterator函數(shù)(在指定的索引處初始化一個列表迭代器)
listTypeIterator *listTypeInitIterator(robj *subject, long index,
unsigned char direction) {
/* 給列表迭代器分配內(nèi)存空間 */
listTypeIterator *li = zmalloc(sizeof(listTypeIterator));
/* 初始化列表迭代器 */
li->subject = subject;
li->encoding = subject->encoding;
li->direction = direction;
li->iter = NULL;
/* LIST_HEAD means start at TAIL and move *towards* head.
* LIST_TAIL means start at HEAD and move *towards* tail. */
/* LIST_HEAD 意味著從列表尾部開始,并向頭部移動。
* LIST_TAIL 表示從列表頭部開始,并向尾部移動 */
int iter_direction =
direction == LIST_HEAD ? AL_START_TAIL : AL_START_HEAD;
/* 檢查編碼類型是否為 quicklist (快速列表) */
if (li->encoding == OBJ_ENCODING_QUICKLIST) {
/* 初始化一個 quicklist 節(jié)點的迭代器,并且該迭代器指向列表的第 index 個元素,
* 雖然用詞是”指向“但是迭代器并不是一個指針,而是個結(jié)構(gòu)體,它記錄的元素信息是列表第 index 個元素 */
li->iter = quicklistGetIteratorAtIdx(li->subject->ptr,
iter_direction, index);
} else {
serverPanic("Unknown list encoding");
}
return li;
}
用處:
linsertCommand函數(shù)中用于遍歷查找,初始化迭代器;在addListRangeReply函數(shù)中初始化范圍起點位置的迭代器?
listTypeSetIteratorDirection函數(shù)(設(shè)置迭代器的方向 )
void listTypeSetIteratorDirection(listTypeIterator *li, unsigned char direction) {
li->direction = direction;
int dir = direction == LIST_HEAD ? AL_START_TAIL : AL_START_HEAD;
quicklistSetDirection(li->iter, dir);
}
listTypeReleaseIterator函數(shù)(釋放迭代器)
void listTypeReleaseIterator(listTypeIterator *li) {
quicklistReleaseIterator(li->iter);
zfree(li);//redis定義的一個函數(shù),在free函數(shù)的基礎(chǔ)上有改變
}
基本上跟在listTypeInitIterator函數(shù)后面,釋放迭代器
listTypeNext函數(shù)
int listTypeNext(listTypeIterator *li, listTypeEntry *entry) {
/* Protect from converting when iterating */
/* 保護(hù)迭代時編碼不被轉(zhuǎn)換,則需要迭代器記錄的編碼類型和迭代器指向的列表對象編碼一致 */
serverAssert(li->subject->encoding == li->encoding);
/* 將參數(shù) li 賦值給參數(shù) entry 的迭代器成員 */
entry->li = li;
/* 檢查編碼類型是否為 quicklist (快速列表) */
if (li->encoding == OBJ_ENCODING_QUICKLIST) {
/* 調(diào)用 quicklistNext 函數(shù)獲取下一個元素,
* 元素 (quicklistEntry) 保存在 entry->entry 中,并推進(jìn)迭代器位置
* 如果 下一個元素存在,該函數(shù)返回1,否則返回0 */
return quicklistNext(li->iter, &entry->entry);
} else {
serverPanic("Unknown list encoding");
}
return 0;
}
分析:
?獲取迭代器指向元素的下一個元素,并推進(jìn)迭代器的位置(推進(jìn)方向由迭代器成員 direction 決定)。?如果 entry(下一個元素) 存在,返回1,否則返回0?
用處:
linsertCommand函數(shù)中用于遍歷查找,在addListRangeReply函數(shù)中設(shè)置迭代器的范圍起點位置文章來源:http://www.zghlxwxcb.cn/news/detail-637281.html
總結(jié):
本篇分析了listpush,popsaver,poplength函數(shù),對列表彈出元素和計算列表長度的功能進(jìn)行分析,同時還分析了關(guān)于迭代器初始化,設(shè)置方向,釋放和獲取迭代器下一個元素的函數(shù),對迭代器的功能進(jìn)行分析。文章來源地址http://www.zghlxwxcb.cn/news/detail-637281.html
到了這里,關(guān)于redis五大類型分析--list(1)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!