use super::*;
pub(super) fn persist_workers_default() -> usize {
if let Ok(v) = std::env::var("ZCCACHE_STORE_WORKERS") {
if let Ok(n) = v.parse::<usize>() {
if n >= 1 {
return n.min(1024);
}
}
}
#[cfg(windows)]
{
8
}
#[cfg(not(windows))]
{
let parallelism = std::thread::available_parallelism()
.map(|n| n.get())
.unwrap_or(8);
parallelism.saturating_mul(2).max(32)
}
}
pub(super) fn hash_file_via_cache(state: &SharedState, path: &Path) -> Option<ContentHash> {
if let Ok(hash) = state.cache_system.metadata().lookup(path) {
return Some(hash);
}
crate::daemon_core::hash::hash_file(path).ok()
}
pub(super) fn hash_normalized_file_via_cache(
state: &SharedState,
path: &NormalizedPath,
) -> Option<ContentHash> {
if let Ok(hash) = state.cache_system.metadata().lookup_normalized(path) {
return Some(hash);
}
crate::daemon_core::hash::hash_file(path).ok()
}
pub(super) fn hash_file(
cache_system: &CacheSystem,
path: &Path,
clock: Clock,
) -> Result<ContentHash, String> {
let lookup_path = path_for_cache_lookup(path);
cache_system
.lookup_since(&NormalizedPath::new(lookup_path.as_ref()), clock)
.map(|r| r.hash)
.map_err(|e| format!("{}: {e}", path.display()))
}
fn path_for_cache_lookup(path: &Path) -> std::borrow::Cow<'_, Path> {
#[cfg(windows)]
{
use std::os::windows::ffi::{OsStrExt, OsStringExt};
if !path.as_os_str().as_encoded_bytes().starts_with(br"\\?\") {
return std::borrow::Cow::Borrowed(path);
}
let encoded: Vec<u16> = path.as_os_str().encode_wide().collect();
let ascii_eq = |value: u16, uppercase: u8| {
value == u16::from(uppercase) || value == u16::from(uppercase.to_ascii_lowercase())
};
let is_unc = encoded.len() >= 8
&& ascii_eq(encoded[4], b'U')
&& ascii_eq(encoded[5], b'N')
&& ascii_eq(encoded[6], b'C')
&& encoded[7] == b'\\' as u16;
let normalized = if is_unc {
let mut result = vec![b'\\' as u16, b'\\' as u16];
result.extend_from_slice(&encoded[8..]);
Some(result)
} else if encoded.len() >= 6
&& encoded[4] <= 0x7f
&& (encoded[4] as u8).is_ascii_alphabetic()
&& encoded[5] == b':' as u16
{
Some(encoded[4..].to_vec())
} else {
None
};
if let Some(normalized) = normalized {
return std::borrow::Cow::Owned(PathBuf::from(std::ffi::OsString::from_wide(
&normalized,
)));
}
}
std::borrow::Cow::Borrowed(path)
}
pub(super) fn context_files_fresh(
state: &SharedState,
context_key: &ContextKey,
source_path: &Path,
since: Clock,
) -> bool {
let journal = state.cache_system.journal();
if journal.changed_since(&source_path.into(), since) {
return false;
}
if let Some(includes) = state.dep_graph.load().get_includes(context_key) {
for header in &includes {
if journal.changed_since(header, since) {
return false;
}
}
}
if let Some(externs) = state.dep_graph.load().get_rustc_externs(context_key) {
for (_, path) in &externs {
if journal.changed_since(path, since) {
return false;
}
}
}
true
}
pub(super) fn context_files_and_env_fresh(
state: &SharedState,
context_key: &ContextKey,
source_path: &Path,
since: Clock,
client_env: Option<&[(String, String)]>,
) -> bool {
if !context_env_deps_fresh(state, context_key, client_env) {
return false;
}
context_files_fresh(state, context_key, source_path, since)
}
pub(super) fn context_env_deps_fresh(
state: &SharedState,
context_key: &ContextKey,
client_env: Option<&[(String, String)]>,
) -> bool {
let Some(deps) = state.dep_graph.load().get_rustc_env_deps(context_key) else {
return true;
};
deps.iter().all(|(name, recorded_hash)| {
let current = client_env
.and_then(|env| env.iter().find(|(k, _)| k == name))
.map(|(_, v)| v.as_str());
crate::daemon_core::depgraph::hash_env_dep_value(current) == *recorded_hash
})
}
pub(super) fn lookup_artifact_with_disk_fallback<'a>(
state: &'a SharedState,
key_hex: &str,
) -> Option<dashmap::mapref::one::RefMut<'a, String, CachedArtifact>> {
if let Some(entry) = state.artifacts.get_mut(key_hex) {
return Some(entry);
}
if !state
.artifact_store_loaded
.load(std::sync::atomic::Ordering::Acquire)
{
let _ = state.artifact_store.load_from_disk();
state
.artifact_store_loaded
.store(true, std::sync::atomic::Ordering::Release);
}
let meta = state.artifact_store.get(key_hex)?;
state
.artifacts
.insert(key_hex.to_string(), CachedArtifact::from_index(meta));
state.artifacts.get_mut(key_hex)
}
#[cfg(all(test, windows))]
mod tests {
use super::*;
use std::os::windows::ffi::{OsStrExt, OsStringExt};
#[test]
fn cache_lookup_path_strips_windows_verbatim_prefix() {
let input = Path::new(r"\\?\C:\workspace\clippy.toml");
assert_eq!(
path_for_cache_lookup(input).as_ref(),
Path::new(r"C:\workspace\clippy.toml")
);
let unc = Path::new(r"\\?\UNC\server\share\clippy.toml");
assert_eq!(
path_for_cache_lookup(unc).as_ref(),
Path::new(r"\\server\share\clippy.toml")
);
let encoded = [
b'\\' as u16,
b'\\' as u16,
b'?' as u16,
b'\\' as u16,
b'C' as u16,
b':' as u16,
b'\\' as u16,
0xd800,
];
let non_unicode = PathBuf::from(std::ffi::OsString::from_wide(&encoded));
assert_eq!(
path_for_cache_lookup(&non_unicode)
.as_os_str()
.encode_wide()
.collect::<Vec<_>>(),
encoded[4..]
);
}
}