hash_bigkey.c 文件:关于大数据记录操作的函数;
__big_insert 函数:插入大数据记录;
函数参数:
hashp : HTAB 指针;
pagep : PAGE16 类型指针,接收记录的页面;
key : DBT 类型指针;记录的键值部分;
val : DBT 类型指针,记录的数据值部分;
返回值 : 成功或失败;
伪代码:
关于插入大数据记录,由于大数据记录是使用溢出页面链表的形式另外存储,在桶链表页中,大数据记录的索引中保存的是溢出页面链表首页的溢出页面编号,所以参数 pagep 实际上传入的是桶链表页,只为记录保留存放索引的空间,本函数将分配存储数据的溢出页面链表,并将表头页的溢出页面编号存放到索引的数据部分;
由于一页可能不能够完全存放完大数据记录,所以需要一个存放指针,设 key_data 为键值的存放指针,初始化为指向 key 的 data 成员起始地址, key_size 记录还剩下多少键值数据没有存储,初始化为键值长度,即 key 的 size 成员; val_data 为数据值的存放指针,初始化为指向 val 的 data 成员起始地址, val_size 记录尚未存储的数据值的大小,初始化为数据值的长度,即 val 的 size 成员;
将 pagep 的成员个数递增 1 ;
1 、使用 __add_bigpage 函数为大数据记录分配存储链表表头页,并将其溢出页面编号存储到 pagep 的指定索引的数据部分,同时将键值部分置为大数据标记;同时将 pagep 指向分配的页面;
2 、由于溢出页链表中只存放一条记录,所以 pagep 的页面记录数量赋值为 1 ;
3 、大数据记录的存储是先存储键值,然后存储数据值,同时二者都有可能占据多页,所以需要现计算当前可以存放数据的空间即页面空闲空间,同时比较键值或数据值可以存放的尺寸,取二者之间的较小值作为后续移动赋值操作的长度,首先计算键值需要复制多少到 pagep 中,取 pagep 的空闲空间和 key_size 的较小值,赋给 key_move_bytes ,然后将 key_move_bytes 赋值给记录索引的键值部分,然后计算数据值可以复制到 pagep 中保存的尺寸 val_mov_bytes ,由于前面已经为键值的存放预留了空间,所以此时页面空闲空间的计算需要减去保存键值的部分,然后取较小值,同时将 val_move_bytes 保存到索引的数据部分;
4 、如果 key_move_bytes 大于 0 ,则表示需要向 pagep 页中保存键值,使用 mommove 函数将 key_data 开始的 key_move_bytes 长度的键值赋值到 pagep 中,首地址从页面去除头部和索引部分之后的地方开始;
5 、如果 val_move_bytes 大于 0 ,则表示可以想 pagep 页中写入数据值,使用 mommove 函数将 val_data 开始的 val_move_bytes 长度的数据值赋值到 pagep 中,首地址从页面取出头部和索引部分及其后续的 key_move_bytes 字节的键值部分之后的地址开始;
6 、将已经保存的键值和数据值从保存指针中去除,即 key_size 减少 key_move_bytes , key_data 指针向下移动 key_move_bytes ; val_size 减少 val_move_bytes , val_data 指针向下移动 key_move_bytes ;
7 、判断 key_size+val_size 是否等于 0 ,若是,则表示所有数据已经存储完,转 14 ;否则转 8 ;
8 、使用 __add_bigpage 函数为后续数据存储分配页面,同时将页面连接到存储链表表尾,将分配的页面赋值给 pagep ;
9 、 pagep 中记录个数为 1 ;
10 、计算 key_move_bytes 和 val_move_bytes ,同时将二者保存到索引中;
11 、根据 key_move_bytes 保存键值;
12 、根据 val_move_bytes 保存数据值;
13 、调整保存指针,转 7 ;
14 、将 pagep 标记为已经更新,需要写回;
返回;
注意:从上面可以看出大数据记录的存储方式,和大数据记录存储页面的基本格式,这将会影响后续对大数据记录的读取;
__big_delete 函数:删除大数据记录函数;
函数参数:
hashp : HTAB 指针;
pagep : PAGE16 类型指针,待删除记录的页面指针;
ndx :整型,待删除记录在页面中的索引值;
返回值:成功或失败;
伪代码:
删除大数据记录,就是释放存储的链表,删除对应索引,调整 pagep 中 ndx 之后记录索引的位置即可,本函数只负责释放链表;
从 pagep 中取出第 ndx 条记录的数据部分,其中存放了大数据记录存储链表表头页的溢出页面编号,将溢出页面编号转换成页面编号,使用 __get_page 函数获取表头页 pagep ;
1 、如果 pagep 的右兄弟不为空,转 2 ,否则转 3 ;
2 、获取 pagep 的右兄弟页面 pagep ,同时保存本页面为 last_pagep ,使用 __delete_page 函数删除 last_pagep 页面;转 1 ;
3 、使用 __delete_page 函数删除 pagep 页面(链表最后一页);
返回;
__find_bigpair 函数:判断当前游标所指的记录是否是指定的记录;
函数参数:
hashp : HTAB 指针;
cursorp :游标指针;
key :键值指针;
size :键值大小;
返回值:相等或不等
伪代码:
同大数据存储一样,由于分页存储,大数据记录的比较同样需要分页进行;
已比较指针 kkey ,初始化等于 key ,剩余未比较键值的长度 ksize ;
获取游标页面 pagep ;
从 pagep 中得到大数据记录存储链表表头页页面编号 next_pgno ;
获取页面编号为 next_pgno 的页面 pagep ;
1 、如果 ksize 大于 0 且 pagep 中键值的长度大于 0 ,表示二者之前的部分相等,后续还有未比较的部分,则转 2 ;否则转;
2 、如果 ksize 小于 ...
本函数后续部分似乎有问题或 bug ,未理解;
__big_keydata 函数:从页面中获取是指定记录;
函数参数:
hashp : HTAB 指针;
pagep : PAGE16 类型指针,存放指定记录的页面;
key : DBT 类型指针,存放返回的键值信息;
val : DBT 类型指针,存放返回的数据值信息;
ndx :整型,记录在页面中的索引;
返回值:成功或失败;
伪代码:
key 和 val 实际上只是指向返回记录的指针,实际的信息保存在 hashp 的大数据缓冲区中,所以本函数返回的缓冲区不能释放;
根据 pagep 和 ndx 获取存储大数据记录链表表头页 key_pagep ;
使用 collect_key 函数将 key_pagep 页面开始的存储链表中的键值部分保存到 hashp 的 bigkey_buf 成员中,同时得到存储键值的最后一页的页面编号 last_page ,根据大数据记录的存储方式可知,这一页同样是数据值存储的起始页;将键值的大小赋给 key 的 size 成员,同时将 key 的 data 指向 hashp 的 bigkey_buf 成员;
将 last_page 赋值给查找项 ii 的 pgno 成员,然后使用 __big_return 函数获取记录的数据值部分;
返回;
__get_key 函数:获取指定记录的键值部分;
函数参数:
hashp : HTAB 指针;
pagep : PAGE16 类型指针,存储指定记录的页面;
ndx :记录在页面内索引;
key : DBT 类型指针,返回键值;
返回值:成功或失败;
伪代码:
根据 pagep 和 ndx 使用 __get_page 函数获取指定记录存储链表的表头页 key_pagep ;
使用 collect_key 函数将键值保存到 hashp 的 bigkey_buf 中,将 key 的 size 赋值为键值长度, key 的 data 指向 bigkey_buf 。
返回;
__big_return 函数:获取指定记录的数据值部分;
函数参数:
hashp : HTAB 指针;
item_info : ITEM_INFO 类型指针,传入指定记录的位置信息;
val : DBT 类型指针;返回记录的数据值;
on_bigkey_page :整型,为 0 则表示 item_info 指示的位置处于桶链表页, item_info 的 data_off 是页面中数据部分的索引,即存储链表表头页的页面编号;为 1 则表示 item_info 指示的页面为记录的存储页,即 item_info 的 pgno 传入了存储页的页面编号;
返回值:成功或失败;
伪代码:
根据 on_bigkey_page 判断获取记录存储链表页 pagep 的方式;获取 pagep ;
顺着存储链表的方向,从 pagep 开始找到存储数据值的起始页面 pagep ;
使用 collect_data 函数获取记录的数据值存放到 hashp 的 bigdata_buf 中;
将 val_size 赋值为数据值的长度, val_data 赋值为 bigdata_buf ;
返回;
collect_key 函数:递归函数,用于获取记录中的键值;
函数参数:
hashp : HTAB 指针;
pagep : PAGE16 类型指针,存储记录链表的页面;
len :已经获取键值的长度;
last_page :页面编号指针,由于键值可能存放到多个页面,其最后一个页面就是数据值存放的起始页面,为了方便获取键值后获取数据值,使用本函数返回键值的最后一页编号;
返回值:获取键值的长度;
将 len 加上本页中键值的长度,得到本次调用将获得键值的总长度 totlen ;
检查本页中数据值的长度,如果不为 0 ,则表示已经到了最后一页,将本页中的键值附加到 bigkey_buf 之后,返回 totlen ,同时将 last_page 赋值为本页的编号;注意,如果 bigkey_buf 的空间不够,需要重新分配;
如果本页中键值的长度为 0 ,则表示前一页是键值的最后一页,而且刚好使用完页面全部的空闲空间,则本页为数据值存储第一页;返回 totlen ;(按照程序的逻辑, last_page 指的是键值存储最后一页,所以 last_page 的值不变)
如果不是上述两种情况,则表示当前页不是键值最后一页,将 last_page 赋值为当前页,准备递归操作;
获取下一页页面编号 next_pgno ;
获取下一页 next_pagep ;
递归调用 collect_key 函数继续沿着链表方向查找,得到返回值 retval ,即键值的长度;
将当前页面保存的键值复制到 bigkey_buf 中,起始地址为 bigkey_buf + len, 长度为本页保存键值的长度;
注意:在递归的过程中, bigkey_buf 不断根据 totlen 来调整自身的长度,在递归返回时才将页面中的键值赋值到对应的位置,避免了内存重分配时可能丢失以前复制数据的风险; len 传入了本页之前的页面键值的长度,所以,本页存储的起始位置就可以定下来了;
返回 retval ;
collect_data 函数:获取指定记录的数据值;
函数参数:
hashp : HTAB 指针;
pagep : PAGE16 类型指针,存储记录数据值部分的页面;
len :整型,传入本页之前存储的数据值的长度;
返回值:获取数据值的长度;
本函数同 collect_key 函数类似;
计算截至本页数据值存储的长度 totlen ;
如果右兄弟页面为空,则本页为最后一页;复制本页数据值到 bigdata_buf ,返回 titlen ;
如果右兄弟页面不为空,则获取下一页页面编号 next_pgno ;
获取下一页 next_pagep ;
递归调用 collect_data 函数,收集后续页面存储的数据值,返回数据值长度 retval ;
将本页数据值复制到 bigdata_buf 中;
返回 retval ;