RocketMQ存储之MappedFile

一、概述

RocketMQ的存储依赖于三类文件:CommitLog、ConsumeQueue、IndexFile,每类文件的具体作用可以参考官方文档,这里我们只做源码分析。三类存储文件都依赖MappedFile 来实现文件底层的数据读写。从类名可以看出:MappedFile 是通过内存映射文件来实现文件操作的,本篇我们分析MappedFile 的实现细节(version 4.8.0)。

二、实现细节

变量

我们先来看一下MappedFile 的变量:

    /**
     * 操作系统内存页大小
     */
    public static final int OS_PAGE_SIZE = 1024 * 4;
    protected static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.STORE_LOGGER_NAME);

    private static final AtomicLong TOTAL_MAPPED_VIRTUAL_MEMORY = new AtomicLong(0);

    private static final AtomicInteger TOTAL_MAPPED_FILES = new AtomicInteger(0);

    /**
     * 写位置,文件写到buffer的position
     */
    protected final AtomicInteger wrotePosition = new AtomicInteger(0);

    /**
     * 提交位置,文件提交到文件映射的内存的位置
     */
    protected final AtomicInteger committedPosition = new AtomicInteger(0);

    /**
     * flush位置,文件刷盘的位置
     */
    private final AtomicInteger flushedPosition = new AtomicInteger(0);
    protected int fileSize;
    protected FileChannel fileChannel;
    /**
     * Message will put to here first, and then reput to FileChannel if writeBuffer is not null.
     * 如果writeBuffer不是空的话,消息会先写到临时的writeBuffer中,随后才会被写到fileChannel中。
     */
    protected ByteBuffer writeBuffer = null;

    /**
     * 临时存储池,即内存池
     */
    protected TransientStorePool transientStorePool = null;
    private String fileName;
    private long fileFromOffset;
    private File file;
    /**
     * 文件内存映射的buffer
     */
    private MappedByteBuffer mappedByteBuffer;
    private volatile long storeTimestamp = 0;
    private boolean firstCreateInQueue = false;

初始化

MappedFile的构造方法:

    public MappedFile() {
   
    }

    public MappedFile(final String fileName, final int fileSize) throws IOException {
   
        init(fileName, fileSize);
    }

    public MappedFile(final String fileName, final int fileSize,
        final TransientStorePool transientStorePool) throws IOException {
   
        init(fileName, fileSize, transientStorePool);
    }

两个有参构造方法需要需要调用init的两个重载方法来完成初始化。
init方法实现逻辑:

    public void init(final String fileName, final int fileSize,
        final TransientStorePool transientStorePool) throws IOException {
   
        init(fileName, fileSize);
        // 只有方法传入了transientStorePool存储池,成员变量writeBuffer才会被赋值
        this.writeBuffer = transientStorePool.borrowBuffer();
        this.transientStorePool = transientStorePool;
    }

    private void init(final String fileName, final int fileSize) throws IOException {
   
        this.fileName = fileName;
        this.fileSize = fileSize;
        this.file = new File(fileName);
        // 映射文件的第一个字节在组文件中的相对位置
        this.fileFromOffset = Long.parseLong(this.file.getName());
        boolean ok = false;

        ensureDirOK(this.file.getParent());

        try {
   
        	// 获取文件的channel
            this.fileChannel = new RandomAccessFile(this.file, "rw").getChannel();
            // 映射文件
            this.mappedByteBuffer = this.fileChannel.map(MapMode.READ_WRITE, 0, fileSize);
            TOTAL_MAPPED_VIRTUAL_MEMORY.addAndGet(fileSize);
            TOTAL_MAPPED_FILES.incrementAndGet();
            ok = true;
        } catch (FileNotFoundException e) {
   
            log.error("Failed to create file " + this.fileName, e);
            throw e;
        } catch (IOException e) {
   
            log.error("Failed to map file " + this.fileName, e);
            throw e;
        } finally {
   
            if (!ok && this.fileChannel != null) {
   
                this.fileChannel.close();
            }
        
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值