1 | /* Copyright 2015 The TensorFlow Authors. All Rights Reserved. |
2 | |
3 | Licensed under the Apache License, Version 2.0 (the "License"); |
4 | you may not use this file except in compliance with the License. |
5 | You may obtain a copy of the License at |
6 | |
7 | http://www.apache.org/licenses/LICENSE-2.0 |
8 | |
9 | Unless required by applicable law or agreed to in writing, software |
10 | distributed under the License is distributed on an "AS IS" BASIS, |
11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
12 | See the License for the specific language governing permissions and |
13 | limitations under the License. |
14 | ==============================================================================*/ |
15 | |
16 | #ifndef TENSORFLOW_TSL_PLATFORM_ERRORS_H_ |
17 | #define TENSORFLOW_TSL_PLATFORM_ERRORS_H_ |
18 | |
19 | #include <sstream> |
20 | #include <string> |
21 | #include <utility> |
22 | |
23 | #include "absl/base/attributes.h" |
24 | #include "absl/strings/str_join.h" |
25 | #include "tensorflow/tsl/platform/logging.h" |
26 | #include "tensorflow/tsl/platform/macros.h" |
27 | #include "tensorflow/tsl/platform/status.h" |
28 | #include "tensorflow/tsl/platform/str_util.h" |
29 | #include "tensorflow/tsl/platform/strcat.h" |
30 | |
31 | namespace tsl { |
32 | namespace error { |
33 | // NOLINTBEGIN(misc-unused-using-decls) |
34 | // TODO(aminim): figure out the protobuf migration story. |
35 | using tensorflow::error::ABORTED; |
36 | using tensorflow::error::ALREADY_EXISTS; |
37 | using tensorflow::error::CANCELLED; |
38 | using tensorflow::error::Code; |
39 | using tensorflow::error::DATA_LOSS; |
40 | using tensorflow::error::DEADLINE_EXCEEDED; |
41 | using tensorflow::error::FAILED_PRECONDITION; |
42 | using tensorflow::error::INTERNAL; |
43 | using tensorflow::error::INVALID_ARGUMENT; |
44 | using tensorflow::error::NOT_FOUND; |
45 | using tensorflow::error::OK; |
46 | using tensorflow::error::OUT_OF_RANGE; |
47 | using tensorflow::error::PERMISSION_DENIED; |
48 | using tensorflow::error::RESOURCE_EXHAUSTED; |
49 | using tensorflow::error::UNAUTHENTICATED; |
50 | using tensorflow::error::UNAVAILABLE; |
51 | using tensorflow::error::UNIMPLEMENTED; |
52 | using tensorflow::error::UNKNOWN; |
53 | // NOLINTEND(misc-unused-using-decls) |
54 | } // namespace error |
55 | |
56 | namespace errors { |
57 | |
58 | namespace internal { |
59 | |
60 | // The DECLARE_ERROR macro below only supports types that can be converted |
61 | // into StrCat's AlphaNum. For the other types we rely on a slower path |
62 | // through std::stringstream. To add support of a new type, it is enough to |
63 | // make sure there is an operator<<() for it: |
64 | // |
65 | // std::ostream& operator<<(std::ostream& os, const MyType& foo) { |
66 | // os << foo.ToString(); |
67 | // return os; |
68 | // } |
69 | // Eventually absl::strings will have native support for this and we will be |
70 | // able to completely remove PrepareForStrCat(). |
71 | template <typename T> |
72 | typename std::enable_if<!std::is_convertible<T, strings::AlphaNum>::value, |
73 | std::string>::type |
74 | PrepareForStrCat(const T& t) { |
75 | std::stringstream ss; |
76 | ss << t; |
77 | return ss.str(); |
78 | } |
79 | inline const strings::AlphaNum& PrepareForStrCat(const strings::AlphaNum& a) { |
80 | return a; |
81 | } |
82 | |
83 | } // namespace internal |
84 | |
85 | // Maps UNIX errors into a Status. |
86 | Status IOError(const string& context, int err_number); |
87 | |
88 | // Returns all payloads from a Status as a key-value map. |
89 | inline std::unordered_map<std::string, std::string> GetPayloads( |
90 | const ::tsl::Status& status) { |
91 | std::unordered_map<std::string, std::string> payloads; |
92 | status.ForEachPayload( |
93 | [&payloads](tsl::StringPiece key, tsl::StringPiece value) { |
94 | payloads[std::string(key)] = std::string(value); |
95 | }); |
96 | return payloads; |
97 | } |
98 | |
99 | // Inserts all given payloads into the given status. Will overwrite existing |
100 | // payloads if they exist with the same key. |
101 | inline void InsertPayloads( |
102 | ::tsl::Status& status, |
103 | const std::unordered_map<std::string, std::string>& payloads) { |
104 | for (const auto& payload : payloads) { |
105 | status.SetPayload(payload.first, payload.second); |
106 | } |
107 | } |
108 | |
109 | // Copies all payloads from one Status to another. Will overwrite existing |
110 | // payloads in the destination if they exist with the same key. |
111 | inline void CopyPayloads(const ::tsl::Status& from, ::tsl::Status& to) { |
112 | from.ForEachPayload([&to](tsl::StringPiece key, tsl::StringPiece value) { |
113 | to.SetPayload(key, value); |
114 | }); |
115 | } |
116 | |
117 | // Creates a new status with the given code, message and payloads. |
118 | inline ::tsl::Status Create( |
119 | Code code, ::tsl::StringPiece message, |
120 | const std::unordered_map<std::string, std::string>& payloads) { |
121 | Status status(code, message); |
122 | InsertPayloads(status, payloads); |
123 | return status; |
124 | } |
125 | |
126 | // Returns a new Status, replacing its message with the given. |
127 | inline ::tsl::Status CreateWithUpdatedMessage(const ::tsl::Status& status, |
128 | ::tsl::StringPiece message) { |
129 | return Create(status.code(), message, GetPayloads(status)); |
130 | } |
131 | |
132 | // Append some context to an error message. Each time we append |
133 | // context put it on a new line, since it is possible for there |
134 | // to be several layers of additional context. |
135 | template <typename... Args> |
136 | void AppendToMessage(::tsl::Status* status, Args... args) { |
137 | auto new_status = ::tsl::Status( |
138 | status->code(), |
139 | ::tsl::strings::StrCat(status->error_message(), "\n\t" , args...)); |
140 | CopyPayloads(*status, new_status); |
141 | *status = std::move(new_status); |
142 | } |
143 | |
144 | // For propagating errors when calling a function. |
145 | #define TF_RETURN_IF_ERROR(...) \ |
146 | do { \ |
147 | ::tsl::Status _status = (__VA_ARGS__); \ |
148 | if (TF_PREDICT_FALSE(!_status.ok())) return _status; \ |
149 | } while (0) |
150 | |
151 | #define TF_RETURN_WITH_CONTEXT_IF_ERROR(expr, ...) \ |
152 | do { \ |
153 | ::tsl::Status _status = (expr); \ |
154 | if (TF_PREDICT_FALSE(!_status.ok())) { \ |
155 | ::tsl::errors::AppendToMessage(&_status, __VA_ARGS__); \ |
156 | return _status; \ |
157 | } \ |
158 | } while (0) |
159 | |
160 | // Convenience functions for generating and using error status. |
161 | // Example usage: |
162 | // status.Update(errors::InvalidArgument("The ", foo, " isn't right.")); |
163 | // if (errors::IsInvalidArgument(status)) { ... } |
164 | // switch (status.code()) { case error::INVALID_ARGUMENT: ... } |
165 | |
166 | // CANCELLED |
167 | template <typename... Args> |
168 | ::tsl::Status Cancelled(Args... args) { |
169 | return ::tsl::Status(::tsl::error::Code::CANCELLED, |
170 | ::tsl::strings::StrCat( |
171 | ::tsl::errors::internal::PrepareForStrCat(args)...)); |
172 | } |
173 | template <typename... Args> |
174 | ::tsl::Status CancelledWithPayloads( |
175 | const ::tsl::StringPiece& message, |
176 | const std::unordered_map<std::string, std::string>& payloads) { |
177 | return errors::Create(::tsl::error::Code::CANCELLED, message, payloads); |
178 | } |
179 | |
180 | // InvalidArgument |
181 | template <typename... Args> |
182 | ::tsl::Status InvalidArgument(Args... args) { |
183 | return ::tsl::Status(::tsl::error::Code::INVALID_ARGUMENT, |
184 | ::tsl::strings::StrCat( |
185 | ::tsl::errors::internal::PrepareForStrCat(args)...)); |
186 | } |
187 | template <typename... Args> |
188 | ::tsl::Status InvalidArgumentWithPayloads( |
189 | const ::tsl::StringPiece& message, |
190 | const std::unordered_map<std::string, std::string>& payloads) { |
191 | return errors::Create(::tsl::error::Code::INVALID_ARGUMENT, message, |
192 | payloads); |
193 | } |
194 | |
195 | // NotFound |
196 | template <typename... Args> |
197 | ::tsl::Status NotFound(Args... args) { |
198 | return ::tsl::Status(::tsl::error::Code::NOT_FOUND, |
199 | ::tsl::strings::StrCat( |
200 | ::tsl::errors::internal::PrepareForStrCat(args)...)); |
201 | } |
202 | template <typename... Args> |
203 | ::tsl::Status NotFoundWithPayloads( |
204 | const ::tsl::StringPiece& message, |
205 | const std::unordered_map<std::string, std::string>& payloads) { |
206 | return errors::Create(::tsl::error::Code::NOT_FOUND, message, payloads); |
207 | } |
208 | |
209 | // AlreadyExists |
210 | template <typename... Args> |
211 | ::tsl::Status AlreadyExists(Args... args) { |
212 | return ::tsl::Status(::tsl::error::Code::ALREADY_EXISTS, |
213 | ::tsl::strings::StrCat( |
214 | ::tsl::errors::internal::PrepareForStrCat(args)...)); |
215 | } |
216 | template <typename... Args> |
217 | ::tsl::Status AlreadyExistsWithPayloads( |
218 | const ::tsl::StringPiece& message, |
219 | const std::unordered_map<std::string, std::string>& payloads) { |
220 | return errors::Create(::tsl::error::Code::ALREADY_EXISTS, message, payloads); |
221 | } |
222 | |
223 | // ResourceExhausted |
224 | template <typename... Args> |
225 | ::tsl::Status ResourceExhausted(Args... args) { |
226 | return ::tsl::Status(::tsl::error::Code::RESOURCE_EXHAUSTED, |
227 | ::tsl::strings::StrCat( |
228 | ::tsl::errors::internal::PrepareForStrCat(args)...)); |
229 | } |
230 | template <typename... Args> |
231 | ::tsl::Status ResourceExhaustedWithPayloads( |
232 | const ::tsl::StringPiece& message, |
233 | const std::unordered_map<std::string, std::string>& payloads) { |
234 | return errors::Create(::tsl::error::Code::RESOURCE_EXHAUSTED, message, |
235 | payloads); |
236 | } |
237 | |
238 | // Unavailable |
239 | template <typename... Args> |
240 | ::tsl::Status Unavailable(Args... args) { |
241 | return ::tsl::Status(::tsl::error::Code::UNAVAILABLE, |
242 | ::tsl::strings::StrCat( |
243 | ::tsl::errors::internal::PrepareForStrCat(args)...)); |
244 | } |
245 | template <typename... Args> |
246 | ::tsl::Status UnavailableWithPayloads( |
247 | const ::tsl::StringPiece& message, |
248 | const std::unordered_map<std::string, std::string>& payloads) { |
249 | return errors::Create(::tsl::error::Code::UNAVAILABLE, message, payloads); |
250 | } |
251 | |
252 | // FailedPrecondition |
253 | template <typename... Args> |
254 | ::tsl::Status FailedPrecondition(Args... args) { |
255 | return ::tsl::Status(::tsl::error::Code::FAILED_PRECONDITION, |
256 | ::tsl::strings::StrCat( |
257 | ::tsl::errors::internal::PrepareForStrCat(args)...)); |
258 | } |
259 | template <typename... Args> |
260 | ::tsl::Status FailedPreconditionWithPayloads( |
261 | const ::tsl::StringPiece& message, |
262 | const std::unordered_map<std::string, std::string>& payloads) { |
263 | return errors::Create(::tsl::error::Code::FAILED_PRECONDITION, message, |
264 | payloads); |
265 | } |
266 | |
267 | // OutOfRange |
268 | template <typename... Args> |
269 | ::tsl::Status OutOfRange(Args... args) { |
270 | return ::tsl::Status(::tsl::error::Code::OUT_OF_RANGE, |
271 | ::tsl::strings::StrCat( |
272 | ::tsl::errors::internal::PrepareForStrCat(args)...)); |
273 | } |
274 | template <typename... Args> |
275 | ::tsl::Status OutOfRangeWithPayloads( |
276 | const ::tsl::StringPiece& message, |
277 | const std::unordered_map<std::string, std::string>& payloads) { |
278 | return errors::Create(::tsl::error::Code::OUT_OF_RANGE, message, payloads); |
279 | } |
280 | |
281 | // Unimplemented |
282 | template <typename... Args> |
283 | ::tsl::Status Unimplemented(Args... args) { |
284 | return ::tsl::Status(::tsl::error::Code::UNIMPLEMENTED, |
285 | ::tsl::strings::StrCat( |
286 | ::tsl::errors::internal::PrepareForStrCat(args)...)); |
287 | } |
288 | template <typename... Args> |
289 | ::tsl::Status UnimplementedWithPayloads( |
290 | const ::tsl::StringPiece& message, |
291 | const std::unordered_map<std::string, std::string>& payloads) { |
292 | return errors::Create(::tsl::error::Code::UNIMPLEMENTED, message, payloads); |
293 | } |
294 | |
295 | // Internal |
296 | template <typename... Args> |
297 | ::tsl::Status Internal(Args... args) { |
298 | return ::tsl::Status(::tsl::error::Code::INTERNAL, |
299 | ::tsl::strings::StrCat( |
300 | ::tsl::errors::internal::PrepareForStrCat(args)...)); |
301 | } |
302 | template <typename... Args> |
303 | ::tsl::Status InternalWithPayloads( |
304 | const ::tsl::StringPiece& message, |
305 | const std::unordered_map<std::string, std::string>& payloads) { |
306 | return errors::Create(::tsl::error::Code::INTERNAL, message, payloads); |
307 | } |
308 | |
309 | // Aborted |
310 | template <typename... Args> |
311 | ::tsl::Status Aborted(Args... args) { |
312 | return ::tsl::Status(::tsl::error::Code::ABORTED, |
313 | ::tsl::strings::StrCat( |
314 | ::tsl::errors::internal::PrepareForStrCat(args)...)); |
315 | } |
316 | template <typename... Args> |
317 | ::tsl::Status AbortedWithPayloads( |
318 | const ::tsl::StringPiece& message, |
319 | const std::unordered_map<std::string, std::string>& payloads) { |
320 | return errors::Create(::tsl::error::Code::ABORTED, message, payloads); |
321 | } |
322 | |
323 | // DeadlineExceeded |
324 | template <typename... Args> |
325 | ::tsl::Status DeadlineExceeded(Args... args) { |
326 | return ::tsl::Status(::tsl::error::Code::DEADLINE_EXCEEDED, |
327 | ::tsl::strings::StrCat( |
328 | ::tsl::errors::internal::PrepareForStrCat(args)...)); |
329 | } |
330 | template <typename... Args> |
331 | ::tsl::Status DeadlineExceededWithPayloads( |
332 | const ::tsl::StringPiece& message, |
333 | const std::unordered_map<std::string, std::string>& payloads) { |
334 | return errors::Create(::tsl::error::Code::DEADLINE_EXCEEDED, message, |
335 | payloads); |
336 | } |
337 | |
338 | // DataLoss |
339 | template <typename... Args> |
340 | ::tsl::Status DataLoss(Args... args) { |
341 | return ::tsl::Status(::tsl::error::Code::DATA_LOSS, |
342 | ::tsl::strings::StrCat( |
343 | ::tsl::errors::internal::PrepareForStrCat(args)...)); |
344 | } |
345 | template <typename... Args> |
346 | ::tsl::Status DataLossWithPayloads( |
347 | const ::tsl::StringPiece& message, |
348 | const std::unordered_map<std::string, std::string>& payloads) { |
349 | return errors::Create(::tsl::error::Code::DATA_LOSS, message, payloads); |
350 | } |
351 | |
352 | // Unknown |
353 | template <typename... Args> |
354 | ::tsl::Status Unknown(Args... args) { |
355 | return ::tsl::Status(::tsl::error::Code::UNKNOWN, |
356 | ::tsl::strings::StrCat( |
357 | ::tsl::errors::internal::PrepareForStrCat(args)...)); |
358 | } |
359 | template <typename... Args> |
360 | ::tsl::Status UnknownPayloads( |
361 | const ::tsl::StringPiece& message, |
362 | const std::unordered_map<std::string, std::string>& payloads) { |
363 | return errors::Create(::tsl::error::Code::UNKNOWN, message, payloads); |
364 | } |
365 | // PermissionDenied |
366 | template <typename... Args> |
367 | ::tsl::Status PermissionDenied(Args... args) { |
368 | return ::tsl::Status(::tsl::error::Code::PERMISSION_DENIED, |
369 | ::tsl::strings::StrCat( |
370 | ::tsl::errors::internal::PrepareForStrCat(args)...)); |
371 | } |
372 | template <typename... Args> |
373 | ::tsl::Status PermissionDeniedWithPayloads( |
374 | const ::tsl::StringPiece& message, |
375 | const std::unordered_map<std::string, std::string>& payloads) { |
376 | return errors::Create(::tsl::error::Code::PERMISSION_DENIED, message, |
377 | payloads); |
378 | } |
379 | |
380 | // Unauthenticated |
381 | template <typename... Args> |
382 | ::tsl::Status Unauthenticated(Args... args) { |
383 | return ::tsl::Status(::tsl::error::Code::UNAUTHENTICATED, |
384 | ::tsl::strings::StrCat( |
385 | ::tsl::errors::internal::PrepareForStrCat(args)...)); |
386 | } |
387 | template <typename... Args> |
388 | ::tsl::Status UnauthenticatedWithPayloads( |
389 | const ::tsl::StringPiece& message, |
390 | const std::unordered_map<std::string, std::string>& payloads) { |
391 | return errors::Create(::tsl::error::Code::UNAUTHENTICATED, message, payloads); |
392 | } |
393 | |
394 | bool IsAborted(const Status& status); |
395 | bool IsAlreadyExists(const Status& status); |
396 | bool IsCancelled(const Status& status); |
397 | bool IsDataLoss(const Status& status); |
398 | bool IsDeadlineExceeded(const Status& status); |
399 | bool IsFailedPrecondition(const Status& status); |
400 | bool IsInternal(const Status& status); |
401 | bool IsInvalidArgument(const Status& status); |
402 | bool IsNotFound(const Status& status); |
403 | bool IsOutOfRange(const Status& status); |
404 | bool IsPermissionDenied(const Status& status); |
405 | bool IsResourceExhausted(const Status& status); |
406 | bool IsUnauthenticated(const Status& status); |
407 | bool IsUnavailable(const Status& status); |
408 | bool IsUnimplemented(const Status& status); |
409 | bool IsUnknown(const Status& status); |
410 | |
411 | // Produces a formatted string pattern from the name which can uniquely identify |
412 | // this node upstream to produce an informative error message. The pattern |
413 | // followed is: {{node <name>}} |
414 | // Note: The pattern below determines the regex _NODEDEF_NAME_RE in the file |
415 | // tensorflow/python/client/session.py |
416 | // LINT.IfChange |
417 | inline std::string FormatNodeNameForError(const std::string& name) { |
418 | return strings::StrCat("{{node " , name, "}}" ); |
419 | } |
420 | // LINT.ThenChange(//tensorflow/python/client/session.py) |
421 | template <typename T> |
422 | std::string FormatNodeNamesForError(const T& names) { |
423 | return absl::StrJoin( |
424 | names, ", " , [](std::string* output, const std::string& s) { |
425 | ::tsl::strings::StrAppend(output, FormatNodeNameForError(s)); |
426 | }); |
427 | } |
428 | // LINT.IfChange |
429 | inline std::string FormatColocationNodeForError(const std::string& name) { |
430 | return strings::StrCat("{{colocation_node " , name, "}}" ); |
431 | } |
432 | // LINT.ThenChange(//tensorflow/python/framework/error_interpolation.py) |
433 | template <typename T> |
434 | std::string FormatColocationNodeForError(const T& names) { |
435 | return absl::StrJoin( |
436 | names, ", " , [](std::string* output, const std::string& s) { |
437 | ::tsl::strings::StrAppend(output, FormatColocationNodeForError(s)); |
438 | }); |
439 | } |
440 | |
441 | inline std::string FormatFunctionForError(const std::string& name) { |
442 | return strings::StrCat("{{function_node " , name, "}}" ); |
443 | } |
444 | |
445 | inline Status ReplaceErrorFromNonCommunicationOps(const Status s, |
446 | const std::string& op_name) { |
447 | assert(::tsl::errors::IsUnavailable(s)); |
448 | return Status( |
449 | error::Code::INTERNAL, |
450 | strings::StrCat( |
451 | s.error_message(), "\nExecuting non-communication op <" , op_name, |
452 | "> originally returned UnavailableError, and was replaced by " |
453 | "InternalError to avoid invoking TF network error handling logic." )); |
454 | } |
455 | |
456 | template <typename T> |
457 | std::string FormatOriginalNodeLocationForError(const T& node_names, |
458 | const T& func_names) { |
459 | std::vector<std::string> error_message; |
460 | for (int i = 0; i != node_names.size(); ++i) { |
461 | if (i != 0) { |
462 | error_message.push_back(", " ); |
463 | } |
464 | if (i < func_names.size()) { |
465 | error_message.push_back(FormatFunctionForError(func_names[i])); |
466 | } |
467 | error_message.push_back(FormatNodeNameForError(node_names[i])); |
468 | } |
469 | return absl::StrJoin(error_message, "" ); |
470 | } |
471 | |
472 | // The CanonicalCode() for non-errors. |
473 | using ::tsl::error::OK; // NOLINT |
474 | |
475 | } // namespace errors |
476 | } // namespace tsl |
477 | |
478 | #endif // TENSORFLOW_TSL_PLATFORM_ERRORS_H_ |
479 | |