$darkmode
Elektra 0.11.0
Backend Plugins

Backend Contract

There exists a backend contract between libelektra-kdb and any plugin acting as a backend plugin. This contract describes:

1 sequenceDiagram
2  actor user
3  participant kdb as libelektra-kdb
4  participant backend as backend
5  participant other as other-backend
6  participant storage
7  participant validation
8  participant sa as storage-unit-a (e.g. file)
9  participant sb as storage-unit-b (e.g. database)
10 
11  user->>+kdb: kdbGet
12  kdb->>backend: init
13  kdb->>other: init
14  kdb->>+backend: resolver
15  backend->>-kdb: "storage-unit-a", update needed
16  kdb->>+other: resolver
17  other->>-kdb: "storage-unit-b", no update needed
18  kdb->>backend: prestorage
19  kdb->>+backend: storage
20  backend->>+storage: #
21  storage->>+sa: #
22  sa-->>-storage: #
23  storage-->>-backend: #
24  backend-->>-kdb: #
25  kdb->>+backend: poststorage
26  backend->>+validation: #
27  validation-->>-backend: #
28  backend-->>-kdb: #
29  kdb->>kdb: merge backends
30  kdb-->>-user: #
1 sequenceDiagram
2  actor user
3  participant kdb as libelektra-kdb
4  participant backend as backend
5  participant other as other-backend
6  participant storage
7  participant validation
8  participant sa as storage-unit-a (e.g. file)
9 
10  user->>+kdb: kdbSet
11  kdb->>kdb: check backends initialized
12  kdb->>+backend: resolver
13  backend-->>-kdb: "storage-unit-a"
14  critical try to store
15  kdb->>+backend: prestorage
16  backend->>+validation: #
17  validation-->>-backend: #
18  backend-->>-kdb: #
19  kdb->>+backend: storage
20  backend->>+storage: #
21  storage->>+sa: write to temp
22  sa-->>-storage: #
23  storage-->>-backend: #
24  backend-->>-kdb: #
25  kdb->>backend: poststorage
26  kdb->>backend: precommit
27  backend->>sa: make changes permanent
28  kdb->>+backend: commit
29  backend-->-kdb: #
30  kdb->>backend: postcommit
31  option on failure
32  kdb->>backend: prerollback
33  kdb->>+backend: rollback
34  backend->>sa: revert changes
35  backend-->>-kdb: #
36  kdb->>backend: postrollback
37  end
38  kdb-->>-user: #

The diagrams above show some typical sequences of phases during a get and a set operation. For each of the phases of a get operation libelektra-kdb calls the backend plugin's elektra<Plugin>Get function once. Similarly, for the phases of a set operation elektra<Plugin>Set is called once. The backend plugin can also (optionally) delegate to other plugins.

The current phase is communicated to the backend plugin (and any other plugin) via the global keyset. It can be retrieved via the elektraPluginGetPhase function.

parentKey

The key parentKey that is given to the backend plugin as an input at various points, must be treated carefully. All modifications to this key will be propagated to the parentKey that was used to call kdbGet.

The name of the parentKey is marked read-only and therefore cannot be changed. The value and metadata can, and in some cases must be, changed. Importantly however, there are no guarantees that the metadata of parentKey can be changed arbitrarily.

Operation get

The get operation is mandatory and all backend plugins must implement it.

Initialization Phase

During the init phase the backend plugin is called with:

The backend plugin then:

This phase exists purely for the backend plugin to initialize and configure itself for the mountpoint.

Note: This phase is only executed once per instance of KDB. Only the first kdbGet() call will result in libelektra-kdb executing this phase, all future calls to kdbGet() (and kdbSet()) start with the resolver phase. The backend plugin must store the necessary information contained in the mountpoint definition internally to accommodate this.

Resolver Phase

During the resolver phase the backend plugin is called with:

The backend plugin then:

Note: The backend plugin may also modify the keyset ks, but libelektra-kdb will discard this keyset after this phase, so these modifications won't have any effects.

During a set operation, the backend plugin must ensure

Cache-Check Phase

Implementing this phase is optional. If a backend plugin does not support caching, it should immediately return a value indicating that the cache is invalid. If there is no cache entry for this backend, libelektra-kdb skips this phase.

During the cachecheck phase the backend plugin is called with:

The backend plugin then:

Note: The backend plugin may also modify the keyset ks, but libelektra-kdb will discard this keyset after this phase, so these modifications won't have any effects.

Storage Phases

These phases are responsible for reading and validating the actual data stored in the KDB.

In the prestorage phase the backend plugin is called with:

There are no restrictions on what the backend plugin may do in this phase, but just like in the resolver phase, change to ks will be discarded. This phase is useful for file-level manipulations, like file-based encryption, line ending conversion or verifying file signatures. In this sense, it is the counter-part of the precommit phase of the set operation.

The storage phase is for reading the actual data. In this phase the backend plugin is called with:

The backend plugin then:

The last of the storage phases is the poststorage phase. In this phase the backend plugin is called with:

Again there are no restrictions on what the backend plugin may do in this phase. However, unlike the prestorage phase, this phase is a very important one. It is where validation, generation of implicit values and similar tasks happen.

Finally, libelektra-kdb merges the keyset returned by the poststorage phase with the ones returned by other backend plugins for different mountpoints and then returns it to the user.

Operation set

The set operation is optional. A mountpoint is automatically read-only and doesn't support the set operation, if the backend plugin does not define a elektra<Plugin>Set function.

Alternatively, the read-only nature of the mountpoint may also be indicated by the backend plugin during the init phase of the get operation.

Resolver Phase

During the resolver phase the backend plugin is called with:

The backend plugin then:

Note: The backend plugin may also modify the keyset ks, but libelektra-kdb will discard this keyset after this phase, so these modifications won't have any effects.

Storage Phases

These phases are responsible for validating and writing data to the KDB.

In the prestorage phase the backend plugin is called with:

There are no restrictions on what the backend plugin may do in this phase. This phase can be used for validation to avoid storing invalid configuration. However, it should not be used for generating keys or values implicitly defined by other keys. Such keys should be generated during the poststorage phase of a get operation and should actually be removed again in this phase. That way there cannot be conflicts, if a key that implies another keys value changes.

Note: Just in case there is actually a use case, where keys have to be generated, removed or modified during this phase, we do not discard changes to ks (like we would do in a get operation).

The storage phase is for writing the actual data. In this phase the backend plugin is called with:

The backend plugin then:

The last of the storage phases is the poststorage phase. In this phase the backend plugin is called with:

There are no formal restrictions, other than those enforced by parentKey and ks being (partially) read-only. But the poststorage phase should not be used as a counter-part to the prestorage phase in the get operation. Use the precommit phase instead. Therefore, the poststorage phase has very little use cases other than logging and exists mostly because of symmetry.

Commit Phases (set only)

If all storage phases completed successfully, libelektra-kdb will continue with calling the commit phases. Even though the commit phases are part of the set operation, libelektra-kdb calls elektra<Plugin>Commit and not elektra<Plugin>Set for these phases.

All the commit phases (precommit, commit, postcommit) are called with:

There are no restrictions on the precommit phase, other than those enforced by parentKey and ks being (partially) read-only. This phase can be used for file-level manipulations, like file-based encryption, line ending conversion or adding file signatures. In this sense, it is the counter-part of the prestorage phase of the get operation.

In the commit phase the backend plugin:

There are no restrictions on what the backend plugin may do in the postcommit phase. However, it is important to keep in mind that an error in the postcommit phase will not make the set operation fail. Once the commit phase completes successfully, the set operation is also deemed successful, since the changes were made permanent. If an error does occur in the postcommit phase, it is reported as warning. This makes the postcommit phase mostly useful for logging.

Finally, libelektra-kdb merges the keyset returned by the postcommit phase (still the same one that was returned by the prestorage phase) with the ones returned by other backend plugins for different mountpoints and then returns it to the user.

Rollback Phases (set only)

If any of the phases prestorage, storage, poststorage, precommit or commit fail, libelektra-kdb will continue with the rollback phases. Even though the rollback phases are part of the set operation, libelektra-kdb calls elektra<Plugin>Error and not elektra<Plugin>Set for these phases.

Similar to the commit phases, the rollback phases (prerollback, rollback and postrollback) are called with:

Additionally, the phase that reported an error is communicated to the backend plugin via the global keyset (together with the current phase). The value of the key system:/elektra/kdb/backend/failedphase is set to the failed phase.

The prerollback and postrollback phases are mostly useful for logging. There are no restrictions on these phases, other than those enforced by parentKey and ks being (partially) read-only. However, they are similar to the postcommit phase, in that any errors they report will be ignored and reported as warnings. In particular, even if the prerollback phase fails, libelektra-kdb will continue with the rollback phase as if prerollback succeeded.

In the rollback phase the backend plugin:

Finally, libelektra-kdb will restore ks to the state in which the user provided it and return.