Skip to content

Commit 94f040a

Browse files
authored
fix: bump cache sqlite dbs to v2 for WAL journal mode change (#24030)
In #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.
1 parent fada25b commit 94f040a

22 files changed

+347
-263
lines changed

Cargo.lock

+4-4
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

cli/Cargo.toml

+2-2
Original file line numberDiff line numberDiff line change
@@ -65,11 +65,11 @@ winres.workspace = true
6565
[dependencies]
6666
deno_ast = { workspace = true, features = ["bundler", "cjs", "codegen", "proposal", "react", "sourcemap", "transforms", "typescript", "view", "visit"] }
6767
deno_cache_dir = { workspace = true }
68-
deno_config = "=0.16.3"
68+
deno_config = "=0.16.4"
6969
deno_core = { workspace = true, features = ["include_js_files_for_snapshotting"] }
7070
deno_doc = { version = "=0.137.0", features = ["html", "syntect"] }
7171
deno_emit = "=0.41.0"
72-
deno_graph = { version = "=0.77.0", features = ["tokio_executor"] }
72+
deno_graph = { version = "=0.77.2", features = ["tokio_executor"] }
7373
deno_lint = { version = "=0.58.4", features = ["docs"] }
7474
deno_lockfile.workspace = true
7575
deno_npm = "=0.21.0"

cli/cache/cache_db.rs

+80-15
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,48 @@ use std::path::Path;
1414
use std::path::PathBuf;
1515
use std::sync::Arc;
1616

17+
use super::FastInsecureHasher;
18+
19+
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
20+
pub struct CacheDBHash(u64);
21+
22+
impl CacheDBHash {
23+
pub fn new(hash: u64) -> Self {
24+
Self(hash)
25+
}
26+
27+
pub fn from_source(source: impl std::hash::Hash) -> Self {
28+
Self::new(
29+
// always write in the deno version just in case
30+
// the clearing on deno version change doesn't work
31+
FastInsecureHasher::new_deno_versioned()
32+
.write_hashable(source)
33+
.finish(),
34+
)
35+
}
36+
}
37+
38+
impl rusqlite::types::ToSql for CacheDBHash {
39+
fn to_sql(&self) -> rusqlite::Result<rusqlite::types::ToSqlOutput<'_>> {
40+
Ok(rusqlite::types::ToSqlOutput::Owned(
41+
// sqlite doesn't support u64, but it does support i64 so store
42+
// this value "incorrectly" as i64 then convert back to u64 on read
43+
rusqlite::types::Value::Integer(self.0 as i64),
44+
))
45+
}
46+
}
47+
48+
impl rusqlite::types::FromSql for CacheDBHash {
49+
fn column_result(
50+
value: rusqlite::types::ValueRef,
51+
) -> rusqlite::types::FromSqlResult<Self> {
52+
match value {
53+
rusqlite::types::ValueRef::Integer(i) => Ok(Self::new(i as u64)),
54+
_ => Err(rusqlite::types::FromSqlError::InvalidType),
55+
}
56+
}
57+
}
58+
1759
/// What should the cache should do on failure?
1860
#[derive(Default)]
1961
pub enum CacheFailure {
@@ -41,21 +83,16 @@ pub struct CacheDBConfiguration {
4183
impl CacheDBConfiguration {
4284
fn create_combined_sql(&self) -> String {
4385
format!(
44-
"
45-
PRAGMA journal_mode=WAL;
46-
PRAGMA synchronous=NORMAL;
47-
PRAGMA temp_store=memory;
48-
PRAGMA page_size=4096;
49-
PRAGMA mmap_size=6000000;
50-
PRAGMA optimize;
51-
52-
CREATE TABLE IF NOT EXISTS info (
53-
key TEXT PRIMARY KEY,
54-
value TEXT NOT NULL
55-
);
56-
57-
{}
58-
",
86+
concat!(
87+
"PRAGMA journal_mode=WAL;",
88+
"PRAGMA synchronous=NORMAL;",
89+
"PRAGMA temp_store=memory;",
90+
"PRAGMA page_size=4096;",
91+
"PRAGMA mmap_size=6000000;",
92+
"PRAGMA optimize;",
93+
"CREATE TABLE IF NOT EXISTS info (key TEXT PRIMARY KEY, value TEXT NOT NULL);",
94+
"{}",
95+
),
5996
self.table_initializer
6097
)
6198
}
@@ -520,4 +557,32 @@ mod tests {
520557
})
521558
.expect_err("Should have failed");
522559
}
560+
561+
#[test]
562+
fn cache_db_hash_max_u64_value() {
563+
assert_same_serialize_deserialize(CacheDBHash::new(u64::MAX));
564+
assert_same_serialize_deserialize(CacheDBHash::new(u64::MAX - 1));
565+
assert_same_serialize_deserialize(CacheDBHash::new(u64::MIN));
566+
assert_same_serialize_deserialize(CacheDBHash::new(u64::MIN + 1));
567+
}
568+
569+
fn assert_same_serialize_deserialize(original_hash: CacheDBHash) {
570+
use rusqlite::types::FromSql;
571+
use rusqlite::types::ValueRef;
572+
use rusqlite::ToSql;
573+
574+
let value = original_hash.to_sql().unwrap();
575+
match value {
576+
rusqlite::types::ToSqlOutput::Owned(rusqlite::types::Value::Integer(
577+
value,
578+
)) => {
579+
let value_ref = ValueRef::Integer(value);
580+
assert_eq!(
581+
original_hash,
582+
CacheDBHash::column_result(value_ref).unwrap()
583+
);
584+
}
585+
_ => unreachable!(),
586+
}
587+
}
523588
}

cli/cache/check.rs

+31-24
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,21 @@
22

33
use super::cache_db::CacheDB;
44
use super::cache_db::CacheDBConfiguration;
5+
use super::cache_db::CacheDBHash;
56
use super::cache_db::CacheFailure;
67
use deno_ast::ModuleSpecifier;
78
use deno_core::error::AnyError;
89
use deno_runtime::deno_webstorage::rusqlite::params;
910

1011
pub static TYPE_CHECK_CACHE_DB: CacheDBConfiguration = CacheDBConfiguration {
1112
table_initializer: concat!(
12-
"CREATE TABLE IF NOT EXISTS checkcache (
13-
check_hash TEXT PRIMARY KEY
14-
);",
15-
"CREATE TABLE IF NOT EXISTS tsbuildinfo (
16-
specifier TEXT PRIMARY KEY,
17-
text TEXT NOT NULL
18-
);",
13+
"CREATE TABLE IF NOT EXISTS checkcache (",
14+
"check_hash INT PRIMARY KEY",
15+
");",
16+
"CREATE TABLE IF NOT EXISTS tsbuildinfo (",
17+
"specifier TEXT PRIMARY KEY,",
18+
"text TEXT NOT NULL",
19+
");",
1920
),
2021
on_version_change: concat!(
2122
"DELETE FROM checkcache;",
@@ -37,7 +38,7 @@ impl TypeCheckCache {
3738
Self(db)
3839
}
3940

40-
pub fn has_check_hash(&self, hash: u64) -> bool {
41+
pub fn has_check_hash(&self, hash: CacheDBHash) -> bool {
4142
match self.hash_check_hash_result(hash) {
4243
Ok(val) => val,
4344
Err(err) => {
@@ -52,14 +53,17 @@ impl TypeCheckCache {
5253
}
5354
}
5455

55-
fn hash_check_hash_result(&self, hash: u64) -> Result<bool, AnyError> {
56+
fn hash_check_hash_result(
57+
&self,
58+
hash: CacheDBHash,
59+
) -> Result<bool, AnyError> {
5660
self.0.exists(
5761
"SELECT * FROM checkcache WHERE check_hash=?1 LIMIT 1",
58-
params![hash.to_string()],
62+
params![hash],
5963
)
6064
}
6165

62-
pub fn add_check_hash(&self, check_hash: u64) {
66+
pub fn add_check_hash(&self, check_hash: CacheDBHash) {
6367
if let Err(err) = self.add_check_hash_result(check_hash) {
6468
if cfg!(debug_assertions) {
6569
panic!("Error saving check hash: {err}");
@@ -69,13 +73,16 @@ impl TypeCheckCache {
6973
}
7074
}
7175

72-
fn add_check_hash_result(&self, check_hash: u64) -> Result<(), AnyError> {
76+
fn add_check_hash_result(
77+
&self,
78+
check_hash: CacheDBHash,
79+
) -> Result<(), AnyError> {
7380
let sql = "
7481
INSERT OR REPLACE INTO
7582
checkcache (check_hash)
7683
VALUES
7784
(?1)";
78-
self.0.execute(sql, params![&check_hash.to_string(),])?;
85+
self.0.execute(sql, params![check_hash])?;
7986
Ok(())
8087
}
8188

@@ -123,10 +130,10 @@ mod test {
123130
let conn = CacheDB::in_memory(&TYPE_CHECK_CACHE_DB, "1.0.0");
124131
let cache = TypeCheckCache::new(conn);
125132

126-
assert!(!cache.has_check_hash(1));
127-
cache.add_check_hash(1);
128-
assert!(cache.has_check_hash(1));
129-
assert!(!cache.has_check_hash(2));
133+
assert!(!cache.has_check_hash(CacheDBHash::new(1)));
134+
cache.add_check_hash(CacheDBHash::new(1));
135+
assert!(cache.has_check_hash(CacheDBHash::new(1)));
136+
assert!(!cache.has_check_hash(CacheDBHash::new(2)));
130137

131138
let specifier1 = ModuleSpecifier::parse("file:///test.json").unwrap();
132139
assert_eq!(cache.get_tsbuildinfo(&specifier1), None);
@@ -137,9 +144,9 @@ mod test {
137144
let conn = cache.0.recreate_with_version("2.0.0");
138145
let cache = TypeCheckCache::new(conn);
139146

140-
assert!(!cache.has_check_hash(1));
141-
cache.add_check_hash(1);
142-
assert!(cache.has_check_hash(1));
147+
assert!(!cache.has_check_hash(CacheDBHash::new(1)));
148+
cache.add_check_hash(CacheDBHash::new(1));
149+
assert!(cache.has_check_hash(CacheDBHash::new(1)));
143150
assert_eq!(cache.get_tsbuildinfo(&specifier1), None);
144151
cache.set_tsbuildinfo(&specifier1, "test");
145152
assert_eq!(cache.get_tsbuildinfo(&specifier1), Some("test".to_string()));
@@ -148,13 +155,13 @@ mod test {
148155
let conn = cache.0.recreate_with_version("2.0.0");
149156
let cache = TypeCheckCache::new(conn);
150157

151-
assert!(cache.has_check_hash(1));
152-
assert!(!cache.has_check_hash(2));
158+
assert!(cache.has_check_hash(CacheDBHash::new(1)));
159+
assert!(!cache.has_check_hash(CacheDBHash::new(2)));
153160
assert_eq!(cache.get_tsbuildinfo(&specifier1), Some("test".to_string()));
154161

155162
// adding when already exists should not cause issue
156-
cache.add_check_hash(1);
157-
assert!(cache.has_check_hash(1));
163+
cache.add_check_hash(CacheDBHash::new(1));
164+
assert!(cache.has_check_hash(CacheDBHash::new(1)));
158165
cache.set_tsbuildinfo(&specifier1, "other");
159166
assert_eq!(
160167
cache.get_tsbuildinfo(&specifier1),

0 commit comments

Comments
 (0)