libelektra icon indicating copy to clipboard operation
libelektra copied to clipboard

[new-backend] Extend kdbOpen contracts for adding mountpoints

Open kodebach opened this issue 3 years ago • 3 comments

The contract KeySet passed to kdbOpen currently supports only two types of contract: adding global plugins and adding keys to the global keyset (see docs)

This is enough for the currently supported use cases of: configuring gopts and setting up I/O bindings and notifications. However, another use case is the new kdb (and possibly other applications). There we want to embed its specification into the application itself to ensure the tool always works and isn't dependent on files/mountpoints being present on the system.

To solve this a new type of contract mountpoint shall be added, i.e. keys below system:/elektra/contract/mountpoint can be used to define an in-process mountpoint. This mountpoint acts like any other mountpoint present on disk. It is added after the boostrap kdbGet, i.e. mountpoints defined in the contract override the ones present on disk.

Because this issue is concerned with mountpoints, it should only be implemented on the new-backend branch.


Proposal for structure

This is a proposal for the structure of the mountpoints contract. IMO the simplest solution would be to use system:/elektra/contract/mountpoint/<mountpointkey>/... where <mountpointkey> is the escaped form of the key at which the backend will be mounted and ... is the definition of the mountpoint. In other words, the contract would be exactly the same as a real mountpoint at system:/elektra/mountpoints, but moved to system:/elektra/contract/mountpoint.

For example to add a modified specload as a new backend at spec:/sw/myapp:


int main (void)
{
  KeySet * contract = ksNew (2,
    keyNew ("system:/elektra/contract/mountpoint/spec:\\/sw\\/myapp/plugins/backend/name", KEY_VALUE, "specload", KEY_END),
    keyNew ("system:/elektra/contract/mountpoint/spec:\\/sw\\/myapp/definition/symbol", KEY_VALUE, "myappGetSpec", KEY_END),
    KS_END
  );
  Key * parent = keyNew ("/sw/myapp", KEY_END);
  KDB * handle = kdbOpen (contract, parent);

  // ...
}

Note See #4444 for the required changes to specload

Required changes to libelektra-kdb

To make this new contract work, a few changes need to be made to libelektra-kdb.

The starting point is ensureContract, the helper function responsible for processing contracts.

https://github.com/ElektraInitiative/libelektra/blob/5f0895bc88c92c623d9e2147cdaf12f77cb4db68/src/libs/elektra/kdb.c#L343-L355

Since the new contract shouldn't have any interaction with the previous ones, we can just add a new ensureContractMountpoint call in line 351.

Since ensureContract is already called at the right place in kdbOpen (after the bootstrap kdbGet, but before mountpoints are processed into the internal structure), this new ensureContractMountpoint is very simple. It basically boils down to: 1) move the keys from system:/elektra/contract/mountpoint to system:/elektra/mountpoints & 2) add them to the existing mountpoints keyset to override.

For the second point we need to pass elektraKs from kdbOpen to ensureContract and then ensureContractMountpoint. Then it should simply be a case of:

static void ensureContractMountpoint (KeySet * elektraKs, KeySet * contract)
{
	Key * mountpointContractsRoot = keyNew ("system:/elektra/contract/mountpoint", KEY_END);
	Key * mountpointsRoot = keyNew ("system:/elektra/mountpoints", KEY_END);

	KeySet * mountpoints = ksCut (contract, mountpointContractsRoot);

	ksRename (mountpoints, mountpointContractsRoot, mountpointsRoot);

	// TODO: ksDel(ksCut(...)) the overlapping parts from elektraKs

	ksAppend (elektraKs, mountpoints);

	ksDel (mountpoints);
	keyDel (mountpointContractsRoot);
	keyDel (mountpointsRoot);
}

Note: This may work on master too. There the KeySet is simply called keys in kdbOpen. However, I'm not 100% sure if the surrounding code needs changes or not. Obviously, on master the contract would look different, since it would have to match the old system:/elektra/mountpoints structure and specload couldn't be used in the new "backend plugin" form.

kodebach avatar Aug 22 '22 15:08 kodebach

cc @hannes99 @markus2330

kodebach avatar Aug 22 '22 15:08 kodebach

system:/elektra/mountpoints

This should be changed to system:/elektra/mountpoint as we have in doc/DESIGN.md "We use singular for all names.". Do we need an extra issue for that?

system:/elektra/contract/mountpoint

:+1:

To make this new contract work, a few changes need to be made to libelektra-kdb.

Thank you, for so carefully investigating what is to be done! :heart_decoration:

I am missing the information what should be done if such a mountpoint already exists. Are you sure that simply inserting the keys, possibly kicking out other keys that were there, is safe with our definition of backends in the new-backend branch?

markus2330 avatar Aug 28 '22 09:08 markus2330

Are you sure that simply inserting the keys, possibly kicking out other keys that were there, is safe with our definition of backends in the new-backend branch?

It would probably be safer, to do appropriate ksCuts before the ksAppend in ensureContractMountpoint. This is more complex than I can quickly write up here, but the basic idea would be to

  1. Find the keys directly below mountpointsRoot in mountpoints.
  2. Do a ksDel (ksCut (elektraKs, keyFrom1)) for each of those.
  3. Then do the ksAppend (elektraKs, mountpoints).

kodebach avatar Aug 28 '22 11:08 kodebach

I mark this stale as it did not have any activity for one year. I'll close it in two weeks if no further activity occurs. If you want it to be alive again, ping by writing a message here or create a new issue with the remainder of this issue. Thank you for your contributions :sparkling_heart:

github-actions[bot] avatar Aug 29 '23 01:08 github-actions[bot]

I closed this now because it has been inactive for more than one year. If I closed it by mistake, please do not hesitate to reopen it or create a new issue with the remainder of this issue. Thank you for your contributions :sparkling_heart:

github-actions[bot] avatar Sep 13 '23 01:09 github-actions[bot]