Пример #1
0
/* Add an element to the target hash table */
int dictAdd(dict *d, void *key, void *val)
{
    int index;
    dictEntry *entry;
    dictht *ht;

    if (dictIsRehashing(d)) _dictRehashStep(d);

    /* Get the index of the new element, or -1 if
     * the element already exists. */
    if ((index = _dictKeyIndex(d, key)) == -1)
        return DICT_ERR;

    /* Allocates the memory and stores key */
    ht = dictIsRehashing(d) ? &d->ht[1] : &d->ht[0];
    entry = zmalloc(sizeof(*entry));
    entry->next = ht->table[index];
    ht->table[index] = entry;
    ht->used++;

    /* Set the hash entry fields. */
    dictSetHashKey(d, entry, key);
    dictSetHashVal(d, entry, val);
    return DICT_OK;
}
Пример #2
0
//这个函数也可以作为向外部提供的API使用,外部用户可以添加一个键值不为void*类型的值
//它向字典中添加一个key值并且返回新创建的 entry对象,这个对象交给调用者操作
dictEntry *dictAddRaw(dict *d, void *key)
{
    int index;
    dictEntry *entry;
    dictht *ht;

    if (dictIsRehashing(d)) _dictRehashStep(d);

    /* Get the index of the new element, or -1 if
     * the element already exists. */
    //获取对应key的bucket索引
    if ((index = _dictKeyIndex(d, key)) == -1)
        return NULL;

    /* Allocate the memory and store the new entry */
    //如果当前在执行rehash,说明需要将ht[0]上的entry转移到ht[1]上,并且尚未执行结束
    //这时候就需要加入到ht[1]中,否则加入到ht[0]中
    ht = dictIsRehashing(d) ? &d->ht[1] : &d->ht[0];
    entry = zmalloc(sizeof(*entry));
    //加入到链表的表头
    entry->next = ht->table[index];
    ht->table[index] = entry;
    ht->used++;

    /* Set the hash entry fields. */
    //最后设置该项的key
    dictSetKey(d, entry, key);
    return entry;
}
Пример #3
0
/* 从字典中查找给定 key 
 *
 * 查找过程是典型的 separate chaining find 操作
 * 具体参见:http://en.wikipedia.org/wiki/Hash_table#Separate_chaining
 */
dictEntry *dictFind(dict *d, const void *key)
{
    dictEntry *he;
    unsigned int h, idx, table;

    // 哈希表为空,直接返回 NULL
    if (d->ht[0].size == 0) return NULL; /* We don't have a table at all */

    // 检查字典(的哈希表)能否执行 rehash 操作
    // 如果可以的话,执行平摊 rehash 操作
    if (dictIsRehashing(d)) _dictRehashStep(d);

    // 查找 
    h = dictHashKey(d, key);                     // 计算哈希值
    for (table = 0; table <= 1; table++) {       // 遍历两个哈希表
        idx = h & d->ht[table].sizemask;         // 计算地址
        he = d->ht[table].table[idx];            // he 指向链表头
        while(he) {                              // 遍历链查找 key
            if (dictCompareKeys(d, key, he->key))
                return he;
            he = he->next;
        }

        if (!dictIsRehashing(d)) return NULL;
    }

    return NULL;
}
Пример #4
0
/* 添加元素的底层实现函数(由 dictAdd 调用)
 * 
 * 新元素的添加操作被分为两步:
 * 1) 创建节点并设置节点的 key ,然后返回节点
 * 2) 设置节点的值
 * 这个函数执行第一步,第二步由函数 dictSetVal 进行
 * 
 * Args:
 *  d 字典
 *  key 新节点的关键字
 *
 * Returns:
 *  NULL 关键字已经存在
 *  entry 设置了关键字的新节点,返回给调用者进行进一步的处理
 */
dictEntry *dictAddRaw(dict *d, void *key)
{
    int index;
    dictEntry *entry;
    dictht *ht;

    // 检查字典(的哈希表)能否执行 rehash 操作
    // 如果可以的话,执行平摊 rehash 操作
    if (dictIsRehashing(d)) _dictRehashStep(d);

    // 计算 key 的 index 值
    // 如果 key 已经存在,_dictKeyIndex 返回 -1 
    if ((index = _dictKeyIndex(d, key)) == -1)
        return NULL;

    // 如果字典正在进行 rehash ,那么将新元素添加到 1 号哈希表,
    // 否则,使用 0 号哈希表
    ht = dictIsRehashing(d) ? &d->ht[1] : &d->ht[0];

    entry = zmalloc(sizeof(*entry));    // 为新节点分配内存
    entry->next = ht->table[index];     // 调整节点的 next 指针
    ht->table[index] = entry;           // 然后将新节点设为链头
    ht->used++;                         // 更新正在使用的节点数量

    // 设置节点的 key 域
    dictSetKey(d, entry, key);

    return entry;   // 返回新节点
}
Пример #5
0
/* Low level add. This function adds the entry but instead of setting
 * a value returns the dictEntry structure to the user, that will make
 * sure to fill the value field as he wishes.
 *
 * This function is also directly exposed to the user API to be called
 * mainly in order to store non-pointers inside the hash value, example:
 *
 * entry = dictAddRaw(dict,mykey);
 * if (entry != NULL) dictSetSignedIntegerVal(entry,1000);
 *
 * Return values:
 *
 * If key already exists NULL is returned.
 * If key was added, the hash entry is returned to be manipulated by the caller.
 */
dictEntry *dictAddRaw(dict *d, void *key)
{
    int index;
    dictEntry *entry;
    dictht *ht;

    if (dictIsRehashing(d)) _dictRehashStep(d);

    /* Get the index of the new element, or -1 if
     * the element already exists. */
    if ((index = _dictKeyIndex(d, key)) == -1)
        return NULL;

    /* Allocate the memory and store the new entry */
    ht = dictIsRehashing(d) ? &d->ht[1] : &d->ht[0];
    entry = zmalloc(sizeof(*entry));
    entry->next = ht->table[index];
    ht->table[index] = entry;
    ht->used++;

    /* Set the hash entry fields. */
    //使用dictType中的keyDup函数
    dictSetKey(d, entry, key);
    return entry;
}
Пример #6
0
/* 删除指定元素的底层实现代码
 *
 * Args:
 *  d
 *  key
 *  nofree 指示是否释放被删除元素的键和值
 *
 * Returns:
 *  DICT_ERR 字典为空,删除失败
 *  DICT_OK 删除成功
 */
static int dictGenericDelete(dict *d, const void *key, int nofree)
{
    unsigned int h, idx;
    dictEntry *he, *prevHe;
    int table;

    // 字典为空,删除失败
    if (d->ht[0].size == 0)
        return DICT_ERR;

    // 平摊 rehash
    if (dictIsRehashing(d))
        _dictRehashStep(d);

    // 哈希值
    h = dictHashKey(d, key);

    // 遍历
    for (table = 0; table <= 1; table++) {
        idx = h & d->ht[table].sizemask;    // 地址索引
        he = d->ht[table].table[idx];       // 表头节点
        prevHe = NULL;
        while(he) {
            if (dictCompareKeys(d, key, he->key)) {
                /* Unlink the element from the list */
                if (prevHe)
                    prevHe->next = he->next;
                else
                    d->ht[table].table[idx] = he->next;

                if (!nofree) {
                    dictFreeKey(d, he);
                    dictFreeVal(d, he);
                }

                zfree(he);
                d->ht[table].used--;

                return DICT_OK;
            }
            // 推进指针
            prevHe = he;
            he = he->next;
        }
        if (!dictIsRehashing(d)) break;
    }

    return DICT_ERR; /* not found */
}
Пример #7
0
dictEntry *dictFind(dict *d, const void *key)
{
    dictEntry *he;
    unsigned int h, idx, table;

    if (d->ht[0].size == 0) return NULL; /* We don't have a table at all */
    if (dictIsRehashing(d)) _dictRehashStep(d);
    h = dictHashKey(d, key);
    for (table = 0; table <= 1; table++) {
        idx = h & d->ht[table].sizemask;
        he = d->ht[table].table[idx];
        while(he) {
            if (dictCompareHashKeys(d, key, he->key))
                return he;
            he = he->next;
        }
        if (!dictIsRehashing(d)) return NULL;
    }
    return NULL;
}
Пример #8
0
/* Return a random entry from the hash table. Useful to
 * implement randomized algorithms */
dictEntry *dictGetRandomKey(dict *d)
{
    dictEntry *he, *orighe;
    unsigned int h;
    int listlen, listele;

    if (dictSize(d) == 0) return NULL;
    //该操作也会引起rehash,step by step...
    if (dictIsRehashing(d)) _dictRehashStep(d);
    if (dictIsRehashing(d)) {
        //如果正在执行rehash,则将两个哈希表都考虑在随机的方位内,找到bucket链表
        do {
            h = random() % (d->ht[0].size+d->ht[1].size);
            he = (h >= d->ht[0].size) ? d->ht[1].table[h - d->ht[0].size] :
                                      d->ht[0].table[h];
        } while(he == NULL);
    } else {
        //否则只从第一个哈希表中随机找到一个bucket
        do {
            h = random() & d->ht[0].sizemask;
            he = d->ht[0].table[h];
        } while(he == NULL);
    }

    /* Now we found a non empty bucket, but it is a linked
     * list and we need to get a random element from the list.
     * The only sane way to do so is counting the elements and
     * select a random index. */
    listlen = 0;
    orighe = he;
    //首先得到这个链表的长度,然后再随机的走k步...
    //这样最科学撒...
    while(he) {
        he = he->next;
        listlen++;
    }
    listele = random() % listlen;
    he = orighe;
    while(listele--) he = he->next;
    return he;
}
Пример #9
0
/* Return a random entry from the hash table. Useful to
 * implement randomized algorithms */
dictEntry *dictGetRandomKey(dict *d)
{
    dictEntry *he, *orighe;
    unsigned int h;
    int listlen, listele;

    if (dictSize(d) == 0) return NULL;
    if (dictIsRehashing(d)) _dictRehashStep(d);
    if (dictIsRehashing(d)) {
        do {
            h = random() % (d->ht[0].size+d->ht[1].size);
            he = (h >= d->ht[0].size) ? d->ht[1].table[h - d->ht[0].size] :
                                      d->ht[0].table[h];
        } while(he == NULL);
    } else {
        do {
            h = random() & d->ht[0].sizemask;
            he = d->ht[0].table[h];
        } while(he == NULL);
    }

    /* Now we found a non empty bucket, but it is a linked
     * list and we need to get a random element from the list.
     * The only sane way to do so is counting the elements and
     * select a random index. */
    listlen = 0;
    orighe = he;
    while(he) {
        he = he->next;
        listlen++;
    }

    listele = random() % listlen;
    he = orighe;
    while(listele--) he = he->next;
    return he;
}