diff options
author | David Sherret <dsherret@users.noreply.github.com> | 2024-05-29 14:38:18 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-05-29 18:38:18 +0000 |
commit | 94f040ac2867706d261e2fe1ec8bc2c4263eb6ab (patch) | |
tree | 5eaed4d41efd8d25da839bc29b8d32554e1a0fca /cli/cache/cache_db.rs | |
parent | fada25b0dd593efee496dabb48ed9cb7a9cb6647 (diff) |
fix: bump cache sqlite dbs to v2 for WAL journal mode change (#24030)
In https://github.com/denoland/deno/pull/23955 we changed the sqlite db
journal mode to WAL. This causes issues when someone is running an old
version of Deno using TRUNCATE and a new version because the two fight
against each other.
Diffstat (limited to 'cli/cache/cache_db.rs')
-rw-r--r-- | cli/cache/cache_db.rs | 95 |
1 files changed, 80 insertions, 15 deletions
diff --git a/cli/cache/cache_db.rs b/cli/cache/cache_db.rs index d9cead720..856587292 100644 --- a/cli/cache/cache_db.rs +++ b/cli/cache/cache_db.rs @@ -14,6 +14,48 @@ use std::path::Path; use std::path::PathBuf; use std::sync::Arc; +use super::FastInsecureHasher; + +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +pub struct CacheDBHash(u64); + +impl CacheDBHash { + pub fn new(hash: u64) -> Self { + Self(hash) + } + + pub fn from_source(source: impl std::hash::Hash) -> Self { + Self::new( + // always write in the deno version just in case + // the clearing on deno version change doesn't work + FastInsecureHasher::new_deno_versioned() + .write_hashable(source) + .finish(), + ) + } +} + +impl rusqlite::types::ToSql for CacheDBHash { + fn to_sql(&self) -> rusqlite::Result<rusqlite::types::ToSqlOutput<'_>> { + Ok(rusqlite::types::ToSqlOutput::Owned( + // sqlite doesn't support u64, but it does support i64 so store + // this value "incorrectly" as i64 then convert back to u64 on read + rusqlite::types::Value::Integer(self.0 as i64), + )) + } +} + +impl rusqlite::types::FromSql for CacheDBHash { + fn column_result( + value: rusqlite::types::ValueRef, + ) -> rusqlite::types::FromSqlResult<Self> { + match value { + rusqlite::types::ValueRef::Integer(i) => Ok(Self::new(i as u64)), + _ => Err(rusqlite::types::FromSqlError::InvalidType), + } + } +} + /// What should the cache should do on failure? #[derive(Default)] pub enum CacheFailure { @@ -41,21 +83,16 @@ pub struct CacheDBConfiguration { impl CacheDBConfiguration { fn create_combined_sql(&self) -> String { format!( - " - PRAGMA journal_mode=WAL; - PRAGMA synchronous=NORMAL; - PRAGMA temp_store=memory; - PRAGMA page_size=4096; - PRAGMA mmap_size=6000000; - PRAGMA optimize; - - CREATE TABLE IF NOT EXISTS info ( - key TEXT PRIMARY KEY, - value TEXT NOT NULL - ); - - {} - ", + concat!( + "PRAGMA journal_mode=WAL;", + "PRAGMA synchronous=NORMAL;", + "PRAGMA temp_store=memory;", + "PRAGMA page_size=4096;", + "PRAGMA mmap_size=6000000;", + "PRAGMA optimize;", + "CREATE TABLE IF NOT EXISTS info (key TEXT PRIMARY KEY, value TEXT NOT NULL);", + "{}", + ), self.table_initializer ) } @@ -520,4 +557,32 @@ mod tests { }) .expect_err("Should have failed"); } + + #[test] + fn cache_db_hash_max_u64_value() { + assert_same_serialize_deserialize(CacheDBHash::new(u64::MAX)); + assert_same_serialize_deserialize(CacheDBHash::new(u64::MAX - 1)); + assert_same_serialize_deserialize(CacheDBHash::new(u64::MIN)); + assert_same_serialize_deserialize(CacheDBHash::new(u64::MIN + 1)); + } + + fn assert_same_serialize_deserialize(original_hash: CacheDBHash) { + use rusqlite::types::FromSql; + use rusqlite::types::ValueRef; + use rusqlite::ToSql; + + let value = original_hash.to_sql().unwrap(); + match value { + rusqlite::types::ToSqlOutput::Owned(rusqlite::types::Value::Integer( + value, + )) => { + let value_ref = ValueRef::Integer(value); + assert_eq!( + original_hash, + CacheDBHash::column_result(value_ref).unwrap() + ); + } + _ => unreachable!(), + } + } } |