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

[new-backend] spec hook #4495

Merged
merged 11 commits into from
Sep 30, 2022
5 changes: 5 additions & 0 deletions doc/news/_preparation_next_release.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,11 @@ The following section lists news about the [plugins](https://www.libelektra.org/
- <<TODO>>
- <<TODO>>

### spec

- Partial rewrite for spec hook _(Maximilian Irlinger @atmaxinger)_
- <<TODO>>

### <<Plugin3>>

- <<TODO>>
Expand Down
16 changes: 12 additions & 4 deletions src/include/kdbprivate.h
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,9 @@ typedef int (*kdbCommitPtr) (Plugin * handle, KeySet * returned, Key * parentKey

typedef int (*kdbHookGoptsGetPtr) (Plugin * handle, KeySet * returned, Key * parentKey);

typedef int (*kdbHookSpecCopyPtr) (Plugin * handle, KeySet * returned, Key * parentKey, bool isKdbGet);
typedef int (*kdbHookSpecRemovePtr) (Plugin * handle, KeySet * returned, Key * parentKey);

typedef Plugin * (*OpenMapper) (const char *, const char *, KeySet *);
typedef int (*CloseMapper) (Plugin *);

Expand Down Expand Up @@ -321,8 +324,6 @@ struct _KeySet
#endif
};

typedef struct _Hooks Hooks;

/**
* The access point to the key database.
*
Expand Down Expand Up @@ -371,9 +372,16 @@ struct _KDB
{
struct
{
struct _Plugin* plugin;
kdbHookGoptsGetPtr kdbHookGoptsGet;
struct _Plugin * plugin;
kdbHookGoptsGetPtr get;
} gopts;

struct
{
struct _Plugin * plugin;
kdbHookSpecCopyPtr copy;
kdbHookSpecRemovePtr remove;
} spec;
} hooks;
};

Expand Down
45 changes: 44 additions & 1 deletion src/libs/elektra/hooks.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,16 @@ void freeHooks (KDB * kdb, Key * errorKey)
if (kdb->hooks.gopts.plugin != NULL)
{
elektraPluginClose (kdb->hooks.gopts.plugin, errorKey);
kdb->hooks.gopts.plugin = NULL;
kdb->hooks.gopts.get = NULL;
}

if (kdb->hooks.spec.plugin != NULL)
{
elektraPluginClose (kdb->hooks.spec.plugin, errorKey);
kdb->hooks.spec.plugin = NULL;
kdb->hooks.spec.copy = NULL;
kdb->hooks.spec.remove = NULL;
}
}

Expand All @@ -43,7 +53,27 @@ static int initHooksGopts (KDB * kdb, Plugin * plugin, Key * errorKey)

kdb->hooks.gopts.plugin = plugin;

if ((kdb->hooks.gopts.kdbHookGoptsGet = (kdbHookGoptsGetPtr) getFunction (plugin, "hook/gopts/get", errorKey)) == NULL)
if ((kdb->hooks.gopts.get = (kdbHookGoptsGetPtr) getFunction (plugin, "hook/gopts/get", errorKey)) == NULL)
{
return -1;
}

return 0;
}

static int initHooksSpec (KDB * kdb, Plugin * plugin, Key * errorKey)
{
if (!plugin)
{
return -1;
}

kdb->hooks.spec.plugin = plugin;

kdb->hooks.spec.copy = (kdbHookSpecCopyPtr) getFunction (plugin, "hook/spec/copy", errorKey);
kdb->hooks.spec.remove = (kdbHookSpecRemovePtr) getFunction (plugin, "hook/spec/remove", errorKey);

if (kdb->hooks.spec.copy == NULL || kdb->hooks.spec.remove == NULL)
{
return -1;
}
Expand Down Expand Up @@ -138,6 +168,13 @@ static bool isGoptsEnabledByContract (const KeySet * contract)
return isEnabled;
}

static bool isSpecEnabledByConfig (const KeySet * config)
{
// TODO: check for system:/elektra/hook/spec/enabled or system:/elektra/hook/spec/disabled or something else ... TBD
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we need to solve this before merging this PR. Can be added later at any time.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed.

// See this discussion: https://github.com/ElektraInitiative/libelektra/issues/4499
return true;
}

/**
* Initializes the hooks stored in the passed KDB handle.
* If the handle already contains initialized hooks, they will be reinitialized, including unloading and loading of their plugins.
Expand Down Expand Up @@ -169,6 +206,12 @@ int initHooks (KDB * kdb, const KeySet * config, KeySet * modules, const KeySet
goto error;
}

if (isSpecEnabledByConfig (config) &&
initHooksSpec (kdb, loadPlugin ("spec", kdb->global, modules, contract, errorKey), errorKey) != 0)
{
goto error;
}

if (!existingError)
{
// remove dummy error again
Expand Down
53 changes: 42 additions & 11 deletions src/libs/elektra/kdb.c
Original file line number Diff line number Diff line change
Expand Up @@ -1865,28 +1865,30 @@ int kdbGet (KDB * handle, KeySet * ks, Key * parentKey)
goto error;
}

/* TODO (kodebach): implement actual steps with new global plugins
// Step 14: run spec plugin
if (!specGet (dataKs, cascadingParent))
{
clear_bit (parentKey->flags, KEY_LOCK_NAME | KEY_LOCK_VALUE);
goto error;
}
clear_bit (parentKey->flags, KEY_LOCK_NAME | KEY_LOCK_VALUE);
*/

// Step 13: run gopts (if enabled)
keyCopy (parentKey, initialParent, KEY_CP_NAME);
keySetNamespace (parentKey, KEY_NS_CASCADING);

if (goptsActive && !handle->hooks.gopts.kdbHookGoptsGet (handle->hooks.gopts.plugin, dataKs, parentKey))
if (goptsActive && !handle->hooks.gopts.get (handle->hooks.gopts.plugin, dataKs, parentKey))
{
clear_bit (parentKey->flags, KEY_LOCK_NAME | KEY_LOCK_VALUE);
goto error;
}

keySetNamespace (parentKey, keyGetNamespace (initialParent));

// Step 14: run spec plugin
if (handle->hooks.spec.plugin && handle->hooks.spec.copy (handle->hooks.spec.plugin, dataKs, parentKey, true) == -1)
{
clear_bit (parentKey->flags, KEY_LOCK_NAME | KEY_LOCK_VALUE);
goto error;
}
clear_bit (parentKey->flags, KEY_LOCK_NAME | KEY_LOCK_VALUE);

// TODO (atmaxinger): should we have a default:/ backend?
Key * defaultCutpoint = keyNew ("default:/", KEY_END);
KeySet * defaults = ksCut (dataKs, defaultCutpoint);

// Step 15: split dataKs for poststorage phase
// FIXME (kodebach): handle proc:/ keys
if (!backendsDivide (backends, dataKs))
Expand Down Expand Up @@ -1917,6 +1919,11 @@ int kdbGet (KDB * handle, KeySet * ks, Key * parentKey)
// Step 18: merge data into ks and return
backendsMerge (backends, ks);

// TODO (atmaxinger): should we have a default:/ backend?
ksAppend (ks, defaults);
ksDel (defaults);
keyDel (defaultCutpoint);

// Step 19: update cache
// FIXME (kodebach): implement cache

Expand Down Expand Up @@ -2320,6 +2327,11 @@ int kdbSet (KDB * handle, KeySet * ks, Key * parentKey)
goto error;
}

if (handle->hooks.spec.plugin && handle->hooks.spec.copy (handle->hooks.spec.plugin, ks, parentKey, false) == -1)
{
goto error;
}

// TODO (kodebach) [opt]: merge steps 4-6
// By merging steps 4-6, we MAY be able to avoid copying keys from unchanged and read-only backends.

Expand Down Expand Up @@ -2407,6 +2419,25 @@ int kdbSet (KDB * handle, KeySet * ks, Key * parentKey)
}
*/

// Step 8: merge data from all backends (for spec removal)
ksClear (setKs);
backendsMerge (backends, setKs);

// Step 9: run the spec plugin to remove copied metadata
if (handle->hooks.spec.plugin && handle->hooks.spec.remove (handle->hooks.spec.plugin, setKs, parentKey) == -1)
{
goto rollback;
}

// Step 10: split setKs for remaining phases
if (!backendsDivide (backends, setKs))
{
ELEKTRA_SET_INTERNAL_ERROR (parentKey,
"Couldn't divide keys into mountpoints after spec removal. Please report this bug at "
"https://issues.libelektra.org.");
goto rollback;
}

// Step 11a: run storage phase
if (!runSetPhase (backends, parentKey, KDB_SET_PHASE_STORAGE, false, KDB_SET_FN_SET))
{
Expand Down
1 change: 0 additions & 1 deletion src/plugins/spec/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
- infos/licence = BSD
- infos/needs =
- infos/provides = check apply
- infos/placements = postgetstorage presetstorage
- infos/status = recommended productive nodep configurable global unfinished
- infos/description = allows to give specifications for keys

Expand Down
Loading