-
-
Notifications
You must be signed in to change notification settings - Fork 54
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add another Cache for accessing files in
ArtifactBundle
s (#1354)
When profiling (via `symbolicator-stress`) processing of javascript events, the majority of the time is spent extracting minified / sourcemap files from artifact bundles (which are essentially zip files). We introduce yet another cache which can avoid this costly unzip process by keeping these unzipped files in memory. For the above mentioned stresstest, this has lead to a throughput increase of 1000x. Though not surprisingly, the stresstest processes the exact same event over and over and has thus a 100% cache hit rate. Co-authored-by: Sebastian Zivota <[email protected]>
- Loading branch information
1 parent
202922a
commit 8218752
Showing
5 changed files
with
111 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
use std::fmt; | ||
use std::time::Duration; | ||
|
||
use symbolicator_sources::RemoteFileUri; | ||
|
||
use crate::lookup::{CachedFileEntry, FileKey}; | ||
|
||
type FileInBundleCacheInner = moka::sync::Cache<(RemoteFileUri, FileKey), CachedFileEntry>; | ||
|
||
/// A cache that memoizes looking up files in artifact bundles. | ||
#[derive(Clone)] | ||
pub struct FileInBundleCache { | ||
cache: FileInBundleCacheInner, | ||
} | ||
|
||
impl std::fmt::Debug for FileInBundleCache { | ||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||
f.debug_struct("FileInBundleCache").finish() | ||
} | ||
} | ||
|
||
impl FileInBundleCache { | ||
/// Creates a new `FileInBundleCache` with a maximum size of 2GiB and | ||
/// idle time of 1h. | ||
pub fn new() -> Self { | ||
// NOTE: We size the cache at 2 GiB which is quite an arbitrary pick. | ||
// As all the files are living in memory, we return the size of the contents | ||
// from the `weigher` which is responsible for this accounting. | ||
const GIGS: u64 = 1 << 30; | ||
let cache = FileInBundleCacheInner::builder() | ||
.max_capacity(2 * GIGS) | ||
.time_to_idle(Duration::from_secs(60 * 60)) | ||
.name("file-in-bundle") | ||
.weigher(|_k, v| { | ||
let content_size = v | ||
.entry | ||
.as_ref() | ||
.map(|cached_file| cached_file.contents.len()) | ||
.unwrap_or_default(); | ||
(std::mem::size_of_val(v) + content_size) | ||
.try_into() | ||
.unwrap_or(u32::MAX) | ||
}) | ||
.build(); | ||
Self { cache } | ||
} | ||
|
||
/// Tries to retrieve a file from the cache. | ||
/// | ||
/// We look for the file under `(bundle_uri, key)` for `bundle_uri` in `bundle_uris`. | ||
/// Retrieval is limited to a specific list of bundles so that e.g. files with the same | ||
/// `abs_path` belonging to different events are disambiguated. | ||
pub fn try_get( | ||
&self, | ||
bundle_uris: impl Iterator<Item = RemoteFileUri>, | ||
mut key: FileKey, | ||
) -> Option<CachedFileEntry> { | ||
for bundle_uri in bundle_uris { | ||
// XXX: this is a really horrible workaround for not being able to look up things via `(&A, &B)` instead of `&(A, B)`. | ||
let lookup_key = (bundle_uri, key); | ||
if let Some(file_entry) = self.cache.get(&lookup_key) { | ||
return Some(file_entry); | ||
} | ||
key = lookup_key.1; | ||
} | ||
None | ||
} | ||
|
||
/// Inserts `file_entry` into the cache under `(bundle_uri, key)`. | ||
/// | ||
/// Files are inserted under a specific bundle so that e.g. files with the same | ||
/// `abs_path` belonging to different events are disambiguated. | ||
pub fn insert(&self, bundle_uri: &RemoteFileUri, key: &FileKey, file_entry: &CachedFileEntry) { | ||
let key = (bundle_uri.clone(), key.clone()); | ||
self.cache.insert(key, file_entry.clone()) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters