summaryrefslogtreecommitdiff
path: root/cli/cache
diff options
context:
space:
mode:
authorDavid Sherret <dsherret@users.noreply.github.com>2024-02-20 16:29:57 -0500
committerGitHub <noreply@github.com>2024-02-20 21:29:57 +0000
commitf90889e5ee19e0ddcd9c1dbcce98720e417dd83e (patch)
treee44392e9506ba8cddc4c142d304f43879a418152 /cli/cache
parentdbc4a4d6327062918b3bc41dc3f60c84ae3c620b (diff)
perf(jsr): fast check cache and lazy fast check graph (#22485)
Diffstat (limited to 'cli/cache')
-rw-r--r--cli/cache/caches.rs15
-rw-r--r--cli/cache/deno_dir.rs6
-rw-r--r--cli/cache/fast_check.rs162
-rw-r--r--cli/cache/mod.rs8
4 files changed, 185 insertions, 6 deletions
diff --git a/cli/cache/caches.rs b/cli/cache/caches.rs
index 7220a2f9d..dc97f02d5 100644
--- a/cli/cache/caches.rs
+++ b/cli/cache/caches.rs
@@ -9,6 +9,7 @@ use super::cache_db::CacheDB;
use super::cache_db::CacheDBConfiguration;
use super::check::TYPE_CHECK_CACHE_DB;
use super::deno_dir::DenoDirProvider;
+use super::fast_check::FAST_CHECK_CACHE_DB;
use super::incremental::INCREMENTAL_CACHE_DB;
use super::module_info::MODULE_INFO_CACHE_DB;
use super::node::NODE_ANALYSIS_CACHE_DB;
@@ -18,6 +19,7 @@ pub struct Caches {
fmt_incremental_cache_db: OnceCell<CacheDB>,
lint_incremental_cache_db: OnceCell<CacheDB>,
dep_analysis_db: OnceCell<CacheDB>,
+ fast_check_db: OnceCell<CacheDB>,
node_analysis_db: OnceCell<CacheDB>,
type_checking_cache_db: OnceCell<CacheDB>,
}
@@ -29,6 +31,7 @@ impl Caches {
fmt_incremental_cache_db: Default::default(),
lint_incremental_cache_db: Default::default(),
dep_analysis_db: Default::default(),
+ fast_check_db: Default::default(),
node_analysis_db: Default::default(),
type_checking_cache_db: Default::default(),
}
@@ -86,6 +89,18 @@ impl Caches {
)
}
+ pub fn fast_check_db(&self) -> CacheDB {
+ Self::make_db(
+ &self.fast_check_db,
+ &FAST_CHECK_CACHE_DB,
+ self
+ .dir_provider
+ .get_or_create()
+ .ok()
+ .map(|dir| dir.fast_check_cache_db_file_path()),
+ )
+ }
+
pub fn node_analysis_db(&self) -> CacheDB {
Self::make_db(
&self.node_analysis_db,
diff --git a/cli/cache/deno_dir.rs b/cli/cache/deno_dir.rs
index 72f8987bd..ee8c35684 100644
--- a/cli/cache/deno_dir.rs
+++ b/cli/cache/deno_dir.rs
@@ -98,6 +98,12 @@ impl DenoDir {
self.root.join("dep_analysis_cache_v1")
}
+ /// Path for the cache used for fast check.
+ pub fn fast_check_cache_db_file_path(&self) -> PathBuf {
+ // bump this version name to invalidate the entire cache
+ self.root.join("fast_check_cache_v1")
+ }
+
/// Path for caching node analysis.
pub fn node_analysis_db_file_path(&self) -> PathBuf {
// bump this version name to invalidate the entire cache
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());
+ }
+}
diff --git a/cli/cache/mod.rs b/cli/cache/mod.rs
index e9d225146..7d95a6423 100644
--- a/cli/cache/mod.rs
+++ b/cli/cache/mod.rs
@@ -1,6 +1,5 @@
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
-use crate::args::jsr_url;
use crate::args::CacheSetting;
use crate::errors::get_error_class_name;
use crate::file_fetcher::FetchOptions;
@@ -11,7 +10,6 @@ use crate::util::fs::atomic_write_file;
use deno_ast::MediaType;
use deno_core::futures;
use deno_core::futures::FutureExt;
-use deno_core::url::Url;
use deno_core::ModuleSpecifier;
use deno_graph::source::CacheInfo;
use deno_graph::source::LoadFuture;
@@ -31,6 +29,7 @@ mod common;
mod deno_dir;
mod disk_cache;
mod emit;
+mod fast_check;
mod incremental;
mod module_info;
mod node;
@@ -43,6 +42,7 @@ pub use deno_dir::DenoDir;
pub use deno_dir::DenoDirProvider;
pub use disk_cache::DiskCache;
pub use emit::EmitCache;
+pub use fast_check::FastCheckCache;
pub use incremental::IncrementalCache;
pub use module_info::ModuleInfoCache;
pub use node::NodeAnalysisCache;
@@ -167,10 +167,6 @@ impl FetchCacher {
}
impl Loader for FetchCacher {
- fn registry_url(&self) -> &Url {
- jsr_url()
- }
-
fn get_cache_info(&self, specifier: &ModuleSpecifier) -> Option<CacheInfo> {
if !self.cache_info_enabled {
return None;