fix #514, call_data_callbacks after shared the data#548
fix #514, call_data_callbacks after shared the data#548
Conversation
benoitmartin88
left a comment
There was a problem hiding this comment.
Great feature to add. Thanks !
Not much is needed to merge this PR.
I think this feature would require a unit test. Could you add this?
656e28b to
3e1d45f
Compare
benoitmartin88
left a comment
There was a problem hiding this comment.
Almost ready to merge.
I do have a few questions that need answering concerning error handling, potentially superfluous functions and writing tests in C++.
f542e39 to
6806742
Compare
benoitmartin88
left a comment
There was a problem hiding this comment.
I think this is almost ready to merge.
Could you make sure the indent and spacing of the modified files is correct ?
Thanks !
Is it normal that the action indent doesn't catch that? |
|
@jbigot Could you review this PR please? |
jbigot
left a comment
There was a problem hiding this comment.
This is a great submission! My main comment is about moving Var_to_reclaim of the provider side instead of expecting each user to implement it. Overall this is really nice though!
|
What's the status for this one? |
It is ready to review. |
|
@Yushan-Wang , @benoitmartin88 , @JAuriac : I'd like a cross review first and then I'll do one. Who has time for one? |
|
Je regarde. |
benoitmartin88
left a comment
There was a problem hiding this comment.
Thank you for this contribution. There are a few changes that are required.
0dee087 to
4656252
Compare
4656252 to
352441e
Compare
| #include <pdi/datatype_template.h> | ||
| #include <pdi/ref_any.h> | ||
|
|
||
| // #include "global_context.h" |
There was a problem hiding this comment.
I will be remove in the next commit
| // #include "global_context.h" | ||
|
|
There was a problem hiding this comment.
| // #include "global_context.h" |
| * \param[in,out] data the shared data | ||
| * \param read whether read access is granted to other references | ||
| * \param write whether write access is granted to other references | ||
| * \param delayed_callbacks a class that allow to delay trigger_delayed_data_callbacks for a list of a data |
There was a problem hiding this comment.
| * \param delayed_callbacks a class that allow to delay trigger_delayed_data_callbacks for a list of a data | |
| * \param delayed_callbacks a list of callbacks where the callback for this data will be added, instead of being triggered. So that one can delay the trigger |
| * \param[in,out] ref a reference to the shared data | ||
| * \param read whether the stored reference should have read access | ||
| * \param write whether the stored reference should have write access | ||
| * \param delayed_callbacks a class that allow to delay trigger_delayed_data_callbacks for a list of a data |
There was a problem hiding this comment.
| * \param delayed_callbacks a class that allow to delay trigger_delayed_data_callbacks for a list of a data | |
| * \param delayed_callbacks a list of callbacks where the callback for this data will be added, instead of being triggered. So that one can delay the trigger |
|
|
||
| /** function to call "data_callbacks" for the shared data. | ||
| */ | ||
| virtual void trigger_delayed_data_callbacks() = 0; |
There was a problem hiding this comment.
We need that because m_context[element_name.c_str()] is a data_descriptor in Delayed_data_callbacks
Do you want to remove trigger_delayed_data_callbacks() in the class data_descriptor_impl and put this function inside class PDI_EXPORT Delayed_data_callbacks?
I want to keep this function inside data_descriptor_impl because I don't want to change m_refs outside this class
/// References to the values of this descriptor
std::stack<std::unique_ptr<Ref_holder>> m_refs;|
|
||
| class PDI_EXPORT Delayed_data_callbacks | ||
| { | ||
| /// friend class Global_context; |
| m_context.logger().error("Error in the destructor of Delayed_data_callbacks, {}", e.what()); | ||
| } else { | ||
| // No exception is throwing. Throw an error. | ||
| m_context.logger().error("Error in the destructor of Delayed_data_callbacks."); |
There was a problem hiding this comment.
since you rethrow. I wouldn't print anything in that case:
| m_context.logger().error("Error in the destructor of Delayed_data_callbacks."); |
| m_context.logger().error("Error in the destructor of Delayed_data_callbacks."); | ||
| } else { | ||
| // No exception is throwing. Throw an error. | ||
| m_context.logger().error("Error in the destructor of Delayed_data_callbacks."); |
There was a problem hiding this comment.
same as above
| m_context.logger().error("Error in the destructor of Delayed_data_callbacks."); |
| // (example: error in the config.yml for a plugin, error due to external library incompatibility) | ||
| ~Delayed_data_callbacks() noexcept(false) | ||
| { | ||
| try { |
There was a problem hiding this comment.
why not move the try one step up?
| void trigger() | ||
| try { | ||
| int i = 0; | ||
| size_t number_of_elements = m_datanames.size(); | ||
| for (auto&& element_name: m_datanames) { | ||
| m_context.logger().trace("Trigger data callback `{}' ({}/{})", element_name.c_str(), ++i, number_of_elements); | ||
| m_context[element_name.c_str()].trigger_delayed_data_callbacks(); | ||
| } | ||
| this->cancel(); // clear the m_datanames | ||
| } catch (Error& e) { | ||
| this->cancel(); // clear the m_datanames | ||
| throw Error(e.status(), "Error in trigger data callback: `{}'", e.what()); | ||
| } catch (...) { | ||
| this->cancel(); // clear the m_datanames | ||
| throw; | ||
| } |
There was a problem hiding this comment.
When an exception is thrown, we'd like the events not yet triggered to remain in the list of events to trigger.
| void trigger() | |
| try { | |
| int i = 0; | |
| size_t number_of_elements = m_datanames.size(); | |
| for (auto&& element_name: m_datanames) { | |
| m_context.logger().trace("Trigger data callback `{}' ({}/{})", element_name.c_str(), ++i, number_of_elements); | |
| m_context[element_name.c_str()].trigger_delayed_data_callbacks(); | |
| } | |
| this->cancel(); // clear the m_datanames | |
| } catch (Error& e) { | |
| this->cancel(); // clear the m_datanames | |
| throw Error(e.status(), "Error in trigger data callback: `{}'", e.what()); | |
| } catch (...) { | |
| this->cancel(); // clear the m_datanames | |
| throw; | |
| } | |
| void trigger() | |
| { | |
| int i = 0; | |
| size_t number_of_elements = m_datanames.size(); | |
| while ( ! m_datanames.empty() ) { | |
| auto&& element_name = m_datanames.back(); | |
| m_context.logger().trace("Trigger data callback `{}' ({}/{})", element_name, ++i, number_of_elements); | |
| m_context[element_name].trigger_delayed_data_callbacks(); | |
| m_datanames.pop_back() | |
| } | |
| } |
|
|
||
| /** A structure to reclaim the datas properly in case of error | ||
| */ | ||
| struct Var_to_reclaim { |
There was a problem hiding this comment.
Why is this class still required? Isn't Delayed_data_callbacks enough?
There was a problem hiding this comment.
These two classes are defined with the same list of dataname in some sense.
(It depends only if we have an error after delayed_callbacks.add_dataname(m_name);
in void* Data_descriptor_impl::share) -> good catch.
Remark:
In PDI_share, the destruction of the object Delayed_data_callbacks execute event on_data in this implementation.
The class Var_to_reclaim is used to call PDI_reclaim the data in PDI_multi_expose.
So if we want to have only 1 class:
- need to rename the class
Delayed_data_callbacks-> name ??? - add a member to this class to know if we are in the multi_expose case to have two version of destructor:
- dtor1 : call trigger()
- dtor2: call trigger() + reclaim the variables.
- Perhaps add a member to this class to know if we call trigger() before.
- don't remove element in the list of the dataname in trigger()
Is it what you want to implement? we can discuss if you want.
!!!INSERT YOUR DESCRIPTION HERE!!!
List of things to check before making a PR
Before merging your code, please check the following:
.clang-format;Fix #issuekeyword to autoclose the issue when merged.