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 '/'
47inline 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
63namespace Hdfs {
64using boost::exception_ptr;
65using boost::rethrow_exception;
66using boost::current_exception;
67}
68
69#else
70#include <exception>
71#include <stdexcept>
72
73namespace Hdfs {
74using std::rethrow_exception;
75using std::current_exception;
76using std::make_exception_ptr;
77using std::exception_ptr;
78}
79#endif // include headers
80
81#if defined(NEED_BOOST) || !defined(HAVE_NESTED_EXCEPTION) // define nested exception
82namespace Hdfs {
83#ifdef NEED_BOOST
84class nested_exception : virtual public boost::exception {
85#else
86class nested_exception : virtual public std::exception {
87#endif
88public:
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 }
109protected:
110 exception_ptr p;
111};
112
113template<typename BaseType>
114struct ExceptionWrapper : public BaseType, public nested_exception {
115 explicit ExceptionWrapper(BaseType const & e) : BaseType(static_cast < BaseType const & >(e)) {}
116 ~ExceptionWrapper() throw() {}
117};
118
119template<typename T>
120ATTRIBUTE_NORETURN
121static 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
133template<typename T>
134static 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
142template<typename T>
143static 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
149namespace Hdfs {
150using std::throw_with_nested;
151using std::rethrow_if_nested;
152} // namespace Hdfs
153#endif // define nested exception
154
155#ifdef NEED_BOOST
156namespace Hdfs {
157namespace Internal {
158
159template<typename THROWABLE>
160ATTRIBUTE_NORETURN ATTRIBUTE_NOINLINE
161void ThrowException(bool nested, const char * f, int l,
162 const char * exceptionName, const char * fmt, ...) __attribute__((format(printf, 5, 6))) ;
163
164template<typename THROWABLE>
165ATTRIBUTE_NORETURN ATTRIBUTE_NOINLINE
166void 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
199namespace Hdfs {
200namespace Internal {
201
202template<typename THROWABLE>
203ATTRIBUTE_NORETURN ATTRIBUTE_NOINLINE
204void ThrowException(bool nested, const char * f, int l,
205 const char * exceptionName, const char * fmt, ...) __attribute__((format(printf, 5, 6)));
206
207template<typename THROWABLE>
208ATTRIBUTE_NORETURN ATTRIBUTE_NOINLINE
209void 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
241namespace 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 */
247extern function<bool(void)> ChecnOperationCanceledCallback;
248
249class HdfsException;
250
251}
252
253namespace Hdfs {
254namespace 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 */
261bool 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 */
269const 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 */
278const char *GetExceptionDetail(const exception_ptr e, std::string &buffer);
279
280const 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 */
288const 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