这部分做的是内存回收的工作,主要目的是判断内存空间是否达到阈值,若达到阈值则应用策略回收cache中的节点以释放足够的空间。
节点回收的三部分组件:
仲裁(Arbiter),查询内存预算空间判断是否需要回收。
目标选择器(TargetSelector),选择目标节点。
回收器(Evictor),执行节点回收。
节点回收的三种线程:
1. The application thread, in the course of doing critical eviction (执行)
2. Daemon threads, such as the cleaner or INCompressor, in the course of doing their respective duties (后台守护线程)
3. Eviction pool threads (线程池)
节点回收分为两种类型PrivateEvictor和SharedEvictor,分别对应单/多Environment的情况,但是逻辑上是一样的。
内存预算通过实现。
Cache通过实现。
目标选择器通过方法selectIN在Cache中取出IN,若使用LRU策略,则挑出最低generation的节点,否则策略优先级由高到低选择:最低tree level脏数据LRU策略。选择IN时的迭代顺序没有特别定义。
对选出的IN,回收器使用方法evictRoot或evictIN回收内存。若IN是一个tree的root,若它的所有子节点都可以被回收,则它也可以被回收,若它是dirty,则需要写入磁盘。对非root的IN,找到其父节点,如果IN是dirty的,则写入磁盘并更新父节点的指针。其中,若IN是BIN,还要先做剪枝,然后将其引用的叶节点释放掉,若其中有数据需要写入磁盘,则将该BIN标记为dirty。
以下几种节点不能被回收:Mapping Tree的节点,内存中正在使用的节点的IN父节点,有游标指向的BIN节点。
Cleaner
Cleaner用来释放磁盘空间。
Cleaner的两个目标:
使migration 的开销尽可能小
Migration操作与用户的其它线程同时来做,避免clean跟不上的情况
JE的树结构中存储了系统数据库_jeUtilization,存储每个文件的利用率信息。
使用lazy migration和proactive migration策略移动节点。Lazy migration是说对LN不是立即移动,而是作以标记在下一次ckpt或者evictor的时候在写BIN时一起flush到日志里面,好处是在写一个BIN时可以尽可能多的将它引用的LN一次写入。
Cleaner做几件事情:1. 标记obsolete;2. 移动entry;3. 删除log文件。
日志中entry可能被obsolete的原因:1. 应用删除/更新了entry;2. Proactive migration主动移动了entry;3. trackDetail被置为false。
待删除文件的几种状态(为了保证文件删除时所有有效内容都被移动):
TO_BE_CLEANED,FlieSelector选出的待clean的文件被标记为该状态
BEING_CLEANED,FileProcessor选择处理的文件被标记为该状态
CLEANED,文件中所有entry被扫描和处理后文件被标记为该状态,这时entry有些未移动有些在pending队列,db也在pending队列
CHECKPOINTED,文件在一个ckpt开始时处于CLEANED状态,则在结束时会被标记为该状态,这时被标记为migrate的该移动的都移动了,但是pending的entry和db还没有处理好
FULLY_PROCESSED,当pending队列处理完时文件被标记为该状态,但此时LN的BIN还没有被重写
SAFE_TO_DELETE,文件在一个ckpt开始时处于SAFE_TO_DELETE状态,则在结束时会被标记为该状态,这个时候就可以删除了