C++ bindings for libpmemobj (part 1) - pmem resident variables

One of the biggest hurdles and error prone things about our C API is that the user has to manually keep track of modifications to the persistent memory resident variables while in a transaction. A special semi-transparent template property class has been implemented to automatically add variable modifications to the transaction undo log.

pmem::obj::p

Let’s start with the vector example from the previous tutorial series. It looked like this:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
struct vector {
int x;
int y;
int z;
}

PMEMoid root = pmemobj_root(pop, sizeof (struct vector));

struct vector </span>*vectorp = pmemobj_direct(root); TX_BEGIN(pop) { pmemobj_tx_add_range(root, 0, sizeof (struct vector)); vectorp->x = 5; vectorp->y = 10; vectorp->z = 15; } TX_END

As you can see, the programmer has to remember to call pmemobj_tx_add_range function before any modifications to the memory. In a simple case like this one it might not be such a big deal, but once the code gets complex it may lead to some difficult to find consistency issues.

By using the C++ API we can simplify this code like so:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
#include <libpmemobj/p.hpp>

using namespace pmem::obj;

struct vector { p<int> x; p<int> y; p<int> z; }

PMEMoid root = pmemobj_root(pop, sizeof (struct vector));

struct vector </span>*vectorp = pmemobj_direct(root); TX_BEGIN(pop) { vectorp->x = 5; vectorp->y = 10; vectorp->z = 15; } TX_END

The template class pmem::obj::p does not add storage overhead. The size of the vector structure is exactly the same as in the C version.

This mechanism works overriding operator= and adding the memory to the undo log before modification. It’s pretty straightforward.

[This entry was edited on 2017-12-11 to reflect the name change from NVML to PMDK.]
Share this Post:

Related Posts: