From 10e025e56021442bfbda8ae0df542bbf53acf471 Mon Sep 17 00:00:00 2001 From: Daniel Griesser Date: Wed, 18 Mar 2026 15:56:18 +0100 Subject: [PATCH] perf: use shallow dup instead of deep_dup for Scope and BreadcrumbBuffer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ⚠️ Needs closer review — changes copy semantics for scope containers. Replace deep_dup with dup for Scope's contexts, extra, tags, user, and fingerprint hashes, and for BreadcrumbBuffer's buffer array. Rationale: These containers are not mutated in-place after duplication. Scope methods like set_tags, set_extras, set_user all use assignment (replacing the entire hash) or merge! on the copy's own hash. The inner values (strings, numbers, symbols) are immutable or treated as such. BreadcrumbBuffer: Individual Breadcrumb objects in the buffer are not mutated after being recorded — they are only read during serialization. A shallow dup of the buffer array is sufficient to prevent the copy from seeing new breadcrumbs added to the original. span, session, and propagation_context still use deep_dup as they contain mutable nested state that may be modified in-place. --- sentry-ruby/lib/sentry/breadcrumb_buffer.rb | 2 +- sentry-ruby/lib/sentry/scope.rb | 12 +++++++----- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/sentry-ruby/lib/sentry/breadcrumb_buffer.rb b/sentry-ruby/lib/sentry/breadcrumb_buffer.rb index 3a5cc0177..6dfd79984 100644 --- a/sentry-ruby/lib/sentry/breadcrumb_buffer.rb +++ b/sentry-ruby/lib/sentry/breadcrumb_buffer.rb @@ -57,7 +57,7 @@ def to_h # @return [BreadcrumbBuffer] def dup copy = super - copy.buffer = buffer.deep_dup + copy.buffer = buffer.dup copy end end diff --git a/sentry-ruby/lib/sentry/scope.rb b/sentry-ruby/lib/sentry/scope.rb index 0f28fca37..96ce36edf 100644 --- a/sentry-ruby/lib/sentry/scope.rb +++ b/sentry-ruby/lib/sentry/scope.rb @@ -124,13 +124,15 @@ def clear_breadcrumbs def dup copy = super copy.breadcrumbs = breadcrumbs.dup - copy.contexts = contexts.deep_dup - copy.extra = extra.deep_dup - copy.tags = tags.deep_dup - copy.user = user.deep_dup + # Shallow dup is sufficient for these containers — inner values are not + # mutated after scope duplication, only replaced via merge! or assignment + copy.contexts = contexts.dup + copy.extra = extra.dup + copy.tags = tags.dup + copy.user = user.dup copy.transaction_name = transaction_name.dup copy.transaction_source = transaction_source.dup - copy.fingerprint = fingerprint.deep_dup + copy.fingerprint = fingerprint.dup copy.span = span.deep_dup copy.session = session.deep_dup copy.propagation_context = propagation_context.deep_dup