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。