天天看點

如何使用mmap做反複擦除一塊page cache做讀寫

如何使用mmap做反複擦除一塊page cache寫入

之前參加天池比賽時,有用到mmap相關的技術,今天簡單聊一聊

先說說page cache的特性

  1. 預讀(如myslq、卡夫卡、rocketmq都有用到預讀)
  2. 檔案一緻性(大部分中間件都會用的,保證出現意外崩潰的時候可以恢複)

本次比賽要求:

評測程式會并發寫入特定資料(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

好處就是

  1. 減少一次記憶體拷貝
  1. 保證一緻性,因為會進行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