blob: 6bbdd39c75f8159239ea0ae9fd135f3ba3d0a371 [file] [log] [blame]
Rolf Badorekef2bf512019-08-20 11:17:15 +03001/*
2 Copyright (c) 2018-2019 Nokia.
3
4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License.
6 You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15*/
16
Timo Tietavainena0745d22019-11-28 09:55:22 +020017/*
18 * This source code is part of the near-RT RIC (RAN Intelligent Controller)
19 * platform project (RICP).
20*/
21
Rolf Badorekef2bf512019-08-20 11:17:15 +030022#include <sstream>
23#include "private/createlogger.hpp"
24#include "private/error.hpp"
25
26using namespace shareddatalayer;
27using namespace shareddatalayer::redis;
28
29namespace
30{
31 /* Error codes under this category are not set directly. All SDL implementation specific error codes can be
32 * mapped to these error codes. These error codes are further on mapped to error codes which are available to
33 * SDL clients (shareddatalayer::Error category).
34 * We could directly map implementation specific error codes to client error codes but having this intermediate
35 * mapping gives some benefits:
36 * - We can easily provide more error categories for clients (e.g. severity, etc.) than just client error code
37 * classification if needed.
38 * - We can implement SDL internal error handling logic based on these internal error codes if needed.
39 * - If implementation specific error would be directly mapped to client error codes, mapping implementation would
40 * easily be quite complicated (especially if the amount of implementation specific errors/error categories increases).
41 */
42 class InternalErrorCategory : public std::error_category
43 {
44 public:
45 InternalErrorCategory() = default;
46 const char* name() const noexcept override;
47 std::string message(int condition) const override;
48 };
49
50 const char* InternalErrorCategory::name() const noexcept
51 {
52 return "SDL-internal-errorcodes";
53 }
54
55 std::string InternalErrorCategory::message(int) const
56 {
57 return "Only for SDL internal usage.";
58 }
59
60 const std::error_category& getInternalErrorCategory() noexcept
61 {
62 static const InternalErrorCategory theInternalErrorCategory;
63 return theInternalErrorCategory;
64 }
65
66 /* This error category is used by both AsyncHiredisCommandDispatcher and AsyncHiredisClusterCommandDispatcher,
67 * thus it is defined here. Error categories related to single class are defined in the files of the corresponding class.
68 * AsyncHiredisCommandDispatcher and AsyncHiredisClusterCommandDispatcher can use common error category as error
69 * handling is identical in those two classes. Also, only one of those classes is always used at a time (depending
70 * on deployment).
71 */
72 class AsyncRedisCommandDispatcherErrorCategory: public std::error_category
73 {
74 public:
75 AsyncRedisCommandDispatcherErrorCategory() = default;
76
77 const char* name() const noexcept override;
78
79 std::string message(int condition) const override;
80
81 std::error_condition default_error_condition(int condition) const noexcept override;
82 };
83
84 const char* AsyncRedisCommandDispatcherErrorCategory::name() const noexcept
85 {
86 /* As the correct dispacther is selected during runtime, we do not known here (without additional implementation)
87 * which dispatcher (redis/rediscluster) is currently in use. At least for now, we do not indicate in error
88 * category name the exact dispacther type but return the same name for all dispatchers.
89 * Main reason for this decision was that in error investigation situations we anyway need to have some other efficient
90 * way to figure out what kind of deployment was used as there can be error situations which do not generate any error
91 * code. Thus it was not seen worth the errort to implement correct dispatcher name display to error category name.
92 * Detailed dispacther name display can be added later if a need for that arises.
93 */
94 return "asyncrediscommanddispatcher";
95 }
96
97 std::string AsyncRedisCommandDispatcherErrorCategory::message(int condition) const
98 {
99 switch (static_cast<AsyncRedisCommandDispatcherErrorCode>(condition))
100 {
101 case AsyncRedisCommandDispatcherErrorCode::SUCCESS:
102 return std::error_code().message();
103 case AsyncRedisCommandDispatcherErrorCode::CONNECTION_LOST:
104 return "redis connection lost";
105 case AsyncRedisCommandDispatcherErrorCode::PROTOCOL_ERROR:
106 return "redis protocol error";
107 case AsyncRedisCommandDispatcherErrorCode::OUT_OF_MEMORY:
108 return "redis out of memory";
109 case AsyncRedisCommandDispatcherErrorCode::DATASET_LOADING:
110 return "redis dataset still being loaded into memory";
111 case AsyncRedisCommandDispatcherErrorCode::NOT_CONNECTED:
112 return "not connected to redis, SDL operation not started";
113 case AsyncRedisCommandDispatcherErrorCode::UNKNOWN_ERROR:
114 return "redis error";
115 case AsyncRedisCommandDispatcherErrorCode::IO_ERROR:
116 return "redis I/O error";
Rolf Badorekb7f49712019-09-23 14:14:56 +0300117 case AsyncRedisCommandDispatcherErrorCode::WRITING_TO_SLAVE:
118 return "writing to slave";
Rolf Badorekef2bf512019-08-20 11:17:15 +0300119 case AsyncRedisCommandDispatcherErrorCode::END_MARKER:
120 logErrorOnce("AsyncRedisCommandDispatcherErrorCode::END_MARKER is not meant to be queried (it is only for enum loop control)");
121 return "unsupported error code for message()";
122 default:
123 return "description missing for AsyncRedisCommandDispatcherErrorCategory error: " + std::to_string(condition);
124 }
125 }
126
127 std::error_condition AsyncRedisCommandDispatcherErrorCategory::default_error_condition(int condition) const noexcept
128 {
129 switch (static_cast<AsyncRedisCommandDispatcherErrorCode>(condition))
130 {
131 case AsyncRedisCommandDispatcherErrorCode::SUCCESS:
132 return InternalError::SUCCESS;
133 case AsyncRedisCommandDispatcherErrorCode::CONNECTION_LOST:
134 return InternalError::BACKEND_CONNECTION_LOST;
135 case AsyncRedisCommandDispatcherErrorCode::PROTOCOL_ERROR:
136 return InternalError::BACKEND_REJECTED_REQUEST;
137 case AsyncRedisCommandDispatcherErrorCode::OUT_OF_MEMORY:
138 return InternalError::BACKEND_ERROR;
139 case AsyncRedisCommandDispatcherErrorCode::DATASET_LOADING:
140 return InternalError::BACKEND_NOT_READY;
141 case AsyncRedisCommandDispatcherErrorCode::NOT_CONNECTED:
142 return InternalError::SDL_NOT_CONNECTED_TO_BACKEND;
143 case AsyncRedisCommandDispatcherErrorCode::UNKNOWN_ERROR:
144 return InternalError::BACKEND_ERROR;
145 case AsyncRedisCommandDispatcherErrorCode::IO_ERROR:
146 return InternalError::BACKEND_ERROR;
Rolf Badorekb7f49712019-09-23 14:14:56 +0300147 case AsyncRedisCommandDispatcherErrorCode::WRITING_TO_SLAVE:
148 return InternalError::BACKEND_ERROR;
Rolf Badorekef2bf512019-08-20 11:17:15 +0300149 case AsyncRedisCommandDispatcherErrorCode::END_MARKER:
150 logErrorOnce("AsyncRedisCommandDispatcherErrorCode::END_MARKER is not meant to be mapped to InternalError (it is only for enum loop control)");
151 return InternalError::SDL_ERROR_CODE_LOGIC_ERROR;
152 default:
153 std::ostringstream msg;
154 msg << "default error condition missing for AsyncRedisCommandDispatcherErrorCategory error: "
155 << condition;
156 logErrorOnce(msg.str());
157 return InternalError::SDL_ERROR_CODE_LOGIC_ERROR;
158 }
159 }
160
161 const std::error_category& getAsyncRedisCommandDispatcherErrorCategory() noexcept
162 {
163 static const AsyncRedisCommandDispatcherErrorCategory theAsyncRedisCommandDispatcherErrorCategory;
164 return theAsyncRedisCommandDispatcherErrorCategory;
165 }
166}
167
168namespace shareddatalayer
169{
170 std::error_condition make_error_condition(InternalError errorCode)
171 {
172 return {static_cast<int>(errorCode), getInternalErrorCategory()};
173 }
174
175 namespace redis
176 {
177 std::error_code make_error_code(AsyncRedisCommandDispatcherErrorCode errorCode)
178 {
179 return std::error_code(static_cast<int>(errorCode), getAsyncRedisCommandDispatcherErrorCategory());
180 }
181
182 AsyncRedisCommandDispatcherErrorCode& operator++ (AsyncRedisCommandDispatcherErrorCode& ecEnum)
183 {
184 if (ecEnum == AsyncRedisCommandDispatcherErrorCode::END_MARKER)
185 throw std::out_of_range("for AsyncRedisCommandDispatcherErrorCode& operator ++");
186
187 ecEnum = AsyncRedisCommandDispatcherErrorCode(static_cast<std::underlying_type<AsyncRedisCommandDispatcherErrorCode>::type>(ecEnum) + 1);
188 return ecEnum;
189 }
190 }
191}