/* 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; }
//这个函数也可以作为向外部提供的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; }
/* 从字典中查找给定 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; // 返回新节点 }
/* 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; }
/* 删除指定元素的底层实现代码 * * 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 (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; }
/* 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; }