-
Notifications
You must be signed in to change notification settings - Fork 440
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
Runtime and threadlocal context #209
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would it make sense to have a dtor for Token which calls Detach?
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.
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.
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.
Added.
…pentelemetry-cpp into runtime_and_threadlocal_context
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.
LGTM.
{ | ||
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
*now
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 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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are we good to merge then?
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.
#219 created for tracking.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's make those methods pure virtual. Then the comment is not needed.
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.
Changed to pure virtual.
~Stack() { delete[] base_; } | ||
|
||
int size_; | ||
int capacity_; |
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.
Those should be size_t
.
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.
Changed to size_t.
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 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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please mark all methods as noexcept
.
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.
Marked as noexcept.
|
||
private: | ||
// A nested class to store the attached contexts in a stack. | ||
class Stack |
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.
Let's mark all Stack
methods as noexcept
. Top
can be const
too.
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.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please use a member initializer list 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.
Switched to initializer list.
Context context_; | ||
|
||
// Returns the stored context object. | ||
Context GetContext() { return context_; } |
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.
This method isn't used anywhere. What would it be needed for?
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 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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please use a member initializer list for that.
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.
Changed to initializer list.
for (auto i = 0; i <= old_size; i++) | ||
{ | ||
temp[i] = base_[i]; | ||
} |
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 you can use std::copy(base_, base_ + old_size, temp);
instead of the loop.
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.
Changed.
This is an implementation of the RuntimeContext and ThreadLocalContext which is used to provide access to a context object globally. @reyang