Skip to content
This repository has been archived by the owner on Oct 15, 2024. It is now read-only.

Commit

Permalink
Restyled by prettier-markdown
Browse files Browse the repository at this point in the history
  • Loading branch information
restyled-commits authored and atmaxinger committed Oct 14, 2022
1 parent 2be121b commit 7148da4
Showing 1 changed file with 34 additions and 29 deletions.
63 changes: 34 additions & 29 deletions doc/decisions/change_tracking.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,18 @@
## Problem

Currently, a range of Elektra plugins are implementing some sort for change-tracking of configuration data.
This includes, but is not limited to, the [internalnotification](../../src/plugins/internalnotification/README.md)
This includes, but is not limited to, the [internalnotification](../../src/plugins/internalnotification/README.md)
and [dbus](../../src/plugins/dbus/README.md) plugins. In the near future, Elektra shall also be extended with session recording.

Having multiple implementations for the same problem is problematic in multiple ways:

1. pointless waste of resources, as data is duplicated in each plugin,
2. multiplication of code, generating a maintenance burden.

Additionally, it was uncovered in issue [#4514](https://issues.libelektra.org/4514),
Additionally, it was uncovered in issue [#4514](https://issues.libelektra.org/4514),
that the current approach to change tracking in plugins is very fragile.
Basically, what plugins do currently is:

1. on `kdbGet` duplicate the returned keyset,
2. on `kdbSet` calculate what changed inbetween.

Expand All @@ -33,16 +35,17 @@ kdbGet(kdb, b, keyB); // (B)
kdbSet(kdb, a, keyA); // (C)
```
* At point `(A)` the plugins internally store the KeySet for key `a`
* At point `(B)` the plugins internally override the stored the KeySet with the KeySet for key `b`
* At point `(C)` they will generate a wrong changeset for key `a`
- At point `(A)` the plugins internally store the KeySet for key `a`
- At point `(B)` the plugins internally override the stored the KeySet with the KeySet for key `b`
- At point `(C)` they will generate a wrong changeset for key `a`
Now, this problem could be overcome by also remembering the key for which the KeySet was read, but none of the plugins do that.
Changing this leads us back to problem number 2, the maintenance burden.
## Constraints
Change tracking must:
- be transparent to developers using the public Elektra API
- be transparent to users changing configuration data
- only be done if it is required, i.e. a plugin specifically requests it
Expand All @@ -52,9 +55,9 @@ Change tracking must:
## Assumptions
- Some kind of memory and computation overhead is acceptable
- Some kind of memory and computation overhead is acceptable
as long as it doesn't scale linearly (or worse) with the number of plugins
- It is possible to design a single change tracking API that is useful
- It is possible to design a single change tracking API that is useful
for all existing and future plugins
## Considered Alternatives
Expand All @@ -67,11 +70,11 @@ This section is both a summary and an extension of this discussion.
While this solves the consistency problem of the calculated change-set,
the issue of duplicated data and maintenance burden for each plugin still persists.
Moreover, it breaks the 'transparency' constraint, as developers need to take
special care how they order their `kdbGet` and `kdbSet` operations to not upset
special care how they order their `kdbGet` and `kdbSet` operations to not upset
change tracking.
2. Fix the change tracking in the plugins by remembering the parent key for each operation.
This fixes the consistency problem and is transparent for developers and users.
However, the duplicated data and maintenance problem is not solved by this approach.
Expand All @@ -80,50 +83,52 @@ This section is both a summary and an extension of this discussion.
This is the first option that does not break any of the constraints.
Essentially, we'd have a 'giant' hashmap in the form of (parent key)->(KeySet) for all parent keys
that were used for a `kdbGet` operation in the lifetime of the `kdb` instance. We also need to
update it on `kdbSet` so that a future `kdbSet` operation without a `kdbGet` will also work.
that were used for a `kdbGet` operation in the lifetime of the `kdb` instance. We also need to
update it on `kdbSet` so that a future `kdbSet` operation without a `kdbGet` will also work.
When change tracking is enabled, this one will have the most memory overhead, as we need to deep-dup
every key we have read or stored.
4. Do the per-parent-key tracking within `libelektra-kdb`, but with meta-keys.
Essentially the same approach as above, but instead of deep-duping, we add the original value
Essentially the same approach as above, but instead of deep-duping, we add the original value
as a meta-key to every key. Not yet clear how we handle changes to meta-data then.
5. Outsource the change tracking into a separate plugin.
Essentially the same as (3), just that it is implemented within a plugin and not
`libelektra-kdb`. This will be a hook plugin, and will be called within `kdbGet` and `kdbSet` accordingly.
It will also need to export a hook-method to get the changeset.
6. Do copy-on-write change tracking within `libelektra-core`.
This option will also not break any of the constraints.
The idea here is that we extend the `KeySet` and `Key` structs with additional fields.
For `KeySet` we need to track the following info:
* What keys have been removed
* What keys have been added
* Whether tracking is enabled for this KeySet
- What keys have been removed
- What keys have been added
- Whether tracking is enabled for this KeySet
For `Key` we need to track:
* Original value of the key
* Size of the original value (for binary keys)
* Whether tracking is enabled for this key
- Original value of the key
- Size of the original value (for binary keys)
- Whether tracking is enabled for this key
The tracking itself would be done within the `ks*` and `key*` methods, after checking if it is enabled.
It would also transparently work for meta-data, as meta-data itself is implemented as a keyset with keys.
Two downsides of this method have been identified by @kodebach:
* It adds functionality to `libelektra-core` which is supposed to be minimal
* Adding fields to the structs causes a slight memory overhead, even with tracking turned off.
While neglectable for `KeySet` due to the low amount of keysets in typical applications,
it may be noticable for `Key`. On a 64-bit system we'd add 8+8=16 bytes to it.
To put this in perspective, the current size of the `Key` struct is 64 bytes,
so we'd add 25% overhead to an empty key. However, this percentage will be much lower in
a real-world application, as the usefulness of an empty key is very low.
Two downsides of this method have been identified by @kodebach:
- It adds functionality to `libelektra-core` which is supposed to be minimal
- Adding fields to the structs causes a slight memory overhead, even with tracking turned off.
While neglectable for `KeySet` due to the low amount of keysets in typical applications,
it may be noticable for `Key`. On a 64-bit system we'd add 8+8=16 bytes to it.
To put this in perspective, the current size of the `Key` struct is 64 bytes,
so we'd add 25% overhead to an empty key. However, this percentage will be much lower in
a real-world application, as the usefulness of an empty key is very low.
## Decision
Expand Down

0 comments on commit 7148da4

Please sign in to comment.