mirror of
https://github.com/denoland/deno.git
synced 2025-09-26 12:19:12 +00:00
fix: fallback to no type checking cache when db file can't be created (#15180)
This commit is contained in:
parent
61340f1d89
commit
698eeb90fd
3 changed files with 62 additions and 26 deletions
82
cli/cache/check.rs
vendored
82
cli/cache/check.rs
vendored
|
@ -3,7 +3,6 @@
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
use deno_ast::ModuleSpecifier;
|
use deno_ast::ModuleSpecifier;
|
||||||
use deno_core::anyhow::Context;
|
|
||||||
use deno_core::error::AnyError;
|
use deno_core::error::AnyError;
|
||||||
use deno_runtime::deno_webstorage::rusqlite::params;
|
use deno_runtime::deno_webstorage::rusqlite::params;
|
||||||
use deno_runtime::deno_webstorage::rusqlite::Connection;
|
use deno_runtime::deno_webstorage::rusqlite::Connection;
|
||||||
|
@ -14,21 +13,45 @@ use super::common::run_sqlite_pragma;
|
||||||
///
|
///
|
||||||
/// This simply stores a hash of the inputs of each successful type check
|
/// This simply stores a hash of the inputs of each successful type check
|
||||||
/// and only clears them out when changing CLI versions.
|
/// and only clears them out when changing CLI versions.
|
||||||
pub struct TypeCheckCache {
|
pub struct TypeCheckCache(Option<Connection>);
|
||||||
conn: Connection,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TypeCheckCache {
|
impl TypeCheckCache {
|
||||||
pub fn new(db_file_path: &Path) -> Result<Self, AnyError> {
|
pub fn new(db_file_path: &Path) -> Self {
|
||||||
let conn = Connection::open(db_file_path).with_context(|| {
|
match Self::try_new(db_file_path) {
|
||||||
format!(
|
Ok(cache) => cache,
|
||||||
concat!(
|
Err(err) => {
|
||||||
"Error opening type checking cache at {} -- ",
|
log::debug!(
|
||||||
"Perhaps it's corrupt. Maybe try deleting it."
|
concat!(
|
||||||
),
|
"Failed creating internal type checking cache. ",
|
||||||
db_file_path.display()
|
"Recreating...\n\nError details:\n{:#}",
|
||||||
)
|
),
|
||||||
})?;
|
err
|
||||||
|
);
|
||||||
|
// Maybe the cache file is corrupt. Attempt to remove the cache file
|
||||||
|
// then attempt to recreate again. Otherwise, use null object pattern.
|
||||||
|
match std::fs::remove_file(db_file_path) {
|
||||||
|
Ok(_) => match Self::try_new(db_file_path) {
|
||||||
|
Ok(cache) => cache,
|
||||||
|
Err(err) => {
|
||||||
|
log::debug!(
|
||||||
|
concat!(
|
||||||
|
"Unable to create internal cache for type checking. ",
|
||||||
|
"This will reduce the performance of type checking.\n\n",
|
||||||
|
"Error details:\n{:#}",
|
||||||
|
),
|
||||||
|
err
|
||||||
|
);
|
||||||
|
Self(None)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Err(_) => Self(None),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn try_new(db_file_path: &Path) -> Result<Self, AnyError> {
|
||||||
|
let conn = Connection::open(db_file_path)?;
|
||||||
Self::from_connection(conn, crate::version::deno())
|
Self::from_connection(conn, crate::version::deno())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -39,7 +62,7 @@ impl TypeCheckCache {
|
||||||
run_sqlite_pragma(&conn)?;
|
run_sqlite_pragma(&conn)?;
|
||||||
create_tables(&conn, cli_version)?;
|
create_tables(&conn, cli_version)?;
|
||||||
|
|
||||||
Ok(Self { conn })
|
Ok(Self(Some(conn)))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn has_check_hash(&self, hash: u64) -> bool {
|
pub fn has_check_hash(&self, hash: u64) -> bool {
|
||||||
|
@ -58,8 +81,12 @@ impl TypeCheckCache {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn hash_check_hash_result(&self, hash: u64) -> Result<bool, AnyError> {
|
fn hash_check_hash_result(&self, hash: u64) -> Result<bool, AnyError> {
|
||||||
|
let conn = match &self.0 {
|
||||||
|
Some(conn) => conn,
|
||||||
|
None => return Ok(false),
|
||||||
|
};
|
||||||
let query = "SELECT * FROM checkcache WHERE check_hash=?1 LIMIT 1";
|
let query = "SELECT * FROM checkcache WHERE check_hash=?1 LIMIT 1";
|
||||||
let mut stmt = self.conn.prepare_cached(query)?;
|
let mut stmt = conn.prepare_cached(query)?;
|
||||||
Ok(stmt.exists(params![hash.to_string()])?)
|
Ok(stmt.exists(params![hash.to_string()])?)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -74,19 +101,26 @@ impl TypeCheckCache {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_check_hash_result(&self, check_hash: u64) -> Result<(), AnyError> {
|
fn add_check_hash_result(&self, check_hash: u64) -> Result<(), AnyError> {
|
||||||
|
let conn = match &self.0 {
|
||||||
|
Some(conn) => conn,
|
||||||
|
None => return Ok(()),
|
||||||
|
};
|
||||||
let sql = "
|
let sql = "
|
||||||
INSERT OR REPLACE INTO
|
INSERT OR REPLACE INTO
|
||||||
checkcache (check_hash)
|
checkcache (check_hash)
|
||||||
VALUES
|
VALUES
|
||||||
(?1)";
|
(?1)";
|
||||||
let mut stmt = self.conn.prepare_cached(sql)?;
|
let mut stmt = conn.prepare_cached(sql)?;
|
||||||
stmt.execute(params![&check_hash.to_string(),])?;
|
stmt.execute(params![&check_hash.to_string(),])?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_tsbuildinfo(&self, specifier: &ModuleSpecifier) -> Option<String> {
|
pub fn get_tsbuildinfo(&self, specifier: &ModuleSpecifier) -> Option<String> {
|
||||||
let mut stmt = self
|
let conn = match &self.0 {
|
||||||
.conn
|
Some(conn) => conn,
|
||||||
|
None => return None,
|
||||||
|
};
|
||||||
|
let mut stmt = conn
|
||||||
.prepare_cached("SELECT text FROM tsbuildinfo WHERE specifier=?1 LIMIT 1")
|
.prepare_cached("SELECT text FROM tsbuildinfo WHERE specifier=?1 LIMIT 1")
|
||||||
.ok()?;
|
.ok()?;
|
||||||
let mut rows = stmt.query(params![specifier.to_string()]).ok()?;
|
let mut rows = stmt.query(params![specifier.to_string()]).ok()?;
|
||||||
|
@ -111,7 +145,11 @@ impl TypeCheckCache {
|
||||||
specifier: &ModuleSpecifier,
|
specifier: &ModuleSpecifier,
|
||||||
text: &str,
|
text: &str,
|
||||||
) -> Result<(), AnyError> {
|
) -> Result<(), AnyError> {
|
||||||
let mut stmt = self.conn.prepare_cached(
|
let conn = match &self.0 {
|
||||||
|
Some(conn) => conn,
|
||||||
|
None => return Ok(()),
|
||||||
|
};
|
||||||
|
let mut stmt = conn.prepare_cached(
|
||||||
"INSERT OR REPLACE INTO tsbuildinfo (specifier, text) VALUES (?1, ?2)",
|
"INSERT OR REPLACE INTO tsbuildinfo (specifier, text) VALUES (?1, ?2)",
|
||||||
)?;
|
)?;
|
||||||
stmt.execute(params![specifier.to_string(), text])?;
|
stmt.execute(params![specifier.to_string(), text])?;
|
||||||
|
@ -185,7 +223,7 @@ mod test {
|
||||||
assert_eq!(cache.get_tsbuildinfo(&specifier1), Some("test".to_string()));
|
assert_eq!(cache.get_tsbuildinfo(&specifier1), Some("test".to_string()));
|
||||||
|
|
||||||
// try changing the cli version (should clear)
|
// try changing the cli version (should clear)
|
||||||
let conn = cache.conn;
|
let conn = cache.0.unwrap();
|
||||||
let cache =
|
let cache =
|
||||||
TypeCheckCache::from_connection(conn, "2.0.0".to_string()).unwrap();
|
TypeCheckCache::from_connection(conn, "2.0.0".to_string()).unwrap();
|
||||||
assert!(!cache.has_check_hash(1));
|
assert!(!cache.has_check_hash(1));
|
||||||
|
@ -196,7 +234,7 @@ mod test {
|
||||||
assert_eq!(cache.get_tsbuildinfo(&specifier1), Some("test".to_string()));
|
assert_eq!(cache.get_tsbuildinfo(&specifier1), Some("test".to_string()));
|
||||||
|
|
||||||
// recreating the cache should not remove the data because the CLI version and state hash is the same
|
// recreating the cache should not remove the data because the CLI version and state hash is the same
|
||||||
let conn = cache.conn;
|
let conn = cache.0.unwrap();
|
||||||
let cache =
|
let cache =
|
||||||
TypeCheckCache::from_connection(conn, "2.0.0".to_string()).unwrap();
|
TypeCheckCache::from_connection(conn, "2.0.0".to_string()).unwrap();
|
||||||
assert!(cache.has_check_hash(1));
|
assert!(cache.has_check_hash(1));
|
||||||
|
|
|
@ -661,9 +661,7 @@ async fn create_graph_and_maybe_check(
|
||||||
eprintln!("{}", ignored_options);
|
eprintln!("{}", ignored_options);
|
||||||
}
|
}
|
||||||
let maybe_config_specifier = ps.options.maybe_config_file_specifier();
|
let maybe_config_specifier = ps.options.maybe_config_file_specifier();
|
||||||
// todo: don't use anything on failure
|
let cache = TypeCheckCache::new(&ps.dir.type_checking_cache_db_file_path());
|
||||||
let cache =
|
|
||||||
TypeCheckCache::new(&ps.dir.type_checking_cache_db_file_path())?;
|
|
||||||
let check_result = emit::check(
|
let check_result = emit::check(
|
||||||
&graph.roots,
|
&graph.roots,
|
||||||
Arc::new(RwLock::new(graph.as_ref().into())),
|
Arc::new(RwLock::new(graph.as_ref().into())),
|
||||||
|
|
|
@ -443,7 +443,7 @@ impl ProcState {
|
||||||
};
|
};
|
||||||
// todo(THIS PR): don't use a cache on failure
|
// todo(THIS PR): don't use a cache on failure
|
||||||
let check_cache =
|
let check_cache =
|
||||||
TypeCheckCache::new(&self.dir.type_checking_cache_db_file_path())?;
|
TypeCheckCache::new(&self.dir.type_checking_cache_db_file_path());
|
||||||
let graph_data = self.graph_data.clone();
|
let graph_data = self.graph_data.clone();
|
||||||
Some(tokio::task::spawn_blocking(move || {
|
Some(tokio::task::spawn_blocking(move || {
|
||||||
emit::check(&roots, graph_data, &check_cache, options)
|
emit::check(&roots, graph_data, &check_cache, options)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue