Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implements functions for manipulating seed IDs #4

Merged
merged 3 commits into from
Jul 12, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 1 addition & 3 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
language: c
compiler: clang
compiler: gcc
script:
- sudo apt-get update -qq
- sudo apt-get install -yqq libc++-dev
- make
- make test
branches:
Expand Down
14 changes: 7 additions & 7 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,25 +1,25 @@
CC = clang
CXX = clang++
CXXFLAGS += -std=c++11 -stdlib=libc++
CC = gcc
CXX = g++
CXXFLAGS += -std=c++11

OBJ = naming.o
OBJ = naming.o MurmurHash3.o

all: cmain ccmain

cmain: main.c $(OBJ)
$(CC) $(CFLAGS) $^ -o $@
ccmain: main.cc $(OBJ)
$(CXX) $(CXXFLAGS) $^ -o $@
naming.o: naming.cc naming.h
naming.o: naming.cc
$(CXX) -c $(CXXFLAGS) $< -o $@
MurmurHash3.o: utils/MurmurHash3.cpp
$(CXX) -c $(CXXFLAGS) $< -o $@

test: testc testcc
testc: cmain
./cmain
./cmain
testcc: ccmain
./ccmain
./ccmain

clean:
$(RM) cmain ccmain $(OBJ)
26 changes: 18 additions & 8 deletions main.c
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#include <assert.h>
#include <stdio.h>
#include "naming.h"

Expand All @@ -11,14 +12,23 @@ int main() {
pm_open("main.pmd", -1);

void *addr = pm_retrieve("Seed");
if (!addr) {
pm_register("Seed", (void *)0xcafe);
printf("Do registration.\n");
} else {
void *addr = pm_retrieve("Seed");
printf("%p\n", addr);
pm_deregister("Seed");
}
assert(!addr);

addr = pm_register("Seed", (void *)0xcafe);
assert(addr == (void *)0xcafe);
printf("Registered 'Seed' with %p\n", addr);

addr = pm_register("Seed", (void *)0xc0ffee);
assert(addr == (void *)0xcafe);
addr = pm_retrieve("Seed");
assert(addr == (void *)0xc0ffee);
printf("Registered 'Seed' with %p\n", addr);

addr = pm_deregister("Seed");
assert(addr == (void *)0xc0ffee);

addr = pm_retrieve("Seed");
assert(!addr);

if (pm_close() != 0) {
fprintf(stderr, "Fail to save persistent data!\n");
Expand Down
11 changes: 1 addition & 10 deletions main.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,14 @@
#include "naming.h"

int main() {
pm_open("main.pmd", 10000000000);
pm_open("main.pmd", 1000000000);
if (pm_close() != 0) {
std::cerr << "Fail to save persistent data!" << std::endl;
return 1;
}

pm_open("main.pmd", -1);

void *addr = pm_retrieve("Seed");
if (!addr) {
pm_register("Seed", (void *)0xcafe);
std::cout << "Do registration." << std::endl;
} else {
void *addr = pm_retrieve("Seed");
std::cout << addr << std::endl;
pm_deregister("Seed");
}
if (pm_close() != 0) {
std::cerr << "Fail to save persistent data!" << std::endl;
return 1;
Expand Down
116 changes: 109 additions & 7 deletions naming.cc
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,55 @@

#include "naming.h"

#include <cassert>
#include <cerrno>
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <sys/mman.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include "utils/MurmurHash3.h"

static void * const kPMAddr = (void *)0x6e256e200000;

/**
* @brief Max length of a string seed ID.
*/
#define SEED_MAX_LEN (240)

/**
* @brief A pair of seed ID and memory address.
*
* Seed is linked in a hashtable for retrieval.
* The size of Seed is statically set to 256 bytes.
* @see SEED_MAX_LEN
*/
struct Seed {
char id[SEED_MAX_LEN];
void *address;
Seed *next;
};

#define TABLE_SHIFT (4)
#define TABLE_SIZE (1U << TABLE_SHIFT)
#define TABLE_MASK (TABLE_SIZE - 1)

/**
* @brief A hashtable to index seed IDs.
*
* Consists of a fixed number of buckets. It is not recommended to have a large
* number of seed IDs, so a static hashtable should be able to handle them
* efficiently. The number of buckets is defined by #TABLE_SIZE.
*/
struct SeedTable {
Seed *buckets[TABLE_SIZE];
};

static SeedTable * const kSeedTableAddr = (SeedTable *)kPMAddr;

//
// Utility functions for manipulating file descriptors
//
Expand All @@ -28,21 +66,30 @@ static size_t g_pm_size = 0;

void pm_open(const char *file, size_t size) {
int fd = -1;
bool to_init = false;
if (size == (size_t)-1) { // mapping to a whole existing file
fd = open(file, O_RDWR | O_NOATIME);
check_error_or_exit(fd);
size = file_size(fd);
g_pm_size = file_size(fd);
} else { // mapping to a (created) file with the specified size
fd = open(file, O_RDWR | O_NOATIME | O_CREAT, S_IRWXU);
check_error_or_exit(fd);
if (file_size(fd) < size) { // in case the file is too small
g_pm_size = file_size(fd);
if (!g_pm_size) { // in case the file is empty
check_error_or_exit(ftruncate(fd, size));
g_pm_size = size;
to_init = true;
}
assert(g_pm_size == size);
}
void *addr = mmap(kPMAddr, size, PROT_READ | PROT_WRITE | PROT_EXEC,
void *addr = mmap(kPMAddr, g_pm_size, PROT_READ | PROT_WRITE | PROT_EXEC,
MAP_SHARED | MAP_FIXED, fd, 0);
check_error_or_exit((uint64_t)addr);
g_pm_size = size;
assert(addr == kPMAddr);
if (to_init) {
// Initializes the persistent memory region
std::memset(kSeedTableAddr, 0, sizeof(SeedTable));
}
}

int pm_close() {
Expand All @@ -52,18 +99,73 @@ int pm_close() {
}

void *pm_retrieve(const char *id) {
const int len = strnlen(id, SEED_MAX_LEN);
if (len == SEED_MAX_LEN) {
return nullptr;
}
uint32_t hash = 0;
MurmurHash3_x86_32(id, len, 0x6e256e2, &hash);

Seed *cur = kSeedTableAddr->buckets[hash & TABLE_MASK];
while (cur) {
if (std::strcmp(cur->id, id) == 0) return cur->address;
cur = cur->next;
}
return nullptr;
}

void pm_register(const char *id, void *addr) {
void *pm_register(const char *id, void *addr) {
const int len = strnlen(id, SEED_MAX_LEN);
if (len == SEED_MAX_LEN) {
return nullptr;
}
uint32_t hash = 0;
MurmurHash3_x86_32(id, len, 0x6e256e2, &hash);

Seed *cur = kSeedTableAddr->buckets[hash & TABLE_MASK];
while (cur) {
if (std::strcmp(cur->id, id) == 0) { // overwriting the old address
void *old_addr = cur->address;
cur->address = addr;
return old_addr;
}
cur = cur->next;
}

Seed *seed = (Seed *)malloc(sizeof(Seed));
if (seed) {
std::strcpy(seed->id, id);
seed->address = addr;
seed->next = kSeedTableAddr->buckets[hash & TABLE_MASK];
kSeedTableAddr->buckets[hash & TABLE_MASK] = seed;
}
return seed->address;
}

void pm_deregister(const char *id) {
void *pm_deregister(const char *id) {
const int len = strnlen(id, SEED_MAX_LEN);
if (len == SEED_MAX_LEN) {
return nullptr;
}
uint32_t hash = 0;
MurmurHash3_x86_32(id, len, 0x6e256e2, &hash);

Seed **pprev = &kSeedTableAddr->buckets[hash & TABLE_MASK];
Seed *cur = *pprev;
while (cur) {
if (std::strcmp(cur->id, id) == 0) {
*pprev = cur->next;
void *addr = cur->address;
free(cur);
return addr;
}
pprev = &cur->next;
cur = cur->next;
}
return nullptr;
}

//

// Implementation of utility functions
//
static void check_error_or_exit(uint64_t ret, const char *message) {
Expand Down
29 changes: 18 additions & 11 deletions naming.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,13 @@ extern "C" {
/**
* @brief Opens the persistent memory region from a backup file that
* stores memory data. The file exists while the program is closed.
* If the specified file does not exist, a new file is created and
* the persistent memory region is empty.
* If the file does not exist, a new file is created with the specified size
* that is the size of the persistent memory region. If @p size is specified
* but does not match the size of the file, the program aborts.
*
* @param file The path to the backup file.
* @param size The size of the persistent memory region. -1 lets it equal
* the size of the backup file.
* @param size The size of the backup file/persistent memory region.
* -1 lets it equal the size of the existing backup file.
*
*/
void pm_open(const char *file, size_t size);
Expand All @@ -40,26 +41,32 @@ int pm_close();
* in the persistent memory region.
*
* @param id The unique string ID of the data object.
* @return The memory address of the data object.
* @return The memory address of the data object. Null on failure.
*/
void *pm_retrieve(const char *id);

/**
* @brief Registers a unique string ID for a data object.
* After the ID is registered, it can be used to retrieve
* the associated data object through pm_retrieve().
* After the ID is registered, it can be used to retrieve the associated data
* object through pm_retrieve().
* The registered pair holds no matter if the program is running or shut down.
* If the ID is already registered, the currently associated address is
* overwritten, and returned.
*
* @param id The unique string ID of the data object.
* @param addr The memory address of the data object.
* @return The overwritten memory address or the new one (i.e., @p addr).
* Null on failure.
*/
void pm_register(const char *id, void *addr);
void *pm_register(const char *id, void *addr);

/**
* @brief Deregisters a unique ID, whose relationship with
* an object in the persistent memory region is terminated.
* @brief Deregisters a unique ID, whose association with an object in
* the persistent memory region is terminated.
*
* @return The old associated memory address. Null if the ID is not found.
*/
void pm_deregister(const char *id);
void *pm_deregister(const char *id);

#ifdef __cplusplus
}
Expand Down
Loading