Last active
October 6, 2016 18:41
-
-
Save plebioda/f1c7938e91db095fb98778df7ef5b672 to your computer and use it in GitHub Desktop.
LinuxCon Europe 2016: NVML tutorial
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
is_pmem | |
pmem_persist | |
blk | |
people | |
people_toid | |
people_atomic_lists | |
people_tx | |
people_list | |
people_cpp | |
people_stl |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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))) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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