table of contents
Plugins(3elektra) | Elektra | Plugins(3elektra) |
NAME¶
Plugins - Elektra plugin framework.Functions¶
int docOpen (Plugin *handle, Key *errorKey)
Detailed Description¶
Elektra plugin framework. Since:version 0.4.9, Elektra can dynamically load different key
storage plugins.
version 0.7.0 Elektra can have multiple backends, mounted at any place in the
key database.
version 0.8.0 Elektra backends are composed out of multiple plugins.
Overview
There are different types of plugins for different
concerns. The types of plugins handled in this document:
Note:
- •
- file storage plugins (also called just storage plugins here)
- •
- filter plugins
- •
- elektraDocOpen()
- •
- elektraDocClose()
- •
- elektraDocGet()
- •
- elektraDocSet()
- •
- elektraDocError() (not needed by storage or filter plugins)
that the Doc within the name is just because the plugin
described here is called doc (see src/plugins/doc/doc.c). Always replace Doc
with the name of the plugin you are going to implement.
See the descriptions below what each of them is supposed to do.
Storage Plugins
A filter plugin is a plugin which already receives some
keys. It may process or change the keyset. Or it may reject specific keysets
which do not meet some criteria.
Filter Plugins
A storage plugin gets an empty keyset and constructs the
information out from a file.
Other persistent storage then a file is not handled within this document because
it involves many other issues. For files the resolver plugin already takes
care for transactions and rollback.
Error and Warnings
In any case of trouble, use ELEKTRA_SET_ERROR and return
with -1. You might add warnings with ELEKTRA_ADD_WARNING if you think it is
appropriate.
Note:
some docu in this section might be confusing or not
updated, please refer to http://www.libelektra.org/ftp/elektra/thesis.pdf or
ask at the mailinglist if something is unclear.
Function Documentation¶
int docClose (Plugin *handle, Key *errorKey)¶
Finalize the plugin. Called prior to unloading the plugin dynamic module. Should ensure that no functions or static/global variables from the module will ever be accessed again. Make sure to free all memory that your plugin requested at runtime. After this call, libelektra.so will unload the plugin library, so this is the point to shutdown any affairs with the storage. Parameters:handle contains internal information of the plugin
errorKey is needed to add warnings using ELEKTRA_ADD_WARNING
Return values:
0 on success
See also:
kdbClose()
elektraPluginGetData(), elektraPluginSetData() and
elektraPluginGetConfig()
int docError (Plugin *handle, KeySet *returned, Key *parentKey)¶
Rollback in case of errors. Parameters:handle contains internal information of the plugin
returned contains a keyset with relevant keys
parentKey contains the information where to set the keys
Return values:
1 on success
0 on success with no action
-1 on failure
int docGet (Plugin *handle, KeySet *returned, Key *parentKey)¶
Retrieve information from a permanent storage to construct a keyset.Introduction¶
The elektraDocGet() function handle everything related to receiving keys.Storage Plugins¶
For storage plugins the filename is written in the value of the parentKey. So the first task of the plugin is to open that file. Then it should parse its content and construct a keyset with all information of that file. You need to be able to reconstruct the same file with the information of the keyset. So be sure to copy all comments, whitespaces and so on into some metadata of the keys. Otherwise the information is lost after writing the file the next time. Now lets look at an example how the typical elektraDocGet() might be implemented. To explain we introduce some pseudo functions which do all the work with the storage (which is of course 90% of the work for a real plugin):- •
- parse_key will parse a key and a value from an open file handle
int elektraDocGet(Plugin *handle, KeySet *returned, const Key *parentKey) { // contract handling, see below FILE *fp = fopen (keyString(parentKey), "r"); char *key; char *value; while ((n = parse_key(fp, &key, &value)) >= 1) { Key *read = keyNew(0); if (keySetName(read, key) == -1) { fclose (fp); keyDel (read); ELEKTRA_SET_ERROR(59, parentKey, key); return -1; } keySetString(read, value); ksAppendKey (returned, read); free (key); free (value); } if (feof(fp) == 0) { fclose (fp); ELEKTRA_SET_ERROR(60, parentKey, "not at the end of file"); return -1; } fclose (fp); return 1; // success }
Filter Plugins¶
For filter plugins the actual task is rather unspecified. You basically can do anything with the keyset. To get roundtrip properties you might want to undo any changes you did in elektraDocSet(). The pseudo functions (which do the real work) are:- •
- do_action() which processes every key in this filter
int elektraDocGet(Plugin *handle, KeySet *returned, Key *parentKey) { // contract handling Key *k; ksRewind (returned); while ((k = ksNext (returned)) != 0) { do_action(k); } return 1; // success }
Conditions¶
Precondition:The caller kdbGet() will make sure before you are
called that the parentKey:
Invariant:
- •
- is a valid key (means that it is a system or user key).
- •
- is below (see keyIsBelow()) your mountpoint and that your plugin is responsible for it. and that the returned:
- •
- is a valid keyset.
- •
- has all keys with the flag KEY_FLAG_SYNC set.
- •
- contains only valid keys direct below (see keyIsDirectBelow()) your parentKey. That also means, that the parentKey will not be in that keyset.
- •
- is in a sorted order (given implicit by semantics of KeySet) and that the handle:
- •
- is a valid KDB for your plugin.
- •
- that elektraPluginhGetBackendHandle() contains the same handle for lifetime kdbOpen() until elektraPluginClose() was called.
- •
- hidden keys they will be thrown away.
- •
- dirs or only dirs kdbGet() will remove the other.
- •
- you will be called again recursively with all subdirectories.
- •
- the keyset will be sorted when needed.
- •
- the keys in returned having KEY_FLAG_SYNC will be sorted out.
There are no global variables and elektraPluginSetData()
stores all information. The handle is to be guaranteed to be the same if it is
the same plugin.
Postcondition:
The keyset returned has the parentKey and all keys direct
below ( keyIsDirectBelow()) with all information from the storage. Make
sure to return all keys, all directories and also all hidden keys. If some of
them are not wished, the caller kdbGet() will drop these keys, see
above.
Updating¶
To get all keys out of the storage over and over again can be very inefficient. You might know a more efficient method to know if the key needs update or not, e.g. by stating it or by an external time stamp info. For file storage plugins this is automatically done for you. For other types (e.g. databases) you need to implement your own resolver doing this. Note:If any calls you use change errno, make sure to restore
the old errno.
See also:
kdbGet() for caller.
Parameters:
handle contains internal information of opened
key database
returned contains a keyset where the function need to append the keys got
from the storage. There might be also some keys inside it, see conditions. You
may use them to support efficient updating of keys, see Updating.
parentKey contains the information below which key the keys should be
gotten.
Returns:
1 on success
0 when nothing was to do
-1 on failure, the current key in returned shows the position. use
ELEKTRA_SET_ERROR of kdberrors.h to define the error code
int docOpen (Plugin *handle, Key *errorKey)¶
Initialize the plugin. This is the first method called after dynamically loading this plugin. This method is responsible for:- •
- plugin's specific configuration gathering
- •
- all plugin's internal structs initialization
- •
- if unavoidable initial setup of all I/O details such as opening a file, connecting to a database, setup connection to a server, etc.
The plugin must not have any global variables. If you do
Elektra will not be threadsafe. It is not a good assumption that your plugin
will be opened only once.
Instead you can use elektraPluginGetData() and elektraPluginSetData() to store
and get any information related to your plugin.
The correct substitute for global variables will be:
struct _GlobalData{ int global; }; typedef struct _GlobalData GlobalData; int elektraDocOpen(Plugin *handle, Key *errorKey) { GlobalData *data; data=malloc(sizeof(GlobalData)); data.global = 20; elektraPluginSetData(handle,data); }If your plugin has no useful way to startup without config, the module loader would not be able to load the module, too. To solve that problem the module loader adds the configuration key /module. Even if your plugin is basically not able to startup successfully, it should still provide a fallback when /module is present, so that docGet() on system/elektra/modules can be called successfully later on. Note:
Make sure to free everything you allocate here within
elektraDocClose().
Returns:
0 on success
Parameters:
handle contains internal information of the plugin
errorKey defines an errorKey
See also:
kdbOpen() which will call elektraDocOpen()
elektraPluginGetData(), elektraPluginSetData() and
elektraPluginGetConfig()
int docSet (Plugin *handle, KeySet *returned, Key *parentKey)¶
Store a keyset permanently. This function does everything related to set and remove keys in a plugin. There is only one function for that purpose to make implementation and locking much easier. The keyset returned was filled in with information from the application using elektra and the task of this function is to store it in a permanent way so that a subsequent call of elektraPluginGet() can rebuild the keyset as it was before. See the live cycle of a comment to understand:void usercode (Key *key) { keySetComment (key, "mycomment"); // the usercode stores a comment for the key ksAppendKey(keyset, key); // append the key to the keyset kdbSet (handle, keyset, 0, 0); } // so now kdbSet is called int kdbSet(KDB *handle, KeySet *keyset, Key *parentKey, options) { // find appropriate plugin elektraPluginSet (handle, keyset, 0); // the keyset with the key will be passed to this function } // so now elektraPluginSet(), which is the function described here, is called elektraPluginSet(KDB *handle, KeySet *keyset, Key *parentKey) { // the task of elektraPluginSet is now to store the comment Key *key = ksCurrent (keyset); // get out the key where the user set the comment before char *comment = allocate(size); keyGetComment (key, comment, size); savetodisc (comment); }
Of course not only the comment, but all information of every key in the keyset returned need to be stored permanetly. So this specification needs to give an exhaustive list of information present in a key. Precondition:
The keyset returned holds all keys which must be saved
permanently for this keyset. The keyset is sorted and rewinded. All keys
having children must be true for keyIsDir().
The parentKey is the key which is the ancestor for all other keys in the keyset.
The first key of the keyset returned has the same keyname. The parentKey is
below the mountpoint, see kdbhGetMountpoint().
The caller kdbSet will fulfill following parts:
Invariant:
- •
- If the user does not want hidden keys they will be thrown away. All keys in returned need to be stored permanently.
- •
- If the user does not want dirs or only dirs kdbGet() will remove the other.
- •
- Sorting of the keyset. It is not important in which order the keys are appended. So make sure to set all keys, all directories and also all hidden keys. If some of them are not wished, the caller kdbSet() will sort them out.
There are no global variables and kdbhGetBackendData()
only stores information which can be regenerated any time. The handle is the
same when it is the same plugin.
Postcondition:
The information of the keyset returned is stored
permanently.
Lock your permanent storage in an exclusive way, no access of a concurrent
elektraPluginSet_plugin() or kdbGet() is possible and these methods
block until the function has finished. Otherwise declare kdbcGetnoLock().
See also:
kdbSet() for caller.
Parameters:
handle contains internal information of the plugin
returned contains a keyset with relevant keys
parentKey contains the information where to set the keys
Returns:
When everything works gracefully return the number of
keys you set. The cursor position and the keys remaining in the keyset are not
important.
Note:
If any calls you use change errno, make sure to restore
the old errno.
Return values:
1 on success
0 on success with no changed key in database
-1 on failure. The cause of the error needs to beadded in parentKey
You also have to make sure that ksGetCursor() shows to the position where
the error appeared.
Plugin* ELEKTRA_PLUGIN_EXPORT (doc)¶
All KDB methods implemented by the plugin can have random names, except ELEKTRA_PLUGIN_EXPORT. This is the single symbol that will be looked up when loading the plugin, and the first method of the backend implementation that will be called. You need to use a macro so that both dynamic and static loading of the plugin works. The first parameter is the name of the plugin. Then every plugin should have: ELEKTRA_PLUGIN_OPEN, ELEKTRA_PLUGIN_CLOSE, ELEKTRA_PLUGIN_GET, ELEKTRA_PLUGIN_SET and optionally ELEKTRA_PLUGIN_ERROR. The list is terminated with ELEKTRA_PLUGIN_END. You must use static 'char arrays' in a read only segment. Don't allocate storage, it won't be freed. Returns:Plugin
See also:
elektraPluginExport()
Author¶
Generated automatically by Doxygen for Elektra from the source code.Tue Aug 19 2014 | Version 0.8.7 |