Berkeley DB 1.8.6源代码学习(八)

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

 

你可能感兴趣的:(delete,存储,insert)