Elektra  0.8.9
Public Member Functions
kdb::KDB Class Reference

Opens the session with the Key database. More...

#include <kdb.hpp>

Public Member Functions

 KDB ()
 Opens the session with the Key database.
 
 KDB (Key &errorKey)
 Opens the session with the Key database.
 
 ~KDB () throw ()
 
 
void open (Key &errorKey)
 Opens the session with the Key database.
 
void close (Key &errorKey) throw ()
 
 
int get (KeySet &returned, std::string const &keyname)
 Retrieve keys in an atomic and universal way.
 
int get (KeySet &returned, Key &parentKey)
 Retrieve keys in an atomic and universal way.
 
int set (KeySet &returned, std::string const &keyname)
 Set keys in an atomic and universal way.
 
int set (KeySet &returned, Key &parentKey)
 Set keys in an atomic and universal way.
 

Detailed Description

Opens the session with the Key database.

Constructs a class KDB.

Exceptions
KDBExceptionif database could not be opened

The method will bootstrap itself 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. These libraries for backends will be loaded and with it the KDB datastructure will be initialized.You must always call this method before retrieving or committing any keys to the database. In the end of the program, after using the key database, you must not forget to kdbClose(). You can use the atexit () handler for it.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:

thread1
{
KDB * h;
h = kdbOpen(0);
// fetch keys and work with them
kdbClose(h, 0);
}
thread2
{
KDB * h;
h = kdbOpen(0);
// fetch keys and work with them
kdbClose(h, 0);
}
You don't need to use the 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
errorKeythe key which holds errors and warnings which were issued
See Also
kdbGet(), kdbClose() to end all affairs to the Key database.
Returns
a KDB pointer on success
NULL on failure

Access to the key database.

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

Constructor & Destructor Documentation

kdb::KDB::KDB ( )
inline

Opens the session with the Key database.

Constructs a class KDB.

Exceptions
KDBExceptionif database could not be opened

The method will bootstrap itself 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. These libraries for backends will be loaded and with it the KDB datastructure will be initialized.You must always call this method before retrieving or committing any keys to the database. In the end of the program, after using the key database, you must not forget to kdbClose(). You can use the atexit () handler for it.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:

thread1
{
KDB * h;
h = kdbOpen(0);
// fetch keys and work with them
kdbClose(h, 0);
}
thread2
{
KDB * h;
h = kdbOpen(0);
// fetch keys and work with them
kdbClose(h, 0);
}
You don't need to use the 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
errorKeythe key which holds errors and warnings which were issued
See Also
kdbGet(), kdbClose() to end all affairs to the Key database.
Returns
a KDB pointer on success
NULL on failure

kdb::KDB::KDB ( Key errorKey)
inline

Opens the session with the Key database.

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

The method will bootstrap itself 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. These libraries for backends will be loaded and with it the KDB datastructure will be initialized.You must always call this method before retrieving or committing any keys to the database. In the end of the program, after using the key database, you must not forget to kdbClose(). You can use the atexit () handler for it.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:

thread1
{
KDB * h;
h = kdbOpen(0);
// fetch keys and work with them
kdbClose(h, 0);
}
thread2
{
KDB * h;
h = kdbOpen(0);
// fetch keys and work with them
kdbClose(h, 0);
}
You don't need to use the 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
errorKeythe key which holds errors and warnings which were issued
See Also
kdbGet(), kdbClose() to end all affairs to the Key database.
Returns
a KDB pointer on success
NULL on failure

kdb::KDB::~KDB ( ) throw ()
inline

The destructor closes the database.

Closes the session with the Key database.This is the counterpart of kdbOpen().You must call this method when you finished your affairs with the key database. You can manipulate Key and KeySet objects also after kdbClose(), but you must not use any kdb*() call afterwards. You can run kdbClose() in the atexit() handler.The handle parameter will be finalized and all resources associated to it will be freed. After a kdbClose(), the handle can't be used anymore.

Precondition
The handle must be a valid handle as returned from kdbOpen()
errorKey must be a valid key, e.g. created with keyNew()
Parameters
handlecontains internal information of opened key database
errorKeythe key which holds error information
Returns
0 on success
-1 on NULL pointer

Member Function Documentation

void kdb::KDB::close ( Key errorKey) throw ()
inline

Open 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.This is the counterpart of kdbOpen().You must call this method when you finished your affairs with the key database. You can manipulate Key and KeySet objects also after kdbClose(), but you must not use any kdb*() call afterwards. You can run kdbClose() in the atexit() handler.The handle parameter will be finalized and all resources associated to it will be freed. After a kdbClose(), the handle can't be used anymore.

Precondition
The handle must be a valid handle as returned from kdbOpen()
errorKey must be a valid key, e.g. created with keyNew()
Parameters
handlecontains internal information of opened key database
errorKeythe key which holds error information
Returns
0 on success
-1 on NULL pointer

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

Retrieve keys in an atomic and universal way.

Get all keys below keyname inside returned.

Precondition
kdbOpen() must be called before using this method.
The returned KeySet must be a valid KeySet, e.g. constructed with ksNew().

The returned KeySet may already contain some keys from previous kdbGet() calls. The new retrieved keys will be appended using ksAppendKey().It will fully retrieve, at least, all keys under the parentKey folder, with all subfolders and their children.

Note
kdbGet() might retrieve more keys then requested (that are not below parentKey). These 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!
See Also
ksCut() for further remarks on that topic.
Example:

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

KeySet *myConfig = ksNew(0,KS_END);
Key *pkey = keyNew("system/sw/MyApp",KEY_END);
KDB *handle = kdbOpen(pkey);
kdbGet(handle, myConfig, pkey); // get the config initially
Key *key = ksLookupByName(myConfig,"/sw/MyApp/key", 0);
// check if key is not 0 and work with it...
kdbGet(handle, myConfig, pkey); // get the config again
ksDel (myConfig); // delete the in-memory configuration
kdbClose(handle, pkey); // no more affairs with the key database.
keyDel(pkey);
Details:

If you pass NULL on any parameter kdbGet() will fail immediately without doing anything.When a backend fails kdbGet() will return -1 with all error and warning information in the parentKey. The parameter returned will not be changed.

Updates:

In the first run of kdbGet all keys are retrieved. On subsequent calls only the keys are retrieved where something was changed inside the key database. The other keys stay unchanged in the keyset, even when they were manipulated.It is your responsibility to save the original keyset if you need it afterwards.If you must get the same keyset again, e.g. in another thread you need to open a second handle to the key database using kdbOpen().

Parameters
handlecontains internal information of opened key database
parentKeyparent key holds the information which keys should be get (it is possible that more are retrieved) - an invalid name gets all keys
ksthe (pre-initialized) KeySet returned with all keys found will not be changed on error or if no update is required
See Also
ksLookup(), ksLookupByName() for powerful lookups after the KeySet was retrieved
kdbSet() to save the configuration afterwards and kdbClose() to finish affairs with the Key database.
Return values
1if the keys were retrieved successfully
0if there was no update - no changes are made to the keyset then
-1on failure - no changes are made to the keyset then

#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;
}
}
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)
int kdb::KDB::get ( KeySet returned,
Key parentKey 
)
inline

Retrieve keys in an atomic and universal way.

Get all keys below parentKey inside returned.

Precondition
kdbOpen() must be called before using this method.
The returned KeySet must be a valid KeySet, e.g. constructed with ksNew().

The returned KeySet may already contain some keys from previous kdbGet() calls. The new retrieved keys will be appended using ksAppendKey().It will fully retrieve, at least, all keys under the parentKey folder, with all subfolders and their children.

Note
kdbGet() might retrieve more keys then requested (that are not below parentKey). These 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!
See Also
ksCut() for further remarks on that topic.
Example:

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

KeySet *myConfig = ksNew(0,KS_END);
Key *pkey = keyNew("system/sw/MyApp",KEY_END);
KDB *handle = kdbOpen(pkey);
kdbGet(handle, myConfig, pkey); // get the config initially
Key *key = ksLookupByName(myConfig,"/sw/MyApp/key", 0);
// check if key is not 0 and work with it...
kdbGet(handle, myConfig, pkey); // get the config again
ksDel (myConfig); // delete the in-memory configuration
kdbClose(handle, pkey); // no more affairs with the key database.
keyDel(pkey);
Details:

If you pass NULL on any parameter kdbGet() will fail immediately without doing anything.When a backend fails kdbGet() will return -1 with all error and warning information in the parentKey. The parameter returned will not be changed.

Updates:

In the first run of kdbGet all keys are retrieved. On subsequent calls only the keys are retrieved where something was changed inside the key database. The other keys stay unchanged in the keyset, even when they were manipulated.It is your responsibility to save the original keyset if you need it afterwards.If you must get the same keyset again, e.g. in another thread you need to open a second handle to the key database using kdbOpen().

Parameters
handlecontains internal information of opened key database
parentKeyparent key holds the information which keys should be get (it is possible that more are retrieved) - an invalid name gets all keys
ksthe (pre-initialized) KeySet returned with all keys found will not be changed on error or if no update is required
See Also
ksLookup(), ksLookupByName() for powerful lookups after the KeySet was retrieved
kdbSet() to save the configuration afterwards and kdbClose() to finish affairs with the Key database.
Return values
1if the keys were retrieved successfully
0if there was no update - no changes are made to the keyset then
-1on failure - no changes are made to the keyset then

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
void kdb::KDB::open ( Key errorKey)
inline

Opens the session with the Key database.

Open the database

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

The method will bootstrap itself 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. These libraries for backends will be loaded and with it the KDB datastructure will be initialized.You must always call this method before retrieving or committing any keys to the database. In the end of the program, after using the key database, you must not forget to kdbClose(). You can use the atexit () handler for it.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:

thread1
{
KDB * h;
h = kdbOpen(0);
// fetch keys and work with them
kdbClose(h, 0);
}
thread2
{
KDB * h;
h = kdbOpen(0);
// fetch keys and work with them
kdbClose(h, 0);
}
You don't need to use the 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
errorKeythe key which holds errors and warnings which were issued
See Also
kdbGet(), kdbClose() to end all affairs to the Key database.
Returns
a KDB pointer on success
NULL on failure

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

Set keys in an atomic and universal way.

Set all keys below keyname.

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

With parentKey you can only store a part of the given keyset. When other keys also belong to a backend, they will be used too, even when they are above parentKey.

Details:

If you pass a parentKey without a name the whole keyset will be set in an atomic way.Each key is checked with keyNeedSync() before being actually committed. So only changed keys are updated. If no key of a backend needs to be synced any affairs to backends omitted and 0 is returned.

Errors:

If some error occurs, kdbSet() will stop. In this situation the KeySet internal cursor will be set on the key that generated the error.None of the keys are actually commited.You should present the error message to the user and let the user decide what to do. Possible solutions are:

  • repeat the same kdbSet (for temporary errors)
  • remove the key and set it again (for validation or type errors)
  • change the value and try it again (for validation errors)
  • do a kdbGet and then (for conflicts ...)
    • set the same keyset again (in favour of what was set by this user)
    • drop the old keyset (in favour of what was set elsewhere)
  • export the configuration into a file (for unresolvable errors)
Example of how this method can be used:
int i;
KeySet *myConfig = ksNew(0,KS_END);
Key *parentKey = keyNew("system/sw/MyApp",KEY_END);
KDB *handle = kdbOpen(pkey);
kdbGet(handle, ks, parentKey); // kdbGet needs to be called first!
KeySet *base = ksDup(ks); // save a copy of original keyset
// change the keys within ks
KeySet *ours = ksDup(ks); // save a copy of our keyset
int ret=kdbSet(handle, ks, parentKey);
while (ret == -1) // as long as we have an error
{
// We got an error. Warn user.
Key *problemKey = ksCurrent(ks);
// parentKey has the errorInformation
// problemKey is the faulty key (may be null)
int userInput = showElektraErrorDialog (parentKey, problemKey);
switch (userInput)
{
case INPUT_USE_OURS:
kdbGet(handle, ks, parentKey); // refresh key database
ksDel(ks);
ks = ours;
break;
case INPUT_DO_MERGE:
kdbGet(handle, ks, parentKey); // refresh key database
KeySet * res=doElektraMerge(ours, ks, base);
ksDel(ks);
ks = res;
break;
case INPUT_USE_THEIRS:
// should always work, we just write what we got
// but to be sure always give the user another way
// to exit the loop
kdbGet(handle, ks, parentKey); // refresh key database
break;
...
}
ret=kdbSet(handle, ks, parentKey);
}
ksDel (ours);
ksDel (base);
ksDel (ks); // 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. For doElektraMerge a 3-way merge algorithm exists in libelektra-tools.

Precondition
kdbGet() must be called before kdbSet():
Parameters
handlecontains internal information of opened key database
ksa KeySet which should contain changed keys, otherwise nothing is done
parentKeyholds the information below which key keys should be set, see above
Return values
1on success
0if nothing had to be done
-1on failure
See Also
keyNeedSync()
ksNext(), ksCurrent() for iteration over the KeySet
kdbOpen() and kdbGet() that must be called first
kdbClose() that must be called afterwards

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
int kdb::KDB::set ( KeySet returned,
Key parentKey 
)
inline

Set keys in an atomic and universal way.

Set all keys below parentKey.

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

With parentKey you can only store a part of the given keyset. When other keys also belong to a backend, they will be used too, even when they are above parentKey.

Details:

If you pass a parentKey without a name the whole keyset will be set in an atomic way.Each key is checked with keyNeedSync() before being actually committed. So only changed keys are updated. If no key of a backend needs to be synced any affairs to backends omitted and 0 is returned.

Errors:

If some error occurs, kdbSet() will stop. In this situation the KeySet internal cursor will be set on the key that generated the error.None of the keys are actually commited.You should present the error message to the user and let the user decide what to do. Possible solutions are:

  • repeat the same kdbSet (for temporary errors)
  • remove the key and set it again (for validation or type errors)
  • change the value and try it again (for validation errors)
  • do a kdbGet and then (for conflicts ...)
    • set the same keyset again (in favour of what was set by this user)
    • drop the old keyset (in favour of what was set elsewhere)
  • export the configuration into a file (for unresolvable errors)
Example of how this method can be used:
int i;
KeySet *myConfig = ksNew(0,KS_END);
Key *parentKey = keyNew("system/sw/MyApp",KEY_END);
KDB *handle = kdbOpen(pkey);
kdbGet(handle, ks, parentKey); // kdbGet needs to be called first!
KeySet *base = ksDup(ks); // save a copy of original keyset
// change the keys within ks
KeySet *ours = ksDup(ks); // save a copy of our keyset
int ret=kdbSet(handle, ks, parentKey);
while (ret == -1) // as long as we have an error
{
// We got an error. Warn user.
Key *problemKey = ksCurrent(ks);
// parentKey has the errorInformation
// problemKey is the faulty key (may be null)
int userInput = showElektraErrorDialog (parentKey, problemKey);
switch (userInput)
{
case INPUT_USE_OURS:
kdbGet(handle, ks, parentKey); // refresh key database
ksDel(ks);
ks = ours;
break;
case INPUT_DO_MERGE:
kdbGet(handle, ks, parentKey); // refresh key database
KeySet * res=doElektraMerge(ours, ks, base);
ksDel(ks);
ks = res;
break;
case INPUT_USE_THEIRS:
// should always work, we just write what we got
// but to be sure always give the user another way
// to exit the loop
kdbGet(handle, ks, parentKey); // refresh key database
break;
...
}
ret=kdbSet(handle, ks, parentKey);
}
ksDel (ours);
ksDel (base);
ksDel (ks); // 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. For doElektraMerge a 3-way merge algorithm exists in libelektra-tools.

Precondition
kdbGet() must be called before kdbSet():
Parameters
handlecontains internal information of opened key database
ksa KeySet which should contain changed keys, otherwise nothing is done
parentKeyholds the information below which key keys should be set, see above
Return values
1on success
0if nothing had to be done
-1on failure
See Also
keyNeedSync()
ksNext(), ksCurrent() for iteration over the KeySet
kdbOpen() and kdbGet() that must be called first
kdbClose() that must be called afterwards

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

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