Wyatt Hepler | f9fb90f | 2020-09-30 18:59:33 -0700 | [diff] [blame] | 1 | .. _module-pw_status: |
Wyatt Hepler | ee3e02f | 2019-12-05 10:52:31 -0800 | [diff] [blame] | 2 | |
| 3 | --------- |
| 4 | pw_status |
| 5 | --------- |
Wyatt Hepler | bb57d9c | 2020-09-25 16:27:38 -0700 | [diff] [blame] | 6 | ``pw_status`` provides features for communicating the result of an operation. |
| 7 | The classes in ``pw_status`` are used extensively throughout Pigweed. |
| 8 | |
| 9 | pw::Status |
| 10 | ========== |
| 11 | The primary feature of ``pw_status`` is the ``pw::Status`` class. |
Wyatt Hepler | ee3e02f | 2019-12-05 10:52:31 -0800 | [diff] [blame] | 12 | ``pw::Status`` (``pw_status/status.h``) is a simple, zero-overhead status |
Wyatt Hepler | bb57d9c | 2020-09-25 16:27:38 -0700 | [diff] [blame] | 13 | object that wraps a status code. |
Wyatt Hepler | ee3e02f | 2019-12-05 10:52:31 -0800 | [diff] [blame] | 14 | |
Wyatt Hepler | bb57d9c | 2020-09-25 16:27:38 -0700 | [diff] [blame] | 15 | ``pw::Status`` uses Google's standard status codes (see the `Google APIs |
| 16 | repository <https://github.com/googleapis/googleapis/blob/master/google/rpc/code.proto>`_). |
| 17 | These codes are used extensively in Google projects including `Abseil |
| 18 | <https://abseil.io>`_ (`status/status.h |
| 19 | <https://cs.opensource.google/abseil/abseil-cpp/+/master:absl/status/status.h>`_ |
| 20 | ) and `gRPC <https://grpc.io>`_ (`doc/statuscodes.md |
| 21 | <https://github.com/grpc/grpc/blob/master/doc/statuscodes.md>`_). |
| 22 | |
Wyatt Hepler | 5a53dfd | 2021-01-08 08:34:27 -0800 | [diff] [blame] | 23 | An OK ``Status`` is created by the ``pw::OkStatus`` function or by the default |
| 24 | ``Status`` constructor. Non-OK ``Status`` is created with a static member |
| 25 | function that corresponds with the status code. |
Wyatt Hepler | bb57d9c | 2020-09-25 16:27:38 -0700 | [diff] [blame] | 26 | |
| 27 | .. code-block:: cpp |
| 28 | |
| 29 | // Ok (gRPC code "OK") does not indicate an error; this value is returned on |
| 30 | // success. It is typical to check for this value before proceeding on any |
| 31 | // given call across an API or RPC boundary. To check this value, use the |
Wyatt Hepler | 5a53dfd | 2021-01-08 08:34:27 -0800 | [diff] [blame] | 32 | // `status.ok()` member function rather than inspecting the raw code. |
| 33 | // |
| 34 | // OkStatus() is provided as a free function, rather than a static member |
| 35 | // function like the error statuses to avoid conflicts with the ok() member |
| 36 | // function. Status::Ok() would be too similar to Status::ok(). |
| 37 | pw::OkStatus() |
Wyatt Hepler | bb57d9c | 2020-09-25 16:27:38 -0700 | [diff] [blame] | 38 | |
| 39 | // Cancelled (gRPC code "CANCELLED") indicates the operation was cancelled, |
| 40 | // typically by the caller. |
Wyatt Hepler | 5a53dfd | 2021-01-08 08:34:27 -0800 | [diff] [blame] | 41 | pw::Status::Cancelled() |
Wyatt Hepler | bb57d9c | 2020-09-25 16:27:38 -0700 | [diff] [blame] | 42 | |
| 43 | // Unknown (gRPC code "UNKNOWN") indicates an unknown error occurred. In |
| 44 | // general, more specific errors should be raised, if possible. Errors raised |
| 45 | // by APIs that do not return enough error information may be converted to |
| 46 | // this error. |
Wyatt Hepler | 5a53dfd | 2021-01-08 08:34:27 -0800 | [diff] [blame] | 47 | pw::Status::Unknown() |
Wyatt Hepler | bb57d9c | 2020-09-25 16:27:38 -0700 | [diff] [blame] | 48 | |
| 49 | // InvalidArgument (gRPC code "INVALID_ARGUMENT") indicates the caller |
| 50 | // specified an invalid argument, such a malformed filename. Note that such |
| 51 | // errors should be narrowly limited to indicate to the invalid nature of the |
| 52 | // arguments themselves. Errors with validly formed arguments that may cause |
| 53 | // errors with the state of the receiving system should be denoted with |
| 54 | // `FailedPrecondition` instead. |
Wyatt Hepler | 5a53dfd | 2021-01-08 08:34:27 -0800 | [diff] [blame] | 55 | pw::Status::InvalidArgument() |
Wyatt Hepler | bb57d9c | 2020-09-25 16:27:38 -0700 | [diff] [blame] | 56 | |
| 57 | // DeadlineExceeded (gRPC code "DEADLINE_EXCEEDED") indicates a deadline |
| 58 | // expired before the operation could complete. For operations that may change |
| 59 | // state within a system, this error may be returned even if the operation has |
| 60 | // completed successfully. For example, a successful response from a server |
| 61 | // could have been delayed long enough for the deadline to expire. |
Wyatt Hepler | 5a53dfd | 2021-01-08 08:34:27 -0800 | [diff] [blame] | 62 | pw::Status::DeadlineExceeded() |
Wyatt Hepler | bb57d9c | 2020-09-25 16:27:38 -0700 | [diff] [blame] | 63 | |
| 64 | // NotFound (gRPC code "NOT_FOUND") indicates some requested entity (such as |
| 65 | // a file or directory) was not found. |
| 66 | // |
| 67 | // `NotFound` is useful if a request should be denied for an entire class of |
| 68 | // users, such as during a gradual feature rollout or undocumented allow list. |
| 69 | // If, instead, a request should be denied for specific sets of users, such as |
| 70 | // through user-based access control, use `PermissionDenied` instead. |
Wyatt Hepler | 5a53dfd | 2021-01-08 08:34:27 -0800 | [diff] [blame] | 71 | pw::Status::NotFound() |
Wyatt Hepler | bb57d9c | 2020-09-25 16:27:38 -0700 | [diff] [blame] | 72 | |
| 73 | // AlreadyExists (gRPC code "ALREADY_EXISTS") indicates the entity that a |
| 74 | // caller attempted to create (such as file or directory) is already present. |
Wyatt Hepler | 5a53dfd | 2021-01-08 08:34:27 -0800 | [diff] [blame] | 75 | pw::Status::AlreadyExists() |
Wyatt Hepler | bb57d9c | 2020-09-25 16:27:38 -0700 | [diff] [blame] | 76 | |
| 77 | // PermissionDenied (gRPC code "PERMISSION_DENIED") indicates that the caller |
| 78 | // does not have permission to execute the specified operation. Note that this |
| 79 | // error is different than an error due to an *un*authenticated user. This |
| 80 | // error code does not imply the request is valid or the requested entity |
| 81 | // exists or satisfies any other pre-conditions. |
| 82 | // |
| 83 | // `PermissionDenied` must not be used for rejections caused by exhausting |
| 84 | // some resource. Instead, use `ResourceExhausted` for those errors. |
| 85 | // `PermissionDenied` must not be used if the caller cannot be identified. |
| 86 | // Instead, use `Unauthenticated` for those errors. |
Wyatt Hepler | 5a53dfd | 2021-01-08 08:34:27 -0800 | [diff] [blame] | 87 | pw::Status::PermissionDenied() |
Wyatt Hepler | bb57d9c | 2020-09-25 16:27:38 -0700 | [diff] [blame] | 88 | |
| 89 | // ResourceExhausted (gRPC code "RESOURCE_EXHAUSTED") indicates some resource |
| 90 | // has been exhausted, perhaps a per-user quota, or perhaps the entire file |
| 91 | // system is out of space. |
Wyatt Hepler | 5a53dfd | 2021-01-08 08:34:27 -0800 | [diff] [blame] | 92 | pw::Status::ResourceExhausted() |
Wyatt Hepler | bb57d9c | 2020-09-25 16:27:38 -0700 | [diff] [blame] | 93 | |
| 94 | // FailedPrecondition (gRPC code "FAILED_PRECONDITION") indicates that the |
| 95 | // operation was rejected because the system is not in a state required for |
| 96 | // the operation's execution. For example, a directory to be deleted may be |
| 97 | // non-empty, an "rmdir" operation is applied to a non-directory, etc. |
| 98 | // |
| 99 | // Some guidelines that may help a service implementer in deciding between |
| 100 | // `FailedPrecondition`, `Aborted`, and `Unavailable`: |
| 101 | // |
| 102 | // (a) Use `Unavailable` if the client can retry just the failing call. |
| 103 | // (b) Use `Aborted` if the client should retry at a higher transaction |
| 104 | // level (such as when a client-specified test-and-set fails, indicating |
| 105 | // the client should restart a read-modify-write sequence). |
| 106 | // (c) Use `FailedPrecondition` if the client should not retry until |
| 107 | // the system state has been explicitly fixed. For example, if an "rmdir" |
| 108 | // fails because the directory is non-empty, `FailedPrecondition` |
| 109 | // should be returned since the client should not retry unless |
| 110 | // the files are deleted from the directory. |
Wyatt Hepler | 5a53dfd | 2021-01-08 08:34:27 -0800 | [diff] [blame] | 111 | pw::Status::FailedPrecondition() |
Wyatt Hepler | bb57d9c | 2020-09-25 16:27:38 -0700 | [diff] [blame] | 112 | |
| 113 | // Aborted (gRPC code "ABORTED") indicates the operation was aborted, |
| 114 | // typically due to a concurrency issue such as a sequencer check failure or a |
| 115 | // failed transaction. |
| 116 | // |
| 117 | // See the guidelines above for deciding between `FailedPrecondition`, |
| 118 | // `Aborted`, and `Unavailable`. |
Wyatt Hepler | 5a53dfd | 2021-01-08 08:34:27 -0800 | [diff] [blame] | 119 | pw::Status::Aborted() |
Wyatt Hepler | bb57d9c | 2020-09-25 16:27:38 -0700 | [diff] [blame] | 120 | |
| 121 | // OutOfRange (gRPC code "OUT_OF_RANGE") indicates the operation was |
| 122 | // attempted past the valid range, such as seeking or reading past an |
| 123 | // end-of-file. |
| 124 | // |
| 125 | // Unlike `InvalidArgument`, this error indicates a problem that may |
| 126 | // be fixed if the system state changes. For example, a 32-bit file |
| 127 | // system will generate `InvalidArgument` if asked to read at an |
| 128 | // offset that is not in the range [0,2^32-1], but it will generate |
| 129 | // `OutOfRange` if asked to read from an offset past the current |
| 130 | // file size. |
| 131 | // |
| 132 | // There is a fair bit of overlap between `FailedPrecondition` and |
| 133 | // `OutOfRange`. We recommend using `OutOfRange` (the more specific |
| 134 | // error) when it applies so that callers who are iterating through |
| 135 | // a space can easily look for an `OutOfRange` error to detect when |
| 136 | // they are done. |
Wyatt Hepler | 5a53dfd | 2021-01-08 08:34:27 -0800 | [diff] [blame] | 137 | pw::Status::OutOfRange() |
Wyatt Hepler | bb57d9c | 2020-09-25 16:27:38 -0700 | [diff] [blame] | 138 | |
| 139 | // Unimplemented (gRPC code "UNIMPLEMENTED") indicates the operation is not |
| 140 | // implemented or supported in this service. In this case, the operation |
| 141 | // should not be re-attempted. |
Wyatt Hepler | 5a53dfd | 2021-01-08 08:34:27 -0800 | [diff] [blame] | 142 | pw::Status::Unimplemented() |
Wyatt Hepler | bb57d9c | 2020-09-25 16:27:38 -0700 | [diff] [blame] | 143 | |
| 144 | // Internal (gRPC code "INTERNAL") indicates an internal error has occurred |
| 145 | // and some invariants expected by the underlying system have not been |
| 146 | // satisfied. This error code is reserved for serious errors. |
Wyatt Hepler | 5a53dfd | 2021-01-08 08:34:27 -0800 | [diff] [blame] | 147 | pw::Status::Internal() |
Wyatt Hepler | bb57d9c | 2020-09-25 16:27:38 -0700 | [diff] [blame] | 148 | |
| 149 | // Unavailable (gRPC code "UNAVAILABLE") indicates the service is currently |
| 150 | // unavailable and that this is most likely a transient condition. An error |
| 151 | // such as this can be corrected by retrying with a backoff scheme. Note that |
| 152 | // it is not always safe to retry non-idempotent operations. |
| 153 | // |
| 154 | // See the guidelines above for deciding between `FailedPrecondition`, |
| 155 | // `Aborted`, and `Unavailable`. |
Wyatt Hepler | 5a53dfd | 2021-01-08 08:34:27 -0800 | [diff] [blame] | 156 | pw::Status::Unavailable() |
Wyatt Hepler | bb57d9c | 2020-09-25 16:27:38 -0700 | [diff] [blame] | 157 | |
| 158 | // DataLoss (gRPC code "DATA_LOSS") indicates that unrecoverable data loss or |
| 159 | // corruption has occurred. As this error is serious, proper alerting should |
| 160 | // be attached to errors such as this. |
Wyatt Hepler | 5a53dfd | 2021-01-08 08:34:27 -0800 | [diff] [blame] | 161 | pw::Status::DataLoss() |
Wyatt Hepler | bb57d9c | 2020-09-25 16:27:38 -0700 | [diff] [blame] | 162 | |
| 163 | // Unauthenticated (gRPC code "UNAUTHENTICATED") indicates that the request |
| 164 | // does not have valid authentication credentials for the operation. Correct |
| 165 | // the authentication and try again. |
Wyatt Hepler | 5a53dfd | 2021-01-08 08:34:27 -0800 | [diff] [blame] | 166 | pw::Status::Unauthenticated() |
Wyatt Hepler | bb57d9c | 2020-09-25 16:27:38 -0700 | [diff] [blame] | 167 | |
| 168 | .. attention:: |
| 169 | |
| 170 | Some code may use all-caps status values such as ``Status::UNKNOWN`` instead |
| 171 | of ``Status::Unknown()``. These all-caps status codes are deprecated and will |
| 172 | be removed in the future. Do not use them; use the functions above instead. |
| 173 | |
| 174 | The all-caps status aliases were deprecated because they do not comply with |
| 175 | the style guide and potentially conflict with macro definitions. For example, |
| 176 | projects might define an ``INTERNAL`` macro, which would prevent ``status.h`` |
| 177 | or code that uses ``Status::INTERNAL`` from compiling. |
| 178 | |
| 179 | The Python tool ``pw_status/update_style.py`` may be used to migrate code in a |
| 180 | Git repo to the new status style. |
| 181 | |
| 182 | C compatibility |
| 183 | --------------- |
| 184 | ``pw_status`` provides the C-compatible ``pw_Status`` enum for the status codes. |
| 185 | For ease of use, ``pw::Status`` implicitly converts to and from ``pw_Status``. |
| 186 | However, the ``pw_Status`` enum should never be used in C++; instead use the |
| 187 | ``Status`` class. |
| 188 | |
| 189 | The values of the ``pw_Status`` enum are all-caps and prefixed with |
| 190 | ``PW_STATUS_``. For example, ``PW_STATUS_DATA_LOSS`` corresponds with the C++ |
| 191 | ``Status::DataLoss()``. |
| 192 | |
| 193 | StatusWithSize |
| 194 | ============== |
Wyatt Hepler | ee3e02f | 2019-12-05 10:52:31 -0800 | [diff] [blame] | 195 | ``pw::StatusWithSize`` (``pw_status/status_with_size.h``) is a convenient, |
Wyatt Hepler | bb57d9c | 2020-09-25 16:27:38 -0700 | [diff] [blame] | 196 | efficient class for reporting a status along with an unsigned integer value. |
| 197 | It is similar to the ``pw::Result<T>`` class, but it stores both a size and a |
| 198 | status, regardless of the status value, and only supports a limited range (27 |
| 199 | bits). |
Wyatt Hepler | ee3e02f | 2019-12-05 10:52:31 -0800 | [diff] [blame] | 200 | |
Wyatt Hepler | bb57d9c | 2020-09-25 16:27:38 -0700 | [diff] [blame] | 201 | ``pw::StatusWithSize`` values may be created with functions similar to |
| 202 | ``pw::Status``. For example, |
| 203 | |
| 204 | .. code-block:: cpp |
| 205 | |
| 206 | // An OK StatusWithSize with a size of 123. |
Wyatt Hepler | 5a53dfd | 2021-01-08 08:34:27 -0800 | [diff] [blame] | 207 | StatusWithSize(123) |
Wyatt Hepler | bb57d9c | 2020-09-25 16:27:38 -0700 | [diff] [blame] | 208 | |
| 209 | // A NOT_FOUND StatusWithSize with a size of 0. |
| 210 | StatusWithSize::NotFound() |
| 211 | |
| 212 | // A RESOURCE_EXHAUSTED StatusWithSize with a size of 10. |
| 213 | StatusWithSize::ResourceExhausted(10) |
| 214 | |
| 215 | PW_TRY |
| 216 | ====== |
David Rogers | b6b14b8 | 2020-09-11 16:27:27 -0700 | [diff] [blame] | 217 | ``PW_TRY`` (``pw_status/try.h``) is a convenient set of macros for working |
| 218 | with Status and StatusWithSize objects in functions that return Status or |
| 219 | StatusWithSize. The PW_TRY and PW_TRY_WITH_SIZE macros call a function and |
| 220 | do an early return if the function's return status is not ok. |
| 221 | |
| 222 | Example: |
| 223 | |
| 224 | .. code-block:: cpp |
| 225 | |
| 226 | Status PwTryExample() { |
| 227 | PW_TRY(FunctionThatReturnsStatus()); |
| 228 | PW_TRY(FunctionThatReturnsStatusWithSize()); |
| 229 | |
| 230 | // Do something, only executed if both functions above return OK. |
| 231 | } |
| 232 | |
| 233 | StatusWithSize PwTryWithSizeExample() { |
| 234 | PW_TRY_WITH_SIZE(FunctionThatReturnsStatus()); |
| 235 | PW_TRY_WITH_SIZE(FunctionThatReturnsStatusWithSize()); |
| 236 | |
| 237 | // Do something, only executed if both functions above return OK. |
| 238 | } |
| 239 | |
| 240 | PW_TRY_ASSIGN is for working with StatusWithSize objects in in functions |
| 241 | that return Status. It is similar to PW_TRY with the addition of assigning |
| 242 | the size from the StatusWithSize on ok. |
| 243 | |
| 244 | .. code-block:: cpp |
| 245 | |
| 246 | Status PwTryAssignExample() { |
| 247 | size_t size_value |
| 248 | PW_TRY_ASSIGN(size_value, FunctionThatReturnsStatusWithSize()); |
| 249 | |
| 250 | // Do something that uses size_value. size_value is only assigned and this |
| 251 | // following code executed if the PW_TRY_ASSIGN function above returns OK. |
| 252 | } |
| 253 | |
Wyatt Hepler | ee3e02f | 2019-12-05 10:52:31 -0800 | [diff] [blame] | 254 | Compatibility |
| 255 | ============= |
| 256 | C++11 |