libstddjb
libskarnet
skalibs
Software
skarnet.org

# The `skalibs/cdb.h` header

## General information

A cdb, for constant database, is an immutable key-value store. In skalibs, a cdb is built once via the cdbmake primitives and stored on disk; the `cdb` primitives, documented here, are about accessing the information.

## Data structures

- A `cdb` is an opaque structure, that must be initialized to `CDB_ZERO` when declared.
- A `cdb_data` is a structure that is passed by address to cdb-reading primitives, which fill it with record information. It contains (at least) two fields:
  - `s`, a `char const *`, which holds a pointer to the record; the `const` indicates that a cdb is read-only, you cannot write to the record even when you have a pointer to it.
  - `len`, a `uint32_t`, which holds the record length. It can be zero (records can be empty). A cdb must fit into 4 GB, so record lengths always fit in 32 bits.
  Pointers returned in a `cdb_data` are only valid while the cdb is mapped. Make sure to copy the information before calling `cdb_free()`.
- A `cdb_find_state` is an opaque structure, that should be initialized to `CDB_FIND_STATE_ZERO` when declared. It is passed by address to `cdb_findnext`, to maintain position state when looking for all the data records under one key.

## Macros and functions

### Starting and ending

`int cdb_init (cdb *c, char const *file)`
Maps the file named file to the cdb pointed to by c. *c must be CDB_ZERO before the call. The function returns a positive integer if it succeeds, and 0 (and sets errno) if it fails.

`int cdb_init_at (cdb *c, int dfd, char const *file)`
Like `cdb_init`, but file is interpreted relative to the file descriptor dfd, which must be open on a directory.

`int cdb_init_fromfd (cdb *c, int fd)`
Like `cdb_init`, but the database file is already open and readable via then file descriptor fd.

`void cdb_free (cdb *c)`
Frees the resources used by a cdb mapping. After the call, c is immediately reusable by another `cdb_init` function.

### cdb lookup

#### Single record lookup

`int cdb_find (cdb const *c, cdb_data *data, char const *key, uint32_t klen)`
Looks up key key of length klen in the cdb *c. The function returns -1 if *c isn't a valid cdb; 0 if no record can be found for the key; and 1 on success, in which case the corresponding value is returned in *data: `data→s` points to the start of the value, and `data→len` contains the length of the value. Only the first record with the same key can be obtained this way.

#### Multiple record lookup

`void cdb_findstart (cdb_find_state *state)`
Initializes state so that the next invocation of `cdb_findnext()` finds the first record for a given key.

`int cdb_findnext (cdb const *c, cdb_data *data, char const *key, uint32_t klen, cdb_find_state *state)`
Like `cdb_find`, except that the extra argument state memorizes internal cdb lookup data, so the next `cdb_findnext()` invocation with the same key, klen and state will yield the next record for the key. `cdb_findnext` returns 0 when all the records for the key have been exhausted.

### cdb enumeration

`void cdb_traverse_init (uint32_t *pos)`
Initializes *pos so that the next invocation of `cdb_traverse_next` finds the first entry in the cdb. *pos can also be initialized to the macro CDB_TRAVERSE_INIT() instead.

`int cdb_traverse_next (cdb const *c, cdb_data *key, cdb_data *data, uint32_t *pos)`
Gets the next entry in the cdb *c. On success, the key is stored in *key and the data is stored in *data. *pos* is an opaque integer storing internal state; it is automatically updated so that the next invocation of `cdb_traverse_next()` yields the next entry. The function returns -1 if *c is not a valid cdb or *pos is not valid state, 1 on success, and 0 if no entry can be found, i.e. the end of the cdb has been reached.