diff --git a/crates/symbolicator-js/src/bundle_lookup.rs b/crates/symbolicator-js/src/bundle_lookup.rs new file mode 100644 index 000000000..8aa8dd83e --- /dev/null +++ b/crates/symbolicator-js/src/bundle_lookup.rs @@ -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, + mut key: FileKey, + ) -> Option { + 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()) + } +} diff --git a/crates/symbolicator-js/src/lib.rs b/crates/symbolicator-js/src/lib.rs index 9172406bd..673500a8d 100644 --- a/crates/symbolicator-js/src/lib.rs +++ b/crates/symbolicator-js/src/lib.rs @@ -1,6 +1,7 @@ mod api_lookup; mod bundle_index; mod bundle_index_cache; +mod bundle_lookup; pub mod interface; mod lookup; mod metrics; diff --git a/crates/symbolicator-js/src/lookup.rs b/crates/symbolicator-js/src/lookup.rs index 21f81ed0b..3b36477dc 100644 --- a/crates/symbolicator-js/src/lookup.rs +++ b/crates/symbolicator-js/src/lookup.rs @@ -28,7 +28,7 @@ use std::fmt::{self, Write}; use std::fs::File; use std::io::{self, BufWriter}; use std::sync::Arc; -use std::time::{Duration, SystemTime}; +use std::time::SystemTime; use futures::future::BoxFuture; use reqwest::Url; @@ -59,6 +59,7 @@ use symbolicator_service::utils::http::is_valid_origin; use crate::api_lookup::{ArtifactHeaders, JsLookupResult, SentryLookupApi}; use crate::bundle_index::BundleIndex; use crate::bundle_index_cache::BundleIndexCache; +use crate::bundle_lookup::FileInBundleCache; use crate::interface::{ JsScrapingAttempt, JsScrapingFailureReason, JsStacktrace, ResolvedWith, SymbolicateJsStacktraces, @@ -557,74 +558,6 @@ struct IndividualArtifact { resolved_with: ResolvedWith, } -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 { - 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. - fn try_get( - &self, - bundle_uris: impl Iterator, - mut key: FileKey, - ) -> Option { - 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. - 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()) - } -} - struct ArtifactFetcher { metrics: JsMetrics, diff --git a/crates/symbolicator-js/src/service.rs b/crates/symbolicator-js/src/service.rs index b299549e5..4e5609f0e 100644 --- a/crates/symbolicator-js/src/service.rs +++ b/crates/symbolicator-js/src/service.rs @@ -10,7 +10,8 @@ use symbolicator_service::services::SharedServices; use crate::api_lookup::SentryLookupApi; use crate::bundle_index_cache::BundleIndexCache; -use crate::lookup::{FetchSourceMapCacheInternal, FileInBundleCache}; +use crate::bundle_lookup::FileInBundleCache; +use crate::lookup::FetchSourceMapCacheInternal; #[derive(Debug, Clone)] pub struct SourceMapService { @@ -45,11 +46,9 @@ impl SourceMapService { in_memory, )); - let files_in_bundles = FileInBundleCache::new(); - Self { objects, - files_in_bundles, + files_in_bundles: FileInBundleCache::new(), sourcefiles_cache, bundle_index_cache: Arc::new(bundle_index_cache), sourcemap_caches: Arc::new(Cacher::new(caches.sourcemap_caches.clone(), shared_cache)),