Skip to content

Commit 7c0988e

Browse files
committed
perf: Optimize cloning of Context since entries are immutable
1 parent 291e2c4 commit 7c0988e

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
@@ -78,9 +78,11 @@ thread_local! {
7878
pub struct Context {
7979
#[cfg(feature = "trace")]
8080
pub(super) span: Option<Arc<SynchronizedSpan>>,
81-
entries: HashMap<TypeId, Arc<dyn Any + Sync + Send>, BuildHasherDefault<IdHasher>>,
81+
entries: Option<Arc<EntryMap>>,
8282
}
8383

84+
type EntryMap = HashMap<TypeId, Arc<dyn Any + Sync + Send>, BuildHasherDefault<IdHasher>>;
85+
8486
impl Context {
8587
/// Creates an empty `Context`.
8688
///
@@ -110,7 +112,7 @@ impl Context {
110112
/// do_work()
111113
/// ```
112114
pub fn current() -> Self {
113-
Context::map_current(|cx| cx.clone())
115+
Self::map_current(|cx| cx.clone())
114116
}
115117

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

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

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

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

0 commit comments

Comments
 (0)