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 | #include "platform.h" |
29 | |
30 | #include "Exception.h" |
31 | #include "ExceptionInternal.h" |
32 | #include "Thread.h" |
33 | |
34 | #include <cstring> |
35 | #include <cassert> |
36 | #include <sstream> |
37 | |
38 | namespace Hdfs { |
39 | |
40 | function<bool(void)> ChecnOperationCanceledCallback; |
41 | |
42 | namespace Internal { |
43 | |
44 | bool CheckOperationCanceled() { |
45 | if (ChecnOperationCanceledCallback && ChecnOperationCanceledCallback()) { |
46 | THROW(HdfsCanceled, "Operation has been canceled by the user." ); |
47 | } |
48 | |
49 | return false; |
50 | } |
51 | |
52 | const char * GetSystemErrorInfo(int eno) { |
53 | static THREAD_LOCAL char message[64]; |
54 | char buffer[64], *pbuffer; |
55 | pbuffer = buffer; |
56 | #ifdef STRERROR_R_RETURN_INT |
57 | strerror_r(eno, buffer, sizeof(buffer)); |
58 | #else |
59 | pbuffer = strerror_r(eno, buffer, sizeof(buffer)); |
60 | #endif |
61 | snprintf(message, sizeof(message), "(errno: %d) %s" , eno, pbuffer); |
62 | return message; |
63 | } |
64 | |
65 | static void GetExceptionDetailInternal(const Hdfs::HdfsException & e, |
66 | std::stringstream & ss, bool topLevel); |
67 | |
68 | static void GetExceptionDetailInternal(const std::exception & e, |
69 | std::stringstream & ss, bool topLevel) { |
70 | try { |
71 | if (!topLevel) { |
72 | ss << "Caused by\n" ; |
73 | } |
74 | |
75 | ss << e.what(); |
76 | } catch (const std::bad_alloc & e) { |
77 | return; |
78 | } |
79 | |
80 | try { |
81 | Hdfs::rethrow_if_nested(e); |
82 | } catch (const Hdfs::HdfsException & nested) { |
83 | GetExceptionDetailInternal(nested, ss, false); |
84 | } catch (const std::exception & nested) { |
85 | GetExceptionDetailInternal(nested, ss, false); |
86 | } |
87 | } |
88 | |
89 | static void GetExceptionDetailInternal(const Hdfs::HdfsException & e, |
90 | std::stringstream & ss, bool topLevel) { |
91 | try { |
92 | if (!topLevel) { |
93 | ss << "Caused by\n" ; |
94 | } |
95 | |
96 | ss << e.msg(); |
97 | } catch (const std::bad_alloc & e) { |
98 | return; |
99 | } |
100 | |
101 | try { |
102 | Hdfs::rethrow_if_nested(e); |
103 | } catch (const Hdfs::HdfsException & nested) { |
104 | GetExceptionDetailInternal(nested, ss, false); |
105 | } catch (const std::exception & nested) { |
106 | GetExceptionDetailInternal(nested, ss, false); |
107 | } |
108 | } |
109 | |
110 | const char* GetExceptionDetail(const Hdfs::HdfsException& e, |
111 | std::string& buffer) { |
112 | try { |
113 | std::stringstream ss; |
114 | ss.imbue(std::locale::classic()); |
115 | GetExceptionDetailInternal(e, ss, true); |
116 | buffer = ss.str(); |
117 | } catch (const std::bad_alloc& e) { |
118 | return "Out of memory" ; |
119 | } |
120 | |
121 | return buffer.c_str(); |
122 | } |
123 | |
124 | const char* GetExceptionDetail(const exception_ptr e, std::string& buffer) { |
125 | std::stringstream ss; |
126 | ss.imbue(std::locale::classic()); |
127 | |
128 | try { |
129 | Hdfs::rethrow_exception(e); |
130 | } catch (const Hdfs::HdfsException& nested) { |
131 | GetExceptionDetailInternal(nested, ss, true); |
132 | } catch (const std::exception& nested) { |
133 | GetExceptionDetailInternal(nested, ss, true); |
134 | } |
135 | |
136 | try { |
137 | buffer = ss.str(); |
138 | } catch (const std::bad_alloc& e) { |
139 | return "Out of memory" ; |
140 | } |
141 | |
142 | return buffer.c_str(); |
143 | } |
144 | |
145 | static void GetExceptionMessage(const std::exception & e, |
146 | std::stringstream & ss, int recursive) { |
147 | try { |
148 | for (int i = 0; i < recursive; ++i) { |
149 | ss << '\t'; |
150 | } |
151 | |
152 | if (recursive > 0) { |
153 | ss << "Caused by: " ; |
154 | } |
155 | |
156 | ss << e.what(); |
157 | } catch (const std::bad_alloc & e) { |
158 | return; |
159 | } |
160 | |
161 | try { |
162 | Hdfs::rethrow_if_nested(e); |
163 | } catch (const std::exception & nested) { |
164 | GetExceptionMessage(nested, ss, recursive + 1); |
165 | } |
166 | } |
167 | |
168 | const char * GetExceptionMessage(const exception_ptr e, std::string & buffer) { |
169 | std::stringstream ss; |
170 | ss.imbue(std::locale::classic()); |
171 | |
172 | try { |
173 | Hdfs::rethrow_exception(e); |
174 | } catch (const std::bad_alloc & e) { |
175 | return "Out of memory" ; |
176 | } catch (const std::exception & e) { |
177 | GetExceptionMessage(e, ss, 0); |
178 | } |
179 | |
180 | try { |
181 | buffer = ss.str(); |
182 | } catch (const std::bad_alloc & e) { |
183 | return "Out of memory" ; |
184 | } |
185 | |
186 | return buffer.c_str(); |
187 | } |
188 | |
189 | } |
190 | } |
191 | |
192 | |