Skip to content

Commit b21004b

Browse files
authored
fix: use hash of in-memory bytes only for code cache (#23966)
* denoland/deno_core#752 * denoland/deno_core#753 Did benchmarking on this and it's slightly faster (couple ms) or equal to in performance as main. Closes #23904
1 parent 92a8d09 commit b21004b

11 files changed

+93
-174
lines changed

Cargo.lock

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

Cargo.toml

+2-1
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ repository = "https://github.com/denoland/deno"
4444

4545
[workspace.dependencies]
4646
deno_ast = { version = "=0.38.2", features = ["transpiling"] }
47-
deno_core = { version = "0.282.0" }
47+
deno_core = { version = "0.283.0" }
4848

4949
deno_bench_util = { version = "0.147.0", path = "./bench_util" }
5050
deno_lockfile = "0.19.0"
@@ -174,6 +174,7 @@ tokio = { version = "1.36.0", features = ["full"] }
174174
tokio-metrics = { version = "0.3.0", features = ["rt"] }
175175
tokio-util = "0.7.4"
176176
tower-lsp = { version = "=0.20.0", features = ["proposed"] }
177+
twox-hash = "=1.6.3"
177178
# Upgrading past 2.4.1 may cause WPT failures
178179
url = { version = "< 2.5.0", features = ["serde", "expose_internals"] }
179180
uuid = { version = "1.3.0", features = ["v4"] }

cli/Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@ thiserror.workspace = true
146146
tokio.workspace = true
147147
tokio-util.workspace = true
148148
tower-lsp.workspace = true
149-
twox-hash = "=1.6.3"
149+
twox-hash.workspace = true
150150
typed-arena = "=2.0.1"
151151
uuid = { workspace = true, features = ["serde"] }
152152
walkdir = "=2.3.2"

cli/cache/code_cache.rs

+15-16
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
22

3+
use deno_ast::ModuleSpecifier;
34
use deno_core::error::AnyError;
45
use deno_runtime::code_cache;
56
use deno_runtime::deno_webstorage::rusqlite::params;
@@ -21,7 +22,6 @@ pub static CODE_CACHE_DB: CacheDBConfiguration = CacheDBConfiguration {
2122
on_failure: CacheFailure::Blackhole,
2223
};
2324

24-
#[derive(Clone)]
2525
pub struct CodeCache {
2626
inner: CodeCacheInner,
2727
}
@@ -52,28 +52,28 @@ impl CodeCache {
5252

5353
pub fn get_sync(
5454
&self,
55-
specifier: &str,
55+
specifier: &ModuleSpecifier,
5656
code_cache_type: code_cache::CodeCacheType,
57-
source_hash: &str,
57+
source_hash: u64,
5858
) -> Option<Vec<u8>> {
5959
Self::ensure_ok(self.inner.get_sync(
60-
specifier,
60+
specifier.as_str(),
6161
code_cache_type,
62-
source_hash,
62+
&source_hash.to_string(),
6363
))
6464
}
6565

6666
pub fn set_sync(
6767
&self,
68-
specifier: &str,
68+
specifier: &ModuleSpecifier,
6969
code_cache_type: code_cache::CodeCacheType,
70-
source_hash: &str,
70+
source_hash: u64,
7171
data: &[u8],
7272
) {
7373
Self::ensure_ok(self.inner.set_sync(
74-
specifier,
74+
specifier.as_str(),
7575
code_cache_type,
76-
source_hash,
76+
&source_hash.to_string(),
7777
data,
7878
));
7979
}
@@ -82,25 +82,24 @@ impl CodeCache {
8282
impl code_cache::CodeCache for CodeCache {
8383
fn get_sync(
8484
&self,
85-
specifier: &str,
85+
specifier: &ModuleSpecifier,
8686
code_cache_type: code_cache::CodeCacheType,
87-
source_hash: &str,
87+
source_hash: u64,
8888
) -> Option<Vec<u8>> {
8989
self.get_sync(specifier, code_cache_type, source_hash)
9090
}
9191

9292
fn set_sync(
9393
&self,
94-
specifier: &str,
94+
specifier: ModuleSpecifier,
9595
code_cache_type: code_cache::CodeCacheType,
96-
source_hash: &str,
96+
source_hash: u64,
9797
data: &[u8],
9898
) {
99-
self.set_sync(specifier, code_cache_type, source_hash, data);
99+
self.set_sync(&specifier, code_cache_type, source_hash, data);
100100
}
101101
}
102102

103-
#[derive(Clone)]
104103
struct CodeCacheInner {
105104
conn: CacheDB,
106105
}
@@ -135,7 +134,7 @@ impl CodeCacheInner {
135134
&self,
136135
specifier: &str,
137136
code_cache_type: code_cache::CodeCacheType,
138-
source_hash: &str,
137+
source_hash: &str, // use string because sqlite doesn't have a u64 type
139138
data: &[u8],
140139
) -> Result<(), AnyError> {
141140
let sql = "

cli/cache/module_info.rs

-17
Original file line numberDiff line numberDiff line change
@@ -87,23 +87,6 @@ impl ModuleInfoCache {
8787
}
8888
}
8989

90-
pub fn get_module_source_hash(
91-
&self,
92-
specifier: &ModuleSpecifier,
93-
media_type: MediaType,
94-
) -> Result<Option<ModuleInfoCacheSourceHash>, AnyError> {
95-
let query = "SELECT source_hash FROM moduleinfocache WHERE specifier=?1 AND media_type=?2";
96-
let res = self.conn.query_row(
97-
query,
98-
params![specifier.as_str(), serialize_media_type(media_type)],
99-
|row| {
100-
let source_hash: String = row.get(0)?;
101-
Ok(ModuleInfoCacheSourceHash(source_hash))
102-
},
103-
)?;
104-
Ok(res)
105-
}
106-
10790
pub fn get_module_info(
10891
&self,
10992
specifier: &ModuleSpecifier,

cli/factory.rs

-1
Original file line numberDiff line numberDiff line change
@@ -798,7 +798,6 @@ impl CliFactory {
798798
},
799799
self.emitter()?.clone(),
800800
self.main_module_graph_container().await?.clone(),
801-
self.module_info_cache()?.clone(),
802801
self.module_load_preparer().await?.clone(),
803802
cli_node_resolver.clone(),
804803
NpmModuleLoader::new(

cli/module_loader.rs

+28-64
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use crate::args::CliOptions;
1313
use crate::args::DenoSubcommand;
1414
use crate::args::TsTypeLib;
1515
use crate::cache::CodeCache;
16-
use crate::cache::ModuleInfoCache;
16+
use crate::cache::FastInsecureHasher;
1717
use crate::cache::ParsedSourceCache;
1818
use crate::emit::Emitter;
1919
use crate::factory::CliFactory;
@@ -55,6 +55,7 @@ use deno_core::ModuleSpecifier;
5555
use deno_core::ModuleType;
5656
use deno_core::RequestedModuleType;
5757
use deno_core::ResolutionKind;
58+
use deno_core::SourceCodeCacheInfo;
5859
use deno_core::SourceMapGetter;
5960
use deno_graph::source::ResolutionMode;
6061
use deno_graph::source::Resolver;
@@ -67,7 +68,6 @@ use deno_graph::Resolution;
6768
use deno_lockfile::Lockfile;
6869
use deno_runtime::code_cache;
6970
use deno_runtime::deno_node::NodeResolutionMode;
70-
use deno_runtime::fs_util::code_timestamp;
7171
use deno_runtime::permissions::PermissionsContainer;
7272
use deno_semver::npm::NpmPackageReqReference;
7373

@@ -221,7 +221,6 @@ struct SharedCliModuleLoaderState {
221221
code_cache: Option<Arc<CodeCache>>,
222222
emitter: Arc<Emitter>,
223223
main_module_graph_container: Arc<MainModuleGraphContainer>,
224-
module_info_cache: Arc<ModuleInfoCache>,
225224
module_load_preparer: Arc<ModuleLoadPreparer>,
226225
node_resolver: Arc<CliNodeResolver>,
227226
npm_module_loader: NpmModuleLoader,
@@ -240,7 +239,6 @@ impl CliModuleLoaderFactory {
240239
code_cache: Option<Arc<CodeCache>>,
241240
emitter: Arc<Emitter>,
242241
main_module_graph_container: Arc<MainModuleGraphContainer>,
243-
module_info_cache: Arc<ModuleInfoCache>,
244242
module_load_preparer: Arc<ModuleLoadPreparer>,
245243
node_resolver: Arc<CliNodeResolver>,
246244
npm_module_loader: NpmModuleLoader,
@@ -261,7 +259,6 @@ impl CliModuleLoaderFactory {
261259
code_cache,
262260
emitter,
263261
main_module_graph_container,
264-
module_info_cache,
265262
module_load_preparer,
266263
node_resolver,
267264
npm_module_loader,
@@ -388,27 +385,20 @@ impl<TGraphContainer: ModuleGraphContainer>
388385
}
389386

390387
let code_cache = if module_type == ModuleType::JavaScript {
391-
self.shared.code_cache.as_ref().and_then(|cache| {
392-
let code_hash = self
393-
.get_code_hash_or_timestamp(specifier, code_source.media_type)
394-
.ok()
395-
.flatten();
396-
if let Some(code_hash) = code_hash {
397-
cache
398-
.get_sync(
399-
specifier.as_str(),
400-
code_cache::CodeCacheType::EsModule,
401-
&code_hash,
402-
)
403-
.map(Cow::from)
404-
.inspect(|_| {
405-
// This log line is also used by tests.
406-
log::debug!(
407-
"V8 code cache hit for ES module: {specifier}, [{code_hash:?}]"
408-
);
409-
})
410-
} else {
411-
None
388+
self.shared.code_cache.as_ref().map(|cache| {
389+
let code_hash = FastInsecureHasher::hash(&code);
390+
let data = cache
391+
.get_sync(specifier, code_cache::CodeCacheType::EsModule, code_hash)
392+
.map(Cow::from)
393+
.inspect(|_| {
394+
// This log line is also used by tests.
395+
log::debug!(
396+
"V8 code cache hit for ES module: {specifier}, [{code_hash:?}]"
397+
);
398+
});
399+
SourceCodeCacheInfo {
400+
hash: code_hash,
401+
data,
412402
}
413403
})
414404
} else {
@@ -589,25 +579,6 @@ impl<TGraphContainer: ModuleGraphContainer>
589579
resolution.map_err(|err| err.into())
590580
}
591581

592-
fn get_code_hash_or_timestamp(
593-
&self,
594-
specifier: &ModuleSpecifier,
595-
media_type: MediaType,
596-
) -> Result<Option<String>, AnyError> {
597-
let hash = self
598-
.shared
599-
.module_info_cache
600-
.get_module_source_hash(specifier, media_type)?;
601-
if let Some(hash) = hash {
602-
return Ok(Some(hash.into()));
603-
}
604-
605-
// Use the modified timestamp from the local file system if we don't have a hash.
606-
let timestamp = code_timestamp(specifier.as_str())
607-
.map(|timestamp| timestamp.to_string())?;
608-
Ok(Some(timestamp))
609-
}
610-
611582
async fn load_prepared_module(
612583
&self,
613584
specifier: &ModuleSpecifier,
@@ -865,28 +836,21 @@ impl<TGraphContainer: ModuleGraphContainer> ModuleLoader
865836

866837
fn code_cache_ready(
867838
&self,
868-
specifier: &ModuleSpecifier,
839+
specifier: ModuleSpecifier,
840+
source_hash: u64,
869841
code_cache: &[u8],
870842
) -> Pin<Box<dyn Future<Output = ()>>> {
871843
if let Some(cache) = self.0.shared.code_cache.as_ref() {
872-
let media_type = MediaType::from_specifier(specifier);
873-
let code_hash = self
874-
.0
875-
.get_code_hash_or_timestamp(specifier, media_type)
876-
.ok()
877-
.flatten();
878-
if let Some(code_hash) = code_hash {
879-
// This log line is also used by tests.
880-
log::debug!(
881-
"Updating V8 code cache for ES module: {specifier}, [{code_hash:?}]"
882-
);
883-
cache.set_sync(
884-
specifier.as_str(),
885-
code_cache::CodeCacheType::EsModule,
886-
&code_hash,
887-
code_cache,
888-
);
889-
}
844+
// This log line is also used by tests.
845+
log::debug!(
846+
"Updating V8 code cache for ES module: {specifier}, [{source_hash:?}]"
847+
);
848+
cache.set_sync(
849+
&specifier,
850+
code_cache::CodeCacheType::EsModule,
851+
source_hash,
852+
code_cache,
853+
);
890854
}
891855
std::future::ready(()).boxed_local()
892856
}

runtime/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,7 @@ signal-hook = "0.3.17"
116116
signal-hook-registry = "1.4.0"
117117
tokio.workspace = true
118118
tokio-metrics.workspace = true
119+
twox-hash.workspace = true
119120
uuid.workspace = true
120121
which = "4.2.5"
121122

runtime/code_cache.rs

+6-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
22

3+
use deno_core::ModuleSpecifier;
4+
35
pub enum CodeCacheType {
46
EsModule,
57
Script,
@@ -17,15 +19,15 @@ impl CodeCacheType {
1719
pub trait CodeCache: Send + Sync {
1820
fn get_sync(
1921
&self,
20-
specifier: &str,
22+
specifier: &ModuleSpecifier,
2123
code_cache_type: CodeCacheType,
22-
source_hash: &str,
24+
source_hash: u64,
2325
) -> Option<Vec<u8>>;
2426
fn set_sync(
2527
&self,
26-
specifier: &str,
28+
specifier: ModuleSpecifier,
2729
code_cache_type: CodeCacheType,
28-
source_hash: &str,
30+
source_hash: u64,
2931
data: &[u8],
3032
);
3133
}

0 commit comments

Comments
 (0)