redis 代码--hash/迭代

ypedef struct dictEntry {
    void *key;
    union {
        void *val;
        uint64_t u64;
        int64_t s64;
    } v;
    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;

/* 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;//桶掩码。 size-1
    unsigned long used;//table中元素总个数
} dictht;

typedef struct dict {
    dictType *type;
    void *privdata;
    dictht ht[2];//ht[0]是供正常使用过的。 ht[1]是供rehash用的。 rehash完之后会将ht[0] = ht[1] && reset(ht[1])
    int rehashidx; /* rehashing not in progress if rehashidx == -1 */
    int iterators; /* number of iterators currently running 只有iterator->safe==1时才会自增或者自减,普通的iterator不会影响该值*/
} dict;



核心函数:

rehashidx 是-1时表示没有在rehash中。 否则rehashidx就是正在rehash 的桶下标。

dictExpand:扩大hashtable的大小; 这里指桶的大小、 而不是指能够存放的总大小。

dictRehash(dict *d, int n):逐个桶的rehash。n仅表示本次函数调用期望处理的有效桶个数。返回0表示整个hash完。

_dictKeyIndex:查找。分别在ht[0]与ht[1]中查找该key,找到则返回-1; 未找到时若在rehash则返回在ht[1]中的桶下标,否则返回ht[0]中的下标。

key的桶下标计算方式是: dictHashKey(key) & (size - 1)。 其中size总是2倍的方式扩大。 此种计算方式得到的桶下标必定


查找:先在ht[0]中找, 未找到且在rehashing中,则继续在ht[1]中找。 返回找到的桶下标,否则返回-1.

插入:如果查找已成功, 则返回-1、不允许插入; 否则如果在rehash中,则插入到ht[1]中;否则插入到ht[0]中。 插入在桶的头部

在unsafe的迭代过程中(iterators > 0)时, 不允许继续rehash。

迭代过程中允许插入和删除。 插入的/删除的可能不会被遍历到。 但不会引起错误, 只要迭代器当前的元素没被删除即可。


删除时,先查找, 然后从链表总删掉。


typedef struct dictIterator {
    dict *d;
    int table; //d的ht的索引。 0或者1
    int index; //d->ht[table]的桶下标
    int safe;  //为1时, 会影响到d->iterators
    dictEntry *entry, *nextEntry;
    long long fingerprint; /* unsafe iterator fingerprint for misuse detection */
} dictIterator;
当未设置safe时, 就必须保证fingerprint在release时相同, 就是说d未被增删元素、未被rehash
dictEntry *dictNext(dictIterator *iter)
{
    while (1) {
        if (iter->entry == NULL) {
            dictht *ht = &iter->d->ht[iter->table];
            if (iter->index == -1 && iter->table == 0) {刚被初始化、第一次调用时
                if (iter->safe)
                    iter->d->iterators++;
                else
                    iter->fingerprint = dictFingerprint(iter->d);
            }
            iter->index++;//该bucket的entry为null,因此继续到下一个bucket。
            if (iter->index >= (signed) ht->size) {//桶下标溢出, 则到ht[1]中从bucket 0开始
                if (dictIsRehashing(iter->d) && iter->table == 0) {
                    iter->table++;
                    iter->index = 0;
                    ht = &iter->d->ht[1];
                } else {
                    break;
                }
            }
            iter->entry = ht->table[iter->index];
        } else {
            iter->entry = iter->nextEntry;
        }
        if (iter->entry) {
            /* We need to save the 'next' here, the iterator user
             * may delete the entry we are returning. */
            iter->nextEntry = iter->entry->next;
            return iter->entry;
        }
    }
    return NULL;
}




你可能感兴趣的:(redis 代码--hash/迭代)