-
Notifications
You must be signed in to change notification settings - Fork 1.1k
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
Add error code categories to Status #2200
Comments
spolitov
added a commit
that referenced
this issue
Sep 5, 2019
Summary: We need a way for different parts of the codebase to augment instances of the Status class with its own types of error codes without adding those error codes to Status. Examples of such error codes include POSIX I/O error codes, YCQL errors, and YSQL errors. Status is used throughout the entire codebase, and simply adding more specific error codes there would introduce unnecessary dependencies between different parts of the codebase, not to mention forcing the recompilation of almost all of the code. This diff introduces the ability to add extra error codes to the status. A status can now contain a map of error code categories to error code values (at most one per category), which could be represented as simple enums, or have a more complex representation, including custom error messages, etc. This serialization format is part of an error category definition. There is a hard limit of 255 on the number of possible error categories, because the category id is represented as a non-zero byte. Category ids and serialization format of individual error codes in each category are part of the wire protocol, so when changing these, backward compatibility and rolling upgrades should be considered. Error category ids should also be globally unique across the codebase, which is checked by a global error code category registry at server startup. Inside of in-memory and on-the-wire representations of a `Status`, a category id is stored as one byte, followed by the category-specific binary representation (e.g. a little-endian number for number-based or "integral" error categories). Accessing the error code of a specific category takes O(N) time, where N is the number of different categories of error codes associated with a given `Status` object. In practice N is assumed to be very small and it obviously can't exceed 255. This representation of error codes is terminated with a special dummy category id of 0. A component might define a simple custom error code that is backed by an enum as follows, e.g. in a header `pizza_error.h` (omitting namespace and other boilerplate): ``` YB_DEFINE_ENUM(PizzaCode, (kSoggy)(kUndercooked)(kTooManyBubbles)(kTooMuchSauce)(kDoesNotTasteGood)); struct PizzaErrorTag : yb::IntegralErrorTag<PizzaCode> { // This category id is part of the wire protocol and should not be changed once released. static constexpr uint8_t kCategory = 123; static const std::string& ToMessage(Value value); }; typedef yb::StatusErrorCodeImpl<PizzaErrorTag> PizzaError; ``` (Note that the comment `// This category id is part of the wire protocol and should not be changed once released` should be there above the category code constant, by our convention.) And in the corresponding file called e.g. `pizza_error.cc` ``` const std::string kPizzaMsgs[] = { "Soggy pizza", "Undercooked pizza", "Too many bubbles in the crust", "Too much sauce on the pizza", "Does not taste good" }; static_assert(arraysize(kPizzaCode) == kElementsInPizzaCode, "Wrong number of pizza error messages"); } // namespace const std::string& PizzaErrorTag::ToMessage(Value value) { return kPizzaMsgs[yb::to_underlying(value)]; } static const std::string kPizzaErrorCategoryName = "pizza"; static yb::StatusCategoryRegisterer pizza_error_category_registerer( yb::StatusCategoryDescription::Make<PizzaErrorTag>(&kPizzaErrorCategoryName)); ``` Then, a status could be created with this error code: ``` return STATUS(IllegalState, "Something is wrong with the pizza", PizzaError(PizzaCode::kTooMuchSauce)); ``` Also, an existing status object could be augmented with an error code: ``` return status.CloneAndAddErrorCode(PizzaError(PizzaCode::kDoesNotTasteGood)); ``` (This would replace an existing error code of the same category if it already exists in the status). Test Plan: Jenkins Backward compatibility was tested using the following steps: 1) In wire_protocol.cc the following line was commented: `pb->set_errors(error_codes.data(), error_codes.size());` So we check that errors are perfectly serialized and deserialized in an old format. 2) Jenkins launched for modified diff. And the test results are checked. 3) Code uncommented. Reviewers: nicolas, mikhail Reviewed By: mikhail Subscribers: ybase, bogdan Differential Revision: https://phabricator.dev.yugabyte.com/D6972
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
We need a way for different parts of the codebase to augment instances of the
Status
class with its own types of error codes without adding those error codes toStatus
. Examples of such error codes include POSIX I/O error codes, YCQL errors, and YSQL errors.Status
is used throughout the entire codebase, and simply adding more specific error codes there will introduce unnecessary dependencies between different parts of the codebase, not to mention forcing the recompilation of almost all of the code.The text was updated successfully, but these errors were encountered: