Skip to content

Commit 6ede983

Browse files
ualtinokalfonso-aft
andcommitted
mason: bound watcher callgraph drain work
Co-authored-by: Alfonso <289616620+alfonso-aft@users.noreply.github.com>
1 parent 29db5b6 commit 6ede983

2 files changed

Lines changed: 454 additions & 77 deletions

File tree

crates/aft/src/callgraph_store/mod.rs

Lines changed: 79 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -701,39 +701,52 @@ impl CallGraphStore {
701701
callgraph_dir: PathBuf,
702702
project_root: PathBuf,
703703
) -> Result<Option<Self>> {
704-
Self::open_ready_with_rebuild_policy(callgraph_dir, project_root, true)
704+
Self::open_ready_with_rebuild_policy(callgraph_dir, project_root, true, true, true)
705+
}
706+
707+
/// Open a ready store for bounded maintenance work without repairing root
708+
/// metadata or starting a cold rebuild. A store that needs either action is
709+
/// reported as unavailable so a background build can own that work.
710+
pub fn open_ready(callgraph_dir: PathBuf, project_root: PathBuf) -> Result<Option<Self>> {
711+
Self::open_ready_with_rebuild_policy(callgraph_dir, project_root, false, false, false)
705712
}
706713

707714
pub fn open_ready_no_rebuild(
708715
callgraph_dir: PathBuf,
709716
project_root: PathBuf,
710717
) -> Result<Option<Self>> {
711-
Self::open_ready_with_rebuild_policy(callgraph_dir, project_root, false)
718+
Self::open_ready_with_rebuild_policy(callgraph_dir, project_root, false, true, true)
712719
}
713720

714721
fn open_ready_with_rebuild_policy(
715722
callgraph_dir: PathBuf,
716723
project_root: PathBuf,
717724
allow_cold_build: bool,
725+
allow_root_repair: bool,
726+
allow_borrow_only: bool,
718727
) -> Result<Option<Self>> {
719728
let project_key = crate::search_index::artifact_cache_key(&project_root);
720729
let Some(writer_lease) = acquire_writer_lease(&callgraph_dir, &project_key, &project_root)?
721730
else {
731+
if !allow_borrow_only {
732+
return Ok(None);
733+
}
722734
return Self::open_readonly(callgraph_dir, project_root)
723735
.map(|store| store.map(ReadonlyCallGraphStore::into_inner));
724736
};
725737
let Some((sqlite_path, generation)) = resolve_ready_target(&callgraph_dir, &project_key)
726738
else {
727739
return Ok(None);
728740
};
729-
let OpenedStore { store, root_repair } = Self::open_at_path(
741+
let OpenedStore { store, root_repair } = Self::open_at_path_with_root_repair(
730742
project_root.clone(),
731743
project_key,
732744
sqlite_path,
733745
generation,
734746
true,
735747
Some(Arc::clone(&writer_lease)),
736748
None,
749+
allow_root_repair,
737750
)?;
738751
match root_repair {
739752
OpenRootRepair::NeedsRebuild { .. } if allow_cold_build => {
@@ -1052,6 +1065,28 @@ impl CallGraphStore {
10521065
use_wal: bool,
10531066
writer_lease: Option<Arc<crate::root_cache::WriterLease>>,
10541067
read_marker: Option<crate::root_cache::ReadMarker>,
1068+
) -> Result<OpenedStore> {
1069+
Self::open_at_path_with_root_repair(
1070+
project_root,
1071+
project_key,
1072+
sqlite_path,
1073+
generation,
1074+
use_wal,
1075+
writer_lease,
1076+
read_marker,
1077+
true,
1078+
)
1079+
}
1080+
1081+
fn open_at_path_with_root_repair(
1082+
project_root: PathBuf,
1083+
project_key: String,
1084+
sqlite_path: PathBuf,
1085+
generation: Option<String>,
1086+
use_wal: bool,
1087+
writer_lease: Option<Arc<crate::root_cache::WriterLease>>,
1088+
read_marker: Option<crate::root_cache::ReadMarker>,
1089+
allow_root_repair: bool,
10551090
) -> Result<OpenedStore> {
10561091
if let Some(lease) = writer_lease.as_ref() {
10571092
verify_writer_lease(lease)?;
@@ -1072,7 +1107,7 @@ impl CallGraphStore {
10721107
if let Some(lease) = writer_lease.as_ref() {
10731108
verify_writer_lease(lease)?;
10741109
}
1075-
let root_repair = reconcile_workspace_roots(&mut conn, &project_root)?;
1110+
let root_repair = reconcile_workspace_roots(&mut conn, &project_root, allow_root_repair)?;
10761111
let read_marker = match (read_marker, generation.as_deref(), sqlite_path.parent()) {
10771112
(Some(marker), _, _) => Some(marker),
10781113
(None, Some(label), Some(cache_dir)) => {
@@ -4091,7 +4126,11 @@ const STORE_DATA_PATH_COLUMNS: &[(&str, &str)] = &[
40914126
/// opener. That can make each clone rebuild on open when they alternate — bounded
40924127
/// by open frequency — but each rebuild is correct for its opener, unlike silent
40934128
/// cross-clone corruption.
4094-
fn reconcile_workspace_roots(conn: &mut Connection, project_root: &Path) -> Result<OpenRootRepair> {
4129+
fn reconcile_workspace_roots(
4130+
conn: &mut Connection,
4131+
project_root: &Path,
4132+
allow_repair: bool,
4133+
) -> Result<OpenRootRepair> {
40954134
let roots = stored_workspace_roots(conn)?;
40964135
let current_root = project_root.display().to_string();
40974136
if roots.is_empty() || (roots.len() == 1 && roots[0] == current_root) {
@@ -4122,6 +4161,14 @@ fn reconcile_workspace_roots(conn: &mut Connection, project_root: &Path) -> Resu
41224161
}
41234162
}
41244163

4164+
if !allow_repair {
4165+
return Ok(OpenRootRepair::NeedsRebuild {
4166+
previous_roots: roots,
4167+
current_root,
4168+
reason: "workspace root metadata requires deferred repair".to_string(),
4169+
});
4170+
}
4171+
41254172
let tx = conn.transaction()?;
41264173
tx.execute(
41274174
"UPDATE OR IGNORE backend_file_state
@@ -8945,6 +8992,33 @@ mod cold_build_insert_tests {
89458992
use std::path::{Path, PathBuf};
89468993
use tempfile::tempdir;
89478994

8995+
#[test]
8996+
fn nonrepairing_open_policy_leaves_moved_root_metadata_for_maintenance() {
8997+
let dir = tempdir().unwrap();
8998+
let previous_root = dir.path().join("previous-root");
8999+
let current_root = dir.path().join("current-root");
9000+
fs::create_dir_all(&previous_root).unwrap();
9001+
fs::create_dir_all(&current_root).unwrap();
9002+
fs::remove_dir(&previous_root).unwrap();
9003+
let mut conn = Connection::open_in_memory().unwrap();
9004+
initialize_schema(&conn).unwrap();
9005+
conn.execute(
9006+
"INSERT INTO backend_file_state(
9007+
backend, workspace_root, file_path, content_hash, status, updated_at
9008+
) VALUES ('rust', ?1, 'src/main.rs', 'hash', 'ready', 1)",
9009+
params![previous_root.display().to_string()],
9010+
)
9011+
.unwrap();
9012+
9013+
let repair = reconcile_workspace_roots(&mut conn, &current_root, false).unwrap();
9014+
9015+
assert!(matches!(repair, OpenRootRepair::NeedsRebuild { .. }));
9016+
assert_eq!(
9017+
stored_workspace_roots(&conn).unwrap(),
9018+
vec![previous_root.display().to_string()]
9019+
);
9020+
}
9021+
89489022
#[test]
89499023
fn sqlite_readonly_uri_percent_encodes_windows_paths() {
89509024
assert_eq!(

0 commit comments

Comments
 (0)