Skip to content

Instantly share code, notes, and snippets.

@plebioda
Last active October 6, 2016 18:41
Show Gist options
  • Save plebioda/f1c7938e91db095fb98778df7ef5b672 to your computer and use it in GitHub Desktop.
Save plebioda/f1c7938e91db095fb98778df7ef5b672 to your computer and use it in GitHub Desktop.
LinuxCon Europe 2016: NVML tutorial
is_pmem
pmem_persist
blk
people
people_toid
people_atomic_lists
people_tx
people_list
people_cpp
people_stl
#include <stdio.h>
#include <string.h>
#include <err.h>
#include <stdlib.h>
#include <libpmemblk.h>
int
main(int argc, char *argv[])
{
if (argc < 2 || argc % 2 != 0) {
printf("usage: %s <file> [<blockno> <data>]\n", argv[0]);
return 1;
}
/* open pmemblk pool */
PMEMblkpool *pbp = pmemblk_open(argv[1], 0);
if (!pbp)
err(1, "pmemblk_open: %s", pmemblk_errormsg());
/* get block size and number of blocks */
size_t bsize = pmemblk_bsize(pbp);
size_t nblock = pmemblk_nblock(pbp);
/* allocate buffer for block operations */
char *block = malloc(bsize);
if (!block)
err(1, "!malloc");
if (argc == 2) {
printf("block size : %zu\n", bsize);
printf("number of blocks: %zu\n", nblock);
/* read all blocks and print stored strings */
for (size_t i = 0; i < nblock; i++) {
if (pmemblk_read(pbp, block, i))
err(1, "pmemblk_read: %s\n", pmemblk_errormsg());
if (strlen(block))
printf("%4zu: %s\n", i, block);
}
} else {
for (int i = 2; i < argc; i += 2) {
size_t lba = atoi(argv[i]);
strncpy(block, argv[i + 1], bsize);
if (pmemblk_write(pbp, block, lba))
err(1, "pmemblk_write: %s\n", pmemblk_errormsg());
}
}
pmemblk_close(pbp);
free(block);
return 0;
}
#include <stdio.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <unistd.h>
#include <err.h>
#include <stdlib.h>
#include <libpmem.h>
/*
* mmap_file -- memory map file and return mapped size
*/
void *
mmap_file(const char *path, size_t *size)
{
int fd = open(path, O_RDWR);
if (fd == -1)
err(1, "!open");
struct stat buf;
if (fstat(fd, &buf))
err(1, "!fstat");
*size = buf.st_size & ~(4096 - 1);
void *addr = mmap(NULL, *size, PROT_READ|PROT_WRITE,
MAP_SHARED, fd, 0);
if (addr == MAP_FAILED)
err(1, "!mmap");
close(fd);
return addr;
}
int
main(int argc, char *argv[])
{
if (argc != 2) {
printf("usage: %s <file>\n", argv[0]);
return 1;
}
size_t size;
#ifdef USE_MMAP
void *pmem = mmap_file(argv[1], &size);
#else
int is_pmem;
void *pmem = pmem_map_file(argv[1], 0, 0, 0666, &size, &is_pmem);
#endif
void *addr = malloc(size);
printf("pmem_is_pmem:\n");
printf("file : %d\n", pmem_is_pmem(pmem, size));
printf("malloc: %d\n", pmem_is_pmem(addr, size));
printf("stack : %d\n", pmem_is_pmem(&size, sizeof(size)));
return 0;
}
pmem_APPS += is_pmem
pmem_APPS += pmem_persist
pmemblk_APPS += blk
pmemobj_APPS += people
pmemobj_APPS += people_toid
pmemobj_APPS += people_list
pmemobj_APPS += people_atomic_lists
pmemobj_APPS += people_tx
pmemobj++_APPS += people_cpp
#pmemobj++_APPS += people_stl
pmemobj++_LANG = _cpp
ALL += pmem
ALL += pmemblk
ALL += pmemobj
ALL += pmemobj++
$(foreach l, $(ALL), $(eval all_APPS += $($(l)_APPS)))
default: all
all: $(all_APPS)
clean:
rm -f $(all_APPS)
CFLAGS += -std=gnu99 -O0 -ggdb
CXXFLAGS += -std=c++11 -O0 -ggdb -lstdc++
define build
$(1): $(1).c
$(CC) $(CFLAGS) $(shell pkg-config --cflags lib$(2)) -o $$@ $$< $(shell pkg-config --libs lib$(2))
endef
define build_cpp
$(1): $(1).cpp
$(CXX) $(CXXFLAGS) $(shell pkg-config --cflags lib$(2)) -o $$@ $$< $(shell pkg-config --libs lib$(2))
endef
define build_all
$(foreach app,$($(1)_APPS),$(eval $(call build$($(1)_LANG),$(app),$(1))))
endef
$(foreach l, $(ALL), $(call build_all,$(l)))
#include <stdio.h>
#include <string.h>
#include <err.h>
#include <stdlib.h>
#include <libpmemobj.h>
#define ENTRY_TYPE_NUM 1
#define MAX_NAME 16
#define MAX_PEOPLE 256
/* entry for one person */
struct entry {
size_t id;
char first_name[MAX_NAME];
char last_name[MAX_NAME];
};
/* list of people */
struct list {
size_t count;
PMEMoid people[MAX_PEOPLE];
};
/* arguments for constructor */
struct entry_args {
size_t id;
const char *first_name;
const char *last_name;
};
/* list entry constructor */
static int
entry_constr(PMEMobjpool *pop, void *ptr, void *arg)
{
struct entry *entry = ptr;
struct entry_args *args = arg;
entry->id = args->id;
strncpy(entry->first_name, args->first_name, MAX_NAME);
strncpy(entry->last_name, args->last_name, MAX_NAME);
pmemobj_persist(pop, entry, sizeof(*entry));
return 0;
}
/* insert one person to the list of people */
static int
insert(PMEMobjpool *pop, const char *first_name, const char *last_name)
{
/* get a root object */
PMEMoid root = pmemobj_root(pop, sizeof(struct list));
if (OID_IS_NULL(root))
err(1, "pmemobj_root: %s\n", pmemobj_errormsg());
struct list *list = pmemobj_direct(root);
if (list->count == MAX_PEOPLE)
err(1, "Sorry, the list is full...\n");
/* allocate new entry */
struct entry_args args = {list->count, first_name, last_name};
int ret = pmemobj_alloc(pop,
&list->people[list->count], /* PMEMoid * */
sizeof(struct entry), /* allocation size */
ENTRY_TYPE_NUM, /* type number */
entry_constr, &args); /* constructor */
if (ret)
err(1, "pmemobj_alloc: %s\n", pmemobj_errormsg());
/* increase number of people */
list->count++;
/* make the new value of people persistent */
pmemobj_persist(pop, &list->count, sizeof(list->count));
return ret;
}
/* print first and last name of given person */
static void
print_person(PMEMoid oid)
{
struct entry *entry = pmemobj_direct(oid);
printf("%2lu: %s %s\n", entry->id, entry->first_name,
entry->last_name);
}
/* list all people on the list */
static void
list(PMEMobjpool *pop)
{
PMEMoid root = pmemobj_root(pop, sizeof(struct list));
if (OID_IS_NULL(root))
err(1, "pmemobj_root: %s\n", pmemobj_errormsg());
struct list *list = pmemobj_direct(root);
printf("Number of people: %lu\n", list->count);
for (size_t i = 0; i < list->count; i++)
print_person(list->people[i]);
}
/* clear all people from the list */
static void
clear(PMEMobjpool *pop)
{
PMEMoid root = pmemobj_root(pop, sizeof(struct list));
if (OID_IS_NULL(root))
err(1, "pmemobj_root: %s\n", pmemobj_errormsg());
struct list *list = pmemobj_direct(root);
while (list->count) {
/*
* The following operations must be in appropriate order.
* Otherwise the recovery steps would be invalid.
*/
list->count--;
pmemobj_persist(pop, &list->count, sizeof(list->count));
pmemobj_free(&list->people[list->count]);
}
}
/* perform recovery */
static void
recovery(PMEMobjpool *pop)
{
PMEMoid root = pmemobj_root(pop, sizeof(struct list));
if (OID_IS_NULL(root))
err(1, "pmemobj_root: %s\n", pmemobj_errormsg());
struct list *list = pmemobj_direct(root);
if (list->count == MAX_PEOPLE)
return;
if (!OID_IS_NULL(list->people[list->count])) {
/*
* Need to perform recovery because new entry has been
* allocated but the counter has not been stored.
*/
printf("Performing recovery:\n");
print_person(list->people[list->count]);
/* increase number of people */
list->count++;
/* make the new value of people persistent */
pmemobj_persist(pop, &list->count, sizeof(list->count));
}
}
/* print usage and exit wit error */
static void
fatal_usage(char *app)
{
printf("usage: %s <file> add|list|clear [<first name> <last name>]\n", app);
exit(1);
}
int
main(int argc, char *argv[])
{
if (argc != 3 && argc != 5)
fatal_usage(argv[0]);
PMEMobjpool *pop = pmemobj_open(argv[1], "people");
if (!pop)
err(1, "pmemobj_open: %s", pmemobj_errormsg());
recovery(pop);
if (argc == 5 && strcmp(argv[2], "add") == 0) {
if (insert(pop, argv[3], argv[4]))
err(1, "insert: %s\n", pmemobj_errormsg());
} else if (argc == 3 && strcmp(argv[2], "list") == 0) {
list(pop);
} else if (argc == 3 && strcmp(argv[2], "clear") == 0) {
clear(pop);
} else {
fatal_usage(argv[0]);
}
pmemobj_close(pop);
return 0;
}
#include <stdio.h>
#include <string.h>
#include <err.h>
#include <stdlib.h>
#include <libpmemobj.h>
#define ENTRY_TYPE_NUM 1
#define MAX_NAME 16
#define MAX_PEOPLE 256
/*
* Declarations of persistent memory data structures.
* Required in order to use type safety macros.
* The type numbers are assigned automaticaly.
*/
POBJ_LAYOUT_BEGIN(people);
POBJ_LAYOUT_TOID(people, struct entry);
POBJ_LAYOUT_ROOT(people, struct list);
POBJ_LAYOUT_END(people);
/* entry for one person */
struct entry {
size_t id;
char first_name[MAX_NAME];
char last_name[MAX_NAME];
POBJ_LIST_ENTRY(struct entry) entry;
};
/* list of people */
struct list {
size_t count;
POBJ_LIST_HEAD(listhead, struct entry) head;
};
/* arguments for constructor */
struct entry_args {
size_t id;
const char *first_name;
const char *last_name;
};
/* list entry constructor */
static int
entry_constr(PMEMobjpool *pop, void *ptr, void *arg)
{
struct entry *entry = ptr;
struct entry_args *args = arg;
entry->id = args->id;
strncpy(entry->first_name, args->first_name, MAX_NAME);
strncpy(entry->last_name, args->last_name, MAX_NAME);
pmemobj_persist(pop, entry, sizeof(*entry));
return 0;
}
/* insert one person to the list of people */
static int
insert(PMEMobjpool *pop, const char *first_name, const char *last_name)
{
/* get a root object */
TOID(struct list) list = POBJ_ROOT(pop, struct list);
if (TOID_IS_NULL(list))
err(1, "POBJ_ROOT: %s\n", pmemobj_errormsg());
/* allocate new entry */
struct entry_args args = {D_RO(list)->count, first_name, last_name};
PMEMoid oid = POBJ_LIST_INSERT_NEW_TAIL(pop,
&D_RW(list)->head, /* list head */
entry, /* new entry */
sizeof(struct entry), /* allocation size */
entry_constr, &args); /* constructor */
if (OID_IS_NULL(oid))
err(1, "POBJ_LIST_INSERT_NEW_TAIL: %s\n", pmemobj_errormsg());
/* increase number of people */
D_RW(list)->count++;
/* make the new value of people persistent */
pmemobj_persist(pop, &D_RW(list)->count, sizeof(D_RO(list)->count));
return 0;
}
/* print first and last name of given person */
static void
print_person(const TOID(struct entry) entry)
{
printf("%2lu: %s %s\n", D_RO(entry)->id, D_RO(entry)->first_name,
D_RO(entry)->last_name);
}
/* list all people on the list */
static void
list(PMEMobjpool *pop)
{
TOID(struct list) list = POBJ_ROOT(pop, struct list);
if (TOID_IS_NULL(list))
err(1, "POBJ_ROOT: %s\n", pmemobj_errormsg());
printf("Number of people: %lu\n", D_RO(list)->count);
TOID(struct entry) i;
POBJ_LIST_FOREACH(i, &D_RO(list)->head, entry) {
print_person(i);
}
}
/* clear all people from the list */
static void
clear(PMEMobjpool *pop)
{
TOID(struct list) list = POBJ_ROOT(pop, struct list);
if (TOID_IS_NULL(list))
err(1, "POBJ_ROOT: %s\n", pmemobj_errormsg());
while (!POBJ_LIST_EMPTY(&D_RO(list)->head)) {
/*
* The following operations must be in appropriate order.
* Otherwise the recovery steps would be invalid.
*/
D_RW(list)->count--;
pmemobj_persist(pop, &D_RW(list)->count,
sizeof(D_RO(list)->count));
POBJ_LIST_REMOVE_FREE(pop, &D_RW(list)->head,
POBJ_LIST_LAST(&D_RO(list)->head, entry), entry);
}
}
/* perform recovery */
static void
recovery(PMEMobjpool *pop)
{
TOID(struct list) list = POBJ_ROOT(pop, struct list);
if (TOID_IS_NULL(list))
err(1, "POBJ_ROOT: %s\n", pmemobj_errormsg());
TOID(struct entry) last = POBJ_LIST_LAST(&D_RO(list)->head, entry);
if (!TOID_IS_NULL(last) && D_RO(last)->id == D_RO(list)->count) {
/*
* Need to perform recovery because new entry has been
* allocated but the counter has not been stored.
*/
printf("Performing recovery:\n");
print_person(last);
/* increase number of people */
D_RW(list)->count++;
/* make the new value of people persistent */
pmemobj_persist(pop, &D_RO(list)->count,
sizeof(D_RO(list)->count));
}
}
/* print usage and exit wit error */
static void
fatal_usage(char *app)
{
printf("usage: %s <file> add|list|clear [<first name> <last name>]\n", app);
exit(1);
}
int
main(int argc, char *argv[])
{
if (argc != 3 && argc != 5)
fatal_usage(argv[0]);
PMEMobjpool *pop = pmemobj_open(argv[1], "people");
if (!pop)
err(1, "pmemobj_open: %s", pmemobj_errormsg());
recovery(pop);
if (argc == 5 && strcmp(argv[2], "add") == 0) {
if (insert(pop, argv[3], argv[4]))
err(1, "insert: %s\n", pmemobj_errormsg());
} else if (argc == 3 && strcmp(argv[2], "list") == 0) {
list(pop);
} else if (argc == 3 && strcmp(argv[2], "clear") == 0) {
clear(pop);
} else {
fatal_usage(argv[0]);
}
pmemobj_close(pop);
return 0;
}
#include <iostream>
#include <string.h>
#include <libpmemobj++/pool.hpp>
#include <libpmemobj++/pext.hpp>
#include <libpmemobj++/transaction.hpp>
#include <libpmemobj++/make_persistent.hpp>
#include <libpmemobj++/make_persistent_array.hpp>
#include <libpmemobj++/persistent_ptr.hpp>
using namespace std;
using namespace nvml::obj;
/* persistent memory string */
struct pstring {
pstring() : pstring("") {}
~pstring() { delete_persistent<char []>(data, len); }
pstring(const string &str) {
len = str.length() + 1;
data = make_persistent<char []>(len);
strncpy(data.get(), str.c_str(), str.length());
}
persistent_ptr<char[]> data;
p<size_t> len;
};
ostream &operator<<(ostream &os, const pstring &str) {
os << str.data.get();
return os;
}
class entry {
public:
entry(size_t _id, string _first_name, string _last_name) :
first_name(_first_name), last_name(_last_name),
id(_id), next(nullptr) { }
~entry() = default;
persistent_ptr<entry> insert(persistent_ptr<entry> _next) {
next = _next;
return next;
}
persistent_ptr<entry> get_next() {
return next;
}
friend ostream &operator<<(ostream &os, const entry &e);
protected:
pstring first_name;
pstring last_name;
p<size_t> id;
persistent_ptr<entry> next;
};
ostream &operator<<(ostream &os, const entry &e) {
os << e.id << ": " << e.first_name << " " << e.last_name << endl;
return os;
}
class list {
public:
void print(void);
void insert(string first_name, string last_name);
void clear(void);
private:
persistent_ptr<entry> head;
persistent_ptr<entry> tail;
p<size_t> count;
};
void
list::print(void)
{
cout << "Number of people: " << this->count << endl;
persistent_ptr<entry> e = head;
while (e != nullptr) {
cout << *e;
e = e->get_next();
}
}
void
list::insert(string first_name, string last_name)
{
if (head == nullptr) {
head = tail = make_persistent<entry>(count, first_name, last_name);
} else {
persistent_ptr<entry> new_entry;
new_entry = make_persistent<entry>(count, first_name, last_name);
tail = tail->insert(new_entry);
}
count++;
}
void
list::clear(void)
{
persistent_ptr<entry> cur = head;
persistent_ptr<entry> next;
while (cur != nullptr) {
next = cur->get_next();
delete_persistent<entry>(cur);
cur = next;
}
head = tail = nullptr;
count = 0;
}
/* print usage and exit wit error */
static void
fatal_usage(char *app)
{
cout << "usage: " << app << " <file> add|list|clear [<first name> <last name>]"
<< endl;
exit(1);
}
int
main(int argc, char *argv[])
{
if (argc != 3 && argc != 5)
fatal_usage(argv[0]);
pool<list> pop = pool<list>::open(argv[1], "people");
persistent_ptr<list> list = pop.get_root();
if (argc == 5 && strcmp(argv[2], "add") == 0) {
transaction::exec_tx(pop, [&] {
list->insert(argv[3], argv[4]);
});
} else if (argc == 3 && strcmp(argv[2], "list") == 0) {
list->print();
} else if (argc == 3 && strcmp(argv[2], "clear") == 0) {
transaction::manual tx(pop);
list->clear();
transaction::commit();
} else {
fatal_usage(argv[0]);
}
pop.close();
return 0;
}
#include <stdio.h>
#include <string.h>
#include <err.h>
#include <stdlib.h>
#include <libpmemobj.h>
#define ENTRY_TYPE_NUM 1
#define MAX_NAME 16
#define MAX_PEOPLE 256
/*
* Declarations of persistent memory data structures.
* Required in order to use type safety macros.
* Each type (except the root object type) needs a
* type number to be specified.
*/
TOID_DECLARE(struct entry, ENTRY_TYPE_NUM);
TOID_DECLARE_ROOT(struct list);
/* entry for one person */
struct entry {
size_t id;
char first_name[MAX_NAME];
char last_name[MAX_NAME];
};
/* list of people */
struct list {
size_t count;
PMEMoid people[MAX_PEOPLE];
};
/* print first and last name of given person */
static void
print_person(const TOID(struct entry) entry)
{
printf("%2lu: %s %s\n", D_RO(entry)->id, D_RO(entry)->first_name,
D_RO(entry)->last_name);
}
int
main(int argc, char *argv[])
{
if (argc != 2) {
printf("usage: %s <file>\n", argv[0]);
return 1;
}
PMEMobjpool *pop = pmemobj_open(argv[1], "people");
if (!pop)
err(1, "pmemobj_open: %s", pmemobj_errormsg());
TOID(struct entry) i;
POBJ_FOREACH_TYPE(pop, i) {
print_person(i);
}
pmemobj_close(pop);
return 0;
}
#include <iostream>
#include <string.h>
#include <vector>
#include <libpmemobj++/pool.hpp>
#include <libpmemobj++/allocator.hpp>
#include <libpmemobj++/pext.hpp>
#include <libpmemobj++/transaction.hpp>
#include <libpmemobj++/make_persistent.hpp>
#include <libpmemobj++/make_persistent_array.hpp>
#include <libpmemobj++/persistent_ptr.hpp>
using namespace std;
using namespace nvml::obj;
struct pstring {
pstring(const string &str) {
size_t len = str.length() + 1;
this->data = make_persistent<char []>(len);
strncpy(this->data.get(), str.c_str(), str.length());
}
persistent_ptr<char[]> data;
};
ostream &operator<<(ostream &os, const pstring &str) {
os << str.data.get();
return os;
}
class entry {
public:
entry(size_t _id, string _first_name, string _last_name) :
first_name(_first_name),
last_name(_last_name),
id(_id)
{
}
friend ostream &operator<<(ostream &os, const entry &e);
protected:
pstring first_name;
pstring last_name;
p<size_t> id;
};
ostream &operator<<(ostream &os, const entry &e) {
os << e.id << ": " << e.first_name << " " << e.last_name << endl;
return os;
}
template <class T>
using pvector = vector<T, nvml::obj::allocator<T>>;
class list {
public:
void print(void) {
cout << "Number of people: " << vec.size() << endl;
for (auto i: vec)
cout << i;
}
void insert(string first_name, string last_name) {
vec.push_back(entry(vec.size(), first_name, last_name));
}
private:
pvector<entry> vec;
};
int
main(int argc, char *argv[])
{
if (argc != 2 && argc != 4) {
cout << "usage: " << argv[0] << " <file> [<first name> <last name>]" << endl;
return 1;
}
pool<list> pop = pool<list>::open(argv[1], "people");
persistent_ptr<list> list = pop.get_root();
if (argc == 4) {
transaction::exec_tx(pop, [&] {
list->insert(argv[2], argv[3]);
});
} else {
list->print();
}
pop.close();
return 0;
}
#include <stdio.h>
#include <string.h>
#include <err.h>
#include <stdlib.h>
#include <libpmemobj.h>
#define ENTRY_TYPE_NUM 1
#define MAX_NAME 16
#define MAX_PEOPLE 256
/*
* Declarations of persistent memory data structures.
* Required in order to use type safety macros.
* Each type (except the root object type) needs a
* type number to be specified.
*/
TOID_DECLARE(struct entry, ENTRY_TYPE_NUM);
TOID_DECLARE_ROOT(struct list);
/* entry for one person */
struct entry {
size_t id;
char first_name[MAX_NAME];
char last_name[MAX_NAME];
};
/* list of people */
struct list {
size_t count;
TOID(struct entry) people[MAX_PEOPLE];
};
/* arguments for constructor */
struct entry_args {
size_t id;
const char *first_name;
const char *last_name;
};
/* list entry constructor */
static int
entry_constr(PMEMobjpool *pop, void *ptr, void *arg)
{
struct entry *entry = ptr;
struct entry_args *args = arg;
entry->id = args->id;
strncpy(entry->first_name, args->first_name, MAX_NAME);
strncpy(entry->last_name, args->last_name, MAX_NAME);
pmemobj_persist(pop, entry, sizeof(*entry));
return 0;
}
/* insert one person to the list of people */
static int
insert(PMEMobjpool *pop, const char *first_name, const char *last_name)
{
/* get a root object */
TOID(struct list) list = POBJ_ROOT(pop, struct list);
if (TOID_IS_NULL(list))
err(1, "POBJ_ROOT: %s\n", pmemobj_errormsg());
if (D_RO(list)->count == MAX_PEOPLE)
err(1, "Sorry, the list is full...\n");
/* allocate new entry */
struct entry_args args = {D_RO(list)->count, first_name, last_name};
int ret = POBJ_NEW(pop, &D_RW(list)->people[D_RO(list)->count],
struct entry, entry_constr, &args);
if (ret)
err(1, "pmemobj_alloc: %s\n", pmemobj_errormsg());
/* increase number of people */
D_RW(list)->count++;
/* make the new value of people persistent */
pmemobj_persist(pop, &D_RW(list)->count, sizeof(D_RO(list)->count));
return ret;
}
/* print first and last name of given person */
static void
print_person(const TOID(struct entry) entry)
{
printf("%2lu: %s %s\n", D_RO(entry)->id, D_RO(entry)->first_name,
D_RO(entry)->last_name);
}
/* list all people on the list */
static void
list(PMEMobjpool *pop)
{
TOID(struct list) list = POBJ_ROOT(pop, struct list);
if (TOID_IS_NULL(list))
err(1, "POBJ_ROOT: %s\n", pmemobj_errormsg());
printf("Number of people: %lu\n", D_RO(list)->count);
for (size_t i = 0; i < D_RO(list)->count; i++)
print_person(D_RO(list)->people[i]);
}
/* clear all people from the list */
static void
clear(PMEMobjpool *pop)
{
TOID(struct list) list = POBJ_ROOT(pop, struct list);
if (TOID_IS_NULL(list))
err(1, "POBJ_ROOT: %s\n", pmemobj_errormsg());
while (D_RO(list)->count) {
/*
* The following operations must be in appropriate order.
* Otherwise the recovery steps would be invalid.
*/
D_RW(list)->count--;
pmemobj_persist(pop, &D_RW(list)->count,
sizeof(D_RO(list)->count));
POBJ_FREE(&D_RO(list)->people[D_RO(list)->count]);
}
}
/* perform recovery */
static void
recovery(PMEMobjpool *pop)
{
TOID(struct list) list = POBJ_ROOT(pop, struct list);
if (TOID_IS_NULL(list))
err(1, "POBJ_ROOT: %s\n", pmemobj_errormsg());
if (D_RO(list)->count == MAX_PEOPLE)
return;
if (!TOID_IS_NULL(D_RO(list)->people[D_RO(list)->count])) {
/*
* Need to perform recovery because new entry has been
* allocated but the counter has not been stored.
*/
printf("Performing recovery:\n");
print_person(D_RO(list)->people[D_RO(list)->count]);
/* increase number of people */
D_RW(list)->count++;
/* make the new value of people persistent */
pmemobj_persist(pop, &D_RO(list)->count,
sizeof(D_RO(list)->count));
}
}
/* print usage and exit wit error */
static void
fatal_usage(char *app)
{
printf("usage: %s <file> add|list|clear [<first name> <last name>]\n", app);
exit(1);
}
int
main(int argc, char *argv[])
{
if (argc != 3 && argc != 5)
fatal_usage(argv[0]);
PMEMobjpool *pop = pmemobj_open(argv[1], "people");
if (!pop)
err(1, "pmemobj_open: %s", pmemobj_errormsg());
recovery(pop);
if (argc == 5 && strcmp(argv[2], "add") == 0) {
if (insert(pop, argv[3], argv[4]))
err(1, "insert: %s\n", pmemobj_errormsg());
} else if (argc == 3 && strcmp(argv[2], "list") == 0) {
list(pop);
} else if (argc == 3 && strcmp(argv[2], "clear") == 0) {
clear(pop);
} else {
fatal_usage(argv[0]);
}
pmemobj_close(pop);
return 0;
}
#include <stdio.h>
#include <string.h>
#include <err.h>
#include <stdlib.h>
#include <libpmemobj.h>
#define ENTRY_TYPE_NUM 1
#define MAX_NAME 16
#define MAX_PEOPLE 256
/*
* Declarations of persistent memory data structures.
* Required in order to use type safety macros.
* The type numbers are assigned automaticaly.
*/
POBJ_LAYOUT_BEGIN(people);
POBJ_LAYOUT_TOID(people, struct entry);
POBJ_LAYOUT_ROOT(people, struct list);
POBJ_LAYOUT_END(people);
/* entry for one person */
struct entry {
size_t id;
char first_name[MAX_NAME];
char last_name[MAX_NAME];
TOID(struct entry) next;
};
/* list of people */
struct list {
size_t count;
TOID(struct entry) head;
TOID(struct entry) tail;
};
/* list entry constructor */
static void
entry_constr(TOID(struct entry) entry, size_t id,
const char *first_name, const char *last_name)
{
D_RW(entry)->id = id;
D_RW(entry)->next = TOID_NULL(struct entry);
strncpy(D_RW(entry)->first_name, first_name, MAX_NAME);
strncpy(D_RW(entry)->last_name, last_name, MAX_NAME);
}
/* insert at first position */
static void
insert_first(TOID(struct list) list, TOID(struct entry) entry)
{
TX_ADD_FIELD(list, head);
TX_ADD_FIELD(list, tail);
D_RW(list)->head = D_RW(list)->tail = entry;
}
/* insert at last position */
static void
insert_tail(TOID(struct list) list, TOID(struct entry) entry)
{
TOID(struct entry) last = D_RW(list)->tail;
TX_ADD_FIELD(list, tail);
TX_ADD_FIELD(last, next);
D_RW(list)->tail = D_RW(last)->next = entry;
}
/* insert one person to the list of people */
static int
insert(PMEMobjpool *pop, const char *first_name, const char *last_name)
{
/* get a root object */
TOID(struct list) list = POBJ_ROOT(pop, struct list);
if (TOID_IS_NULL(list))
err(1, "POBJ_ROOT: %s\n", pmemobj_errormsg());
TX_BEGIN(pop) {
TOID(struct entry) entry = TX_NEW(struct entry);
entry_constr(entry, D_RO(list)->count, first_name, last_name);
if (TOID_IS_NULL(D_RO(list)->head))
insert_first(list, entry);
else
insert_tail(list, entry);
TX_ADD_FIELD(list, count);
D_RW(list)->count++;
} TX_ONABORT {
err(1, "transaction aborted: %s\n", pmemobj_errormsg());
} TX_END
return 0;
}
/* print first and last name of given person */
static void
print_person(const TOID(struct entry) entry)
{
printf("%2lu: %s %s\n", D_RO(entry)->id, D_RO(entry)->first_name,
D_RO(entry)->last_name);
}
/* list all people on the list */
static void
list(PMEMobjpool *pop)
{
TOID(struct list) list = POBJ_ROOT(pop, struct list);
if (TOID_IS_NULL(list))
err(1, "POBJ_ROOT: %s\n", pmemobj_errormsg());
printf("Number of people: %lu\n", D_RO(list)->count);
TOID(struct entry) i = D_RO(list)->head;
while (!TOID_IS_NULL(i)) {
print_person(i);
i = D_RO(i)->next;
}
}
/* clear all people from the list */
static void
clear(PMEMobjpool *pop)
{
TOID(struct list) list = POBJ_ROOT(pop, struct list);
if (TOID_IS_NULL(list))
err(1, "POBJ_ROOT: %s\n", pmemobj_errormsg());
TOID(struct entry) cur = D_RO(list)->head;
TOID(struct entry) next;
TX_BEGIN(pop) {
while (!TOID_IS_NULL(cur)) {
next = D_RO(cur)->next;
TX_FREE(cur);
cur = next;
}
TX_SET(list, tail, TOID_NULL(struct entry));
TX_SET(list, head, TOID_NULL(struct entry));
TX_SET(list, count, 0);
} TX_ONABORT {
err(1, "transaction aborted: %s\n", pmemobj_errormsg());
} TX_END
}
/* print usage and exit wit error */
static void
fatal_usage(char *app)
{
printf("usage: %s <file> add|list|clear [<first name> <last name>]\n", app);
exit(1);
}
int
main(int argc, char *argv[])
{
if (argc != 3 && argc != 5)
fatal_usage(argv[0]);
PMEMobjpool *pop = pmemobj_open(argv[1], "people");
if (!pop)
err(1, "pmemobj_open: %s", pmemobj_errormsg());
if (argc == 5 && strcmp(argv[2], "add") == 0) {
if (insert(pop, argv[3], argv[4]))
err(1, "insert: %s\n", pmemobj_errormsg());
} else if (argc == 3 && strcmp(argv[2], "list") == 0) {
list(pop);
} else if (argc == 3 && strcmp(argv[2], "clear") == 0) {
clear(pop);
} else {
fatal_usage(argv[0]);
}
pmemobj_close(pop);
return 0;
}
#include <stdio.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <unistd.h>
#include <err.h>
#include <stdlib.h>
#include <libpmem.h>
struct my_struct {
int a;
int b;
int c;
};
int
main(int argc, char *argv[])
{
if (argc != 2) {
printf("usage: %s <file>\n", argv[0]);
return 1;
}
/* map pmem file */
size_t len;
void *addr = pmem_map_file(argv[1], 0, 0, 0775, &len, NULL);
if (!addr)
err(1, "!pmem_map_file");
struct my_struct *s = addr;
/* store value and make it persitent */
s->a = 1;
pmem_persist(&s->a, sizeof(s->a));
/* !!! not made persistent */
s->b = 2;
s->c = 3;
pmem_unmap(addr, len);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment