新聞中心
深入學(xué)習(xí)Redis:DICT源碼剖析

創(chuàng)新互聯(lián)公司專(zhuān)注于揚(yáng)中企業(yè)網(wǎng)站建設(shè),響應(yīng)式網(wǎng)站,電子商務(wù)商城網(wǎng)站建設(shè)。揚(yáng)中網(wǎng)站建設(shè)公司,為揚(yáng)中等地區(qū)提供建站服務(wù)。全流程按需求定制設(shè)計(jì),專(zhuān)業(yè)設(shè)計(jì),全程項(xiàng)目跟蹤,創(chuàng)新互聯(lián)公司專(zhuān)業(yè)和態(tài)度為您提供的服務(wù)
Redis是一個(gè)高性能的鍵值存儲(chǔ)系統(tǒng),其中的數(shù)據(jù)結(jié)構(gòu)dict扮演了至關(guān)重要的角色。dict是Redis內(nèi)部用來(lái)實(shí)現(xiàn)哈希表的數(shù)據(jù)結(jié)構(gòu),它的性能決定了Redis的性能。本文將深入探究Redis中的dict數(shù)據(jù)結(jié)構(gòu)源碼以及如何使用它。
dict的基本結(jié)構(gòu)
在Redis的源碼中,dict的實(shí)現(xiàn)在字典結(jié)構(gòu)體dictType中定義。dictType的結(jié)構(gòu)如下:
typedef struct dictType {
unsigned int (*hashFunction)(const void *KEY);
void *(*keyDup)(void *privdata, const void *key);
void *(*valDup)(void *privdata, const void *obj);
int (*keyCompare)(void *privdata, const void *key1, const void *key2);
void (*keyDestructor)(void *privdata, void *key);
void (*valDestructor)(void *privdata, void *obj);
} dictType;
dictType中定義了dict的6個(gè)回調(diào)函數(shù),包括了鍵的哈希函數(shù)、鍵的復(fù)制函數(shù)、值的復(fù)制函數(shù)、鍵的比較函數(shù)、鍵的析構(gòu)函數(shù)以及值的析構(gòu)函數(shù)。
接著我們看dictEntry的定義,dictEntry正好能代表dict中的一項(xiàng),其結(jié)構(gòu)體如下:
typedef struct dictEntry {
void *key;
union {
void *val;
uint64_t u64;
int64_t s64;
double d;
} v;
struct dictEntry *next;
} dictEntry;
dictEntry中存放了一個(gè)key以及一個(gè)val,其中val是一個(gè)Union,能存放多種類(lèi)型的值。next是為了解決hash算法沖突而存在的指針。
最后是dict的定義了,它的結(jié)構(gòu)體定義如下:
typedef struct dictht {
dictEntry **TABLE;
unsigned long size;
unsigned long sizemask;
unsigned long used;
} dictht;
typedef struct dict {
dictType *type;
void *privdata;
dictht ht[2];
long rehashidx; /* rehashing not in progress if rehashidx == -1 */
int iterators; /* number of iterators currently running */
} dict;
在dict的定義中,我們可以看到dict是由兩個(gè)dictht結(jié)構(gòu)體組成的,也就是說(shuō),dict中包含了兩個(gè)哈希表(table)。其中一個(gè)叫做ht[0],它是正在被使用的哈希表,ht[1]則是用來(lái)在rehash(rehash是Redis用來(lái)動(dòng)態(tài)擴(kuò)容的)過(guò)程中存放數(shù)據(jù)的哈希表。
dict的方法實(shí)現(xiàn)
dict的方法可以分為兩類(lèi):通用方法和私有方法。通用方法是指dict的外部接口,提供給外部程序使用的方法。它們包括dictAdd、dictFind、dictDelete等方法。而私有方法是指dict內(nèi)部使用的方法,只供dict內(nèi)部調(diào)用。它們包括_dictRehashStep、_dictKeyIndex、_dictExpandIfNeeded等方法。
dict的添加函數(shù)dictAdd的實(shí)現(xiàn)如下:
int dictAdd(dict *ht, void *key, void *val)
{
dictEntry *entry = dictAddRaw(ht,key,NULL);
if (!entry) return DICT_ERR;
dictSetVal(ht, entry, val);
return DICT_OK;
}
dictAdd方法調(diào)用了dictAddRaw方法來(lái)添加一個(gè)新的鍵值對(duì),如果添加成功,則返回DICT_OK,否則返回DICT_ERR。
dict的查找函數(shù)dictFind實(shí)現(xiàn)如下:
dictEntry *dictFind(dict *ht, const void *key)
{
dictEntry *he;
unsigned int h;
if (ht->size == 0) return NULL;
if (dictIsRehashing(ht)) _dictRehashStep(ht);
h = dictHashKey(ht, key);
for (int table = 0; table
he = ht->ht[table].table[h & ht->ht[table].sizemask];
while (he) {
if (dictCompareKeys(ht, key, he->key))
return he;
he = he->next;
}
if (!dictIsRehashing(ht)) return NULL;
}
return NULL;
}
dictFind方法通過(guò)dictHashKey方法計(jì)算出key對(duì)應(yīng)的哈希值,然后從兩個(gè)哈希表中查找對(duì)應(yīng)的dictEntry對(duì)象。查找時(shí),先從正在使用的哈希表(table[0])開(kāi)始查找,如果找到了就返回當(dāng)前的dictEntry對(duì)象,如果在table[0]中沒(méi)有找到,再到table[1]中查找。如果在table[1]中依然沒(méi)有找到,說(shuō)明該key不存在于Redis里。
dict的刪除函數(shù)dictDelete實(shí)現(xiàn)如下:
int dictDelete(dict *ht, const void *key)
{
dictEntry *he, *prevHe = NULL;
unsigned int h;
int table;
if (ht->ht[0].size == 0 && ht->ht[1].size == 0) return DICT_ERR;
if (dictIsRehashing(ht)) _dictRehashStep(ht);
h = dictHashKey(ht, key);
for (table = 0; table
he = ht->ht[table].table[h & ht->ht[table].sizemask];
while (he) {
if (dictCompareKeys(ht, key, he->key)) {
if (prevHe)
prevHe->next = he->next;
else
ht->ht[table].table[h & ht->ht[table].sizemask] = he->next;
dictFreeEntryKey(ht, he);
dictFreeEntryVal(ht, he);
zfree(he);
ht->ht[table].used--;
return DICT_OK;
}
prevHe = he;
he = he->next;
}
if (!dictIsRehashing(ht)) break;
}
return DICT_ERR;
}
dictDelete方法先計(jì)算key的哈希值,然后從兩個(gè)哈希表中查找包含該key的dictEntry對(duì)象。找到該對(duì)象后,從鏈表上刪除,并釋放內(nèi)存。如果刪除成功,返回DICT_OK,否則返回DICT_ERR。
使用dict實(shí)現(xiàn)緩存機(jī)制
dict的高效性能為Redis實(shí)現(xiàn)緩存機(jī)制提供了極大的便利。我們可以將常用數(shù)據(jù)放入Redis中,它們會(huì)被存儲(chǔ)在內(nèi)存中,當(dāng)需要訪問(wèn)數(shù)據(jù)時(shí)可以直接從內(nèi)存中讀取,減少了文件I/O操作,提升了訪問(wèn)速度。
我們可以編寫(xiě)以下代碼來(lái)實(shí)現(xiàn)緩存機(jī)制:
#include "redis.h"
void cacheData(redisClient *c) {
dictEntry *de;
dict *dictPtr;
long long bytes = 0;
/* If the key already exists in the cache, delete it first */
if (lookupKeyRead(c->db,c->argv[1]->ptr) != NULL) {
dbDelete(c->db,c->argv[1]);
}
/* Add the key-value pr to the cache */
dictPtr = c->db->dict;
de = dictAddRaw(dictPtr,c->argv[1]->ptr,NULL);
bytes += sdslen(c->argv[1]->ptr)+dictSize(dictPtr->valsize);
dictSetVal(dictPtr, de, c->argv[2]);
incrRefCount(c->argv[2]);
c->db->dict->expire = 0;
addReply(c,shared.ok);
}
cacheData方法首先從Redis中查找key,如果已經(jīng)存在這個(gè)key,則需要先將這個(gè)key對(duì)應(yīng)的value從Redis中刪除。然后,將新的key-value放入Redis的dict中即可。
本文簡(jiǎn)要的介紹了dict的基本結(jié)構(gòu)以及dict的三個(gè)基本方法,同時(shí)也講述了如何使用dict實(shí)現(xiàn)緩存機(jī)制。在實(shí)際的應(yīng)用中,我們還需要根據(jù)實(shí)際情況合理的設(shè)置dict的回調(diào)函數(shù),以讓dict提供更好的性能,從而為Redis提供高效的數(shù)據(jù)存儲(chǔ)和檢索服務(wù)。
成都網(wǎng)站營(yíng)銷(xiāo)推廣找創(chuàng)新互聯(lián),全國(guó)分站站群網(wǎng)站搭建更好做SEO營(yíng)銷(xiāo)。
創(chuàng)新互聯(lián)(www.cdcxhl.com)四川成都IDC基礎(chǔ)服務(wù)商,價(jià)格厚道。提供成都服務(wù)器托管租用、綿陽(yáng)服務(wù)器租用托管、重慶服務(wù)器托管租用、貴陽(yáng)服務(wù)器機(jī)房服務(wù)器托管租用。
本文標(biāo)題:深入學(xué)習(xí)Redisdict源碼剖析(redis源碼之dict)
文章URL:http://fisionsoft.com.cn/article/dhphhjs.html


咨詢(xún)
建站咨詢(xún)
