status.cc 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444
  1. // Copyright 2019 The Abseil Authors.
  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. // https://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. #include "absl/status/status.h"
  15. #include <cassert>
  16. #include "absl/base/internal/raw_logging.h"
  17. #include "absl/debugging/stacktrace.h"
  18. #include "absl/debugging/symbolize.h"
  19. #include "absl/status/status_payload_printer.h"
  20. #include "absl/strings/escaping.h"
  21. #include "absl/strings/str_cat.h"
  22. #include "absl/strings/str_format.h"
  23. #include "absl/strings/str_split.h"
  24. namespace absl {
  25. ABSL_NAMESPACE_BEGIN
  26. std::string StatusCodeToString(StatusCode code) {
  27. switch (code) {
  28. case StatusCode::kOk:
  29. return "OK";
  30. case StatusCode::kCancelled:
  31. return "CANCELLED";
  32. case StatusCode::kUnknown:
  33. return "UNKNOWN";
  34. case StatusCode::kInvalidArgument:
  35. return "INVALID_ARGUMENT";
  36. case StatusCode::kDeadlineExceeded:
  37. return "DEADLINE_EXCEEDED";
  38. case StatusCode::kNotFound:
  39. return "NOT_FOUND";
  40. case StatusCode::kAlreadyExists:
  41. return "ALREADY_EXISTS";
  42. case StatusCode::kPermissionDenied:
  43. return "PERMISSION_DENIED";
  44. case StatusCode::kUnauthenticated:
  45. return "UNAUTHENTICATED";
  46. case StatusCode::kResourceExhausted:
  47. return "RESOURCE_EXHAUSTED";
  48. case StatusCode::kFailedPrecondition:
  49. return "FAILED_PRECONDITION";
  50. case StatusCode::kAborted:
  51. return "ABORTED";
  52. case StatusCode::kOutOfRange:
  53. return "OUT_OF_RANGE";
  54. case StatusCode::kUnimplemented:
  55. return "UNIMPLEMENTED";
  56. case StatusCode::kInternal:
  57. return "INTERNAL";
  58. case StatusCode::kUnavailable:
  59. return "UNAVAILABLE";
  60. case StatusCode::kDataLoss:
  61. return "DATA_LOSS";
  62. default:
  63. return "";
  64. }
  65. }
  66. std::ostream& operator<<(std::ostream& os, StatusCode code) {
  67. return os << StatusCodeToString(code);
  68. }
  69. namespace status_internal {
  70. static int FindPayloadIndexByUrl(const Payloads* payloads,
  71. absl::string_view type_url) {
  72. if (payloads == nullptr) return -1;
  73. for (size_t i = 0; i < payloads->size(); ++i) {
  74. if ((*payloads)[i].type_url == type_url) return i;
  75. }
  76. return -1;
  77. }
  78. // Convert canonical code to a value known to this binary.
  79. absl::StatusCode MapToLocalCode(int value) {
  80. absl::StatusCode code = static_cast<absl::StatusCode>(value);
  81. switch (code) {
  82. case absl::StatusCode::kOk:
  83. case absl::StatusCode::kCancelled:
  84. case absl::StatusCode::kUnknown:
  85. case absl::StatusCode::kInvalidArgument:
  86. case absl::StatusCode::kDeadlineExceeded:
  87. case absl::StatusCode::kNotFound:
  88. case absl::StatusCode::kAlreadyExists:
  89. case absl::StatusCode::kPermissionDenied:
  90. case absl::StatusCode::kResourceExhausted:
  91. case absl::StatusCode::kFailedPrecondition:
  92. case absl::StatusCode::kAborted:
  93. case absl::StatusCode::kOutOfRange:
  94. case absl::StatusCode::kUnimplemented:
  95. case absl::StatusCode::kInternal:
  96. case absl::StatusCode::kUnavailable:
  97. case absl::StatusCode::kDataLoss:
  98. case absl::StatusCode::kUnauthenticated:
  99. return code;
  100. default:
  101. return absl::StatusCode::kUnknown;
  102. }
  103. }
  104. } // namespace status_internal
  105. absl::optional<absl::Cord> Status::GetPayload(
  106. absl::string_view type_url) const {
  107. const auto* payloads = GetPayloads();
  108. int index = status_internal::FindPayloadIndexByUrl(payloads, type_url);
  109. if (index != -1) return (*payloads)[index].payload;
  110. return absl::nullopt;
  111. }
  112. void Status::SetPayload(absl::string_view type_url, absl::Cord payload) {
  113. if (ok()) return;
  114. PrepareToModify();
  115. status_internal::StatusRep* rep = RepToPointer(rep_);
  116. if (!rep->payloads) {
  117. rep->payloads = absl::make_unique<status_internal::Payloads>();
  118. }
  119. int index =
  120. status_internal::FindPayloadIndexByUrl(rep->payloads.get(), type_url);
  121. if (index != -1) {
  122. (*rep->payloads)[index].payload = std::move(payload);
  123. return;
  124. }
  125. rep->payloads->push_back({std::string(type_url), std::move(payload)});
  126. }
  127. bool Status::ErasePayload(absl::string_view type_url) {
  128. int index = status_internal::FindPayloadIndexByUrl(GetPayloads(), type_url);
  129. if (index != -1) {
  130. PrepareToModify();
  131. GetPayloads()->erase(GetPayloads()->begin() + index);
  132. if (GetPayloads()->empty() && message().empty()) {
  133. // Special case: If this can be represented inlined, it MUST be
  134. // inlined (EqualsSlow depends on this behavior).
  135. StatusCode c = static_cast<StatusCode>(raw_code());
  136. Unref(rep_);
  137. rep_ = CodeToInlinedRep(c);
  138. }
  139. return true;
  140. }
  141. return false;
  142. }
  143. void Status::ForEachPayload(
  144. absl::FunctionRef<void(absl::string_view, const absl::Cord&)> visitor)
  145. const {
  146. if (auto* payloads = GetPayloads()) {
  147. bool in_reverse =
  148. payloads->size() > 1 && reinterpret_cast<uintptr_t>(payloads) % 13 > 6;
  149. for (size_t index = 0; index < payloads->size(); ++index) {
  150. const auto& elem =
  151. (*payloads)[in_reverse ? payloads->size() - 1 - index : index];
  152. #ifdef NDEBUG
  153. visitor(elem.type_url, elem.payload);
  154. #else
  155. // In debug mode invalidate the type url to prevent users from relying on
  156. // this string lifetime.
  157. // NOLINTNEXTLINE intentional extra conversion to force temporary.
  158. visitor(std::string(elem.type_url), elem.payload);
  159. #endif // NDEBUG
  160. }
  161. }
  162. }
  163. const std::string* Status::EmptyString() {
  164. static std::string* empty_string = new std::string();
  165. return empty_string;
  166. }
  167. constexpr const char Status::kMovedFromString[];
  168. const std::string* Status::MovedFromString() {
  169. static std::string* moved_from_string = new std::string(kMovedFromString);
  170. return moved_from_string;
  171. }
  172. void Status::UnrefNonInlined(uintptr_t rep) {
  173. status_internal::StatusRep* r = RepToPointer(rep);
  174. // Fast path: if ref==1, there is no need for a RefCountDec (since
  175. // this is the only reference and therefore no other thread is
  176. // allowed to be mucking with r).
  177. if (r->ref.load(std::memory_order_acquire) == 1 ||
  178. r->ref.fetch_sub(1, std::memory_order_acq_rel) - 1 == 0) {
  179. delete r;
  180. }
  181. }
  182. Status::Status(absl::StatusCode code, absl::string_view msg)
  183. : rep_(CodeToInlinedRep(code)) {
  184. if (code != absl::StatusCode::kOk && !msg.empty()) {
  185. rep_ = PointerToRep(new status_internal::StatusRep(code, msg, nullptr));
  186. }
  187. }
  188. int Status::raw_code() const {
  189. if (IsInlined(rep_)) {
  190. return static_cast<int>(InlinedRepToCode(rep_));
  191. }
  192. status_internal::StatusRep* rep = RepToPointer(rep_);
  193. return static_cast<int>(rep->code);
  194. }
  195. absl::StatusCode Status::code() const {
  196. return status_internal::MapToLocalCode(raw_code());
  197. }
  198. void Status::PrepareToModify() {
  199. ABSL_RAW_CHECK(!ok(), "PrepareToModify shouldn't be called on OK status.");
  200. if (IsInlined(rep_)) {
  201. rep_ = PointerToRep(new status_internal::StatusRep(
  202. static_cast<absl::StatusCode>(raw_code()), absl::string_view(),
  203. nullptr));
  204. return;
  205. }
  206. uintptr_t rep_i = rep_;
  207. status_internal::StatusRep* rep = RepToPointer(rep_);
  208. if (rep->ref.load(std::memory_order_acquire) != 1) {
  209. std::unique_ptr<status_internal::Payloads> payloads;
  210. if (rep->payloads) {
  211. payloads = absl::make_unique<status_internal::Payloads>(*rep->payloads);
  212. }
  213. status_internal::StatusRep* const new_rep = new status_internal::StatusRep(
  214. rep->code, message(), std::move(payloads));
  215. rep_ = PointerToRep(new_rep);
  216. UnrefNonInlined(rep_i);
  217. }
  218. }
  219. bool Status::EqualsSlow(const absl::Status& a, const absl::Status& b) {
  220. if (IsInlined(a.rep_) != IsInlined(b.rep_)) return false;
  221. if (a.message() != b.message()) return false;
  222. if (a.raw_code() != b.raw_code()) return false;
  223. if (a.GetPayloads() == b.GetPayloads()) return true;
  224. const status_internal::Payloads no_payloads;
  225. const status_internal::Payloads* larger_payloads =
  226. a.GetPayloads() ? a.GetPayloads() : &no_payloads;
  227. const status_internal::Payloads* smaller_payloads =
  228. b.GetPayloads() ? b.GetPayloads() : &no_payloads;
  229. if (larger_payloads->size() < smaller_payloads->size()) {
  230. std::swap(larger_payloads, smaller_payloads);
  231. }
  232. if ((larger_payloads->size() - smaller_payloads->size()) > 1) return false;
  233. // Payloads can be ordered differently, so we can't just compare payload
  234. // vectors.
  235. for (const auto& payload : *larger_payloads) {
  236. bool found = false;
  237. for (const auto& other_payload : *smaller_payloads) {
  238. if (payload.type_url == other_payload.type_url) {
  239. if (payload.payload != other_payload.payload) {
  240. return false;
  241. }
  242. found = true;
  243. break;
  244. }
  245. }
  246. if (!found) return false;
  247. }
  248. return true;
  249. }
  250. std::string Status::ToStringSlow(StatusToStringMode mode) const {
  251. std::string text;
  252. absl::StrAppend(&text, absl::StatusCodeToString(code()), ": ", message());
  253. const bool with_payload = (mode & StatusToStringMode::kWithPayload) ==
  254. StatusToStringMode::kWithPayload;
  255. if (with_payload) {
  256. status_internal::StatusPayloadPrinter printer =
  257. status_internal::GetStatusPayloadPrinter();
  258. this->ForEachPayload([&](absl::string_view type_url,
  259. const absl::Cord& payload) {
  260. absl::optional<std::string> result;
  261. if (printer) result = printer(type_url, payload);
  262. absl::StrAppend(
  263. &text, " [", type_url, "='",
  264. result.has_value() ? *result : absl::CHexEscape(std::string(payload)),
  265. "']");
  266. });
  267. }
  268. return text;
  269. }
  270. std::ostream& operator<<(std::ostream& os, const Status& x) {
  271. os << x.ToString(StatusToStringMode::kWithEverything);
  272. return os;
  273. }
  274. Status AbortedError(absl::string_view message) {
  275. return Status(absl::StatusCode::kAborted, message);
  276. }
  277. Status AlreadyExistsError(absl::string_view message) {
  278. return Status(absl::StatusCode::kAlreadyExists, message);
  279. }
  280. Status CancelledError(absl::string_view message) {
  281. return Status(absl::StatusCode::kCancelled, message);
  282. }
  283. Status DataLossError(absl::string_view message) {
  284. return Status(absl::StatusCode::kDataLoss, message);
  285. }
  286. Status DeadlineExceededError(absl::string_view message) {
  287. return Status(absl::StatusCode::kDeadlineExceeded, message);
  288. }
  289. Status FailedPreconditionError(absl::string_view message) {
  290. return Status(absl::StatusCode::kFailedPrecondition, message);
  291. }
  292. Status InternalError(absl::string_view message) {
  293. return Status(absl::StatusCode::kInternal, message);
  294. }
  295. Status InvalidArgumentError(absl::string_view message) {
  296. return Status(absl::StatusCode::kInvalidArgument, message);
  297. }
  298. Status NotFoundError(absl::string_view message) {
  299. return Status(absl::StatusCode::kNotFound, message);
  300. }
  301. Status OutOfRangeError(absl::string_view message) {
  302. return Status(absl::StatusCode::kOutOfRange, message);
  303. }
  304. Status PermissionDeniedError(absl::string_view message) {
  305. return Status(absl::StatusCode::kPermissionDenied, message);
  306. }
  307. Status ResourceExhaustedError(absl::string_view message) {
  308. return Status(absl::StatusCode::kResourceExhausted, message);
  309. }
  310. Status UnauthenticatedError(absl::string_view message) {
  311. return Status(absl::StatusCode::kUnauthenticated, message);
  312. }
  313. Status UnavailableError(absl::string_view message) {
  314. return Status(absl::StatusCode::kUnavailable, message);
  315. }
  316. Status UnimplementedError(absl::string_view message) {
  317. return Status(absl::StatusCode::kUnimplemented, message);
  318. }
  319. Status UnknownError(absl::string_view message) {
  320. return Status(absl::StatusCode::kUnknown, message);
  321. }
  322. bool IsAborted(const Status& status) {
  323. return status.code() == absl::StatusCode::kAborted;
  324. }
  325. bool IsAlreadyExists(const Status& status) {
  326. return status.code() == absl::StatusCode::kAlreadyExists;
  327. }
  328. bool IsCancelled(const Status& status) {
  329. return status.code() == absl::StatusCode::kCancelled;
  330. }
  331. bool IsDataLoss(const Status& status) {
  332. return status.code() == absl::StatusCode::kDataLoss;
  333. }
  334. bool IsDeadlineExceeded(const Status& status) {
  335. return status.code() == absl::StatusCode::kDeadlineExceeded;
  336. }
  337. bool IsFailedPrecondition(const Status& status) {
  338. return status.code() == absl::StatusCode::kFailedPrecondition;
  339. }
  340. bool IsInternal(const Status& status) {
  341. return status.code() == absl::StatusCode::kInternal;
  342. }
  343. bool IsInvalidArgument(const Status& status) {
  344. return status.code() == absl::StatusCode::kInvalidArgument;
  345. }
  346. bool IsNotFound(const Status& status) {
  347. return status.code() == absl::StatusCode::kNotFound;
  348. }
  349. bool IsOutOfRange(const Status& status) {
  350. return status.code() == absl::StatusCode::kOutOfRange;
  351. }
  352. bool IsPermissionDenied(const Status& status) {
  353. return status.code() == absl::StatusCode::kPermissionDenied;
  354. }
  355. bool IsResourceExhausted(const Status& status) {
  356. return status.code() == absl::StatusCode::kResourceExhausted;
  357. }
  358. bool IsUnauthenticated(const Status& status) {
  359. return status.code() == absl::StatusCode::kUnauthenticated;
  360. }
  361. bool IsUnavailable(const Status& status) {
  362. return status.code() == absl::StatusCode::kUnavailable;
  363. }
  364. bool IsUnimplemented(const Status& status) {
  365. return status.code() == absl::StatusCode::kUnimplemented;
  366. }
  367. bool IsUnknown(const Status& status) {
  368. return status.code() == absl::StatusCode::kUnknown;
  369. }
  370. ABSL_NAMESPACE_END
  371. } // namespace absl