/* 从字典中查找给定 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; }
/* 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; }
/* 删除指定元素的底层实现代码 * * 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 */ }
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 (dictCompareKeys(d, key, he->key)) return he; he = he->next; } if (!dictIsRehashing(d)) return NULL; } return NULL; }
/* 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 */ 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 (dictCompareKeys(d, key, he->key)) return -1; he = he->next; } if (!dictIsRehashing(d)) break; } return idx; }