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

Improve our SafeDup module #2960

Merged
merged 9 commits into from
Jul 14, 2023
Merged

Improve our SafeDup module #2960

merged 9 commits into from
Jul 14, 2023

Conversation

GustavoCaso
Copy link
Member

@GustavoCaso GustavoCaso commented Jul 12, 2023

What does this PR do?

When working on #2936 I noticed that calling SafeDup.frozen_or_dup({a: :b}) on ruby 3.2 would break; because it tries to call +(-){a: :b} which doesn't work.

I had to ensure the SafeDup module worked for all objects.

I decided to extract that work into a separate PR to ease the work of reviewing.

The method frozen_or_dup and frozen_dup for ruby 2.3 and forward only expect to receive String values. This could lead to future errors.
By checking if the value is a String, we can warranty the same behaviour for all kinds of objects

I extracted the refinements into the backport file under the BackportFrom24 namespace

Motivation

Additional Notes

Interesting read on the whole dup and clone debacle for ruby versions https://blog.arkency.com/2017/03/prototypes-in-ruby/

How to test the change?

@GustavoCaso GustavoCaso requested a review from a team July 12, 2023 10:09
I noticed that calling `SafeDup.frozen_or_dup({a: :b})` on ruby 3.2 would break;
because it tries to call `+(-){a: :b}` which doesn't work.

I had to ensure the `SafeDup` module worked for all objects.

I decided to extract that work into a separate PR to ease the work of reviewing.

The method `frozen_or_dup` and `frozen_dup` for ruby 2.3 and forward only expect to receive String values.
This could lead to future errors.
By checking if the value is a String we can warranty the same behaviour for all kinds of objects

Also, I added some extract refimients to be able to call `#dup` on `true, false, 1, 1.0` values.
@github-actions github-actions bot added the core Involves Datadog core libraries label Jul 12, 2023
@codecov-commenter
Copy link

Codecov Report

Merging #2960 (6eb1176) into master (4890f92) will increase coverage by 0.10%.
The diff coverage is 98.70%.

@@            Coverage Diff             @@
##           master    #2960      +/-   ##
==========================================
+ Coverage   97.96%   98.07%   +0.10%     
==========================================
  Files        1287     1301      +14     
  Lines       71025    71955     +930     
  Branches     3285     3308      +23     
==========================================
+ Hits        69581    70571     +990     
+ Misses       1444     1384      -60     
Impacted Files Coverage Δ
lib/datadog/appsec/contrib/devise/patcher.rb 69.56% <ø> (-2.44%) ⬇️
lib/datadog/core/utils/safe_dup.rb 81.39% <84.61%> (+2.44%) ⬆️
lib/datadog/tracing/contrib/opensearch/quantize.rb 94.44% <94.44%> (ø)
lib/datadog/tracing/contrib/opensearch/patcher.rb 96.92% <96.92%> (ø)
...datadog/tracing/contrib/opensearch/patcher_spec.rb 99.23% <99.23%> (ø)
lib/datadog/appsec/contrib/devise/event.rb 100.00% <100.00%> (ø)
...ec/contrib/devise/patcher/authenticatable_patch.rb 100.00% <100.00%> (+75.67%) ⬆️
...ib/devise/patcher/registration_controller_patch.rb 100.00% <100.00%> (+68.96%) ⬆️
lib/datadog/kit/appsec/events.rb 100.00% <100.00%> (ø)
lib/datadog/profiling/component.rb 97.67% <100.00%> (+0.11%) ⬆️
... and 14 more

... and 6 files with indirect coverage changes

📣 We’re building smart automated test selection to slash your CI/CD build times. Learn more

# - then it will dup it more efficiently with +v
v.frozen? ? v : +(-v)
case v
when String
Copy link
Member

Choose a reason for hiding this comment

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

Can you capture here why String is handled separately from other types?

Copy link
Member Author

Choose a reason for hiding this comment

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

Done f4429a6

Copy link
Member

Choose a reason for hiding this comment

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

Minor: Isn't case v .... when String ... else ... the same as if String === v ... else? (Same applies below as well)

end

def self.frozen_dup(v)
-v if v
case v
when String
Copy link
Member

Choose a reason for hiding this comment

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

Same here.

Copy link
Member Author

Choose a reason for hiding this comment

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

Done f4429a6

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.

Looks great to me! I think the main two things to look at are the module_function thing (rename or remove) and making sure the change in span operation is correct, otherwise the rest is all smaller suggestions and nitpicks :)

lib/datadog/core/backport.rb Outdated Show resolved Hide resolved
lib/datadog/core/backport.rb Outdated Show resolved Hide resolved
# - then it will dup it more efficiently with +v
v.frozen? ? v : +(-v)
case v
when String
Copy link
Member

Choose a reason for hiding this comment

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

Minor: Isn't case v .... when String ... else ... the same as if String === v ... else? (Same applies below as well)

lib/datadog/tracing/span_operation.rb Show resolved Hide resolved
sig/datadog/core/backport.rbs Outdated Show resolved Hide resolved
spec/datadog/core/utils/safe_dup_spec.rb Outdated Show resolved Hide resolved
spec/datadog/core/utils/safe_dup_spec.rb Outdated Show resolved Hide resolved
spec/datadog/core/utils/safe_dup_spec.rb Outdated Show resolved Hide resolved
# they are faster and chepaer on the memory side.
# Check the benchmark on
# https://github.com/DataDog/dd-trace-rb/pull/2704
if v === String
Copy link
Member

Choose a reason for hiding this comment

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

Ah wait, it's not the same thing between v === String and String === v as Class#=== checks for instances but not the way around:

[12] pry(main)> "foo" === String
=> false
[13] pry(main)> String === "foo"
=> true
[14] pry(main)> class MyString < String
[14] pry(main)* end  
=> nil
[15] pry(main)> String === MyString.new
=> true

Copy link
Member

Choose a reason for hiding this comment

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

Interestingly enough, since this code path is a fast path, the tests don't catch this error ;)

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 will use v.is_a?(String) is quite readable

@GustavoCaso GustavoCaso merged commit 090aa64 into master Jul 14, 2023
202 of 203 checks passed
@GustavoCaso GustavoCaso deleted the imporve-safe-dup-module branch July 14, 2023 07:23
@github-actions github-actions bot added this to the 1.13.0 milestone Jul 14, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
core Involves Datadog core libraries tracing
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants