Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 3 additions & 5 deletions packages/nx/src/native/tasks/hashers/hash_runtime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,13 @@ use crate::native::hasher::hash;
use crate::native::utils::command::create_shell_command;
use dashmap::DashMap;
use std::collections::HashMap;
use std::sync::Arc;
use tracing::trace;

pub fn hash_runtime(
workspace_root: &str,
command: &str,
env: &HashMap<String, String>,
cache: Arc<DashMap<String, String>>,
cache: &DashMap<String, String>,
) -> anyhow::Result<String> {
let cache_key = runtime_cache_key(command, env);

Expand Down Expand Up @@ -51,16 +50,15 @@ mod tests {
use super::*;
use dashmap::DashMap;
use std::collections::HashMap;
use std::sync::Arc;

#[test]
fn test_hash_runtime() {
let workspace_root = if cfg!(windows) { "C:\\" } else { "/tmp" };
let command = "echo runtime";
let env: HashMap<String, String> = HashMap::new();
let cache = Arc::new(DashMap::new());
let cache = DashMap::new();

let result = hash_runtime(workspace_root, command, &env, Arc::clone(&cache)).unwrap();
let result = hash_runtime(workspace_root, command, &env, &cache).unwrap();
assert_eq!(result, "10571312846059850300");
}

Expand Down
86 changes: 61 additions & 25 deletions packages/nx/src/native/tasks/task_hasher.rs
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,14 @@ pub struct HasherOptions {
pub selectively_hash_ts_config: bool,
}

/// Cached result for project/workspace file hashing.
/// Stores both the hash value and the matched file paths (for input collection).
#[derive(Clone)]
struct CachedFileSetHash {
hash: String,
files: Vec<String>,
}

#[napi]
pub struct TaskHasher {
workspace_root: String,
Expand All @@ -150,7 +158,6 @@ pub struct TaskHasher {
root_tsconfig_path: Option<String>,
options: Option<HasherOptions>,
external_cache: Arc<DashMap<String, String>>,
runtime_cache: Arc<DashMap<String, String>>,
}
#[napi]
impl TaskHasher {
Expand Down Expand Up @@ -181,7 +188,6 @@ impl TaskHasher {
root_tsconfig_path,
options,
external_cache: Arc::new(DashMap::new()),
runtime_cache: Arc::new(DashMap::new()),
}
}

Expand All @@ -193,10 +199,13 @@ impl TaskHasher {
cwd: String,
collect_task_inputs: Option<bool>,
) -> anyhow::Result<NapiDashMap<String, HashDetails>> {
// Create a fresh task output cache for this invocation
// Create fresh caches for this invocation.
// This ensures no stale caches across multiple CLI commands when the daemon holds
// the TaskHasher instance
// the TaskHasher instance.
let task_output_cache = DashMap::new();
let runtime_cache: DashMap<String, String> = DashMap::new();
let project_file_set_cache: DashMap<String, CachedFileSetHash> = DashMap::new();
let workspace_file_set_cache: DashMap<String, CachedFileSetHash> = DashMap::new();
let should_collect_inputs = collect_task_inputs.unwrap_or(false);

let function_start = std::time::Instant::now();
Expand Down Expand Up @@ -252,6 +261,9 @@ impl TaskHasher {
sorted_externals: &sorted_externals,
selectively_hash_tsconfig,
task_output_cache: &task_output_cache,
runtime_cache: &runtime_cache,
project_file_set_cache: &project_file_set_cache,
workspace_file_set_cache: &workspace_file_set_cache,
cwd: cwd_path,
collect_inputs: should_collect_inputs,
},
Expand Down Expand Up @@ -326,6 +338,9 @@ impl TaskHasher {
sorted_externals,
selectively_hash_tsconfig,
task_output_cache,
runtime_cache,
project_file_set_cache,
workspace_file_set_cache,
cwd,
collect_inputs,
}: HashInstructionArgs,
Expand All @@ -335,29 +350,36 @@ impl TaskHasher {
let empty = HashInputsBuilder::default();
let (hash, inputs) = match instruction {
HashInstruction::WorkspaceFileSet(workspace_file_set) => {
let result = hash_workspace_files_with_inputs(
workspace_file_set,
&self.all_workspace_files,
)?;
let cache_key = instruction.to_string();
// Check cache first; clone and drop the Ref before any insert
let cached_entry = if let Some(entry) = workspace_file_set_cache.get(&cache_key) {
entry.clone()
} else {
let result = hash_workspace_files_with_inputs(
workspace_file_set,
&self.all_workspace_files,
)?;
let entry = CachedFileSetHash {
hash: result.hash,
files: result.files,
};
workspace_file_set_cache.insert(cache_key, entry.clone());
entry
};
trace!(parent: &span, "hash_workspace_files: {:?}", now.elapsed());
let inputs = if collect_inputs {
HashInputsBuilder {
files: result.files.into_iter().collect(),
files: cached_entry.files.into_iter().collect(),
..Default::default()
}
} else {
drop(result.files);
empty
};
(result.hash, inputs)
(cached_entry.hash, inputs)
}
HashInstruction::Runtime(runtime) => {
let hashed_runtime = hash_runtime(
&self.workspace_root,
runtime,
js_env,
Arc::clone(&self.runtime_cache),
)?;
let hashed_runtime =
hash_runtime(&self.workspace_root, runtime, js_env, runtime_cache)?;
trace!(parent: &span, "hash_runtime: {:?}", now.elapsed());
let inputs = if collect_inputs {
instruction.into()
Expand All @@ -383,22 +405,33 @@ impl TaskHasher {
(hashed_cwd, empty)
}
HashInstruction::ProjectFileSet(project_name, file_sets) => {
let result = hash_project_files_with_inputs(
project_name,
file_sets,
&self.project_file_map,
)?;
let cache_key = instruction.to_string();
// Check cache first; clone and drop the Ref before any insert
let cached_entry = if let Some(entry) = project_file_set_cache.get(&cache_key) {
entry.clone()
} else {
let result = hash_project_files_with_inputs(
project_name,
file_sets,
&self.project_file_map,
)?;
let entry = CachedFileSetHash {
hash: result.hash,
files: result.files,
};
project_file_set_cache.insert(cache_key, entry.clone());
entry
};
trace!(parent: &span, "hash_project_files: {:?}", now.elapsed());
let inputs = if collect_inputs {
HashInputsBuilder {
files: result.files.into_iter().collect(),
files: cached_entry.files.into_iter().collect(),
..Default::default()
}
} else {
drop(result.files);
empty
};
(result.hash, inputs)
(cached_entry.hash, inputs)
}
HashInstruction::ProjectConfiguration(project_name) => {
let hashed_project_config =
Expand Down Expand Up @@ -514,6 +547,9 @@ struct HashInstructionArgs<'a> {
sorted_externals: &'a [&'a String],
selectively_hash_tsconfig: bool,
task_output_cache: &'a DashMap<String, CachedTaskOutput>,
runtime_cache: &'a DashMap<String, String>,
project_file_set_cache: &'a DashMap<String, CachedFileSetHash>,
workspace_file_set_cache: &'a DashMap<String, CachedFileSetHash>,
cwd: &'a std::path::Path,
collect_inputs: bool,
}
Loading