1 | /******************************************************************** |
2 | * Copyright (c) 2013 - 2014, Pivotal Inc. |
3 | * All rights reserved. |
4 | * |
5 | * Author: Zhanwei Wang |
6 | ********************************************************************/ |
7 | /******************************************************************** |
8 | * 2014 - |
9 | * open source under Apache License Version 2.0 |
10 | ********************************************************************/ |
11 | /** |
12 | * Licensed to the Apache Software Foundation (ASF) under one |
13 | * or more contributor license agreements. See the NOTICE file |
14 | * distributed with this work for additional information |
15 | * regarding copyright ownership. The ASF licenses this file |
16 | * to you under the Apache License, Version 2.0 (the |
17 | * "License"); you may not use this file except in compliance |
18 | * with the License. You may obtain a copy of the License at |
19 | * |
20 | * http://www.apache.org/licenses/LICENSE-2.0 |
21 | * |
22 | * Unless required by applicable law or agreed to in writing, software |
23 | * distributed under the License is distributed on an "AS IS" BASIS, |
24 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
25 | * See the License for the specific language governing permissions and |
26 | * limitations under the License. |
27 | */ |
28 | #ifndef _HDFS_LIBHDFS3_EXCEPTION_EXCEPTIONINTERNAL_H_ |
29 | #define _HDFS_LIBHDFS3_EXCEPTION_EXCEPTIONINTERNAL_H_ |
30 | |
31 | #include "platform.h" |
32 | |
33 | #include <cassert> |
34 | #include <cstdarg> |
35 | #include <cstdio> |
36 | #include <cstring> |
37 | #include <unistd.h> |
38 | #include <string> |
39 | #include <sstream> |
40 | |
41 | #include "Function.h" |
42 | #include "StackPrinter.h" |
43 | |
44 | #define STACK_DEPTH 64 |
45 | |
46 | #define PATH_SEPRATOR '/' |
47 | inline static const char * SkipPathPrefix(const char * path) { |
48 | int i, len = strlen(path); |
49 | |
50 | for (i = len - 1; i > 0; --i) { |
51 | if (path[i] == PATH_SEPRATOR) { |
52 | break; |
53 | } |
54 | } |
55 | |
56 | assert(i > 0 && i < len); |
57 | return path + i + 1; |
58 | } |
59 | |
60 | #ifdef NEED_BOOST // include headers |
61 | #include <boost/exception/all.hpp> |
62 | |
63 | namespace Hdfs { |
64 | using boost::exception_ptr; |
65 | using boost::rethrow_exception; |
66 | using boost::current_exception; |
67 | } |
68 | |
69 | #else |
70 | #include <exception> |
71 | #include <stdexcept> |
72 | |
73 | namespace Hdfs { |
74 | using std::rethrow_exception; |
75 | using std::current_exception; |
76 | using std::make_exception_ptr; |
77 | using std::exception_ptr; |
78 | } |
79 | #endif // include headers |
80 | |
81 | #if defined(NEED_BOOST) || !defined(HAVE_NESTED_EXCEPTION) // define nested exception |
82 | namespace Hdfs { |
83 | #ifdef NEED_BOOST |
84 | class nested_exception : virtual public boost::exception { |
85 | #else |
86 | class nested_exception : virtual public std::exception { |
87 | #endif |
88 | public: |
89 | nested_exception() : p(current_exception()) { |
90 | } |
91 | |
92 | nested_exception(const nested_exception & other) : p(other.p) { |
93 | } |
94 | |
95 | nested_exception & operator = (const nested_exception & other) { |
96 | this->p = other.p; |
97 | return *this; |
98 | } |
99 | |
100 | virtual ~nested_exception() throw() {} |
101 | |
102 | void rethrow_nested() const { |
103 | rethrow_exception(p); |
104 | } |
105 | |
106 | exception_ptr nested_ptr() const { |
107 | return p; |
108 | } |
109 | protected: |
110 | exception_ptr p; |
111 | }; |
112 | |
113 | template<typename BaseType> |
114 | struct ExceptionWrapper : public BaseType, public nested_exception { |
115 | explicit ExceptionWrapper(BaseType const & e) : BaseType(static_cast < BaseType const & >(e)) {} |
116 | ~ExceptionWrapper() throw() {} |
117 | }; |
118 | |
119 | template<typename T> |
120 | ATTRIBUTE_NORETURN |
121 | static inline void throw_with_nested(T const & e) { |
122 | if (dynamic_cast<const nested_exception *>(&e)) { |
123 | std::terminate(); |
124 | } |
125 | |
126 | #ifdef NEED_BOOST |
127 | boost::throw_exception(ExceptionWrapper<T>(static_cast < T const & >(e))); |
128 | #else |
129 | throw ExceptionWrapper<T>(static_cast < T const & >(e)); |
130 | #endif |
131 | } |
132 | |
133 | template<typename T> |
134 | static inline void rethrow_if_nested(T const & e) { |
135 | const nested_exception * nested = dynamic_cast<const nested_exception *>(&e); |
136 | |
137 | if (nested) { |
138 | nested->rethrow_nested(); |
139 | } |
140 | } |
141 | |
142 | template<typename T> |
143 | static inline void rethrow_if_nested(const nested_exception & e) { |
144 | e.rethrow_nested(); |
145 | } |
146 | |
147 | } // namespace Hdfs |
148 | #else // not boost and have nested exception |
149 | namespace Hdfs { |
150 | using std::throw_with_nested; |
151 | using std::rethrow_if_nested; |
152 | } // namespace Hdfs |
153 | #endif // define nested exception |
154 | |
155 | #ifdef NEED_BOOST |
156 | namespace Hdfs { |
157 | namespace Internal { |
158 | |
159 | template<typename THROWABLE> |
160 | ATTRIBUTE_NORETURN ATTRIBUTE_NOINLINE |
161 | void ThrowException(bool nested, const char * f, int l, |
162 | const char * exceptionName, const char * fmt, ...) __attribute__((format(printf, 5, 6))) ; |
163 | |
164 | template<typename THROWABLE> |
165 | ATTRIBUTE_NORETURN ATTRIBUTE_NOINLINE |
166 | void ThrowException(bool nested, const char * f, int l, |
167 | const char * exceptionName, const char * fmt, ...) { |
168 | va_list ap; |
169 | va_start(ap, fmt); |
170 | std::string buffer; |
171 | buffer = exceptionName; |
172 | buffer.append(": " ); |
173 | int size = vsnprintf(NULL, 0, fmt, ap); |
174 | va_end(ap); |
175 | int offset = buffer.size(); |
176 | buffer.resize(offset + size + 1); |
177 | va_start(ap, fmt); |
178 | vsnprintf(&buffer[offset], size + 1, fmt, ap); |
179 | va_end(ap); |
180 | |
181 | if (!nested) { |
182 | boost::throw_exception( |
183 | THROWABLE(buffer.c_str(), SkipPathPrefix(f), l, |
184 | Hdfs::Internal::PrintStack(1, STACK_DEPTH).c_str())); |
185 | } else { |
186 | Hdfs::throw_with_nested( |
187 | THROWABLE(buffer.c_str(), SkipPathPrefix(f), l, |
188 | Hdfs::Internal::PrintStack(1, STACK_DEPTH).c_str())); |
189 | } |
190 | |
191 | throw std::logic_error("should not reach here." ); |
192 | } |
193 | |
194 | } // namespace Internal |
195 | } // namespace Hdfs |
196 | |
197 | #else |
198 | |
199 | namespace Hdfs { |
200 | namespace Internal { |
201 | |
202 | template<typename THROWABLE> |
203 | ATTRIBUTE_NORETURN ATTRIBUTE_NOINLINE |
204 | void ThrowException(bool nested, const char * f, int l, |
205 | const char * exceptionName, const char * fmt, ...) __attribute__((format(printf, 5, 6))); |
206 | |
207 | template<typename THROWABLE> |
208 | ATTRIBUTE_NORETURN ATTRIBUTE_NOINLINE |
209 | void ThrowException(bool nested, const char * f, int l, |
210 | const char * exceptionName, const char * fmt, ...) { |
211 | va_list ap; |
212 | va_start(ap, fmt); |
213 | std::string buffer; |
214 | buffer = exceptionName; |
215 | buffer.append(": " ); |
216 | int size = vsnprintf(NULL, 0, fmt, ap); |
217 | va_end(ap); |
218 | int offset = buffer.size(); |
219 | buffer.resize(offset + size + 1); |
220 | va_start(ap, fmt); |
221 | vsnprintf(&buffer[offset], size + 1, fmt, ap); |
222 | va_end(ap); |
223 | |
224 | if (!nested) { |
225 | throw THROWABLE(buffer.c_str(), SkipPathPrefix(f), l, |
226 | Hdfs::Internal::PrintStack(1, STACK_DEPTH).c_str()); |
227 | } else { |
228 | Hdfs::throw_with_nested( |
229 | THROWABLE(buffer.c_str(), SkipPathPrefix(f), l, |
230 | Hdfs::Internal::PrintStack(1, STACK_DEPTH).c_str())); |
231 | } |
232 | |
233 | throw std::logic_error("should not reach here." ); |
234 | } |
235 | |
236 | } // namespace Internal |
237 | } // namespace Hdfs |
238 | |
239 | #endif |
240 | |
241 | namespace Hdfs { |
242 | |
243 | /** |
244 | * A user defined callback function used to check if a slow operation has been canceled by the user. |
245 | * If this function return true, HdfsCanceled will be thrown. |
246 | */ |
247 | extern function<bool(void)> ChecnOperationCanceledCallback; |
248 | |
249 | class HdfsException; |
250 | |
251 | } |
252 | |
253 | namespace Hdfs { |
254 | namespace Internal { |
255 | |
256 | /** |
257 | * Check if a slow operation has been canceled by the user. |
258 | * @throw return false if operation is not canceled, else throw HdfsCanceled. |
259 | * @throw HdfsCanceled |
260 | */ |
261 | bool CheckOperationCanceled(); |
262 | |
263 | /** |
264 | * Get a exception's detail message. |
265 | * If the exception contains a nested exception, recursively get all the nested exception's detail message. |
266 | * @param e The exception which detail message to be return. |
267 | * @return The exception's detail message. |
268 | */ |
269 | const char *GetExceptionDetail(const Hdfs::HdfsException &e, |
270 | std::string &buffer); |
271 | |
272 | /** |
273 | * Get a exception's detail message. |
274 | * If the exception contains a nested exception, recursively get all the nested exception's detail message. |
275 | * @param e The exception which detail message to be return. |
276 | * @return The exception's detail message. |
277 | */ |
278 | const char *GetExceptionDetail(const exception_ptr e, std::string &buffer); |
279 | |
280 | const char * GetExceptionMessage(const exception_ptr e, std::string & buffer); |
281 | |
282 | /** |
283 | * Get a error information by the given system error number. |
284 | * @param eno System error number. |
285 | * @return The error information. |
286 | * @throw nothrow |
287 | */ |
288 | const char * GetSystemErrorInfo(int eno); |
289 | |
290 | } |
291 | } |
292 | |
293 | #define THROW(throwable, fmt, ...) \ |
294 | Hdfs::Internal::ThrowException<throwable>(false, __FILE__, __LINE__, #throwable, fmt, ##__VA_ARGS__); |
295 | |
296 | #define NESTED_THROW(throwable, fmt, ...) \ |
297 | Hdfs::Internal::ThrowException<throwable>(true, __FILE__, __LINE__, #throwable, fmt, ##__VA_ARGS__); |
298 | |
299 | #endif /* _HDFS_LIBHDFS3_EXCEPTION_EXCEPTIONINTERNAL_H_ */ |
300 | |