MappedFileQueue
前面已经介绍了RocketMQ跟存储交互的底层封装对象mappedFile
。而跟CommitLog,ConsumeQueue进行交互的并不是mappedFile
,而是对其进一步封装的MappedFileQueue
类。
属性介绍
//文件的存储路径
private final String storePath;
//映射文件大小,指的是单个文件的大小,比如CommitLog大小为1G
private final int mappedFileSize;
//并发线程安全队列存储映射文件
private final CopyOnWriteArrayList<MappedFile> mappedFiles = new CopyOnWriteArrayList<MappedFile>();
private final AllocateMappedFileService allocateMappedFileService;
//刷新完的位置
private long flushedWhere = 0;
//提交完成的位置
private long committedWhere = 0;
//存储时间
private volatile long storeTimestamp = 0;
MappedFileQueue
这个类的属性相对来说比较少,其中需要说的是,AllocateMappedFileService
类型的字段,这个对象的作用是根据情况来决定是否需要提前创建好MappedFile
对象供后续的直接使用。而这个参数是在构造MappedFileQueue
对象的时候的一个参数。只有在CommitLog
中构造时才会传入AllocateMappedFileService
,在ConsumeQueue
并没有传入。
方法介绍
构造方法
MappedFileQueue
只有一个全参构造器,分别是传入文件的存储路径storePath
,单个存储文件的大小mappedFileSize
和提前创建MappedFile
对象的allocateMappedFileService
public MappedFileQueue(final String storePath, int mappedFileSize,
AllocateMappedFileService allocateMappedFileService) {
//指定文件的存储路径
this.storePath = storePath;
//指定单个文件的大小
this.mappedFileSize = mappedFileSize;
this.allocateMappedFileService = allocateMappedFileService;
}
检查文件是否完整checkSelf
/**
* 检查文件的是否完整,检查的方式。上一个文件的起始偏移量减去当前文件的起始偏移量,如果差值=mappedFileSize那么说明文件是完整的,否则有损坏
*/
public void checkSelf() {
//检查文件组是否为空
if (!this.mappedFiles.isEmpty()) {
//对文件进行迭代,一个一个进行检查
Iterator<MappedFile> iterator = mappedFiles.iterator();
MappedFile pre = null;
while (iterator.hasNext()) {
MappedFile cur = iterator.next();
if (pre != null) {
//用当前文件的其实偏移量-上一个文件的其实偏移量 正常情况下应该等于一个文件的大小。如果不相等,说明文件存在问题
if (cur.getFileFromOffset() - pre.getFileFromOffset() != this.mappedFileSize) {
LOG_ERROR.error("[BUG]The mappedFile queue's data is damaged, the adjacent mappedFile's offset don't match. pre file {}, cur file {}",
pre.getFileName(), cur.getFileName());
}
}
pre = cur;
}
}
}
这里检查文件是否被破坏的原理,就是检查文件的大小是不是等于前一个文件的起始偏移量和后一个文件的起始偏移量是不是等于文件大小。而这里的起始偏移量又是在MappedFile
进行获取的fileFromOffset
,而这个值就是我们在构造MappedFile
的时候传入的文件名转化得到的
private void init(final String fileName, final int fileSize) throws IOException {
//根据文件的名称计算文件其实的偏移量
this.fileFromOffset = Long.parseLong(this.file.getName());
}
加载文件load
public boolean load() {
/**
*System.getProperty("user.home") + File.separator + "store" + File.separator + 文件名
* 根据传入的文件保存路径storePath 来获取文件
*/
File dir = new File(this.storePath);
File[] files = dir.listFiles();
//文件列表不为空则进行加载
if (files != null) {
// ascending order
//对文件进行排序
Arrays.sort(files);
for (File file : files) {
//队列映射文件的大小不等于设置的文件类型的大小,说明加载到了最后的一个文件 比如 如果是commitLog那么对于的大小应该为1G
if (file.length(