如何使用mmap做反複擦除一塊page cache寫入
之前參加天池比賽時,有用到mmap相關的技術,今天簡單聊一聊
先說說page cache的特性
- 預讀(如myslq、卡夫卡、rocketmq都有用到預讀)
- 檔案一緻性(大部分中間件都會用的,保證出現意外崩潰的時候可以恢複)
本次比賽要求:
評測程式會并發寫入特定資料(key 8B、value 4KB)同時進行任意次kill -9來模拟程序意外退出(參賽引擎需要保證程序意外退出時資料持久化不丢失),接着重新打開DB,調用Read、Range接口來進行正确性校驗。
1 随機寫入:64個線程并發随機寫入,每個線程使用Write各寫100萬次随機資料(key 8B、value 4KB)。
2 随機讀取:64個線程并發随機讀取,每個線程各使用Read讀取100萬次随機資料。
3 順序讀取:64個線程并發順序讀取,每個線程使用Range全局順序疊代DB資料2次
本次就大緻講解下随機寫入用到的mmap吧
簡單了解題意哈,固定大小的随機key,value資料,思路就是分桶,計算一下key的大小:
總大小:(4k+8byte)64100w=256G
假如分1024個桶,每個桶大約250M,如何随機、高效去分桶,這是第一個難點,下一篇文章講解一下。
// 能了解的大佬求放過
public int partition(byte[] key) {
int result = ((0x03 & (key[0] >>> 6))) << 8;
int subResult = ((0x3F & key[0]) << 2);
int lastResult = 0x03 & (key[1] >>> 6);
return
我們key除了存本身的資料也要存value的索引,用幾個位元組來表示100w呢?
很明顯:1個位元組能辨別0~255,2個位元組是0到65535;(有符号),4個位元組是0到4294967295;(有符号)
那最終key = 8B + 4B , value = 4k
100w的key大約: 12B * 64 * 100w = 768M
因為寫入key、value分别寫需要加鎖
這裡key存儲用的是mmap,申請的空間是12byte << 16, 剛好能容納每個分片的大小 767M/1024 = 750k
好處就是
- 減少一次記憶體拷貝
- 保證一緻性,因為會進行kill -9
以下就是反複擦除核心邏輯code
// 初始化一個mmap
public MmapLogWriter(File file) throws IOException {
requireNonNull(file, "file is null");
this.file = file;
this.fileChannel = new RandomAccessFile(file, "rw").getChannel();
//TODO append position should be file size mmap
mappedByteBuffer = fileChannel.map(FileChannel.MapMode.READ_WRITE, 0, PAGE_SIZE);
}
// 追加資料-》此緩沖區中剩餘的元素數不足,就ummap重新再配置設定map
private void ensureCapacity(int throws IOException {
// 此緩沖區中剩餘的元素數不足,就ummap重新再配置設定map
if