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

fix: do not cache io errors #5856

Merged
merged 9 commits into from
Jan 5, 2022

Conversation

matklad
Copy link
Contributor

@matklad matklad commented Dec 16, 2021

When we compile & cache the contract, there are two very different kinds
of "errors" we can have:

  • IO error due to the database being corrupted and such
  • Contract failed to compile because it contained invalid WASM

The second outcome is normal, expected mode of execution and should be
cached. The first error is a genuine exceptional situation, and should
not be cached (eg, retrying the operation might succeed).

Test Plan

Existing tests to verify that the happy path still works. I don't believe we current have fault injection tests to make sure genuine IO-errors are handled correctly.

Copy link
Contributor

@EgorKulikov EgorKulikov left a comment

Choose a reason for hiding this comment

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

Always a pleasure to review

{
match self.get_or_try_insert(key, |k| Ok::<V, std::convert::Infallible>(f(k))) {
Ok(it) => it,
Err(never) => match never {},
Copy link
Collaborator

Choose a reason for hiding this comment

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

hmm isn't this equivalent to Err(_) => ()?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

not really, the type of () is (), the type of match never {} is !. The result type here is V, and match never {} is compatible with that.

For context: Infallible is an empty enum: enum Infallible {}

Copy link
Contributor

Choose a reason for hiding this comment

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

Why not use:

diff --git i/utils/near-cache/src/lib.rs w/utils/near-cache/src/lib.rs
index 069662c90..c13416021 100644
--- i/utils/near-cache/src/lib.rs
+++ w/utils/near-cache/src/lib.rs
@@ -26,10 +26,7 @@ where
         V: Clone,
         F: FnOnce(&K) -> V,
     {
-        match self.get_or_try_put(key, |k| Ok::<V, std::convert::Infallible>(f(k))) {
-            Ok(it) => it,
-            Err(never) => match never {},
-        }
+        self.get_or_try_put(key, |k| Ok::<V, std::convert::Infallible>(f(k))).unwrap()
     }
 
     /// Returns the value of they key in the cache if present, otherwise

Copy link
Contributor Author

Choose a reason for hiding this comment

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

.unwrap() is an operation that can in general fail at runtime. In this case it can't actually fail, but you need to read the context to understand this. In contrast, match never {} can't fail in a statically-checked way.

Really, thish should be just Result::into_ok (https://doc.rust-lang.org/stable/std/result/enum.Result.html#method.into_ok) but that needs to wait until ! is stabilized properly.

Copy link
Collaborator

@nagisa nagisa Dec 23, 2021

Choose a reason for hiding this comment

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

In previous codebases I used

Result::<_, Infallible>::unwrap(result)

to very signal clearly enough that “yeah this is unwrap, but no it is actually into_ok”. At codegen level LLVM can see easily enough that panic within unwrap is not reachable panic won't actually materialize.


match never {} seems to have confused sufficient number of people that I think its probably not worth whatever static benefits it provides.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Excellent suggestion, thanks!

These two pass-through functions were only necessary when we used cache
crate, we don't need them now.
When we compile & cache the contract, there are two very different kinds
of "error" we can have:

* IO error due to the database being corrupted and such
* Contract failed to compile because it contained invalid WASM

The second outcome is normal, expected mode of execution and should be
cached. The first error is a genuine exceptional situation, and should
not be cached (eg, retrying the operation might succeed).
Copy link
Contributor

@pmnoxx pmnoxx left a comment

Choose a reason for hiding this comment

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

LGTM, though, it would be nice to have a test for it..

@matklad
Copy link
Contributor Author

matklad commented Dec 23, 2021

LGTM, though, it would be nice to have a test for it..

That's a very good call. I've written that "we don't have fault injection tests", but of course we can cheaply add them here, as the cache is already polymorphic. And, surely, doing so uncovered a minor preexisting bug where I mixed up read error and write error!

@matklad matklad requested a review from nikurt as a code owner December 23, 2021 11:11
It's not really tiny, `trivial_contract` is significantly simpler
/// Returns the value of they key in the cache if present, otherwise
/// computes the value using the provided closure.
///
/// If the key is already in the cache, it gets moved to the head of the LDU
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
/// If the key is already in the cache, it gets moved to the head of the LDU
/// If the key is already in the cache, it gets moved to the head of the LRU

@near-bulldozer near-bulldozer bot merged commit 42d81d9 into near:master Jan 5, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants