Replace `Mutex<RefCell>` with `Mutex` in vendored file system" (#12170)

This commit is contained in:
Micha Reiser 2024-07-03 15:12:13 +02:00 committed by GitHub
parent 47eb6ee42b
commit b950a6c389
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
1 changed files with 20 additions and 44 deletions

View File

@ -1,5 +1,4 @@
use std::borrow::Cow; use std::borrow::Cow;
use std::cell::RefCell;
use std::collections::BTreeMap; use std::collections::BTreeMap;
use std::fmt::{self, Debug}; use std::fmt::{self, Debug};
use std::io::{self, Read}; use std::io::{self, Read};
@ -13,6 +12,7 @@ pub use path::{VendoredPath, VendoredPathBuf};
pub mod path; pub mod path;
type Result<T> = io::Result<T>; type Result<T> = io::Result<T>;
type LockedZipArchive<'a> = MutexGuard<'a, VendoredZipArchive>;
/// File system that stores all content in a static zip archive /// File system that stores all content in a static zip archive
/// bundled as part of the Ruff binary. /// bundled as part of the Ruff binary.
@ -20,20 +20,19 @@ type Result<T> = io::Result<T>;
/// "Files" in the `VendoredFileSystem` are read-only and immutable. /// "Files" in the `VendoredFileSystem` are read-only and immutable.
/// Directories are supported, but symlinks and hardlinks cannot exist. /// Directories are supported, but symlinks and hardlinks cannot exist.
pub struct VendoredFileSystem { pub struct VendoredFileSystem {
inner: VendoredFileSystemInner, inner: Mutex<VendoredZipArchive>,
} }
impl VendoredFileSystem { impl VendoredFileSystem {
pub fn new(raw_bytes: &'static [u8]) -> Result<Self> { pub fn new(raw_bytes: &'static [u8]) -> Result<Self> {
Ok(Self { Ok(Self {
inner: VendoredFileSystemInner::new(raw_bytes)?, inner: Mutex::new(VendoredZipArchive::new(raw_bytes)?),
}) })
} }
pub fn exists(&self, path: &VendoredPath) -> bool { pub fn exists(&self, path: &VendoredPath) -> bool {
let normalized = NormalizedVendoredPath::from(path); let normalized = NormalizedVendoredPath::from(path);
let inner_locked = self.inner.lock(); let mut archive = self.lock_archive();
let mut archive = inner_locked.borrow_mut();
// Must probe the zipfile twice, as "stdlib" and "stdlib/" are considered // Must probe the zipfile twice, as "stdlib" and "stdlib/" are considered
// different paths in a zip file, but we want to abstract over that difference here // different paths in a zip file, but we want to abstract over that difference here
@ -47,13 +46,12 @@ impl VendoredFileSystem {
pub fn metadata(&self, path: &VendoredPath) -> Option<Metadata> { pub fn metadata(&self, path: &VendoredPath) -> Option<Metadata> {
let normalized = NormalizedVendoredPath::from(path); let normalized = NormalizedVendoredPath::from(path);
let inner_locked = self.inner.lock(); let mut archive = self.lock_archive();
// Must probe the zipfile twice, as "stdlib" and "stdlib/" are considered // Must probe the zipfile twice, as "stdlib" and "stdlib/" are considered
// different paths in a zip file, but we want to abstract over that difference here // different paths in a zip file, but we want to abstract over that difference here
// so that paths relative to the `VendoredFileSystem` // so that paths relative to the `VendoredFileSystem`
// work the same as other paths in Ruff. // work the same as other paths in Ruff.
let mut archive = inner_locked.borrow_mut();
if let Ok(zip_file) = archive.lookup_path(&normalized) { if let Ok(zip_file) = archive.lookup_path(&normalized) {
return Some(Metadata::from_zip_file(zip_file)); return Some(Metadata::from_zip_file(zip_file));
} }
@ -71,46 +69,45 @@ impl VendoredFileSystem {
/// - The path exists in the underlying zip archive, but represents a directory /// - The path exists in the underlying zip archive, but represents a directory
/// - The contents of the zip file at `path` contain invalid UTF-8 /// - The contents of the zip file at `path` contain invalid UTF-8
pub fn read(&self, path: &VendoredPath) -> Result<String> { pub fn read(&self, path: &VendoredPath) -> Result<String> {
let inner_locked = self.inner.lock(); let mut archive = self.lock_archive();
let mut archive = inner_locked.borrow_mut();
let mut zip_file = archive.lookup_path(&NormalizedVendoredPath::from(path))?; let mut zip_file = archive.lookup_path(&NormalizedVendoredPath::from(path))?;
let mut buffer = String::new(); let mut buffer = String::new();
zip_file.read_to_string(&mut buffer)?; zip_file.read_to_string(&mut buffer)?;
Ok(buffer) Ok(buffer)
} }
/// Acquire a lock on the underlying zip archive.
/// The call will block until it is able to acquire the lock.
///
/// ## Panics:
/// If the current thread already holds the lock.
fn lock_archive(&self) -> LockedZipArchive {
self.inner.lock().unwrap()
}
} }
impl fmt::Debug for VendoredFileSystem { impl fmt::Debug for VendoredFileSystem {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let locked_inner = self.inner.lock(); let mut archive = self.lock_archive();
if f.alternate() { if f.alternate() {
let mut paths: Vec<String> = locked_inner let mut paths: Vec<String> = archive.0.file_names().map(String::from).collect();
.borrow()
.0
.file_names()
.map(String::from)
.collect();
paths.sort(); paths.sort();
let debug_info: BTreeMap<String, ZipFileDebugInfo> = paths let debug_info: BTreeMap<String, ZipFileDebugInfo> = paths
.iter() .iter()
.map(|path| { .map(|path| {
( (
path.to_owned(), path.to_owned(),
ZipFileDebugInfo::from(locked_inner.borrow_mut().0.by_name(path).unwrap()), ZipFileDebugInfo::from(archive.0.by_name(path).unwrap()),
) )
}) })
.collect(); .collect();
f.debug_struct("VendoredFileSystem") f.debug_struct("VendoredFileSystem")
.field("inner_mutex_poisoned", &self.inner.0.is_poisoned()) .field("inner_mutex_poisoned", &self.inner.is_poisoned())
.field("paths", &paths) .field("paths", &paths)
.field("data_by_path", &debug_info) .field("data_by_path", &debug_info)
.finish() .finish()
} else { } else {
write!( write!(f, "VendoredFileSystem(<{} paths>)", archive.len())
f,
"VendoredFileSystem(<{} paths>)",
locked_inner.borrow().len()
)
} }
} }
} }
@ -196,27 +193,6 @@ impl Metadata {
} }
} }
struct VendoredFileSystemInner(Mutex<RefCell<VendoredZipArchive>>);
type LockedZipArchive<'a> = MutexGuard<'a, RefCell<VendoredZipArchive>>;
impl VendoredFileSystemInner {
fn new(raw_bytes: &'static [u8]) -> Result<Self> {
Ok(Self(Mutex::new(RefCell::new(VendoredZipArchive::new(
raw_bytes,
)?))))
}
/// Acquire a lock on the underlying zip archive.
/// The call will block until it is able to acquire the lock.
///
/// ## Panics:
/// If the current thread already holds the lock.
fn lock(&self) -> LockedZipArchive {
self.0.lock().unwrap()
}
}
/// Newtype wrapper around a ZipArchive. /// Newtype wrapper around a ZipArchive.
#[derive(Debug)] #[derive(Debug)]
struct VendoredZipArchive(ZipArchive<io::Cursor<&'static [u8]>>); struct VendoredZipArchive(ZipArchive<io::Cursor<&'static [u8]>>);