diff options
Diffstat (limited to 'cli/cache/fast_check.rs')
-rw-r--r-- | cli/cache/fast_check.rs | 162 |
1 files changed, 162 insertions, 0 deletions
diff --git a/cli/cache/fast_check.rs b/cli/cache/fast_check.rs new file mode 100644 index 000000000..f8335d5ea --- /dev/null +++ b/cli/cache/fast_check.rs @@ -0,0 +1,162 @@ +// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. + +use deno_core::error::AnyError; +use deno_graph::FastCheckCacheItem; +use deno_graph::FastCheckCacheKey; +use deno_runtime::deno_webstorage::rusqlite::params; + +use super::cache_db::CacheDB; +use super::cache_db::CacheDBConfiguration; +use super::cache_db::CacheFailure; + +pub static FAST_CHECK_CACHE_DB: CacheDBConfiguration = CacheDBConfiguration { + table_initializer: "CREATE TABLE IF NOT EXISTS fastcheckcache ( + hash TEXT PRIMARY KEY, + data TEXT NOT NULL + );", + on_version_change: "DELETE FROM fastcheckcache;", + preheat_queries: &[], + on_failure: CacheFailure::Blackhole, +}; + +#[derive(Clone)] +pub struct FastCheckCache { + inner: FastCheckCacheInner, +} + +impl FastCheckCache { + pub fn new(db: CacheDB) -> Self { + Self { + inner: FastCheckCacheInner::new(db), + } + } + + fn ensure_ok<T: Default>(res: Result<T, AnyError>) -> T { + match res { + Ok(x) => x, + Err(err) => { + // TODO(mmastrac): This behavior was inherited from before the refactoring but it probably makes sense to move it into the cache + // at some point. + // should never error here, but if it ever does don't fail + if cfg!(debug_assertions) { + panic!("Error using fast check cache: {err:#}"); + } else { + log::debug!("Error using fast check cache: {:#}", err); + } + T::default() + } + } + } +} + +impl deno_graph::FastCheckCache for FastCheckCache { + fn get(&self, key: FastCheckCacheKey) -> Option<FastCheckCacheItem> { + Self::ensure_ok(self.inner.get(key)) + } + + fn set(&self, key: FastCheckCacheKey, value: FastCheckCacheItem) { + Self::ensure_ok(self.inner.set(key, &value)); + } +} + +#[derive(Clone)] +struct FastCheckCacheInner { + conn: CacheDB, +} + +impl FastCheckCacheInner { + pub fn new(conn: CacheDB) -> Self { + Self { conn } + } + + pub fn get( + &self, + key: FastCheckCacheKey, + ) -> Result<Option<FastCheckCacheItem>, AnyError> { + let query = " + SELECT + data + FROM + fastcheckcache + WHERE + hash=?1 + LIMIT 1"; + let res = self + .conn + // key is a string because SQLite can't handle u64 + .query_row(query, params![key.as_u64().to_string()], |row| { + let value: Vec<u8> = row.get(0)?; + Ok(bincode::deserialize::<FastCheckCacheItem>(&value)?) + })?; + Ok(res) + } + + pub fn set( + &self, + key: FastCheckCacheKey, + data: &FastCheckCacheItem, + ) -> Result<(), AnyError> { + let sql = " + INSERT OR REPLACE INTO + fastcheckcache (hash, data) + VALUES + (?1, ?2)"; + self.conn.execute( + sql, + params![key.as_u64().to_string(), &bincode::serialize(data)?], + )?; + Ok(()) + } +} + +#[cfg(test)] +mod test { + use std::collections::BTreeSet; + + use deno_ast::ModuleSpecifier; + use deno_graph::FastCheckCacheModuleItem; + use deno_graph::FastCheckCacheModuleItemDiagnostic; + use deno_semver::package::PackageNv; + + use super::*; + + #[test] + pub fn cache_general_use() { + let conn = CacheDB::in_memory(&FAST_CHECK_CACHE_DB, "1.0.0"); + let cache = FastCheckCacheInner::new(conn); + + let key = FastCheckCacheKey::build( + &PackageNv::from_str("@scope/a@1.0.0").unwrap(), + &Default::default(), + ); + assert!(cache.get(key).unwrap().is_none()); + let value = FastCheckCacheItem { + dependencies: BTreeSet::from([ + PackageNv::from_str("@scope/b@1.0.0").unwrap() + ]), + modules: vec![( + ModuleSpecifier::parse("https://jsr.io/test.ts").unwrap(), + FastCheckCacheModuleItem::Diagnostic( + FastCheckCacheModuleItemDiagnostic { source_hash: 123 }, + ), + )], + }; + cache.set(key, &value).unwrap(); + let stored_value = cache.get(key).unwrap().unwrap(); + assert_eq!(stored_value, value); + + // adding when already exists should not cause issue + cache.set(key, &value).unwrap(); + + // recreating with same cli version should still have it + let conn = cache.conn.recreate_with_version("1.0.0"); + let cache = FastCheckCacheInner::new(conn); + let stored_value = cache.get(key).unwrap().unwrap(); + assert_eq!(stored_value, value); + + // now changing the cli version should clear it + let conn = cache.conn.recreate_with_version("2.0.0"); + let cache = FastCheckCacheInner::new(conn); + assert!(cache.get(key).unwrap().is_none()); + } +} |