Skip to content

Commit d554c22

Browse files
committed
Use Entry pattern to call only once into the hashmap to get or insert an ElfResolver
1 parent ad8ce8b commit d554c22

File tree

3 files changed

+32
-20
lines changed

3 files changed

+32
-20
lines changed

datadog-crashtracker-ffi/src/crash_info/api.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ pub unsafe extern "C" fn ddog_crasht_CrashInfo_resolve_names(
7474
// is tailored for performance. It makes sure that required resources between normalize_ips and
7575
// resolve_names are shared and reused, which is not the case when calling the two functions
7676
// separately.
77-
// While this is more efficient, it means that you are force to do both operations, and you are not
77+
// While this is more efficient, it means that you are forced to do both operations, and you are not
7878
// able to do only one of them.
7979
#[no_mangle]
8080
#[must_use]

datadog-crashtracker/src/crash_info/error_data.rs

Lines changed: 30 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -39,24 +39,35 @@ impl<'a> CachedElfResolvers<'a> {
3939
}
4040
}
4141

42-
pub fn get(&mut self, file_path: &PathBuf) -> anyhow::Result<Rc<ElfResolver>> {
42+
pub fn get_or_insert(&mut self, file_path: &PathBuf) -> anyhow::Result<Rc<ElfResolver>> {
4343
use anyhow::Context;
44-
if !self.elf_resolvers.contains_key(file_path.as_path()) {
45-
let resolver = Rc::new(ElfResolver::open(file_path).with_context(|| {
46-
format!(
47-
"ElfResolver::open failed for '{}'",
48-
file_path.to_string_lossy()
49-
)
50-
})?);
51-
let _ = self
52-
.symbolizer
53-
.register_elf_resolver(file_path.as_path(), Rc::clone(&resolver));
54-
self.elf_resolvers.insert(file_path.clone(), resolver);
44+
let entry = self.elf_resolvers.entry(file_path.clone());
45+
46+
match entry {
47+
std::collections::hash_map::Entry::Occupied(o) => Ok(o.get().clone()),
48+
std::collections::hash_map::Entry::Vacant(v) => {
49+
let resolver = ElfResolver::open(file_path).with_context(|| {
50+
format!(
51+
"ElfResolver::open failed for '{}'",
52+
file_path.to_string_lossy()
53+
)
54+
});
55+
56+
match resolver {
57+
Ok(resolver) => {
58+
let resolver = Rc::new(resolver);
59+
// even if the symbolizer failed at registering the elf resolver, we still cache it
60+
// to avoid trying to open it again
61+
let _ = self
62+
.symbolizer
63+
.register_elf_resolver(file_path.as_path(), Rc::clone(&resolver));
64+
v.insert(Rc::clone(&resolver));
65+
Ok(resolver)
66+
}
67+
Err(e) => Err(e),
68+
}
69+
}
5570
}
56-
self.elf_resolvers
57-
.get(file_path.as_path())
58-
.with_context(|| "key '{}' not found in ElfResolver cache")
59-
.cloned()
6071
}
6172
}
6273

@@ -80,14 +91,15 @@ impl ErrorData {
8091
elf_resolvers: &mut CachedElfResolvers,
8192
) -> anyhow::Result<()> {
8293
let mut errors = 0;
94+
let pid = pid.into();
8395
self.stack
84-
.normalize_ips(normalizer, pid.into(), elf_resolvers)
96+
.normalize_ips(normalizer, pid, elf_resolvers)
8597
.unwrap_or_else(|_| errors += 1);
8698

8799
for thread in &mut self.threads {
88100
thread
89101
.stack
90-
.normalize_ips(normalizer, pid.into(), elf_resolvers)
102+
.normalize_ips(normalizer, pid, elf_resolvers)
91103
.unwrap_or_else(|_| errors += 1);
92104
}
93105
anyhow::ensure!(

datadog-crashtracker/src/crash_info/stacktrace.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,7 @@ impl StackFrame {
195195
let (file_offset, meta_idx) = normed.outputs[0];
196196
let meta = &normed.meta[meta_idx];
197197
let elf = meta.as_elf().context("Not elf")?;
198-
let resolver = elf_resolvers.get(&elf.path)?;
198+
let resolver = elf_resolvers.get_or_insert(&elf.path)?;
199199
let virt_address = resolver
200200
.file_offset_to_virt_offset(file_offset)?
201201
.context("No matching segment found")?;

0 commit comments

Comments
 (0)