$darkmode
|
Elektra 0.11.0
|
There are four main operations in libelektra-kdb: open, get, set and close. For each of these there is a kdb* function the user calls to trigger the operation and plugins export a function for each of the operations they support (at least get).
Additionally, plugins may implement commit and error. These are part of the set operation and there is no corresponding kdbCommit or kdbError function available in libelektra-kdb.
The operations get and set also have different phases:
get operation has: init, resolver, cachecheck, prestorage, storage and poststorage.set operation has: resolver, prestorage, storage and poststorage followed by precommit, commit and postcommit if the previous phases where successful or by prerollback, rollback and postrollback if the previous phases failed.These phases are implemented by a backend plugin. Read the Documentation on Backend Plugins for more information on what backend plugins do.
Note The steps of the operations described below, are referenced in the source code with
// Step Xcomments.
The open operation implemented in kdbOpen is the first thing that happens to all KDB instances.
The basic flow of this operation is:
KDB instanceKDB instance for bootstrapget operation: This loads the contents of system:/elektra/mountpoints so that the mountpoints can be configured.system:/elektra/mountpoints into the internal state stored in a KDB instance.KDB with real mountpoints: This switches the KDB instance from bootstrap mode to use the real mountpoint state created above.KDB instance: There are a few hard coded mountpoints (root mountpoints, system:/elektra/modules, system:/elektra/version, etc.) that are always present. They are added in this step.Namespaces in mountpoint configs:
dir:/, user:/ and system:/ mountpoints can be created without restrictions, except for the reserved sections listed below.spec:/ mountpoints can be created with the same restrictions, but they are also treated specially during get and set.proc:/ mountpoints are always read-only and receive special treatment during getdefault:/ mountpoints are read-only and receive special treatment during get, specifically they only go through the poststorage phaseNote The special treatments of the various namespaces are explained below in the sections for the
getandsetoperation.
Reserved sections:
/elektra or below in any namespace is forbidden. This section of the KDB is reserved for Elektra's own config.system:/elektra/mountpoints, user:/elektra/mountpoints and dir:/elektra/mountpoints are all required for the bootstrap process and use a hard coded backend. The backends are implemented by a standard file-based backend plugin that is defined at compile-time of libelektra-kdb.system:/elektra/version and system:/elektra/modules will always use hard coded read-only backends containing information about this Elektra installation. The backends are implemented by special purpose backend plugins.The purpose of the get operation is to read data stored in backends into a KDB instance.
Note: Some details of a
getoperation are defined in the contract with backend plugins.
Properties of kdbGet():
kdbGet (kdb, ks, parentKey), the KeySet ks will contain all keys (including their values) that are stored in any backend with a mountpoint that is below parentKey.kdbGet (kdb, ks, parentKey), below parentKey the KeySet ks will mostly contain keys that are stored in a backend. The exception here are proc:/ and spec:/ keys. For other namespaces, all keys below parentKey will be removed from ks. For proc:/ and spec:/ only keys that overlap with a backend that was loaded will be removed from ks.ks may contain other keys not below parentKey:parentKey, but are stored in a backend that contains other keys which are below parentKey. These keys are returned, because backends are treated as one atomic unit. Either all keys within a backend are read, or none of them are.ks when kdbGet() was called and do not conflict with the goal of representing the current state of the KDB below parentKey.kdbGet (kdb, ks, parentKey), the Key parentKey will only have the meta:/error/* or meta:/warnings/#/* metakeys, if the errors/warnings originate from this kdbGet() call. In other words, kdbGet () first clears any existing errors/warnings and only then starts doing the actual work.parentKey with a namespace other than: default:/, proc:/, spec:, dir:/, user:/, system:/ or cascadingTo the caller it looks as if kdbGet() had removed all keys below parentKey, as well as some others, from ks and then loaded the data from the backends. Which backends are actually read is an implementation detail. Which keys are removed from ks depends on the backends that are read.
kdbGet() will always try to be efficient in achieving its goal of reading the keys below parentKey. It is only guaranteed that below parentKey the KeySet ks correctly represents the state of the KDB. For the rest of ks there are no such guarantees.
Note: In the list below "phase" always refers to a phase of the
getoperation as described in the backend plugin contract.
The flow of this operation is:
parentKeyopen operation for all required backends that haven't been openedinit phase on all the backends that haven't been initializedresolver phase on all backendscachecheck phase on all backendsprestorage and storage phase on all backends.poststorage phase of all spec:/ backends.gopts/get hook.spec/copy hook.poststorage phase for all non-spec:/ backends.ks.ks.notification/send hook. Then return.Note: In case of error, we abort immediately, restore
ksto its original state and return.
Influence of namespaces:
spec:/ backends go through init, resolver, cache, presetstorage and storage phases as normal, but their poststorage phase is called earlier. This is required, because any validation and post-processing of spec:/ keys needs to happen, before they are used as the specification for other keys in the actual poststorage phase.dir:/, user:/ and system:/ go through all phases as described above.proc:/ mountpoints go through all the phases as described above, but they are not stored in the cache.default:/ backends only go through the poststorage phase. This is because default:/ keys are generated from the specification (stored as spec:/ keys). Therefore, no default:/ keys can exist before the specification is processed by the spec/copy hook.ksThe purpose of the set operation is to write data from a KDB instance into backends.
Note: Some details of a
setoperation are defined in the contract with backend plugins.
Properties of kdbSet():
kdbSet (kdb, ks, parentKey) the contents (key names, values and metadata) of ks will mostly not be modified. The only modifications that are made to ks are those that originate from the spec/copy hook.ks that are below parentKey will be persisted in the KDB, when a kdbSet (kdb, ks, parentKey) call returns successfully. Additionally, any key in ks that shares a backend with another key which is below parentKey will also be persisted.kdbSet may result in an error, if kdbGet wasn't called on this KDB instance with the same parentKey at least once.kdbSet (kdb, ks, parentKey), the Key parentKey will only have the meta:/error/* or meta:/warnings/#/* metakeys, if the errors/warnings originate from this kdbSet() call. In other words, kdbSet () first clears any existing errors/warnings and only then starts doing the actual work.parentKey with a namespace other than: default:/, proc:/, spec:, dir:/, user:/, system:/ or cascadingThe flow of this operation is:
parentKey.kdbGet() was called).spec/copy hook on ks (to add metakeys to newly created keys).ks (below parentKey) into a new KeySet set_ksset_ks into individual backendsKEY_FLAG_SYNC) could contain changed data. From now on ignore all backends that have not changed. From now on also ignore all backends that were initialized as read-only. Issue a warning, if a change was detected (via KEY_FLAG_SYNC) in a read-only backend. 7. Run theNote: Steps 4-6 might be combined into a single procedure that deep-copies only keys from changed backends into separate KeySets per backend
resolver and prestorage on all backends (abort immediately on error and go to e).set_ks.spec/remove hook on set_ks (to remove copied metakeys).set_ks into individual backends again.storage and poststorage phases on all backends (abort immediately on error and go to e).precommit and commit phases on all backends (abort immediately on error and go to e), then run the postcommit phase on all backends (record all errors as warnings and ignore them) and return.prerollback, rollback and postrollback phases on all backends and return. Influence of namespaces:
default:/ and proc:/ keys are completely ignored by kdbSet()spec:/, dir:/, user:/ and system:/ go through all phases as described above.ksThe close operation is very simple. It simply frees up all resources used by a KDB instance.