Skip to content

Commit 08ec6e1

Browse files
committed
perf: Optimize cloning of Context since entries are immutable
1 parent aacf87d commit 08ec6e1

File tree

1 file changed

+23
-17
lines changed

1 file changed

+23
-17
lines changed

opentelemetry/src/context.rs

+23-17
Original file line numberDiff line numberDiff line change
@@ -79,9 +79,11 @@ thread_local! {
7979
pub struct Context {
8080
#[cfg(feature = "trace")]
8181
pub(super) span: Option<Arc<SynchronizedSpan>>,
82-
entries: HashMap<TypeId, Arc<dyn Any + Sync + Send>, BuildHasherDefault<IdHasher>>,
82+
entries: Option<Arc<EntryMap>>,
8383
}
8484

85+
type EntryMap = HashMap<TypeId, Arc<dyn Any + Sync + Send>, BuildHasherDefault<IdHasher>>;
86+
8587
impl Context {
8688
/// Creates an empty `Context`.
8789
///
@@ -111,7 +113,7 @@ impl Context {
111113
/// do_work()
112114
/// ```
113115
pub fn current() -> Self {
114-
Context::map_current(|cx| cx.clone())
116+
Self::map_current(|cx| cx.clone())
115117
}
116118

117119
/// Applies a function to the current context returning its value.
@@ -153,12 +155,7 @@ impl Context {
153155
/// assert_eq!(all_current_and_b.get::<ValueB>(), Some(&ValueB(42)));
154156
/// ```
155157
pub fn current_with_value<T: 'static + Send + Sync>(value: T) -> Self {
156-
let mut new_context = Context::current();
157-
new_context
158-
.entries
159-
.insert(TypeId::of::<T>(), Arc::new(value));
160-
161-
new_context
158+
Self::map_current(|cx| cx.with_value(value))
162159
}
163160

164161
/// Returns a reference to the entry for the corresponding value type.
@@ -184,8 +181,9 @@ impl Context {
184181
/// ```
185182
pub fn get<T: 'static>(&self) -> Option<&T> {
186183
self.entries
187-
.get(&TypeId::of::<T>())
188-
.and_then(|rc| rc.downcast_ref())
184+
.as_ref()?
185+
.get(&TypeId::of::<T>())?
186+
.downcast_ref()
189187
}
190188

191189
/// Returns a copy of the context with the new value included.
@@ -216,12 +214,20 @@ impl Context {
216214
/// assert_eq!(cx_with_a_and_b.get::<ValueB>(), Some(&ValueB(42)));
217215
/// ```
218216
pub fn with_value<T: 'static + Send + Sync>(&self, value: T) -> Self {
219-
let mut new_context = self.clone();
220-
new_context
221-
.entries
222-
.insert(TypeId::of::<T>(), Arc::new(value));
223-
224-
new_context
217+
let entries = if let Some(current_entries) = &self.entries {
218+
let mut inner_entries = (**current_entries).clone();
219+
inner_entries.insert(TypeId::of::<T>(), Arc::new(value));
220+
Some(Arc::new(inner_entries))
221+
} else {
222+
let mut entries = EntryMap::default();
223+
entries.insert(TypeId::of::<T>(), Arc::new(value));
224+
Some(Arc::new(entries))
225+
};
226+
Context {
227+
entries,
228+
#[cfg(feature = "trace")]
229+
span: self.span.clone(),
230+
}
225231
}
226232

227233
/// Replaces the current context on this thread with this context.
@@ -327,7 +333,7 @@ impl Context {
327333
impl fmt::Debug for Context {
328334
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
329335
let mut dbg = f.debug_struct("Context");
330-
let mut entries = self.entries.len();
336+
let mut entries = self.entries.as_ref().map_or(0, |e| e.len());
331337
#[cfg(feature = "trace")]
332338
{
333339
if let Some(span) = &self.span {

0 commit comments

Comments
 (0)