-
Notifications
You must be signed in to change notification settings - Fork 174
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
storage: introduce shm/pmem backed datapool abstraction
This patch creates a datapool abstraction for managing large amounts of contiguous memory, and adds two implementations: - shm, backed by shared memory allocated through cc_alloc - pmem, backed by memory-mapped file managed through libpmem The default implementation, datapool_shm, currently does not differ from simply managing memory through cc_alloc/cc_free. The datapool_pmem implementation, which can be enabled through -DUSE_PMEM=ON, allows for durable (persistent) implementations of the storage layer as it attempts to recover the previous content of the managed memory.
- Loading branch information
Showing
11 changed files
with
412 additions
and
0 deletions.
There are no files selected for viewing
This file contains 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
This file contains 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
This file contains 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
This file contains 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
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
add_library(datapool) | ||
|
||
if(USE_PMEM) | ||
target_sources(datapool PRIVATE datapool_pmem.c) | ||
target_include_directories(datapool PRIVATE ${LIBPMEM_INCLUDE_DIRS}) | ||
target_link_libraries(datapool ${LIBPMEM_LIBRARIES}) | ||
else() | ||
target_sources(datapool PRIVATE datapool_shm.c) | ||
endif(USE_PMEM) |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
#pragma once | ||
|
||
#include <stddef.h> | ||
|
||
struct datapool; | ||
|
||
struct datapool *datapool_open(const char *path, size_t size, | ||
int *fresh); | ||
void datapool_close(struct datapool *pool); | ||
|
||
void *datapool_addr(struct datapool *pool); | ||
size_t datapool_size(struct datapool *pool); |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,217 @@ | ||
/* | ||
* File-backed datapool. | ||
* Retains its contents if the pool has been closed correctly. | ||
* | ||
*/ | ||
#include "datapool.h" | ||
|
||
#include <cc_mm.h> | ||
#include <cc_debug.h> | ||
|
||
#include <inttypes.h> | ||
|
||
#include <libpmem.h> | ||
|
||
#define DATAPOOL_SIGNATURE ("PELIKAN") /* 8 bytes */ | ||
#define DATAPOOL_SIGNATURE_LEN (sizeof(DATAPOOL_SIGNATURE)) | ||
#define DATAPOOL_HEADER_LEN 4096 | ||
#define DATAPOOL_VERSION 1 | ||
|
||
#define DATAPOOL_FLAG_DIRTY (1 << 0) | ||
#define DATAPOOL_VALID_FLAGS (DATAPOOL_FLAG_DIRTY) | ||
|
||
/* | ||
* Header at the beginning of the file, it's verified every time the pool is | ||
* opened. | ||
*/ | ||
struct datapool_header { | ||
uint8_t signature[DATAPOOL_SIGNATURE_LEN]; | ||
uint64_t version; | ||
uint64_t size; | ||
uint64_t flags; | ||
uint8_t unused[DATAPOOL_HEADER_LEN - 32]; | ||
}; | ||
|
||
struct datapool { | ||
void *addr; | ||
|
||
struct datapool_header *hdr; | ||
void *user_addr; | ||
size_t mapped_len; | ||
int is_pmem; | ||
int file_backed; | ||
}; | ||
|
||
static void | ||
datapool_sync_hdr(struct datapool *pool) | ||
{ | ||
pmem_msync(pool->hdr, DATAPOOL_HEADER_LEN); | ||
} | ||
|
||
static void | ||
datapool_sync(struct datapool *pool) | ||
{ | ||
pmem_msync(pool->addr, pool->mapped_len); | ||
} | ||
|
||
static int | ||
datapool_valid(struct datapool *pool) | ||
{ | ||
if (memcmp(pool->hdr->signature, | ||
DATAPOOL_SIGNATURE, DATAPOOL_SIGNATURE_LEN) != 0) { | ||
log_info("no signature found in datapool"); | ||
return 0; | ||
} | ||
|
||
if (pool->hdr->version != DATAPOOL_VERSION) { | ||
log_info("incompatible datapool version (is: %d, expecting: %d)", | ||
pool->hdr->version, DATAPOOL_SIGNATURE); | ||
return 0; | ||
} | ||
|
||
if (pool->hdr->size == 0) { | ||
log_error("datapool has 0 size"); | ||
return 0; | ||
} | ||
|
||
if (pool->hdr->size > pool->mapped_len) { | ||
log_error("datapool has invalid size (is: %d, expecting: %d)", | ||
pool->mapped_len, pool->hdr->size); | ||
return 0; | ||
} | ||
|
||
if (pool->hdr->flags & ~DATAPOOL_VALID_FLAGS) { | ||
log_error("datapool has invalid flags set"); | ||
return 0; | ||
} | ||
|
||
if (pool->hdr->flags & DATAPOOL_FLAG_DIRTY) { | ||
log_info("datapool has a valid header but is dirty"); | ||
return 0; | ||
} | ||
|
||
return 1; | ||
} | ||
|
||
static void | ||
datapool_initialize(struct datapool *pool) | ||
{ | ||
log_info("initializing fresh datapool"); | ||
|
||
/* 1. clear the header from any leftovers */ | ||
memset(pool->hdr, 0, DATAPOOL_HEADER_LEN); | ||
datapool_sync_hdr(pool); | ||
|
||
/* 2. fill in the data */ | ||
pool->hdr->version = DATAPOOL_VERSION; | ||
pool->hdr->size = pool->mapped_len; | ||
pool->hdr->flags = 0; | ||
datapool_sync_hdr(pool); | ||
|
||
/* 3. set the signature */ | ||
memcpy(pool->hdr->signature, DATAPOOL_SIGNATURE, DATAPOOL_SIGNATURE_LEN); | ||
datapool_sync_hdr(pool); | ||
} | ||
|
||
static void | ||
datapool_flag_set(struct datapool *pool, int flag) | ||
{ | ||
pool->hdr->flags |= flag; | ||
datapool_sync_hdr(pool); | ||
} | ||
|
||
static void | ||
datapool_flag_clear(struct datapool *pool, int flag) | ||
{ | ||
pool->hdr->flags &= ~flag; | ||
datapool_sync_hdr(pool); | ||
} | ||
|
||
/* | ||
* Opens, and if necessary initializes, a datapool that resides in the given | ||
* file. If no file is provided, the pool is allocated through cc_zalloc. | ||
* | ||
* The the datapool to retain its contents, the datapool_close() call must | ||
* finish successfully. | ||
*/ | ||
struct datapool * | ||
datapool_open(const char *path, size_t size, int *fresh) | ||
{ | ||
struct datapool *pool = cc_alloc(sizeof(*pool)); | ||
if (pool == NULL) { | ||
log_error("unable to create allocate memory for pmem mapping"); | ||
goto err_alloc; | ||
} | ||
|
||
size_t map_size = size + sizeof(struct datapool_header); | ||
|
||
if (path == NULL) { /* fallback to DRAM if pmem is not configured */ | ||
pool->addr = cc_zalloc(map_size); | ||
pool->mapped_len = map_size; | ||
pool->is_pmem = 0; | ||
pool->file_backed = 0; | ||
} else { | ||
pool->addr = pmem_map_file(path, map_size, PMEM_FILE_CREATE, 0600, | ||
&pool->mapped_len, &pool->is_pmem); | ||
pool->file_backed = 1; | ||
} | ||
|
||
if (pool->addr == NULL) { | ||
log_error(pmem_errormsg()); | ||
goto err_map; | ||
} | ||
|
||
log_info("mapped datapool %s with size %llu, is_pmem: %d", | ||
path, pool->mapped_len, pool->is_pmem); | ||
|
||
pool->hdr = pool->addr; | ||
pool->user_addr = (uint8_t *)pool->addr + sizeof(struct datapool_header); | ||
|
||
if (fresh) | ||
*fresh = 0; | ||
|
||
if (datapool_valid(pool)) | ||
goto out; | ||
|
||
if (fresh) | ||
*fresh = 1; | ||
|
||
datapool_initialize(pool); | ||
|
||
out: | ||
datapool_flag_set(pool, DATAPOOL_FLAG_DIRTY); | ||
|
||
return pool; | ||
|
||
err_map: | ||
cc_free(pool); | ||
err_alloc: | ||
return NULL; | ||
} | ||
|
||
void | ||
datapool_close(struct datapool *pool) | ||
{ | ||
datapool_sync(pool); | ||
datapool_flag_clear(pool, DATAPOOL_FLAG_DIRTY); | ||
|
||
if (pool->file_backed) | ||
pmem_unmap(pool->addr, pool->mapped_len); | ||
else | ||
cc_free(pool->addr); | ||
|
||
cc_free(pool); | ||
} | ||
|
||
void * | ||
datapool_addr(struct datapool *pool) | ||
{ | ||
return pool->user_addr; | ||
} | ||
|
||
size_t | ||
datapool_size(struct datapool *pool) | ||
{ | ||
return pool->mapped_len - sizeof(struct datapool_header); | ||
} | ||
|
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
/* | ||
* Anonymous shared memory backed datapool. | ||
* Loses all its contents after closing. | ||
*/ | ||
#include "datapool.h" | ||
|
||
#include <cc_debug.h> | ||
#include <cc_mm.h> | ||
|
||
struct datapool * | ||
datapool_open(const char *path, size_t size, int *fresh) | ||
{ | ||
if (path != NULL) { | ||
log_warn("attempted to open a file-based data pool without" | ||
"pmem features enabled"); | ||
return NULL; | ||
} | ||
|
||
if (fresh) | ||
*fresh = 1; | ||
|
||
return cc_zalloc(size); | ||
} | ||
|
||
void | ||
datapool_close(struct datapool *pool) | ||
{ | ||
cc_free(pool); | ||
} | ||
|
||
void * | ||
datapool_addr(struct datapool *pool) | ||
{ | ||
return pool; | ||
} | ||
|
||
size_t | ||
datapool_size(struct datapool *pool) | ||
{ | ||
return cc_alloc_usable_size(pool); | ||
} | ||
|
This file contains 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
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
set(suite datapool) | ||
set(test_name check_${suite}) | ||
|
||
set(source check_${suite}.c) | ||
|
||
add_executable(${test_name} ${source}) | ||
target_link_libraries(${test_name} ${suite}) | ||
target_link_libraries(${test_name} ccommon-static ${CHECK_LIBRARIES}) | ||
target_link_libraries(${test_name} datapool) | ||
|
||
add_dependencies(check ${test_name}) | ||
add_test(${test_name} ${test_name}) |
Oops, something went wrong.