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

Rename thread-local to fiber-local in concurrent context #1984

Merged
merged 3 commits into from
Apr 26, 2022

Conversation

marcotc
Copy link
Member

@marcotc marcotc commented Apr 21, 2022

Fixes #1979

Thread[] and Thread[]= are fiber-local attributes¹, not thread-local as we have described them in ddtrace.
But they are also thread-safe, given these attributes are retrieved from the "current thread's root fiber if not explicitly inside a Fiber". Effectively, Thread[] and Thread[]= are both thread-safe and fiber-safe, but fiber-safe is the most accurate way to describe them.

This PR does not change any behavior, only clarifies nomenclature around fiber- vs thread-local storage.

Also, this PR adds one test to ensure the fiber-local behavior explicitly, given all tests are centered around threads today.

One alternative to this PR is to move from using Thread[] to Thread#thread_variable_get, making the execution context thread-safe but not fiber-safe. I believe this is not in our best interest, given in a context where Fibers are utilized concurrent spans could be created and interwoven, creating unexpected span child-parent relationships. Keeping our contexts fiber-local avoids this issue but creating distinct execution contexts for each fiber.

@marcotc marcotc added the dev/refactor Involves refactoring existing components label Apr 21, 2022
@marcotc marcotc requested a review from a team April 21, 2022 23:14
@marcotc marcotc self-assigned this Apr 21, 2022
@codecov-commenter
Copy link

codecov-commenter commented Apr 21, 2022

Codecov Report

Merging #1984 (eae045d) into master (663aaa4) will increase coverage by 0.00%.
The diff coverage is 100.00%.

@@           Coverage Diff           @@
##           master    #1984   +/-   ##
=======================================
  Coverage   97.71%   97.71%           
=======================================
  Files        1004     1004           
  Lines       50628    50639   +11     
=======================================
+ Hits        49472    49483   +11     
  Misses       1156     1156           
Impacted Files Coverage Δ
lib/datadog/tracing/tracer.rb 97.36% <ø> (ø)
lib/datadog/tracing/context_provider.rb 95.23% <100.00%> (ø)
spec/datadog/tracing/context_provider_spec.rb 95.95% <100.00%> (+0.50%) ⬆️
spec/datadog/tracing/integration_spec.rb 96.98% <100.00%> (ø)

📣 Codecov can now indicate which changes are the most critical in Pull Requests. Learn more

Copy link
Member

@ivoanjo ivoanjo left a comment

Choose a reason for hiding this comment

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

Thanks for fixing this! LGTM 👍

# @see https://ruby-doc.org/core-3.1.2/Thread.html#method-i-5B-5D Thread attributes are fiber-local
class FiberLocalContext
# FiberLocalContext can be used as a tracer global reference to create
# a different {Datadog::Tracing::Context} for each fiber. In synchronous tracer, this
Copy link
Member

Choose a reason for hiding this comment

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

Minor: I'm curious about what we mean here by "synchronous tracer"...?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yeah, it reads kind of weird.

I rephrased it to actually document some information that would be useful when reading this class.

Comment on lines 47 to 49
# FiberLocalContext can be used as a tracer global reference to create
# a different {Datadog::Tracing::Context} for each fiber. In synchronous tracer, this
# is required to prevent multiple fivers sharing the same {Datadog::Tracing::Context}
Copy link
Member

Choose a reason for hiding this comment

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

Minor: We repeat the same docs for the class and the initializer. I suggest perhaps removing the extra copy on the constructor.

Copy link
Member Author

Choose a reason for hiding this comment

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

Removed duplication from initializer.

Comment on lines 126 to 135
context = fiber_local_context.local

Fiber.new do
expect { @fiber_context = fiber_local_context.local }
.to change { thread_contexts.size }.from(0).to(1)

expect(@fiber_context).to be_a Datadog::Tracing::Context
end.resume

expect(@fiber_context).to_not eq(context)
Copy link
Member

Choose a reason for hiding this comment

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

Minor: The instance variable use seems a bit weird to me, and I don't quite like that if somehow the fiber doesn't assign to @fiber_context, the expect(@fiber_context).to_not eq(context) will still pass (because it'll be nil).

So here's a tiny suggestion that I think covers both 😄:

Suggested change
context = fiber_local_context.local
Fiber.new do
expect { @fiber_context = fiber_local_context.local }
.to change { thread_contexts.size }.from(0).to(1)
expect(@fiber_context).to be_a Datadog::Tracing::Context
end.resume
expect(@fiber_context).to_not eq(context)
main_fiber_context = fiber_local_context.local
other_fiber_context = nil
Fiber.new do
expect { other_fiber_context = fiber_local_context.local }
.to change { thread_contexts.size }.from(0).to(1)
end.resume
expect(other_fiber_context).to be_a Datadog::Tracing::Context
expect(other_fiber_context).to_not eq(main_fiber_context)

Copy link
Member Author

Choose a reason for hiding this comment

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

Nice improvement! I applied it to both places. 🙇


Fiber.new do
expect { @fiber_context = fiber_local_context.local }
.to change { thread_contexts.size }.from(0).to(1)
Copy link
Member

Choose a reason for hiding this comment

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

Minor: Should thread_contexts be renamed as well?

Copy link
Member Author

Choose a reason for hiding this comment

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

I wasn't 100% sure if it would make sense to rename thread_contexts, given the values do come from threads, but they happen to match with the respective fibers.

I ended up renaming it now, take a look :)

@marcotc marcotc requested a review from ivoanjo April 25, 2022 23:08
Copy link
Member

@ivoanjo ivoanjo left a comment

Choose a reason for hiding this comment

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

👍 LGTM :shipit: 💯

@marcotc marcotc merged commit 855e5b9 into master Apr 26, 2022
@marcotc marcotc deleted the thread-to-fiber branch April 26, 2022 19:12
@github-actions github-actions bot added this to the 1.0.0.beta3 milestone Apr 26, 2022
@ioquatix
Copy link
Contributor

Great, thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
dev/refactor Involves refactoring existing components
Projects
None yet
Development

Successfully merging this pull request may close these issues.

ThreadLocalContext is actually Fiber local.
4 participants