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

Constructs a class KDB. More...

#include <kdb.hpp>

Inheritance diagram for kdb::KDB:
Inheritance graph
[legend]

Public Member Functions

 KDB ()
 Constructs a class KDB. More...
 
 KDB (Key &errorKey)
 Constructs a class KDB. More...
 
 KDB (KeySet &contract)
 Constructs a class KDB. More...
 
 KDB (KeySet &contract, Key &errorKey)
 Constructs a class KDB. More...
 
virtual void open (Key &errorKey)
 Open the database. More...
 
virtual void open (KeySet &contract, Key &errorKey)
 Open the database. More...
 
virtual void close () throw ()
 Close the database. More...
 
virtual void close (Key &errorKey) throw ()
 Close the database. More...
 
virtual int get (KeySet &returned, std::string const &keyname)
 Get all keys below keyname inside returned. More...
 
virtual int get (KeySet &returned, Key &parentKey)
 Get all keys below parentKey inside returned. More...
 
virtual int set (KeySet &returned, std::string const &keyname)
 Set all keys below keyname. More...
 
virtual int set (KeySet &returned, Key &parentKey)
 Set all keys below parentKey. More...
 

Detailed Description

Constructs a class KDB.

Exceptions
KDBExceptionif 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()
Constructs a class KDB.
Definition: kdb.hpp:75
KDB * kdbOpen(const KeySet *contract, Key *errorKey)
Opens the session with the Key database.
Definition: kdb.c:417
int kdbClose(KDB *handle, Key *errorKey)
Closes the session with the Key database.
Definition: kdb.c:590
Key * keyNew(const char *name,...)
A practical way to fully create a Key object in one step.
Definition: key.c:144
@ KEY_END
Definition: kdbenum.c:97

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
contractthe 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
errorKeythe key which holds errors and warnings which were issued
Returns
handle to the newly created KDB on success
Return values
NULLon 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
KDBExceptionif 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
contractthe 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
errorKeythe key which holds errors and warnings which were issued
Returns
handle to the newly created KDB on success
Return values
NULLon 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)
inlineexplicit

Constructs a class KDB.

Parameters
errorKeyis useful if you want to get the warnings in the successful case, when no exception is thrown.
Exceptions
KDBExceptionif 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
contractthe 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
errorKeythe key which holds errors and warnings which were issued
Returns
handle to the newly created KDB on success
Return values
NULLon 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)
inlineexplicit

Constructs a class KDB.

Parameters
contractthe contract that should be ensured
errorKeyis useful if you want to get the warnings in the successful case, when no exception is thrown.
Exceptions
KDBExceptionif 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
contractthe 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
errorKeythe key which holds errors and warnings which were issued
Returns
handle to the newly created KDB on success
Return values
NULLon 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
contractthe contract that should be ensured
errorKeyis useful if you want to get the warnings in the successful case, when no exception is thrown.
Exceptions
KDBExceptionif 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
contractthe 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
errorKeythe key which holds errors and warnings which were issued
Returns
handle to the newly created KDB on success
Return values
NULLon failure
Since
1.0.0
See also
kdbClose() to close the session of a Key database opened by kdbOpen()

Member Function Documentation

◆ close() [1/2]

void kdb::KDB::close ( )
throw (
)
inlinevirtual

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
handlecontains internal information of opened key database
errorKeythe key which holds error/warning information
Return values
0on success
-1on 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 (
)
inlinevirtual

Close the database.

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

Parameters
errorKeyis 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
handlecontains internal information of opened key database
errorKeythe key which holds error/warning information
Return values
0on success
-1on 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 
)
inlinevirtual

Get all keys below parentKey inside returned.

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

Precondition
The handle must be passed as returned from kdbOpen().
The returned KeySet must be a valid KeySet, e.g. constructed with ksNew().
The parentKey Key must be a valid Key, e.g. constructed with keyNew().

If you pass NULL on any parameter, kdbGet() will fail immediately without doing anything.

The returned KeySet ks may already contain some keys, e.g. from previous kdbGet() calls. The newly retrieved Keys will be appended using ksAppendKey().

If not done earlier, kdbGet() will fully retrieve all keys under the parentKey folder recursively (See Optimization below when it will not be done). Cascading Keys (starting with /) will retrieve the same path in all namespaces. / will retrieve all Keys in handle.

It is recommended to use the most specific parentKey possible. (e.g. using system:/ is rarely the most specific)

Note
kdbGet() might retrieve more Keys than requested which are not below parentKey or even in a different namespace. These keys, except of proc:/ keys, must be passed to calls of kdbSet(), otherwise they will be lost. This stems from the fact that the user has the only copy of the whole configuration and backends only write configuration that was passed to them. For example, if you kdbGet() "system:/mountpoint/interest" you will not only get all Keys below system:/mountpoint/interest, but also all Keys below system:/mountpoint (if system:/mountpoint is a mountpoint as the name suggests, but system:/mountpoint/interest is not a mountpoint). Make sure to not touch or remove Keys outside the Keys of interest, because others may need them!
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"));
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.
}
int kdbGet(KDB *handle, KeySet *ks, Key *parentKey)
Retrieve Keys from a Key database in an atomic and universal way.
Definition: kdb.c:1207
int keyDel(Key *key)
A destructor for Key objects.
Definition: key.c:504
const Key * keyGetMeta(const Key *key, const char *metaName)
Returns the Key for a metadata entry with name metaName.
Definition: keymeta.c:453
const char * keyName(const Key *key)
Returns a pointer to the abbreviated real internal key name.
Definition: elektra/keyname.c:254
int ksDel(KeySet *ks)
A destructor for KeySet objects.
Definition: keyset.c:451
KeySet * ksNew(size_t alloc,...)
Allocate, initialize and return a new KeySet object.
Definition: keyset.c:229
#define KS_END
End of a list of keys.
Definition: kdbenum.c:158
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:2499
const char * keyString(const Key *key)
Get a pointer to the c-string representing the value.
Definition: keyvalue.c:213
int main(int argc, char **argv)
[kdbio testsuite main]
Definition: testio_doc.c:48

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
handlecontains internal information of opened key database
parentKeyKeys below parentKey will be retrieved from handle. It is also used to add warnings and set error information.
ksthe (pre-initialized) KeySet returned with all keys found will not be changed on error or if no update is required
Return values
1if 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!
0if there was no update - 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!
-1on 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
returnedthe keyset where the keys will be in
parentKeythe parentKey of returned
Return values
0if no key was updated
1if user or system keys were updated
2if user and system keys were updated
Exceptions
KDBExceptionif 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 
)
inlinevirtual

Get all keys below keyname inside returned.

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

Precondition
The handle must be passed as returned from kdbOpen().
The returned KeySet must be a valid KeySet, e.g. constructed with ksNew().
The parentKey Key must be a valid Key, e.g. constructed with keyNew().

If you pass NULL on any parameter, kdbGet() will fail immediately without doing anything.

The returned KeySet ks may already contain some keys, e.g. from previous kdbGet() calls. The newly retrieved Keys will be appended using ksAppendKey().

If not done earlier, kdbGet() will fully retrieve all keys under the parentKey folder recursively (See Optimization below when it will not be done). Cascading Keys (starting with /) will retrieve the same path in all namespaces. / will retrieve all Keys in handle.

It is recommended to use the most specific parentKey possible. (e.g. using system:/ is rarely the most specific)

Note
kdbGet() might retrieve more Keys than requested which are not below parentKey or even in a different namespace. These keys, except of proc:/ keys, must be passed to calls of kdbSet(), otherwise they will be lost. This stems from the fact that the user has the only copy of the whole configuration and backends only write configuration that was passed to them. For example, if you kdbGet() "system:/mountpoint/interest" you will not only get all Keys below system:/mountpoint/interest, but also all Keys below system:/mountpoint (if system:/mountpoint is a mountpoint as the name suggests, but system:/mountpoint/interest is not a mountpoint). Make sure to not touch or remove Keys outside the Keys of interest, because others may need them!
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"));
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
handlecontains internal information of opened key database
parentKeyKeys below parentKey will be retrieved from handle. It is also used to add warnings and set error information.
ksthe (pre-initialized) KeySet returned with all keys found will not be changed on error or if no update is required
Return values
1if 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!
0if there was no update - 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!
-1on 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.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;
}
}
This is the main namespace for the C++ binding and libraries.
Definition: backend.hpp:31
Parameters
returnedthe keyset where the keys will be in
keynamethe root keyname which should be used to get keys below it
Return values
0if no key was updated
1if user or system keys were updated
2if user and system keys were updated
Exceptions
KDBExceptionif there were problems with the database
See also
KDB::get (KeySet & returned, Key & parentKey)

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

◆ open() [1/2]

void kdb::KDB::open ( Key errorKey)
inlinevirtual

Open the database.

Parameters
errorKeyis 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
contractthe 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
errorKeythe key which holds errors and warnings which were issued
Returns
handle to the newly created KDB on success
Return values
NULLon 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 
)
inlinevirtual

Open the database.

Parameters
contractthe contract that should be ensured
errorKeyis 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
contractthe 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
errorKeythe key which holds errors and warnings which were issued
Returns
handle to the newly created KDB on success
Return values
NULLon failure
Since
1.0.0
See also
kdbClose() to close the session of a Key database opened by kdbOpen()

◆ set() [1/2]

int kdb::KDB::set ( KeySet returned,
Key parentKey 
)
inlinevirtual

Set all keys below parentKey.

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

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

Precondition
kdbGet() must be called before kdbSet():
The returned KeySet must be a valid KeySet, e.g. constructed with ksNew().
The parentKey Key must be a valid Key, e.g. constructed with keyNew(). It must not have read-only name, value or metadata.

If you pass NULL on any parameter, kdbSet() will fail immediately without doing anything.

With parentKey you can specify which part of the given keyset is of interest for you. Then you promise to only modify or remove keys below this key. All others would be passed back as they were retrieved by kdbGet(). Cascading keys (starting with /) will set the path in all namespaces. / will commit all keys. This parameter is an optimization toonly save keys of mountpoints affected by the specified parentKey. This does not necessarily mean that only changes to keys below that parentKey are saved. Meta-names in parentKey will be rejected (error C01320). Empty/Invalid Keys will also be rejected (error C01320).

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:
  • kdbSet() will leave the KeySet's * internal cursor on the key that generated the error.
  • 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)
  • repeat 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
Each key is checked with keyNeedSync() before being actually committed. If no key of a backend needs to be synced any affairs to backends are omitted and 0 is returned.
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 = getConflicts (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);
int kdbSet(KDB *handle, KeySet *ks, Key *parentKey)
Set Keys to a Key database in an atomic and universal way.
Definition: kdb.c:1779
@ KEY_VALUE
Definition: kdbenum.c:89
KeySet * ksCut(KeySet *ks, const Key *cutpoint)
Cuts out all Keys from KeySet ks that are below or at cutpoint.
Definition: keyset.c:1284
ssize_t ksAppendKey(KeySet *ks, Key *toAppend)
Appends a Key to the end of ks.
Definition: keyset.c:789
KeySet * ksDup(const KeySet *source)
Return a duplicate of a KeySet.
Definition: keyset.c:312
KeySet * elektraMerge(KeySet *our, Key *ourRoot, KeySet *their, Key *theirRoot, KeySet *base, Key *baseRoot, Key *resultKey, int strategy, Key *informationKey)
This function can incorporate changes from two modified versions (our and their) into a common preced...
Definition: kdbmerge.c:956
int getConflicts(Key *informationKey)
This function returns the number of conflicts that is store in the key.
Definition: kdbmerge.c:190

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

Parameters
handlecontains internal information of opened key database
ksa KeySet which should contain changed keys, otherwise nothing is done
parentKeyKeys below parentKey will be set to handle. It is also used to add warnings and set error information.
Return values
1on success
0if nothing had to be done, no changes in KDB
-1on 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
0if no key was updated
1if user or system keys were updated
2if user and system keys were updated
Parameters
returnedthe keyset where the keys are passed to the user
parentKeythe parentKey of returned
Exceptions
KDBExceptionif there were problems with the database

◆ set() [2/2]

int kdb::KDB::set ( KeySet returned,
std::string const &  keyname 
)
inlinevirtual

Set all keys below keyname.

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

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

Precondition
kdbGet() must be called before kdbSet():
The returned KeySet must be a valid KeySet, e.g. constructed with ksNew().
The parentKey Key must be a valid Key, e.g. constructed with keyNew(). It must not have read-only name, value or metadata.

If you pass NULL on any parameter, kdbSet() will fail immediately without doing anything.

With parentKey you can specify which part of the given keyset is of interest for you. Then you promise to only modify or remove keys below this key. All others would be passed back as they were retrieved by kdbGet(). Cascading keys (starting with /) will set the path in all namespaces. / will commit all keys. This parameter is an optimization toonly save keys of mountpoints affected by the specified parentKey. This does not necessarily mean that only changes to keys below that parentKey are saved. Meta-names in parentKey will be rejected (error C01320). Empty/Invalid Keys will also be rejected (error C01320).

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:
  • kdbSet() will leave the KeySet's * internal cursor on the key that generated the error.
  • 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)
  • repeat 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
Each key is checked with keyNeedSync() before being actually committed. If no key of a backend needs to be synced any affairs to backends are omitted and 0 is returned.
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 = getConflicts (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
handlecontains internal information of opened key database
ksa KeySet which should contain changed keys, otherwise nothing is done
parentKeyKeys below parentKey will be set to handle. It is also used to add warnings and set error information.
Return values
1on success
0if nothing had to be done, no changes in KDB
-1on 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
0if no key was updated
1if user or system keys were updated
2if user and system keys were updated
Parameters
returnedthe keyset where the keys will be in
keynamethe keyname below the names should be set
Exceptions
KDBExceptionif there were problems with the database

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