PMEMKV(3) | PMEMKV Programmer's Manual | PMEMKV(3) |
pmemkv - Key/Value Datastore for Persistent Memory
#include <libpmemkv.h> typedef int pmemkv_get_kv_callback(const char *key, size_t keybytes, const char *value,
size_t valuebytes, void *arg); typedef void pmemkv_get_v_callback(const char *value, size_t valuebytes, void *arg); int pmemkv_open(const char *engine, pmemkv_config *config, pmemkv_db **db); void pmemkv_close(pmemkv_db *kv); int pmemkv_count_all(pmemkv_db *db, size_t *cnt); int pmemkv_count_above(pmemkv_db *db, const char *k, size_t kb, size_t *cnt); int pmemkv_count_below(pmemkv_db *db, const char *k, size_t kb, size_t *cnt); int pmemkv_count_between(pmemkv_db *db, const char *k1, size_t kb1, const char *k2,
size_t kb2, size_t *cnt); int pmemkv_get_all(pmemkv_db *db, pmemkv_get_kv_callback *c, void *arg); int pmemkv_get_above(pmemkv_db *db, const char *k, size_t kb, pmemkv_get_kv_callback *c,
void *arg); int pmemkv_get_below(pmemkv_db *db, const char *k, size_t kb, pmemkv_get_kv_callback *c,
void *arg); int pmemkv_get_between(pmemkv_db *db, const char *k1, size_t kb1, const char *k2,
size_t kb2, pmemkv_get_kv_callback *c, void *arg); int pmemkv_exists(pmemkv_db *db, const char *k, size_t kb); int pmemkv_get(pmemkv_db *db, const char *k, size_t kb, pmemkv_get_v_callback *c,
void *arg); int pmemkv_get_copy(pmemkv_db *db, const char *k, size_t kb, char *buffer,
size_t buffer_size, size_t *value_size); int pmemkv_put(pmemkv_db *db, const char *k, size_t kb, const char *v, size_t vb); int pmemkv_remove(pmemkv_db *db, const char *k, size_t kb); int pmemkv_defrag(pmemkv_db *db, double start_percent, double amount_percent); const char *pmemkv_errormsg(void);
For pmemkv configuration API description see libpmemkv_config(3). For pmemkv iterator API description see libpmemkv_iterator(3). For general pmemkv information, engine descriptions and bindings details see libpmemkv(7).
Keys and values stored in a pmemkv database can be arbitrary binary data and can contain multiple null characters. Every function which accepts key expects const char *k pointer to data and its size as size_t.
Some of the functions (mainly range-query API) are not guaranteed to be implemented by all engines. If an engine does not support a certain function, it will return PMEMKV_STATUS_NOT_SUPPORTED.
Note: There are no explicit upper_bound/lower_bound functions. If you want to obtain an element(s) above or below the selected key, you can use pmemkv_get_above() or pmemkv_get_below(). See descriptions of these functions for details.
Each function, except for pmemkv_close() and pmemkv_errormsg(), returns one of the following status codes:
Status returned from a function can change in a future version of a library to a more specific one. For example, if a function returns PMEMKV_STATUS_UNKNOWN_ERROR, it is possible that in future versions it will return PMEMKV_STATUS_INVALID_ARGUMENT. Recommended way to check for an error is to compare status with PMEMKV_STATUS_OK.
The following example is taken from examples/pmemkv_basic_c directory.
Basic pmemkv usage in C:
#include <assert.h> #include <libpmemkv.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #define ASSERT(expr) \
do { \
if (!(expr)) \
puts(pmemkv_errormsg()); \
assert(expr); \
} while (0) #define LOG(msg) puts(msg) #define MAX_VAL_LEN 64 static const uint64_t SIZE = 1024UL * 1024UL * 1024UL; int get_kv_callback(const char *k, size_t kb, const char *value, size_t value_bytes,
void *arg) {
printf(" visited: %s\n", k);
return 0; } int main(int argc, char *argv[]) {
if (argc < 2) {
fprintf(stderr, "Usage: %s file\n", argv[0]);
exit(1);
}
/* See libpmemkv_config(3) for more detailed example of config creation */
LOG("Creating config");
pmemkv_config *cfg = pmemkv_config_new();
ASSERT(cfg != NULL);
int s = pmemkv_config_put_path(cfg, argv[1]);
ASSERT(s == PMEMKV_STATUS_OK);
s = pmemkv_config_put_size(cfg, SIZE);
ASSERT(s == PMEMKV_STATUS_OK);
s = pmemkv_config_put_force_create(cfg, true);
ASSERT(s == PMEMKV_STATUS_OK);
LOG("Opening pmemkv database with 'cmap' engine");
pmemkv_db *db = NULL;
s = pmemkv_open("cmap", cfg, &db);
ASSERT(s == PMEMKV_STATUS_OK);
ASSERT(db != NULL);
LOG("Putting new key");
const char *key1 = "key1";
const char *value1 = "value1";
s = pmemkv_put(db, key1, strlen(key1), value1, strlen(value1));
ASSERT(s == PMEMKV_STATUS_OK);
size_t cnt;
s = pmemkv_count_all(db, &cnt);
ASSERT(s == PMEMKV_STATUS_OK);
ASSERT(cnt == 1);
LOG("Reading key back");
char val[MAX_VAL_LEN];
s = pmemkv_get_copy(db, key1, strlen(key1), val, MAX_VAL_LEN, NULL);
ASSERT(s == PMEMKV_STATUS_OK);
ASSERT(!strcmp(val, "value1"));
LOG("Iterating existing keys");
const char *key2 = "key2";
const char *value2 = "value2";
const char *key3 = "key3";
const char *value3 = "value3";
pmemkv_put(db, key2, strlen(key2), value2, strlen(value2));
pmemkv_put(db, key3, strlen(key3), value3, strlen(value3));
pmemkv_get_all(db, &get_kv_callback, NULL);
LOG("Removing existing key");
s = pmemkv_remove(db, key1, strlen(key1));
ASSERT(s == PMEMKV_STATUS_OK);
ASSERT(pmemkv_exists(db, key1, strlen(key1)) == PMEMKV_STATUS_NOT_FOUND);
LOG("Defragmenting the database");
s = pmemkv_defrag(db, 0, 100);
ASSERT(s == PMEMKV_STATUS_OK);
LOG("Closing database");
pmemkv_close(db);
return 0; }
Common mistake in pmemkv API usage (especially when using C++ API) is to dereference pointer to the data stored in pmemkv outside of a callback function scope.
std::string value; const char* ptr; size_t sz; kv->get("key1", [&](string_view v) {
/* Save pointer to the data to use it later outside of a callback scope */
ptr = v.data();
sz = v.size(); }); kv->remove("key"); /* ERROR!
* Using this pointer outside of a callback function may cause access to some random data
* or a segmentation fault. At that point, ptr should be considered as invalid.
*/ value.append(ptr, sz);
libpmemkv(7), libpmemkv_config(3), libpmemkv_iterator(3) and <https://pmem.io>
2021-02-15 | PMEMKV - pmemkv version 1.4 |