数据结构

redis-字典.drawio.png

数据操作

初始化

  1. int _dictInit(dict *d, dictType *type, void *privDataPtr) {
  2. _dictReset(&d->ht[0]);
  3. _dictReset(&d->ht[1]);
  4. d->type = type;
  5. d->privdata = privDataPtr;
  6. d->rehashidx = -1;
  7. d->iterators = 0;
  8. return DICT_OK;
  9. }
  10. //----
  11. static void _dictReset(dictht *ht)
  12. {
  13. ht->table = NULL;
  14. ht->size = 0;
  15. ht->sizemask = 0;
  16. ht->used = 0;
  17. }

增加(替换)

  1. int dictReplace(dict *d, void *key, void *val)
  2. {
  3. dictEntry *entry, *existing, auxentry;
  4. /* Try to add the element. If the key
  5. * does not exists dictAdd will succeed. */
  6. entry = dictAddRaw(d,key,&existing);
  7. if (entry) {
  8. //添加成功,设置hash节点的value
  9. dictSetVal(d, entry, val);
  10. return 1;
  11. }
  12. /* Set the new value and free the old one. Note that it is important
  13. * to do that in this order, as the value may just be exactly the same
  14. * as the previous one. In this context, think to reference counting,
  15. * you want to increment (set), and then decrement (free), and not the
  16. * reverse. */
  17. auxentry = *existing;
  18. //设置新的value值
  19. dictSetVal(d, existing, val);
  20. //释放老的节点
  21. dictFreeVal(d, &auxentry);
  22. return 0;
  23. }

删除(hash获取数组下标 && 链表移除节点,直接释放内存/后台释放内存)

  1. /* Search and remove an element. This is an helper function for
  2. * dictDelete() and dictUnlink(), please check the top comment
  3. * of those functions. */
  4. static dictEntry *dictGenericDelete(dict *d, const void *key, int nofree) {
  5. uint64_t h, idx;
  6. dictEntry *he, *prevHe;
  7. int table;
  8. if (d->ht[0].used == 0 && d->ht[1].used == 0) return NULL;
  9. //执行rehash
  10. if (dictIsRehashing(d)) _dictRehashStep(d);
  11. //获取数组索引下标
  12. h = dictHashKey(d, key);
  13. for (table = 0; table <= 1; table++) {
  14. idx = h & d->ht[table].sizemask;
  15. he = d->ht[table].table[idx];
  16. prevHe = NULL;
  17. while(he) {
  18. //找到了key
  19. if (key==he->key || dictCompareKeys(d, key, he->key)) {
  20. //key在链表中
  21. if (prevHe)
  22. prevHe->next = he->next;
  23. else//key在数组中
  24. d->ht[table].table[idx] = he->next;
  25. if (!nofree) {//根据配置释放直接释放内存
  26. dictFreeKey(d, he);
  27. dictFreeVal(d, he);
  28. zfree(he);
  29. }
  30. d->ht[table].used--;
  31. return he;
  32. }
  33. prevHe = he;
  34. he = he->next;
  35. }
  36. if (!dictIsRehashing(d)) break;
  37. }
  38. return NULL; /* not found */
  39. }

渐进式哈希

在rehashIndex!=-1的时候进入,rehashIndex就是数组的下标,每次都取走n个bucket的数据(n个bucket+bucket链表的数据),将其插入到第二个hash表上,采用头插法的方式进行。

  1. /* Performs N steps of incremental rehashing. Returns 1 if there are still
  2. * keys to move from the old to the new hash table, otherwise 0 is returned.
  3. *
  4. * Note that a rehashing step consists in moving a bucket (that may have more
  5. * than one key as we use chaining) from the old to the new hash table, however
  6. * since part of the hash table may be composed of empty spaces, it is not
  7. * guaranteed that this function will rehash even a single bucket, since it
  8. * will visit at max N*10 empty buckets in total, otherwise the amount of
  9. * work it does would be unbound and the function may block for a long time. */
  10. int dictRehash(dict *d, int n) {
  11. int empty_visits = n*10; /* Max number of empty buckets to visit. */
  12. if (!dictIsRehashing(d)) return 0;
  13. while(n-- && d->ht[0].used != 0) {
  14. dictEntry *de, *nextde;
  15. //跳过数组下标为null的节点
  16. while(d->ht[0].table[d->rehashidx] == NULL) {
  17. d->rehashidx++;
  18. if (--empty_visits == 0) return 1;
  19. }
  20. //获取第一个节点
  21. de = d->ht[0].table[d->rehashidx];
  22. /* Move all the keys in this bucket from the old to the new hash HT */
  23. while(de) {
  24. uint64_t h;
  25. //获取下一个节点
  26. nextde = de->next;
  27. /* Get the index in the new hash table */
  28. //获取新索引值
  29. h = dictHashKey(d, de->key) & d->ht[1].sizemask;
  30. //通过头插法进行插入,这里只是更新节点下标,不需要释放节点内存
  31. de->next = d->ht[1].table[h];
  32. d->ht[1].table[h] = de;
  33. d->ht[0].used--;
  34. d->ht[1].used++;
  35. de = nextde;
  36. }
  37. //一个bucket就解决了
  38. d->ht[0].table[d->rehashidx] = NULL;
  39. d->rehashidx++;
  40. }
  41. //检查是否已经处理完了整个hash表
  42. /* Check if we already rehashed the whole table... */
  43. if (d->ht[0].used == 0) {
  44. zfree(d->ht[0].table);
  45. d->ht[0] = d->ht[1];
  46. _dictReset(&d->ht[1]);
  47. d->rehashidx = -1;
  48. return 0;
  49. }
  50. /* More to rehash... */
  51. return 1;
  52. }

图解

image.png
image.png
image.png
image.png
image.png
image.png