博客园  :: 首页  :: 新随笔  :: 订阅 订阅  :: 管理

MySQL源码解读之数据结构-LF_HASH

Posted on 2022-01-14 10:33  面具下的戏命师  阅读(290)  评论(0编辑  收藏  举报

MySQL源码解读之数据结构-LF_HASH

MySQL的代码中实现了一个Lock Free的Hash结构,称作LF_Hash。Metadata_Lock就依赖于它。LF_HASH具有以下特点:

1、动态扩展:

初始化时bucket的数量是1. 每个bucket平均拥有的元素(Element)是1个。因此当元素的总数量超过bucket的数量时,就会自动分裂。每次分裂增加一倍的buckets

2、Lock Free

lf_hash采用Lock Free的方式实现,为了保证多线程操作的安全。lf_hash实现了一个叫做pin的东西来保证多线程操作的安全性。lf_hash的操作都需要通过pin来保护。因此lf_hash提供了获取pin和释放pin的函数。lf_hash自己维护了一个pin的动态数组。

3、内存管理

lf_hash元素的内存都是lf_hash分配和管理的。用户的数据需要拷贝到lf_hash创建的元素中。

LF_HASH的基本结构

lf_hash的基本结构有以下特点 所有的元素维护在一个全局排序链表中, 同一个bucket的所有元素排在一起  每个bucket有一个指针,指向这个bucket的所有元素的head。如下图所示:

 

元素管理

lf_hash的元素使用了一块连续的内存,包含两部分信息:

  • LF_SLIST 链表和hash相关的信息.
  • 用户数据 放在LF_SLIST之后。

LF_SLIST

struct LF_SLIST {
  std::atomic<LF_SLIST *>
      link;      /* a pointer to the next element in a listand a flag */
  uint32 hashnr; /* reversed hash number, for sorting                 */
  const uchar *key;
  size_t keylen;
  /*
    data is stored here, directly after the keylen.
    thus the pointer to data is (void*)(slist_element_ptr+1)
  */
};
  • link:指向链表中的下一个元素
  • hashnr: hash的反转值
  • key:  指针指向key值
  • keylen:  key的长度

LF_HASH

struct LF_HASH {
  LF_DYNARRAY array;             /* hash itself */
  LF_ALLOCATOR alloc;            /* allocator for elements */
  hash_get_key_function get_key; /* see HASH */
  CHARSET_INFO *charset;         /* see HASH */
  lf_hash_func *hash_function;   /* see HASH */
  uint key_offset, key_length;   /* see HASH */
  uint element_size;             /* size of memcpy'ed area on insert */
  uint flags;                    /* LF_HASH_UNIQUE, etc */
  std::atomic<int32> size;       /* size of array */
  std::atomic<int32> count;      /* number of elements in the hash */
  /**
    "Initialize" hook - called to finish initialization of object provided by
     LF_ALLOCATOR (which is pointed by "dst" parameter) and set element key
     from object passed as parameter to lf_hash_insert (pointed by "src"
     parameter). Allows to use LF_HASH with objects which are not "trivially
     copyable".
     NULL value means that element initialization is carried out by copying
     first element_size bytes from object which provided as parameter to
     lf_hash_insert.
  */
  lf_hash_init_func *initialize;
};

array  动态数组,hash的所有元素存到动态数组中。 

alloc   内存分配器,为hash的元素申请内存空间

get_key  用于从LF_HASH中提取用户数据中的密钥和密钥长度

charset  计算hash值采用的字符集

hash_function 计算hash值的函数

key_offset  用户数据到hash之后的key的偏移量

key_length  hash之后密钥的长度

element_size 用户数据的大小

flags

size    array数组的大小(bucket的数量)

count  统计hash表中的元素个数

initialize 用来初始化一个对象,当传入的用户数据是不可复制的时候,可以传入初始化函数来进行初始化。当initialize是空值时,会把用户数据复制(memcopy)一份。

 

CURSOR

typedef struct {
  std::atomic<LF_SLIST *> *prev;
  LF_SLIST *curr, *next;
} CURSOR;

函数介绍:

1、lf_hash_init2 初始化lf_hash。

2、lf_hash_destory 销毁LF_HASH,。。

3、lf_hash_insert 把一个新元素插入到hash表中,它会把被hash的用户数据复制一份,而不是一个指针指向用户数据。返回值 0插入内存 1 插入失败,唯一key冲突 -1 内存溢出

4、hash_key  返回hash密钥的指针,同时获取hash密钥的长度。

5、calc_hash  计算hash值