summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormo8it <mo8it@proton.me>2024-08-29 00:17:22 +0200
committermo8it <mo8it@proton.me>2024-08-29 00:17:22 +0200
commitafc320bed4ca57d19b66f9d1d33d71806f333e27 (patch)
tree549004cc8ffdad41b5f53acad1eaf6cdb58b2418
parentcba4a6f9c8f3b76ccfbf8c4c2aab6adda649df64 (diff)
Fix error about too many open files during the final check
-rw-r--r--src/app_state.rs101
1 files changed, 64 insertions, 37 deletions
diff --git a/src/app_state.rs b/src/app_state.rs
index b88c125..cc77711 100644
--- a/src/app_state.rs
+++ b/src/app_state.rs
@@ -1,8 +1,8 @@
-use anyhow::{bail, Context, Error, Result};
+use anyhow::{bail, Context, Result};
use std::{
env,
fs::{self, File},
- io::{Read, StdoutLock, Write},
+ io::{self, Read, StdoutLock, Write},
path::Path,
process::{Command, Stdio},
thread,
@@ -35,6 +35,12 @@ pub enum StateFileStatus {
NotRead,
}
+enum AllExercisesCheck {
+ Pending(usize),
+ AllDone,
+ CheckedUntil(usize),
+}
+
pub struct AppState {
current_exercise_ind: usize,
exercises: Vec<Exercise>,
@@ -340,59 +346,80 @@ impl AppState {
}
}
- /// Mark the current exercise as done and move on to the next pending exercise if one exists.
- /// If all exercises are marked as done, run all of them to make sure that they are actually
- /// done. If an exercise which is marked as done fails, mark it as pending and continue on it.
- pub fn done_current_exercise(&mut self, stdout: &mut StdoutLock) -> Result<ExercisesProgress> {
- let exercise = &mut self.exercises[self.current_exercise_ind];
- if !exercise.done {
- exercise.done = true;
- self.n_done += 1;
- }
-
- if let Some(ind) = self.next_pending_exercise_ind() {
- self.set_current_exercise_ind(ind)?;
- return Ok(ExercisesProgress::NewPending);
- }
-
+ // Return the exercise index of the first pending exercise found.
+ fn check_all_exercises(&self, stdout: &mut StdoutLock) -> Result<Option<usize>> {
stdout.write_all(RERUNNING_ALL_EXERCISES_MSG)?;
-
let n_exercises = self.exercises.len();
- let pending_exercise_ind = thread::scope(|s| {
+ let status = thread::scope(|s| {
let handles = self
.exercises
- .iter_mut()
- .map(|exercise| {
- s.spawn(|| {
- let success = exercise.run_exercise(None, &self.cmd_runner)?;
- exercise.done = success;
- Ok::<_, Error>(success)
- })
- })
+ .iter()
+ .map(|exercise| s.spawn(|| exercise.run_exercise(None, &self.cmd_runner)))
.collect::<Vec<_>>();
for (exercise_ind, handle) in handles.into_iter().enumerate() {
write!(stdout, "\rProgress: {exercise_ind}/{n_exercises}")?;
stdout.flush()?;
- let success = handle.join().unwrap()?;
+ let Ok(success) = handle.join().unwrap() else {
+ return Ok(AllExercisesCheck::CheckedUntil(exercise_ind));
+ };
+
if !success {
- stdout.write_all(b"\n\n")?;
- return Ok(Some(exercise_ind));
+ return Ok(AllExercisesCheck::Pending(exercise_ind));
}
}
- Ok::<_, Error>(None)
+ Ok::<_, io::Error>(AllExercisesCheck::AllDone)
})?;
- if let Some(pending_exercise_ind) = pending_exercise_ind {
+ let mut exercise_ind = match status {
+ AllExercisesCheck::Pending(exercise_ind) => return Ok(Some(exercise_ind)),
+ AllExercisesCheck::AllDone => return Ok(None),
+ AllExercisesCheck::CheckedUntil(ind) => ind,
+ };
+
+ // We got an error while checking all exercises in parallel.
+ // This could be because we exceeded the limit of open file descriptors.
+ // Therefore, try to continue the check sequentially.
+ for exercise in &self.exercises[exercise_ind..] {
+ write!(stdout, "\rProgress: {exercise_ind}/{n_exercises}")?;
+ stdout.flush()?;
+
+ let success = exercise.run_exercise(None, &self.cmd_runner)?;
+ if !success {
+ return Ok(Some(exercise_ind));
+ }
+
+ exercise_ind += 1;
+ }
+
+ Ok(None)
+ }
+
+ /// Mark the current exercise as done and move on to the next pending exercise if one exists.
+ /// If all exercises are marked as done, run all of them to make sure that they are actually
+ /// done. If an exercise which is marked as done fails, mark it as pending and continue on it.
+ pub fn done_current_exercise(&mut self, stdout: &mut StdoutLock) -> Result<ExercisesProgress> {
+ let exercise = &mut self.exercises[self.current_exercise_ind];
+ if !exercise.done {
+ exercise.done = true;
+ self.n_done += 1;
+ }
+
+ if let Some(ind) = self.next_pending_exercise_ind() {
+ self.set_current_exercise_ind(ind)?;
+ return Ok(ExercisesProgress::NewPending);
+ }
+
+ if let Some(pending_exercise_ind) = self.check_all_exercises(stdout)? {
+ stdout.write_all(b"\n\n")?;
+
self.current_exercise_ind = pending_exercise_ind;
- self.n_done = self
- .exercises
- .iter()
- .filter(|exercise| exercise.done)
- .count() as u16;
+ self.exercises[pending_exercise_ind].done = false;
+ // All exercises were marked as done.
+ self.n_done -= 1;
self.write()?;
return Ok(ExercisesProgress::NewPending);
}