-
Notifications
You must be signed in to change notification settings - Fork 3
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
Replace anyhow with thiserror #115
base: master
Are you sure you want to change the base?
Conversation
After fixing the divergence between |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great work! I added some messaging clarifications. Would you be up for rebasing onto current master?
banyan/src/store/mem_store.rs
Outdated
pub fn into_inner(self) -> anyhow::Result<FnvHashMap<L, Box<[u8]>>> { | ||
let inner = Arc::try_unwrap(self.0).map_err(|_| anyhow!("busy"))?; | ||
pub fn into_inner(self) -> Result<FnvHashMap<L, Box<[u8]>>, Error> { | ||
let inner = Arc::try_unwrap(self.0).map_err(|_| Error::Busy)?; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This could be made clearer, for example Error::MemStore("multiple strong references")
banyan/src/store/mem_store.rs
Outdated
let digest = (self.0.digest)(&data); | ||
let len = data.len(); | ||
let mut blocks = self.0.blocks.lock(); | ||
if blocks.current_size + data.len() > self.0.max_size { | ||
anyhow::bail!("full"); | ||
return Err(Error::Full) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
… then this one could be Error::MemStore("max_size would be exceeded")
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You would consolidate the "multiple strong references" and the "max_size would be exceeded" error variants, as it seems. I'd rather keep them seperate, but make the error variants more expressive, to explain what happened...
See my patches 😉
if let Some(value) = self.get0(link) { | ||
Ok(value) | ||
} else { | ||
Err(anyhow!("not there")) | ||
Err(Error::NotThere) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This will be relevant also for external implementations, right? So perhaps Error::BlockNotFound
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So why return an error instead of an Option
here? A Option
expresses clearly what happened...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This comes from the ReadOnlyStore signature, which should still allow for real errors, I think.
Thanks for the in-depth review! I cannot do the fixes right now. Maybe later today, if not then tomorrow! I am eager to get this in! 👍 |
I am about to rebase this btw |
ac9b424
to
a74c92d
Compare
Okay. So the Normally I would add associated types for the error type here, but that makes the whole codebase even more generic, as I would need to add them everywhere. Another way would be to add a "catchall" error variant in the What do you think? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Regarding the put
/get
errors: that code should be free to return any type of error it finds useful. I don’t like dyn Error
very much, but the alternative is to add two enum variants and make it Error<PutError, GetError>
, possibly held in an associated type (e.g. for Transaction
— which could with Rust 1.65 be lifted to the Result
level, like fn(...) -> Self::Result<()>
).
impl<...> Transaction<...> {
type Result<T> = Result<T, Error<W::Error, R::Error>>;
...
}
I’m on the fence. The second approach could also benefit from adding
impl<T, U> From<Error<Void, Void>> for Error<T, U> {
fn from(...) -> Self {
// map genuine Banyan errors, as foreign errors are guaranteed absent
}
}
(to be used in code that calls neither put
nor get
)
If you want to try out the shiny new GAT feature of Rust 1.65 then feel free! Otherwise, I’d also agree if you said that it is too much effort — the difference lies in how (reliably) users of Banyan can extract underlying store errors to react programmatically.
@@ -502,7 +508,10 @@ where | |||
offset -= child.count(); | |||
} | |||
} | |||
Err(anyhow!("index out of bounds: {}", offset)) | |||
Err(Error::IndexOutOfBounds { | |||
length: node.children.len(), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
since we’re iterating over node.children
already above, how about summing up length
at the same time?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's no need, self.children.len()
is slice::len()
which is const
and O(1)
(if I read this correctly), so this won't cost anything AFAICS! 🤔
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ah, but then it’s not the right .len()
to compare to!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You mean I need to sum up child.count()
and use that as length?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes, because that is what failed
if let Some(value) = self.get0(link) { | ||
Ok(value) | ||
} else { | ||
Err(anyhow!("not there")) | ||
Err(Error::NotThere) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This comes from the ReadOnlyStore signature, which should still allow for real errors, I think.
There's the third alternative: Make the trait BlockWriter {
type Error;
// ...
} And use our own error type only for places where we implement these traits within the codebase. The associated type might need a I don't think that's too much effort. Quite contrary, I think this is actually the way to go! Just wanted to make sure whether you're okay with this! 😄 wrt your annotations: Will push fixes in a few minutes. |
We were talking about almost the same thing :-) My proposal only has the wrapping done the other way around: the Banyan library functions (like |
Are you still working on this? I’d like to publish 0.18 next week, and I could also help push this over the finish line if you want. |
417b306
to
5a158a5
Compare
Rebased, squashed away my fixups and formatted the codebase. Thanks for pinging me on this! |
And some more things to make clippy happy. Please have a look at 6e04476 because I think there might be a bug there... |
🤔 why does clippy succeed locally but fail on actions? What am I missing here? |
Probably a different version: |
Weird. I am using nightly here, which is IIRC the one specified for the clippy step.
I will double check tomorrow, am on the road today.
|
Yes, the new code looks more reasonable than the original, good catch! |
Signed-off-by: Matthias Beyer <[email protected]>
By adding a "available" length field that can be shown in the error display. For this, the ZstdDagCborSeq::len() function was added. Signed-off-by: Matthias Beyer <[email protected]>
The error variant is not nice yet, but better than before. Signed-off-by: Matthias Beyer <[email protected]>
This patch simplifies the boolean expressions. Before this patch, the expressions were ported from the `anyhow::ensure!()` macro by replacing it with `if !(...)`, which was simple and a no-brainer to replace. With this patch, we simplify the expression to not contain unnecessary `!` in there. Signed-off-by: Matthias Beyer <[email protected]>
Signed-off-by: Matthias Beyer <[email protected]>
Signed-off-by: Matthias Beyer <[email protected]>
Signed-off-by: Matthias Beyer <[email protected]>
Signed-off-by: Matthias Beyer <[email protected]>
Signed-off-by: Matthias Beyer <[email protected]>
Signed-off-by: Matthias Beyer <[email protected]>
Signed-off-by: Matthias Beyer <[email protected]>
Signed-off-by: Matthias Beyer <[email protected]>
d9054de
to
de35a90
Compare
Hi @matthiasbeyer, do you plan on adding the PutError and GetError variants to the new Error type? As far as I can see this PR cannot yet be merged as is, right? |
Hi. Yeah... so what I've done (not published yet) is trying to get the banyan-utils crate to build as well... but because of the change of interfaces in the banyan crate, this essentially means to rewrite the whole banyan-utils codebase, which is one big mess (the rewrite, not the code). I'm kinda stuck in the middle of it, actually... help would be much appreciated, TBH! 😆 |
I’m currently incapacitated, but if you push your code somewhere I could take a look after Christmas. |
This patch rewrites banyan-utils to use thiserror and the new (thiserror-based) banyan API instead of anyhow.
Sure, here it is. This commit does not build and is not complete and needs some work and cleanup (and possible needs to be split up into more detailed, individual commits), of course! |
Turns out I wasn’t able to work on this over the Christmas break, and it is unlikely that I’ll be able to before Jan 19, sorry about that. |
No problem, take your time! |
As this is a library crate, it should not use
anyhow
.It should rather use
thiserror
and define actual error types, that a user can then handle properly and as they think it is best for them.This PR refactors the codebase to use
thiserror
rather thananyhow
.Some of these error kinds are still not nice, but I guess it is a starting point. Please tell me what you think!