Skip to content
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

[WIP] Context API #99

Closed
wants to merge 37 commits into from
Closed

[WIP] Context API #99

wants to merge 37 commits into from

Conversation

satac2
Copy link
Contributor

@satac2 satac2 commented Jun 8, 2020

If you could take a look at the class declarations and see if I am on the right track for the context api, that would be great, thanks.

@linux-foundation-easycla
Copy link

linux-foundation-easycla bot commented Jun 8, 2020

CLA Check
The committers are authorized under a signed CLA.

/* Context: contructor, creates a context object from a map
* of keys and identifiers
*/
Context(std::map<std::string, int> ctx);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All the public APIs need to be ABI compatible - which means they are not supposed to expose dependency on STL traits/layout.

@reyang reyang changed the title Context api [WIP] @reyang [WIP] Context API Jun 8, 2020
@reyang
Copy link
Member

reyang commented Jun 8, 2020

Welcome to your first PR @satac2, please clear the CLA steps as required by the CI / CNCF.


context_id_mutex.lock();

Context::last_key_identifier_++;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of maintaining a counter and introducing a contention, consider using the address of the underlying object to uniquely identify the key.

Context(std::map<int,int> ctx_map){
ctx_map_ = ctx_map;
}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need to format the code.

/* Contructor, creates a context object from a map
* of keys and identifiers
*/
Context(ContextKey key, int value){
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This ctor would only take 1 key-value pair?

/* Accepts a new key/value pair and then returns a new
* context that contains both the original pairs and the new pair.
*/
Context WriteValue(ContextKey key, int value){
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess the value should a nostd::variant type instead of an int?

}

/* A constructor that will set the context as the passed in context. */
RuntimeContext(Context &context){
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

According to the spec these will be global/static function so no ctor needed here?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My current thinking:

  • Provide RuntimeContext as an interface, providing static methods for Attach/Detach/GetCurrent.
  • Implement ThreadLocalContext, providing biding for TLS (thread local storage).
  • By default the static methods from RuntimeContext will use ThreadLocalContext, and there is a way for the user to implement/specify their own context binding.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm a little confused what you mean by this, should the ThreadLocalContext be a derived class of RuntimeContext?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm a little confused what you mean by this, should the ThreadLocalContext be a derived class of RuntimeContext?

Yes.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How would it be different than RuntimeContext, should the RuntimeContext just have a static context and the ThreadLocal have a static thread_local context?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think RuntimeContext is the abstraction layer (which doesn't have understanding about TLS).

/* Constructs a new ContextKey with the passed in name and
* identifier.
*/
ContextKey(std::string key_name, int identifier){
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't use std::string , only nostd::string_view in API

/* Consructs a new ContextKey with the passed in name and increments
* the identifier then assigns it to be the key's identifier.
*/
ContextKey(std::string key_name){
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use nostd::string_view

* user to the context map. The identifier is used as a key
* to the context map.
*/
class ContextKey{
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd suggest to use this class as a foundation for key-value iterable:
https://github.com/open-telemetry/opentelemetry-cpp/blob/master/api/include/opentelemetry/trace/key_value_iterable.h

You can entirely avoid using std::map in API. We do not require std::map


private:

static thread_local Context context_;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not 100% sure this static would always work in certain DLL loading scenarios, where two different DLLs consume OT API surface, esp. lazy loading / delay-loading. May want to spell out the limitations somewhere in the class documentation..

https://devblogs.microsoft.com/oldnewthing/20101122-00/?p=12233

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed. Rather use this singleton style (adding thread_local). That's what we use here.


std::mutex context_id_mutex;

/*The context class provides a context identifier */
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use // style comments and add a full stop. :)

/* Consructs a new ContextKey with the passed in name and increments
* the identifier then assigns it to be the key's identifier.
*/
ContextKey(std::string key_name){
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please mark this constructor explicit.

cc_test(
name = "runtimeContext_test",
srcs = [
"runtimeContext_test.cc",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use lowercase + underscores, i.e. runtime_context_test (also on L15) to be consistent with the rest of the files.

srcs = [
"runtimeContext_test.cc",
],
copts = ["-Wall","-std=c++17"],
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please remove these copts.

@g-easy
Copy link
Contributor

g-easy commented Jun 11, 2020

More general context questions:

  1. Should the actual TLS part be a pointer, and allocate the per-thread context when it's accessed by Attach/GetCurrent?

  2. However we end up resolving the std::map question: how can we attach/detach faster than doing a full copy of the map?

@reyang
Copy link
Member

reyang commented Jun 11, 2020

  1. However we end up resolving the std::map question: how can we attach/detach faster than doing a full copy of the map?

https://www.python.org/dev/peps/pep-0550/#implementation 😄

@g-easy
Copy link
Contributor

g-easy commented Jun 11, 2020

And refcount the context objects that form chains?

@g-easy
Copy link
Contributor

g-easy commented Jun 12, 2020

Can we have a no-op Context API and move the implementation into the SDK, so that other SDKs can make different performance tradeoffs in how this is implemented?

@reyang
Copy link
Member

reyang commented Jun 12, 2020

Can we have a no-op Context API and move the implementation into the SDK, so that other SDKs can make different performance trade-offs in how this is implemented?

Probably not, the OpenTelemetry API package has to give a default implementation that flows the incoming traceid/spanid/tracestate/flags to the outgoing request, thus the actual implementation cannot be in the SDK.
However we need to make sure that other SDKs / components can replace the context implementation.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants