Redis字典其實就是Hash表,其實現和JAVA語言中的hashmap結構大同小異,按Key-Value方式存儲鍵值對,但是又存在一定的差異。
java中的hashmap結構即包含hash表,又實現了rehash自我擴充;
而redis字典則通過dictht結構實現hash表,通過字典(dict)實現rehash(字典中包含一個dictht數組dictht ht[2])。
Redis字典的實現
Redis字典所使用的哈希表由dict.h/dictht結構定義:
typedef struct dictht{
dictEntry **table;
unsigned long size;
unsigned long sizemask;
unsigned long used;
}dictht;
table為一個dictEntry結構的數組,每個dictEntry結構保存著一個key-value對。size為table數組的大小(注意不是key-value對的個數);used才是key-value對的個數;sizemask為size-1,用途後面會提到;
dictEntry結構定義如下:
typedef struct dictEntry{
void *key;
union{
void *val;
uint64_t u64;
int64_t s64;
} v;
struct dictEntry *next;
}
key即為鍵,v即為值,由定義可以看出,v既可以是一個指針,也可以是一個uint64_t整數或者int64_t整數。
next屬性指向下一個dictEntry,形成鏈表結構。在字典結構中,每一個key-value中的key的hash值映射到table的下標,如果有多個key的hash值映射到table的同一個下標,則這些key-value對將通過 next指針形成一個鏈表,存到table的當前下標中。
Redis中的字典由dict.h/dict結構表示:
typedef struct dict{
dictType *type;
void *privdata;
dictht ht[2];
int rehashidx;
} dict;
注意到,其中:
dictht即為前面介紹的哈希表結構; type指針為一個dictType結構,該結構保存了一些用於操作特定類型鍵值對的函數,Redis會為用途不同的字典設置不同的類型特定函數; privdata則保存了需要傳遞給type中特定函數的可選參數;typedef struct dictType{
//計算hash值
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;
ht數組則包含2個dictht結構,平時只使用ht[0],在rehash的時候使用ht[1];
rehashidx則為一個標志位,如果當前沒有在進行rehash,則值為-1;redis通過漸進方式進行rehash,rehash期間,每執行一次操作,則rehashidx值加1;
Redis哈希算法
(未完待續。。。)