zccache 1.11.5

Local-first compiler cache for C/C++/Rust/Emscripten
Documentation
//! Cached-hit branch controllers for the compile pipeline.

use super::super::*;
use super::cached_hit::{
    materialize_cached_compile_hit, CachedHitMaterializeRequest, CachedHitPhases,
};

pub(super) struct RequestCacheHitProbe<'a> {
    pub(super) state: &'a SharedState,
    pub(super) sid: &'a SessionId,
    pub(super) compiler_path: &'a Path,
    pub(super) effective_args: &'a [String],
    pub(super) cwd: &'a Path,
    pub(super) request_cache_key_root: &'a Option<NormalizedPath>,
    pub(super) client_env: Option<&'a [(String, String)]>,
    pub(super) compile_start: Instant,
    pub(super) snap_clock: Clock,
}

pub(super) fn try_request_cache_hit(probe: RequestCacheHitProbe<'_>) -> Option<Response> {
    let RequestCacheHitProbe {
        state,
        sid,
        compiler_path,
        effective_args,
        cwd,
        request_cache_key_root,
        client_env,
        compile_start,
        snap_clock,
    } = probe;

    if !state.watcher_active.load(Ordering::Acquire) {
        return None;
    }

    let t_request_cache_lookup = Instant::now();
    let request_fp = request_fingerprint(
        compiler_path,
        effective_args,
        cwd,
        request_cache_key_root.as_deref(),
        client_env,
    );
    let req_entry = state.request_cache.get(&request_fp)?;
    let request_cache_lookup_ns = t_request_cache_lookup.elapsed().as_nanos() as u64;
    if !request_cache_entry_matches_root(&req_entry, request_cache_key_root.as_ref()) {
        return None;
    }
    let fh_entry = state.fast_hit_cache.get(&req_entry.context_key)?;
    let artifact_key_hex = &fh_entry.artifact_key_hex;
    let source_path = req_entry
        .source_path
        .resolve(request_cache_key_root.as_deref());
    let output_path = req_entry
        .output_path
        .resolve(request_cache_key_root.as_deref());
    let same_root = req_entry.root.as_ref() == request_cache_key_root.as_ref();
    let t_cross_root_validate = Instant::now();
    let inputs_match = if same_root {
        context_files_fresh(state, &req_entry.context_key, &source_path, fh_entry.clock)
    } else {
        request_cache_artifact_matches(
            state,
            &req_entry,
            request_fp,
            request_cache_key_root.as_ref(),
            artifact_key_hex,
            compile_start,
            snap_clock,
        )
    };
    let cross_root_validate_ns = if same_root {
        0
    } else {
        t_cross_root_validate.elapsed().as_nanos() as u64
    };
    if !cache_entry_fresh_at(compile_start, fh_entry.cached_at, FAST_HIT_MAX_AGE)
        || !cache_entry_fresh_at(compile_start, req_entry.cached_at, EPHEMERAL_CACHE_MAX_AGE)
        || !inputs_match
    {
        return None;
    }

    let hit_label = if same_root {
        "HIT_REQUEST"
    } else {
        "HIT_WORKTREE_REQUEST"
    };
    materialize_cached_compile_hit(CachedHitMaterializeRequest {
        state,
        sid,
        artifact_key_hex,
        source_path: &source_path,
        output_path: &output_path,
        secondary_output_dir: output_path.parent().unwrap_or(cwd).to_path_buf(),
        compile_start,
        hit_label,
        cached_error_label: "CACHED_ERROR_REQUEST",
        record_compilation: true,
        downgrade_output_metadata: false,
        phases: CachedHitPhases::request_cache(request_cache_lookup_ns, cross_root_validate_ns),
    })
}

pub(super) struct FastHitProbe<'a> {
    pub(super) state: &'a SharedState,
    pub(super) sid: &'a SessionId,
    pub(super) context_key: ContextKey,
    pub(super) source_path: &'a NormalizedPath,
    pub(super) output_path: &'a NormalizedPath,
    pub(super) cwd_path: &'a NormalizedPath,
    pub(super) ctx: &'a CompileContext,
    pub(super) compiler_path: &'a Path,
    pub(super) effective_args: &'a [String],
    pub(super) cwd: &'a Path,
    pub(super) request_cache_key_root: &'a Option<NormalizedPath>,
    pub(super) client_env: Option<&'a [(String, String)]>,
    pub(super) is_rustc: bool,
    pub(super) worktree_equivalent_context: bool,
    pub(super) compile_start: Instant,
    pub(super) parse_args_ns: u64,
    pub(super) build_context_ns: u64,
}

pub(super) fn try_fast_hit(probe: FastHitProbe<'_>) -> Option<Response> {
    let FastHitProbe {
        state,
        sid,
        context_key,
        source_path,
        output_path,
        cwd_path,
        ctx,
        compiler_path,
        effective_args,
        cwd,
        request_cache_key_root,
        client_env,
        is_rustc,
        worktree_equivalent_context,
        compile_start,
        parse_args_ns,
        build_context_ns,
    } = probe;

    if !state.watcher_active.load(Ordering::Acquire) {
        return None;
    }
    if worktree_equivalent_context {
        // Cross-worktree hits may be the first time this daemon has seen the
        // current root's source paths. Until that root has gone through a
        // miss path and installed directory watches, keep using the hashed
        // depgraph path instead of the zero-hash fast-hit cache.
        return None;
    }
    let entry = state.fast_hit_cache.get(&context_key)?;
    if !cache_entry_fresh_at(compile_start, entry.cached_at, FAST_HIT_MAX_AGE)
        || !context_files_fresh(state, &context_key, source_path, entry.clock)
    {
        return None;
    }

    let secondary_output_dir = if is_rustc {
        output_path.parent().unwrap_or(cwd_path).to_path_buf()
    } else {
        cwd_path.clone().to_path_buf()
    };
    let hit_label = if worktree_equivalent_context {
        "HIT_WORKTREE_FAST"
    } else {
        "HIT_FAST"
    };
    let response = materialize_cached_compile_hit(CachedHitMaterializeRequest {
        state,
        sid,
        artifact_key_hex: &entry.artifact_key_hex,
        source_path,
        output_path,
        secondary_output_dir,
        compile_start,
        hit_label,
        cached_error_label: "CACHED_ERROR_FAST",
        record_compilation: false,
        downgrade_output_metadata: true,
        phases: CachedHitPhases {
            parse_args_ns,
            build_context_ns,
            hash_source_ns: 0,
            hash_headers_ns: 0,
            depgraph_check_ns: 0,
            request_cache_lookup_ns: 0,
            cross_root_validate_ns: 0,
        },
    })?;

    let rfp = request_fingerprint(
        compiler_path,
        effective_args,
        cwd,
        request_cache_key_root.as_deref(),
        client_env,
    );
    let input_paths = request_cache_input_paths(state, &context_key, source_path, ctx);
    state.request_cache.insert(
        rfp,
        request_cache_entry(
            context_key,
            source_path,
            output_path,
            input_paths,
            request_cache_key_root.as_ref(),
        ),
    );
    Some(response)
}

pub(super) struct DepgraphHitProbe<'a> {
    pub(super) state: &'a SharedState,
    pub(super) sid: &'a SessionId,
    pub(super) context_key: ContextKey,
    pub(super) artifact_key_hex: &'a str,
    pub(super) source_path: &'a NormalizedPath,
    pub(super) output_path: &'a NormalizedPath,
    pub(super) cwd_path: &'a NormalizedPath,
    pub(super) ctx: &'a CompileContext,
    pub(super) compiler_path: &'a Path,
    pub(super) effective_args: &'a [String],
    pub(super) cwd: &'a Path,
    pub(super) request_cache_key_root: &'a Option<NormalizedPath>,
    pub(super) client_env: Option<&'a [(String, String)]>,
    pub(super) is_rustc: bool,
    pub(super) worktree_equivalent_context: bool,
    pub(super) compile_start: Instant,
    pub(super) parse_args_ns: u64,
    pub(super) build_context_ns: u64,
    pub(super) hash_source_ns: u64,
    pub(super) hash_headers_ns: u64,
    pub(super) depgraph_check_ns: u64,
}

pub(super) fn try_depgraph_cached_hit(probe: DepgraphHitProbe<'_>) -> Option<Response> {
    let DepgraphHitProbe {
        state,
        sid,
        context_key,
        artifact_key_hex,
        source_path,
        output_path,
        cwd_path,
        ctx,
        compiler_path,
        effective_args,
        cwd,
        request_cache_key_root,
        client_env,
        is_rustc,
        worktree_equivalent_context,
        compile_start,
        parse_args_ns,
        build_context_ns,
        hash_source_ns,
        hash_headers_ns,
        depgraph_check_ns,
    } = probe;

    let secondary_output_dir = if is_rustc {
        output_path.parent().unwrap_or(cwd_path).to_path_buf()
    } else {
        cwd_path.clone().to_path_buf()
    };
    let hit_label = if worktree_equivalent_context {
        "HIT_WORKTREE"
    } else {
        "HIT"
    };
    let response = materialize_cached_compile_hit(CachedHitMaterializeRequest {
        state,
        sid,
        artifact_key_hex,
        source_path,
        output_path,
        secondary_output_dir,
        compile_start,
        hit_label,
        cached_error_label: "CACHED_ERROR",
        record_compilation: false,
        downgrade_output_metadata: true,
        phases: CachedHitPhases {
            parse_args_ns,
            build_context_ns,
            hash_source_ns,
            hash_headers_ns,
            depgraph_check_ns,
            request_cache_lookup_ns: 0,
            cross_root_validate_ns: 0,
        },
    })?;

    if !worktree_equivalent_context {
        let input_paths = request_cache_input_paths(state, &context_key, source_path, ctx);
        state.cache_system.register_tracked(&input_paths);
        let current_clock = state.cache_system.current_clock();
        state.fast_hit_cache.insert(
            context_key,
            FastHitEntry {
                clock: current_clock,
                artifact_key_hex: artifact_key_hex.to_string(),
                cached_at: Instant::now(),
            },
        );

        let rfp = request_fingerprint(
            compiler_path,
            effective_args,
            cwd,
            request_cache_key_root.as_deref(),
            client_env,
        );
        state.request_cache.insert(
            rfp,
            request_cache_entry(
                context_key,
                source_path,
                output_path,
                input_paths,
                request_cache_key_root.as_ref(),
            ),
        );
    }
    Some(response)
}