赞
踩
迭代器,在很多的高级语言都会有该实现,其作用就是实现对容器的遍历
- typedef struct dictIterator {
- dict *d;
- long index;
- int table, safe; // safe 是否是安全的迭代器
- dictEntry *entry, *nextEntry;
- /* unsafe iterator fingerprint for misuse detection. */
- long long fingerprint;
- } dictIterator;
通过safe来区分 safe=1为安全迭代器
entry与nextEntry两个指针分别指向Hash冲突后的两个父子节点。 如果在安全模式下, 删除了entry节点, nextEntry字段可以保证后续迭代数据不丢失
普通的迭代器:只遍历数据
安全的迭代器:遍历的同时删除数据
- dictIterator *dictGetIterator(dict *d)
- {
- dictIterator *iter = zmalloc(sizeof(*iter));
-
- iter->d = d;
- iter->table = 0;
- iter->index = -1;
- iter->safe = 0;
- iter->entry = NULL;
- iter->nextEntry = NULL;
- return iter;
- }
不允许对数据进行操作,因为遍历迭代器时会获取dictGetIterator 会获取dictFingerprint ,时整个字典的指纹,如果遍历完成有指纹发生变化,则会导致错误。
这时你可能会问,为啥不是单线程的吗,为什么遍历有可能被其他修改了呢?其实,如果你仔细看,我们对字典的任何插入,查找等操作,都会调用rehashstep,这就有可能导致了字典指纹的变化。
其实只是相对普通迭代器设置safe标志为1
- dictIterator *dictGetSafeIterator(dict *d) {
- dictIterator *i = dictGetIterator(d);
-
- i->safe = 1;
- return i;
- }
字典的增删改查操作会调用dictRehashStep函数进行渐进式rehash操作,但是我们看到
- static void _dictRehashStep(dict *d) {
- if (d->iterators == 0) dictRehash(d,1);
- }
其实,rehash的时候,会判断是不是在安全迭代器模式,如果是则不会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++;
- if (iter->index >= (long) ht->size) {
- 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;
- }

如果是安全模式:首次遍历iterators 会++ ,表示现在字典在安全遍历,会禁止了rehash
如果不是安全模式:首次则要记录字典的指纹信息。
字典指纹的获取:其实就是将字典转换为一个64位的数组,也可以理解是一种hash
- long long dictFingerprint(dict *d) {
- long long integers[6], hash = 0;
- int j;
-
- integers[0] = (long) d->ht[0].table;
- integers[1] = d->ht[0].size;
- integers[2] = d->ht[0].used;
- integers[3] = (long) d->ht[1].table;
- integers[4] = d->ht[1].size;
- integers[5] = d->ht[1].used;
-
- /* We hash N integers by summing every successive integer with the integer
- * hashing of the previous sum. Basically:
- *
- * Result = hash(hash(hash(int1)+int2)+int3) ...
- *
- * This way the same set of integers in a different order will (likely) hash
- * to a different number. */
- for (j = 0; j < 6; j++) {
- hash += integers[j];
- /* For the hashing step we use Tomas Wang's 64 bit integer hash. */
- hash = (~hash) + (hash << 21); // hash = (hash << 21) - hash - 1;
- hash = hash ^ (hash >> 24);
- hash = (hash + (hash << 3)) + (hash << 8); // hash * 265
- hash = hash ^ (hash >> 14);
- hash = (hash + (hash << 2)) + (hash << 4); // hash * 21
- hash = hash ^ (hash >> 28);
- hash = hash + (hash << 31);
- }
- return hash;
- }

- void dictReleaseIterator(dictIterator *iter)
- {
- if (!(iter->index == -1 && iter->table == 0)) {
- if (iter->safe)
- iter->d->iterators--;
- else
- assert(iter->fingerprint == dictFingerprint(iter->d));
- }
- zfree(iter);
- }
释放迭代器要将安全模式下iterators++的值减回去,如果不是安全模式,则要判断字典是不是遍历的过程中被修改,修改则触发断言。
最后释放迭代器。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。