根据索引信息进行存储,索引信息通过哈希表(并使用缓存淘汰算法)进行存储。
索引信息包括:
1. 数据起始的文件偏移位置
2. 数据的长度
数据被分为key
与data
两份文件进行存储,其中key
存储的是索引信息(一个哈希表对象);data
存储的是多个缓存对象。如下图所示(理想情况「无磁盘碎片」)。
一个对象被持久化到磁盘中会有一个len
值(占用4 byte)与一个data
byte数组(占用len byte)。
因为写入磁盘是比较浪费性能的操作,所以可以通过相关配置来决定什么时候需要执行写入磁盘的操作。
-
DiskUsagePattern.UPDATE
&& Put执行Put操作时,并且当前缓存实例是实时更新状态,即会向磁盘中持久化缓存。
-
DiskUsagePattern.SWAP
&&dispose()
orfreeMemoryCache()
执行了销毁操作(
dispose()
)或释放内存中的缓存操作(freeMemoryCache()
)时,并且当前缓存实例是非实时更新,即会向磁盘中持久化缓存。
存在相同Key则可以在其原有位置进行更新(旧空间容得下新缓存情况下);或删除其旧的数据,插入新数据。
可以借助回收站(见下文,磁盘碎片利用与整理-回收站)来更好地利用磁盘空间。
-
缓存实例初始化时,根据配置文件到指定目录进行读取数据。
-
在
MemCache
中不存在该Key缓存的时候,而磁盘中存在时,则需要进行。
从哈希表中检索该索引信息,然后根据索引信息,根据文件偏移量,进行相关的==数据校验==与读取。
因为file xxx.key
文件中仅仅存放一个Map实例,数据的起始偏移量则为0,数据的长度则可以通过file.length - 4
得到;根据偏移量信息,很容易还原磁盘索引信息的K-V数据。
根据还原之后的索引信息,我们可以容易地得到对应的缓存数据。
数据存储需要具备数据校验功能,用于检查数据文件是否损坏,是否被篡改。
每一块数据的前4个字节(HEADER_SIZE_BYTES
)是一个int值,存放着数据的长度;若该表示的数据长度与索引信息中的数据长度信息不一致,则证明数据是有问题的。
回收站,即存放已经不使用的磁盘空间(磁盘碎片)。
磁盘碎片由主动移除缓存产生,或者由缓存淘汰算法进行淘汰产生。
在往磁盘中持久化一个缓存时,若从回收站中找到一个空间大小略大于或者等于该位置的空间大小时,则可以将该块空间加以重新利用。
- 将索引信息通过排序规则(文件偏移量小的优先),返回一个索引列表;
- 取出第一个索引信息,对比理想的偏移地址与当前索引所在的偏移地址,若偏移地址不同,则表明有磁盘碎片,需要移动该索引指向位置的数据到理想的偏移地址处;通过理想的文件偏移地址加上索引信息中的长度,即得到下一个理想的偏移地址,重复此操作直至列表为空。