Skip to content

Commit 3fbd440

Browse files
committed
fix: baz
1 parent 9db02d1 commit 3fbd440

File tree

2 files changed

+45
-62
lines changed

2 files changed

+45
-62
lines changed

src/cache/cache_impl.rs

Lines changed: 42 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -227,70 +227,53 @@ impl<Fs: FileSystem> Cache<Fs> {
227227
///
228228
/// <https://github.com/parcel-bundler/parcel/blob/4d27ec8b8bd1792f536811fef86e74a31fa0e704/crates/parcel-resolver/src/cache.rs#L232>
229229
pub(crate) fn canonicalize_impl(&self, path: &CachedPath) -> Result<CachedPath, ResolveError> {
230-
let mut result: Option<_> = None;
231-
while result.is_none() {
232-
result = {
233-
// Check if this thread is already canonicalizing. If so, we have found a circular symlink.
234-
// If a different thread is canonicalizing, OnceLock will queue this thread to wait for the result.
235-
let tid = THREAD_ID.with(|t| *t);
236-
if path.canonicalizing.load(Ordering::Acquire) == tid {
237-
return Err(io::Error::new(io::ErrorKind::NotFound, "Circular symlink").into());
238-
}
239-
240-
#[expect(clippy::collection_is_never_read)]
241-
let mut _temp = None;
230+
// Check if this thread is already canonicalizing. If so, we have found a circular symlink.
231+
// If a different thread is canonicalizing, OnceLock will queue this thread to wait for the result.
232+
let tid = THREAD_ID.with(|t| *t);
233+
if path.canonicalizing.load(Ordering::Acquire) == tid {
234+
return Err(io::Error::new(io::ErrorKind::NotFound, "Circular symlink").into());
235+
}
242236

243-
path.canonicalized
244-
.get_or_init(|| {
245-
path.canonicalizing.store(tid, Ordering::Release);
237+
let mut canonicalized_guard = path.canonicalized.lock().unwrap();
238+
let canonicalized = canonicalized_guard.clone()?;
239+
if let Some(cached_path) = canonicalized.upgrade() {
240+
return Ok(CachedPath(cached_path));
241+
}
246242

247-
let res = path.parent().map_or_else(
248-
|| Ok(path.normalize_root(self)),
249-
|parent| {
250-
self.canonicalize_impl(&parent).and_then(|parent_canonical| {
251-
let normalized = parent_canonical.normalize_with(
252-
path.path().strip_prefix(parent.path()).unwrap(),
253-
self,
254-
);
243+
path.canonicalizing.store(tid, Ordering::Release);
255244

256-
if self
257-
.fs
258-
.symlink_metadata(path.path())
259-
.is_ok_and(|m| m.is_symlink)
260-
{
261-
let link = self.fs.read_link(normalized.path())?;
262-
if link.is_absolute() {
263-
return self
264-
.canonicalize_impl(&self.value(&link.normalize()));
265-
} else if let Some(dir) = normalized.parent() {
266-
// Symlink is relative `../../foo.js`, use the path directory
267-
// to resolve this symlink.
268-
return self.canonicalize_impl(
269-
&dir.normalize_with(&link, self),
270-
);
271-
}
272-
debug_assert!(
273-
false,
274-
"Failed to get path parent for {}.",
275-
normalized.path().display()
276-
);
277-
}
245+
let res = path.parent().map_or_else(
246+
|| Ok(path.normalize_root(self)),
247+
|parent| {
248+
self.canonicalize_impl(&parent).and_then(|parent_canonical| {
249+
let normalized = parent_canonical
250+
.normalize_with(path.path().strip_prefix(parent.path()).unwrap(), self);
278251

279-
Ok(normalized)
280-
})
281-
},
252+
if self.fs.symlink_metadata(path.path()).is_ok_and(|m| m.is_symlink) {
253+
let link = self.fs.read_link(normalized.path())?;
254+
if link.is_absolute() {
255+
return self.canonicalize_impl(&self.value(&link.normalize()));
256+
} else if let Some(dir) = normalized.parent() {
257+
// Symlink is relative `../../foo.js`, use the path directory
258+
// to resolve this symlink.
259+
return self.canonicalize_impl(&dir.normalize_with(&link, self));
260+
}
261+
debug_assert!(
262+
false,
263+
"Failed to get path parent for {}.",
264+
normalized.path().display()
282265
);
266+
}
283267

284-
path.canonicalizing.store(0, Ordering::Release);
285-
_temp = res.as_ref().ok().map(|cp| Arc::clone(&cp.0));
286-
res.map(|cp| Arc::downgrade(&cp.0))
287-
})
288-
.as_ref()
289-
.map_err(Clone::clone)
290-
.map(|weak| weak.upgrade().map(CachedPath))
291-
.transpose()
292-
};
293-
}
294-
result.unwrap()
268+
Ok(normalized)
269+
})
270+
},
271+
);
272+
273+
path.canonicalizing.store(0, Ordering::Release);
274+
// Convert to Weak reference for storage
275+
*canonicalized_guard = res.as_ref().map_err(Clone::clone).map(|cp| Arc::downgrade(&cp.0));
276+
277+
res
295278
}
296279
}

src/cache/cached_path.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use std::{
44
hash::{Hash, Hasher},
55
ops::Deref,
66
path::{Component, Path, PathBuf},
7-
sync::{Arc, Weak, atomic::AtomicU64},
7+
sync::{Arc, Mutex, Weak, atomic::AtomicU64},
88
};
99

1010
use cfg_if::cfg_if;
@@ -27,7 +27,7 @@ pub struct CachedPathImpl {
2727
pub is_node_modules: bool,
2828
pub inside_node_modules: bool,
2929
pub meta: OnceLock<Option<FileMetadata>>,
30-
pub canonicalized: OnceLock<Result<Weak<CachedPathImpl>, ResolveError>>,
30+
pub canonicalized: Mutex<Result<Weak<CachedPathImpl>, ResolveError>>,
3131
pub canonicalizing: AtomicU64,
3232
pub node_modules: OnceLock<Option<Weak<CachedPathImpl>>>,
3333
pub package_json: OnceLock<Option<Arc<PackageJson>>>,
@@ -49,7 +49,7 @@ impl CachedPathImpl {
4949
is_node_modules,
5050
inside_node_modules,
5151
meta: OnceLock::new(),
52-
canonicalized: OnceLock::new(),
52+
canonicalized: Mutex::new(Ok(Weak::new())),
5353
canonicalizing: AtomicU64::new(0),
5454
node_modules: OnceLock::new(),
5555
package_json: OnceLock::new(),

0 commit comments

Comments
 (0)