概述
这一层包含MappedFileQueue、MappedFile、MappedByteBuffer,其中MappedFileQueue在介绍CommitLog的时候已经讲过了,可以参考CommitLog。MappedFile对应着磁盘上的存储文件,同时也是MappedByteBuffer的封装,消息存储跟磁盘、内存的交互都是通过它完成。
属性介绍
// 默认页大小
public static final int OS_PAGE_SIZE = 1024 * 4;
protected static final InternalLogger log = InternalLoggerFactory.getLogger(LoggerName.STORE_LOGGER_NAME);
// jvm映射虚拟内存总大小
private static final AtomicLong TOTAL_MAPPED_VIRTUAL_MEMORY = new AtomicLong(0);
// jvm中mmap数量
private static final AtomicInteger TOTAL_MAPPED_FILES = new AtomicInteger(0);
// 当前写文件位置
protected final AtomicInteger wrotePosition = new AtomicInteger(0);
// 提交位置
protected final AtomicInteger committedPosition = new AtomicInteger(0);
// 刷盘位置
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.
*/
protected ByteBuffer writeBuffer = null;
// 暂存池
protected TransientStorePool transientStorePool = null;
private String fileName;
// 映射起始偏移量
private long fileFromOffset;
// 映射文件
private File file;
// 映射的内存对象
private MappedByteBuffer mappedByteBuffer;
// 最后一条消息保存时间
private volatile long storeTimestamp = 0;
private boolean firstCreateInQueue = false;
方法介绍
初始化
public void init(final String fileName, final int fileSize,
final TransientStorePool transientStorePool) throws IOException {
init(fileName, fileSize);
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);
// 文件名为起始offset
this.fileFromOffset = Long.parseLong(this.file.getName());
boolean ok = false;
ensureDirOK(this.file.getParent());
try {
// fileChannel
this.fileChannel = new RandomAccessFile(this.file, "rw").getChannel();
// mmap
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("create file channel " + this.fileName + " Failed. ", e);
throw e;
} catch (IOException e) {
log.error("map file " + this.fileName + " Failed. ", e);
throw e;
} finally {
if (!ok && this.fileChannel != null) {