Skip to content

Commit 06eb4a1

Browse files
committed
perf: Optimize cloning of Context since it is immutable
1 parent 2971467 commit 06eb4a1

File tree

2 files changed

+83
-33
lines changed

2 files changed

+83
-33
lines changed

opentelemetry/src/context.rs

+72-28
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,11 @@ thread_local! {
9292
/// ```
9393
#[derive(Clone, Default)]
9494
pub struct Context {
95+
pub(super) inner: Option<Arc<InnerContext>>,
96+
}
97+
98+
#[derive(Clone, Default)]
99+
pub(super) struct InnerContext {
95100
#[cfg(feature = "trace")]
96101
pub(crate) span: Option<Arc<SynchronizedSpan>>,
97102
entries: Option<Arc<EntryMap>>,
@@ -196,7 +201,9 @@ impl Context {
196201
/// assert_eq!(cx.get::<MyUser>(), None);
197202
/// ```
198203
pub fn get<T: 'static>(&self) -> Option<&T> {
199-
self.entries
204+
self.inner
205+
.as_ref()?
206+
.entries
200207
.as_ref()?
201208
.get(&TypeId::of::<T>())?
202209
.downcast_ref()
@@ -230,20 +237,28 @@ impl Context {
230237
/// assert_eq!(cx_with_a_and_b.get::<ValueB>(), Some(&ValueB(42)));
231238
/// ```
232239
pub fn with_value<T: 'static + Send + Sync>(&self, value: T) -> Self {
233-
let entries = if let Some(current_entries) = &self.entries {
234-
let mut inner_entries = (**current_entries).clone();
235-
inner_entries.insert(TypeId::of::<T>(), Arc::new(value));
236-
Some(Arc::new(inner_entries))
240+
let (span, mut entries, suppress_telemetry) = if let Some(inner) = &self.inner {
241+
#[cfg(feature = "trace")]
242+
let span = inner.span.clone();
243+
#[cfg(not(feature = "trace"))]
244+
let span: Option<()> = None;
245+
246+
if let Some(entries) = &inner.entries {
247+
(span, (**entries).clone(), inner.suppress_telemetry)
248+
} else {
249+
(span, EntryMap::default(), inner.suppress_telemetry)
250+
}
237251
} else {
238-
let mut entries = EntryMap::default();
239-
entries.insert(TypeId::of::<T>(), Arc::new(value));
240-
Some(Arc::new(entries))
252+
(None, EntryMap::default(), false)
241253
};
254+
entries.insert(TypeId::of::<T>(), Arc::new(value));
242255
Context {
243-
entries,
244-
#[cfg(feature = "trace")]
245-
span: self.span.clone(),
246-
suppress_telemetry: self.suppress_telemetry,
256+
inner: Some(Arc::new(InnerContext {
257+
#[cfg(feature = "trace")]
258+
span,
259+
entries: Some(Arc::new(entries)),
260+
suppress_telemetry,
261+
})),
247262
}
248263
}
249264

@@ -333,16 +348,37 @@ impl Context {
333348
/// Returns whether telemetry is suppressed in this context.
334349
#[inline]
335350
pub fn is_telemetry_suppressed(&self) -> bool {
336-
self.suppress_telemetry
351+
if let Some(inner) = &self.inner {
352+
inner.suppress_telemetry
353+
} else {
354+
false
355+
}
337356
}
338357

339358
/// Returns a new context with telemetry suppression enabled.
340359
pub fn with_telemetry_suppressed(&self) -> Self {
341-
Context {
342-
entries: self.entries.clone(),
360+
if self.is_telemetry_suppressed() {
361+
return self.clone();
362+
}
363+
let (span, entries) = if let Some(inner) = &self.inner {
343364
#[cfg(feature = "trace")]
344-
span: self.span.clone(),
345-
suppress_telemetry: true,
365+
{
366+
(inner.span.clone(), inner.entries.clone())
367+
}
368+
#[cfg(not(feature = "trace"))]
369+
{
370+
(Option::<()>::None, inner.entries.clone())
371+
}
372+
} else {
373+
(None, None)
374+
};
375+
Context {
376+
inner: Some(Arc::new(InnerContext {
377+
#[cfg(feature = "trace")]
378+
span,
379+
entries,
380+
suppress_telemetry: true,
381+
})),
346382
}
347383
}
348384

@@ -408,30 +444,38 @@ impl Context {
408444

409445
#[cfg(feature = "trace")]
410446
pub(crate) fn current_with_synchronized_span(value: SynchronizedSpan) -> Self {
411-
Self::map_current(|cx| Context {
412-
span: Some(Arc::new(value)),
413-
entries: cx.entries.clone(),
414-
suppress_telemetry: cx.suppress_telemetry,
415-
})
447+
Self::map_current(|cx| cx.with_synchronized_span(value))
416448
}
417449

418450
#[cfg(feature = "trace")]
419451
pub(crate) fn with_synchronized_span(&self, value: SynchronizedSpan) -> Self {
452+
let (entries, suppress_telemetry) = if let Some(inner) = &self.inner {
453+
(inner.entries.clone(), inner.suppress_telemetry)
454+
} else {
455+
(None, false)
456+
};
420457
Context {
421-
span: Some(Arc::new(value)),
422-
entries: self.entries.clone(),
423-
suppress_telemetry: self.suppress_telemetry,
458+
inner: Some(Arc::new(InnerContext {
459+
span: Some(Arc::new(value)),
460+
entries,
461+
suppress_telemetry,
462+
})),
424463
}
425464
}
426465
}
427466

428467
impl fmt::Debug for Context {
429468
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
430469
let mut dbg = f.debug_struct("Context");
431-
let mut entries = self.entries.as_ref().map_or(0, |e| e.len());
470+
let (mut entries, suppress_telemetry) = self.inner.as_ref().map_or((0, false), |inner| {
471+
(
472+
inner.entries.as_ref().map_or(0, |e| e.len()),
473+
inner.suppress_telemetry,
474+
)
475+
});
432476
#[cfg(feature = "trace")]
433477
{
434-
if let Some(span) = &self.span {
478+
if let Some(span) = self.inner.as_ref().and_then(|inner| inner.span.as_ref()) {
435479
dbg.field("span", &span.span_context());
436480
entries += 1;
437481
} else {
@@ -440,7 +484,7 @@ impl fmt::Debug for Context {
440484
}
441485

442486
dbg.field("entries count", &entries)
443-
.field("suppress_telemetry", &self.suppress_telemetry)
487+
.field("suppress_telemetry", &suppress_telemetry)
444488
.finish()
445489
}
446490
}

opentelemetry/src/trace/context.rs

+11-5
Original file line numberDiff line numberDiff line change
@@ -284,15 +284,21 @@ impl TraceContextExt for Context {
284284
}
285285

286286
fn span(&self) -> SpanRef<'_> {
287-
if let Some(span) = self.span.as_ref() {
288-
SpanRef(span)
289-
} else {
290-
SpanRef(&NOOP_SPAN)
287+
if let Some(inner) = self.inner.as_ref() {
288+
if let Some(span) = inner.span.as_ref() {
289+
return SpanRef(span);
290+
}
291291
}
292+
293+
SpanRef(&NOOP_SPAN)
292294
}
293295

294296
fn has_active_span(&self) -> bool {
295-
self.span.is_some()
297+
if let Some(inner) = self.inner.as_ref() {
298+
inner.span.is_some()
299+
} else {
300+
false
301+
}
296302
}
297303

298304
fn with_remote_span_context(&self, span_context: crate::trace::SpanContext) -> Self {

0 commit comments

Comments
 (0)