$darkmode
Elektra 0.11.0
|
Certain plugins, e.g. rename
, perform transformations on keys and keysets within Elektra. Those transformations include, but are not limited to:
true
-> 1
, 1
-> true
While these features are useful, they do create feature-interaction problems. More specifically, problems have been observed in conjunction with the following (overlapping) types of plugins:
The problem, in general, can be described as: Which representation of the KDB should be used for notifications/change tracking?
We differentiate between:
storage
plugins.kdbGet
and passed to kdbSet
.Suppose there is a plugin that changes key names. It converts to lowercase for the runtime representation, and to uppercase for the stored representation. The plugin is executed in the post-storage phase for the get
operation and the pre-storage phase for the set
operation. This results in the keys being in UPPERCASE in the configuration files, but they are presented in lowercase to other plugins and applications using the Elektra API.
For example, here is a configuration file with a hypothetical format:
As can be seen, the keys are in UPPERCASE within the configuration file. In Elektra keys are case-sensitive. As operations on keysets such as ksLookup
operate with runtime data after the post-storage phase, kdb get /DISPLAY/BRIGHTNESS
will fail. For Elektra, the key /DISPLAY/BRIGHTNESS
does not exist, as the rename
plugin transformed this into the lowercase /display/brightness
.
This leads to problems with the notification plugins. As notification plugins are executed after the post-storage phase of the set
operation, they will receive a keyset with the already transformed keys. In this example, the notification plugins will receive all-UPPERCASE keys, and send out notifications with those all-UPPERCASE keys. An application listening to those notifications will not be able to query Elektra for those keys, as for Elektra those UPPERCASE keys do not exist.
Apart from the problems with notifications, the way key name changing plugins work also breaks change tracking in plugins like dbus
. This is because key names are read-only when they are contained in a KeySet
. In order to change the name of a key, such a plugin has to create a new key with the changed name, and delete the key with the old name. The dbus
plugin implements change tracking by checking the 'key needs sync' flag instead of comparing the values. As new keys by design have the 'key needs sync' flag set, the plugins that implement change tracking via the flag will always erroneously detect transformed keys as changed.
Suppose we have a plugin that changes the value of a key to the hard coded value 1
during the storage phase of the set
operation. If a plugin does change tracking, this will lead to false positives.
If the user changes the value, e.g. using kdb set user:/limits/openfiles 23
, plugins will observe the new value 23
. The value-changing plugin, however, will reset that value back to 1
. So in practice, the configuration has not been changed. Plugins relying on change tracking plugins (e.g. notification plugins) will however think that it has.
meta:/
keys.meta:/...
keys cankdbSet
meta:/generated/...
. The meta:/generated/...
metakeys are never stored and are automatically removed during kdbSet
before storage
is called.Require plugins that rename keys to remove the keyNeedsSync
flag. This would require making the 'key sync' APIs public. Letting user code modify these internal flags may lead to serious bugs. This does not solve the problem of changing values.
Eliminate the need of the keyNeedsSync
flag by utilizing the planned change tracking API. This does not solve the problem of changing values and false positives.
For key name transformations require that transformation plugins set a metakey (e.g. meta:/elektra/runtimename
) with the runtime name before they do any transformations in the kdbSet
phase. This must not be done if this metakey already exists, i.e. another plugin already tranformed it beforehand. This allows notification and change tracking functionality to work determine and work with the runtime name of the key.
A similiar thing was already attempted for values, i.e. meta:/origvalue
.
Plugins must use a special function to transform key names, e.g.:
How the elektraApplyNameTransform
function marks the original name is an internal implementation detail. May be as meta:/
or something else entireley.
Something similar could be done for the value of a key as well.
We could also introduce a new phase between before/after storage exclusively for transformations. Then we can just do a "fake" call to that phase to get back the transient names for change tracking.
After a value has been set by the user, call the transformation plugin. We could store those callbacks as metakeys, i.e. meta:/generated/transformation/value/callback/#1
. Alternatively, we could implement a linked list or other data structure for the callbacks.
There will be 3 possibilities where transformations take place:
keySetValue
/ keySetString
the callbacks are called.kdbSet
, as it is now.ksAppend
and/or ksAppendKey
the callbacks are copied from the original key and then executed on the new key.We also need to provide a simple API to plugins to register such callbacks for a key.
As the transformations for existing keys will be applied before kdbSet
, this will elimate false positives in changetracking.
A drawback to this solution is that it adds some complexity to libelektra-core
.