‹ Back to Video Series: Get Started with Persistent Memory Programming

Persistent Memory Programming Part 5: A C++ Example

  • Overview
  • Resources
  • Transcript

Andy Rudoff is a Non-volatile Memory Software Architect at Intel Corporation and a member of the SNIA (Storage Networking Industry Association) Non-volatile Memory Programming Technical Work Group. In this video, Andy walks through a C++ example that implements a persistent memory-resident queue. The “libpmemobj” library is used to create transactional updates to the queue. Andy describes the code first and then runs the example program (taken from the NVM Libraries GitHub repo) and shows how it works.

Hi, I'm Andy Rudolph from Intel. Persistent memory programming is made easier by the open source NVM libraries. In this video, we will show a simple C++ example using the NVM libraries to create a persistent memory resident queue data structure. Let's start off by creating a C++ program to implement the queue example. I'll walk through an example from the Git Hub link in the description below, we'll skip to the interesting parts. 

Let's start by creating the class pmem queue, which will contain the head and tail pointers. Notice the persistent pointer template wrapping the type name here. That declares pointers to objects in persistent memory. Normal C++ pointers can't point directly into persistent memory, you have to use persistent pointer instead. This prevents programming errors when persistent and volatile data structures are used together. 

Next, we'll define the struct pmem entry that gets allocated each time a new element is added to the queue. Since the queue elements are stored as a linked list we need to use the persistent pointer template again here to provide a link to the next entry in the queue. Each entry also contains a value which is a uint64t. Since that value is persistent memory resident we indicate that to the library using the p template, as I've shown here. 

When our example program opens the pmem pool it provides a layout name which is just a string used by the program to name the contents of the pmem pool. The layout name is checked to ensure it matches the layout name used when creating the pmem pool. Power open call also includes the type of the root object. That allows the get root method, I'm showing here, to know the type of the root object when it locates it. 

After executing this line the queue variable points to the root object in the persistent memory pool. Our example program next decides whether it should push a new value on the queue, pop an existing value of, or display the entire queue contents based on the command line arguments that were given when it was run. 

Now let's examine the code that adds a new entry to the queue. We need this code to be transactional, so it either executes fully or not at all in the face of failure. This is done using the C++ lambda syntax I show here. A lambda is a nameless function and the code for it is within these curly braces. Everything between the curly braces is part of the transaction, that includes the persistent memory allocation done by make persistent. If the transaction is interrupted any persistent memory allocations, or freeze, are rolled back automatically by the library along with any other changes made to persistent memory data structures. 

Here you see the allocation, the initialization of the entry fields, and the updating of the head and tail pointers all happening as a single transaction in persistent memory. Popping an element off the queue is done transactional in a similar fashion. Notice how we can abort the transaction at runtime if we detect something wrong. The abort will roll back the transaction just as a program crash would. 

When the example program is built we can create a pmem pool file and run the program. First, let's create the pmem pool as I describe in another video in this playlist. Notice the layout name provided matches the layout expected by the example program. The queue is empty, initially. Here you see me adding multiple items to the queue and popping them back off with the queue contents preserved between runs by the persistent memory. 

The full queue example and many more examples are available in the NVML examples directory. Remember to refer to the pmem.io website for more detailed examples in both C and C++.