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