Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(error): simplify all boxed error wrapper definition #13725

Merged
merged 13 commits into from
Dec 1, 2023

Conversation

BugenZhao
Copy link
Member

@BugenZhao BugenZhao commented Nov 29, 2023

I hereby agree to the terms of the RisingWave Labs, Inc. Contributor License Agreement.

What's changed and what's your intention?

Follow up of #13200. Close #13215.

Use thiserror_ext::Box to define the boxed types. Introduce thiserror_ext::Arc to wrap the error in Arc, which implements Clone.

Also refactor some constructors with thiserror_ext::Construct.

Important

This PR also removes all manual Debug implementations for these error wrappers. As explained in #13264, we should now prefer calling as_report or to_report_string before printing the error out, instead of embedding the source chain or backtrace directly in Display or Debug implementation.

As a result, Debug of these error types behaves as the default derive, which means that it's not human-readable anymore and does not print the backtrace of inner error. Previously, they were used by developers for debugging purposes. To fix that, we might have to review all usages of error logging and replace them with thiserror_ext::Report.

Checklist

  • I have written necessary rustdoc comments
  • I have added necessary unit tests and integration tests
  • All checks passed in ./risedev check (or alias, ./risedev c)

Documentation

  • My PR needs documentation updates. (Please use the Release note section below to summarize the impact on users)

Release note

If this PR includes changes that directly affect users or other significant modifications relevant to the community, kindly draft a release note to provide a concise summary of these changes. Please prioritize highlighting the impact these changes will have on users.

Signed-off-by: Bugen Zhao <i@bugenzhao.com>
Signed-off-by: Bugen Zhao <i@bugenzhao.com>
Signed-off-by: Bugen Zhao <i@bugenzhao.com>
Signed-off-by: Bugen Zhao <i@bugenzhao.com>
Signed-off-by: Bugen Zhao <i@bugenzhao.com>
Signed-off-by: Bugen Zhao <i@bugenzhao.com>
Signed-off-by: Bugen Zhao <i@bugenzhao.com>
Signed-off-by: Bugen Zhao <i@bugenzhao.com>
Signed-off-by: Bugen Zhao <i@bugenzhao.com>
@@ -80,7 +79,8 @@ pub struct NotImplemented {
pub issue: TrackingIssue,
}

#[derive(Error, Debug)]
#[derive(Error, Debug, Box)]
#[thiserror_ext(type = RwError, backtrace)]
Copy link
Member Author

@BugenZhao BugenZhao Nov 29, 2023

Choose a reason for hiding this comment

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

backtrace here means that a backtrace will be generated if the inner error does not provide one.

https://docs.rs/thiserror-ext/0.0.9/src/thiserror_ext/backtrace.rs.html#26-41

/// Capture backtrace if the error does not already have one.
pub struct MaybeBacktrace(Option<Backtrace>);

impl WithBacktrace for MaybeBacktrace {
    fn capture(inner: &dyn std::error::Error) -> Self {
        let inner = if std::error::request_ref::<Backtrace>(inner).is_none() {
            Some(Backtrace::capture())
        } else {
            None
        };
        Self(inner)
    }

    fn provide<'a>(&'a self, request: &mut std::error::Request<'a>) {
        if let Some(backtrace) = &self.0 {
            request.provide_ref(backtrace);
        }
    }
}

Copy link
Member

Choose a reason for hiding this comment

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

nit: would it be better to let it be like

Suggested change
#[thiserror_ext(type = RwError, backtrace)]
#[thiserror_ext(boxed = RwError, backtrace)]

since thiserror_ext does many other things besides boxing

Copy link
Member

Choose a reason for hiding this comment

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

Oh, but we now also have Arc 😕

Copy link
Contributor

@wangrunji0408 wangrunji0408 left a comment

Choose a reason for hiding this comment

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

LGTM!

Copy link
Member

@xxchan xxchan left a comment

Choose a reason for hiding this comment

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

As a result, we might have to review all (important) usages of error logging and replace them with thiserror_ext::Report.

You reminds me of the nightmare of #11288 🤡

Copy link
Member

@yezizp2012 yezizp2012 left a comment

Choose a reason for hiding this comment

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

LGTM

Comment on lines -340 to -350
impl Debug for RwError {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{}\n{}",
self.inner,
// Use inner error's backtrace by default, otherwise use the generated one in `From`.
std::error::request_ref::<Backtrace>(&self.inner).unwrap_or(&*self.backtrace)
)
}
}
Copy link
Member

Choose a reason for hiding this comment

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

Is this part the user-facing change? i.e., "As a result, we might have to review all (important) usages of error logging and replace them with thiserror_ext::Report."

Can you elaborate a bit more about the changes?

Copy link
Member Author

Choose a reason for hiding this comment

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

Strictly speaking it's not as the only user-facing part is the psql interface. However, it really impacts the developing/debugging experience as we print logs for errors. 😕

Copy link
Member

Choose a reason for hiding this comment

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

By "user-facing" I don't mean end-user, but just wanted to know what's the behavior change.

Copy link
Member

Choose a reason for hiding this comment

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

i.e., for users of the error type. Is Display and/or Debug and/or other things changed.

Copy link
Member

Choose a reason for hiding this comment

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

Just want to confirm that so that we can better evaluate the radius of influence

Copy link
Member

@xxchan xxchan Nov 29, 2023

Choose a reason for hiding this comment

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

I'm not blocking this PR if Debug is not readable now. Either change to report or impl better Debug in the future is OK to me.

But I'd like to double-confirm these (even if I feel it's the case):

  • Debug is loseless
  • Display is not changed

If so, I think we won't have the aws-sdk surprise again.

Copy link
Member Author

Choose a reason for hiding this comment

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

IIRC anyhow's Debug is still relatively pretty

This is true but I'm not sure whether we should adopt the same idea. anyhow::Error can be used throughout an application, so developers may get used to the debug formatting and use it everywhere.

However, not all errors are wrapped with new types in RisingWave, and developers may also log the external errors directly. That is to say, developers still have to choose different formatting based on the concrete type. In this sense, as_report can be a more unified solution.

Copy link
Member Author

@BugenZhao BugenZhao Dec 1, 2023

Choose a reason for hiding this comment

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

  • Display is not changed

Yes.

  • Debug is loseless

I guess it's lossy. Backtrace is lost and it'll use the derived Debug impl. However I suddenly realize that the refactor does not conflict with customized Debug implementation. Let's revert it now and redo it after #13750.

Copy link
Member Author

@BugenZhao BugenZhao Dec 1, 2023

Choose a reason for hiding this comment

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

UPDATE:

Although I don't quite like it, I have introduced a flag called report_debug to forward the Debug impl of the newtype to its thiserror_ext::Report. In this case the backtrace is still retained.

#[derive(Error, Debug, Box)]
#[thiserror_ext(newtype(name = RwError, backtrace, report_debug))]
pub enum ErrorCode {

This should be considered as a temporary solution as I believe the Debug formatting of errors are abused. Let's depend on #13750 to get them reviewed.

Copy link
Member

Choose a reason for hiding this comment

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

My point is that: in the perfect world, Debug should never be used at all! But in fact developers are not knowledgeable or careful enough, so they may misuse Debug. That's why I think Debug should contain enough information - to make it more foolproof. Not that related with the difference between application and library.

@BugenZhao
Copy link
Member Author

You reminds me of the nightmare of #11288 🤡

I'm exploring whether we can detect them with custom compiler lints. 😕

@xxchan
Copy link
Member

xxchan commented Nov 29, 2023

You reminds me of the nightmare of #11288 🤡

I'm exploring whether we can detect them with custom compiler lints. 😕

Do you want rust-lang/rust-clippy#8581? 🤪

Copy link

codecov bot commented Nov 29, 2023

Codecov Report

Attention: 36 lines in your changes are missing coverage. Please review.

Comparison is base (7677abc) 68.21% compared to head (b2e5cba) 68.26%.

Files Patch % Lines
src/meta/src/controller/cluster.rs 16.66% 5 Missing ⚠️
src/meta/src/error.rs 20.00% 4 Missing ⚠️
src/meta/src/manager/catalog/mod.rs 0.00% 3 Missing ⚠️
src/meta/src/manager/cluster.rs 0.00% 3 Missing ⚠️
src/meta/src/manager/system_param/mod.rs 0.00% 2 Missing ⚠️
src/meta/src/rpc/ddl_controller.rs 0.00% 2 Missing ⚠️
src/source/src/connector_source.rs 0.00% 2 Missing ⚠️
src/storage/src/hummock/error.rs 50.00% 2 Missing ⚠️
src/storage/src/hummock/sstable_store.rs 86.66% 2 Missing ⚠️
src/common/src/error.rs 66.66% 1 Missing ⚠️
... and 10 more
Additional details and impacted files
@@            Coverage Diff             @@
##             main   #13725      +/-   ##
==========================================
+ Coverage   68.21%   68.26%   +0.04%     
==========================================
  Files        1524     1524              
  Lines      262499   262221     -278     
==========================================
- Hits       179074   179014      -60     
+ Misses      83425    83207     -218     
Flag Coverage Δ
rust 68.26% <42.85%> (+0.04%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

Signed-off-by: Bugen Zhao <i@bugenzhao.com>
Signed-off-by: Bugen Zhao <i@bugenzhao.com>
@BugenZhao BugenZhao requested a review from xxchan December 1, 2023 12:58
@BugenZhao BugenZhao added this pull request to the merge queue Dec 1, 2023
Merged via the queue into main with commit b149c67 Dec 1, 2023
27 of 28 checks passed
@BugenZhao BugenZhao deleted the bz/more-thiserror-ext branch December 1, 2023 13:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

error-handling: simplify boxed error definition
4 participants