Indexfile的文件存储结构
Index File Struct
Indexfile的逻辑关系
一个文件大小约400M
Table 1 Index File关系图
使用messagekey查询
IndexFile:消息的索引文件,存储消息Key与Offset的对应关系。
如果一个消息包含key值的话,会使用IndexFile存储消息索引,文件的内容结构如图:
消息索引。是否建立索引可以通过配置文件配置。
索引文件主要用于根据key来查询消息的
创建过程:
将消息索引键与消息偏移量映射关系写入到IndexFile的实现方法名称:
public boolean putKey(final String key, final long phyOffset, final long storeTimestamp)
S1:向IndexFile中写入索引消息
if (this.indexHeader.getIndexCount() < this.indexNum) {
int keyHash = indexKeyHashMethod(key);
int slotPos = keyHash % this.hashSlotNum;
int absSlotPos = IndexHeader.INDEX_HEADER_SIZE + slotPos * hashSlotSize;
}
如果已使用条目小于最大条目,索引文件满,返回false。否则计算hash。
根据Key计算hashcode,计算公式是String自带的。
s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]
使用 int 算法,这里 s[i] 是字符串的第 i 个字符,n 是字符串的长度,^ 表示求幂。空字符串的哈希值为 0。
keyHash 对哈希槽数量(hashSlotNum)取余,即hashcode对应的hash槽下标。
最后计算物理地址等于index头部(固定的40字节) +hash槽大小*逻辑下标。
S2:读取槽存储数据
如果值小于等于0,表示消息第一次创建索引
如果大于0,表示索引存在。
int slotValue = this.mappedByteBuffer.getInt(absSlotPos);
if (slotValue <= invalidIndex || slotValue > this.indexHeader.getIndexCount()) {
slotValue = invalidIndex; }
S3:更新时间戳
S4:将详细信息存储到IndexFile中
int absIndexPos =
IndexHeader.INDEX_HEADER_SIZE + this.hashSlotNum * hashSlotSize
+ this.indexHeader.getIndexCount() * indexSize;
this.mappedByteBuffer.putInt(absIndexPos, keyHash);
this.mappedByteBuffer.putLong(absIndexPos + 4, phyOffset);
this.mappedByteBuffer.putInt(absIndexPos + 4 + 8, (int) timeDiff);
//冲突的hash值得上一个消息的索引index,即获取的slotvalue
this.mappedByteBuffer.putInt(absIndexPos + 4 + 8 + 4, slotValue);
//将当前的槽的当前索引index值存入槽的位置,槽中值始终保持最新
this.mappedByteBuffer.putInt(absSlotPos, this.indexHeader.getIndexCount());
S5:累计更新文件索引头信息。如果是第一条信息,更新开始时间。
根据索引Key查找信息的实现:
public void selectPhyOffset(final List<Long> phyOffsets, final String key, final int maxNum,
final long begin, final long end, boolean lock)
S1:计算方法跟putkey的S1相同。获取到对应的hash槽中存储的条目的数据索引。如果没有数据条目直接返回。
S2:循环查找hash冲突,根据slotvalue定位到Hash槽最新的一个条目,然后依次查找上一条index。