Skip to content

Commit

Permalink
refactor: improve storage error message (#8740)
Browse files Browse the repository at this point in the history
  • Loading branch information
LingyuCoder authored Dec 18, 2024
1 parent e60bd61 commit f7ba52f
Show file tree
Hide file tree
Showing 27 changed files with 1,287 additions and 872 deletions.
3 changes: 1 addition & 2 deletions crates/rspack_core/src/cache/persistent/storage/memory.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
use std::sync::{Arc, Mutex};

use rspack_error::Result;
use rspack_storage::Storage;
use rspack_storage::{Result, Storage};
use rustc_hash::FxHashMap as HashMap;
use tokio::sync::oneshot::{channel, Receiver};

Expand Down
4 changes: 2 additions & 2 deletions crates/rspack_core/src/cache/persistent/storage/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use std::{path::PathBuf, sync::Arc};
pub use memory::MemoryStorage;
use rspack_fs::IntermediateFileSystem;
pub use rspack_storage::Storage;
use rspack_storage::{PackBridgeFS, PackStorage, PackStorageOptions};
use rspack_storage::{BridgeFileSystem, PackStorage, PackStorageOptions};

/// Storage Options
///
Expand All @@ -31,7 +31,7 @@ pub fn create_storage(
bucket_size: 20,
pack_size: 500 * 1024,
expire: 7 * 24 * 60 * 60 * 1000,
fs: Arc::new(PackBridgeFS(fs)),
fs: Arc::new(BridgeFileSystem(fs)),
version,
};
Arc::new(PackStorage::new(option))
Expand Down
177 changes: 177 additions & 0 deletions crates/rspack_storage/src/error.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
use rspack_error::miette;

use crate::fs::{BatchFSError, FSError};

#[derive(Debug)]
pub struct InvalidDetail {
pub reason: String,
pub packs: Vec<String>,
}

#[derive(Debug)]
pub enum ValidateResult {
NotExists,
Valid,
Invalid(InvalidDetail),
}

impl ValidateResult {
pub fn invalid(reason: &str) -> Self {
Self::Invalid(InvalidDetail {
reason: reason.to_string(),
packs: vec![],
})
}
pub fn invalid_with_packs(reason: &str, packs: Vec<String>) -> Self {
Self::Invalid(InvalidDetail {
reason: reason.to_string(),
packs,
})
}
pub fn is_valid(&self) -> bool {
matches!(self, ValidateResult::Valid)
}
}

#[derive(Debug)]
enum ErrorReason {
Reason(String),
Detail(InvalidDetail),
Error(Box<dyn std::error::Error + Send + Sync>),
}

#[derive(Debug)]
pub enum ErrorType {
Validate,
Save,
Load,
}

impl std::fmt::Display for ErrorType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
ErrorType::Validate => write!(f, "validate"),
ErrorType::Save => write!(f, "save"),
ErrorType::Load => write!(f, "load"),
}
}
}

#[derive(Debug)]
pub struct Error {
r#type: Option<ErrorType>,
scope: Option<&'static str>,
inner: ErrorReason,
}

impl From<FSError> for Error {
fn from(e: FSError) -> Self {
Self {
r#type: None,
scope: None,
inner: ErrorReason::Error(Box::new(e)),
}
}
}

impl From<BatchFSError> for Error {
fn from(e: BatchFSError) -> Self {
Self {
r#type: None,
scope: None,
inner: ErrorReason::Error(Box::new(e)),
}
}
}

impl Error {
pub fn from_detail(
r#type: Option<ErrorType>,
scope: Option<&'static str>,
detail: InvalidDetail,
) -> Self {
Self {
r#type,
scope,
inner: ErrorReason::Detail(detail),
}
}
pub fn from_error(
r#type: Option<ErrorType>,
scope: Option<&'static str>,
error: Box<dyn std::error::Error + Send + Sync>,
) -> Self {
Self {
r#type,
scope,
inner: ErrorReason::Error(error),
}
}
pub fn from_reason(
r#type: Option<ErrorType>,
scope: Option<&'static str>,
reason: String,
) -> Self {
Self {
r#type,
scope,
inner: ErrorReason::Reason(reason),
}
}
}

impl std::fmt::Display for Error {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if let Some(t) = &self.r#type {
write!(f, "{} ", t)?;
}
if let Some(scope) = self.scope {
write!(f, "scope `{}` ", scope)?;
}
write!(f, "failed due to")?;

match &self.inner {
ErrorReason::Detail(detail) => {
write!(f, " {}", detail.reason)?;
let mut pack_info_lines = detail
.packs
.iter()
.map(|p| format!("- {}", p))
.collect::<Vec<_>>();
if pack_info_lines.len() > 5 {
pack_info_lines.truncate(5);
pack_info_lines.push("...".to_string());
}
if !pack_info_lines.is_empty() {
write!(f, ":\n{}", pack_info_lines.join("\n"))?;
}
}
ErrorReason::Error(e) => {
write!(f, " {}", e)?;
}
ErrorReason::Reason(e) => {
write!(f, " {}", e)?;
}
}
Ok(())
}
}

impl std::error::Error for Error {}

impl miette::Diagnostic for Error {
fn code<'a>(&'a self) -> Option<Box<dyn std::fmt::Display + 'a>> {
Some(Box::new(format!(
"Error::{}",
self
.r#type
.as_ref()
.map_or("".to_string(), |t| t.to_string())
)))
}
fn severity(&self) -> Option<miette::Severity> {
Some(miette::Severity::Warning)
}
}

pub type Result<T> = std::result::Result<T, Error>;
160 changes: 160 additions & 0 deletions crates/rspack_storage/src/fs/error.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
use std::io::ErrorKind;

use cow_utils::CowUtils;
use rspack_paths::Utf8Path;
use tokio::task::JoinError;

#[derive(Debug)]
pub enum FSOperation {
Read,
Write,
Dir,
Remove,
Stat,
Move,
Redirect,
}

impl std::fmt::Display for FSOperation {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Read => write!(f, "read"),
Self::Write => write!(f, "write"),
Self::Dir => write!(f, "create dir"),
Self::Remove => write!(f, "remove"),
Self::Stat => write!(f, "stat"),
Self::Move => write!(f, "move"),
Self::Redirect => write!(f, "redirect"),
}
}
}

#[derive(Debug)]
pub struct FSError {
file: String,
inner: rspack_fs::Error,
opt: FSOperation,
}

impl std::error::Error for FSError {}

impl FSError {
pub fn from_fs_error(file: &Utf8Path, opt: FSOperation, error: rspack_fs::Error) -> Self {
Self {
file: file.to_string(),
inner: error,
opt,
}
}
pub fn from_message(file: &Utf8Path, opt: FSOperation, message: String) -> Self {
Self {
file: file.to_string(),
inner: rspack_fs::Error::Io(std::io::Error::new(std::io::ErrorKind::Other, message)),
opt,
}
}
pub fn is_not_found(&self) -> bool {
if matches!(self.kind(), ErrorKind::NotFound) {
return true;
}
let error_content = self.inner.to_string();
let lower_case_error_content = error_content.cow_to_lowercase();
lower_case_error_content.contains("no such file")
|| lower_case_error_content.contains("file not exists")
}
pub fn kind(&self) -> ErrorKind {
match &self.inner {
rspack_fs::Error::Io(e) => e.kind(),
}
}
}

impl std::fmt::Display for FSError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{} `{}` failed due to `{}`",
self.opt,
self.file,
match &self.inner {
rspack_fs::Error::Io(e) => e,
}
)
}
}

#[derive(Debug)]
pub struct BatchFSError {
message: String,
join_error: Option<JoinError>,
errors: Vec<Box<dyn std::error::Error + std::marker::Send + Sync>>,
}

impl From<FSError> for BatchFSError {
fn from(error: FSError) -> Self {
Self {
message: "".to_string(),
join_error: None,
errors: vec![Box::new(error)],
}
}
}

impl std::fmt::Display for BatchFSError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.message)?;
if let Some(join_error) = &self.join_error {
write!(f, " due to `{}`", join_error)?;
}
if self.errors.len() == 1 {
write!(f, "{}", self.errors[0])?;
} else {
for error in &self.errors {
write!(f, "\n- {}", error)?;
}
}

Ok(())
}
}

impl BatchFSError {
pub fn try_from_joined_result<T: std::error::Error + std::marker::Send + Sync + 'static, R>(
message: &str,
res: Result<Vec<Result<R, T>>, JoinError>,
) -> Result<Vec<R>, Self> {
match res {
Ok(res) => Self::try_from_results(message, res),
Err(join_error) => Err(Self {
message: message.to_string(),
errors: vec![],
join_error: Some(join_error),
}),
}
}

pub fn try_from_results<T: std::error::Error + std::marker::Send + Sync + 'static, R>(
message: &str,
results: Vec<Result<R, T>>,
) -> Result<Vec<R>, Self> {
let mut errors = vec![];
let mut res = vec![];
for r in results {
match r {
Ok(r) => res.push(r),
Err(e) => errors.push(Box::new(e).into()),
}
}
if errors.is_empty() {
Ok(res)
} else {
Err(Self {
message: message.to_string(),
errors,
join_error: None,
})
}
}
}

impl std::error::Error for BatchFSError {}
Loading

2 comments on commit f7ba52f

@rspack-bot
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📝 Ran ecosystem CI: Open

suite result
modernjs ❌ failure
_selftest ✅ success
rsdoctor ❌ failure
rspress ✅ success
rslib ✅ success
rsbuild ❌ failure
examples ❌ failure
devserver ✅ success
nuxt ✅ success

@rspack-bot
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📝 Benchmark detail: Open

Name Base (2024-12-18 8a7084e) Current Change
10000_big_production-mode_disable-minimize + exec 37.9 s ± 525 ms 37.6 s ± 660 ms -0.83 %
10000_development-mode + exec 1.86 s ± 24 ms 1.84 s ± 28 ms -0.85 %
10000_development-mode_hmr + exec 683 ms ± 26 ms 690 ms ± 37 ms +1.02 %
10000_production-mode + exec 2.45 s ± 80 ms 2.41 s ± 35 ms -1.57 %
arco-pro_development-mode + exec 1.79 s ± 95 ms 1.77 s ± 79 ms -1.20 %
arco-pro_development-mode_hmr + exec 378 ms ± 1.1 ms 379 ms ± 2.7 ms +0.04 %
arco-pro_production-mode + exec 3.26 s ± 89 ms 3.26 s ± 53 ms +0.01 %
arco-pro_production-mode_generate-package-json-webpack-plugin + exec 3.32 s ± 126 ms 3.33 s ± 107 ms +0.36 %
arco-pro_production-mode_traverse-chunk-modules + exec 3.29 s ± 91 ms 3.3 s ± 54 ms +0.36 %
threejs_development-mode_10x + exec 1.64 s ± 20 ms 1.64 s ± 35 ms -0.24 %
threejs_development-mode_10x_hmr + exec 817 ms ± 17 ms 828 ms ± 33 ms +1.35 %
threejs_production-mode_10x + exec 5.4 s ± 134 ms 5.42 s ± 183 ms +0.38 %
10000_big_production-mode_disable-minimize + rss memory 9531 MiB ± 380 MiB 9478 MiB ± 112 MiB -0.56 %
10000_development-mode + rss memory 671 MiB ± 19.2 MiB 703 MiB ± 9.54 MiB +4.80 %
10000_development-mode_hmr + rss memory 1494 MiB ± 296 MiB 1585 MiB ± 242 MiB +6.09 %
10000_production-mode + rss memory 644 MiB ± 24.1 MiB 686 MiB ± 46.4 MiB +6.43 %
arco-pro_development-mode + rss memory 572 MiB ± 28.6 MiB 609 MiB ± 40.2 MiB +6.47 %
arco-pro_development-mode_hmr + rss memory 623 MiB ± 53.8 MiB 642 MiB ± 29.6 MiB +3.02 %
arco-pro_production-mode + rss memory 774 MiB ± 49.9 MiB 750 MiB ± 48.4 MiB -3.05 %
arco-pro_production-mode_generate-package-json-webpack-plugin + rss memory 752 MiB ± 54.9 MiB 756 MiB ± 59.4 MiB +0.58 %
arco-pro_production-mode_traverse-chunk-modules + rss memory 774 MiB ± 82.3 MiB 793 MiB ± 41.3 MiB +2.43 %
threejs_development-mode_10x + rss memory 654 MiB ± 29.2 MiB 685 MiB ± 34.1 MiB +4.80 %
threejs_development-mode_10x_hmr + rss memory 1203 MiB ± 127 MiB 1206 MiB ± 215 MiB +0.25 %
threejs_production-mode_10x + rss memory 971 MiB ± 66.9 MiB 984 MiB ± 42.3 MiB +1.30 %

Please sign in to comment.