/* 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; }
/* 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; }
/* 从字典中查找给定 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; }
/* 添加元素的底层实现函数(由 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; // 返回新节点 }
//这个函数也可以作为向外部提供的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; }
/* 删除指定元素的底层实现代码 * * 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 */ }
/* Expand or create the hashtable */ int dictExpand(dict *d, unsigned long size) { dictht n; /* the new hashtable */ unsigned long realsize = _dictNextPower(size); /* the size is invalid if it is smaller than the number of * elements already inside the hashtable */ if (dictIsRehashing(d) || d->ht[0].used > size) return DICT_ERR; /* Allocate the new hashtable and initialize all pointers to NULL */ n.size = realsize; n.sizemask = realsize-1; n.table = zcalloc(1, realsize*sizeof(dictEntry*)); n.used = 0; /* Is this the first initialization? If so it's not really a rehashing * we just set the first hash table so that it can accept keys. */ if (d->ht[0].table == NULL) { d->ht[0] = n; return DICT_OK; } /* Prepare a second hash table for incremental rehashing */ d->ht[1] = n; d->rehashidx = 0; return DICT_OK; }
dictEntry *dictNext(dictIterator *iter) { while (1) { if (iter->entry == NULL) { dictht *ht = &iter->d->ht[iter->table]; if (iter->safe && iter->index == -1 && iter->table == 0) iter->d->iterators++; iter->index++; if (iter->index >= (signed) 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; }
/************************************************************* * Function : RehashStep * Author : bulldozer.ma * Date : 2015-11-01 * Input : dict *pHeader * Output : N/A * Return : void * Other : N/A * Description : RehashStep **************************************************************/ static void RehashStep(dict *pHeader) { if (dictIsRehashing(pHeader)) { Rehash(pHeader,1); } }
/* 对字典进行扩展 * * 这个函数完成以下两个工作的其中之一: * 1) 如果字典的 0 号哈希表不存在,那么创建它 * 2) 如果字典的 0 号哈希表存在,那么创建字典的 1 号哈希表 * * 这个函数的作用,对于第一件任务来说,是创建字典(的哈希表)。 * 而对于第二个任务来说,则是扩展字典(的哈希表)。 */ int dictExpand(dict *d, unsigned long size) { // 一般调用函数已经进行了检查,为了安全起见再次对参数进行检查 if (dictIsRehashing(d) || d->ht[0].used > size) return DICT_ERR; // 计算哈希表的(真正)大小 unsigned long realsize = _dictNextPower(size); // 创建新哈希表 dictht n; n.size = realsize; n.sizemask = realsize-1; n.table = zcalloc(realsize*sizeof(dictEntry*)); n.used = 0; // 字典的 0 号哈希表是否已经初始化? // 如果没有的话,我们将新建哈希表作为字典的 0 号哈希表 if (d->ht[0].table == NULL) { d->ht[0] = n; } else { // 否则,将新建哈希表作为字典的 1 号哈希表,并将它用于 rehash d->ht[1] = n; d->rehashidx = 0; } return DICT_OK; }
//扩展字典,在检查到需要扩展的时候,这里包含了检测的过程 static int _dictExpandIfNeeded(dict *d) { /* Incremental rehashing already in progress. Return. */ //如果正在执行rehash操作,直接返回 if (dictIsRehashing(d)) return DICT_OK; /* If the hash table is empty expand it to the initial size. */ //第一次添加元素,执行扩展 if (d->ht[0].size == 0) return dictExpand(d, DICT_HT_INITIAL_SIZE); /* If we reached the 1:1 ratio, and we are allowed to resize the hash * table (global setting) or we should avoid it but the ratio between * elements/buckets is over the "safe" threshold, we resize doubling * the number of buckets. */ //如果设置了resize标记,那么在USED/BUCKET的比率大于1的时候就会执行扩展 //如果没有设置该标志,在该比率超过dict_force_resize_ratio的时候再进行扩展 if (d->ht[0].used >= d->ht[0].size && (dict_can_resize || d->ht[0].used/d->ht[0].size > dict_force_resize_ratio)) { //扩展的结果是bucket的数目增大一倍 return dictExpand(d, ((d->ht[0].size > d->ht[0].used) ? d->ht[0].size : d->ht[0].used)*2); } return DICT_OK; }
void dictPrintStats(dict *d) { _dictPrintStatsHt(&d->ht[0]); if (dictIsRehashing(d)) { printf("-- Rehashing into ht[1]:\n"); _dictPrintStatsHt(&d->ht[1]); } }
/* 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; }
//该函数会在真正创建哈希表或者扩展哈希表的时候被调用 int dictExpand(dict *d, unsigned long size) { dictht n; /* the new hash table */ //新的哈希表的bucket数目是大于当前used entry的数目的最小的2的指数 unsigned long realsize = _dictNextPower(size); /* the size is invalid if it is smaller than the number of * elements already inside the hash table */ //保证该字典未进行rehash,并且保证USED/BUCKETS的比率小于1 if (dictIsRehashing(d) || d->ht[0].used > size) return DICT_ERR; /* Allocate the new hash table and initialize all pointers to NULL */ //分配并初始化一个新的哈希表 n.size = realsize; n.sizemask = realsize-1; n.table = zcalloc(realsize*sizeof(dictEntry*)); n.used = 0; /* Is this the first initialization? If so it's not really a rehashing * we just set the first hash table so that it can accept keys. */ //既然不是在rehash状态中,那么当前使用的哈希表应该是ht[0],如果它为NULL //说明这是在第一次分配该哈希表,所以将它保存在ht[0]中 if (d->ht[0].table == NULL) { d->ht[0] = n; return DICT_OK; } /* Prepare a second hash table for incremental rehashing */ //否则将新分配的哈希表保存在ht[1]中,因为不在rehash,所以当前ht[1]为空 //并且标记rehash标志,在接下来的哈希表操作中会进行rehash操作 d->ht[1] = n; d->rehashidx = 0; return DICT_OK; }
/* Resize the table to the minimal size that contains all the elements, * but with the invariant of a USER/BUCKETS ratio near to <= 1 */ int dictResize(dict *d) { int minimal; if (!dict_can_resize || dictIsRehashing(d)) return DICT_ERR; minimal = d->ht[0].used; if (minimal < DICT_HT_INITIAL_SIZE) minimal = DICT_HT_INITIAL_SIZE; return dictExpand(d, minimal); }
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; }
/* 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; }
/* Expand the hash table if needed */ static int _dictExpandIfNeeded(dict *d) { /* If the hash table is empty expand it to the intial size, * if the table is "full" dobule its size. */ if (dictIsRehashing(d)) return DICT_OK; if (d->ht[0].size == 0) return dictExpand(d, DICT_HT_INITIAL_SIZE); if (d->ht[0].used >= d->ht[0].size && dict_can_resize) return dictExpand(d, ((d->ht[0].size > d->ht[0].used) ? d->ht[0].size : d->ht[0].used)*2); return DICT_OK; }
/* 字典(的哈希表) 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; }
/* Resize the table to the minimal size that contains all the elements, * but with the invariant of a USED/BUCKETS ratio near to <= 1 */ int dictResize(dict *d) { int minimal; //在未设置resize标记和rehash进行中的字典不能进行扩展 if (!dict_can_resize || dictIsRehashing(d)) return DICT_ERR; //扩展之后的bucket数目将大于当前哈希表中的entry的总数,这样可以使USED/BUCKETS的 //比率小于1,尽量达到O(1)查询的效率 minimal = d->ht[0].used; if (minimal < DICT_HT_INITIAL_SIZE) minimal = DICT_HT_INITIAL_SIZE; return dictExpand(d, minimal); }
/* 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; }
/************************************************************* * Function : dictShow * Author : bulldozer.ma * Date : 2015-11-01 * Input : dict *pHeader * Output : N/A * Return : int * Other : N/A * Description : show all **************************************************************/ int dictShow(dict *pHeader) { int iRet = DICT_ERROR; if (NULL == pHeader) { return DICT_ERROR; } iRet = ShowValue(pHeader->ht[0]); if (dictIsRehashing(pHeader)) { iRet = ShowValue(pHeader->ht[1]); } return iRet; }
/************************************************************* * Function : ExpandIfNeeded * Author : bulldozer.ma * Date : 2015-11-01 * Input : dict *pHeader * Output : N/A * Return : int * Other : N/A * Description : ExpandIfNeeded **************************************************************/ static int ExpandIfNeeded(dict *pHeader) { if (NULL == pHeader || dictIsRehashing(pHeader)) { return DICT_ERROR; } unsigned int uiUsed = 0, uiSize = 0; uiSize = pHeader->ht[0]->size; uiUsed = pHeader->ht[0]->used; if (uiUsed > uiSize && 1 <= uiUsed / uiSize) { return dictExpand(pHeader, pHeader->ht[1]->size); } return DICT_ERROR; }
//执行一次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; }
void lrw_dict_put(LRWDict *d, const Term *key, const void *value) { dictEntry *entry = dictFind(d->dict, key); // pstring *t = term_to_s(key); // printf("adding %.*s to size %d\n", t->len, t->val,dictSize(d->dict)); if(entry == NULL) { if(dictSize(d->dict) >= d->capacity) { _truncate(d); } entry = dictAddRaw(d->dict, (void *) key); if(!entry && dictIsRehashing(d->dict)) { entry = dictFind(d->dict, key); } assert(entry); } dictSetVal(d->dict, entry, (void *) value); _bump(d, entry->key); }
/* 迭代器的推进函数 */ dictEntry *dictNext(dictIterator *iter) { while (1) { // 如果迭代器是新的(未使用过),那么初始化新迭代器 if (iter->entry == NULL) { dictht *ht = &iter->d->ht[iter->table]; // 在第一次迭代的时候增加字典 iterators 属性的计数 if (iter->safe && iter->index == -1 && iter->table == 0) iter->d->iterators++; iter->index++; // 当迭代器的 index 值超过哈希表的 index 值时。。。 if (iter->index >= (signed) ht->size) { // 如果字典正在进行 rehash ,那么转移阵地 // 到 1 号哈希表继续迭代 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; }
static int dictExpand(dict *pHeader, unsigned int size) { if (NULL == pHeader || 0 >= size || dictIsRehashing(pHeader)) { return DICT_ERROR; } size *= 2; pHeader->ht[1]->table = (dictEntry**)realloc((void *)pHeader->ht[1]->table,(sizeof(dictEntry *)*size)); if (NULL == pHeader->ht[1]->table) { return DICT_ERROR; } memset(pHeader->ht[1]->table, 0, (sizeof(dictEntry *) * size)); pHeader->ht[1]->size = size; pHeader->ht[1]->used = 0; pHeader->rehashidx = 0; return DICT_OK; }
/************************************************************* * Function : Rehash * Author : bulldozer.ma * Date : 2015-11-01 * Input : dict *pHeader, int n * Output : N/A * Return : int * Other : N/A * Description : Rehash **************************************************************/ int Rehash(dict *pHeader, int n) { if (NULL == pHeader || !dictIsRehashing(pHeader)|| 0 >= n) { return DICT_ERROR; } while (n --) { dictEntry *node= NULL, *nextnode = NULL; unsigned int uiKey = 0; if (0 == pHeader->ht[0]->used) { dictht *pTemp = pHeader->ht[0]; pHeader->ht[0] = pHeader->ht[1]; pHeader->ht[1] = pTemp; pHeader->rehashidx = -1; return DICT_ERROR; } while (NULL == pHeader->ht[0]->table[pHeader->rehashidx]) { pHeader->rehashidx++; } node = pHeader->ht[0]->table[pHeader->rehashidx]; while (node) { nextnode = node->next; uiKey = getKey(node->value, strlen (node->value), pHeader->ht[1]); node->key = uiKey; node->next = pHeader->ht[1]->table[uiKey]; pHeader->ht[1]->table[uiKey] = node; pHeader->ht[0]->used--; pHeader->ht[1]->used++; node = nextnode; } pHeader->ht[0]->table[pHeader->rehashidx] = NULL; pHeader->rehashidx++; } return DICT_OK; }
/* Expand the hash table if needed */ static int _dictExpandIfNeeded(dict *d) { /* Incremental rehashing already in progress. Return. */ if (dictIsRehashing(d)) return DICT_OK; /* If the hash table is empty expand it to the initial size. */ if (d->ht[0].size == 0) return dictExpand(d, DICT_HT_INITIAL_SIZE); /* If we reached the 1:1 ratio, and we are allowed to resize the hash * table (global setting) or we should avoid it but the ratio between * elements/buckets is over the "safe" threshold, we resize doubling * the number of buckets. */ if (d->ht[0].used >= d->ht[0].size && (dict_can_resize || d->ht[0].used/d->ht[0].size > dict_force_resize_ratio)) { return dictExpand(d, d->ht[0].used*2); } return DICT_OK; }
//下一个迭代项的entry,从上面的迭代器初始化可以看出 //迭代器在初始化的时候是不指向任何entry的,需要执行next操作获entry的指针 dictEntry *dictNext(dictIterator *iter) { while (1) { //第一次next if (iter->entry == NULL) { dictht *ht = &iter->d->ht[iter->table]; //这里说明是一个安全的迭代器第一次next操作,增加字典中的计数 //之所以对着三项都进行判断,因为只有这样才能够唯一得标志该状态 if (iter->safe && iter->index == -1 && iter->table == 0) iter->d->iterators++; iter->index++; //这里说明bucket的index已经超出当前的最大值了 if (iter->index >= (signed) ht->size) { //如果执行rehash,切换哈希表,这个指挥执行一次 //并且是对于是否安全的迭代器都会执行该操作 //那么安全迭代器的安全体现在哪里呢?!!! if (dictIsRehashing(iter->d) && iter->table == 0) { iter->table++; iter->index = 0; ht = &iter->d->ht[1]; } else { //没有rehash操作,说明已经到达了最后一个元素 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. */ //这里在得到迭代器的entry之后会继续得到nextEntry,当值entry被删除 //但是如果这两个元素都被删除了呢? //如何让迭代器感应到这种变化? iter->nextEntry = iter->entry->next; return iter->entry; } } return NULL; }