Skip to content

Commit a21ecb4

Browse files
committed
building entries while parallel traversing
1 parent 2cd3e87 commit a21ecb4

File tree

2 files changed

+39
-17
lines changed

2 files changed

+39
-17
lines changed

src/project_builder.rs

Lines changed: 38 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use std::{
44
sync::{Arc, Mutex},
55
};
66

7-
use error_stack::{Result, ResultExt};
7+
use error_stack::{Report, Result, ResultExt};
88
use fast_glob::glob_match;
99
use ignore::{WalkBuilder, WalkParallel, WalkState};
1010
use rayon::iter::{IntoParallelIterator, ParallelIterator};
@@ -51,53 +51,75 @@ impl<'a> ProjectBuilder<'a> {
5151

5252
#[instrument(level = "debug", skip_all)]
5353
pub fn build(&mut self) -> Result<Project, Error> {
54-
let mut entry_types = Vec::with_capacity(INITIAL_VECTOR_CAPACITY);
5554
let mut builder = WalkBuilder::new(&self.base_path);
5655
builder.hidden(false);
5756
let walk_parallel: WalkParallel = builder.build_parallel();
5857

59-
let collected = Arc::new(Mutex::new(Vec::with_capacity(INITIAL_VECTOR_CAPACITY)));
60-
let collected_for_threads = Arc::clone(&collected);
58+
let collected_entry_types = Arc::new(Mutex::new(Vec::with_capacity(INITIAL_VECTOR_CAPACITY)));
59+
let collected_for_threads = Arc::clone(&collected_entry_types);
60+
let error_holder: Arc<Mutex<Option<Report<Error>>>> = Arc::new(Mutex::new(None));
61+
let error_holder_for_threads = Arc::clone(&error_holder);
62+
63+
let this: &ProjectBuilder<'a> = self;
6164

6265
walk_parallel.run(move || {
6366
let collected = Arc::clone(&collected_for_threads);
67+
let error_holder = Arc::clone(&error_holder_for_threads);
6468
Box::new(move |res| {
6569
if let Ok(entry) = res {
66-
if let Ok(mut v) = collected.lock() {
67-
v.push(entry);
70+
match this.build_entry_type(entry) {
71+
Ok(entry_type) => {
72+
if let Ok(mut v) = collected.lock() {
73+
v.push(entry_type);
74+
}
75+
}
76+
Err(report) => {
77+
if let Ok(mut slot) = error_holder.lock() {
78+
if slot.is_none() {
79+
*slot = Some(report);
80+
}
81+
}
82+
}
6883
}
6984
}
7085
WalkState::Continue
7186
})
7287
});
7388

74-
// Process sequentially with &mut self without panicking on Arc/Mutex unwraps
75-
let collected_entries = match Arc::try_unwrap(collected) {
76-
// We are the sole owner of the Arc
89+
// Take ownership of the collected entry types
90+
let entry_types = match Arc::try_unwrap(collected_entry_types) {
7791
Ok(mutex) => match mutex.into_inner() {
78-
// Mutex not poisoned
7992
Ok(entries) => entries,
80-
// Recover entries even if the mutex was poisoned
8193
Err(poisoned) => poisoned.into_inner(),
8294
},
83-
// There are still other Arc references; lock and take the contents
8495
Err(arc) => match arc.lock() {
8596
Ok(mut guard) => std::mem::take(&mut *guard),
86-
// Recover guard even if poisoned, then take contents
8797
Err(poisoned) => {
8898
let mut guard = poisoned.into_inner();
8999
std::mem::take(&mut *guard)
90100
}
91101
},
92102
};
93-
for entry in collected_entries {
94-
entry_types.push(self.build_entry_type(entry)?);
103+
104+
// If any error occurred while building entry types, return it
105+
let maybe_error = match Arc::try_unwrap(error_holder) {
106+
Ok(mutex) => match mutex.into_inner() {
107+
Ok(err_opt) => err_opt,
108+
Err(poisoned) => poisoned.into_inner(),
109+
},
110+
Err(arc) => match arc.lock() {
111+
Ok(mut guard) => guard.take(),
112+
Err(poisoned) => poisoned.into_inner().take(),
113+
},
114+
};
115+
if let Some(report) = maybe_error {
116+
return Err(report);
95117
}
96118

97119
self.build_project_from_entry_types(entry_types)
98120
}
99121

100-
fn build_entry_type(&mut self, entry: ignore::DirEntry) -> Result<EntryType, Error> {
122+
fn build_entry_type(&self, entry: ignore::DirEntry) -> Result<EntryType, Error> {
101123
let absolute_path = entry.path();
102124

103125
let is_dir = entry.file_type().ok_or(Error::Io).change_context(Error::Io)?.is_dir();

src/project_file_builder.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ impl<'a> ProjectFileBuilder<'a> {
2121
Self { global_cache }
2222
}
2323

24-
pub(crate) fn build(&mut self, path: PathBuf) -> ProjectFile {
24+
pub(crate) fn build(&self, path: PathBuf) -> ProjectFile {
2525
if let Ok(Some(cached_project_file)) = self.get_project_file_from_cache(&path) {
2626
return cached_project_file;
2727
}

0 commit comments

Comments
 (0)