示例#1
0
/* Returns the index of a free slot that can be populated with
 * an hash entry for the given 'key'.
 * If the key already exists, -1 is returned.
 *
 * Note that if we are in the process of rehashing the hash table, the
 * index is always returned in the context of the second (new) hash table. */
static int _dictKeyIndex(dict *d, const void *key)
{
    unsigned int h, idx, table;
    dictEntry *he;

    /* Expand the hash table if needed */
    //在添加之前检查是否需要扩展
    if (_dictExpandIfNeeded(d) == DICT_ERR)
        return -1;
    /* Compute the key hash value */
    //得到对应的bucket索引值
    h = dictHashKey(d, key);
    //这里之所以需要遍历两个哈希表,是因为有rehash的需求
    //必须保证在字典中key是唯一的,并且是不变的
    for (table = 0; table <= 1; table++) {
        idx = h & d->ht[table].sizemask;
        /* Search if this slot does not already contain the given key */
        he = d->ht[table].table[idx];
        //如果这个bucket中已经存在相同的key,直接返回错误
        while(he) {
            if (dictCompareKeys(d, key, he->key))
                return -1;
            he = he->next;
        }
        //如果当前未执行rehash操作(-1),说明所有的key-value都存放在ht[0]中
        //所以这里避免了第二次的遍历
        if (!dictIsRehashing(d)) break;
    }
    return idx;
}
示例#2
0
文件: dict.c 项目: snoplus/orca
/* Search and remove an element */
static int dictDelete(dict *ht, const void *key) {
    unsigned int h;
    dictEntry *de, *prevde;

    if (ht->size == 0)
        return DICT_ERR;
    h = dictHashKey(ht, key) & ht->sizemask;
    de = ht->table[h];

    prevde = NULL;
    while(de) {
        if (dictCompareHashKeys(ht,key,de->key)) {
            /* Unlink the element from the list */
            if (prevde)
                prevde->next = de->next;
            else
                ht->table[h] = de->next;

            dictFreeEntryKey(ht,de);
            dictFreeEntryVal(ht,de);
            free(de);
            ht->used--;
            return DICT_OK;
        }
        prevde = de;
        de = de->next;
    }
    return DICT_ERR; /* not found */
}
示例#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
/* 字典(的哈希表) rehash 函数
 *
 * Args:
 *  d
 *  n 要执行 rehash 的元素数量
 *
 * Returns:
 *  0 所有元素 rehash 完毕
 *  1 还有元素没有 rehash
 */
int dictRehash(dict *d, int n) {
    if (!dictIsRehashing(d))
        return 0;

    while(n--) {
        dictEntry *de, *nextde;

        // 0 号哈希表的所有元素 rehash 完毕?
        if (d->ht[0].used == 0) {
            zfree(d->ht[0].table);  // 替换 1 号为 0 号
            d->ht[0] = d->ht[1];

            _dictReset(&d->ht[1]);  // 重置 1 号哈希表

            d->rehashidx = -1;      // 重置 rehash flag

            return 0;
        }

        /* Note that rehashidx can't overflow as we are sure there are more
         * elements because ht[0].used != 0 */
        assert(d->ht[0].size > (unsigned)d->rehashidx);

        // 略过所有空链
        while(d->ht[0].table[d->rehashidx] == NULL)
            d->rehashidx++;

        // 指向链头
        de = d->ht[0].table[d->rehashidx];
        // 将链表内的所有节点移动到 1 号哈希表
        while(de) {
            unsigned int h;

            nextde = de->next;

            // 计算新的地址(用于 1 号哈希表)
            h = dictHashKey(d, de->key) & d->ht[1].sizemask;

            de->next = d->ht[1].table[h];   // 更新 next 指针
            d->ht[1].table[h] = de;         // 移动
            d->ht[0].used--;                // 更新 0 号表计算器
            d->ht[1].used++;                // 更新 1 号表计算器

            de = nextde;
        }

        d->ht[0].table[d->rehashidx] = NULL;    // 清空链头
        d->rehashidx++; // 更新索引
    }

    return 1;
}
示例#5
0
文件: dict.c 项目: snoplus/orca
static dictEntry *dictFind(dict *ht, const void *key) {
    dictEntry *he;
    unsigned int h;

    if (ht->size == 0) return NULL;
    h = dictHashKey(ht, key) & ht->sizemask;
    he = ht->table[h];
    while(he) {
        if (dictCompareHashKeys(ht, key, he->key))
            return he;
        he = he->next;
    }
    return NULL;
}
示例#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
//执行一次rehash操作,一般在检查到该字典的rehash标记被设置之后调用该函数
//这里的参数n表示至少执行多少bucket的移动(reahash),每次移动从rehashidx开始
int dictRehash(dict *d, int n) {
    if (!dictIsRehashing(d)) return 0;

    while(n--) {
        dictEntry *de, *nextde;

        /* Check if we already rehashed the whole table... */
        //如果已经全部移动了,说明这一次rehash操作执行完成了
        //释放ht[0],然后重新将移动之后的ht[1]替换,这样保证不再rehash操作
        //的时候都是使用ht[0]保存新添加的元素
        if (d->ht[0].used == 0) {
            zfree(d->ht[0].table);
            //复制&重置
            d->ht[0] = d->ht[1];
            _dictReset(&d->ht[1]);
            d->rehashidx = -1;
            return 0;
        }

        /* Note that rehashidx can't overflow as we are sure there are more
         * elements because ht[0].used != 0 */
        //在rehash过程中,rehashidx保存的是上一次移动的bucket的下标
        //这样在下一次移动的时候从rehashidx开始
        assert(d->ht[0].size > (unsigned)d->rehashidx);
        //跳过没有任何元素的bucket
        while(d->ht[0].table[d->rehashidx] == NULL) d->rehashidx++;
        de = d->ht[0].table[d->rehashidx];
        /* Move all the keys in this bucket from the old to the new hash HT */
        //将旧哈希表ht[0]中的每一个bucket上的每一个entry都移动到ht[1]上
        //因为同一个entry在两个表定位的bucket不同,所以需要重新hash,然后添加到bucket
        //中entry链表的表头
        while(de) {
            unsigned int h;

            nextde = de->next;
            /* Get the index in the new hash table */
            h = dictHashKey(d, de->key) & d->ht[1].sizemask;
            de->next = d->ht[1].table[h];
            d->ht[1].table[h] = de;
            d->ht[0].used--;
            d->ht[1].used++;
            de = nextde;
        }
        d->ht[0].table[d->rehashidx] = NULL;
        d->rehashidx++;
    }
    return 1;
}
示例#8
0
/* Expand or create the hashtable */
static int dictExpand(dict *ht, unsigned long size)
{
    dict n; /* the new hashtable */
    unsigned long realsize = _dictNextPower(size), i;

    /* the size is invalid if it is smaller than the number of
     * elements already inside the hashtable */
    if (ht->used > size)
        return DICT_ERR;

    _dictInit(&n, ht->type, ht->privdata);
    n.size = realsize;
    n.sizemask = realsize-1;
    n.table = calloc(realsize,sizeof(dictEntry*));

    /* Copy all the elements from the old to the new table:
     * note that if the old hash table is empty ht->size is zero,
     * so dictExpand just creates an hash table. */
    n.used = ht->used;
    for (i = 0; i < ht->size && ht->used > 0; i++) {
        dictEntry *he, *nextHe;

        if (ht->table[i] == NULL) continue;

        /* For each hash entry on this slot... */
        he = ht->table[i];
        while(he) {
            unsigned int h;

            nextHe = he->next;
            /* Get the new element index */
            h = dictHashKey(ht, he->key) & n.sizemask;
            he->next = n.table[h];
            n.table[h] = he;
            ht->used--;
            /* Pass to the next element */
            he = nextHe;
        }
    }
    assert(ht->used == 0);
    free(ht->table);

    /* Remap the new hashtable in the old */
    *ht = n;
    return DICT_OK;
}
示例#9
0
文件: dict.c 项目: snoplus/orca
/* Returns the index of a free slot that can be populated with
 * an hash entry for the given 'key'.
 * If the key already exists, -1 is returned. */
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;
    /* 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;
}
示例#10
0
文件: dict.c 项目: AMCScarface/misc
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;
}
示例#11
0
/* Performs N steps of incremental rehashing. Returns 1 if there are still
 * keys to move from the old to the new hash table, otherwise 0 is returned.
 * Note that a rehashing step consists in moving a bucket (that may have more
 * thank one key as we use chaining) from the old to the new hash table. */
int dictRehash(dict *d, int n) {
    if (!dictIsRehashing(d)) return 0;

    while(n--) {
        dictEntry *de, *nextde;

        /* Check if we already rehashed the whole table... */
        if (d->ht[0].used == 0) {
            free(d->ht[0].table);
            d->ht[0] = d->ht[1];
            _dictReset(&d->ht[1]);
            d->rehashidx = -1;
            return 0;
        }

        /* Note that rehashidx can't overflow as we are sure there are more
         * elements because ht[0].used != 0 */
        assert(d->ht[0].size > (unsigned)d->rehashidx);
        while(d->ht[0].table[d->rehashidx] == NULL) d->rehashidx++;
        de = d->ht[0].table[d->rehashidx];
        /* Move all the keys in this bucket from the old to the new hash HT */
        while(de) {
            unsigned int h;

            nextde = de->next;
            /* Get the index in the new hash table */
            h = dictHashKey(d, de->key) & d->ht[1].sizemask;
            de->next = d->ht[1].table[h];
            d->ht[1].table[h] = de;
            d->ht[0].used--;
            d->ht[1].used++;
            de = nextde;
        }
        d->ht[0].table[d->rehashidx] = NULL;
        d->rehashidx++;
    }
    return 1;
}
示例#12
0
文件: dict.c 项目: AMCScarface/misc
/* Returns the index of a free slot that can be populated with
 * an hash entry for the given 'key'.
 * If the key already exists, -1 is returned.
 *
 * Note that if we are in the process of rehashing the hash table, the
 * index is always returned in the context of the second (new) hash table. */
static int _dictKeyIndex(dict *d, const void *key)
{
    unsigned int h, idx, table;
    dictEntry *he;

    /* Expand the hashtable if needed */
    if (_dictExpandIfNeeded(d) == DICT_ERR)
        return -1;
    /* Compute the key hash value */
    h = dictHashKey(d, key);
    for (table = 0; table <= 1; table++) {
        idx = h & d->ht[table].sizemask;
        /* Search if this slot does not already contain the given key */
        he = d->ht[table].table[idx];
        while(he) {
            if (dictCompareHashKeys(d, key, he->key))
                return -1;
            he = he->next;
        }
        if (!dictIsRehashing(d)) break;
    }
    return idx;
}