Redis 2.8.9源码 - 字典哈希表操作函数头整理,并注释作用和参数说明(附测试方法和代码)

本文为作者原创,转载请注明出处:http://my.oschina.net/fuckphp/blog/277226

点击查看测试代码


/**
 * 32数混淆函数(没看到哪里有用这个函数)
 * unsigned int key 需要混淆的数字
 * return 混淆后的数字
 */
unsigned int dictIntHashFunction(unsigned int key);


/**
 * 设置hash函数的随机种子
 * uint32_t seed 随机种子默认 5381
 * return void
 */
void dictSetHashFunctionSeed(uint32_t seed);


/**
 * 获取hash函数的随机种子
 * return 返回随机种子
 */
uint32_t dictGetHashFunctionSeed(void);


/**
 * MurmurHash2 算法的实现
 * const void *key 需要进行hash的字符串
 * int len 需要进行hash的字符串长度
 * return 返回hash后的结果
 */
unsigned int dictGenHashFunction(const void *key, int len);


/**
 * DjbHash 算法的实现
 * const unsigned char *buf 需要进行hash的字符串
 * int len 需要进行hash的字符串长度
 * return 返回hash后的结果
 */
unsigned int dictGenCaseHashFunction(const unsigned char *buf, int len);


/**
 * 对 hashtable 进行重置操作 私有函数
 * dictht *ht 需要初始化的 hashtable
 * return 返回hash后的结果
 */
static void _dictReset(dictht *ht);


/**
 * 创建一个新的字典
 * dictType *type  字典操作函数类型(type是一个包含一组回调函数的结构)
 * void *privDataPtr 设置为不同类型回调函数提供的 私有参数
 * return 返回一个新的字典
 */
dict *dictCreate(dictType *type, void *privDataPtr);


/**
 * 对新的字典进行初始化操作 对字典中的hashtable进行重置操作,并对其他属性设置默认值 私有函数
 * dict *d 需要初始化操作的字典
 * dictType *type  字典操作函数类型(type是一个包含一组回调函数的结构)
 * void *privDataPtr 设置为不同类型回调函数提供的 私有参数
 * return 返回初始化的状态
 */
int _dictInit(dict *d, dictType *type, void *privDataPtr);


/**
 * 重新设置桶的大小 如果 dict_can_resize 为 0 或者 正在进行rehash则不进行重新设置
 * dict *d 需要扩展的字典
 * return 返回扩展结果的状态
 */
int dictResize(dict *d);


/**
 * 将字典创建hashable,并对hashtable桶的个数进行扩展,如果正在rehash 或者 当前节点数 小于传递过来的节点数 则不进行rehash
 * dict *d 需要扩展的字典
 * unsigned long size  当前的节点数 最小为 DICT_HT_INITIAL_SIZE
 * return 返回扩展结果的状态
 */
int dictExpand(dict *d, unsigned long size);


/**
 * 对字典的n个桶进行rehash,计算每个桶内链表所有key并计算hash后,存放在ht[1]中,并将ht[0]中处理过的桶指针指向空
 * dict *d 需要rehash的字典
 * int n 进行rehash的桶的的个数
 * return 返回0表示rehash结束 否则表示 还没有完全rehash结束
 */
int dictRehash(dict *d, int n);


/**
 * 获取以毫秒为单位的时间戳
 * return 返回 以毫秒为单位的时间戳 例如:1401352736541
 */
long long timeInMilliseconds(void);


/**
 * 对字典进行rehash操作,每次rehash 100个桶,知道rehash时间超过 ms毫秒
 * dict *d 进行rehash的字典
 * int ms rehash的时间限制
 * return  返回执行rehash的桶的个数
 */
int dictRehashMilliseconds(dict *d, int ms);


/**
 * 如果没有进行迭代操作,则进行一次rehash操作(渐进式rehash,将rehash操作分不到每一个操作上)
 * dict *d 进行rehash的字典
 * return  void
 */
static void _dictRehashStep(dict *d);


/**
 * 向hashtable中加入一个新的节点
 * dict *d 加入节点的字典
 * void *key 节点的key
 * void *val 节点的value
 * return 返回 成功或失败
 */
int dictAdd(dict *d, void *key, void *val);


/**
 * 创建一个包含KEY的dictEntry对象,如果正在进行Rehash,会执行一个桶的Rehash操作(在检查key的时候会判断是否处罚rehash)
 * dict *d 加入节点的字典
 * void *key 节点的key
 * return 返回创建成功包含key的dictEntry
 */
dictEntry *dictAddRaw(dict *d, void *key);


/**
 * 创建一个包含KEY的dictEntry对象,如果key已经存在则覆盖,如果正在进行Rehash,会执行一个桶的Rehash操作(在检查key的时候会判断是否处罚rehash)
 * dict *d 加入节点的字典
 * void *key 节点的key
 * void *val 节点的val
 * return 返回 成功或失败
 */
int dictReplace(dict *d, void *key, void *val);


/**
 * 查找如果存在key则返回key对应的结构,否则 创建一个包含key的新的结构并返回
 * dict *d 加入节点的字典
 * void *key 节点的key
 * return 返回 查找到的或新创建的 dictEntry
 */
dictEntry *dictReplaceRaw(dict *d, void *key);


/**
 * 查找并在hashtable删除某个key所对应的结构
 * dict *d 加入节点的字典
 * void *key 要删除的节点的key
 * int nofree 如果为1 则删除的某个key的结构不进行内存释放
 * return 返回 成功或失败
 */
static int dictGenericDelete(dict *d, const void *key, int nofree);


/**
 * 查找并在hashtable删除某个key所对应的结构,并不释放内存
 * dict *d 加入节点的字典
 * void *key 要删除的节点的key
 * return 返回 成功或失败
 */
int dictDeleteNoFree(dict *ht, const void *key);


/**
 * 将字典中的某个ht中所有节点全部删除
 * dict *d 要进行删除操作的的字典
 * dictht *ht dictht[0] 或 dictht[1]
 * void(callback)(void *) 回调函数,void *参数为 dict结构中的pridata
 * return 返回 成功或失败
 */
int _dictClear(dict *d, dictht *ht, void(callback)(void *));


/**
 * 将字典所有节点清空,并释放字典
 * dict *d 要删除的字典
 * return 返回 成功或失败
 */
void dictRelease(dict *d);


/**
 * 在字典中查找key并返回找到的entry(会遍历 ht[0]和ht[1])
 * dict *d 被查找的字典
 * const void *key 要查找的key
 * return 返回 找到的entry
 */
dictEntry *dictFind(dict *d, const void *key);


/**
 * 查找并返回指定key对应的val
 * dict *d 被查找的字典
 * const void *key 要查找的key
 * return 返回 相应key对应的val
 */
void *dictFetchValue(dict *d, const void *key);


/**
 * 根据dict生成该字典的指纹信息
 * dict *d 生成的字典
 * return 返回 生成的指纹信息
 */
long long dictFingerprint(dict *d);


/**
 * 创建字典迭代器
 * dict *d 字典
 * return 返回 字典迭代器结构
 */
dictIterator *dictGetIterator(dict *d);


/**
 * 创建安全字典迭代器
 * dict *d 字典
 * return 返回 创建安全字典迭代器
 */
dictIterator *dictGetSafeIterator(dict *d);


/**
 * 根据迭代器结构对字典进行迭代,获取迭代器指向的当前entry结构(安全迭代将字典的iterators++结束的时候在减去,非安全则设置字典的指纹信息)
 * dictIterator *iter 字典迭代器
 * return 返回当前dictEntry结构
 */
dictEntry *dictNext(dictIterator *iter);


/**
 * 释放字典迭代器对象
 * dictIterator *iter 字典迭代器
 * return void
 */
void dictReleaseIterator(dictIterator *iter);


/**
 * 根据字典随机获取一个key
 * dict *d 字典
 * return 随机返回一个 entry
 */
dictEntry *dictGetRandomKey(dict *d);


/**
 * 遍历字典每个元素,使用  Pieter Noordhuis 的一个算法
 * dict *d 字典
 * unsigned long v 游标值
 * dictScanFunction *fn 处理每个元素的回调函数
 * void *privdata 处理每个元素的回调函数的值
 * return 返回新的游标值
 */
unsigned long dictScan(dict *d, unsigned long v, dictScanFunction *fn, void *privdata);


/**
 * 判断字典是否需要进行扩展操作
 * dict *d 需要判断的字典
 * return 返回状态
 */
static int _dictExpandIfNeeded(dict *d);


/**
 * 根据当前节点数量,计算hashtable扩展桶的数量,最大扩展桶的数量为 LONG_MAX 最小为 DICT_HT_INITIAL_SIZE,设置桶的个数为2的N次方大于节点数的最小值
 * unsigned long size 当前节点数
 * return 返回新计算的桶的大小
 */
static unsigned long _dictNextPower(unsigned long size);


/**
 * 查找指定key存在于哪个桶里
 * dict *d 需要判断的字典
 * void *key 需要查找的key
 * return 返回 桶的索引
 */
static int _dictKeyIndex(dict *d, const void *key);


/**
 * 将字典清空重置
 * dict *d 需要清空的字典
 * void(callback)(void*) 
 * return 返回 桶的索引
 */
void dictEmpty(dict *d, void(callback)(void*));


测试方法和代码:  

为了减少依赖,需要稍微修改一点点代码来完成测试,单独运行dict.c

删除如下代码:

#include "redisassert.h"

在删除的代码出加入以下宏定义:

#define assert(c) (c)

在页面底部加入如下main的测试代码:

//定义一组字典回调函数
unsigned int test_hash(const void *key) {
    return dictGenHashFunction(key, strlen((char *)key));
}
/*
void *test_keyDup(void *privdata, const void *key);
void *test_valDup(void *privdata, const void *obj);
int test_keyCompare(void *privdata, const void *key1, const void *key2);
void test_keyDestructor(void *privdata, void *key);
void test_valDestructor(void *privdata, void *obj);
*/

#define htLengthOut(info, d) ( \
printf("%s: ht[0].size:%d\tht[1].size:%d\tht[0].used:%d\tht[1].used:%d\n", (info), (d)->ht[0].size, (d)->ht[1].size, (d)->ht[0].used, (d)->ht[1].used)\
)
int main (void) {
    dict *d;
    dictEntry *de; 
    dictType type = {
        test_hash,
        NULL,
        NULL,
        NULL,
        NULL 
    };   
    dictIterator *di; 
    d = dictCreate(&type, NULL);
    htLengthOut("  empty dict", d);
    //向字典中加入元素,并触发rehash进行扩展
    dictAdd(d, "logbird", "123234123");
    dictAdd(d, "logbird2", "23434123");
    dictAdd(d, "logbird3", "123452453");
    dictAdd(d, "logbird4", "1345234523");
    dictAdd(d, "logbird5", "1457623");
    dictAdd(d, "logbird6", "12345234523");
    htLengthOut("start rehash", d);
    //进行5毫秒的rehash处理
    dictRehashMilliseconds(d, 5);
    htLengthOut("after rehash", d);
    //随机获取一条数据
    srand(timeInMilliseconds());
    de = dictGetRandomKey(d);
    printf("Random KEY: %s, VAL: %s\n", dictGetKey(de), dictGetVal(de));
    //获取某个key的val
    printf("KEY: 'logbird' VALUE: %s\n", (char *)dictFetchValue(d, "logbird"));
    //删除一个key
    dictDeleteNoFree(d, "logbird");
    htLengthOut("one key removed", d);
    //遍历字典所有数据
    di = dictGetIterator(d);
    printf("---------------------------Iterator Start----------------------\n");
    while ((de = dictNext(di))) {
        do { 
            printf("KEY: %s VALUE: %s\n", dictGetKey(de), dictGetVal(de));
        } while((de = de->next));
    }
    dictReleaseIterator(di);

    //释放字典
    dictRelease(d);
}

最后执行以下代码进行编译执行:

gcc zmalloc.c sds.c dict.c
./a.out


你可能感兴趣的:(redis,hash,Hashtable,dict,字典,hash算法,哈希算法,redis源码)