0
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2025-02-08 07:16:56 -05:00

fix: do not log cache creation failure on readonly file system (#27794)

This commit is contained in:
David Sherret 2025-01-23 11:33:24 -05:00 committed by Bartek Iwańczuk
parent e01719ba60
commit f81debe9f6
No known key found for this signature in database
GPG key ID: 0C6BCDDC3B3AD750

64
cli/cache/cache_db.rs vendored
View file

@ -232,7 +232,7 @@ impl CacheDB {
config: &CacheDBConfiguration,
conn: &Connection,
version: &str,
) -> Result<(), AnyError> {
) -> Result<(), rusqlite::Error> {
let sql = config.create_combined_sql();
conn.execute_batch(&sql)?;
@ -265,7 +265,7 @@ impl CacheDB {
fn open_connection_and_init(
&self,
path: Option<&Path>,
) -> Result<Connection, AnyError> {
) -> Result<Connection, rusqlite::Error> {
let conn = self.actually_open_connection(path)?;
Self::initialize_connection(self.config, &conn, self.version)?;
Ok(conn)
@ -368,7 +368,9 @@ impl CacheDB {
fn open_connection(
config: &CacheDBConfiguration,
path: Option<&Path>,
open_connection_and_init: impl Fn(Option<&Path>) -> Result<Connection, AnyError>,
open_connection_and_init: impl Fn(
Option<&Path>,
) -> Result<Connection, rusqlite::Error>,
) -> Result<ConnectionState, AnyError> {
// Success on first try? We hope that this is the case.
let err = match open_connection_and_init(path) {
@ -379,9 +381,20 @@ fn open_connection(
let Some(path) = path.as_ref() else {
// If an in-memory DB fails, that's game over
log::error!("Failed to initialize in-memory cache database.");
return Err(err);
return Err(err.into());
};
// reduce logging for readonly file system
if let rusqlite::Error::SqliteFailure(ffi_err, _) = &err {
if ffi_err.code == rusqlite::ErrorCode::ReadOnly {
log::debug!(
"Failed creating cache db. Folder readonly: {}",
path.display()
);
return handle_failure_mode(config, err, open_connection_and_init);
}
}
// ensure the parent directory exists
if let Some(parent) = path.parent() {
match std::fs::create_dir_all(parent) {
@ -410,10 +423,11 @@ fn open_connection(
// Failed, try deleting it
let is_tty = std::io::stderr().is_terminal();
log::log!(
if is_tty { log::Level::Warn } else { log::Level::Trace },
"Could not initialize cache database '{}', deleting and retrying... ({err:?})",
path.to_string_lossy()
);
if is_tty { log::Level::Warn } else { log::Level::Trace },
"Could not initialize cache database '{}', deleting and retrying... ({err:?})",
path.to_string_lossy()
);
if std::fs::remove_file(path).is_ok() {
// Try a third time if we successfully deleted it
let res = open_connection_and_init(Some(path));
@ -422,6 +436,11 @@ fn open_connection(
};
}
log_failure_mode(path, is_tty, config);
handle_failure_mode(config, err, open_connection_and_init)
}
fn log_failure_mode(path: &Path, is_tty: bool, config: &CacheDBConfiguration) {
match config.on_failure {
CacheFailure::InMemory => {
log::log!(
@ -431,9 +450,8 @@ fn open_connection(
log::Level::Trace
},
"Failed to open cache file '{}', opening in-memory cache.",
path.to_string_lossy()
path.display()
);
Ok(ConnectionState::Connected(open_connection_and_init(None)?))
}
CacheFailure::Blackhole => {
log::log!(
@ -443,23 +461,36 @@ fn open_connection(
log::Level::Trace
},
"Failed to open cache file '{}', performance may be degraded.",
path.to_string_lossy()
path.display()
);
Ok(ConnectionState::Blackhole)
}
CacheFailure::Error => {
log::error!(
"Failed to open cache file '{}', expect further errors.",
path.to_string_lossy()
path.display()
);
Err(err)
}
}
}
fn handle_failure_mode(
config: &CacheDBConfiguration,
err: rusqlite::Error,
open_connection_and_init: impl Fn(
Option<&Path>,
) -> Result<Connection, rusqlite::Error>,
) -> Result<ConnectionState, AnyError> {
match config.on_failure {
CacheFailure::InMemory => {
Ok(ConnectionState::Connected(open_connection_and_init(None)?))
}
CacheFailure::Blackhole => Ok(ConnectionState::Blackhole),
CacheFailure::Error => Err(err.into()),
}
}
#[cfg(test)]
mod tests {
use deno_core::anyhow::anyhow;
use test_util::TempDir;
use super::*;
@ -520,7 +551,8 @@ mod tests {
let path = temp_dir.path().join("data").to_path_buf();
let state = open_connection(&TEST_DB, Some(path.as_path()), |maybe_path| {
match maybe_path {
Some(_) => Err(anyhow!("fail")),
// this error was chosen because it was an error easy to construct
Some(_) => Err(rusqlite::Error::SqliteSingleThreadedMode),
None => Ok(Connection::open_in_memory().unwrap()),
}
})