Kudu C++ client API
status.h
Go to the documentation of this file.
1 // Copyright (c) 2011 The LevelDB Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. See the AUTHORS file for names of contributors.
4 //
5 // A Status encapsulates the result of an operation. It may indicate success,
6 // or it may indicate an error with an associated error message.
7 //
8 // Multiple threads can invoke const methods on a Status without
9 // external synchronization, but if any of the threads may call a
10 // non-const method, all threads accessing the same Status must use
11 // external synchronization.
12 
13 #ifndef KUDU_UTIL_STATUS_H_
14 #define KUDU_UTIL_STATUS_H_
15 
16 // NOTE: using stdint.h instead of cstdint and errno.h instead of cerrno because
17 // this file is supposed to be processed by a compiler lacking C++11 support.
18 #include <errno.h>
19 #include <stdint.h>
20 
21 #include <cstddef>
22 #include <string>
23 
24 // This macro is not defined when status.h is consumed by third party applications.
25 #ifdef KUDU_HEADERS_USE_SHORT_STATUS_MACROS
26 #include <glog/logging.h>
27 #endif
28 
29 #ifdef KUDU_HEADERS_NO_STUBS
30 #include "kudu/gutil/macros.h"
31 #include "kudu/gutil/port.h"
32 #else
33 #include "kudu/client/stubs.h"
34 #endif
35 
36 #include "kudu/util/kudu_export.h"
37 #include "kudu/util/slice.h"
38 
40 #define KUDU_RETURN_NOT_OK(s) do { \
41  const ::kudu::Status& _s = (s); \
42  if (PREDICT_FALSE(!_s.ok())) return _s; \
43  } while (0)
44 
47 #define KUDU_RETURN_NOT_OK_PREPEND(s, msg) do { \
48  const ::kudu::Status& _s = (s); \
49  if (PREDICT_FALSE(!_s.ok())) return _s.CloneAndPrepend(msg); \
50  } while (0)
51 
55 #define KUDU_RETURN_NOT_OK_RET(to_call, to_return) do { \
56  const ::kudu::Status& s = (to_call); \
57  if (PREDICT_FALSE(!s.ok())) return (to_return); \
58  } while (0)
59 
61 #define KUDU_RETURN_NOT_OK_EVAL(s, on_error) do { \
62  const ::kudu::Status& _s = (s); \
63  if (PREDICT_FALSE(!_s.ok())) { \
64  (on_error); \
65  return _s; \
66  } \
67  } while (0)
68 
70 #define KUDU_WARN_NOT_OK(to_call, warning_prefix) do { \
71  const ::kudu::Status& _s = (to_call); \
72  if (PREDICT_FALSE(!_s.ok())) { \
73  KUDU_LOG(WARNING) << (warning_prefix) << ": " << _s.ToString(); \
74  } \
75  } while (0)
76 
78 #define KUDU_LOG_AND_RETURN(level, status) do { \
79  const ::kudu::Status& _s = (status); \
80  KUDU_LOG(level) << _s.ToString(); \
81  return _s; \
82  } while (0)
83 
85 #define KUDU_RETURN_NOT_OK_LOG(s, level, msg) do { \
86  const ::kudu::Status& _s = (s); \
87  if (PREDICT_FALSE(!_s.ok())) { \
88  KUDU_LOG(level) << "Status: " << _s.ToString() << " " << (msg); \
89  return _s; \
90  } \
91  } while (0)
92 
95 #define KUDU_CHECK_OK_PREPEND(to_call, msg) do { \
96  const ::kudu::Status& _s = (to_call); \
97  KUDU_CHECK(_s.ok()) << (msg) << ": " << _s.ToString(); \
98  } while (0)
99 
102 #define KUDU_CHECK_OK(s) KUDU_CHECK_OK_PREPEND(s, "Bad status")
103 
106 #define KUDU_DCHECK_OK_PREPEND(to_call, msg) do { \
107  const ::kudu::Status& _s = (to_call); \
108  KUDU_DCHECK(_s.ok()) << (msg) << ": " << _s.ToString(); \
109  } while (0)
110 
113 #define KUDU_DCHECK_OK(s) KUDU_DCHECK_OK_PREPEND(s, "Bad status")
114 
119 #define KUDU_RETURN_MAIN_NOT_OK(to_call, msg, ret_code) do { \
120  DCHECK_NE(0, (ret_code)) << "non-OK return code should not be 0"; \
121  const ::kudu::Status& _s = (to_call); \
122  if (!_s.ok()) { \
123  const ::kudu::Status& _ss = _s.CloneAndPrepend((msg)); \
124  LOG(ERROR) << _ss.ToString(); \
125  return (ret_code); \
126  } \
127  } while (0)
128 
129 // Introduce [[nodiscard]] attribute if compiling with the C++17 or newer.
130 #if __cplusplus >= 201703L
131  // This works as intended with KUDU_EXPORT and other attributes for LLVM/CLANG
132  // (at least starting version 11.0.0 that's current version in thirdparty),
133  // but GCC prior to version 13.0 is touchy if mixing attributes of different
134  // types/styles, see [1] for details. So, enable this only if compiling with
135  // CLANG or GCC version 13 and newer.
136  //
137  // [1] https://gcc.gnu.org/bugzilla/show_bug.cgi?id=69585 for details).
138  #if defined(__clang__) || (defined(__GNUC__) && __GNUC__ >= 13)
139  #define KUDU_ATTR_NODISCARD [[nodiscard]] // NOLINT(whitespace/braces)
140  #else
141  #define KUDU_ATTR_NODISCARD
142  #endif
143 #else // #if __cplusplus >= 201703L ...
144  #define KUDU_ATTR_NODISCARD
145 #endif // #if __cplusplus >= 201703L ... #else ...
146 
160 #ifdef KUDU_HEADERS_USE_SHORT_STATUS_MACROS
161 #define RETURN_NOT_OK KUDU_RETURN_NOT_OK
162 #define RETURN_NOT_OK_PREPEND KUDU_RETURN_NOT_OK_PREPEND
163 #define RETURN_NOT_OK_RET KUDU_RETURN_NOT_OK_RET
164 #define RETURN_NOT_OK_EVAL KUDU_RETURN_NOT_OK_EVAL
165 #define WARN_NOT_OK KUDU_WARN_NOT_OK
166 #define LOG_AND_RETURN KUDU_LOG_AND_RETURN
167 #define RETURN_NOT_OK_LOG KUDU_RETURN_NOT_OK_LOG
168 #define CHECK_OK_PREPEND KUDU_CHECK_OK_PREPEND
169 #define CHECK_OK KUDU_CHECK_OK
170 #define DCHECK_OK_PREPEND KUDU_DCHECK_OK_PREPEND
171 #define DCHECK_OK KUDU_DCHECK_OK
172 #define RETURN_MAIN_NOT_OK KUDU_RETURN_MAIN_NOT_OK
173 
174 // These are standard glog macros.
175 #define KUDU_LOG LOG
176 #define KUDU_CHECK CHECK
177 #define KUDU_DCHECK DCHECK
178 #endif
179 
180 namespace kudu {
181 
183 class KUDU_EXPORT KUDU_ATTR_NODISCARD Status {
184  public:
186  Status() : state_(NULL) { }
187 
188  ~Status() { delete[] state_; }
189 
194  Status(const Status& s);
195 
201  Status& operator=(const Status& s);
202 
203 #if __cplusplus >= 201103L
208  Status(Status&& s) noexcept;
209 
215  Status& operator=(Status&& s) noexcept;
216 
238  template<typename F>
239  Status AndThen(F op) {
240  if (ok()) {
241  return op();
242  }
243  return *this;
244  }
245 #endif
246 
248  static Status OK() { return Status(); }
249 
252 
260  static Status NotFound(const Slice& msg, const Slice& msg2 = Slice(),
261  int16_t posix_code = -1) {
262  return Status(kNotFound, msg, msg2, posix_code);
263  }
264  static Status Corruption(const Slice& msg, const Slice& msg2 = Slice(),
265  int16_t posix_code = -1) {
266  return Status(kCorruption, msg, msg2, posix_code);
267  }
268  static Status NotSupported(const Slice& msg, const Slice& msg2 = Slice(),
269  int16_t posix_code = -1) {
270  return Status(kNotSupported, msg, msg2, posix_code);
271  }
272  static Status InvalidArgument(const Slice& msg, const Slice& msg2 = Slice(),
273  int16_t posix_code = -1) {
274  return Status(kInvalidArgument, msg, msg2, posix_code);
275  }
276  static Status IOError(const Slice& msg, const Slice& msg2 = Slice(),
277  int16_t posix_code = -1) {
278  return Status(kIOError, msg, msg2, posix_code);
279  }
280  static Status AlreadyPresent(const Slice& msg, const Slice& msg2 = Slice(),
281  int16_t posix_code = -1) {
282  return Status(kAlreadyPresent, msg, msg2, posix_code);
283  }
284  static Status RuntimeError(const Slice& msg, const Slice& msg2 = Slice(),
285  int16_t posix_code = -1) {
286  return Status(kRuntimeError, msg, msg2, posix_code);
287  }
288  static Status NetworkError(const Slice& msg, const Slice& msg2 = Slice(),
289  int16_t posix_code = -1) {
290  return Status(kNetworkError, msg, msg2, posix_code);
291  }
292  static Status IllegalState(const Slice& msg, const Slice& msg2 = Slice(),
293  int16_t posix_code = -1) {
294  return Status(kIllegalState, msg, msg2, posix_code);
295  }
296  static Status NotAuthorized(const Slice& msg, const Slice& msg2 = Slice(),
297  int16_t posix_code = -1) {
298  return Status(kNotAuthorized, msg, msg2, posix_code);
299  }
300  static Status Aborted(const Slice& msg, const Slice& msg2 = Slice(),
301  int16_t posix_code = -1) {
302  return Status(kAborted, msg, msg2, posix_code);
303  }
304  static Status RemoteError(const Slice& msg, const Slice& msg2 = Slice(),
305  int16_t posix_code = -1) {
306  return Status(kRemoteError, msg, msg2, posix_code);
307  }
308  static Status ServiceUnavailable(const Slice& msg, const Slice& msg2 = Slice(),
309  int16_t posix_code = -1) {
310  return Status(kServiceUnavailable, msg, msg2, posix_code);
311  }
312  static Status TimedOut(const Slice& msg, const Slice& msg2 = Slice(),
313  int16_t posix_code = -1) {
314  return Status(kTimedOut, msg, msg2, posix_code);
315  }
316  static Status Uninitialized(const Slice& msg, const Slice& msg2 = Slice(),
317  int16_t posix_code = -1) {
318  return Status(kUninitialized, msg, msg2, posix_code);
319  }
320  static Status ConfigurationError(const Slice& msg, const Slice& msg2 = Slice(),
321  int16_t posix_code = -1) {
322  return Status(kConfigurationError, msg, msg2, posix_code);
323  }
324  static Status Incomplete(const Slice& msg, const Slice& msg2 = Slice(),
325  int64_t posix_code = -1) {
326  return Status(kIncomplete, msg, msg2, posix_code);
327  }
328  static Status EndOfFile(const Slice& msg, const Slice& msg2 = Slice(),
329  int64_t posix_code = -1) {
330  return Status(kEndOfFile, msg, msg2, posix_code);
331  }
332  static Status Immutable(const Slice& msg, const Slice& msg2 = Slice(),
333  int64_t posix_code = -1) {
334  return Status(kImmutable, msg, msg2, posix_code);
335  }
337 
339  bool ok() const { return (state_ == NULL); }
340 
342  bool IsNotFound() const { return code() == kNotFound; }
343 
345  bool IsCorruption() const { return code() == kCorruption; }
346 
348  bool IsNotSupported() const { return code() == kNotSupported; }
349 
351  bool IsIOError() const { return code() == kIOError; }
352 
354  bool IsInvalidArgument() const { return code() == kInvalidArgument; }
355 
357  bool IsAlreadyPresent() const { return code() == kAlreadyPresent; }
358 
360  bool IsRuntimeError() const { return code() == kRuntimeError; }
361 
363  bool IsNetworkError() const { return code() == kNetworkError; }
364 
366  bool IsIllegalState() const { return code() == kIllegalState; }
367 
369  bool IsNotAuthorized() const { return code() == kNotAuthorized; }
370 
372  bool IsAborted() const { return code() == kAborted; }
373 
375  bool IsRemoteError() const { return code() == kRemoteError; }
376 
378  bool IsServiceUnavailable() const { return code() == kServiceUnavailable; }
379 
381  bool IsTimedOut() const { return code() == kTimedOut; }
382 
384  bool IsUninitialized() const { return code() == kUninitialized; }
385 
387  bool IsConfigurationError() const { return code() == kConfigurationError; }
388 
390  bool IsIncomplete() const { return code() == kIncomplete; }
391 
393  bool IsEndOfFile() const { return code() == kEndOfFile; }
394 
396  bool IsImmutable() const { return code() == kImmutable; }
397 
399  bool IsDiskFailure() const {
400  switch (posix_code()) {
401  case EIO:
402  case ENODEV:
403  case ENXIO:
404  case EROFS:
405  return true;
406  }
407  return false;
408  }
409 
412  std::string ToString() const;
413 
416  std::string CodeAsString() const;
417 
426  Slice message() const;
427 
430  int16_t posix_code() const;
431 
440  Status CloneAndPrepend(const Slice& msg) const;
441 
450  Status CloneAndAppend(const Slice& msg) const;
451 
455 
459 
460  private:
461  // OK status has a NULL state_. Otherwise, state_ is a new[] array
462  // of the following form:
463  // state_[0..3] == length of message
464  // state_[4] == code
465  // state_[5..6] == posix_code
466  // state_[7..] == message
467  const char* state_;
468 
469  enum Code {
470  kOk = 0,
471  kNotFound = 1,
472  kCorruption = 2,
473  kNotSupported = 3,
474  kInvalidArgument = 4,
475  kIOError = 5,
476  kAlreadyPresent = 6,
477  kRuntimeError = 7,
478  kNetworkError = 8,
479  kIllegalState = 9,
480  kNotAuthorized = 10,
481  kAborted = 11,
482  kRemoteError = 12,
483  kServiceUnavailable = 13,
484  kTimedOut = 14,
485  kUninitialized = 15,
486  kConfigurationError = 16,
487  kIncomplete = 17,
488  kEndOfFile = 18,
489  // kCancelled stems from AppStatusPB, although it seems nobody use it now, we still reserve it.
490  // kCancelled = 19,
491  kImmutable = 20,
492  // NOTE: Remember to duplicate these constants into wire_protocol.proto and
493  // and to add StatusTo/FromPB ser/deser cases in wire_protocol.cc !
494  // Also remember to make the same changes to the java client in Status.java.
495  //
496  // TODO: Move error codes into an error_code.proto or something similar.
497  };
498  COMPILE_ASSERT(sizeof(Code) == 4, code_enum_size_is_part_of_abi);
499 
500  Code code() const {
501  return (state_ == NULL) ? kOk : static_cast<Code>(state_[4]);
502  }
503 
504  Status(Code code, const Slice& msg, const Slice& msg2, int16_t posix_code);
505  static const char* CopyState(const char* s);
506 };
507 
508 inline Status::Status(const Status& s) {
509  state_ = (s.state_ == NULL) ? NULL : CopyState(s.state_);
510 }
511 
512 inline Status& Status::operator=(const Status& s) {
513  // The following condition catches both aliasing (when this == &s),
514  // and the common case where both s and *this are OK.
515  if (state_ != s.state_) {
516  delete[] state_;
517  state_ = (s.state_ == NULL) ? NULL : CopyState(s.state_);
518  }
519  return *this;
520 }
521 
522 #if __cplusplus >= 201103L
523 inline Status::Status(Status&& s) noexcept : state_(s.state_) {
524  s.state_ = nullptr;
525 }
526 
527 inline Status& Status::operator=(Status&& s) noexcept {
528  if (state_ != s.state_) {
529  delete[] state_;
530  state_ = s.state_;
531  s.state_ = nullptr;
532  }
533  return *this;
534 }
535 #endif
536 
537 } // namespace kudu
538 
539 #endif // KUDU_UTIL_STATUS_H_
A wrapper around externally allocated data.
Definition: slice.h:51
A representation of an operation's outcome.
Definition: status.h:183
bool IsInvalidArgument() const
Definition: status.h:354
static Status TimedOut(const Slice &msg, const Slice &msg2=Slice(), int16_t posix_code=-1)
Definition: status.h:312
bool IsRemoteError() const
Definition: status.h:375
size_t memory_footprint_including_this() const
bool IsEndOfFile() const
Definition: status.h:393
static Status Immutable(const Slice &msg, const Slice &msg2=Slice(), int64_t posix_code=-1)
Definition: status.h:332
bool IsTimedOut() const
Definition: status.h:381
bool IsUninitialized() const
Definition: status.h:384
static Status RuntimeError(const Slice &msg, const Slice &msg2=Slice(), int16_t posix_code=-1)
Definition: status.h:284
static Status IOError(const Slice &msg, const Slice &msg2=Slice(), int16_t posix_code=-1)
Definition: status.h:276
int16_t posix_code() const
bool IsAlreadyPresent() const
Definition: status.h:357
bool IsCorruption() const
Definition: status.h:345
size_t memory_footprint_excluding_this() const
static Status ServiceUnavailable(const Slice &msg, const Slice &msg2=Slice(), int16_t posix_code=-1)
Definition: status.h:308
static Status Corruption(const Slice &msg, const Slice &msg2=Slice(), int16_t posix_code=-1)
Definition: status.h:264
bool IsIOError() const
Definition: status.h:351
static Status IllegalState(const Slice &msg, const Slice &msg2=Slice(), int16_t posix_code=-1)
Definition: status.h:292
bool IsAborted() const
Definition: status.h:372
static Status Aborted(const Slice &msg, const Slice &msg2=Slice(), int16_t posix_code=-1)
Definition: status.h:300
std::string CodeAsString() const
static Status NotSupported(const Slice &msg, const Slice &msg2=Slice(), int16_t posix_code=-1)
Definition: status.h:268
Status CloneAndAppend(const Slice &msg) const
bool IsNotFound() const
Definition: status.h:342
bool IsServiceUnavailable() const
Definition: status.h:378
bool IsConfigurationError() const
Definition: status.h:387
static Status AlreadyPresent(const Slice &msg, const Slice &msg2=Slice(), int16_t posix_code=-1)
Definition: status.h:280
Status & operator=(const Status &s)
Definition: status.h:512
bool IsDiskFailure() const
Definition: status.h:399
static Status NotFound(const Slice &msg, const Slice &msg2=Slice(), int16_t posix_code=-1)
Definition: status.h:260
bool IsNotSupported() const
Definition: status.h:348
static Status InvalidArgument(const Slice &msg, const Slice &msg2=Slice(), int16_t posix_code=-1)
Definition: status.h:272
static Status Incomplete(const Slice &msg, const Slice &msg2=Slice(), int64_t posix_code=-1)
Definition: status.h:324
Status CloneAndPrepend(const Slice &msg) const
static Status NetworkError(const Slice &msg, const Slice &msg2=Slice(), int16_t posix_code=-1)
Definition: status.h:288
static Status Uninitialized(const Slice &msg, const Slice &msg2=Slice(), int16_t posix_code=-1)
Definition: status.h:316
bool IsIncomplete() const
Definition: status.h:390
bool IsNotAuthorized() const
Definition: status.h:369
static Status NotAuthorized(const Slice &msg, const Slice &msg2=Slice(), int16_t posix_code=-1)
Definition: status.h:296
Status()
Create an object representing success status.
Definition: status.h:186
bool IsIllegalState() const
Definition: status.h:366
bool IsNetworkError() const
Definition: status.h:363
bool IsImmutable() const
Definition: status.h:396
static Status OK()
Definition: status.h:248
bool ok() const
Definition: status.h:339
bool IsRuntimeError() const
Definition: status.h:360
std::string ToString() const
static Status EndOfFile(const Slice &msg, const Slice &msg2=Slice(), int64_t posix_code=-1)
Definition: status.h:328
static Status ConfigurationError(const Slice &msg, const Slice &msg2=Slice(), int16_t posix_code=-1)
Definition: status.h:320
static Status RemoteError(const Slice &msg, const Slice &msg2=Slice(), int16_t posix_code=-1)
Definition: status.h:304
Slice message() const