mirror of
https://github.com/ceph/ceph
synced 2025-02-24 03:27:10 +00:00
Merge pull request #38585 from tchaikov/wip-doc-dev-errorator
doc/dev/crimson: highlight code blocks using C++ lexer Reviewed-by: Radoslaw Zarzynski <rzarzyns@redhat.com>
This commit is contained in:
commit
32921b7003
@ -3,16 +3,16 @@ error handling
|
||||
==============
|
||||
|
||||
|
||||
In Seastar, a `future` represents a value not yet available but that can become
|
||||
available later. `future` can have one of following states:
|
||||
In Seastar, a ``future`` represents a value not yet available but that can become
|
||||
available later. ``future`` can have one of following states:
|
||||
|
||||
* unavailable: value is not available yet,
|
||||
* value,
|
||||
* failed: an exception was thrown when computing the value. This exception has
|
||||
been captured and stored in the `future` instance via `std::exception_ptr`.
|
||||
been captured and stored in the ``future`` instance via ``std::exception_ptr``.
|
||||
|
||||
In the last case, the exception can be processed using `future::handle_exception()` or
|
||||
`future::handle_exception_type()`. Seastar even provides `future::or_terminate()` to
|
||||
In the last case, the exception can be processed using ``future::handle_exception()`` or
|
||||
``future::handle_exception_type()``. Seastar even provides ``future::or_terminate()`` to
|
||||
terminate the program if the future fails.
|
||||
|
||||
But in Crimson, quite a few errors are not serious enough to fail the program entirely.
|
||||
@ -26,36 +26,36 @@ that all expected errors are handled. It should be something like the statical a
|
||||
performed by compiler to spit a warning if any enum value is not handled in a ``switch-case``
|
||||
statement.
|
||||
|
||||
Unfortunately, `seastar::future` is not able to satisfy these two requirements.
|
||||
Unfortunately, ``seastar::future`` is not able to satisfy these two requirements.
|
||||
|
||||
* Seastar imposes re-throwing an exception to dispatch between different types of
|
||||
exceptions. This is not very performant nor even scalable as locking in the language's
|
||||
runtime can occur.
|
||||
* Seastar does not encode the expected exception type in the type of the returned
|
||||
`seastar::future`. Only the type of the value is encoded. This imposes huge
|
||||
``seastar::future``. Only the type of the value is encoded. This imposes huge
|
||||
mental load on programmers as ensuring that all intended errors are indeed handled
|
||||
requires manual code audit.
|
||||
|
||||
So, "errorator" is created. It is a wrapper around the vanilla `seastar::future`.
|
||||
.. highlight:: c++
|
||||
|
||||
So, "errorator" is created. It is a wrapper around the vanilla ``seastar::future``.
|
||||
It addresses the performance and scalability issues while embedding the information
|
||||
about all expected types-of-errors to the type-of-future.::
|
||||
|
||||
|
||||
|
||||
using ertr = crimson::errorator<crimson::ct_error::enoent,
|
||||
crimson::ct_error::einval>;
|
||||
|
||||
In above example we defined an errorator that allows for two error types:
|
||||
|
||||
* `crimson::ct_error::enoent` and
|
||||
* `crimson::ct_error::einval`.
|
||||
* ``crimson::ct_error::enoent`` and
|
||||
* ``crimson::ct_error::einval``.
|
||||
|
||||
These (and other ones in the `crimson::ct_error` namespace) are basically
|
||||
unthrowable wrappers over `std::error_code` to exclude accidental throwing
|
||||
These (and other ones in the ``crimson::ct_error`` namespace) are basically
|
||||
unthrowable wrappers over ``std::error_code`` to exclude accidental throwing
|
||||
and ensure signaling errors in a way that enables compile-time checking.
|
||||
|
||||
The most fundamental thing in an errorator is a descendant of `seastar::future`
|
||||
which can be used as e.g. function's return type:::
|
||||
The most fundamental thing in an errorator is a descendant of ``seastar::future``
|
||||
which can be used as e.g. function's return type::
|
||||
|
||||
static ertr::future<int> foo(int bar) {
|
||||
if (bar == 42) {
|
||||
@ -66,7 +66,7 @@ which can be used as e.g. function's return type:::
|
||||
}
|
||||
|
||||
It's worth to note that returning an error that is not a part the errorator's error set
|
||||
would result in a compile-time error:::
|
||||
would result in a compile-time error::
|
||||
|
||||
static ertr::future<int> foo(int bar) {
|
||||
// Oops, input_output_error is not allowed in `ertr`. static_assert() will
|
||||
@ -80,9 +80,9 @@ would result in a compile-time error:::
|
||||
The errorator concept goes further. It not only provides callers with the information
|
||||
about all potential errors embedded in the function's type; it also ensures at the caller
|
||||
site that all these errors are handled. As the reader probably know, the main method
|
||||
in `seastar::future` is `then()`. On errorated future it is available but only if errorator's
|
||||
error set is empty (literally: `errorator<>::future`); otherwise callers have
|
||||
to use `safe_then()` instead:::
|
||||
in ``seastar::future`` is ``then()``. On errorated future it is available but only if errorator's
|
||||
error set is empty (literally: ``errorator<>::future``); otherwise callers have
|
||||
to use ``safe_then()`` instead::
|
||||
|
||||
seastar::future<> baz() {
|
||||
return foo(42).safe_then(
|
||||
@ -102,10 +102,10 @@ to use `safe_then()` instead:::
|
||||
});
|
||||
}
|
||||
|
||||
In the above example `ertr::all_same_way` has been used to handle all errors in the same
|
||||
In the above example ``ertr::all_same_way`` has been used to handle all errors in the same
|
||||
manner. This is not obligatory -- a caller can handle each of them separately. Moreover,
|
||||
it can provide a handler for only a subset of errors. The price for that is the availability
|
||||
of `then()`::
|
||||
of ``then()``::
|
||||
|
||||
using einval_ertr = crimson::errorator<crimson::ct_error::einval>;
|
||||
|
||||
@ -129,9 +129,9 @@ of `then()`::
|
||||
}
|
||||
|
||||
That is, handling errors removes them from errorated future's error set. This works
|
||||
in the opposite direction too -- returning new errors in `safe_then()` appends them
|
||||
the error set. Of course, this set must be compliant with error set in the `baz()`'s
|
||||
signature:::
|
||||
in the opposite direction too -- returning new errors in ``safe_then()`` appends them
|
||||
the error set. Of course, this set must be compliant with error set in the ``baz()``'s
|
||||
signature::
|
||||
|
||||
using broader_ertr = crimson::errorator<crimson::ct_error::enoent,
|
||||
crimson::ct_error::einval,
|
||||
@ -149,7 +149,7 @@ signature:::
|
||||
ertr::pass_further{});
|
||||
}
|
||||
|
||||
As it can be seen, handling and signaling errors in `safe_then()` is basically
|
||||
As it can be seen, handling and signaling errors in ``safe_then()`` is basically
|
||||
an operation on the error set checked at compile-time.
|
||||
|
||||
More details can be found in `the slides from ceph::errorator<> throw/catch-free,
|
||||
|
Loading…
Reference in New Issue
Block a user