diff --git a/Cargo.lock b/Cargo.lock index f0b08881..798b77b1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1000,6 +1000,19 @@ version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7762d17f1241643615821a8455a0b2c3e803784b058693d990b11f2dce25a0ca" +[[package]] +name = "dashmap" +version = "5.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856" +dependencies = [ + "cfg-if", + "hashbrown 0.14.3", + "lock_api", + "once_cell", + "parking_lot_core", +] + [[package]] name = "data-encoding" version = "2.5.0" @@ -2874,6 +2887,7 @@ dependencies = [ "chrono", "config", "csv-async", + "dashmap", "dotenvy", "env_logger", "futures-util", diff --git a/Cargo.toml b/Cargo.toml index 5154aab8..039aedc7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,7 +27,8 @@ log = "0.4.17" env_logger = "0.10.0" mime_guess = "2.0.4" futures-util = "0.3.21" -tokio = { version = "1.24.1", features = ["macros", "rt", "process", "sync"] } +dashmap = "5.5.1" +tokio = { version = "1.24.1", features = ["macros", "rt", "process"] } tokio-stream = "0.1.9" anyhow = "1" serde = "1" diff --git a/src/file_cache.rs b/src/file_cache.rs index 0395d35e..f1023680 100644 --- a/src/file_cache.rs +++ b/src/file_cache.rs @@ -4,6 +4,7 @@ use actix_web::http::StatusCode; use anyhow::Context; use async_trait::async_trait; use chrono::{DateTime, TimeZone, Utc}; +use dashmap::DashMap; use std::collections::HashMap; use std::path::PathBuf; use std::sync::atomic::{ @@ -12,7 +13,6 @@ use std::sync::atomic::{ }; use std::sync::Arc; use std::time::SystemTime; -use tokio::sync::RwLock; /// The maximum time in milliseconds that a file can be cached before its freshness is checked /// (in production mode) @@ -68,7 +68,7 @@ impl Cached { } pub struct FileCache { - cache: Arc>>>, + cache: Arc>>, /// Files that are loaded at the beginning of the program, /// and used as fallback when there is no match for the request in the file system static_files: HashMap>, @@ -96,21 +96,25 @@ impl FileCache { } pub async fn get(&self, app_state: &AppState, path: &PathBuf) -> anyhow::Result> { - log::trace!("Attempting to get from cache {:?}", path); - if let Some(cached) = self.cache.read().await.get(path) { + if let Some(cached) = self.cache.get(path) { if app_state.config.environment.is_prod() && !cached.needs_check() { log::trace!("Cache answer without filesystem lookup for {:?}", path); return Ok(Arc::clone(&cached.content)); } - match app_state - .file_system - .modified_since(app_state, path, cached.last_check_time(), true) - .await - { + let modified_res = app_state.file_system.modified_since( + app_state, + path, + cached.last_check_time(), + true, + ); + drop(cached); + match modified_res.await { Ok(false) => { log::trace!("Cache answer with filesystem metadata read for {:?}", path); - cached.update_check_time(); - return Ok(Arc::clone(&cached.content)); + if let Some(cached) = self.cache.get(path) { + cached.update_check_time(); + return Ok(Arc::clone(&cached.content)); + } } Ok(true) => log::trace!("{path:?} was changed, updating cache..."), Err(e) => log::trace!("Cannot read metadata of {path:?}, re-loading it: {e:#}"), @@ -149,9 +153,7 @@ impl FileCache { match parsed { Ok(value) => { let new_val = Arc::clone(&value.content); - log::trace!("Writing to cache {:?}", path); - self.cache.write().await.insert(path.clone(), value); - log::trace!("Done writing to cache {:?}", path); + self.cache.insert(path.clone(), value); log::trace!("{:?} loaded in cache", path); Ok(new_val) } @@ -159,9 +161,7 @@ impl FileCache { log::trace!( "Evicting {path:?} from the cache because the following error occurred: {e}" ); - log::trace!("Removing from cache {:?}", path); - self.cache.write().await.remove(path); - log::trace!("Done removing from cache {:?}", path); + self.cache.remove(path); Err(e) } }