Skip to content

Commit 2e2c19c

Browse files
NSoiffercursoragent
andcommitted
Serialize rules unzip and YAML reads during parallel tests
Co-authored-by: Cursor <cursoragent@cursor.com>
1 parent 786d058 commit 2e2c19c

2 files changed

Lines changed: 30 additions & 8 deletions

File tree

‎src/prefs.rs‎

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ use std::cell::RefCell;
2626
use std::rc::Rc;
2727
use log::{debug, error, warn};
2828
use std::path::{Path, PathBuf};
29-
use std::sync::{LazyLock, Mutex};
29+
use std::sync::LazyLock;
3030
use crate::speech::{as_str_checked, RulesFor, FileAndTime};
3131
use std::collections::{HashMap, HashSet};
3232
use phf::phf_set;
@@ -458,10 +458,6 @@ impl PreferenceManager {
458458
/// Unzip the files if needed
459459
/// Returns true if it unzipped them
460460
pub fn unzip_files(path: &Path, lang: &str, default_lang: Option<&str>) -> Result<bool> {
461-
// cargo test runs many threads against the same Rules/ tree. Extracting en.zip
462-
// concurrently can truncate unicode.yaml and yaml-rust then reports "Didn't find rules!".
463-
static UNZIP_LOCK: Mutex<()> = Mutex::new(());
464-
let _guard = UNZIP_LOCK.lock().unwrap_or_else(|poisoned| poisoned.into_inner());
465461
return PreferenceManager::unzip_files_locked(path, lang, default_lang);
466462
}
467463

‎src/shim_filesystem.rs‎

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -361,15 +361,40 @@ cfg_if! {
361361
}
362362
}
363363

364+
// Tests extract language/braille zips in parallel. During extraction, individual YAML
365+
// files can briefly exist in a partially-written state (created/truncated before the
366+
// full contents are flushed). Guard both extraction and YAML reads with the same lock
367+
// so readers never observe truncated YAML.
368+
use std::sync::Mutex;
369+
static RULES_ZIP_EXTRACT_LOCK: Mutex<()> = Mutex::new(());
370+
371+
fn should_lock_rules_yaml_path(path: &Path) -> bool {
372+
let s = path.to_string_lossy();
373+
let is_yaml = s.ends_with(".yaml") || s.ends_with(".yml");
374+
if !is_yaml {
375+
return false;
376+
}
377+
return s.contains("Rules/Languages/") || s.contains("Rules\\Languages\\")
378+
|| s.contains("Rules/Braille/") || s.contains("Rules\\Braille\\");
379+
}
380+
364381
pub fn read_to_string_shim(path: &Path) -> Result<String> {
365382
let path = match path.canonicalize() {
366383
Ok(path) => path,
367384
Err(_) => path.to_path_buf(),
368385
};
369386
debug!("Reading file '{}'", path.display());
370-
match std::fs::read_to_string(&path) {
371-
Ok(str) => return Ok(str),
372-
Err(e) => bail!("Read error while trying to read {}: {}", path.display(), e),
387+
if should_lock_rules_yaml_path(&path) {
388+
let _guard = RULES_ZIP_EXTRACT_LOCK.lock().unwrap_or_else(|poisoned| poisoned.into_inner());
389+
match std::fs::read_to_string(&path) {
390+
Ok(str) => return Ok(str),
391+
Err(e) => bail!("Read error while trying to read {}: {}", path.display(), e),
392+
}
393+
} else {
394+
match std::fs::read_to_string(&path) {
395+
Ok(str) => return Ok(str),
396+
Err(e) => bail!("Read error while trying to read {}: {}", path.display(), e),
397+
}
373398
}
374399
}
375400

@@ -386,6 +411,7 @@ cfg_if! {
386411
}
387412
},
388413
Ok(contents) => {
414+
let _guard = RULES_ZIP_EXTRACT_LOCK.lock().unwrap_or_else(|poisoned| poisoned.into_inner());
389415
let archive = std::io::Cursor::new(contents);
390416
let mut zip_archive = zip::ZipArchive::new(archive).unwrap();
391417
zip_archive.extract(dir).expect("Zip extraction failed");

0 commit comments

Comments
 (0)