MySQL源码解读之数据结构-LF_HASH
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::atomiclink; /* 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::atomicsize; /* size of array */ std::atomic 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*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值