X-Git-Url: https://gerrit.o-ran-sc.org/r/gitweb?a=blobdiff_plain;f=src%2Ferror.cpp;fp=src%2Ferror.cpp;h=347e6513e9f836d3d8fbb12dda312f1d1ada6157;hb=ef2bf51d04aaf01fa0cabdcaf905b23423067662;hp=0000000000000000000000000000000000000000;hpb=edc9b96a441194b571e8d55ec1603b5be0ea52eb;p=ric-plt%2Fsdl.git diff --git a/src/error.cpp b/src/error.cpp new file mode 100644 index 0000000..347e651 --- /dev/null +++ b/src/error.cpp @@ -0,0 +1,182 @@ +/* + Copyright (c) 2018-2019 Nokia. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +#include +#include "private/createlogger.hpp" +#include "private/error.hpp" + +using namespace shareddatalayer; +using namespace shareddatalayer::redis; + +namespace +{ + /* Error codes under this category are not set directly. All SDL implementation specific error codes can be + * mapped to these error codes. These error codes are further on mapped to error codes which are available to + * SDL clients (shareddatalayer::Error category). + * We could directly map implementation specific error codes to client error codes but having this intermediate + * mapping gives some benefits: + * - We can easily provide more error categories for clients (e.g. severity, etc.) than just client error code + * classification if needed. + * - We can implement SDL internal error handling logic based on these internal error codes if needed. + * - If implementation specific error would be directly mapped to client error codes, mapping implementation would + * easily be quite complicated (especially if the amount of implementation specific errors/error categories increases). + */ + class InternalErrorCategory : public std::error_category + { + public: + InternalErrorCategory() = default; + const char* name() const noexcept override; + std::string message(int condition) const override; + }; + + const char* InternalErrorCategory::name() const noexcept + { + return "SDL-internal-errorcodes"; + } + + std::string InternalErrorCategory::message(int) const + { + return "Only for SDL internal usage."; + } + + const std::error_category& getInternalErrorCategory() noexcept + { + static const InternalErrorCategory theInternalErrorCategory; + return theInternalErrorCategory; + } + + /* This error category is used by both AsyncHiredisCommandDispatcher and AsyncHiredisClusterCommandDispatcher, + * thus it is defined here. Error categories related to single class are defined in the files of the corresponding class. + * AsyncHiredisCommandDispatcher and AsyncHiredisClusterCommandDispatcher can use common error category as error + * handling is identical in those two classes. Also, only one of those classes is always used at a time (depending + * on deployment). + */ + class AsyncRedisCommandDispatcherErrorCategory: public std::error_category + { + public: + AsyncRedisCommandDispatcherErrorCategory() = default; + + const char* name() const noexcept override; + + std::string message(int condition) const override; + + std::error_condition default_error_condition(int condition) const noexcept override; + }; + + const char* AsyncRedisCommandDispatcherErrorCategory::name() const noexcept + { + /* As the correct dispacther is selected during runtime, we do not known here (without additional implementation) + * which dispatcher (redis/rediscluster) is currently in use. At least for now, we do not indicate in error + * category name the exact dispacther type but return the same name for all dispatchers. + * Main reason for this decision was that in error investigation situations we anyway need to have some other efficient + * way to figure out what kind of deployment was used as there can be error situations which do not generate any error + * code. Thus it was not seen worth the errort to implement correct dispatcher name display to error category name. + * Detailed dispacther name display can be added later if a need for that arises. + */ + return "asyncrediscommanddispatcher"; + } + + std::string AsyncRedisCommandDispatcherErrorCategory::message(int condition) const + { + switch (static_cast(condition)) + { + case AsyncRedisCommandDispatcherErrorCode::SUCCESS: + return std::error_code().message(); + case AsyncRedisCommandDispatcherErrorCode::CONNECTION_LOST: + return "redis connection lost"; + case AsyncRedisCommandDispatcherErrorCode::PROTOCOL_ERROR: + return "redis protocol error"; + case AsyncRedisCommandDispatcherErrorCode::OUT_OF_MEMORY: + return "redis out of memory"; + case AsyncRedisCommandDispatcherErrorCode::DATASET_LOADING: + return "redis dataset still being loaded into memory"; + case AsyncRedisCommandDispatcherErrorCode::NOT_CONNECTED: + return "not connected to redis, SDL operation not started"; + case AsyncRedisCommandDispatcherErrorCode::UNKNOWN_ERROR: + return "redis error"; + case AsyncRedisCommandDispatcherErrorCode::IO_ERROR: + return "redis I/O error"; + case AsyncRedisCommandDispatcherErrorCode::END_MARKER: + logErrorOnce("AsyncRedisCommandDispatcherErrorCode::END_MARKER is not meant to be queried (it is only for enum loop control)"); + return "unsupported error code for message()"; + default: + return "description missing for AsyncRedisCommandDispatcherErrorCategory error: " + std::to_string(condition); + } + } + + std::error_condition AsyncRedisCommandDispatcherErrorCategory::default_error_condition(int condition) const noexcept + { + switch (static_cast(condition)) + { + case AsyncRedisCommandDispatcherErrorCode::SUCCESS: + return InternalError::SUCCESS; + case AsyncRedisCommandDispatcherErrorCode::CONNECTION_LOST: + return InternalError::BACKEND_CONNECTION_LOST; + case AsyncRedisCommandDispatcherErrorCode::PROTOCOL_ERROR: + return InternalError::BACKEND_REJECTED_REQUEST; + case AsyncRedisCommandDispatcherErrorCode::OUT_OF_MEMORY: + return InternalError::BACKEND_ERROR; + case AsyncRedisCommandDispatcherErrorCode::DATASET_LOADING: + return InternalError::BACKEND_NOT_READY; + case AsyncRedisCommandDispatcherErrorCode::NOT_CONNECTED: + return InternalError::SDL_NOT_CONNECTED_TO_BACKEND; + case AsyncRedisCommandDispatcherErrorCode::UNKNOWN_ERROR: + return InternalError::BACKEND_ERROR; + case AsyncRedisCommandDispatcherErrorCode::IO_ERROR: + return InternalError::BACKEND_ERROR; + case AsyncRedisCommandDispatcherErrorCode::END_MARKER: + logErrorOnce("AsyncRedisCommandDispatcherErrorCode::END_MARKER is not meant to be mapped to InternalError (it is only for enum loop control)"); + return InternalError::SDL_ERROR_CODE_LOGIC_ERROR; + default: + std::ostringstream msg; + msg << "default error condition missing for AsyncRedisCommandDispatcherErrorCategory error: " + << condition; + logErrorOnce(msg.str()); + return InternalError::SDL_ERROR_CODE_LOGIC_ERROR; + } + } + + const std::error_category& getAsyncRedisCommandDispatcherErrorCategory() noexcept + { + static const AsyncRedisCommandDispatcherErrorCategory theAsyncRedisCommandDispatcherErrorCategory; + return theAsyncRedisCommandDispatcherErrorCategory; + } +} + +namespace shareddatalayer +{ + std::error_condition make_error_condition(InternalError errorCode) + { + return {static_cast(errorCode), getInternalErrorCategory()}; + } + + namespace redis + { + std::error_code make_error_code(AsyncRedisCommandDispatcherErrorCode errorCode) + { + return std::error_code(static_cast(errorCode), getAsyncRedisCommandDispatcherErrorCategory()); + } + + AsyncRedisCommandDispatcherErrorCode& operator++ (AsyncRedisCommandDispatcherErrorCode& ecEnum) + { + if (ecEnum == AsyncRedisCommandDispatcherErrorCode::END_MARKER) + throw std::out_of_range("for AsyncRedisCommandDispatcherErrorCode& operator ++"); + + ecEnum = AsyncRedisCommandDispatcherErrorCode(static_cast::type>(ecEnum) + 1); + return ecEnum; + } + } +}