NAME
SYNOPSIS
DESCRIPTION
ERRORS
EXAMPLE
SEE ALSO

NAME

pmemkv_iterator - Iterator API for libpmemkv

This API is EXPERIMENTAL and might change.

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);

For general description of pmemkv and available engines see libpmemkv(7). For description of pmemkv core API see libpmemkv(3).

DESCRIPTION

Iterators provide methods to iterate over records in db.

Both iterator types (pmemkv_iterator (read) and pmemkv_write_iterator) allow reading record’s key and value. To use pmemkv_write_iterator as a pmemkv_iterator you need to get its member “iter” (write_it->iter).

Example of calling pmemkv_iterator_seek_to_first() 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);

A pmemkv_write_iterator additionally can modify record’s value transactionally.

Some of the functions 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.

Holding simultaneously in the same thread more than one iterator is undefined behavior.

int pmemkv_iterator_new(pmemkv_db *db, pmemkv_iterator **it);

Creates a new pmemkv_iterator instance and stores a pointer to it in *it.

int pmemkv_write_iterator_new(pmemkv_db *db, pmemkv_write_iterator **it);

Creates a new pmemkv_write_iterator instance and stores a pointer to it in *it.

void pmemkv_iterator_delete(pmemkv_iterator *it);

Deletes pmemkv_iterator.

void pmemkv_write_iterator_delete(pmemkv_write_iterator *it);

Deletes pmemkv_write_iterator

int pmemkv_iterator_seek(pmemkv_iterator *it, const char *k, size_t kb);

Changes iterator position to the record with given key k of length kb. If the record is present and no errors occurred, returns PMEMKV_STATUS_OK. If the record does not exist, PMEMKV_STATUS_NOT_FOUND is returned and the iterator position is undefined. It internally aborts all changes made to an element previously pointed by the iterator.

int pmemkv_iterator_seek_lower(pmemkv_iterator *it, const char *k, size_t kb);

Changes iterator position to the record with key lower than given key k of length kb. If the record is present and no errors occurred, returns PMEMKV_STATUS_OK. If the record does not exist, PMEMKV_STATUS_NOT_FOUND is returned and the iterator position is undefined. It internally aborts all changes made to an element previously pointed by the iterator.

int pmemkv_iterator_seek_lower_eq(pmemkv_iterator *it, const char *k, size_t kb);

Changes iterator position to the record with key equal or lower than given key k of length kb. If the record is present and no errors occurred, returns PMEMKV_STATUS_OK. If the record does not exist, PMEMKV_STATUS_NOT_FOUND is returned and the iterator position is undefined. It internally aborts all changes made to an element previously pointed by the iterator.

int pmemkv_iterator_seek_higher(pmemkv_iterator *it, const char *k, size_t kb);

Changes iterator position to the record with key higher than given key k of length kb. If the record is present and no errors occurred, returns PMEMKV_STATUS_OK. If the record does not exist, PMEMKV_STATUS_NOT_FOUND is returned and the iterator position is undefined. It internally aborts all changes made to an element previously pointed by the iterator.

int pmemkv_iterator_seek_higher_eq(pmemkv_iterator *it, const char *k, size_t kb);

Changes iterator position to the record with key equal or higher than given key k of length kb. If the record is present and no errors occurred, returns PMEMKV_STATUS_OK. If the record does not exist, PMEMKV_STATUS_NOT_FOUND is returned and the iterator position is undefined. It internally aborts all changes made to an element previously pointed by the iterator.

int pmemkv_iterator_seek_to_first(pmemkv_iterator *it);

Changes iterator position to the first record. If db isn’t empty, and no errors occurred, returns PMEMKV_STATUS_OK. If db is empty, PMEMKV_STATUS_NOT_FOUND is returned and the iterator position is undefined. It internally aborts all changes made to an element previously pointed by the iterator.

int pmemkv_iterator_seek_to_last(pmemkv_iterator *it);

Changes iterator position to the last record. If db isn’t empty, and no errors occurred, returns PMEMKV_STATUS_OK. If db is empty, PMEMKV_STATUS_NOT_FOUND is returned and the iterator position is undefined. It internally aborts all changes made to an element previously pointed by the iterator.

int pmemkv_iterator_is_next(pmemkv_iterator *it);

Checks if there is a next record available. If true is returned, it is guaranteed that pmemkv_iterator_next(it) will return PMEMKV_STATUS_OK, otherwise iterator is already on the last element and pmemkv_iterator_next(it) will return PMEMKV_STATUS_NOT_FOUND.

int pmemkv_iterator_next(pmemkv_iterator *it);

Changes iterator position to the next record. If the next record exists, returns PMEMKV_STATUS_OK, otherwise PMEMKV_STATUS_NOT_FOUND is returned and the iterator position is undefined. It internally aborts all changes made to an element previously pointed by the iterator.

int pmemkv_iterator_prev(pmemkv_iterator *it);

Changes iterator position to the previous record. If the previous record exists, returns PMEMKV_STATUS_OK, otherwise PMEMKV_STATUS_NOT_FOUND is returned and the iterator position is undefined. It internally aborts all changes made to an element previously pointed by the iterator.

int pmemkv_iterator_key(pmemkv_iterator *it, const char **k, size_t *kb);

Assigns record’s key’s address to k and key’s length to kb. If the iterator is on an undefined position, calling this method is undefined behaviour.

int pmemkv_iterator_read_range(pmemkv_iterator *it, size_t pos, size_t n, const char **data, size_t *rb);

Allows getting record’s value’s range which can be only read. You can request for either full value or only value’s subrange (n elements starting from pos). Assigns pointer to the beginning of the requested range to data, and number of elements in range to rb. If n is bigger than length of a value it’s automatically shrunk. If the iterator is on an undefined position, calling this method is undefined behaviour.

int pmemkv_write_iterator_write_range(pmemkv_write_iterator *it, size_t pos, size_t n, char **data, size_t *wb);

Allows getting record’s value’s range which can be modified. You can request for either full value or only value’s subrange (n elements starting from pos). Assigns pointer to the beginning of the requested range to data, and number of elements in range to wb. If n is bigger than length of a value it’s automatically shrunk. Changes made on a requested range are not persistent until pmemkv_write_iterator_commit() is called. If the iterator is on an undefined position, calling this method is undefined behaviour.

int pmemkv_write_iterator_commit(pmemkv_write_iterator *it);

Commits modifications made on the current record. Calling this method is the only way to save modifications made by the iterator on the current record. You need to call this method before changing the iterator position, otherwise modifications will be automatically aborted.

void pmemkv_write_iterator_abort(pmemkv_write_iterator *it);

Aborts uncommitted modifications made on the current record.

ERRORS

Each function, except for pmemkv_iterator_delete(), pmemkv_write_iterator_delete() and pmemkv_write_iterator_abort(), returns one of the pmemkv status codes. To check possible options see libpmemkv(3).

EXAMPLE

The following example is taken from examples/pmemkv_iterator_c directory.

Usage of basic iterator functions to iterate over all records and modify one of them.

#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); }

<span style="color:#66d9ef">const</span> size_t n_elements <span style="color:#f92672">=</span> <span style="color:#ae81ff">10</span>;
<span style="color:#66d9ef">char</span> buffer[<span style="color:#ae81ff">64</span>];

<span style="color:#75715e">/* See libpmemkv_config(3) for more detailed example of config creation */</span>
LOG(<span style="color:#e6db74">&#34;Creating config&#34;</span>);
pmemkv_config <span style="color:#f92672">*</span>cfg <span style="color:#f92672">=</span> pmemkv_config_new();
ASSERT(cfg <span style="color:#f92672">!=</span> NULL);

<span style="color:#66d9ef">int</span> s <span style="color:#f92672">=</span> pmemkv_config_put_path(cfg, argv[<span style="color:#ae81ff">1</span>]);
ASSERT(s <span style="color:#f92672">==</span> PMEMKV_STATUS_OK);
s <span style="color:#f92672">=</span> pmemkv_config_put_size(cfg, SIZE);
ASSERT(s <span style="color:#f92672">==</span> PMEMKV_STATUS_OK);
s <span style="color:#f92672">=</span> pmemkv_config_put_create_if_missing(cfg, true);
ASSERT(s <span style="color:#f92672">==</span> PMEMKV_STATUS_OK);

LOG(<span style="color:#e6db74">&#34;Opening pmemkv database with &#39;radix&#39; engine&#34;</span>);
pmemkv_db <span style="color:#f92672">*</span>db <span style="color:#f92672">=</span> NULL;
s <span style="color:#f92672">=</span> pmemkv_open(<span style="color:#e6db74">&#34;radix&#34;</span>, cfg, <span style="color:#f92672">&amp;</span>db);
ASSERT(s <span style="color:#f92672">==</span> PMEMKV_STATUS_OK);
ASSERT(db <span style="color:#f92672">!=</span> NULL);

LOG(<span style="color:#e6db74">&#34;Putting new keys&#34;</span>);
<span style="color:#66d9ef">for</span> (size_t i <span style="color:#f92672">=</span> <span style="color:#ae81ff">0</span>; i <span style="color:#f92672">&lt;</span> n_elements; <span style="color:#f92672">++</span>i) {
	<span style="color:#66d9ef">char</span> key[<span style="color:#ae81ff">10</span>];
	<span style="color:#66d9ef">const</span> <span style="color:#66d9ef">char</span> <span style="color:#f92672">*</span>value <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;value&#34;</span>;
	sprintf(key, <span style="color:#e6db74">&#34;key%zu&#34;</span>, i);
	s <span style="color:#f92672">=</span> pmemkv_put(db, key, strlen(key), value, strlen(value));
	ASSERT(s <span style="color:#f92672">==</span> PMEMKV_STATUS_OK);
}

<span style="color:#75715e">/* get a new read iterator */</span>
pmemkv_iterator <span style="color:#f92672">*</span>it;
s <span style="color:#f92672">=</span> pmemkv_iterator_new(db, <span style="color:#f92672">&amp;</span>it);
ASSERT(s <span style="color:#f92672">==</span> PMEMKV_STATUS_OK);

LOG(<span style="color:#e6db74">&#34;Iterate from first to last element&#34;</span>);
s <span style="color:#f92672">=</span> pmemkv_iterator_seek_to_first(it);
ASSERT(s <span style="color:#f92672">==</span> PMEMKV_STATUS_OK);

size_t element_number <span style="color:#f92672">=</span> <span style="color:#ae81ff">0</span>;
<span style="color:#66d9ef">do</span> {
	<span style="color:#66d9ef">const</span> <span style="color:#66d9ef">char</span> <span style="color:#f92672">*</span>str;
	size_t cnt;
	<span style="color:#75715e">/* read a key */</span>
	s <span style="color:#f92672">=</span> pmemkv_iterator_key(it, <span style="color:#f92672">&amp;</span>str, <span style="color:#f92672">&amp;</span>cnt);
	ASSERT(s <span style="color:#f92672">==</span> PMEMKV_STATUS_OK);
	sprintf(buffer, <span style="color:#e6db74">&#34;Key %zu = %s&#34;</span>, element_number<span style="color:#f92672">++</span>, str);
	LOG(buffer);
} <span style="color:#66d9ef">while</span> (pmemkv_iterator_next(it) <span style="color:#f92672">!=</span> PMEMKV_STATUS_NOT_FOUND);

<span style="color:#75715e">/* iterator must be deleted manually */</span>
pmemkv_iterator_delete(it);

<span style="color:#75715e">/* get a new write_iterator */</span>
pmemkv_write_iterator <span style="color:#f92672">*</span>w_it;
s <span style="color:#f92672">=</span> pmemkv_write_iterator_new(db, <span style="color:#f92672">&amp;</span>w_it);
ASSERT(s <span style="color:#f92672">==</span> PMEMKV_STATUS_OK);

<span style="color:#75715e">/* 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);

<span style="color:#75715e">/* get a write range, to modify last element&#39;s value */</span>
<span style="color:#66d9ef">char</span> <span style="color:#f92672">*</span>data;
size_t cnt;
s <span style="color:#f92672">=</span> pmemkv_write_iterator_write_range(w_it, <span style="color:#ae81ff">0</span>, <span style="color:#ae81ff">5</span>, <span style="color:#f92672">&amp;</span>data, <span style="color:#f92672">&amp;</span>cnt);
ASSERT(s <span style="color:#f92672">==</span> PMEMKV_STATUS_OK);

<span style="color:#66d9ef">for</span> (size_t i <span style="color:#f92672">=</span> <span style="color:#ae81ff">0</span>; i <span style="color:#f92672">&lt;</span> cnt; <span style="color:#f92672">++</span>i)
	data[i] <span style="color:#f92672">=</span> <span style="color:#e6db74">&#39;x&#39;</span>;

<span style="color:#75715e">/* commit changes */</span>
s <span style="color:#f92672">=</span> pmemkv_write_iterator_commit(w_it);
ASSERT(s <span style="color:#f92672">==</span> PMEMKV_STATUS_OK);

<span style="color:#75715e">/* get a read range, to read modified value */</span>
<span style="color:#66d9ef">const</span> <span style="color:#66d9ef">char</span> <span style="color:#f92672">*</span>str;
s <span style="color:#f92672">=</span> pmemkv_iterator_read_range(w_it<span style="color:#f92672">-&gt;</span>iter, <span style="color:#ae81ff">0</span>, <span style="color:#ae81ff">5</span>, <span style="color:#f92672">&amp;</span>str, <span style="color:#f92672">&amp;</span>cnt);
ASSERT(s <span style="color:#f92672">==</span> PMEMKV_STATUS_OK);

<span style="color:#75715e">/* verify a modified value */</span>
ASSERT(strcmp(str, <span style="color:#e6db74">&#34;xxxxx&#34;</span>) <span style="color:#f92672">==</span> <span style="color:#ae81ff">0</span>);
sprintf(buffer, <span style="color:#e6db74">&#34;Modified value = %s&#34;</span>, str);
LOG(buffer);

<span style="color:#75715e">/* iterator must be deleted manually */</span>
pmemkv_write_iterator_delete(w_it);

LOG(<span style="color:#e6db74">&#34;Closing database&#34;</span>);
pmemkv_close(db);

<span style="color:#66d9ef">return</span> <span style="color:#ae81ff">0</span>;

}

SEE ALSO

libpmemkv(7), libpmemkv(3) and https://pmem.io

The contents of this web site and the associated GitHub repositories are BSD-licensed open source.