一、概述
上一篇我们分析了MappedFile的实现细节,MappedFile实现了文件内存映射的功能。本篇我们分析MappedFileQueue的实现。
MappedFileQueue的作用是:将多个MappedFile按顺序组织起来,并且提供MappedFile的“增删查”操作等作用。由于MappedFileQueue的实现逻辑并不复杂,本篇只分析一部分源码实现。
二、实现细节
首先来看一下MappedFileQueue的创建和加载:
public MappedFileQueue(final String storePath, int mappedFileSize,
AllocateMappedFileService allocateMappedFileService) {
this.storePath = storePath;
this.mappedFileSize = mappedFileSize;
this.allocateMappedFileService = allocateMappedFileService;
}
public boolean load() {
File dir = new File(this.storePath);
File[] files = dir.listFiles();
if (files != null) {
// ascending order
// 按顺序加载到队列中
Arrays.sort(files);
for (File file : files) {
if (file.length() != this.mappedFileSize) {
log.warn(file + "\t" + file.length()
+ " length not matched message store config value, please check it manually");
return false;
}
try {
MappedFile mappedFile = new MappedFile(file.getPath(), mappedFileSize);
mappedFile.setWrotePosition(this.mappedFileSize);
mappedFile.setFlushedPosition(this.mappedFileSize);
mappedFile.setCommittedPosition(this.mappedFileSize);
this.mappedFiles.add(mappedFile);
log.info("load " + file.getPath() + " OK");
} catch (IOException e) {
log.error("load file " + file + " error", e);
return false;
}
}
}
return true;
}
实现过程很简单:将指定文件夹下的所有文件都加载映射为MappedFile,然后添加到队列中。
根据时间获取MappedFile:
/**
* 获取第一个更新时间大于timestamp的MappedFile,没有的话就返回最新的MappedFile
* @param timestamp
* @return
*/
public MappedFile getMappedFileByTime(final long timestamp) {
// mappedFiles队列的副本
Object[] mfs = this.copyMappedFiles(0);
if (null == mfs)
return null;
for (int i = 0; i < mfs.length; i++) {
MappedFile mappedFile = (MappedFile) mfs[i];
if (mappedFile.getLastModifiedTimestamp() >= timestamp) {
return mappedFile;
}
}
return (MappedFile) mfs[mfs.length - 1];
}
根据更新时间获取MappedFile的实现很简单,通过遍历mappedFiles队列查找第一个修改时间大于timestamp的MappedFile对象并返回,如果没有,就返回队列中的最后一个对象。
删除大于offset的数据:
/**
*
* 删除大于offset的记录
* @param offset
*/
public void truncateDirtyFiles(long offset) {
List<MappedFile> willRemoveFiles = new ArrayList<MappedFile>();
for (MappedFile file : this.mappedFiles) {
// 当前file的最大offset
long fileTailOffset = file.getFileFromOffset() + this.mappedFileSize;
if (fileTailOffset > offset) {
// 当前文件最大的offset大于offset,说明有需要删除的记录
if (offset >= file.getFileFromOffset()) {
// 当前文件的最小offset小于等于offset,说明当前文件有部分记录需要删除
// 将MappedFile的三个指针都设置到offset对应的位置,使大于offset的数据可以被覆盖
file.setWrotePosition((int) (offset % th