Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
30 changes: 18 additions & 12 deletions src/commands/bootstrap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -145,12 +145,15 @@ pub fn new_engine() -> anyhow::Result<(Arc<engine::Engine>, ShutdownTrigger)> {

// Opt-in factories — instantiated by `apply_config` if listed in the YAML.
e.register_provider_factory("buildfile", |init, opts| {
Ok(Box::new(pluginbuildfile::Provider::from_options(
init.root.to_path_buf(),
&init.skip_dirs,
&init.skip_globs,
opts,
)?))
Ok(Box::new(
pluginbuildfile::Provider::from_options(
init.root.to_path_buf(),
&init.skip_dirs,
&init.skip_globs,
opts,
)?
.with_walker(init.walker.clone()),
))
})?;
e.register_provider_factory("go", |init, opts| {
Ok(Box::new(plugingo::Provider::from_options(
Expand Down Expand Up @@ -268,12 +271,15 @@ mod tests {
})?;

e.register_provider_factory("buildfile", |init, opts| {
Ok(Box::new(pluginbuildfile::Provider::from_options(
init.root.to_path_buf(),
&init.skip_dirs,
&init.skip_globs,
opts,
)?))
Ok(Box::new(
pluginbuildfile::Provider::from_options(
init.root.to_path_buf(),
&init.skip_dirs,
&init.skip_globs,
opts,
)?
.with_walker(init.walker.clone()),
))
})?;
e.register_managed_driver_factory("exec", |_init, opts| {
Ok(Box::new(pluginexec::Driver::from_options_exec(opts)?))
Expand Down
23 changes: 21 additions & 2 deletions src/engine/engine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,8 @@ pub struct PluginInit {
/// Workspace-relative `fs.skip` glob patterns (e.g. `**/node_modules/**`),
/// matched against entry paths.
pub skip_globs: Vec<String>,
/// Shared cross-run filesystem-walk cache for tree-walking plugins.
pub walker: Arc<crate::htwalk::CachedWalker>,
}

/// True if `entry` contains wax glob metacharacters — used to split `fs.skip`
Expand Down Expand Up @@ -132,6 +134,9 @@ pub struct Engine {
/// memory and never touch the SQLite WAL; entries over the per-entry cap
/// spill to `local_cache`. See [`LocalCacheTmp`].
pub(crate) local_cache_tmp: Arc<dyn LocalCache>,
/// Shared cross-run filesystem-walk cache (separate `fswalk.db`), handed to
/// tree-walking plugins via [`PluginInit`].
pub(crate) walker: Arc<crate::htwalk::CachedWalker>,

pub(crate) providers: Vec<Arc<Provider>>,
pub(crate) providers_by_name: HashMap<String, Arc<Provider>>,
Expand Down Expand Up @@ -400,13 +405,20 @@ impl Engine {
.with_context(|| format!("create lock dir {lock_dir:?}"))?;
let result_lock = ResultLock::new(cfg.lock_backend, lock_dir);

// Shared cross-run filesystem-walk cache, handed to tree-walking plugins
// via `PluginInit`. Its own sqlite db so it can be pruned independently.
let walker = Arc::new(crate::htwalk::CachedWalker::open(
&home.join("cache").join("fswalk.db"),
));

let max_workers = 2 * parallelism;

let mut engine = Engine {
cfg: cfg.clone(),
home: home.clone(),
local_cache,
local_cache_tmp,
walker,
providers: vec![],
providers_by_name: HashMap::new(),
drivers: vec![],
Expand All @@ -433,14 +445,20 @@ impl Engine {
&init.skip_dirs,
&init.skip_globs,
)?);
Ok(Box::new(crate::pluginfs::Provider::new(ignore)))
Ok(Box::new(crate::pluginfs::Provider::new(
ignore,
init.walker.clone(),
)))
})?;
engine.try_register_driver(|init| {
let ignore = Arc::new(crate::htwalk::Ignore::new(
&init.skip_dirs,
&init.skip_globs,
)?);
Ok(Box::new(crate::pluginfs::Driver::new(ignore)))
Ok(Box::new(crate::pluginfs::Driver::new(
ignore,
init.walker.clone(),
)))
})?;

Ok(engine)
Expand Down Expand Up @@ -507,6 +525,7 @@ impl Engine {
root: self.cfg.root.clone(),
skip_dirs: self.skip_dirs(),
skip_globs: self.skip_globs(),
walker: self.walker.clone(),
}
}

Expand Down
14 changes: 14 additions & 0 deletions src/engine/gc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ pub struct GcStats {
/// Targets that could not be processed (resolve/delete failed). GC logs each
/// and keeps going — a single bad target never aborts the sweep.
pub errored: usize,
/// Rows pruned from the shared filesystem-walk cache (stale past the TTL or
/// orphaned because their path no longer exists).
pub fswalk_rows_removed: usize,
}

/// Per-target result of a GC pass, accumulated into [`GcStats`].
Expand Down Expand Up @@ -226,6 +229,17 @@ impl Engine {
Self::drain_one(&mut set, &rs, &mut stats).await;
}

// Prune the shared filesystem-walk cache: drop rows untouched past the
// TTL and rows whose path no longer exists. Best-effort — a prune failure
// never fails the artifact GC.
let walker = self.walker.clone();
match crate::process_supervisor::block_or_inline(move || {
walker.prune(crate::htwalk::cached_walker::DEFAULT_TTL, true)
}) {
Ok(n) => stats.fswalk_rows_removed = n,
Err(e) => tracing::warn!(error = %format!("{e:#}"), "fswalk prune failed"),
}

Ok(stats)
}

Expand Down
Loading
Loading