| Elektra 0.11.0

Public Member Functions | List of all members
kdb::KDB Class Reference

Constructs a class KDB. More...

`#include <kdb.hpp>`

Inheritance diagram for kdb::KDB:

## Public Member Functions
| KDB ()
| Constructs a class KDB.
| KDB (Key &errorKey)
| Constructs a class KDB.
| KDB (KeySet &contract)
| Constructs a class KDB.
| KDB (KeySet &contract, Key &errorKey)
| Constructs a class KDB.
virtual void | open (Key &errorKey)
| Open the database.
virtual void | open (KeySet &contract, Key &errorKey)
| Open the database.
virtual void | close () throw ()
| Close the database.
virtual void | close (Key &errorKey) throw ()
| Close the database.
virtual int | get (KeySet &returned, std::string const &keyname)
| Get all keys below keyname inside returned.
virtual int | get (KeySet &returned, Key &parentKey)
| Get all keys below parentKey inside returned.
virtual int | set (KeySet &returned, std::string const &keyname)
| Set all keys below keyname.
virtual int | set (KeySet &returned, Key &parentKey)
| Set all keys below parentKey.
virtual ElektraDiff | calculateChanges (KeySet &changedKeySet, std::string const &parentKeyName)
| Calculates the changes between the provided KeySet and the current state of the KDB.
virtual ElektraDiff | calculateChanges (KeySet &changedKeySet, Key &parentKey)
| Calculates the changes between the provided KeySet and the current state of the KDB.
ckdb::KDB * | getKdb () const
| Passes out the raw kdb pointer.
ckdb::KDB * | operator* () const
| Is an abbreviation for getKdb.

## Detailed Description

Constructs a class KDB.

Exceptions

  KDBException | if database could not be opened

Opens the session with the Key database.

Precondition
  errorKey must be a valid key, e.g. created with keyNew()

You must always call this method before retrieving or committing any keys to the database. At the end of a program, after using the Key database (KDB), you must not forget to call kdbClose() to free resources.

The method will bootstrap itself in the following way. The first step is to open the default backend. With it `system:/elektra/mountpoints` will be loaded and all needed libraries and mountpoints will be determined. Then the global plugins and global keyset data from the `contract` is processed. Finally, the libraries for backends will be loaded and with it the `KDB` data structure will be initialized.

The pointer to the `KDB` structure returned will be initialized like described above, and it must be passed along on any kdb*() method your application calls.

Get a `KDB` handle for every thread using elektra. Don't share the handle across threads, and also not the pointer accessing it:

void thread1 (void)
{
Key * parent = keyNew ("/app/part1", KEY_END);
KDB * h = kdbOpen (NULL, parent);
// fetch keys and work with them
kdbClose (h, parent);
}
void thread2 (void)
{
Key * parent = keyNew ("/app/part2", KEY_END);
KDB * h = kdbOpen (NULL, parent);
// fetch keys and work with them
kdbClose (h, parent);
}
kdb::KDB
Constructs a class KDB.
Definition kdb.hpp:45
kdb::Key
Key is an essential class that encapsulates key name , value and metainfo .
Definition key.hpp:98
kdbOpen
KDB * kdbOpen(const KeySet *contract, Key *errorKey)
Opens the session with the Key database.
Definition kdb.c:967
kdbClose
int kdbClose(KDB *handle, Key *errorKey)
Closes the session with the Key database.
Definition kdb.c:1105
keyNew
Key * keyNew(const char *name,...)
A practical way to fully create a Key object in one step.
Definition key.c:144

You don't need kdbOpen() if you only want to manipulate plain in-memory Key or KeySet objects.

Precondition
  errorKey must be a valid key, e.g. created with keyNew()

Parameters

  contract | the contract that should be ensured before opening the KDB all data is copied and the KeySet can safely be used for e.g. kdbGet() later
  errorKey | the key which holds errors and warnings which were issued

Returns
  handle to the newly created KDB on success

Return values

  NULL | on failure

Since
  1.0.0

See also
  kdbClose() to close the session of a Key database opened by kdbOpen()

Access to the key database.

Invariant
  the object holds a valid connection to the key database or is empty

## Constructor & Destructor Documentation

## ◆ KDB() [1/4]

kdb::KDB::KDB | ( |  | ) |
| inline

Constructs a class KDB.

Exceptions

  KDBException | if database could not be opened

Opens the session with the Key database.

Precondition
  errorKey must be a valid key, e.g. created with keyNew()

You must always call this method before retrieving or committing any keys to the database. At the end of a program, after using the Key database (KDB), you must not forget to call kdbClose() to free resources.

The method will bootstrap itself in the following way. The first step is to open the default backend. With it `system:/elektra/mountpoints` will be loaded and all needed libraries and mountpoints will be determined. Then the global plugins and global keyset data from the `contract` is processed. Finally, the libraries for backends will be loaded and with it the `KDB` data structure will be initialized.

The pointer to the `KDB` structure returned will be initialized like described above, and it must be passed along on any kdb*() method your application calls.

Get a `KDB` handle for every thread using elektra. Don't share the handle across threads, and also not the pointer accessing it:

void thread1 (void)
{
Key * parent = keyNew ("/app/part1", KEY_END);
KDB * h = kdbOpen (NULL, parent);
// fetch keys and work with them
kdbClose (h, parent);
}
void thread2 (void)
{
Key * parent = keyNew ("/app/part2", KEY_END);
KDB * h = kdbOpen (NULL, parent);
// fetch keys and work with them
kdbClose (h, parent);
}

You don't need kdbOpen() if you only want to manipulate plain in-memory Key or KeySet objects.

Precondition
  errorKey must be a valid key, e.g. created with keyNew()

Parameters

  contract | the contract that should be ensured before opening the KDB all data is copied and the KeySet can safely be used for e.g. kdbGet() later
  errorKey | the key which holds errors and warnings which were issued

Returns
  handle to the newly created KDB on success

Return values

  NULL | on failure

Since
  1.0.0

See also
  kdbClose() to close the session of a Key database opened by kdbOpen()

## ◆ KDB() [2/4]

kdb::KDB::KDB | ( | Key & | errorKey | ) |
| inline explicit

Constructs a class KDB.

Parameters

  errorKey | is useful if you want to get the warnings in the successful case, when no exception is thrown.

Exceptions

  KDBException | if database could not be opened

Opens the session with the Key database.

Precondition
  errorKey must be a valid key, e.g. created with keyNew()

You must always call this method before retrieving or committing any keys to the database. At the end of a program, after using the Key database (KDB), you must not forget to call kdbClose() to free resources.

The method will bootstrap itself in the following way. The first step is to open the default backend. With it `system:/elektra/mountpoints` will be loaded and all needed libraries and mountpoints will be determined. Then the global plugins and global keyset data from the `contract` is processed. Finally, the libraries for backends will be loaded and with it the `KDB` data structure will be initialized.

The pointer to the `KDB` structure returned will be initialized like described above, and it must be passed along on any kdb*() method your application calls.

Get a `KDB` handle for every thread using elektra. Don't share the handle across threads, and also not the pointer accessing it:

void thread1 (void)
{
Key * parent = keyNew ("/app/part1", KEY_END);
KDB * h = kdbOpen (NULL, parent);
// fetch keys and work with them
kdbClose (h, parent);
}
void thread2 (void)
{
Key * parent = keyNew ("/app/part2", KEY_END);
KDB * h = kdbOpen (NULL, parent);
// fetch keys and work with them
kdbClose (h, parent);
}

You don't need kdbOpen() if you only want to manipulate plain in-memory Key or KeySet objects.

Precondition
  errorKey must be a valid key, e.g. created with keyNew()

Parameters

  contract | the contract that should be ensured before opening the KDB all data is copied and the KeySet can safely be used for e.g. kdbGet() later
  errorKey | the key which holds errors and warnings which were issued

Returns
  handle to the newly created KDB on success

Return values

  NULL | on failure

Since
  1.0.0

See also
  kdbClose() to close the session of a Key database opened by kdbOpen()

## ◆ KDB() [3/4]

kdb::KDB::KDB | ( | KeySet & | contract | ) |
| inline explicit

Constructs a class KDB.

Parameters

  contract | the contract that should be ensured
  errorKey | is useful if you want to get the warnings in the successful case, when no exception is thrown.

Exceptions

  KDBException | if database could not be opened

Opens the session with the Key database.

Precondition
  errorKey must be a valid key, e.g. created with keyNew()

You must always call this method before retrieving or committing any keys to the database. At the end of a program, after using the Key database (KDB), you must not forget to call kdbClose() to free resources.

The method will bootstrap itself in the following way. The first step is to open the default backend. With it `system:/elektra/mountpoints` will be loaded and all needed libraries and mountpoints will be determined. Then the global plugins and global keyset data from the `contract` is processed. Finally, the libraries for backends will be loaded and with it the `KDB` data structure will be initialized.

The pointer to the `KDB` structure returned will be initialized like described above, and it must be passed along on any kdb*() method your application calls.

Get a `KDB` handle for every thread using elektra. Don't share the handle across threads, and also not the pointer accessing it:

void thread1 (void)
{
Key * parent = keyNew ("/app/part1", KEY_END);
KDB * h = kdbOpen (NULL, parent);
// fetch keys and work with them
kdbClose (h, parent);
}
void thread2 (void)
{
Key * parent = keyNew ("/app/part2", KEY_END);
KDB * h = kdbOpen (NULL, parent);
// fetch keys and work with them
kdbClose (h, parent);
}

You don't need kdbOpen() if you only want to manipulate plain in-memory Key or KeySet objects.

Precondition
  errorKey must be a valid key, e.g. created with keyNew()

Parameters

  contract | the contract that should be ensured before opening the KDB all data is copied and the KeySet can safely be used for e.g. kdbGet() later
  errorKey | the key which holds errors and warnings which were issued

Returns
  handle to the newly created KDB on success

Return values

  NULL | on failure

Since
  1.0.0

See also
  kdbClose() to close the session of a Key database opened by kdbOpen()

## ◆ KDB() [4/4]

kdb::KDB::KDB | ( | KeySet & | contract,
|  | Key & | errorKey
| ) |  |
| inline

Constructs a class KDB.

Parameters

  contract | the contract that should be ensured
  errorKey | is useful if you want to get the warnings in the successful case, when no exception is thrown.

Exceptions

  KDBException | if database could not be opened

Opens the session with the Key database.

Precondition
  errorKey must be a valid key, e.g. created with keyNew()

You must always call this method before retrieving or committing any keys to the database. At the end of a program, after using the Key database (KDB), you must not forget to call kdbClose() to free resources.

The method will bootstrap itself in the following way. The first step is to open the default backend. With it `system:/elektra/mountpoints` will be loaded and all needed libraries and mountpoints will be determined. Then the global plugins and global keyset data from the `contract` is processed. Finally, the libraries for backends will be loaded and with it the `KDB` data structure will be initialized.

The pointer to the `KDB` structure returned will be initialized like described above, and it must be passed along on any kdb*() method your application calls.

Get a `KDB` handle for every thread using elektra. Don't share the handle across threads, and also not the pointer accessing it:

void thread1 (void)
{
Key * parent = keyNew ("/app/part1", KEY_END);
KDB * h = kdbOpen (NULL, parent);
// fetch keys and work with them
kdbClose (h, parent);
}
void thread2 (void)
{
Key * parent = keyNew ("/app/part2", KEY_END);
KDB * h = kdbOpen (NULL, parent);
// fetch keys and work with them
kdbClose (h, parent);
}

You don't need kdbOpen() if you only want to manipulate plain in-memory Key or KeySet objects.

Precondition
  errorKey must be a valid key, e.g. created with keyNew()

Parameters

  contract | the contract that should be ensured before opening the KDB all data is copied and the KeySet can safely be used for e.g. kdbGet() later
  errorKey | the key which holds errors and warnings which were issued

Returns
  handle to the newly created KDB on success

Return values

  NULL | on failure

Since
  1.0.0

See also
  kdbClose() to close the session of a Key database opened by kdbOpen()

## Member Function Documentation

## ◆ calculateChanges() [1/2]

ElektraDiff kdb::KDB::calculateChanges | ( | KeySet & | changedKeySet,
|  | Key & | parentKey
| ) |  |
| inline virtual

Calculates the changes between the provided KeySet and the current state of the KDB.

Parameters

  changedKeySet | the keyset that should be used to diff
  parentKey | only changes same or below this keys are calculated

Returns
  a diff with all the changes

## ◆ calculateChanges() [2/2]

ElektraDiff kdb::KDB::calculateChanges | ( | KeySet & | changedKeySet,
|  | std::string const & | parentKeyName
| ) |  |
| inline virtual

Calculates the changes between the provided KeySet and the current state of the KDB.

Parameters

  changedKeySet | the keyset that should be used to diff
  parentKeyName | only changes same or below this keys are calculated

Returns
  a diff with all the changes

## ◆ close() [1/2]

void kdb::KDB::close | ( |  | ) |
throw | ( |
| ) |  |
| inline virtual

Close the database.

The return value does not matter because its only a null pointer check.

Closes the session with the Key database.

Precondition
  The handle must be a valid handle as returned from kdbOpen()
  errorKey must be a valid key, e.g. created with keyNew()

This is the counterpart of kdbOpen().

You must call this method when you are finished working with the Key database. You can manipulate Key and KeySet objects also after kdbClose(), but you must not use any kdb*() call afterwards.

The `handle` parameter will be finalized and all resources associated to it will be freed. After a kdbClose(), the `handle` cannot be used anymore.

Parameters

  handle | contains internal information of opened key database
  errorKey | the key which holds error/warning information

Return values

  0 | on success
  -1 | on NULL pointer

Since
  1.0.0

See also
  kdbOpen() for opening a session with a Key database

## ◆ close() [2/2]

void kdb::KDB::close | ( | Key & | errorKey | ) |
throw | ( |
| ) |  |
| inline virtual

Close the database.

The return value does not matter because its only a null pointer check.

Parameters

  errorKey | is useful if you want to get the warnings

Closes the session with the Key database.

Precondition
  The handle must be a valid handle as returned from kdbOpen()
  errorKey must be a valid key, e.g. created with keyNew()

This is the counterpart of kdbOpen().

You must call this method when you are finished working with the Key database. You can manipulate Key and KeySet objects also after kdbClose(), but you must not use any kdb*() call afterwards.

The `handle` parameter will be finalized and all resources associated to it will be freed. After a kdbClose(), the `handle` cannot be used anymore.

Parameters

  handle | contains internal information of opened key database
  errorKey | the key which holds error/warning information

Return values

  0 | on success
  -1 | on NULL pointer

Since
  1.0.0

See also
  kdbOpen() for opening a session with a Key database

## ◆ get() [1/2]

int kdb::KDB::get | ( | KeySet & | returned,
|  | Key & | parentKey
| ) |  |
| inline virtual

Get all keys below parentKey inside returned.

Retrieve Keys from the Key database in an atomic and universal way.

Precondition
  The `handle` must be a valid KDB handle as returned from kdbOpen().
  The KeySet `returned` must be a valid KeySet, i.e., constructed with ksNew().
  The KeySet `returned` must contain keys only from the `spec:/`, `dir:/`, `user:/`, `system:/`, `default:/` or `proc:/` namespaces.
  The Key `parentKey` must be a valid Key, i.e., constructed with keyNew().
  The Key `parentKey` must not have read-only name, value or metadata.
  The Key `parentKey` must use the `spec:/`, `dir:/`, `user:/`, `system:/`, `default:/`, `proc:/` or cascading namespace.

If you pass `NULL` or a key with read-only metadata as `parentKey`, kdbGet() will fail immediately without doing anything. If you pass another invalid `parentKey`, or `NULL` as `ks` or `handle`, kdbGet() will set an error on `parentKey` and then return immediately.

Note
  If you pass a non-NULL `parentKey` with writable metadata, kdbGet() will always remove any existing errors and warnings from `parentKey`.

Warning
  If you later call kdbSet() with the same `handle` you must make sure to pass all keys from `ks`, which you do not want to remove.

Loadable Namespaces

Not all namespace can be loaded.

- `spec:/`, `dir:/`, `user:/` and `system:/` can be loaded via kdbGet().
- `proc:/` keys can be loaded via kdbGet(), but are not persisted or cached.
- `default:/` keys can be inserted by kdbGet() but they will always stem from a specification in `spec:/` keys.
- If `ks` contains a key with any other namespace, an error will be returned.

Parent Key

The `parentKey` defines which parts of `ks` will be loaded. Everything that is at or below `parentKey` wil be loaded together with any key that shares a backend with such a key. Backends are always loaded as an atomic unit.

Note
  If `parentKey` is in the cascading namespace, keys of all loadable namespaces (see above) will be loaded. This is generally the recommended approach.

Upon sucessfully returning kdbGet() also sets the value of `parentKey` to the storage identifier used by the backend that contains (or would contain) `parentKey`. For file-based backends this is the absolute path of the underlying file. Other backends may use different identifiers, but it always uniquely identifies the underlying storage unit.

Note
  If `parentKey` is in the cascading, `default:/` or `proc:/ namespace, the value of `parentKey` will be set to an empty string. This is done, because those namespaces are not persistable (see kdbSet()) and therfore have no storage identifier.

KeySet Modifications

Below or at `parentKey`, the KeySet `ks` will mostly contain keys loaded from backends. The only exception are `proc:/` and `spec:/` keys that were already present, before kdbGet() was called and do not overlap with an existing backend (for those namespaces). This can be used to provide a hard-coded fallback specifications and/or process-specific data.

Keys not below (or at) `parentKey` that were present when kdbGet() was called, may still be removed. For example, this could be because they overlap with a backend that also has keys below `parentKey` (backends are atomic units).

Example:
  This example demonstrates the typical usecase within an application (without error handling).

#include <kdb.h>
#include <stdio.h>
int main (void)
{
KeySet * myConfig = ksNew (0, KS_END);
// for error handling see kdbget_error.c
// clang-format off
Key * key = keyNew ("/sw/tests/myapp/#0/current/", KEY_END);
KDB * handle = kdbOpen (NULL, key);
kdbGet (handle, myConfig, key);
Key * result = ksLookupByName (myConfig, "/sw/tests/myapp/#0/current/testkey1", 0);
// clang-format on
keyDel (key);
const char * key_name = keyName (result);
const char * key_value = keyString (result);
const char * key_comment = keyString (keyGetMeta (result, "comment/#0"));
printf ("key: %s value: %s comment: %s\n", key_name, key_value, key_comment);
ksDel (myConfig); // delete the in-memory configuration
// maybe you want kdbSet() myConfig here
kdbClose (handle, 0); // no more affairs with the key database.
}
kdb::KeySet
A keyset holds together a set of keys.
Definition keyset.hpp:54
kdbGet
int kdbGet(KDB *handle, KeySet *ks, Key *parentKey)
Retrieve Keys from the Key database in an atomic and universal way.
Definition kdb.c:1734
keyDel
int keyDel(Key *key)
A destructor for Key objects.
Definition key.c:459
keyGetMeta
const Key * keyGetMeta(const Key *key, const char *metaName)
Returns the Key for a metadata entry with name metaName.
Definition keymeta.c:379
keyName
const char * keyName(const Key *key)
Returns a pointer to the abbreviated real internal key name.
Definition elektra/keyname.c:429
ksDel
int ksDel(KeySet *ks)
A destructor for KeySet objects.
Definition keyset.c:521
KS_END
#define KS_END
End of a list of keys.
Definition kdbenum.c:156
ksLookupByName
Key * ksLookupByName(KeySet *ks, const char *name, elektraLookupFlags options)
Convenience method to look for a Key contained in ks with name name.
Definition keyset.c:2778
ksNew
KeySet * ksNew(size_t alloc,...)
Allocate, initialize and return a new KeySet object.
Definition keyset.c:282
keyString
const char * keyString(const Key *key)
Get a pointer to the c-string representing the value.
Definition keyvalue.c:208

When a backend fails kdbGet() will return -1 with all error and warning information in the `parentKey`. The parameter `returned` will not be changed.

Optimization:
  In the first run of kdbGet all requested (or more) Keys are retrieved. On subsequent calls only the Keys are retrieved where something was changed inside the Key database. The other Keys stay in the KeySet returned as passed.

It is your responsibility to save the original KeySet if you need it afterwards.

If you want to be sure to get a fresh KeySet again, you need to open a second handle to the Key database using kdbOpen().

Parameters

  handle | contains internal information of opened key database
  parentKey | Keys below `parentKey` will be retrieved from `handle`. It is also used to add warnings and set error information.
  ks | the (pre-initialized) KeySet returned with all keys found will not be changed on error or if no update is required

Return values

  2 | if only `proc:/` backends were executed. This means no data was loaded from storage. There might be warnings attached to the parentKey! Depending on your use case, you might need to treat them as errors!
  1 | if the Keys were retrieved successfully. There might be warnings attached to the parentKey! Depending on your use case, you might need to treat them as errors!
  0 | if there was no update at all - no changes are made to the KeySet then. There might be warnings attached to the parentKey! Depending on your use case, you might need to treat them as erorrs!
  -1 | on failure - no changes are made to the KeySet then

Since
  1.0.0

See also
  ksLookup(), ksLookupByName() for powerful lookups after the KeySet was retrieved
  kdbOpen() which needs to be called before
  kdbSet() to save the configuration afterwards
  kdbClose() to finish affairs with the Key database.

Parameters

  returned | the keyset where the keys will be in
  parentKey | the parentKey of returned

Return values

  0 | if no key was updated
  1 | if user or system keys were updated
  2 | if user and system keys were updated

Exceptions

  KDBException | if there were problems with the database

Reimplemented in kdb::tools::merging::MergingKDB.

## ◆ get() [2/2]

int kdb::KDB::get | ( | KeySet & | returned,
|  | std::string const & | keyname
| ) |  |
| inline virtual

Get all keys below keyname inside returned.

Retrieve Keys from the Key database in an atomic and universal way.

Precondition
  The `handle` must be a valid KDB handle as returned from kdbOpen().
  The KeySet `returned` must be a valid KeySet, i.e., constructed with ksNew().
  The KeySet `returned` must contain keys only from the `spec:/`, `dir:/`, `user:/`, `system:/`, `default:/` or `proc:/` namespaces.
  The Key `parentKey` must be a valid Key, i.e., constructed with keyNew().
  The Key `parentKey` must not have read-only name, value or metadata.
  The Key `parentKey` must use the `spec:/`, `dir:/`, `user:/`, `system:/`, `default:/`, `proc:/` or cascading namespace.

If you pass `NULL` or a key with read-only metadata as `parentKey`, kdbGet() will fail immediately without doing anything. If you pass another invalid `parentKey`, or `NULL` as `ks` or `handle`, kdbGet() will set an error on `parentKey` and then return immediately.

Note
  If you pass a non-NULL `parentKey` with writable metadata, kdbGet() will always remove any existing errors and warnings from `parentKey`.

Warning
  If you later call kdbSet() with the same `handle` you must make sure to pass all keys from `ks`, which you do not want to remove.

Loadable Namespaces

Not all namespace can be loaded.

- `spec:/`, `dir:/`, `user:/` and `system:/` can be loaded via kdbGet().
- `proc:/` keys can be loaded via kdbGet(), but are not persisted or cached.
- `default:/` keys can be inserted by kdbGet() but they will always stem from a specification in `spec:/` keys.
- If `ks` contains a key with any other namespace, an error will be returned.

Parent Key

The `parentKey` defines which parts of `ks` will be loaded. Everything that is at or below `parentKey` wil be loaded together with any key that shares a backend with such a key. Backends are always loaded as an atomic unit.

Note
  If `parentKey` is in the cascading namespace, keys of all loadable namespaces (see above) will be loaded. This is generally the recommended approach.

Upon sucessfully returning kdbGet() also sets the value of `parentKey` to the storage identifier used by the backend that contains (or would contain) `parentKey`. For file-based backends this is the absolute path of the underlying file. Other backends may use different identifiers, but it always uniquely identifies the underlying storage unit.

Note
  If `parentKey` is in the cascading, `default:/` or `proc:/ namespace, the value of `parentKey` will be set to an empty string. This is done, because those namespaces are not persistable (see kdbSet()) and therfore have no storage identifier.

KeySet Modifications

Below or at `parentKey`, the KeySet `ks` will mostly contain keys loaded from backends. The only exception are `proc:/` and `spec:/` keys that were already present, before kdbGet() was called and do not overlap with an existing backend (for those namespaces). This can be used to provide a hard-coded fallback specifications and/or process-specific data.

Keys not below (or at) `parentKey` that were present when kdbGet() was called, may still be removed. For example, this could be because they overlap with a backend that also has keys below `parentKey` (backends are atomic units).

Example:
  This example demonstrates the typical usecase within an application (without error handling).

#include <kdb.h>
#include <stdio.h>
int main (void)
{
KeySet * myConfig = ksNew (0, KS_END);
// for error handling see kdbget_error.c
// clang-format off
Key * key = keyNew ("/sw/tests/myapp/#0/current/", KEY_END);
KDB * handle = kdbOpen (NULL, key);
kdbGet (handle, myConfig, key);
Key * result = ksLookupByName (myConfig, "/sw/tests/myapp/#0/current/testkey1", 0);
// clang-format on
keyDel (key);
const char * key_name = keyName (result);
const char * key_value = keyString (result);
const char * key_comment = keyString (keyGetMeta (result, "comment/#0"));
printf ("key: %s value: %s comment: %s\n", key_name, key_value, key_comment);
ksDel (myConfig); // delete the in-memory configuration
// maybe you want kdbSet() myConfig here
kdbClose (handle, 0); // no more affairs with the key database.
}

When a backend fails kdbGet() will return -1 with all error and warning information in the `parentKey`. The parameter `returned` will not be changed.

Optimization:
  In the first run of kdbGet all requested (or more) Keys are retrieved. On subsequent calls only the Keys are retrieved where something was changed inside the Key database. The other Keys stay in the KeySet returned as passed.

It is your responsibility to save the original KeySet if you need it afterwards.

If you want to be sure to get a fresh KeySet again, you need to open a second handle to the Key database using kdbOpen().

Parameters

  handle | contains internal information of opened key database
  parentKey | Keys below `parentKey` will be retrieved from `handle`. It is also used to add warnings and set error information.
  ks | the (pre-initialized) KeySet returned with all keys found will not be changed on error or if no update is required

Return values

  2 | if only `proc:/` backends were executed. This means no data was loaded from storage. There might be warnings attached to the parentKey! Depending on your use case, you might need to treat them as errors!
  1 | if the Keys were retrieved successfully. There might be warnings attached to the parentKey! Depending on your use case, you might need to treat them as errors!
  0 | if there was no update at all - no changes are made to the KeySet then. There might be warnings attached to the parentKey! Depending on your use case, you might need to treat them as erorrs!
  -1 | on failure - no changes are made to the KeySet then

Since
  1.0.0

See also
  ksLookup(), ksLookupByName() for powerful lookups after the KeySet was retrieved
  kdbOpen() which needs to be called before
  kdbSet() to save the configuration afterwards
  kdbClose() to finish affairs with the Key database.

#include <kdb.hpp>
#include <keyio.hpp>
using namespace kdb;
int main ()
{
KeySet config;
KDB kdb;
kdb.get (config, "/sw/MyApp");
Key k = config.lookup ("/sw/MyApp/mykey");
if (k)
{
std::cout << k << " is " << k.get<int> () << std::endl;
}
else
{
std::cerr << "No key found" << std::endl;
return 1;
}
}
kdb::KeySet::lookup
Key lookup(const Key &k, const elektraLookupFlags options=KDB_O_NONE) const
Look for a Key contained in ks that matches the name of the key.
Definition keyset.hpp:729
kdb::Key::get
T get() const
Get a key value.
Definition key.hpp:1083
kdb.hpp
keyio.hpp
kdb
This is the main namespace for the C++ binding and libraries.
Definition backend.hpp:31

Parameters

  returned | the keyset where the keys will be in
  keyname | the root keyname which should be used to get keys below it

Return values

  0 | if no key was updated
  1 | if user or system keys were updated
  2 | if user and system keys were updated

Exceptions

  KDBException | if there were problems with the database

See also
  KDB::get (KeySet & returned, Key & parentKey)

Reimplemented in kdb::tools::merging::MergingKDB.

## ◆ getKdb()

ckdb::KDB * kdb::KDB::getKdb | ( |  | ) | const
| inline

Passes out the raw kdb pointer.

This pointer can be used to directly interact with the underlying kdb instance

Note
  that the ownership remains in the object

## ◆ open() [1/2]

void kdb::KDB::open | ( | Key & | errorKey | ) |
| inline virtual

Open the database.

Parameters

  errorKey | is useful if you want to get the warnings in the successful case, when no exception is thrown.

Opens the session with the Key database.

Precondition
  errorKey must be a valid key, e.g. created with keyNew()

You must always call this method before retrieving or committing any keys to the database. At the end of a program, after using the Key database (KDB), you must not forget to call kdbClose() to free resources.

The method will bootstrap itself in the following way. The first step is to open the default backend. With it `system:/elektra/mountpoints` will be loaded and all needed libraries and mountpoints will be determined. Then the global plugins and global keyset data from the `contract` is processed. Finally, the libraries for backends will be loaded and with it the `KDB` data structure will be initialized.

The pointer to the `KDB` structure returned will be initialized like described above, and it must be passed along on any kdb*() method your application calls.

Get a `KDB` handle for every thread using elektra. Don't share the handle across threads, and also not the pointer accessing it:

void thread1 (void)
{
Key * parent = keyNew ("/app/part1", KEY_END);
KDB * h = kdbOpen (NULL, parent);
// fetch keys and work with them
kdbClose (h, parent);
}
void thread2 (void)
{
Key * parent = keyNew ("/app/part2", KEY_END);
KDB * h = kdbOpen (NULL, parent);
// fetch keys and work with them
kdbClose (h, parent);
}

You don't need kdbOpen() if you only want to manipulate plain in-memory Key or KeySet objects.

Precondition
  errorKey must be a valid key, e.g. created with keyNew()

Parameters

  contract | the contract that should be ensured before opening the KDB all data is copied and the KeySet can safely be used for e.g. kdbGet() later
  errorKey | the key which holds errors and warnings which were issued

Returns
  handle to the newly created KDB on success

Return values

  NULL | on failure

Since
  1.0.0

See also
  kdbClose() to close the session of a Key database opened by kdbOpen()

## ◆ open() [2/2]

void kdb::KDB::open | ( | KeySet & | contract,
|  | Key & | errorKey
| ) |  |
| inline virtual

Open the database.

Parameters

  contract | the contract that should be ensured
  errorKey | is useful if you want to get the warnings in the successful case, when no exception is thrown.

Opens the session with the Key database.

Precondition
  errorKey must be a valid key, e.g. created with keyNew()

You must always call this method before retrieving or committing any keys to the database. At the end of a program, after using the Key database (KDB), you must not forget to call kdbClose() to free resources.

The method will bootstrap itself in the following way. The first step is to open the default backend. With it `system:/elektra/mountpoints` will be loaded and all needed libraries and mountpoints will be determined. Then the global plugins and global keyset data from the `contract` is processed. Finally, the libraries for backends will be loaded and with it the `KDB` data structure will be initialized.

The pointer to the `KDB` structure returned will be initialized like described above, and it must be passed along on any kdb*() method your application calls.

Get a `KDB` handle for every thread using elektra. Don't share the handle across threads, and also not the pointer accessing it:

void thread1 (void)
{
Key * parent = keyNew ("/app/part1", KEY_END);
KDB * h = kdbOpen (NULL, parent);
// fetch keys and work with them
kdbClose (h, parent);
}
void thread2 (void)
{
Key * parent = keyNew ("/app/part2", KEY_END);
KDB * h = kdbOpen (NULL, parent);
// fetch keys and work with them
kdbClose (h, parent);
}

You don't need kdbOpen() if you only want to manipulate plain in-memory Key or KeySet objects.

Precondition
  errorKey must be a valid key, e.g. created with keyNew()

Parameters

  contract | the contract that should be ensured before opening the KDB all data is copied and the KeySet can safely be used for e.g. kdbGet() later
  errorKey | the key which holds errors and warnings which were issued

Returns
  handle to the newly created KDB on success

Return values

  NULL | on failure

Since
  1.0.0

See also
  kdbClose() to close the session of a Key database opened by kdbOpen()

## ◆ operator*()

ckdb::KDB * kdb::KDB::operator* | ( |  | ) | const
| inline

Is an abbreviation for getKdb.

Passes out the raw kdb pointer.

This pointer can be used to directly interact with the underlying kdb instance

Note
  that the ownership remains in the object

See also
  getKdb()

## ◆ set() [1/2]

int kdb::KDB::set | ( | KeySet & | returned,
|  | Key & | parentKey
| ) |  |
| inline virtual

Set all keys below parentKey.

If the keyname of the parentKey is invalid (e.g. empty) all keys will be set.

Set Keys to the Key database in an atomic and universal way.

Precondition
  kdbGet() must be called before kdbSet():
  - initially (after kdbOpen())
  - after conflict errors in kdbSet().
  The KeySet `ks` must be a valid KeySet, i.e., constructed with ksNew().
  The KeySet `ks` must only contain only keys in the `spec:/`, `dir:/`, `user:/`, `system:/`, `default:/` or `proc:/` namespaces.
  The Key `parentKey` must be a valid Key, e.g. constructed with keyNew().
  The Key `parentKey` must not have read-only name, value or metadata.
  The Key `parentKey` must use the `spec:/`, `dir:/`, `user:/`, `system:/`, `default:/`, `proc:/` or cascading namespace.

If you pass `NULL` or a key with read-only metadata as `parentKey`, kdbSet() will fail immediately without doing anything. If you pass another invalid `parentKey`, or `NULL` as `ks` or `handle`, kdbSet() will set an error on `parentKey` and then return immediately.

Note
  If you pass a non-NULL `parentKey` with writable metadata, kdbSet() will always remove any existing errors and warnings from `parentKey`.

Persistable Namespaces

Not all namespace can be persisted.

- `spec:/`, `dir:/`, `user:/` and `system:/` will be persisted by kdbSet().
- `default:/` and `proc:/` keys are ignored by kdbSet().
- If `ks` contains a key with any other namespace, an error will be returned.

In general it is recommended to use a `parentKey` in the cascading namespace to cover all namespaces at once.

Parent Key

The `parentKey` defines which parts of `ks` will be stored. Everything that is at or below `parentKey` will be persisted together with any key that shares a backend with such a key. Backends are always stored as an atomic unit.

Note
  If `parentKey` is in the cascading namespace, keys of all persistable namespaces (see above) will be stored. This is generally the recommended approach.

KeySet modifications

The contents of `ks` will mostly not be modified by kdbSet(). The only modifications made are those caused by applying the specification in `spec:/` to `dir:/`, `user:/` and `system:/`.

Errors
  If `parentKey == NULL` or `parentKey` has read-only metadata, kdbSet() will immediately return the error code -1. In all other error cases the following happens:
  - Error information will be written into the metadata of the parent key, if possible.
  - None of the keys are actually committed in this situation, i.e. no configuration file will be modified.

In case of errors you should present the error message to the user and let the user decide what to do. Possible solutions are:

- remove the problematic key and use kdbSet() again (for validation or type errors)
- change the value of the problematic key and use kdbSet() again (for validation errors)
- do a kdbGet() (for conflicts, i.e. error C02000) and then
  - set the same keyset again (in favour of what was set by this user)
  - drop the old keyset (in favour of what was set from another application)
  - merge the original, your own and the other keyset
- export the configuration into a file (for unresolvable errors)
- repeating the same kdbSet() might be of limited use, if the user does not explicitly request it, because temporary errors are rare and its unlikely that they fix themselves (e.g. disc full, permission problems)

Optimization
  Only backends that
  - contain at least one changed key according to elektraDiffCalculate(),
  - contain fewer keys than at the end of kdbGet() will be called. There won't be an unnecessary write for unchanged keys.

If none of the backends needs an update, kdbSet() returns 0 and does nothing.

KeySet * myConfig = ksNew (0, KS_END);
Key * parentKey = keyNew ("system:/sw/MyApp", KEY_END);
KDB * handle = kdbOpen (NULL, parentKey);
kdbGet (handle, myConfig, parentKey); // kdbGet needs to be called first!
KeySet * base = ksDup (myConfig); // save a copy of original keyset
// change the keys within myConfig
ksAppendKey (myConfig, keyNew ("system:/sw/MyApp/Test", KEY_VALUE, "5", KEY_END));
KeySet * ours = ksDup (myConfig); // save a copy of our keyset
KeySet * theirs; // needed for 3-way merging
int ret = kdbSet (handle, myConfig, parentKey);
while (ret == -1) // as long as we have an error
{
int strategy = showElektraErrorDialog (parentKey);
theirs = ksDup (ours);
kdbGet (handle, theirs, parentKey); // refresh key database
KeySet * result = elektraMerge(
ksCut(ours, parentKey), parentKey,
ksCut(theirs, parentKey), parentKey,
ksCut(base, parentKey), parentKey,
parentKey, strategy, parentKey);
int numberOfConflicts = elektraMergeGetConflicts (parentKey);
ksDel (theirs);
if (result != NULL) {
ret = kdbSet (handle, result, parentKey);
} else {
// an error happened while merging
if (numberOfConflicts > 0 && strategy == MERGE_STRATEGY_ABORT)
{
// Error due to merge conflicts
ret = -1;
}
else
{
// Internal errors, out of memory etc.
ret = -1;
}
}
}
ksDel (ours);
ksDel (base);
ksDel (myConfig); // delete the in-memory configuration
kdbClose (handle, parentKey); // no more affairs with the key database.
keyDel (parentKey);
kdbSet
int kdbSet(KDB *handle, KeySet *ks, Key *parentKey)
Set Keys to the Key database in an atomic and universal way.
Definition kdb.c:2343
ksDup
KeySet * ksDup(const KeySet *source)
Return a duplicate of a KeySet.
Definition keyset.c:371
ksAppendKey
ssize_t ksAppendKey(KeySet *ks, Key *toAppend)
Appends a Key to the end of ks.
Definition keyset.c:968
ksCut
KeySet * ksCut(KeySet *ks, const Key *cutpoint)
Cuts out all Keys from KeySet ks that are below or at cutpoint.
Definition keyset.c:1608
MERGE_STRATEGY_ABORT
@ MERGE_STRATEGY_ABORT
Definition kdbmerge.h:26

showElektraErrorDialog() and doElektraMerge() need to be implemented by the user of Elektra. For doElektraMerge a 3-way merge algorithm exists in libelektra-tools.

Parameters

  handle | contains internal information of opened key database
  ks | a KeySet which should contain changed keys, otherwise nothing is done
  parentKey | Keys below `parentKey` will be set to `handle`. It is also used to add warnings and set error information.

Return values

  1 | on success
  0 | if nothing had to be done, no changes in KDB
  -1 | on failure, no changes in KDB, an error will be set on `parentKey` if possible (see "Errors" above)

Since
  1.0.0

See also
  kdbOpen() for getting `handle`
  kdbClose() that must be called afterwards
  ksCurrent() contains the error Key

Return values

  0 | if no key was updated
  1 | if user or system keys were updated
  2 | if user and system keys were updated

Parameters

  returned | the keyset where the keys are passed to the user
  parentKey | the parentKey of returned

Exceptions

  KDBException | if there were problems with the database

## ◆ set() [2/2]

int kdb::KDB::set | ( | KeySet & | returned,
|  | std::string const & | keyname
| ) |  |
| inline virtual

Set all keys below keyname.

If the keyname of the parentKey is invalid (e.g. empty) all keys will be set.

Set Keys to the Key database in an atomic and universal way.

Precondition
  kdbGet() must be called before kdbSet():
  - initially (after kdbOpen())
  - after conflict errors in kdbSet().
  The KeySet `ks` must be a valid KeySet, i.e., constructed with ksNew().
  The KeySet `ks` must only contain only keys in the `spec:/`, `dir:/`, `user:/`, `system:/`, `default:/` or `proc:/` namespaces.
  The Key `parentKey` must be a valid Key, e.g. constructed with keyNew().
  The Key `parentKey` must not have read-only name, value or metadata.
  The Key `parentKey` must use the `spec:/`, `dir:/`, `user:/`, `system:/`, `default:/`, `proc:/` or cascading namespace.

If you pass `NULL` or a key with read-only metadata as `parentKey`, kdbSet() will fail immediately without doing anything. If you pass another invalid `parentKey`, or `NULL` as `ks` or `handle`, kdbSet() will set an error on `parentKey` and then return immediately.

Note
  If you pass a non-NULL `parentKey` with writable metadata, kdbSet() will always remove any existing errors and warnings from `parentKey`.

Persistable Namespaces

Not all namespace can be persisted.

- `spec:/`, `dir:/`, `user:/` and `system:/` will be persisted by kdbSet().
- `default:/` and `proc:/` keys are ignored by kdbSet().
- If `ks` contains a key with any other namespace, an error will be returned.

In general it is recommended to use a `parentKey` in the cascading namespace to cover all namespaces at once.

Parent Key

The `parentKey` defines which parts of `ks` will be stored. Everything that is at or below `parentKey` will be persisted together with any key that shares a backend with such a key. Backends are always stored as an atomic unit.

Note
  If `parentKey` is in the cascading namespace, keys of all persistable namespaces (see above) will be stored. This is generally the recommended approach.

KeySet modifications

The contents of `ks` will mostly not be modified by kdbSet(). The only modifications made are those caused by applying the specification in `spec:/` to `dir:/`, `user:/` and `system:/`.

Errors
  If `parentKey == NULL` or `parentKey` has read-only metadata, kdbSet() will immediately return the error code -1. In all other error cases the following happens:
  - Error information will be written into the metadata of the parent key, if possible.
  - None of the keys are actually committed in this situation, i.e. no configuration file will be modified.

In case of errors you should present the error message to the user and let the user decide what to do. Possible solutions are:

- remove the problematic key and use kdbSet() again (for validation or type errors)
- change the value of the problematic key and use kdbSet() again (for validation errors)
- do a kdbGet() (for conflicts, i.e. error C02000) and then
  - set the same keyset again (in favour of what was set by this user)
  - drop the old keyset (in favour of what was set from another application)
  - merge the original, your own and the other keyset
- export the configuration into a file (for unresolvable errors)
- repeating the same kdbSet() might be of limited use, if the user does not explicitly request it, because temporary errors are rare and its unlikely that they fix themselves (e.g. disc full, permission problems)

Optimization
  Only backends that
  - contain at least one changed key according to elektraDiffCalculate(),
  - contain fewer keys than at the end of kdbGet() will be called. There won't be an unnecessary write for unchanged keys.

If none of the backends needs an update, kdbSet() returns 0 and does nothing.

KeySet * myConfig = ksNew (0, KS_END);
Key * parentKey = keyNew ("system:/sw/MyApp", KEY_END);
KDB * handle = kdbOpen (NULL, parentKey);
kdbGet (handle, myConfig, parentKey); // kdbGet needs to be called first!
KeySet * base = ksDup (myConfig); // save a copy of original keyset
// change the keys within myConfig
ksAppendKey (myConfig, keyNew ("system:/sw/MyApp/Test", KEY_VALUE, "5", KEY_END));
KeySet * ours = ksDup (myConfig); // save a copy of our keyset
KeySet * theirs; // needed for 3-way merging
int ret = kdbSet (handle, myConfig, parentKey);
while (ret == -1) // as long as we have an error
{
int strategy = showElektraErrorDialog (parentKey);
theirs = ksDup (ours);
kdbGet (handle, theirs, parentKey); // refresh key database
KeySet * result = elektraMerge(
ksCut(ours, parentKey), parentKey,
ksCut(theirs, parentKey), parentKey,
ksCut(base, parentKey), parentKey,
parentKey, strategy, parentKey);
int numberOfConflicts = elektraMergeGetConflicts (parentKey);
ksDel (theirs);
if (result != NULL) {
ret = kdbSet (handle, result, parentKey);
} else {
// an error happened while merging
if (numberOfConflicts > 0 && strategy == MERGE_STRATEGY_ABORT)
{
// Error due to merge conflicts
ret = -1;
}
else
{
// Internal errors, out of memory etc.
ret = -1;
}
}
}
ksDel (ours);
ksDel (base);
ksDel (myConfig); // delete the in-memory configuration
kdbClose (handle, parentKey); // no more affairs with the key database.
keyDel (parentKey);

showElektraErrorDialog() and doElektraMerge() need to be implemented by the user of Elektra. For doElektraMerge a 3-way merge algorithm exists in libelektra-tools.

Parameters

  handle | contains internal information of opened key database
  ks | a KeySet which should contain changed keys, otherwise nothing is done
  parentKey | Keys below `parentKey` will be set to `handle`. It is also used to add warnings and set error information.

Return values

  1 | on success
  0 | if nothing had to be done, no changes in KDB
  -1 | on failure, no changes in KDB, an error will be set on `parentKey` if possible (see "Errors" above)

Since
  1.0.0

See also
  kdbOpen() for getting `handle`
  kdbClose() that must be called afterwards
  ksCurrent() contains the error Key

Return values

  0 | if no key was updated
  1 | if user or system keys were updated
  2 | if user and system keys were updated

Parameters

  returned | the keyset where the keys will be in
  keyname | the keyname below the names should be set

Exceptions

  KDBException | if there were problems with the database

The documentation for this class was generated from the following file:

- kdb.hpp