-
Notifications
You must be signed in to change notification settings - Fork 122
[new-backend] Various open questions #4407
Comments
Thank you for summarizing everything! ❤️
I think keeping them separated makes perfect sense. What would be the advantage of merging them?
The approach that other warning actually contains the reason for the error is ugly. Would be glad if we can get rid of this.
I am strongly against putting even more complexities into CMake. Defining this stuff in CMake failed totally. Nobody except devs&build server is actually using this, so far everyone wanted to use upstream packages as-is. A huge improvement in this area would be to have double-bootstrapping. This would also fix @Kochise's problems #4349.
If you see a way to do so protocols in between these parts? The resolver definitely could need some love, e.g., #3692 #1470 are long out-standing issues. Having smaller&simpler pieces would be a big help.
If it is inconsistent it is useless. I think at some point we correctly did it (always restoring every errno we changed). I am in favor of keeping it: it doesn't have disadvantages and the less side-effects Elektra has, the better. The new-backend branch is now a good time to recheck if it is done correctly.
IIRC this was an attempt to not destroy/leak meta-data.
In general split is needed to correctly determine which backends have something to do. It is possible that Thomas W. added some additional complications for global hooks. These additional complications most likely can be removed now with the simplifications in the hooks. (I do not think we need any for-each hook at all).
Yes: It already has two KeySets as arguments.
Could be very useful for import/export. @atmaxinger what do you think?
Is imho a good reason.
Probably it makes sense for a few specialized plugins. I would prefer, however, if all can keep the same interface and the contract simply states how they are allowed to be mounted. It makes the tooling much easier.
Discussing performance without benchmarks/profiling usually doesn't make much sense. These questions are no exception. But I can add a question for someone who actually makes benchmarks/profiling: newbackend introduced, iirc, some information which states in which position the backend currently is in. I wonder if this is really so cheap that it is worth having this feature. |
An immediate benefit is, reducing the size of The other thing is that we don't need to reload the exported symbols, when a (non-backend) plugin wants to call another plugin. The symbols would be in the global keyset, which is accessible to plugins, unlike
It doesn't even really have to be in CMake. The current
The easiest way would be to create some extra libs. These could then just be called by
I think this would only make sense, if we do and guarantee it across the entire public API of Elektra. That would be quite a big task, because we'd have to check everything that calls external functions. It is also a bit weird (but less so), if we don't enforce it on a plugin level.
I don't think so AFAICT metadata is the only thing that never gets restored from
I think there was a misunderstanding.... The split data structure doesn't exist in the The question was about a technical implementation detail in
And? What's the problem with that?
What tooling do you have in mind? I can't think of anything that would be involved here, other than the
I know, that's why I put them into a separate section. It's basically a "we don't need to talk about this right now, but we shouldn't forget about it" section.
That's exactly what "KDB phase passed as integer" is about. Right now we set a string in the global keyset (every time before a backend plugin is called) and there is a new function in the plugin API for retrieving this string. Additionally there are some Passing the values is pretty cheap, the global keyset already exists and if setting one key makes such a big difference we'd have much bigger problems. However, replacing the string with an integer could in theory speed up the plugin side (
|
The first question needs to be if plugins should have access to modules. If they should, then the proposal makes sense. Let us see what @atmaxinger does in his plugins.
I agree.
Very good idea. This would also save disc space, as currently every resolver includes this code separately. This is, however, actually totally unrelated to new-backend, isn't it?
This task was already done a few times. The question is how we can ensure that it stays correct in future, i.e., add some regression tests. For kdb* we could have a plugin that modifies errno and test cases that check if errno is unchanged.
This would be even harder to test? The current approach (to restore at user-interface) seems simpler to me.
It is API smell. Users can easily confuse which argument is what.
Tools like
I think issues with |
Yeah, I'm still not quite sure about that one. Probably, we should hide it somewhere and change the APIs for opening/calling other plugins, so that it internally goes through
Yes, AFAICT.
It's really hard to test this in general. Things like
And the current API isn't? There is a field in Actually I think this could be combined with the
AFAICT this only does a
I agree. I'll create a separate one once we decide which of the open questions are actionable items that need something done. This is more of a discussion issue (maybe we should move to the Discussions section of GitHub?). |
This comment was marked as resolved.
This comment was marked as resolved.
You only need to restore errno on the exit points. Not being able to fulfill such small requirements is an indication that we should not export such symbols. E.g. in this specific case, I think we should only support gopts and have elektraGetOpts as private (static) lib. So many different ways to do the same things are also a nightmare to test and maintain. They also make the docu harder to write and decrease discoverability.
Of course. If you see a way to simplify it, I am very open to suggestions.
If we do it in a way so that there is no overlap with src/libs/invoke, I am open to it. Maybe it can be done by improving src/libs/invoke?
How much it currently does or not does not change the fact that a generic tool that can check any plugin is much easier to write compared to a tool that needs to know about X different types of plugins, which all have different interfaces.
I think I already created all the needed issues. The other points seem to me to be implementation details. If at all, we might discuss it in a PR with a specific solution. Do you agree? |
I guess storing We also need to clarify, where we do want the
Adding the global keyset argument to the
Yes, this change would mostly be a replacement of the invoke lib. The idea is basically, that originally
To me this again seems like the almost obsessive need to make everything in Elektra generic and fit every use case.
|
Exactly. Actually the goal is even more general: we do not want to have any side-effect. Only our data structures are allowed to be modified; no thread-local or global variable. I created #4453
This is very debatable. Actually, most of the plugins don't need to load other plugins. But I agree that with backend=plugin it shifts a bit. It must be very clear, however, what problem the new API actually solves which the old ones (libinvoke and the modules) did not. To do something in this area would be a separate decision, though. I would prefer to do only minimal changes (or no changes), as there were no troubles with these parts at all.
I don't know what you are talking about. I was talking about making "implementing the tools" easier for us. E.g. imho
Also here I do not know what you are talking about. AFAIK |
The trouble IMO is that we're duplicating the helper data (like the
Seems like I missed that part of the code. The code in If we switch from the plugin struct to just the contract, the checks for the exported functions are not needed anymore, except for checking that the value can be cast to a function pointer. At that point using special functions for hook plugins would just mean adding a few entries to the list of "must contain function pointer" keys.
As stated above, it seems I missed part of the code. However, there are definitely more checks that could be done. For example, you could declare the same plugin in |
Continued in #4521 |
This is a summary of open questions from the
new-backend
branch:modules
vsglobal
Should we merge the
KeySet * modules
andKeySet * global
withinstruct _KDB
?They already use separate hierarchies, so there should be no overlap.
elektraModulesInit
errorWouldn't it be better, if
elektraModulesInit
set an error directly, instead of letting the calling function define the error?libelektra/src/libs/elektra/kdb.c
Lines 364 to 383 in 5f0895b
bootstrap resolver
The bootstrap backend which contains
system:/elektra
is currently loaded with default resolver and storage plugin. These could be overridden after installation by changing symlinks.IMO we should at least create separate CMake based
#define
s forKDB_BOOTSTRAP_STORAGE
andKDB_BOOTSTRAP_RESOLVER
. We could also go one step further and hard-code the absolute path of the bootstrap storage file (via a CMake variable).The goal here is to reduce the "moving parts" of the bootstrap sequence, because if the bootstrap works Elektra is essentially unusable and you need to manually correct/reset files.
Once that is done, we should probably go a step further. Instead of just defining
KDB_BOOTSTRAP_STORAGE
andKDB_BOOTSTRAP_RESOLVER
, we should define the actual backend plugin used asKDB_BOOTSTRAP_BACKEND
. We we'd either have to specify the config for the plugin as well, or IMO even better would be, if the plugin doesn't have a config. All it's dependencies are defined at compile-time and it just does its thing.The CMake defines for
KDB_DEFAULT_*
are always the same AFAIK and we use symlinks to change the defaults. We can keep that and get rid of the CMake defines, or we can use a fully compile-time defined setup and prohibit symlinks. Either way,I think bootstrap and default backend should be separate.What do you think?
split
resolver
Should we split the
resolver
into the actual resolving parts and the parts needed for atomic/safe read-write?The atomic read-write parts would form a separate library that could also be used in other parts of Elektra, or by other resolver implementations.
errnosave
Some of the
kdb*
functions attempt to save and restoreerrno
. Is this really needed?initialParent
inkdbGet
/kdbSet
Do we need the
initialParent
copy ofparentKey
inkdbGet
/kdbSet
?kdbGet
merge/split (step 12/15)In the current
kdbGet
implementation, the data from all backends is merged in step 12 and then split again in step 15. That is after the mainstorage
phase, and thepoststorage
phase ofspec:/
backends were executed, we merge all backends so that we can executegopts
andspec
. Then we need to split everything up again for thepoststorage
phase of non-spec:/
backends.Do we really need to do this?
The answer here is probably that we really need these merge/split steps. But it is a kinda annoying thing and probably expensive (haven't tested it, but doing lots of iteration, comparing of key names and
ksAppendKey
, is always kinda expensive).KeySet * global
as argument toelektraPluginOpen
Is there a good reason, why
elektraPluginOpen
doesn't take theglobal
keyset as an argument?Currently after every
elektraPluginOpen
call inlibelektra-kdb
we need to do aplugin->global = kdb->global
.backend
absolute path read-writeThe
backend
plugin currently supports read-only access to an absolute path without any resolver being defined. Should we also support writing to such files?This would require extracting the atomic/safe read-write code from
resolver
into a library.kdb file /foo
Should
kdb file
work with cascading keys?IMO there is no reason why this should be supported, but there is currently no check against it.
The only use case I can think of is, if you want to know what file a certain key will come from when an application reads it. But for that a separate
kdb lookup /foo
that returns e.g.user:/foo
would make more sense.specific functions for hooks/global plugins
Every "global plugins" should fulfil certain functionality specific to is hook (which is why I'll call them hook plugins here).
IMO instead of reusing the
get
/set
/etc. functions, these hook plugins should export extra functions for the hooks points at which they are called. Forspec
this could be:Then it would be clear, when a plugin can only be used as a hook plugin and when it is dual purpose. For example, since
dbus
can run globally or just for a single mountpoint, it would exportget
/set
functions and the specific hooks for notification plugins.How will
spec
work?For
spec
to work properly, this conditions must be fulfilled:kdbGet
meta:/default/
onspec:/[name]
todefault:/[name]
spec:/[name]
to all other namespaces (in particularproc:/
,dir:/
,user:/
,system:/
anddefault:/
)kdbSet
beforeprestorage
(i.e. before validation/conversion happens):kdbGet
kdbSet
afterprestorage
, but beforestorage
(i.e. after validation/conversion happens, but before data is serialised):meta:/
keys from all namespace other thanspec:/
(strictly speaking onlydir:/
,user:/
,system:/
, must be handled, as nothing else is persisted)1.i. and 1.ii. are pretty simple and are already done (apart from proper handling of wildcards, but that's another story #3954). Therefore 2.i. is also pretty simple, as long as
spec
is called properly (still open, but not an issue).3.i. however is pretty complex. We need to reliably detect, whether or not a metakey has changed. One approach to this would be relying on pointer/address equality. We already share metakeys between
spec:/
and non-spec:/
keys to save memory. We could simply remove allmeta:/
keys whose address is the same as the one onspec:/
. First of all this requires a Copy-On-Write enforcement formeta:/
keys, but that's something we want anyways (#3610). However, this leaves one open edge case. What ifmeta:/foo
onspec:/[name]
was removed? Then we have no way of knowing, whethermeta:/foo
on e.g.user:/[name]
was added by thespec
plugin or by the user. A way around that would be to keep an additional copy of allmeta:/
keys inside thespec
plugin. Then we always know whichKey *
to delete. But that is a bit of a memory waste, because there is a better solution.We could simply introduce a
metadefault:/
namespace (Note: thedefault:/
namespace might be reused, if we implement #3598). Whenever youksLookup
ameta:/
key, we not only check formeta:/
but also formetadefault:/
keys. Thespec
plugin would only addmetadefault:/
keys and wouldn't have to do anything, since evenlibelektra-kdb
itself could remove those before thestorage
phase inkdbSet
(similar todefault:/
andproc:/
).Performance questions
backendsFindParent
backendsFindParent
does a lookup and removes the basename repeatedly until a backend is found. Could this be a performance bottleneck? Is there a better way to do this?My purely theoretical analysis is that it should be fine: With
m
= number of parts in key &n
= size of backends the new runtime should be aroundO(m)
, if theKeySet
with the backends uses the hashmap andO(m*log(n))
otherwise. The old trie solution wasO(k)
wherek
is the length of the keyname we are looking for. The expectation is thatk
is bigger thanm*log(n)
in most cases, sincelog(n)
will be generally small andm
is necessarily smaller thank
(generallym
is much smaller thank
, since even an average name part size of 2 would meank = 2*m
).KDB phase passed as integer
Currently, we pass the phase a backend should execute from
libelektra-kdb
to a backend plugin as a string ("prestorage"
,"storage"
, etc.). Should we switch this to an integer?Using an integer would allow using an
enum
to define the constants and also using aswitch
statement (instead of repeatedif(strcmp() == 0)
in the plugin).Note: the integer must be passed as a binary key, otherwise we'd just pay for int->string->int conversion instead of
strcmp
.The text was updated successfully, but these errors were encountered: