如何使用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
unmap,sun没有自己实现,我简单实现了下,发现有问题,这里引用的lucene
svn.apache.org/repos/asf/l…