Skip to content

Commit 9a9e5f6

Browse files
committed
perf: Optimize cloning of Context since it is immutable
1 parent 99cb67d commit 9a9e5f6

File tree

2 files changed

+94
-42
lines changed

2 files changed

+94
-42
lines changed

opentelemetry/src/context.rs

Lines changed: 83 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,11 @@ thread_local! {
9494
/// ```
9595
#[derive(Clone, Default)]
9696
pub struct Context {
97+
pub(super) inner: Option<Arc<InnerContext>>,
98+
}
99+
100+
#[derive(Clone, Default)]
101+
pub(super) struct InnerContext {
97102
#[cfg(feature = "trace")]
98103
pub(crate) span: Option<Arc<SynchronizedSpan>>,
99104
entries: Option<Arc<EntryMap>>,
@@ -198,7 +203,9 @@ impl Context {
198203
/// assert_eq!(cx.get::<MyUser>(), None);
199204
/// ```
200205
pub fn get<T: 'static>(&self) -> Option<&T> {
201-
self.entries
206+
self.inner
207+
.as_ref()?
208+
.entries
202209
.as_ref()?
203210
.get(&TypeId::of::<T>())?
204211
.downcast_ref()
@@ -232,20 +239,30 @@ impl Context {
232239
/// assert_eq!(cx_with_a_and_b.get::<ValueB>(), Some(&ValueB(42)));
233240
/// ```
234241
pub fn with_value<T: 'static + Send + Sync>(&self, value: T) -> Self {
235-
let entries = if let Some(current_entries) = &self.entries {
236-
let mut inner_entries = (**current_entries).clone();
237-
inner_entries.insert(TypeId::of::<T>(), Arc::new(value));
238-
Some(Arc::new(inner_entries))
242+
if let Some(inner) = &self.inner {
243+
let (mut entries, suppress_telemetry) = if let Some(entries) = &inner.entries {
244+
((**entries).clone(), inner.suppress_telemetry)
245+
} else {
246+
(EntryMap::default(), inner.suppress_telemetry)
247+
};
248+
entries.insert(TypeId::of::<T>(), Arc::new(value));
249+
Context {
250+
inner: Some(Arc::new(InnerContext {
251+
#[cfg(feature = "trace")]
252+
span: inner.span.clone(),
253+
entries: Some(Arc::new(entries)),
254+
suppress_telemetry,
255+
})),
256+
}
239257
} else {
240258
let mut entries = EntryMap::default();
241259
entries.insert(TypeId::of::<T>(), Arc::new(value));
242-
Some(Arc::new(entries))
243-
};
244-
Context {
245-
entries,
246-
#[cfg(feature = "trace")]
247-
span: self.span.clone(),
248-
suppress_telemetry: self.suppress_telemetry,
260+
Context {
261+
inner: Some(Arc::new(InnerContext {
262+
entries: Some(Arc::new(entries)),
263+
..Default::default()
264+
})),
265+
}
249266
}
250267
}
251268

@@ -335,16 +352,35 @@ impl Context {
335352
/// Returns whether telemetry is suppressed in this context.
336353
#[inline]
337354
pub fn is_telemetry_suppressed(&self) -> bool {
338-
self.suppress_telemetry
355+
if let Some(inner) = &self.inner {
356+
inner.suppress_telemetry
357+
} else {
358+
false
359+
}
339360
}
340361

341362
/// Returns a new context with telemetry suppression enabled.
342363
pub fn with_telemetry_suppressed(&self) -> Self {
343-
Context {
344-
entries: self.entries.clone(),
345-
#[cfg(feature = "trace")]
346-
span: self.span.clone(),
347-
suppress_telemetry: true,
364+
if self.is_telemetry_suppressed() {
365+
return self.clone();
366+
}
367+
368+
if let Some(inner) = &self.inner {
369+
Context {
370+
inner: Some(Arc::new(InnerContext {
371+
#[cfg(feature = "trace")]
372+
span: inner.span.clone(),
373+
entries: inner.entries.clone(),
374+
suppress_telemetry: true,
375+
})),
376+
}
377+
} else {
378+
Context {
379+
inner: Some(Arc::new(InnerContext {
380+
suppress_telemetry: true,
381+
..Default::default()
382+
})),
383+
}
348384
}
349385
}
350386

@@ -410,43 +446,53 @@ impl Context {
410446

411447
#[cfg(feature = "trace")]
412448
pub(crate) fn current_with_synchronized_span(value: SynchronizedSpan) -> Self {
413-
Self::map_current(|cx| Context {
414-
span: Some(Arc::new(value)),
415-
entries: cx.entries.clone(),
416-
suppress_telemetry: cx.suppress_telemetry,
417-
})
449+
Self::map_current(|cx| cx.with_synchronized_span(value))
418450
}
419451

420452
#[cfg(feature = "trace")]
421453
pub(crate) fn with_synchronized_span(&self, value: SynchronizedSpan) -> Self {
454+
let (entries, suppress_telemetry) = if let Some(inner) = &self.inner {
455+
(inner.entries.clone(), inner.suppress_telemetry)
456+
} else {
457+
(None, false)
458+
};
422459
Context {
423-
span: Some(Arc::new(value)),
424-
entries: self.entries.clone(),
425-
suppress_telemetry: self.suppress_telemetry,
460+
inner: Some(Arc::new(InnerContext {
461+
span: Some(Arc::new(value)),
462+
entries,
463+
suppress_telemetry,
464+
})),
426465
}
427466
}
428467
}
429468

430469
impl fmt::Debug for Context {
431470
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
432471
let mut dbg = f.debug_struct("Context");
472+
let mut entries = 0;
473+
let mut suppress_telemetry = false;
433474

434-
#[cfg(feature = "trace")]
435-
let mut entries = self.entries.as_ref().map_or(0, |e| e.len());
436-
#[cfg(feature = "trace")]
437-
{
438-
if let Some(span) = &self.span {
439-
dbg.field("span", &span.span_context());
440-
entries += 1;
441-
} else {
475+
if let Some(inner) = &self.inner {
476+
entries = inner.entries.as_ref().map_or(0, |e| e.len());
477+
#[cfg(feature = "trace")]
478+
{
479+
if let Some(span) = inner.span.as_ref() {
480+
dbg.field("span", &span.span_context());
481+
entries += 1;
482+
} else {
483+
dbg.field("span", &"None");
484+
}
485+
}
486+
suppress_telemetry = inner.suppress_telemetry;
487+
} else {
488+
#[cfg(feature = "trace")]
489+
{
442490
dbg.field("span", &"None");
443491
}
444492
}
445-
#[cfg(not(feature = "trace"))]
446-
let entries = self.entries.as_ref().map_or(0, |e| e.len());
447493

448494
dbg.field("entries count", &entries)
449-
.field("suppress_telemetry", &self.suppress_telemetry)
495+
.field("suppress_telemetry", &suppress_telemetry)
450496
.finish()
451497
}
452498
}

opentelemetry/src/trace/context.rs

Lines changed: 11 additions & 5 deletions
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)