最近实现的两个patch都使用到了MySQL内置的hash结构。这个结构在MySQL框架层中被多处使用,理解它可以方便代码阅读。
1、总体
InnoDB中也有自带的HASH表,本文中介绍的是MySQL框架层的hash表。其定义的头文件在include/hash.h,实现位置mysys/hash.c。内部存储数据使用了动态数组DYNAMIC_ARRAY。
这个hash表实现了插入、删除、修改、查找接口,也提供了遍历接口。在打patch时会发现很好用。
2、初始化_my_hash_init
a)声明
参数表
说明
HASH *hash
欲初始化的hash表地址
uint growth_size
Hash表空间不够时再次申请的个数
CHARSET_INFO *charset
系统字符集
ulong default_array_elements
初始容量
size_t key_offset
Key在data中的偏移量
size_t key_length
Key的长度
my_hash_get_key get_key
获取key的回调函数
void (*free_element)(void*)
析构回调
uint flags
hash表类型
b)说明:1)调用时growth_size一般取值为0,内部会根据初始值和每个HASH_LINK大小得到一个合理的值(./mysys/array.c), sizeof(HASH_LINK)=sizeof(int)+sizeof(char*);
2)hash表类型目前只有0和1(HASH_UNIQUE),为1表示key值不允许重复;
3)析够回调中,对于传入的元素指针,需要自定义一个合适的删除方法。
4)特别说明typedef uchar *(*my_hash_get_key)(const uchar *,size_t*,my_bool)。若该回调函数不为NULL,则通过该函数的size_t*传出key的长度,返回值为key在data中的起始地址;若为NULL,则偏移量为key_offset,key长度为key_length。
从init的声明中可以看到,这个hash表中存的是全数据(data),也包含了key的内容。Key作为data的一部分,通过my_hash_get_key告诉hash表key的获取方式(当然获取到key之后,最终还是签名后决定hash位置)。
3、插入元素my_hash_insert
a)声明
参数表
说明
HASH *info
hash表地址
const uchar *data
插入的数据地址
b)说明: 1)可以看到,插入的参数只有一个data,key的获取方式即为init时指定的my_hash_get_key或key_offset& key_length;
2)需要注意,hash中存的只是data的地址,因此data不能为栈变量。且需要在free_element中自定义删除方法。
3)返回值为TRUE时,表示插入失败,为0时表示插入成功。
4、查找元素my_hash_search
a)声明
参数表
说明
const HASH *info
hash表地址
const uchar *key
查找的key
size_t length
Key长度
b)说明: 1)返回值为查找到的data的地址,若查找不到,返回NULL
2)由于直接返回data的地址,因此如果要修改data中的非key字段,可以直接指针操作。
5、删除/修改元素
a)删除my_hash_delete
参数表
说明
const HASH *info
hash表地址
const uchar *data
删除的数据地址
说明: 1)注意这里是按照地址比较的,非key。
b)修改my_hash_update
参数表
说明
const HASH *info
hash表地址
const uchar *data
修改的数据地址
uchar *old_key
原key
size_t old_key_length
原key长度
说明: 1)该函数的功能是,当data内容有涉及到key的修改时,修改key,及其在hash表的位置。效果上等效于delete+insert,但效率更高。
6、遍历
遍历功能使得这个数据结构非常好用。看下面的代码就知道用法了。
for(i=0; irecords; i++)
{
hash_item= (hash_item_t*)my_hash_element(my_hash, i);
}
说明:其中hash_item_t为hash表中的元素――我们自定义的类型。
7、一个例子
用一个例子来简要说明用法,只需要演示init部分就可以了。
初始化语句
hash_init(&table_hash, &my_charset_bin, MAX_RECORD_NUM+16, 0, 0, hash_item_get_key, (hash_free_key)hash_item_free_entry, MYF(0));
说明:MySQL代码中多使用这个宏,其中growth_size在替换中默认使用0;
typedef struct st_hash_item
{
int value;
int key_len;
char key[2*NAME_CHAR_LEN+1];
}hash_item_t;
uchar *hash_item_get_key(const uchar *record, size_t *length, my_bool not_used __attribute__((unused)))
{
hash_item_t *entry= (hash_item_t*) record;
*length= entry->key_len;
return (uchar*) entry->key;
}
static void hash_item_free_entry(hash_item_t* record)
{
delete record;
DBUG_VOID_RETURN;
}
说明:1)我们使用字符串的key,因此在hash_item_t中有key_len和key[]。配合hash_item_get_key提供根据输入的data,获取key_len和key的方法。
2)由于insert进hash表的数据是通过new hash_item_t的方法得到的,因此在free_entry中直接使用delete回收。
2
顶
1
踩
分享到:
2010-11-30 00:10
浏览 3598
分类:数据库
评论
1 楼
pirate1997
2013-03-15
对于这个结构我使用了以下代码:
初始化:
my_hash_init(&c_sql,system_charset_info,100,0,100,0,0,HASH_UNIQUE);
插入数据:
char tmp[100];//临时定为100
strcpy(tmp,thd->query_string.str());
my_hash_insert(&c_sql,(uchar *)tmp);
遍历:
for(i=0 ; i
fprintf(stderr,"COM_QUERY : %s \n",(char *)my_hash_element(&c_sql,i));
每次插入是总不会成功,而且遍历时只能看到最后两次插入的数据,本意是想保留100条的,
能否给个简单示例说明这个结构如何使用的?
谢谢。
我的信箱:pirate1997@163.com