intel持久性内存峰会学习篇3
PMDK essentials
part2
介绍的主要内容
- 持久性存储开发工具详细介绍
开发工具模型介绍
flushing, transactions, allocation
- 有了之前章节的介绍,我们需要让数据变得持久化。首先我们就需要在pmem中建立和文件之间的映射。
1
2
3
4
5
6
7
8
9
10
11if((pmemaddr = pmem_map_file(argv[2],BUF_LEN, PMEM_FILE_CREATE | PMEM_FILE_EXCL, 0666, &mapped_len, &is_pmem)) == NULL){
perror("pmem_map_file");
exit(1);
}
if(is_pmem){ //如果是持久性内存,就会清空cache行
pmem_memcpy_persist(pmemaddr, buf, cc);
}
else{ //如果不是就调用基本的memcpy api
memcpy(pmemaddr, buf, cc);
pmem_msync(pmemaddr, cc);
} - 如果在执行persist操作的过程中遇到了系统中断,接下来分析这种情况:
1
2
3
4
5
6
7
8
9
10
11open(...);
mmap(...);
strcpy(pmem, "Hello World!");
pmem_persist(pmem, 14);
/*****flush操作并不是原子性的,可能会遇到的情况******/
1. "\0\0\0\0\0\0\0\0\0..."
2. "Hello, W\0\0\0\0..."
3. "\0\0\0\0\0\0\0\0orld!\0"
4. "Hello,\0\0\0\0\0\0\0\0"
5. "Hello, World!\0" - 为了避免以上出现的情况,于是intel开发出了libpmemobj库来引入原子性操作避免以上的情况:
- libpmemobj库提供了原子性操作能够保证持久化的过程变成像事务类型一样要么全部执行成功,要么全部执行失败。同时这个库也保证了数据的一致性,能够让多个事务同时访问一个数据池。在一个事务中你可以完成的事情:分配新的对象,释放掉旧的对象,修改掉已经存在的对象,丢弃对象。
- libpmemobj库的内存分配设计:分配器的元数据存储在dram中
- libpmemobj库原子性api:内存分配分成两个步骤:1.选择一个内存块进行分配2.把分配的内存用一个指针指向。如果这个时候应用终止,如果是dram并不会发生什么,但是如果是持久性内存,就会发生内存泄露,因为这次分配的存储空间再也无法访问了。但是在libpmemobj库中就直接把这两个步骤合并成了一步并提供了一个api:pmemobj_alloc()。这样就避免了内存泄漏的情况了。对于事务操作,提供了自动上锁的功能,只有当一个事务完成之后才会释放锁。
- 有了之前章节的介绍,我们需要让数据变得持久化。首先我们就需要在pmem中建立和文件之间的映射。