专为文件系统元数据存储的KV存储引擎MetaKV
Insert(pinode_fname,inode)
对DirTreeTable 的写请求首先访问内存中的Dir Table Cache,获取到pinode对应LogStore 指针,直接将KV 数据追加写入到LogStore 的尾部,
同时将返回的NVM 指针以及LogStore 指针写入到Full Table。如果Dir Table Cache 未命中,则访问NVM 上的Dir Table,并对缓存中的Dir Table 进行淘汰替换。
Get(pinode_fname)->inode
对DirTreeTable 的读请求首先访问内存中的Entry Cache,如果命中,则直接访问NVM 指针中存放的数据项并返回;
如果未命中则在NVM 上的哈希索引结构中进行查找和读取操作。
ReadDir(pinode)->
读取目录的请求首先访问Dir Table Cache,获取对应目录的LogStore 指针,如果Cache 不命中,则访问NVM 上的Dir Table。
扫描LogStore 来获取对应目录下所有文件名及inode 信息,在内存中维护fname->inode 的map,用以存放fname 最新版本的数据。最终将扫描得到的KV Set 返回。
空间管理
还基于Chunk 为单位,提供了顺序写入模型的数据结构LogStore 和管理定长空间的StatAllocator。写入MetaKV 的KV数据最终都写入LogStore 和StatAllocator 管理的空间中。
Gc 操作以LogStore 为单位进行扫描,回收被删除的和已经被覆盖的KV 数据。
而StatAllocator 管理的定长空间可以直接重新分配使用,不需要进行Gc 操作。
1.LogStore
LogStore 负责提供NVM 的Append 写入、读取和持久化接口。
LogStore 向POBJ 申请若干个Chunk(可设置的固定大小空间片),这些Chunk 被组织为链表结构,所有数据数据追加写入到LogStore 中,
同时GC 线程负责从LogStore 头部开始回收数据
每次通过Dir Table 访问到对应的LogStore 时,都需要对相应的bucket 进行加锁,避免GC 和Log Store 的插入产生冲突
写入操作通过竞争尾指针来向 LogStore 写入数据和分配新Chunk。
2.Stat Allocator
Stat Allocator 负责提供定长Stat 空间的分配和管理。
Stat Allocator 同样向POBJ 申请若干个Chunk,这些Chunk 被分为两类,分别使用两个链表组织。
chunk_list 记录了Stat Allocator 申请的所有Chunk
free_chunk_list 则记录了存在空闲空间的chunk。chunk_list 持久化在NVM 的元数据信息中,free_chunk_list 在重启时通过chunk_list 恢复到内存。
Stat Allocator 申请的每个Chunk 都按照stat 进行空间划分,在Chunk 头部维护了每个Chunk 中stat 空间使用情况的BitMap。
在申请空闲空间时,访问内存中的free_chunk_list,获取某一存在空闲空间Chunk 的指针。然后使用Chunk头部的BitMap 分配空闲stat 空间。
当某一个原本写满数据的Chunk(如图 Stat Allocator 中的chunk5)删除某一数据后,则将其加入到free_chunk_list。
当free_chunk_list 为空时,则申请新的Chunk,并加入到chunk_list 和free_chunk_list中。
3.GC
当系统的NVM 空间不足时,触发NVM 的空间回收
- NVM 空间受用到达一定阈值
- LogStore 中无效数据比例达到一定比例
内存中维护了每个LogStore 的有效数据比例.每次insert、update、delete操作都会更新LogStore 的有效数据比例
有效比例计算:(insert-delete)/(chunk_size*chunk_num)
在Gc 的时候对所有LogStore 的有效数据比例进行一次排序,按照从低到高的LogStore顺序进行Gc。
4.Filemata Table
File-Meta Table 基于定长版本的CCEH 实现。inode(8bytes)直接存放在Bucket 中,而128bytes 的stat 存放在StatAllocator 分配的定长空间中,Bucket 中存放了指向stat 内容的指针