summaryrefslogtreecommitdiff
path: root/cli/cache/fast_check.rs
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/fast_check.rs
parentdbc4a4d6327062918b3bc41dc3f60c84ae3c620b (diff)
perf(jsr): fast check cache and lazy fast check graph (#22485)
Diffstat (limited to 'cli/cache/fast_check.rs')
-rw-r--r--cli/cache/fast_check.rs162
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());
+ }
+}