You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 2 Next »

文件存储模块,向MetadataDiskManager提供MetaFile接口,目前文件读写的主要实现逻辑在MTreeFile中。提供MNode在文件中的read、write以及remove等功能接口。

1. 文件格式设计

1.1. 文件整体设计

文件整体采用定长记录的组织方式,即一个定长的Header+定长Node序列。Header中存储文件的描述性信息,Node中存储MNode的序列化信息。

MTreeFile.png

Header中目前的字段信息如下表所示。

字段名类型大小描述
header lengthbyte1 byte文件头的长度,1byte 可保证 256 个字节的存储,已足够当前 header 的信息存储,当前的header使用64 byte
node lengthshort2 byte一个节点记录的长度,2 byte长度可保证65536个字节的存储,目前代码中多使用512B或1024B,实验表明类似sg1、sg2、d1、d2这种的简单命名,1KB的Node大小可支撑100个子节点
root positionlong8 byte根节点的地址
first free positionlong8 byte第一个空闲空间的地址,node记录的删除通过首部的bitmap标志位置为0进行软删除,空闲空间内存储下一个空闲空间的地址,即这些空闲空间被组织为链表,可以快速取用
reserved

保留字段

1.2. Node设计

MNode对象的序列化信息在MTree文件中,以定长Node记录链表的形式进行存储。Node记录中的信息包含两个部分,Node Header与 data body, 其中Node Header包含bitmap、pre position、extension position三个字段。Node记录有如下几种类型:

  1. Root Node,根节点。

  2. Internal Node,中间节点记录形式,主要存储name、parent、children等结构信息。

  3. StorageGroup Node,在中间节点的基础上额外存储一个dataTTL字段。

  4. Entity Node,实体节点,在中间节点基础上额外存储aliasChildren、template、LastCacheMap等信息。

  5. StorageGroupEntity Node,实体节点与存储组节点的结合形式,为二者信息取并集。

  6. Measurement Node,在中间节点的基础上额外存储alias、tagOffset、schema以及lastCache信息。

  7. Extension Node,每个Node记录内依次存储字段信息,如果一个Node记录空间不够,则开额外的Extension Node进行使用,即MNode对象的序列化信息被组织成链表进行存储。

Internal Node的格式如下:

字段

描述

长度

内容

Header

bitmap

1 byte

1-3位用于标识类别

Pre position

8 byte

若Node不是Extension Node,则表示父节点地址,Extension Node的此位表示链表前置Node的地址

Next position

8 byte

链表中下一个Extension Node的地址

Body



Name

var

MNode节点名,String的存储一律采用length+content的形式,其中length采用varInt类型,content采用byte[]

templateName

var

模板名

children




size

var




子节点map,存储采用键值对序列的形式,其中name采用string格式,表示子节点名,position采用long,表示子节点地址,最后一个end tag 即1 byte的 00000000 表示map结束



name

position

......

name

position
end tag1 byte 标识当前Node数据的结束,下一个字段的数据需要从下一个extension node进行读取

StorageGroup Node的格式如下:

字段

描述

长度

内容

Header

bitmap

1 byte

1-3位用于标识类别

Pre position

8 byte

若Node不是Extension Node,则表示父节点地址,Extension Node的此位表示链表前置Node的地址

Next position

8 byte

链表中下一个Extension Node的地址

Body







Name

var

MNode节点名,String的存储一律采用length+content的形式,其中length采用varInt类型,content采用byte[]

dataTTL

8 byte

存储组中的数据生存时间

templateName

var

模板名

children




sizevar intchild数量

name

position

var



子节点map,存储采用键值对序列的形式,其中name采用string格式,表示子节点名,position采用long,表示子节点地址,最后一个end tag 即1 byte的 00000000 表示map结束



......

name

position

end tag1 byte 标识当前Node数据的结束,下一个字段的数据需要从下一个extension node进行读取


EntityMNode

字段

描述

长度

内容

Header

bitmap

1 byte

1-3位用于标识类别

Pre position

8 byte

若Node不是Extension Node,则表示父节点地址,Extension Node的此位表示链表前置Node的地址

Next position

8 byte

链表中下一个Extension Node的地址

Body










Name

var

MNode节点名,String的存储一律采用length+content的形式,其中length采用varInt类型,content采用byte[]

templateName

var

模板名

children

size

var

子节点map,存储采用键值对序列的形式,其中name采用string格式,表示子节点名,position采用long,表示子节点地址,最后一个end tag 即1 byte的 00000000 表示map结束

name

position

......

name

position

aliasChildren

size

var




子节点别名map,存储方式与children相同

name

position

......

name

position

end tag1 byte 标识当前Node数据的结束,下一个字段的数据需要从下一个extension node进行读取


StorageGroupEntityMNode

字段

描述

长度

内容

Header

bitmap

1 byte

1-3位用于标识类别

Pre position

8 byte

若Node不是Extension Node,则表示父节点地址,Extension Node的此位表示链表前置Node的地址

Next position

8 byte

链表中下一个Extension Node的地址

Body











Name

var

MNode节点名,String的存储一律采用length+content的形式,其中length采用varInt类型,content采用byte[]

dataTTL

8 byte

存储组中的数据生存时间

templateName

var

模板名

children

size

var

子节点map,存储采用键值对序列的形式,其中name采用string格式,表示子节点名,position采用long,表示子节点地址,最后一个end tag 即1 byte的 00000000 表示map结束

name

position

......

name

position

aliasChildren

size

var




子节点别名map,存储方式与children相同


name

position

......

name

position

end tag1 byte 标识当前Node数据的结束,下一个字段的数据需要从下一个extension node进行读取


Measurement Node的格式如下:

字段

描述

长度

内容

Header

bitmap

1 byte

1-3位用于标识类别

Pre position

8 byte

若Node不是Extension Node,则表示父节点地址,Extension Node的此位表示链表前置Node的地址

Next position

8 byte

链表中下一个Extension Node的地址

Body










Name

var

MNode节点名,String的存储一律采用length+content的形式,其中length采用varInt类型,content采用byte[]

alias

var

Measurement MNode节点别名

tagOffset

8 byte

标签/属性信息在TagFile中的位置

schema

type


1 byte

数据类型

encoding


1 byte

编码方式

compressor


1 byte

压缩方式

props

key

value

var




压缩参数

key

value

......

End tag

end tag 1 byte标识当前Node数据的结束,下一个字段的数据需要从下一个extension node进行读取


2. 文件读写功能设计

目前的文件读写功能的实现主要分三个层次

  1. MetaFile 层。对外接口为 MetaFileAccess,提供基于存储信息的 MNode 文件读写功能,主要负责交互逻辑的处理,与外部交互所使用的数据类为PersistenceInfo。目前的一个具体实现为 MetaFile 类。

  2. MTreeFile 层。实现基于地址的 MNode 文件读写功能,包括MNode序列化和反序列化、基于地址的节点读写、节点删除与文件空闲空间管理等功能。文件二进制数据的读取和写入通过调用 SlottedFile 层进行实现。

  3. SlottedFile 层。对外接口为 SlottedFileAccess,提供基于地址和长度的二进制数据读取功能。实现文件头加定长记录序列的这种格式的文件数据读写,以块为数据传输单位进行文件读写。目前的一个实现为 SlottedFile 类。

metafile_class.png


2.1. MNode读取

目前的MNode读取以寻址读取为主。在获取到MNode的存储地址后,直接对文件对应位置的序列化数据进行读取,主要分为以下几个步骤:

  1. 获取二进制数据:首先读取第一个Node的bitmap中的节点类型,将文件中的Node链表中的每个Node的data body读取为完整的ByteBuffer。
  2. 反序列化:基于节点类型创建对应的对象,依次读取ByteBuffer中的字段信息。

2.2. MNode写入

MNode对象的创建与修改,都以写入的方式在文件中实现。MNode的写入分以下两个步骤:

  1. 序列化:按照MNode在文件中的字段存储顺序,将所有属性信息序列化为一个ByteBuffer。
  2. 二进制数据分割与写入:将1中得到的ByteBuffer,根据文件Node的data body长度进行分割,分割过程中给每一个Extension Node分配空闲空间,数据分割与地址分配完成后,进行数据写入


2.3. Node跨页读写

针对链表型的二进制数据,设计合理的数据结构,数据从磁盘读进内存时直接读入该数据结构并自动实现切割。

该数据结构需支持跨块/跨Node字段的二进制数据组合读取和分割写入:? 每个Node结尾设置end tag,表示该页已结束,需要使用下一页。

该数据结构可避免序列化数据的切割和二次copy。


2.4. 文件整理

上层执行节点删除后,其父节点中指向该节点的指针被清除,意味着该子树的存储空间不会再被访问,成为文件内碎片


2.5. 文件地址管理

文件地址管理包括地址预分配,出现删除操作后的空闲地址维护

每一个MNode在MTree上创建时,地址预分配保证了后期刷盘的父节点地址与子节点地址信息完整性。

  • No labels