PMDK Programming Guidelines  
        
      
     
    
   
  libpmemobj 在使用 libpmemobj 库时,不需要直接使用 mmap。libpmemobj 提供了高级的 API 来管理持久内存池和分配内存。mmap 通常用于更底层的内存映射操作,而 libpmemobj 封装了这些操作,使得管理持久内存更加方便和安全。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 #include  <libpmemobj.h>  #include  <iostream>  #include  <cassert>  #include  <cstring>  #include  <unistd.h>  #include  <stdlib.h>  #include  <stdio.h>  void  init_pmem ()   {         const  char  *pool_name = "/mnt/pmem0/matianmao/fast_fair.data" ;     const  char  *layout_name = "fast_fair" ;     size_t  pool_size = 64LL  * 1024  * 1024  * 1024 ;      if  (access (pool_name, 0 )) {         pmem_pool = pmemobj_create (pool_name, layout_name, pool_size, 0666 );         if  (pmem_pool == nullptr ) {             std::cout << "[FAST FAIR]\tcreate fail\n" ;             assert (0 );         }         std::cout << "[FAST FAIR]\tcreate\n" ;     } else  {         pmem_pool = pmemobj_open (pool_name, layout_name);         std::cout << "[FAST FAIR]\topen\n" ;     }     std::cout << "[FAST FAIR]\topen pmem pool successfully\n" ; } void  *allocate (size_t  size)   {         void  *addr;          PMEMoid ptr;          int  ret = pmemobj_zalloc (pmem_pool, &ptr, sizeof (char ) * size, TOID_TYPE_NUM (char ));     if  (ret) {         std::cout << "[FAST FAIR]\tallocate btree successfully\n" ;         assert (0 );     }          addr = (char  *)pmemobj_direct (ptr);          return  addr; } 
 
1️⃣ 使用 libpmemobj 库函数读写持久内存的示例代码 libpmemobj_pmem.cpp  (without mmap —— 封装📦好了):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 #include  <libpmemobj.h>  #include  <iostream>  #include  <cassert>  #include  <cstring>  #include  <unistd.h>  #include  <stdlib.h>  #include  <stdio.h>  PMEMobjpool *pmem_pool; #define  TOID_TYPE_NUM_CHAR 1 void  init_pmem ()   {         const  char  *pool_name = "/mnt/pmem1/libpmemobj_pmem" ;     const  char  *layout_name = "fast_fair" ;          size_t  pool_size = 16LL  * 1024  * 1024  * 1024 ;          if  (access (pool_name, 0 )) {                  pmem_pool = pmemobj_create (pool_name, layout_name, pool_size, 0666 );         if  (pmem_pool == nullptr ) {             std::cout << "[FAST FAIR]\tcreate fail\n" ;             assert (0 );         }         std::cout << "[FAST FAIR]\tcreate\n" ;     } else  {                  pmem_pool = pmemobj_open (pool_name, layout_name);         if  (pmem_pool == nullptr ) {             std::cout << "[FAST FAIR]\topen fail\n" ;             assert (0 );         }         std::cout << "[FAST FAIR]\topen\n" ;     }     std::cout << "[FAST FAIR]\topen pmem pool successfully\n" ; } void  *allocate (size_t  size)   {         void  *addr;          PMEMoid ptr;          int  ret = pmemobj_zalloc (pmem_pool, &ptr, sizeof (char ) * size, TOID_TYPE_NUM_CHAR);     if  (ret) {         std::cout << "[FAST FAIR]\tallocate fail\n" ;         assert (0 );     }          addr = pmemobj_direct (ptr);          return  addr; } int  main ()   {         init_pmem ();          void  *pmem_addr = allocate (1024 );     std::cout << "[FAST FAIR]\tallocated 1024 bytes at "  << pmem_addr << "\n" ;          strcpy ((char  *)pmem_addr, "Hello, Persistent Memory!" );     std::cout << "[FAST FAIR]\tdata written: "  << (char  *)pmem_addr << "\n" ;          pmemobj_close (pmem_pool);     std::cout << "[FAST FAIR]\tpmem pool closed\n" ;     return  0 ; } 
 
编译命令:
1 2 $ g++ -o libpmemobj libpmemobj_pmem.cpp -lpmemobj $ ./libpmemobj 
 
mmap 2️⃣ 如果不使用 libpmemobj 库函数来读写持久内存(PM),你可以直接使用 mmap 函数将持久内存映射到虚拟地址空间,然后通过指针操作进行读写。以下是一个示例代码 mmap_pmem.cpp  ,展示了如何使用 mmap 来读写持久内存:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 #include  <fcntl.h>  #include  <sys/mman.h>  #include  <unistd.h>  #include  <iostream>  #include  <cstring>  #include  <cassert>  #define  PMEM_FILE_PATH "/mnt/pmem1/mmap_pmem"  #define  PMEM_FILE_SIZE (16LL * 1024 * 1024 * 1024)  void * pmem_addr = nullptr ;int  pmem_fd = -1 ;void  init_pmem ()   {         pmem_fd = open (PMEM_FILE_PATH, O_RDWR | O_CREAT, 0666 );     if  (pmem_fd < 0 ) {         std::cerr << "Failed to open or create PMEM file"  << std::endl;         exit (1 );     }          if  (ftruncate (pmem_fd, PMEM_FILE_SIZE) != 0 ) {         std::cerr << "Failed to set PMEM file size"  << std::endl;         close (pmem_fd);         exit (1 );     }          pmem_addr = mmap (nullptr , PMEM_FILE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, pmem_fd, 0 );     if  (pmem_addr == MAP_FAILED) {         std::cerr << "Failed to mmap PMEM file"  << std::endl;         close (pmem_fd);         exit (1 );     }     std::cout << "PMEM initialized successfully"  << std::endl; } void  close_pmem ()   {    if  (pmem_addr != nullptr ) {         munmap (pmem_addr, PMEM_FILE_SIZE);         pmem_addr = nullptr ;     }     if  (pmem_fd >= 0 ) {         close (pmem_fd);         pmem_fd = -1 ;     }     std::cout << "PMEM closed successfully"  << std::endl; } int  main ()   {         init_pmem ();          void * data_addr = static_cast <char *>(pmem_addr) + 1024 ;     std::cout << "Allocated 1024 bytes at "  << data_addr << std::endl;          strcpy (static_cast <char *>(data_addr), "Hello, Persistent Memory!" );     std::cout << "Data written: "  << static_cast <char *>(data_addr) << std::endl;          close_pmem ();     return  0 ; } 
 
pmem_map_file 3️⃣ 调用 pmem_map_file 函数来映射 PM,pmem_map_file 是 libpmem 库中的一个函数,用于将持久内存文件映射到虚拟地址空间。示例代码 pmem.c   如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 #include  <fcntl.h>        #include  <unistd.h>       #include  <sys/types.h>    #include  <sys/stat.h>     #include  <libpmem.h>      #include  <stdio.h>  #include  <stdlib.h>  #define  PMEM_SIZE 1024 #define  PMEM_FILE "/mnt/pmem1/pmem_file"  int  main ()   {         int  fd = open (PMEM_FILE, O_RDWR | O_CREAT | O_TRUNC, 0666 );     if  (fd < 0 ) {         perror ("open" );         return  EXIT_FAILURE;     }     ftruncate (fd, PMEM_SIZE);          void  *pmem_addr = pmem_map_file (PMEM_FILE, PMEM_SIZE, PMEM_FILE_CREATE, 0666 , NULL , NULL );     if  (pmem_addr == NULL ) {         perror ("pmem_map_file" );         return  EXIT_FAILURE;     }          sprintf (pmem_addr, "Hello, Persistent Memory!" );          pmem_persist (pmem_addr, PMEM_SIZE);          printf ("%s\n" , (char  *)pmem_addr);          pmem_unmap (pmem_addr, PMEM_SIZE);     close (fd);     return  EXIT_SUCCESS; } 
 
pmem_map_file 底层封装的也是 mmap,以下是 pmem_map_file 实现的一个简化示例,具体实现可能会有所不同:
pmdk/src/libpmem/pmem.c 代码库中对 pmem_map_file 的定义 – create or open the file and map it to memory 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 #include  <libpmem.h>  #include  <sys/mman.h>  #include  <fcntl.h>  #include  <unistd.h>  #include  <stdio.h>  void  *pmem_map_file (const  char  *path, size_t  len, int  flags, mode_t  mode, size_t  *mapped_lenp, int  *is_pmemp)   {    int  fd = open (path, flags, mode);     if  (fd < 0 ) {         perror ("open" );         return  NULL ;     }     if  (len == 0 ) {         len = lseek (fd, 0 , SEEK_END);         if  (len == (size_t )-1 ) {             perror ("lseek" );             close (fd);             return  NULL ;         }     }     void  *addr = mmap (NULL , len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0 );     if  (addr == MAP_FAILED) {         perror ("mmap" );         close (fd);         return  NULL ;     }     close (fd);     if  (mapped_lenp)         *mapped_lenp = len;     if  (is_pmemp)         *is_pmemp = 1 ;      return  addr; }