Redis dict

今天看了redis dict部分的源码(dict.h,dict.c),跟大家分享一下。

这两个文件包含了redis的hashtable的接口和实现。

Redis中hashtable的主要特点是增量rehash,rehash毕竟是一个耗时的操作,redis把它分摊到hashtable的各个小操作中,从而让字典操作性能曲线比较平滑。

既然要增量rehash,就要在一个dict中保留两个hashtable,分批次从hashtable[0]搬运元素到hashtable[1]中。

dict的iterator,iterator分为安全的iterator和不安全的iterator,安全的iterator锁定dict,不让它进行rehash及新增元素,直到它释放为止(dict中对安全iterator进行计数)。(这个做法颇有启发)

redis中hashtable的数组总是2的幂,按照数据结构的理论,理想的应该是素数,作者可能是为了方便或是hash计算时更快速。

dict 中提供了两个hash函数,unsigned int dictGenHashFunction(const void *key, int len);这是大名鼎鼎的MurmurHash2,unsigned int dictGenCaseHashFunction(const unsigned char *buf, int len);这是字符串中常用的hash算法(djb hash),只是不区分大小写,从seed开始,hash*33+char。当然也有获得和设置hash seed的接口。

主要的结构如下:

typedef struct dict {
    dictType *type;
    void *privdata;
    dictht ht[2];
    int rehashidx; /* rehashing not in progress if rehashidx == -1 */
    int iterators; /* number of iterators currently running */
} dict;


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;

/* This is our hash table structure. Every dictionary has two of this as we
 * implement incremental rehashing, for the old to the new table. */
typedef struct dictht {
    dictEntry **table;
    unsigned long size;
    unsigned long sizemask;
    unsigned long used;
} dictht;

typedef struct dictEntry {
    void *key;
    union {
        void *val;
        uint64_t u64;
        int64_t s64;
    } v;
    struct dictEntry *next;
} dictEntry;

有一些简单接口用宏包装,rehash触发的条件是used / size > 5。

一般的操作都会做一步rehash即把一个bucket从ht[0]放到ht[1]中,但是replace接口会做两次,因为会先调用find,再调用Add。

有专门的rehash接口,指定rehash几步,还可以指定花多少时间用于rehash,它实际上是每rehash100步检查下时间知道时间超出。

你可能感兴趣的:(redis,Hashtable,dict)