Runtime and threadlocal context#209
Conversation
Co-authored-by: Reiley Yang <reyang@microsoft.com>
…emetry-cpp into context_api_dummy_methods
…emetry-cpp into context_api_dummy_methods
Context api actual methods
…d an overloaded comparison to context API
…d ContextConfig has been removed
Codecov Report
@@ Coverage Diff @@
## master #209 +/- ##
==========================================
+ Coverage 92.31% 92.34% +0.03%
==========================================
Files 102 102
Lines 3174 3188 +14
==========================================
+ Hits 2930 2944 +14
Misses 244 244
|
| class RuntimeContext | ||
| { | ||
| public: | ||
| class Token |
There was a problem hiding this comment.
Would it make sense to have a dtor for Token which calls Detach?
There was a problem hiding this comment.
That make sense, seems like it will add an element of safety so the context can't get stuck after a token has gone out of scope. I will add it.
…pentelemetry-cpp into runtime_and_threadlocal_context
| { | ||
| std::map<std::string, context::ContextValue> map_test = {{"test_key", (int64_t)123}}; | ||
| context::Context test_context = context::Context(map_test); | ||
| context::RuntimeContext::Token old_context = context::RuntimeContext::Attach(&test_context); |
There was a problem hiding this comment.
What is the memory management strategy when managing context? Will contexts always be stored on the stack?
I'm afraid we might run into issues when having contexts stored on the stack, while managing all the context state via raw pointers.
There was a problem hiding this comment.
Another thing I wonder about: whenever a new span is started, we have to set the current span. I think we can only do this by adding a new context. So we'll add a new context when a span is started and we end the context when the span is ended. The user though has the option to end a child span before a parent span. This shouldn't screw up our context stack. Maybe I'm also not completely understanding the workflow here, please correct me if I'm wrong.
There was a problem hiding this comment.
Perhaps RuntimeContext::Attach should take a context object instead of a ptr and that should prevent issues if the original context object goes out of scope.
There was a problem hiding this comment.
What is the memory management strategy when managing context? Will contexts always be stored on the stack?
I think the context object has to be always allocated on the heap. Context can be propagated between threads and threads can get killed by the underlying OS (which means the stack will be reclaimed and repurposed).
There was a problem hiding this comment.
The user though has the option to end a child span before a parent span. This shouldn't screw up our context stack.
That's a very interesting topic, @pyohannes what would you expect for the following scenario?
// current span = EMPTY
span("A") begin
// current span = A
span("B") begin
// current span = B
span("C") begin
// current span = C
span("B") end
// current span = ???
span("A") end
// current span = ???
span("C") end
// current span = ???There was a problem hiding this comment.
Changed to RuntimeContext accepting a Context object instead of Context* so we should not be ref counting it.
There was a problem hiding this comment.
I was originally thinking to unblock this PR first and then revisit
That's ok for me, as long as we keep track of open issues (memory management and asynchronous spans), preferably via GitHub issues.
There was a problem hiding this comment.
Are we good to merge then?
| virtual Token InternalAttach(Context *context) { return Token(); } | ||
|
|
||
| // Dummy method to be overriden by derived class implementation | ||
| virtual bool InternalDetach(Token &token) { return false; } |
There was a problem hiding this comment.
Let's make those methods pure virtual. Then the comment is not needed.
There was a problem hiding this comment.
Changed to pure virtual.
| ~Stack() { delete[] base_; } | ||
|
|
||
| int size_; | ||
| int capacity_; |
pyohannes
left a comment
There was a problem hiding this comment.
I have some smaller nits.
Can you please submit an issue regarding the support of asynchronous segments (parent segments that end before their children). It seems the memory issue is accounted for by having copies of Context on the stack.
|
|
||
| virtual Token InternalAttach(Context context) = 0; | ||
|
|
||
| virtual bool InternalDetach(Token &token) = 0; |
There was a problem hiding this comment.
Please mark all methods as noexcept.
|
|
||
| private: | ||
| // A nested class to store the attached contexts in a stack. | ||
| class Stack |
There was a problem hiding this comment.
Let's mark all Stack methods as noexcept. Top can be const too.
There was a problem hiding this comment.
Marked as noexcept and const.
|
|
||
| // A constructor that sets the token's Context object to the | ||
| // one that was passed in. | ||
| Token(Context context) { context_ = context; } |
There was a problem hiding this comment.
Please use a member initializer list here.
There was a problem hiding this comment.
Switched to initializer list.
| Context context_; | ||
|
|
||
| // Returns the stored context object. | ||
| Context GetContext() { return context_; } |
There was a problem hiding this comment.
This method isn't used anywhere. What would it be needed for?
There was a problem hiding this comment.
It was initially used to get the context for comparison, but now that the comparison operator compares directly with contexts it is unnecessary, I will remove it.
| class Token | ||
| { | ||
| public: | ||
| bool operator==(const Context &other) { return context_ == other; } |
There was a problem hiding this comment.
This makes it possible to compare a Token to a Context. I wonder if the argument should be of type Token?
There was a problem hiding this comment.
Yes, that was on purpose. There has not been a use case for token to token comparison.
| { | ||
| size_ = 0; | ||
| capacity_ = 0; | ||
| base_ = nullptr; |
There was a problem hiding this comment.
Please use a member initializer list for that.
There was a problem hiding this comment.
Changed to initializer list.
| for (auto i = 0; i <= old_size; i++) | ||
| { | ||
| temp[i] = base_[i]; | ||
| } |
There was a problem hiding this comment.
I think you can use std::copy(base_, base_ + old_size, temp); instead of the loop.
Update dependency rules_pkg to v1.1.0
This is an implementation of the RuntimeContext and ThreadLocalContext which is used to provide access to a context object globally. @reyang