PMEMKV_ITERATOR(3)
π NAME π
pmemkv_iterator β it's the Iterator API for libpmemkv, bestie. That's the whole vibe. (You'll also see it written as PMEMKV_ITERATOR(3), from the PMEMKV Programmer's Manual, iykyk.)
β οΈ Heads up gorgeous: This API is EXPERIMENTAL and might change. So like... don't build your whole personality on it. π
β¨ SYNOPSIS β¨
#include <libpmemkv.h>
int pmemkv_iterator_new(pmemkv_db *db, pmemkv_iterator **it);
int pmemkv_write_iterator_new(pmemkv_db *db, pmemkv_write_iterator **it);
void pmemkv_iterator_delete(pmemkv_iterator *it);
void pmemkv_write_iterator_delete(pmemkv_write_iterator *it);
int pmemkv_iterator_seek(pmemkv_iterator *it, const char *k, size_t kb);
int pmemkv_iterator_seek_lower(pmemkv_iterator *it, const char *k, size_t kb);
int pmemkv_iterator_seek_lower_eq(pmemkv_iterator *it, const char *k, size_t kb);
int pmemkv_iterator_seek_higher(pmemkv_iterator *it, const char *k, size_t kb);
int pmemkv_iterator_seek_higher_eq(pmemkv_iterator *it, const char *k, size_t kb);
int pmemkv_iterator_seek_to_first(pmemkv_iterator *it);
int pmemkv_iterator_seek_to_last(pmemkv_iterator *it);
int pmemkv_iterator_is_next(pmemkv_iterator *it);
int pmemkv_iterator_next(pmemkv_iterator *it);
int pmemkv_iterator_prev(pmemkv_iterator *it);
int pmemkv_iterator_key(pmemkv_iterator *it, const char **k, size_t *kb);
int pmemkv_iterator_read_range(pmemkv_iterator *it, size_t pos, size_t n,
const char **data, size_t *rb);
int pmemkv_write_iterator_write_range(pmemkv_write_iterator *it, size_t pos, size_t n,
char **data, size_t *wb);
int pmemkv_write_iterator_commit(pmemkv_write_iterator *it);
void pmemkv_write_iterator_abort(pmemkv_write_iterator *it);
Fr fr, for the general rundown of pmemkv and all the engines you can pick from, go peek at libpmemkv(7). And for the tea on the pmemkv core API? That's libpmemkv(3). π«Ά
πΈ DESCRIPTION πΈ
Iterators are literally just the little helpers that let you walk over the records inside db. Slay.
So there's two flavors of iterator: pmemkv_iterator (the read one) and pmemkv_write_iterator. Both of them let you read a record's key and value. π
The cute little trick: if you wanna use a pmemkv_write_iterator as a pmemkv_iterator, you just grab its member called "iter" β so like write_it->iter. That's it, that's the whole hack. π
Here's what calling pmemkv_iterator_seek_to_first() looks like with both iterator types:
/* read_it is already created, by pmemkv_iterator */
int status = pmemkv_iterator_seek_to_first(read_it);
/* write_it is already created, by pmemkv_write_iterator */
int status = pmemkv_iterator_seek_to_first(write_it->iter);
And the extra sparkle on pmemkv_write_iterator? It can also modify a record's value transactionally. Main character energy honestly. β¨
π«§ Lowkey important: not every engine is guaranteed to implement all of these functions. If an engine doesn't support a certain function, it'll hand you back PMEMKV_STATUS_NOT_SUPPORTED. No cap.
π Also β holding more than one iterator at the same time in the same thread is undefined behavior. Don't do it, bestie, I'm begging.
π The Functions, One By One π
int pmemkv_iterator_new(pmemkv_db *db, pmemkv_iterator **it);β Makes a brand newpmemkv_iteratorand drops a pointer to it into*it. πint pmemkv_write_iterator_new(pmemkv_db *db, pmemkv_write_iterator **it);β Makes a brand newpmemkv_write_iteratorand drops a pointer to it into*it. π¦void pmemkv_iterator_delete(pmemkv_iterator *it);β Deletes thepmemkv_iterator. Bye bestie. πvoid pmemkv_write_iterator_delete(pmemkv_write_iterator *it);β Deletes thepmemkv_write_iterator. Also bye. πint pmemkv_iterator_seek(pmemkv_iterator *it, const char *k, size_t kb);β Moves the iterator to the record with the given keyk, which iskblong. If that record is there and nothing went wrong, you getPMEMKV_STATUS_OKback. If the record doesn't exist, you getPMEMKV_STATUS_NOT_FOUNDand the iterator position is undefined. Sneaky detail: it internally aborts all changes made to an element the iterator was pointing at before. πint pmemkv_iterator_seek_lower(pmemkv_iterator *it, const char *k, size_t kb);β Moves the iterator to the record with a key lower than the given keykof lengthkb. If that record is present and no errors occurred, you getPMEMKV_STATUS_OK. If it doesn't exist,PMEMKV_STATUS_NOT_FOUNDcomes back and the iterator position is undefined. It also internally aborts all changes made to an element previously pointed at by the iterator. π«int pmemkv_iterator_seek_lower_eq(pmemkv_iterator *it, const char *k, size_t kb);β Moves the iterator to the record with a key equal to or lower than the given keykof lengthkb. Present + no errors =PMEMKV_STATUS_OK. Doesn't exist =PMEMKV_STATUS_NOT_FOUNDand undefined position. And yes, it internally aborts all changes made to an element previously pointed at by the iterator. πΈint pmemkv_iterator_seek_higher(pmemkv_iterator *it, const char *k, size_t kb);β Moves the iterator to the record with a key higher than the given keykof lengthkb. Record present and no errors βPMEMKV_STATUS_OK. Record missing βPMEMKV_STATUS_NOT_FOUND, iterator position undefined. It internally aborts all changes made to an element previously pointed at by the iterator. βint pmemkv_iterator_seek_higher_eq(pmemkv_iterator *it, const char *k, size_t kb);β Moves the iterator to the record with a key equal to or higher than the given keykof lengthkb. Present and error-free βPMEMKV_STATUS_OK. Not present βPMEMKV_STATUS_NOT_FOUNDplus an undefined position. And (say it with me) it internally aborts all changes made to an element previously pointed at by the iterator. π§int pmemkv_iterator_seek_to_first(pmemkv_iterator *it);β Moves the iterator to the first record. Ifdbisn't empty and no errors happened, you getPMEMKV_STATUS_OK. Ifdbis empty, you getPMEMKV_STATUS_NOT_FOUNDand the iterator position is undefined. It internally aborts all changes made to an element previously pointed at by the iterator. π₯int pmemkv_iterator_seek_to_last(pmemkv_iterator *it);β Moves the iterator to the last record.dbnot empty + no errors =PMEMKV_STATUS_OK.dbempty =PMEMKV_STATUS_NOT_FOUND, position undefined. Yep, it internally aborts all changes made to an element previously pointed at by the iterator. πint pmemkv_iterator_is_next(pmemkv_iterator *it);β Checks whether there's a next record available. If it comes back true, it's guaranteed thatpmemkv_iterator_next(it)will returnPMEMKV_STATUS_OK. Otherwise the iterator is already sitting on the last element, andpmemkv_iterator_next(it)will returnPMEMKV_STATUS_NOT_FOUND. A little peek, no commitment. πint pmemkv_iterator_next(pmemkv_iterator *it);β Moves the iterator to the next record. If the next record exists you getPMEMKV_STATUS_OK; otherwisePMEMKV_STATUS_NOT_FOUNDand the iterator position is undefined. And once again: it internally aborts all changes made to an element previously pointed at by the iterator. β‘οΈint pmemkv_iterator_prev(pmemkv_iterator *it);β Moves the iterator to the previous record. Previous record exists βPMEMKV_STATUS_OK. Doesn't exist βPMEMKV_STATUS_NOT_FOUNDand undefined position. Also aborts all changes made to an element previously pointed at by the iterator, internally. β¬ οΈint pmemkv_iterator_key(pmemkv_iterator *it, const char **k, size_t *kb);β Assigns the record's key's address tok, and the key's length tokb. If the iterator is on an undefined position, calling this is undefined behavior. πint pmemkv_iterator_read_range(pmemkv_iterator *it, size_t pos, size_t n, const char **data, size_t *rb);β Lets you grab a record's value's range, and it's read-only. You can ask for the full value or just a subrange of it (nelements starting frompos). It assigns a pointer to the beginning of the requested range todata, and the number of elements in the range torb. Ifnis bigger than the length of the value, it gets automatically shrunk. And if the iterator is on an undefined position, calling this method is undefined behavior. πint pmemkv_write_iterator_write_range(pmemkv_write_iterator *it, size_t pos, size_t n, char **data, size_t *wb);β Lets you grab a record's value's range that you can actually modify. Again, full value or just a subrange (nelements starting frompos). Assigns a pointer to the beginning of the requested range todata, and the number of elements in the range towb. Ifnis bigger than the value's length, it's automatically shrunk. Changes made on a requested range are not persistent untilpmemkv_write_iterator_commit()is called. And if the iterator is on an undefined position, calling this method is undefined behavior. βοΈint pmemkv_write_iterator_commit(pmemkv_write_iterator *it);β Commits the modifications made on the current record. Calling this method is the ONLY way to save the modifications the iterator made on the current record. You have to call it before changing the iterator position, otherwise your modifications get automatically aborted. It's giving... use it or lose it. π€void pmemkv_write_iterator_abort(pmemkv_write_iterator *it);β Aborts uncommitted modifications made on the current record. The "nvm, forget I said anything" button. π
π₯ ERRORS π₯
Every single one of these functions returns one of the pmemkv status codes β except for pmemkv_iterator_delete(), pmemkv_write_iterator_delete() and pmemkv_write_iterator_abort(). Wanna see all the possible status code options? That's libpmemkv(3), go look. π
β¨ EXAMPLE β¨
Okay bestie, this next bit is the part where it all clicks, I promise. π«Ά The example below is taken straight from the examples/pmemkv_iterator_c directory, no cap.
It shows off the basic iterator functions in action: iterating over all the records, and then modifying one of them. Iconic behaviour, honestly. π
#include "libpmemkv.h"
#include <assert.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)
static const uint64_t SIZE = 1024UL * 1024UL * 1024UL;
int main(int argc, char *argv[])
{
if (argc < 2) {
fprintf(stderr, "Usage: %s file\n", argv[0]);
exit(1);
}
const size_t n_elements = 10;
char buffer[64];
/* 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_create_if_missing(cfg, true);
ASSERT(s == PMEMKV_STATUS_OK);
LOG("Opening pmemkv database with 'radix' engine");
pmemkv_db *db = NULL;
s = pmemkv_open("radix", cfg, &db);
ASSERT(s == PMEMKV_STATUS_OK);
ASSERT(db != NULL);
LOG("Putting new keys");
for (size_t i = 0; i < n_elements; ++i) {
char key[10];
const char *value = "value";
sprintf(key, "key%zu", i);
s = pmemkv_put(db, key, strlen(key), value, strlen(value));
ASSERT(s == PMEMKV_STATUS_OK);
}
/* get a new read iterator */
pmemkv_iterator *it;
s = pmemkv_iterator_new(db, &it);
ASSERT(s == PMEMKV_STATUS_OK);
LOG("Iterate from first to last element");
s = pmemkv_iterator_seek_to_first(it);
ASSERT(s == PMEMKV_STATUS_OK);
size_t element_number = 0;
do {
const char *str;
size_t cnt;
/* read a key */
s = pmemkv_iterator_key(it, &str, &cnt);
ASSERT(s == PMEMKV_STATUS_OK);
sprintf(buffer, "Key %zu = %s", element_number++, str);
LOG(buffer);
} while (pmemkv_iterator_next(it) != PMEMKV_STATUS_NOT_FOUND);
/* iterator must be deleted manually */
pmemkv_iterator_delete(it);
/* get a new write_iterator */
pmemkv_write_iterator *w_it;
s = pmemkv_write_iterator_new(db, &w_it);
ASSERT(s == PMEMKV_STATUS_OK);
/* if you want to get a pmemkv_iterator (read iterator) from a
* pmemkv_write_iterator, you should do: write_it->iter */
s = pmemkv_iterator_seek_to_last(w_it->iter);
ASSERT(s == PMEMKV_STATUS_OK);
/* get a write range, to modify last element's value */
char *data;
size_t cnt;
s = pmemkv_write_iterator_write_range(w_it, 0, 5, &data, &cnt);
ASSERT(s == PMEMKV_STATUS_OK);
for (size_t i = 0; i < cnt; ++i)
data[i] = 'x';
/* commit changes */
s = pmemkv_write_iterator_commit(w_it);
ASSERT(s == PMEMKV_STATUS_OK);
/* get a read range, to read modified value */
const char *str;
s = pmemkv_iterator_read_range(w_it->iter, 0, 5, &str, &cnt);
ASSERT(s == PMEMKV_STATUS_OK);
/* verify a modified value */
ASSERT(strcmp(str, "xxxxx") == 0);
sprintf(buffer, "Modified value = %s", str);
LOG(buffer);
/* iterator must be deleted manually */
pmemkv_write_iterator_delete(w_it);
LOG("Closing database");
pmemkv_close(db);
return 0;
}
π SEE ALSO π
Go get your extra reading in, bestie, it's giving study era πβ¨:
And that's a wrap on this whole page, fr fr. π This was PMEMKV β pmemkv version 1.5.0, dated 2022-03-09, aka the PMEMKV_ITERATOR(3) glow-up. Go iterate on something beautiful, you absolute icon. π ππ¦
π¦ where this page comes from
- ubuntu jammy: libpmemkv-dev 1.5.0-4build1 Β· BSD-3
- π the page's license: BSD-3-Clause
- Copyright 2019-2022, Intel Corporation
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms