Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Core] Making aplications deregistrable V3 #12306
[Core] Making aplications deregistrable V3 #12306
Changes from 2 commits
4d4ed88
fac137a
a9a29d3
9694b6a
ecd6e0b
c609e2c
117b3bf
8d77e96
21aae0f
02df3ac
b637f0d
0fc4296
79f8840
aaaacdb
6b7fbe9
701be9b
File filter
Filter by extension
Conversations
Jump to
There are no files selected for viewing
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am not sure if this is a correct behavior. We don't want to have different geometries, elements and conditions with the same names in different applications.
And we don't want to deregister an entity if is created by someone else before us.
So I would check if the name exists in that typeof branch and Add an item to the
[Registry::GetCurrentSource()].deregister_list.name
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agree, but this is currently how components are added ( as a matter of fact, you can have several components from the same app or different applications with the same name as long as the types are different ):
Nevertheless it is true that this could cause a registered component to be unloaded by an incorrect app. Just to confirm that we want to avoid this case:
I will change it to keep track of this case
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We are in the same page!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe I am misunderstanding something, but
I think that what you need here is something that behaves like a counted pointer, not keeping track of who registered what.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, because the implementation of
KratosComponents
is misleading.If two applications want to add a component with the same name, provided that all checks pass, this will be executed:
Which will insert the component if not present, but will do nothing the second time (
msComponents
is a map andinsert
only does something if the key is not existent). That implies that the moment we unload the application that has added the component, the component becomes invalid: 1 - because the reference is no longer correct, 2 - because the second app did nothing.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, but in this situation the second app is left in an invalid state. Essentially, once the first app is unloaded, anything else that shared a name with it is left in an incomplete state and cannot be trusted to work.
If this is the case, wouldn't it be simpler to just have an "unload everything" (or maybe "unload all applications, leaving core untouched") mechanism instead of keeping track of individual apps?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, the second app was never in a valid state, it was referencing something it does not own (our eternal discussion if a variable can be registered by two apps). I think we don't have any example in which only a single application is unloaded.
The implementation we wanted to replace (can be found isolated in #11511) actually does what you suggest (the kernel is in charge of clearing all the components) but @RiccardoRossi commented it had a very important flaw: It cannot deal with custom types. In fact #11506 would fail if we try to register a preconditioned for example, as it is a component unknown by the kernel.
This cannot be done (and basically is the root of why I want to use tests to change the current behavior) because creating an instance of the kernel automatically tries to register the "KratosMultiphysics" app, and while the kernel class has a lifetime with initialization and destruction, the components are static and do not. Consider this code:
At
i=0
the first instance of the kernel is created, the we call:At
i=1
If code is left untouched (no deregisters, etc...) this will work, because even if the kernel was destroyed, the list applications loaded and the list of components was never cleared, which implies that applications, and components are "eternal", once registered there is no way back. In other worlds, if the kernel was a singleton it could never be destroyed even if you wanted to.Now consider now what happens with the new tests (for example, but a custom workflow from the GeoMechanics or anything that does not use Python as an entry point has the same problem)
The base test code defines the life cycle that will be executed per every test:
Now, for every app I will be able to derive this using:
Of course, I can
1 - Check if the application is already loaded and do nothing: Works without changing the current code. We use the same kernel across all tests, which is deeply wrong
2 - I unloaded the applications manually keeping the kernel: I have no way to instruct the applications to de-register custom component types and I don't know what was loaded by the kernel or by the apps
3 - I unloaded everything throw the kernel: Works, but as 2 I have no way to de-register custom components.
4 - Everyone keeps track of who is an what has registered and is in charge or de-register: No problems.
Honestly, any solution can work with we assume the consequences but for me 4 is by far the good solution.
That being said, the fact that two applications can register the same thing and the second does nothing without a warning is super dangerous and should be changed, but probably in a separate PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, understood. I just think that we need to be clear that this solves the testing use-case by delegating the cleaning-up of the components to the applications, but it does not make applications unloadable in any meaningful way. Or, in other words, I do not think this solution would work for any use case that does not use python as an entrypoint, but I agree that it works for this one.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Completely agree 👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For consistency, I would suggest to use "deregister" everywhere, rather than mixing it with "unregister".
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agree. It will be done like in #12281, just wanted to avoid having more changes than the necessary here as I got a lot of comments about renaming in the other PR
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am not sure someone will get what this means by the comment... :/
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is me or the spacing is inconsistent?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is consistent, the inconsistent one is the initializer which is indented at 10 chars to have it in the same column as
mApplicationName
. We could change it in a different PRThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we need this? I think, the registry will create all the parent keys if they are not present ryt? Is this done for consistency?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here, if we store the list of added items in the
[Registry::GetCurrentSource()].deregister_list
then we can only iterate over it and remove them from registry without even distinguishing the type.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We need the type to instantiate the proper KratosComponents template or I am missing something?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You are right! Still we need that for components
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
mCurrentSource
is a static data member of the class. These access functions don't seem to be thread-safe to me. Not sure how important that is here?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should be fine, registering an application should not be done in parallel and the registry itself relies on being static.
In this regard we may want to implement Registry as a singleton and have a thread lock in the setters/getters. Ping @pooyan-dadvand.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The registry has a thread safe double lock guarded implementation. For this one, I assume that the creation of applications is serial, but making it thread safe don't harm anyone
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thinking more about it, I think it would be better to first register the application in the registry and keep the entry as an static member of the application itself:
Then we can use this name everywhere using the
Application
base class member functionGetApplicationName
(you may find better names for them to be coherent also in the core)In the core we can use
KratosCore
orCore
as the name.Then we can add all items not only to their type but also as a reference under this branch (optional) and have a
deregistry_list
with all added items to be removed:With all of this in place, the deregistry function can be implemented in a generic way in the base class or as a utility
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I get the idea but I have a comment:
Essentially, this information is already available in https://github.com/KratosMultiphysics/Kratos/blob/master/kratos/includes/kratos_application.h#L155. The motivation for adding a
mCurrentSource
is to get access to this information outside the application context (for example, for registering preconditioners https://github.com/KratosMultiphysics/Kratos/blob/master/kratos/factories/standard_preconditioner_factory.cpp#L47-L50 )With that being said, what we can do is to store this "current application" inside the registry itself instead of being a static member. That will also solve the thread-safety concerns. Modifying a bit your proposal would be like:
And then the registering process would be like:
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Btw I remember that we agreed that registry keys should start with the component name and then the application name (
process.all.xxxx
,process.FluidDynamics.yyyyy
), so it should be: