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

Posted January 12, 2016         « Previous post     Next post »

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 *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 *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.]


Posted by @pbalcer         « Previous post     Next post »