Hash 结构

哈希表默认是支持动态扩容的,即当哈希表存放键值对大于 3/4 哈希桶的个数时,会 2 倍扩容。 哈希冲突时,Vector 长度认为是没有限制的。

Hash 结构内存分布及结构体描述

哈希结构内存分布如下图所示: 在这里插入图片描述

Hash 冲突时是如何解决的

哈希冲突解决分 2 中情况(具体代码在 lookup() 函数中): 1、Key 和 Vlaue 都保存时 Hash 结构体中 log2_pair_size 不等于 0 是,存储的是 hash_pair_indirect_t 结构。使用 alloc_len 保存 hash_pair_t 结构数量。 在这里插入图片描述 2、只保存 Key 时。 Hash结构体中 log2_pair_size= 0, 存储的是指针 hash_pair_t*,变成 vec_head_t 结构存储

在这里插入图片描述

Hash函数操作:

  • 哈希函数创建 (hash.h) 在这里插入图片描述

  • Hash 函数操作 在这里插入图片描述

Mhash学习

  • Mhash 结构及相关实现描述 在这里插入图片描述

  • Mhash 操作函数 在这里插入图片描述

Hash 和 Mhash 的不同

1、对 Key 的处理, Hash 结构 Key 是需要使用的自己存储的,而 Mhash 结构内部会保存 Key 内容。 2、Mhash 和 Hash 都是不支持多核操作的,在使用中需要注意加锁。 3、Mhash 底层使用的是 Hash 操作函数。

MHash使用的一些问题:

1、Mhash_free 函数存在内存泄露 对 key_tmps 内存释放是在源码中没有的;在 mhash_init 函数中是有的。

always_inline void
mhash_free (mhash_t * h)
{
  if (mhash_key_vector_is_heap (h))
    heap_free (h->key_vector_or_heap);
  else
    vec_free (h->key_vector_or_heap);
  vec_free (h->key_vector_free_indices);
   /*对key_tmps内存释放是在源码中没有的*/
   {
    int i;
    for (i = 0; i < vec_len (h->key_tmps); i++)
      vec_free (h->key_tmps[i]);
  }
  vec_free (h->key_tmps);
  hash_free (h->hash);
}

2、mhash_set和mhash_unset 对key_tmps的使用
always_inline void
mhash_sanitize_hash_user (mhash_t * mh)
{
  uword * hash = mh->hash;
  hash_t * h = hash_header (hash);
  h->user = pointer_to_uword (mh);
}

static uword mhash_set_tmp_key (mhash_t * h, void * key)
{
  u8 * key_tmp;
  int my_cpu = os_get_cpu_number();

  vec_validate(h->key_tmps, my_cpu);
  key_tmp = h->key_tmps[my_cpu];

  vec_reset_length (key_tmp);

  if (mhash_key_vector_is_heap (h))
    {
      uword is_c_string = h->n_key_bytes == MHASH_C_STRING_KEY;

      if (is_c_string)
	vec_add (key_tmp, key, strlen (key) + 1);
      else
	vec_add (key_tmp, key, vec_len (key));
    }
  else
    vec_add (key_tmp, key, h->n_key_bytes);

  h->key_tmps[my_cpu] = key_tmp;

  return ~0;
}


mhash_sanitize_hash_user (h);
/*i 一直返回全FF,但是怎么去查询hash对的*/
  i = mhash_set_tmp_key (h, key);

  p = hash_get_pair (h->hash, i);

i = mhash_set_tmp_key (h, key); 操作是i返回的是全 F,如何来查询 Vlaue 的呢? 答案就在 Hash 函数中 mhash_key_to_mem,如果 Key 是全 F 就从 key_tmps 获取 Key。

static uword								\
  mhash_key_sum_##N_KEY_BYTES (hash_t * h, uword key)			\
  {									\
    mhash_t * hv = uword_to_pointer (h->user, mhash_t *);		\
    return mhash_key_sum_inline (mhash_key_to_mem (hv, key),		\
				 (N_KEY_BYTES),				\
				 hv->hash_seed);			\
  }									\