/Users/deen/code/yugabyte-db/src/yb/util/status.cc
Line | Count | Source (jump to first uncovered line) |
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 | | // The following only applies to changes made to this file as part of YugaByte development. |
6 | | // |
7 | | // Portions Copyright (c) YugaByte, Inc. |
8 | | // |
9 | | // Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except |
10 | | // in compliance with the License. You may obtain a copy of the License at |
11 | | // |
12 | | // http://www.apache.org/licenses/LICENSE-2.0 |
13 | | // |
14 | | // Unless required by applicable law or agreed to in writing, software distributed under the License |
15 | | // is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express |
16 | | // or implied. See the License for the specific language governing permissions and limitations |
17 | | // under the License. |
18 | | // |
19 | | |
20 | | // Portions Copyright (c) YugaByte, Inc. |
21 | | #include "yb/util/status.h" |
22 | | |
23 | | #include <array> |
24 | | #include <atomic> |
25 | | #include <regex> |
26 | | |
27 | | #include "yb/gutil/dynamic_annotations.h" |
28 | | #include "yb/util/debug-util.h" |
29 | | #include "yb/util/malloc.h" |
30 | | #include "yb/util/slice.h" |
31 | | #include "yb/util/status_ec.h" |
32 | | |
33 | | namespace yb { |
34 | | |
35 | | namespace { |
36 | | |
37 | | #ifndef NDEBUG |
38 | | // This allows to dump stack traces whenever an error status matching a certain regex is generated. |
39 | 20.6k | boost::optional<std::regex> StatusStackTraceRegEx() { |
40 | 20.6k | const char* regex_str = getenv("YB_STACK_TRACE_ON_ERROR_STATUS_RE"); |
41 | 20.6k | if (!regex_str) { |
42 | 20.6k | return boost::none; |
43 | 20.6k | } |
44 | 0 | return std::regex(regex_str); |
45 | 0 | } |
46 | | #endif |
47 | | |
48 | | namespace { |
49 | | |
50 | | struct StatusCategories { |
51 | | // Category is stored as uint8_t, so there could be only 256 categories. |
52 | | std::array<StatusCategoryDescription, 0x100> categories; |
53 | | |
54 | 0 | std::string KnownCategoriesStr() { |
55 | 0 | std::ostringstream ss; |
56 | 0 | bool first = true; |
57 | 0 | for (size_t i = 0; i < categories.size(); ++i) { |
58 | 0 | const auto& category = categories[i]; |
59 | 0 | if (category.name != nullptr) { |
60 | 0 | if (!first) { |
61 | 0 | ss << ", "; |
62 | 0 | } |
63 | 0 | first = false; |
64 | 0 | ss << i << "=" << *category.name; |
65 | 0 | } |
66 | 0 | } |
67 | 0 | return ss.str(); |
68 | 0 | } |
69 | | |
70 | | // In debug mode log as many details as possible and crash. |
71 | | // In release mode log a warning. |
72 | 0 | void ReportMissingCategory(uint8_t category_id, const char* function_name) { |
73 | 0 | #ifndef NDEBUG |
74 | 0 | LOG(WARNING) << "Known categories: " << KnownCategoriesStr(); |
75 | 0 | #endif |
76 | 0 | LOG(DFATAL) << "In " << function_name |
77 | 0 | << ": unknown category description for " << static_cast<int>(category_id); |
78 | 0 | } |
79 | | |
80 | 268k | void Register(const StatusCategoryDescription& description) { |
81 | 268k | CHECK(!categories[description.id].name); |
82 | 268k | categories[description.id] = description; |
83 | 268k | } |
84 | | |
85 | 1.11M | const std::string& CategoryName(uint8_t category) { |
86 | 1.11M | const auto& description = categories[category]; |
87 | 1.11M | if (!description.name) { |
88 | 0 | static std::string kUnknownCategory("unknown error category"); |
89 | 0 | return kUnknownCategory; |
90 | 0 | } |
91 | 1.11M | return *description.name; |
92 | 1.11M | } |
93 | | |
94 | | // Returns data slice w/o category for error code starting with start. |
95 | 19.2M | Slice GetSlice(const uint8_t* start) { |
96 | 19.2M | const uint8_t category_id = *start; |
97 | 19.2M | const auto& description = categories[category_id]; |
98 | 19.2M | if (description.name == nullptr) { |
99 | 8.32M | if (category_id > 0) |
100 | 0 | ReportMissingCategory(category_id, __func__); |
101 | 8.32M | return Slice(); |
102 | 8.32M | } |
103 | 10.8M | return Slice(start, 1 + description.decode_size(start + 1)); |
104 | 10.8M | } |
105 | | |
106 | 1.11M | std::string ToString(Slice encoded_err_code) { |
107 | 1.11M | const uint8_t category_id = *encoded_err_code.data(); |
108 | 1.11M | const auto& description = categories[category_id]; |
109 | 1.11M | if (description.name == nullptr) { |
110 | 0 | if (category_id > 0) |
111 | 0 | ReportMissingCategory(category_id, __func__); |
112 | 0 | return std::string(); |
113 | 0 | } |
114 | 1.11M | return description.to_string(encoded_err_code.data() + 1); |
115 | 1.11M | } |
116 | | }; |
117 | | |
118 | 21.7M | StatusCategories& status_categories() { |
119 | 21.7M | static StatusCategories result; |
120 | 21.7M | return result; |
121 | 21.7M | } |
122 | | |
123 | | } // namespace |
124 | | |
125 | | class ErrorCodeIterator : public std::iterator<std::forward_iterator_tag, Slice> { |
126 | | public: |
127 | | explicit ErrorCodeIterator(const char* address) |
128 | | : current_(address ? status_categories().GetSlice(pointer_cast<const uint8_t*>(address)) |
129 | 20.8M | : Slice()) {} |
130 | | |
131 | 27.5M | bool is_end() const { |
132 | 27.5M | return current_.empty(); |
133 | 27.5M | } |
134 | | |
135 | 10.8M | value_type operator*() const { |
136 | 10.8M | return current_; |
137 | 10.8M | } |
138 | | |
139 | 8.80M | ErrorCodeIterator& operator++() { |
140 | 8.80M | current_ = status_categories().GetSlice(current_.end()); |
141 | 8.80M | return *this; |
142 | 8.80M | } |
143 | | |
144 | | private: |
145 | 19.2M | friend bool operator==(const ErrorCodeIterator& lhs, const ErrorCodeIterator& rhs) { |
146 | 10.8M | return lhs.is_end() ? rhs.is_end() : lhs.current_.data() == rhs.current_.data(); |
147 | 19.2M | } |
148 | | |
149 | 19.2M | friend bool operator!=(const ErrorCodeIterator& lhs, const ErrorCodeIterator& rhs) { |
150 | 19.2M | return !(lhs == rhs); |
151 | 19.2M | } |
152 | | |
153 | | Slice current_; |
154 | | }; |
155 | | |
156 | 3.57M | uint8_t* DoEncode(const StatusErrorCode& error, uint8_t* out) { |
157 | 3.57M | *out++ = error.Category(); |
158 | 3.57M | auto new_out = error.Encode(out); |
159 | 3.57M | DCHECK_EQ(out + error.EncodedSize(), new_out); |
160 | 3.57M | return new_out; |
161 | 3.57M | } |
162 | | |
163 | | class ErrorCodesRange { |
164 | | public: |
165 | 10.4M | explicit ErrorCodesRange(const char* start) : start_(start) { |
166 | 10.4M | } |
167 | | |
168 | | typedef ErrorCodeIterator const_iterator; |
169 | | |
170 | 10.4M | const_iterator begin() const { |
171 | 10.4M | return ErrorCodeIterator(start_); |
172 | 10.4M | } |
173 | | |
174 | 10.4M | const_iterator end() const { |
175 | 10.4M | return ErrorCodeIterator(nullptr); |
176 | 10.4M | } |
177 | | |
178 | | private: |
179 | | const char* start_; |
180 | | }; |
181 | | |
182 | | } // anonymous namespace |
183 | | |
184 | 966 | StringVectorBackedErrorTag::Value StringVectorBackedErrorTag::Decode(const uint8_t* source) { |
185 | 966 | if (!source) { |
186 | 1 | return Value(); |
187 | 1 | } |
188 | 965 | Value result; |
189 | 965 | Slice buf(source, DecodeSize(source)); |
190 | 965 | buf.remove_prefix(sizeof(SizeType)); |
191 | 1.09k | while (buf.size() > 0) { |
192 | 132 | const auto str_size = Load<SizeType, LittleEndian>(buf.data()); |
193 | 132 | buf.remove_prefix(sizeof(SizeType)); |
194 | 132 | result.emplace_back(buf.cdata(), str_size); |
195 | 132 | buf.remove_prefix(str_size); |
196 | 132 | } |
197 | 965 | return result; |
198 | 965 | } |
199 | | |
200 | 691 | size_t StringVectorBackedErrorTag::EncodedSize(const StringVectorBackedErrorTag::Value& value) { |
201 | 691 | size_t size = sizeof(SizeType); |
202 | 92 | for (const auto& str : value) { |
203 | 92 | size += sizeof(SizeType) + str.size(); |
204 | 92 | } |
205 | 691 | return size; |
206 | 691 | } |
207 | | |
208 | | uint8_t* StringVectorBackedErrorTag::Encode( |
209 | 344 | const StringVectorBackedErrorTag::Value& value, uint8_t* out) { |
210 | 344 | uint8_t* const start = out; |
211 | 344 | out += sizeof(SizeType); |
212 | 46 | for (const auto& str : value) { |
213 | 46 | Store<SizeType, LittleEndian>(out, str.size()); |
214 | 46 | out += sizeof(SizeType); |
215 | 46 | memcpy(out, str.data(), str.size()); |
216 | 46 | out += str.size(); |
217 | 46 | } |
218 | 344 | Store<SizeType, LittleEndian>(start, out - start); |
219 | 344 | return out; |
220 | 344 | } |
221 | | |
222 | | // Error codes are stored after message. |
223 | | // For each error code first byte encodes category and a special value of 0 means the end of the |
224 | | // list. Error code is encoded after category and concrete encoding depends on the category. |
225 | | struct Status::State { |
226 | | State(const State&) = delete; |
227 | | void operator=(const State&) = delete; |
228 | | |
229 | | std::atomic<size_t> counter; |
230 | | uint32_t message_len; |
231 | | uint8_t code; |
232 | | // This must always be a pointer to a constant string. |
233 | | // The status object does not own this string. |
234 | | const char* file_name; |
235 | | int line_number; |
236 | | char message[1]; |
237 | | |
238 | | template <class Errors> |
239 | | static StatePtr Create( |
240 | | Code code, const char* file_name, int line_number, const Slice& msg, const Slice& msg2, |
241 | | const Errors& errors, DupFileName dup_file_name); |
242 | | |
243 | 10.4M | ErrorCodesRange error_codes() const { |
244 | 10.4M | return ErrorCodesRange(message + message_len); |
245 | 10.4M | } |
246 | | |
247 | 2.36M | const char* ErrorCodesEnd() const { |
248 | 2.36M | Slice last(message + message_len, size_t(0)); |
249 | 1.81M | for (Slice current : error_codes()) { |
250 | 1.81M | last = current; |
251 | 1.81M | } |
252 | 2.36M | return last.cend() + 1; |
253 | 2.36M | } |
254 | | |
255 | 1.73M | Slice ErrorCodesSlice() const { |
256 | 1.73M | return Slice(message + message_len, ErrorCodesEnd()); |
257 | 1.73M | } |
258 | | |
259 | 625k | bool FileNameDuplicated() const { |
260 | 625k | return file_name == ErrorCodesEnd(); |
261 | 625k | } |
262 | | |
263 | 39.8M | static size_t ErrorsSize(const StatusErrorCode* error) { |
264 | 39.8M | size_t result = 1; |
265 | 39.8M | if (error) { |
266 | 3.28M | result += 1 + error->EncodedSize(); |
267 | 3.28M | } |
268 | 39.8M | return result; |
269 | 39.8M | } |
270 | | |
271 | 39.8M | static uint8_t* StoreErrors(const StatusErrorCode* error, uint8_t* out) { |
272 | 39.8M | if (error) { |
273 | 3.28M | out = DoEncode(*error, out); |
274 | 3.28M | } |
275 | 39.8M | *out++ = 0; |
276 | 39.8M | return out; |
277 | 39.8M | } |
278 | | |
279 | 975k | static size_t ErrorsSize(const Slice& errors) { |
280 | 975k | return errors.size(); |
281 | 975k | } |
282 | | |
283 | 975k | static uint8_t* StoreErrors(const Slice& errors, uint8_t* out) { |
284 | 975k | memcpy(out, errors.data(), errors.size()); |
285 | 975k | return out + errors.size(); |
286 | 975k | } |
287 | | }; |
288 | | |
289 | | template <class Errors> |
290 | | Status::StatePtr Status::State::Create( |
291 | | Code code, const char* file_name, int line_number, const Slice& msg, const Slice& msg2, |
292 | 40.8M | const Errors& errors, DupFileName dup_file_name) { |
293 | 40.8M | static constexpr size_t kHeaderSize = offsetof(State, message); |
294 | | |
295 | 40.8M | assert(code != kOk); |
296 | 40.8M | const size_t len1 = msg.size(); |
297 | 40.8M | const size_t len2 = msg2.size(); |
298 | 38.4M | const size_t size = len1 + (len2 ? (2 + len2) : 0); |
299 | 40.8M | const size_t errors_size = ErrorsSize(errors); |
300 | 40.8M | size_t file_name_size = 0; |
301 | 40.8M | if (dup_file_name) { |
302 | 610k | file_name_size = strlen(file_name) + 1; |
303 | 610k | } |
304 | 40.8M | StatePtr result(static_cast<State*>(malloc(size + kHeaderSize + errors_size + file_name_size))); |
305 | 40.8M | result->message_len = static_cast<uint32_t>(size); |
306 | 40.8M | result->code = static_cast<uint8_t>(code); |
307 | | // We aleady assigned intrusive_ptr, so counter should be one. |
308 | 40.8M | result->counter.store(1, std::memory_order_relaxed); |
309 | 40.8M | result->line_number = line_number; |
310 | 40.8M | memcpy(result->message, msg.data(), len1); |
311 | 40.8M | if (len2) { |
312 | 2.44M | result->message[len1] = ':'; |
313 | 2.44M | result->message[len1 + 1] = ' '; |
314 | 2.44M | memcpy(result->message + 2 + len1, msg2.data(), len2); |
315 | 2.44M | } |
316 | 40.8M | auto errors_start = pointer_cast<uint8_t*>(&result->message[0] + size); |
317 | 40.8M | auto out = StoreErrors(errors, errors_start); |
318 | 40.8M | DCHECK_EQ(out, errors_start + errors_size); |
319 | 40.8M | if (dup_file_name) { |
320 | 611k | auto new_file_name = out; |
321 | 611k | memcpy(new_file_name, file_name, file_name_size); |
322 | 611k | file_name = pointer_cast<char*>(new_file_name); |
323 | 611k | } |
324 | | |
325 | 40.8M | result->file_name = file_name; |
326 | | |
327 | 40.8M | return result; |
328 | 40.8M | } _ZN2yb6Status5State6CreateIPKNS_15StatusErrorCodeEEEN5boost13intrusive_ptrIS1_EENS0_4CodeEPKciRKNS_5SliceESE_RKT_NS_17StronglyTypedBoolINS_15DupFileName_TagEEE Line | Count | Source | 292 | 39.8M | const Errors& errors, DupFileName dup_file_name) { | 293 | 39.8M | static constexpr size_t kHeaderSize = offsetof(State, message); | 294 | | | 295 | 39.8M | assert(code != kOk); | 296 | 39.8M | const size_t len1 = msg.size(); | 297 | 39.8M | const size_t len2 = msg2.size(); | 298 | 37.7M | const size_t size = len1 + (len2 ? (2 + len2) : 0); | 299 | 39.8M | const size_t errors_size = ErrorsSize(errors); | 300 | 39.8M | size_t file_name_size = 0; | 301 | 39.8M | if (dup_file_name) { | 302 | 0 | file_name_size = strlen(file_name) + 1; | 303 | 0 | } | 304 | 39.8M | StatePtr result(static_cast<State*>(malloc(size + kHeaderSize + errors_size + file_name_size))); | 305 | 39.8M | result->message_len = static_cast<uint32_t>(size); | 306 | 39.8M | result->code = static_cast<uint8_t>(code); | 307 | | // We aleady assigned intrusive_ptr, so counter should be one. | 308 | 39.8M | result->counter.store(1, std::memory_order_relaxed); | 309 | 39.8M | result->line_number = line_number; | 310 | 39.8M | memcpy(result->message, msg.data(), len1); | 311 | 39.8M | if (len2) { | 312 | 2.10M | result->message[len1] = ':'; | 313 | 2.10M | result->message[len1 + 1] = ' '; | 314 | 2.10M | memcpy(result->message + 2 + len1, msg2.data(), len2); | 315 | 2.10M | } | 316 | 39.8M | auto errors_start = pointer_cast<uint8_t*>(&result->message[0] + size); | 317 | 39.8M | auto out = StoreErrors(errors, errors_start); | 318 | 39.8M | DCHECK_EQ(out, errors_start + errors_size); | 319 | 39.8M | if (dup_file_name) { | 320 | 0 | auto new_file_name = out; | 321 | 0 | memcpy(new_file_name, file_name, file_name_size); | 322 | 0 | file_name = pointer_cast<char*>(new_file_name); | 323 | 0 | } | 324 | | | 325 | 39.8M | result->file_name = file_name; | 326 | | | 327 | 39.8M | return result; | 328 | 39.8M | } |
_ZN2yb6Status5State6CreateINS_5SliceEEEN5boost13intrusive_ptrIS1_EENS0_4CodeEPKciRKS3_SB_RKT_NS_17StronglyTypedBoolINS_15DupFileName_TagEEE Line | Count | Source | 292 | 975k | const Errors& errors, DupFileName dup_file_name) { | 293 | 975k | static constexpr size_t kHeaderSize = offsetof(State, message); | 294 | | | 295 | 975k | assert(code != kOk); | 296 | 975k | const size_t len1 = msg.size(); | 297 | 975k | const size_t len2 = msg2.size(); | 298 | 639k | const size_t size = len1 + (len2 ? (2 + len2) : 0); | 299 | 975k | const size_t errors_size = ErrorsSize(errors); | 300 | 975k | size_t file_name_size = 0; | 301 | 975k | if (dup_file_name) { | 302 | 610k | file_name_size = strlen(file_name) + 1; | 303 | 610k | } | 304 | 975k | StatePtr result(static_cast<State*>(malloc(size + kHeaderSize + errors_size + file_name_size))); | 305 | 975k | result->message_len = static_cast<uint32_t>(size); | 306 | 975k | result->code = static_cast<uint8_t>(code); | 307 | | // We aleady assigned intrusive_ptr, so counter should be one. | 308 | 975k | result->counter.store(1, std::memory_order_relaxed); | 309 | 975k | result->line_number = line_number; | 310 | 975k | memcpy(result->message, msg.data(), len1); | 311 | 975k | if (len2) { | 312 | 335k | result->message[len1] = ':'; | 313 | 335k | result->message[len1 + 1] = ' '; | 314 | 335k | memcpy(result->message + 2 + len1, msg2.data(), len2); | 315 | 335k | } | 316 | 975k | auto errors_start = pointer_cast<uint8_t*>(&result->message[0] + size); | 317 | 975k | auto out = StoreErrors(errors, errors_start); | 318 | 975k | DCHECK_EQ(out, errors_start + errors_size); | 319 | 975k | if (dup_file_name) { | 320 | 611k | auto new_file_name = out; | 321 | 611k | memcpy(new_file_name, file_name, file_name_size); | 322 | 611k | file_name = pointer_cast<char*>(new_file_name); | 323 | 611k | } | 324 | | | 325 | 975k | result->file_name = file_name; | 326 | | | 327 | 975k | return result; | 328 | 975k | } |
|
329 | | |
330 | | Status::Status(Code code, |
331 | | const char* file_name, |
332 | | int line_number, |
333 | | const Slice& msg, |
334 | | const Slice& msg2, |
335 | | const StatusErrorCode* error, |
336 | | DupFileName dup_file_name) |
337 | 39.8M | : state_(State::Create(code, file_name, line_number, msg, msg2, error, dup_file_name)) { |
338 | 39.8M | #ifndef NDEBUG |
339 | 39.8M | static const bool print_stack_trace = getenv("YB_STACK_TRACE_ON_ERROR_STATUS") != nullptr; |
340 | 39.8M | static const boost::optional<std::regex> status_stack_trace_re = |
341 | 39.8M | StatusStackTraceRegEx(); |
342 | | |
343 | 39.8M | std::string string_rep; // To avoid calling ToString() twice. |
344 | 39.8M | if (print_stack_trace || |
345 | 39.8M | (status_stack_trace_re && |
346 | 0 | std::regex_search(string_rep = ToString(), *status_stack_trace_re))) { |
347 | 0 | if (string_rep.empty()) { |
348 | 0 | string_rep = ToString(); |
349 | 0 | } |
350 | | // We skip a couple of top frames like these: |
351 | | // ~/code/yugabyte/src/yb/util/status.cc:53: |
352 | | // @ yb::Status::Status(yb::Status::Code, yb::Slice const&, yb::Slice const&, long, |
353 | | // char const*, int) |
354 | | // ~/code/yugabyte/src/yb/util/status.h:137: |
355 | | // @ yb::STATUS(Corruption, char const*, int, yb::Slice const&, yb::Slice const&, short) |
356 | | // ~/code/yugabyte/src/yb/common/doc_hybrid_time.cc:94: |
357 | | // @ yb::DocHybridTime::DecodeFrom(yb::Slice*) |
358 | 0 | LOG(WARNING) << "Non-OK status generated: " << string_rep << ", stack trace:\n" |
359 | 0 | << GetStackTrace(StackTraceLineFormat::DEFAULT, /* skip frames: */ 1); |
360 | 0 | } |
361 | 39.8M | #endif |
362 | 39.8M | } |
363 | | |
364 | | Status::Status(Code code, |
365 | | const char* file_name, |
366 | | int line_number, |
367 | | const Slice& msg, |
368 | | const Slice& error, |
369 | | DupFileName dup_file_name) |
370 | 349k | : state_(State::Create(code, file_name, line_number, msg, Slice(), error, dup_file_name)) { |
371 | 349k | } |
372 | | |
373 | | Status::Status(StatePtr state) |
374 | 626k | : state_(std::move(state)) { |
375 | 626k | } |
376 | | |
377 | | Status::Status(YBCStatusStruct* state, AddRef add_ref) |
378 | 322k | : state_(pointer_cast<State*>(state), add_ref) { |
379 | 322k | } |
380 | | |
381 | | Status::Status(Code code, |
382 | | const char* file_name, |
383 | | int line_number, |
384 | | const StatusErrorCode& error, |
385 | | DupFileName dup_file_name) |
386 | 176 | : Status(code, file_name, line_number, error.Message(), Slice(), error, dup_file_name) { |
387 | 176 | } Unexecuted instantiation: _ZN2yb6StatusC2ENS0_4CodeEPKciRKNS_15StatusErrorCodeENS_17StronglyTypedBoolINS_15DupFileName_TagEEE _ZN2yb6StatusC1ENS0_4CodeEPKciRKNS_15StatusErrorCodeENS_17StronglyTypedBoolINS_15DupFileName_TagEEE Line | Count | Source | 386 | 176 | : Status(code, file_name, line_number, error.Message(), Slice(), error, dup_file_name) { | 387 | 176 | } |
|
388 | | |
389 | | Status::Status(Code code, |
390 | | const char* file_name, |
391 | | int line_number, |
392 | | const Slice& msg, |
393 | | const StatusErrorCode& error, |
394 | | DupFileName dup_file_name) |
395 | 1.72M | : Status(code, file_name, line_number, msg, error.Message(), error, dup_file_name) { |
396 | 1.72M | } Unexecuted instantiation: _ZN2yb6StatusC2ENS0_4CodeEPKciRKNS_5SliceERKNS_15StatusErrorCodeENS_17StronglyTypedBoolINS_15DupFileName_TagEEE _ZN2yb6StatusC1ENS0_4CodeEPKciRKNS_5SliceERKNS_15StatusErrorCodeENS_17StronglyTypedBoolINS_15DupFileName_TagEEE Line | Count | Source | 395 | 1.72M | : Status(code, file_name, line_number, msg, error.Message(), error, dup_file_name) { | 396 | 1.72M | } |
|
397 | | |
398 | 2.55k | YBCStatusStruct* Status::RetainStruct() const { |
399 | 2.55k | if (state_) { |
400 | 0 | intrusive_ptr_add_ref(state_.get()); |
401 | 0 | } |
402 | 2.55k | return pointer_cast<YBCStatusStruct*>(state_.get()); |
403 | 2.55k | } |
404 | | |
405 | 77.2M | YBCStatusStruct* Status::DetachStruct() { |
406 | 77.2M | return pointer_cast<YBCStatusStruct*>(state_.detach()); |
407 | 77.2M | } |
408 | | |
409 | 2.49M | const char* Status::CodeAsCString() const { |
410 | 2.49M | switch (code()) { |
411 | 0 | #define YB_STATUS_CODE(name, pb_name, value, message) \ |
412 | 2.49M | case Status::BOOST_PP_CAT(k, name): \ |
413 | 2.49M | return message; |
414 | 0 | #include "yb/util/status_codes.h" |
415 | 2.49M | #undef YB_STATUS_CODE |
416 | 2.49M | } |
417 | 0 | return nullptr; |
418 | 2.49M | } |
419 | | |
420 | 2.44M | std::string Status::CodeAsString() const { |
421 | 2.44M | auto* cstr = CodeAsCString(); |
422 | 2.44M | return cstr != nullptr ? cstr : "Incorrect status code " + std::to_string(code()); |
423 | 2.44M | } |
424 | | |
425 | 2.44M | std::string Status::ToString(bool include_file_and_line, bool include_code) const { |
426 | 2.44M | std::string result; |
427 | | |
428 | 2.44M | if (include_code) { |
429 | 2.44M | result += CodeAsString(); |
430 | 2.44M | } |
431 | | |
432 | 2.44M | if (state_ == nullptr) { |
433 | 1.03M | return result; |
434 | 1.03M | } |
435 | | |
436 | 1.41M | if (include_file_and_line && state_->file_name != nullptr && state_->line_number) { |
437 | 1.36M | result.append(result.empty() ? "(" : " ("); |
438 | | |
439 | | // Try to only include file path starting from source root directory. We are assuming that all |
440 | | // C++ code is located in $YB_SRC_ROOT/src, where $YB_SRC_ROOT is the repository root. Note that |
441 | | // this will break if the repository itself is located in a parent directory named "src". |
442 | | // However, neither Jenkins, nor our standard code location on a developer workstation |
443 | | // (~/code/yugabyte) should have that problem. |
444 | 1.36M | const char* src_subpath = strstr(state_->file_name, "/src/"); |
445 | 18.4E | result.append(src_subpath != nullptr ? src_subpath + 5 : state_->file_name); |
446 | | |
447 | 1.36M | result.append(":"); |
448 | 1.36M | result.append(std::to_string(state_->line_number)); |
449 | 1.36M | result.append(")"); |
450 | 1.36M | } |
451 | | |
452 | 1.41M | if (!result.empty()) { |
453 | 1.41M | result.append(": "); |
454 | 1.41M | } |
455 | | |
456 | 1.41M | Slice msg = message(); |
457 | 1.41M | result.append(reinterpret_cast<const char*>(msg.data()), msg.size()); |
458 | | |
459 | | // If no message (rare case) - show code (if it's not shown yet). |
460 | 1.41M | if (result.empty()) { |
461 | 0 | result += CodeAsString(); |
462 | 0 | } |
463 | | |
464 | 1.11M | for (auto slice : state_->error_codes()) { |
465 | 1.11M | result += " ("; |
466 | 1.11M | result += CategoryName(*slice.data()); |
467 | 1.11M | result += ' '; |
468 | 1.11M | result += status_categories().ToString(slice); |
469 | 1.11M | result += ')'; |
470 | 1.11M | } |
471 | | |
472 | 1.41M | return result; |
473 | 1.41M | } |
474 | | |
475 | 4.05M | Slice Status::message() const { |
476 | 4.05M | if (state_ == nullptr) { |
477 | 1 | return Slice(); |
478 | 1 | } |
479 | | |
480 | 4.05M | return Slice(state_->message, state_->message_len); |
481 | 4.05M | } |
482 | | |
483 | 862k | const char* Status::file_name() const { |
484 | 862k | return state_ ? state_->file_name : ""; |
485 | 862k | } |
486 | | |
487 | 863k | int Status::line_number() const { |
488 | 863k | return state_ ? state_->line_number : 0; |
489 | 863k | } |
490 | | |
491 | 239M | Status::Code Status::code() const { |
492 | 165M | return !state_ ? kOk : static_cast<Code>(state_->code); |
493 | 239M | } |
494 | | |
495 | 322k | Status Status::CloneAndPrepend(const Slice& msg) const { |
496 | 322k | return Status(State::Create( |
497 | 322k | code(), state_->file_name, state_->line_number, msg, message(), state_->ErrorCodesSlice(), |
498 | 322k | DupFileName(file_name_duplicated()))); |
499 | 322k | } |
500 | | |
501 | 22 | Status Status::CloneAndReplaceCode(Code code) const { |
502 | 22 | return Status(State::Create( |
503 | 22 | code, state_->file_name, state_->line_number, message(), Slice(), state_->ErrorCodesSlice(), |
504 | 22 | DupFileName(file_name_duplicated()))); |
505 | 22 | } |
506 | | |
507 | 12.9k | Status Status::CloneAndAppend(const Slice& msg) const { |
508 | 12.9k | return Status(State::Create( |
509 | 12.9k | code(), state_->file_name, state_->line_number, message(), msg, state_->ErrorCodesSlice(), |
510 | 12.9k | DupFileName(file_name_duplicated()))); |
511 | 12.9k | } |
512 | | |
513 | 289k | Status Status::CloneAndAddErrorCode(const StatusErrorCode& error_code) const { |
514 | 289k | auto errors_slice = state_->ErrorCodesSlice(); |
515 | 289k | size_t new_errors_size = errors_slice.size() + 1 + error_code.EncodedSize(); |
516 | 289k | auto buffer = static_cast<uint8_t*>(alloca(new_errors_size)); |
517 | 289k | auto out = buffer; |
518 | 289k | bool inserted = false; |
519 | | // Insert encoded error code to existing list of error codes. |
520 | | // Which is ordered by category. |
521 | 181k | for (const auto error : state_->error_codes()) { |
522 | 181k | auto current_category = *error.data(); |
523 | | // Appropriate place to insert new error code, when existing category is greater |
524 | | // and we did not insert yet. |
525 | 181k | if (!inserted && current_category >= error_code.Category()) { |
526 | 52.9k | size_t size = error.data() - errors_slice.data(); |
527 | 52.9k | memcpy(out, errors_slice.data(), size); |
528 | 52.9k | out += size; |
529 | 52.9k | out = DoEncode(error_code, out); |
530 | | // Copy remaining errors. |
531 | 52.9k | if (current_category != error_code.Category()) { |
532 | 51.2k | size_t size = errors_slice.end() - error.data(); |
533 | 51.2k | memcpy(out, error.data(), size); |
534 | 51.2k | out += size; |
535 | 1.65k | } else { |
536 | | // Skip error with the same code. |
537 | 1.65k | size_t size = errors_slice.end() - error.end(); |
538 | 1.65k | memcpy(out, error.end(), size); |
539 | 1.65k | out += size; |
540 | 1.65k | new_errors_size -= error.size(); |
541 | 1.65k | } |
542 | 52.9k | inserted = true; |
543 | 52.9k | break; |
544 | 52.9k | } |
545 | 181k | } |
546 | | // There is no error code with category greater than added, so add to end of the list. |
547 | 289k | if (!inserted) { |
548 | | // Don't copy terminating zero. |
549 | 236k | memcpy(out, errors_slice.data(), errors_slice.size() - 1); |
550 | 236k | out += errors_slice.size() - 1; |
551 | 236k | out = DoEncode(error_code, out); |
552 | 236k | *out++ = 0; |
553 | 236k | } |
554 | 289k | size_t encoded_size = out - buffer; |
555 | 13 | LOG_IF(DFATAL, encoded_size != new_errors_size) |
556 | 13 | << "New error codes size is expected to be " << new_errors_size << " but " << encoded_size |
557 | 13 | << " bytes were encoded"; |
558 | 289k | return Status(State::Create( |
559 | 289k | code(), state_->file_name, state_->line_number, message(), Slice(), |
560 | 289k | Slice(buffer, new_errors_size), DupFileName(file_name_duplicated()))); |
561 | 289k | } |
562 | | |
563 | 2 | size_t Status::memory_footprint_excluding_this() const { |
564 | 1 | return state_ ? malloc_usable_size(state_.get()) : 0; |
565 | 2 | } |
566 | | |
567 | 0 | size_t Status::memory_footprint_including_this() const { |
568 | 0 | return malloc_usable_size(this) + memory_footprint_excluding_this(); |
569 | 0 | } |
570 | | |
571 | 625k | bool Status::file_name_duplicated() const { |
572 | 625k | return state_->FileNameDuplicated(); |
573 | 625k | } |
574 | | |
575 | 20.0M | const uint8_t* Status::ErrorData(uint8_t category) const { |
576 | 20.0M | if (!state_) { |
577 | 13.6M | return nullptr; |
578 | 13.6M | } |
579 | | |
580 | 7.79M | for (auto slice : state_->error_codes()) { |
581 | 7.79M | if (*slice.data() == category) { |
582 | 2.04M | return slice.data() + 1; |
583 | 2.04M | } |
584 | 7.79M | } |
585 | | |
586 | 4.31M | return nullptr; |
587 | 6.35M | } |
588 | | |
589 | 1.11M | Slice Status::ErrorCodesSlice() const { |
590 | 1.11M | if (!state_) { |
591 | 0 | return Slice(); |
592 | 0 | } |
593 | | |
594 | 1.11M | return state_->ErrorCodesSlice(); |
595 | 1.11M | } |
596 | | |
597 | 104M | void intrusive_ptr_release(Status::State* state) { |
598 | 104M | if (state->counter.fetch_sub(1, std::memory_order_acq_rel) == 1) { |
599 | 40.7M | free(state); |
600 | 40.7M | } |
601 | 104M | } |
602 | | |
603 | 104M | void intrusive_ptr_add_ref(Status::State* state) { |
604 | 104M | state->counter.fetch_add(1, std::memory_order_relaxed); |
605 | 104M | } |
606 | | |
607 | 268k | void Status::RegisterCategory(const StatusCategoryDescription& description) { |
608 | 268k | status_categories().Register(description); |
609 | 268k | } |
610 | | |
611 | 1.11M | const std::string& Status::CategoryName(uint8_t category) { |
612 | 1.11M | return status_categories().CategoryName(category); |
613 | 1.11M | } |
614 | | |
615 | 268k | StatusCategoryRegisterer::StatusCategoryRegisterer(const StatusCategoryDescription& description) { |
616 | 268k | Status::RegisterCategory(description); |
617 | 268k | } |
618 | | |
619 | 931 | std::string StringVectorBackedErrorTag::DecodeToString(const uint8_t* source) { |
620 | 931 | return AsString(Decode(source)); |
621 | 931 | } |
622 | | |
623 | 21.1G | void StatusCheck(bool value) { |
624 | 21.1G | CHECK(value); |
625 | 21.1G | } |
626 | | |
627 | | } // namespace yb |