redis源码hash表的解析(赏心悦目的代码)

    Redis是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。

Redis的好多方案都是可以拿出来应用到具体的工程中.

    Hash表就是很不错的实现.主要在Dict.h Dict.c这个文件中.

其中函数:

/* API */
static unsigned int dictGenHashFunction(const unsigned char *buf, int len);
static dict *dictCreate(dictType *type, void *privDataPtr);
static int dictExpand(dict *ht, unsigned long size);
static int dictAdd(dict *ht, void *key, void *val);
static int dictReplace(dict *ht, void *key, void *val);
static int dictDelete(dict *ht, const void *key);
static void dictRelease(dict *ht);
static dictEntry * dictFind(dict *ht, const void *key);
static dictIterator *dictGetIterator(dict *ht);
static dictEntry *dictNext(dictIterator *iter);

static void dictReleaseIterator(dictIterator *iter);

使用步骤大概如下,根据Redis中的使用进行举例:

ac->sub.channels = dictCreate(&callbackDict,NULL);//创建hash表.

dict *callbacks = ac->sub.channels;

de = dictFind(callbacks,sname);//根据关键字查找value
if (de != NULL) {
   memcpy(dstcb,dictGetEntryVal(de),sizeof(*dstcb));//获取value
   /* If this is an unsubscribe message, remove it. */
   if (strcasecmp(stype+pvariant,"unsubscribe") == 0) {
         dictDelete(callbacks,sname);                            //删除该key-value键值对
   /* If this was the last unsubscribe message, revert to
   * non-subscribe mode. */
   assert(reply->element[2]->type == REDIS_REPLY_INTEGER);
   if (reply->element[2]->integer == 0)
          c->flags &= ~REDIS_SUBSCRIBED;
   }
   }

ret = dictReplace(ac->sub.channels,sname,&cb);//添加一个新的key-value键值对,如果已经存在,释放旧的,添加新的.


接下来关注一下hash表的一些结构体定义.

typedef struct dictEntry {
    void *key;
    void *val;
    struct dictEntry *next;

} dictEntry;


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;


typedef struct dict {
    dictEntry **table;
    dictType *type;
    unsigned long size;
    unsigned long sizemask;
    unsigned long used;
    void *privdata;

} dict;

然后是create函数:

static void _dictReset(dict *ht) {
    ht->table = NULL;
    ht->size = 0;
    ht->sizemask = 0;
    ht->used = 0;
}
/* Create a new hash table */
static dict *dictCreate(dictType *type, void *privDataPtr) {
    dict *ht = malloc(sizeof(*ht));
    _dictInit(ht,type,privDataPtr);
    return ht;
}
/* Initialize the hash table */
static int _dictInit(dict *ht, dictType *type, void *privDataPtr) {
    _dictReset(ht);
    ht->type = type;
    ht->privdata = privDataPtr;
    return DICT_OK;
}

hash表就创建成功了.回掉函数就可以根据实际情况来写回掉函数.redis的hash函数采用的是常见的hash算法,即:

static unsigned int dictGenHashFunction(const unsigned char *buf, int len) {
    unsigned int hash = 5381;
    while (len--)
        hash = ((hash << 5) + hash) + (*buf++);
/* hash * 33 + c */
    return hash;

}

然后看一下addhash函数:

/* Add an element to the target hash table */
static int dictAdd(dict *ht, void *key, void *val) {
    int index;
    dictEntry *entry;//节点
    /* Get the index of the new element, or -1 if
     * the element already exists. */
    if ((index = _dictKeyIndex(ht, key)) == -1)
        return DICT_ERR;
    /* Allocates the memory and stores key */
    entry = malloc(sizeof(*entry));//节点分配内存
    entry->next = ht->table[index];//哈希表新加一个节点.
    ht->table[index] = entry;
    /* Set the hash entry fields. */
    dictSetHashKey(ht, entry, key);//生成节点里的key值
    dictSetHashVal(ht, entry, val);//生成节点里的value值
    ht->used++;//哈希表的数量加一
    return DICT_OK;

}

首先看一下函数dictKeyIndex,

static int _dictKeyIndex(dict *ht, const void *key) {
    unsigned int h;
    dictEntry *he;
    /* Expand the hashtable if needed */
    if (_dictExpandIfNeeded(ht) == DICT_ERR)
        return -1;
    /* Compute the key hash value */
    h = dictHashKey(ht, key) & ht->sizemask;    //调用hash算法.根据key计算得到索引index.返回索引值.
    /* Search if this slot does not already contain the given key */
    he = ht->table[h];
    while(he) {
        if (dictCompareHashKeys(ht, key, he->key))
            return -1;
        he = he->next;
    }
    return h;
}













  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值