发明内容
鉴于上述现有技术的不足,本发明旨在提供一种适合非定长大数据页的高效数据访问与存取数据结构,使磁盘访问量能维持在O(1)的水平上,以满足非关系型数据库的存储和使用需要。
本发明是通过以下技术方案来实现的:
一种大数据页中高效存储非定长数据方法,包括存储结构和记录内容两部分,存储结构的数据页包括存储文件头、空间管理段、元数据管理段和数据块四种类型。
所述存储文件头,用于记录存储文件的基本信息,存储文件头位于数据页的开始端。
所述空间管理段,用于维护和管理整个存储文件的空闲数据页信息,并以0代表数据页未分配,1代表数据页已分配但未被占用,2代表数据页被占用。
所述元数据管理段,存储和管理存储文件中所包含的全部集合信息。
所述数据块,用于存储用户数据的空间,数据块包含有数据块头信息及用户数据信息,一个数据块由一个或多个数据页构成。
所述记录内容包含有数据记录头和数据记录两部分,记录内容用于存储记录的相关信息。
所述存储文件头内记录的基本信息包括:文件标示串、数据页长度、存储文件长度、存储文件名和序列号。文件标示串用于标识数据存储文件的格式;数据页长度为数据块中每个数据页的大小,所有数据页以该大小为标准;存储文件长度表示存储文件头、空间管理段以及全部数据块文件所占据的数据页的数量,并以数据页的个数为单位;存储文件名代表了存储文件的名称;序列号代表存储文件在当前数据库中所属的编号。
所述元数据管理段包括一个以上的元数据单元,每个数据单元包含的信息有:集合名、标示、集合ID、起始数据块ID、终结数据块ID、删除列表和逻辑ID。集合名代表了该集合的名称;标示采用标示符代表该集合的状态;集合ID表示该集合在元数据管理段中所占据的地址;起始数据块ID表示该集合中包含的第一个数据块所在的数据页;终结数据块ID表示该集合中包含的最后一个数据块所在的数据页;删除列表中记录了该集合中不同长度记录被删除的第一条记录的位置;逻辑ID代表了该集合创建时的逻辑位置。
所述数据块头信息及用户数据信息包含有:字符标示串、数据块长度、所属集合ID、数据块标示、数据块版本、数据块逻辑ID、前一个数据块ID、后一个数据块ID、记录数、第一条记录偏移、最后一条记录偏移、空闲空间。字符标示串代表一个数据块起始的信息,并以字符标示数据块是否为非法数据块;数据块长度代表了该数据块所占数据页的数量,数据页在文件中必须连续,并且不能被别的集合所使用;所属集合ID代表了该数据块所属于的集合ID;数据块标示代表该数据块的状态;数据块版本代表该数据块的格式信息;数据块逻辑ID是以逻辑递增方式标示出在每个集合中创建的新的数据块;前一个数据块ID标示了该数据块的前块ID;后一个数据块ID标示了该数据块的后块ID;记录数代表着该数据块内包含的用户记录个数;第一条记录偏移代表了该数据块内第一条记录的偏移地址;最后一条记录偏移代表了该数据块内最后一条记录的偏移地址;空闲空间代表了该数据块内的可用空间大小。
所述数据记录头包含的信息有:记录标示、记录长度、记录在数据块中偏移、前一条记录偏移、后一条记录偏移。记录标示代表了该数据记录的状态;记录长度代表了该数据记录的长度;记录在数据块中偏移代表了该数据记录在当前数据块内的偏移地址;前一条记录偏移标示了该数据记录的前一条记录的偏移指针;后一条记录偏移标示了该数据记录的后一条记录的偏移指针。
本发明所述的大数据页中高效存储非定长数据方法,其有益效果在于:能够对使用非定长数据页的非关系型数据库,在使用常数个IO开销(O(1))的前提下找到一个空闲空间进行数据插入,以适应非定长数据页中快速检索与变更数据的需求,可持续对复杂程度与大小日益增长的数据进行快速,灵活的检索和更新。克服了传统数据库结构在非定长数据页中,其空闲空间查找效率为O(n)的弊端。查找效率和使用灵活性明显提高,方便了大数据页非定长数据的存储需要。
具体实施方式
下面对本发明所述的大数据页中高效存储非定长数据方法在实际应用中的具体结构做进一步的详细描述:
本发明所述的一种大数据页中高效存储非定长数据方法,包括存储结构和记录内容两部分。记录内容用于存储记录的相关信息,存储结构用于反映和指示存储的相关状态。
一、存储结构的数据页包括存储文件头、空间管理段、元数据管理段和数据块四种类型,各类型数据页包含的具体信息内容如下:
1、存储文件头
存储文件头用于记录存储文件的基本信息,存储文件头位于数据页的开始端,并且占据了65536个字节,其余部分以0补位。存储文件头内记录的基本信息包括:文件标示串、数据页长度、存储文件长度、存储文件名和序列号。如下表:
名称 |
长度(字节) |
描述 |
文件标示串 |
8 |
字符串“SDBSUINT”,作为数据文件的标示串 |
数据页长度 |
4 |
数据页大小,字节为单位 |
存储文件长度 |
4 |
存储文件中包含的数据页数量 |
存储文件名 |
128 |
存储文件的名称 |
序列号 |
4 |
存储文件序号 |
a\文件标示串用于标识数据存储文件的格式,本例中,文件标示串为固定字符串“SDBSUINT”,凡是起始字符串不为该字符串的文件不可被识别。
b\数据页长度为数据块中每个数据页的大小,单位为字节,可以选择的数据页长度为4096、8192、16384、32768或65536字节,每个存储文件中所有的数据页均以该长度为准。
c\存储文件长度表示存储文件头、空间管理段以及全部数据块文件所占据的数据页的数量,并以数据页的个数为单位。
d\存储文件名代表了存储文件的名称,最多为128个字节,包括以零为结尾的结束符。
e\序列号代表存储文件在当前数据库中所属的编号,由1起始,占据4个字节。
2、空间管理段
空间管理段用于维护和管理整个存储文件的空闲数据页信息,并以0代表数据页未分配,1代表数据页已分配但未被占用,2代表数据页被占用。空间管理段占据16777216个字节,每个字节描述一个数据页的特征,从而可以很容易地发现是否有一个或多个可用的数据页,实现空间管理。
3、元数据管理段
元数据管理段用于存储和管理存储文件中所包含的全部集合信息。元数据管理段占据4194304个字节,每1024个字节作为一个单位,总共可以存放4096个单位。每个单位作为一个元数据单元,每个数据单元包含的信息有:集合名、标示、集合ID、起始数据块ID、终结数据块ID、删除列表和逻辑ID。如下表:
名称 |
长度(字节) |
描述 |
集合名 |
128 |
集合的名称,最多为128字节UTF-8字符串,包括以零结尾的终结符 |
标示 |
2 |
集合标示,每个比特位代表集合的特定状态 |
集合ID |
2 |
集合ID,与该元数据在元数据段中所处的单位保持一致 |
起始数据块ID |
4 |
该集合包含的第一个数据块所在的数据页 |
终结数据块ID |
4 |
该集合包含的最后一个数据块所在的数据页 |
删除列表 |
160 |
包含20种不同长度类型的被删除记录ID |
逻辑ID |
4 |
该集合的逻辑ID标示 |
a\集合名代表了该集合的名称,集合名为128个字节,采用UTF-8格式的集合名称,包含以零为结尾的终结符。
b\标示为2字节的标示符,标示每个集合的状态,具体状态信息如下:
状态 |
描述 |
0x0000 |
空闲 |
0x0001 |
被占用 |
0x0002 |
被删除 |
c\集合ID表示该集合在元数据管理段中所占据的地址。本例中,集合ID为2字节,由0开始,最高4095个字节,通过集合ID就可以迅速地锁定该集合的元数据信息所在的位置。
d\起始数据块ID表示该集合中包含的第一个数据块所在的数据页。起始数据块ID为4字节,如果该集合为空则指向-1。
e\终结数据块ID表示该集合中包含的最后一个数据块所在的数据页。终结数据块ID也为4字节,如果该集合为空则指向-1。
f\删除列表中记录了该集合中不同长度记录被删除的第一条记录的位置。本例中,删除列表为160字节,包含20个8字节的记录ID。每一个记录ID的格式如下表:
名称 |
长度(字节) |
描述 |
数据块ID |
4 |
该记录所在的数据块所在的数据页 |
偏移ID |
4 |
该记录所在数据块内的偏移地址 |
20个记录ID中的每一个分别代表一种记录长度类型,如下表:
位置 |
记录长度范围(字节) |
0 |
0-31 |
1 |
32-63 |
2 |
64-127 |
3 |
128-255 |
4 |
256-511 |
5 |
512-1023 |
6 |
1024-2047 |
7 |
2048-4095 |
8 |
4096-8191 |
9 |
8192-16383 |
10 |
16384-32767 |
11 |
32768-65535 |
12 |
65536-131071 |
13 |
131072-262143 |
14 |
262144-524287 |
15 |
524288-1048575 |
16 |
1048576-2097151 |
17 |
2097152-4194303 |
18 |
4194304-8388607 |
19 |
8388608-16777216 |
删除列表中的每一个元素为8字节记录ID,20个槽位中从0开始代表0-31字节记录,至19槽位代表的8MB-16MB字节记录,分别指向该集合中此类型被删除的第一条记录。
g\逻辑ID代表了该集合创建时的逻辑位置。与物理集合ID不同,每一个逻辑集合ID在创建集合时递增,因此不会出现重复情况。
4、数据块
数据块用于存储用户数据的空间,数据块包含有数据块头信息及用户数据信息,一个数据块由一个或多个数据页构成。空闲空间代表了该数据块内可用的空间大小,其单位为字节。数据块头信息及用户数据信息包含有:字符标示串、数据块长度、所属集合ID、数据块标示、数据块版本、数据块逻辑ID、前一个数据块ID、后一个数据块ID、记录数、第一条记录偏移、最后一条记录偏移和空闲空间,如下表:
名称 |
长度(字节) |
描述 |
字符标示串 |
2 |
以字符”DE”标示数据块的起始 |
数据块长度 |
2 |
该数据块所占据的数据页数量,单位为数据页个数 |
所属集合ID |
2 |
该数据块所属的集合ID |
数据块标示 |
1 |
该数据块的状态标示 |
数据块版本 |
1 |
该数据块格式的版本信息 |
数据块逻辑ID |
4 |
数据块逻辑ID |
前一个数据块ID |
4 |
上一个数据块ID |
后一个数据块ID |
4 |
下一个数据块ID |
记录数 |
4 |
该数据块内包含的记录数量 |
第一条记录偏移 |
4 |
该数据块内第一条记录的起始偏移 |
最后一条记录偏移 |
4 |
该数据块内最后一条记录的起始偏移 |
空闲空间 |
4 |
该数据块内包含的空闲可用空间 |
a\字符标示串代表一个数据块起始的信息,本例中,以ASCII字符D与E来标示,凡是不包含该两个字符的数据块为非法数据块。
b\数据块长度代表了该数据块所占数据页的数量,数据块长度包含2个字节的长度,每个数据块的内容必须连续,因此假设一个数据块包含N个数据页,这N个数据页在文件中必须连续,并且不能被别的集合所使用。
c\所属集合ID代表了该数据块所属于的集合ID。
d\数据块标示代表该数据块的状态。本例中,以‘1’标示该数据块被占用,以‘2’标示该数据块空闲。
e\数据块版本代表该数据块的格式信息。当系统升级时,有可能数据块的格式发生变化,该标示代表本数据块的格式版本需要用相应版本的处理函数进行解析,从而保证了数据的延续性。
f\数据块逻辑ID是以逻辑递增方式标示出在每个集合中创建的新的数据块。数据块逻辑ID不同于数据块ID,数据块ID为该数据块的第一个数据页所处的位置,而数据块逻辑ID在每个集合创建新的数据块时递增,与其文件中的物理位置无关。
g\前一个数据块ID标示了该数据块的前块ID。
h\后一个数据块ID标示了该数据块的后块ID。
前一个数据块ID和后一个数据块ID分别指向了该数据块的前后块。由于一个存储文件中可能包含多个集合,每个集合所占用的数据块互相交织在一起,因此,必须通过每个数据块的前后ID将整个集合中所包含的数据块以链表的形式进行串联,以方便数据读取。
i\记录数代表着该数据块内包含的用户记录个数。
j\第一条记录偏移代表了该数据块内第一条记录的偏移地址,空数据块中为-1。
k\最后一条记录偏移代表了该数据块内最后一条记录的偏移地址,空数据块中为-1。
l\空闲空间代表了该数据块内的可用空间大小。
二、记录内容包含有数据记录头和数据记录两部分,数据记录头之后为用户数据记录,记录格式使用标准BSON格式。其中,数据记录头包含的基本信息包括:记录标示、记录长度、记录在数据块中偏移、前一条记录偏移、后一条记录偏移。每条数据记录共16个字节,具体结构如下表:
名称 |
长度(字节) |
描述 |
记录标示 |
1 |
该记录的状态 |
记录长度 |
3 |
该记录的长度,单位为字节 |
记录在数据块中偏移 |
4 |
该记录在当前数据块中的偏移地址 |
前一条记录偏移 |
4 |
前一条记录在当前数据块内的偏移地址 |
后一条记录偏移 |
4 |
后一条记录在当前数据块内的偏移地址 |
a\记录标示代表了该数据记录的状态。其中,以数值‘0’标示正常记录;以数值‘1’标示溢出源;以数值‘2’标示溢出目标;以数值‘3’标示被删除。
b\记录长度代表了该数据记录的长度,该长度为3个字节,因此,一条数据记录的最大长度为16MB。
c\记录在数据块中偏移代表了该数据记录在当前数据块内的偏移地址。
d\前一条记录偏移标示了该数据记录的前一条记录的偏移指针。
e\后一条记录偏移标示了该数据记录的后一条记录的偏移指针。
对上述非定长数据结构进行操作时,具体存储流程分为:数据块分配与回收、数据的增删改查,以及集合的创建和删除。
1、数据块分配
数据页分配时,首先从空间管理段中取得指定数据页长度的连续空间。如果空间不足则在文件末尾添加128MB字节的空间,同时,将空间管理段中相应位置的数据页标示置为1。当寻找到连续的可用空间时,即指定连续数据页的状态均为1时,将这些状态位置为2,代表空间已经分配。修改空间管理段之后,需要将寻找到的起始数据页初始化其数据块头,代表由该数据页开始,之后的若干个数据页均属于该数据块。
数据块分配后,需要将其中包含的空闲空间做成若干个空记录,放置入集合元数据的删除列表。第一步判断剩余空间的大小,然后模最大记录长度16MB,得到余数,代表最后一条不到16MB长度的数据大小,再将剩余空间除以最大记录长度,得到结果,作为最大被删除记录的数量。通过循环最大被删除记录的数量,将数据块中相应偏移的记录初始化记录头,并将其记录ID作为链表链入集合元数据中相应记录长度类型的链表中,最后,将之前取模的大小作为最后一条记录链入相应长度的集合元数据删除链表中。
此时,新的数据块被切分为一个或多个被删除记录,分别作为链表存放在集合元数据的头中。
2、数据块回收
数据页回收刚好与数据页分配相反。首先通过指定的数据块ID寻找到该块的头,校验该数据块是否与集合ID一致,并且其头是否完整;校验结束后,将数据块状态设置为2,代表其可用;最后,到空间管理段中,由数据页所对应的标示起,将其后的若干个字节状态置为1即可。
3、数据的增删改查
A、新增数据
新增数据需由用户指定集合ID与数据记录。当请求被接收后,首先需要判断记录长度是否小于16MB。如果满足要求,则将其长度加上数据记录头的长度作为总长度,从删除列表的相应槽位中取得第一条被删除记录。如果该被删除记录的长度不足以容纳新的记录,则继续循环。当循环次数超过特定上限时,则跳出循环,将比指定槽位大的槽位作为当前搜索槽,继续搜索。如果搜索槽已经为19,且无法找到合适的被删除记录,则需要创建新的数据块,在新的数据块所产生的被删除记录中放置。插入场景中,需要将新数据的前指针设置为数据块最后记录的偏移,同时修改原先最后记录,将其后指针设置为新记录,最后修改数据块头,将数据块的终结记录指针设置为新记录。
B、删除记录
删除记录时,首先找到给定记录ID,校验其所在数据块的合法性。通过记录ID,可以构建出记录头,通过头跳转到前一条记录和后一条记录。如果前后记录存在,则按照双指针元素删除的算法将前后元素链接起来,并且将被删除记录头状态置为4,并将其记录ID放入删除列表。
删除遍历记录的方式参见后续查找数据部分。
C、更新数据
更新数据需要涉及两种情况:1、新的数据小于等于原先数据的大小;2、新的数据大于原先数据的大小。
对于第一种情况,更新数据时将原本记录所占据的位置替换成新的数据即可。节省出来的空间如果能够容纳超过一条空记录,则将其切割出来作为一条空记录放入删除列表。
对于第二种情况,新的记录需要以插入的形式(但是不需更新数据块头信息)放入新的位置,并将其记录ID存放入原先记录的位置,然后对原先记录的标示修改为1,新记录位置的标示修改为2。这样,所有需要查询这条记录的请求,都可以通过原先记录位置中存放的指针,直接跳转到新记录的位置,这种类型的数据叫做溢出数据。如果原先数据被大小减去记录ID的长度超过了一条空记录,则将其截断,后续部分作为空记录放入删除列表。
搜索遍历记录的方式参见后续查找数据部分。
D、查找数据
查找数据需要指定条件与集合ID。通过集合ID,搜索程序首先根据集合ID找到元数据段中所在元数据,并得到其起始数据块ID。根据其起始数据块ID,程序首先读取其数据块头进行校验,然后在数据块内依靠初始记录偏移找到第一条记录,以链表方式从前向后读取。当当前数据块读取结束后,则依照链表方式跳转到下一个数据块继续读取。读取的判定结果存放入缓存中以发送给请求客户端。对于更新和删除数据请求,则将匹配的记录ID发送给相应函数进行特定记录的更新和删除。
4、集合的创建
集合创建时,需要在元数据段内寻找到第一个空闲槽位,将集合名复制入相应位置,并将集合状态改为1,同时,将集合的第一与最后一个数据块ID置为-1,代表该集合为空。
5、集合的删除
删除集合时,首先要找到指定集合ID所在元数据段内的位置,并校验其状态必须为1,之后由第一个数据块ID起始,依照链表遍历的方式回收各个数据块。数据块回收后,将该元数据所在槽位的状态置为2。
上述内容只是列举了部分操作的过程,其并不代表本发明大数据页中高效存储非定长数据方法操作的全部。而本发明的保护范围,应以权利要求书为准。