fix: Fix parallel locking when -Zfine-grain-locking is enabled

This commit replaces a `Mutex` with an `RwLock` lock to avoid holding a
mutex guard while waiting on a file lock. Instead we hold a read guard
which allows multiple threads to access the `HashMap` inside of
`LockManager`.
This commit is contained in:
Ross Sullivan 2026-02-20 22:44:58 +09:00
parent 21ac09614f
commit 31d3b42857
No known key found for this signature in database
GPG Key ID: A7D198C212395322

View File

@ -10,19 +10,19 @@ use std::{
collections::HashMap,
fmt::{Display, Formatter},
path::PathBuf,
sync::Mutex,
sync::RwLock,
};
use tracing::instrument;
/// A struct to store the lock handles for build units during compilation.
pub struct LockManager {
locks: Mutex<HashMap<LockKey, FileLock>>,
locks: RwLock<HashMap<LockKey, FileLock>>,
}
impl LockManager {
pub fn new() -> Self {
Self {
locks: Mutex::new(HashMap::new()),
locks: RwLock::new(HashMap::new()),
}
}
@ -41,7 +41,7 @@ impl LockManager {
let key = LockKey::from_unit(build_runner, unit);
tracing::Span::current().record("key", key.0.to_str());
let mut locks = self.locks.lock().unwrap();
let mut locks = self.locks.write().unwrap();
if let Some(lock) = locks.get_mut(&key) {
lock.file().lock_shared()?;
} else {
@ -60,8 +60,8 @@ impl LockManager {
#[instrument(skip(self))]
pub fn lock(&self, key: &LockKey) -> CargoResult<()> {
let mut locks = self.locks.lock().unwrap();
if let Some(lock) = locks.get_mut(&key) {
let locks = self.locks.read().unwrap();
if let Some(lock) = locks.get(&key) {
lock.file().lock()?;
} else {
bail!("lock was not found in lock manager: {key}");
@ -73,8 +73,8 @@ impl LockManager {
/// Upgrades an existing exclusive lock into a shared lock.
#[instrument(skip(self))]
pub fn downgrade_to_shared(&self, key: &LockKey) -> CargoResult<()> {
let mut locks = self.locks.lock().unwrap();
let Some(lock) = locks.get_mut(key) else {
let locks = self.locks.read().unwrap();
let Some(lock) = locks.get(key) else {
bail!("lock was not found in lock manager: {key}");
};
lock.file().lock_shared()?;
@ -83,8 +83,8 @@ impl LockManager {
#[instrument(skip(self))]
pub fn unlock(&self, key: &LockKey) -> CargoResult<()> {
let mut locks = self.locks.lock().unwrap();
if let Some(lock) = locks.get_mut(key) {
let locks = self.locks.read().unwrap();
if let Some(lock) = locks.get(key) {
lock.file().unlock()?;
};