版本
- 基于
rocketmq-all-4.3.1
版本
IndexFile
-
IndexFile(索引文件)由
IndexHeader
(索引文件头),Slot
(槽位)和Index
(消息的索引内容)三部分构成。对于每个IndexFile
来说IndexHeader
是固定大小的,Slot是索引的目录,用于定位Index在IndexFile中存储的物理位置 -
存储图
-
slot总数系统默认500W个,slot中放的是最新index的位置,因为一般查询的时候肯定是优先查最近的消息,每个slot中放的位置值是索引在indexFile中的偏移量
-
IndexFile属性
//hash槽大小 private static int hashSlotSize = 4; //index大小 private static int indexSize = 20; private static int invalidIndex = 0; /** * 槽位,默认500w个 * 配置参见org.apache.rocketmq.store.config.MessageStoreConfig#maxHashSlotNum */ private final int hashSlotNum; /** * 默认2000w * 配置参见org.apache.rocketmq.store.config.MessageStoreConfig#maxIndexNum */ private final int indexNum; private final MappedFile mappedFile; private final FileChannel fileChannel; private final MappedByteBuffer mappedByteBuffer; private final IndexHeader indexHeader;
-
IndexHeader
属性public static final int INDEX_HEADER_SIZE = 40; private static int beginTimestampIndex = 0; private static int endTimestampIndex = 8; private static int beginPhyoffsetIndex = 16; private static int endPhyoffsetIndex = 24; private static int hashSlotcountIndex = 32; private static int indexCountIndex = 36; private final ByteBuffer byteBuffer; //第一个索引消息落在Broker的时间戳 private AtomicLong beginTimestamp = new AtomicLong(0); //最后一个索引消息落在Broker的时间戳 private AtomicLong endTimestamp = new AtomicLong(0); //第一个索引消息在commitlog的物理偏移量 private AtomicLong beginPhyOffset = new AtomicLong(0); //最后一个索引消息在commitlog的物理偏移量 private AtomicLong endPhyOffset = new AtomicLong(0); //构建索引占用的槽位数 private AtomicInteger hashSlotCount = new AtomicInteger(0); //构建的索引个数 private AtomicInteger indexCount = new AtomicInteger(1);
构造函数
-
构造函数:IndexFile也是通过MappedFile创建
public IndexFile(final String fileName, final int hashSlotNum, final int indexNum, final long endPhyOffset, final long endTimestamp) throws IOException { //文件大小=indexHeader(40Byte)+HashSlotNum(500w*4Byte)+indexNum(2000w*20Byte) int fileTotalSize = IndexHeader.INDEX_HEADER_SIZE + (hashSlotNum * hashSlotSize) + (indexNum * indexSize); this.mappedFile = new MappedFile(fileName, fileTotalSize); this.fileChannel = this.mappedFile.getFileChannel(); this.mappedByteBuffer = this.mappedFile.getMappedByteBuffer(); this.hashSlotNum = hashSlotNum; this.indexNum = indexNum; // 共享同一个byteBuffer,但是索引位置独立 ByteBuffer byteBuffer = this.mappedByteBuffer.slice(); this.indexHeader = new IndexHeader(byteBuffer); //初始化头文件的beginPhyOffset 和 endPhyOffset if (endPhyOffset > 0) { this.indexHeader.setBeginPhyOffset(endPhyOffset); this.indexHeader.setEndPhyOffset(endPhyOffset); } //初始化头文件的beginTimestamp 和 endTimestamp if (endTimestamp > 0) { this.indexHeader.setBeginTimestamp(endTimestamp); this.indexHeader.setEndTimestamp(endTimestamp); } }
putKey
-
步骤
- 计算消息key的hash
- 根据hash计算hashsolt位置,并计算solt的实际的物理位置,hashsolt中存储的是当前构建索引的总个数,也是存储的index下标(通过this.indexHeader.getIndexCount()维护)
- 获取solt上次存入的值,默认是0
- 计算当前存储index的物理位置,并存入hash、phyOffset、storeTimestamp、slotValue
-
源码
public boolean putKey(final String key, final long phyOffset, final long storeTimestamp) { //如果已经构建的索引index数量 < 最大的index数量,则进行插入,否则直接返回 false if (this.indexHe