/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 | 32.7k | boost::optional<std::regex> StatusStackTraceRegEx() { |
40 | 32.7k | const char* regex_str = getenv("YB_STACK_TRACE_ON_ERROR_STATUS_RE"); |
41 | 32.7k | if (!regex_str) { |
42 | 32.7k | return boost::none; |
43 | 32.7k | } |
44 | 0 | return std::regex(regex_str); |
45 | 32.7k | } |
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 | 452k | void Register(const StatusCategoryDescription& description) { |
81 | 452k | CHECK(!categories[description.id].name); |
82 | 452k | categories[description.id] = description; |
83 | 452k | } |
84 | | |
85 | 2.66M | const std::string& CategoryName(uint8_t category) { |
86 | 2.66M | const auto& description = categories[category]; |
87 | 2.66M | if (!description.name) { |
88 | 0 | static std::string kUnknownCategory("unknown error category"); |
89 | 0 | return kUnknownCategory; |
90 | 0 | } |
91 | 2.66M | return *description.name; |
92 | 2.66M | } |
93 | | |
94 | | // Returns data slice w/o category for error code starting with start. |
95 | 44.8M | Slice GetSlice(const uint8_t* start) { |
96 | 44.8M | const uint8_t category_id = *start; |
97 | 44.8M | const auto& description = categories[category_id]; |
98 | 44.8M | if (description.name == nullptr) { |
99 | 21.1M | if (category_id > 0) |
100 | 0 | ReportMissingCategory(category_id, __func__); |
101 | 21.1M | return Slice(); |
102 | 21.1M | } |
103 | 23.7M | return Slice(start, 1 + description.decode_size(start + 1)); |
104 | 44.8M | } |
105 | | |
106 | 2.66M | std::string ToString(Slice encoded_err_code) { |
107 | 2.66M | const uint8_t category_id = *encoded_err_code.data(); |
108 | 2.66M | const auto& description = categories[category_id]; |
109 | 2.66M | if (description.name == nullptr) { |
110 | 0 | if (category_id > 0) |
111 | 0 | ReportMissingCategory(category_id, __func__); |
112 | 0 | return std::string(); |
113 | 0 | } |
114 | 2.66M | return description.to_string(encoded_err_code.data() + 1); |
115 | 2.66M | } |
116 | | }; |
117 | | |
118 | 50.6M | StatusCategories& status_categories() { |
119 | 50.6M | static StatusCategories result; |
120 | 50.6M | return result; |
121 | 50.6M | } |
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 | 54.4M | : Slice()) {} |
130 | | |
131 | 66.0M | bool is_end() const { |
132 | 66.0M | return current_.empty(); |
133 | 66.0M | } |
134 | | |
135 | 23.7M | value_type operator*() const { |
136 | 23.7M | return current_; |
137 | 23.7M | } |
138 | | |
139 | 17.6M | ErrorCodeIterator& operator++() { |
140 | 17.6M | current_ = status_categories().GetSlice(current_.end()); |
141 | 17.6M | return *this; |
142 | 17.6M | } |
143 | | |
144 | | private: |
145 | 44.8M | friend bool operator==(const ErrorCodeIterator& lhs, const ErrorCodeIterator& rhs) { |
146 | 44.8M | return lhs.is_end() ? rhs.is_end()21.1M : lhs.current_.data() == rhs.current_.data()23.7M ; |
147 | 44.8M | } |
148 | | |
149 | 44.8M | friend bool operator!=(const ErrorCodeIterator& lhs, const ErrorCodeIterator& rhs) { |
150 | 44.8M | return !(lhs == rhs); |
151 | 44.8M | } |
152 | | |
153 | | Slice current_; |
154 | | }; |
155 | | |
156 | 7.83M | uint8_t* DoEncode(const StatusErrorCode& error, uint8_t* out) { |
157 | 7.83M | *out++ = error.Category(); |
158 | 7.83M | auto new_out = error.Encode(out); |
159 | 7.83M | DCHECK_EQ(out + error.EncodedSize(), new_out); |
160 | 7.83M | return new_out; |
161 | 7.83M | } |
162 | | |
163 | | class ErrorCodesRange { |
164 | | public: |
165 | 27.2M | explicit ErrorCodesRange(const char* start) : start_(start) { |
166 | 27.2M | } |
167 | | |
168 | | typedef ErrorCodeIterator const_iterator; |
169 | | |
170 | 27.2M | const_iterator begin() const { |
171 | 27.2M | return ErrorCodeIterator(start_); |
172 | 27.2M | } |
173 | | |
174 | 27.2M | const_iterator end() const { |
175 | 27.2M | return ErrorCodeIterator(nullptr); |
176 | 27.2M | } |
177 | | |
178 | | private: |
179 | | const char* start_; |
180 | | }; |
181 | | |
182 | | } // anonymous namespace |
183 | | |
184 | 1.01k | StringVectorBackedErrorTag::Value StringVectorBackedErrorTag::Decode(const uint8_t* source) { |
185 | 1.01k | if (!source) { |
186 | 5 | return Value(); |
187 | 5 | } |
188 | 1.00k | Value result; |
189 | 1.00k | Slice buf(source, DecodeSize(source)); |
190 | 1.00k | buf.remove_prefix(sizeof(SizeType)); |
191 | 1.14k | while (buf.size() > 0) { |
192 | 134 | const auto str_size = Load<SizeType, LittleEndian>(buf.data()); |
193 | 134 | buf.remove_prefix(sizeof(SizeType)); |
194 | 134 | result.emplace_back(buf.cdata(), str_size); |
195 | 134 | buf.remove_prefix(str_size); |
196 | 134 | } |
197 | 1.00k | return result; |
198 | 1.01k | } |
199 | | |
200 | 796 | size_t StringVectorBackedErrorTag::EncodedSize(const StringVectorBackedErrorTag::Value& value) { |
201 | 796 | size_t size = sizeof(SizeType); |
202 | 796 | for (const auto& str : value) { |
203 | 160 | size += sizeof(SizeType) + str.size(); |
204 | 160 | } |
205 | 796 | return size; |
206 | 796 | } |
207 | | |
208 | | uint8_t* StringVectorBackedErrorTag::Encode( |
209 | 398 | const StringVectorBackedErrorTag::Value& value, uint8_t* out) { |
210 | 398 | uint8_t* const start = out; |
211 | 398 | out += sizeof(SizeType); |
212 | 398 | for (const auto& str : value) { |
213 | 80 | Store<SizeType, LittleEndian>(out, str.size()); |
214 | 80 | out += sizeof(SizeType); |
215 | 80 | memcpy(out, str.data(), str.size()); |
216 | 80 | out += str.size(); |
217 | 80 | } |
218 | 398 | Store<SizeType, LittleEndian>(start, out - start); |
219 | 398 | return out; |
220 | 398 | } |
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 | 27.2M | ErrorCodesRange error_codes() const { |
244 | 27.2M | return ErrorCodesRange(message + message_len); |
245 | 27.2M | } |
246 | | |
247 | 9.23M | const char* ErrorCodesEnd() const { |
248 | 9.23M | Slice last(message + message_len, size_t(0)); |
249 | 9.23M | for (Slice current : error_codes()) { |
250 | 4.22M | last = current; |
251 | 4.22M | } |
252 | 9.23M | return last.cend() + 1; |
253 | 9.23M | } |
254 | | |
255 | 5.83M | Slice ErrorCodesSlice() const { |
256 | 5.83M | return Slice(message + message_len, ErrorCodesEnd()); |
257 | 5.83M | } |
258 | | |
259 | 3.40M | bool FileNameDuplicated() const { |
260 | 3.40M | return file_name == ErrorCodesEnd(); |
261 | 3.40M | } |
262 | | |
263 | 187M | static size_t ErrorsSize(const StatusErrorCode* error) { |
264 | 187M | size_t result = 1; |
265 | 187M | if (error) { |
266 | 7.10M | result += 1 + error->EncodedSize(); |
267 | 7.10M | } |
268 | 187M | return result; |
269 | 187M | } |
270 | | |
271 | 187M | static uint8_t* StoreErrors(const StatusErrorCode* error, uint8_t* out) { |
272 | 187M | if (error) { |
273 | 7.10M | out = DoEncode(*error, out); |
274 | 7.10M | } |
275 | 187M | *out++ = 0; |
276 | 187M | return out; |
277 | 187M | } |
278 | | |
279 | 4.04M | static size_t ErrorsSize(const Slice& errors) { |
280 | 4.04M | return errors.size(); |
281 | 4.04M | } |
282 | | |
283 | 4.04M | static uint8_t* StoreErrors(const Slice& errors, uint8_t* out) { |
284 | 4.04M | memcpy(out, errors.data(), errors.size()); |
285 | 4.04M | return out + errors.size(); |
286 | 4.04M | } |
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 | 191M | const Errors& errors, DupFileName dup_file_name) { |
293 | 191M | static constexpr size_t kHeaderSize = offsetof(State, message); |
294 | | |
295 | 191M | assert(code != kOk); |
296 | 0 | const size_t len1 = msg.size(); |
297 | 191M | const size_t len2 = msg2.size(); |
298 | 191M | const size_t size = len1 + (len2 ? (2 + len2)7.97M : 0183M ); |
299 | 191M | const size_t errors_size = ErrorsSize(errors); |
300 | 191M | size_t file_name_size = 0; |
301 | 191M | if (dup_file_name) { |
302 | 1.01M | file_name_size = strlen(file_name) + 1; |
303 | 1.01M | } |
304 | 191M | StatePtr result(static_cast<State*>(malloc(size + kHeaderSize + errors_size + file_name_size))); |
305 | 191M | result->message_len = static_cast<uint32_t>(size); |
306 | 191M | result->code = static_cast<uint8_t>(code); |
307 | | // We aleady assigned intrusive_ptr, so counter should be one. |
308 | 191M | result->counter.store(1, std::memory_order_relaxed); |
309 | 191M | result->line_number = line_number; |
310 | 191M | memcpy(result->message, msg.data(), len1); |
311 | 191M | if (len2) { |
312 | 7.97M | result->message[len1] = ':'; |
313 | 7.97M | result->message[len1 + 1] = ' '; |
314 | 7.97M | memcpy(result->message + 2 + len1, msg2.data(), len2); |
315 | 7.97M | } |
316 | 191M | auto errors_start = pointer_cast<uint8_t*>(&result->message[0] + size); |
317 | 191M | auto out = StoreErrors(errors, errors_start); |
318 | 191M | DCHECK_EQ(out, errors_start + errors_size); |
319 | 191M | if (dup_file_name) { |
320 | 1.01M | auto new_file_name = out; |
321 | 1.01M | memcpy(new_file_name, file_name, file_name_size); |
322 | 1.01M | file_name = pointer_cast<char*>(new_file_name); |
323 | 1.01M | } |
324 | | |
325 | 191M | result->file_name = file_name; |
326 | | |
327 | 191M | return result; |
328 | 191M | } boost::intrusive_ptr<yb::Status::State> yb::Status::State::Create<yb::StatusErrorCode const*>(yb::Status::Code, char const*, int, yb::Slice const&, yb::Slice const&, yb::StatusErrorCode const* const&, yb::StronglyTypedBool<yb::DupFileName_Tag>) Line | Count | Source | 292 | 187M | const Errors& errors, DupFileName dup_file_name) { | 293 | 187M | static constexpr size_t kHeaderSize = offsetof(State, message); | 294 | | | 295 | 187M | assert(code != kOk); | 296 | 0 | const size_t len1 = msg.size(); | 297 | 187M | const size_t len2 = msg2.size(); | 298 | 187M | const size_t size = len1 + (len2 ? (2 + len2)5.30M : 0182M ); | 299 | 187M | const size_t errors_size = ErrorsSize(errors); | 300 | 187M | size_t file_name_size = 0; | 301 | 187M | if (dup_file_name) { | 302 | 0 | file_name_size = strlen(file_name) + 1; | 303 | 0 | } | 304 | 187M | StatePtr result(static_cast<State*>(malloc(size + kHeaderSize + errors_size + file_name_size))); | 305 | 187M | result->message_len = static_cast<uint32_t>(size); | 306 | 187M | result->code = static_cast<uint8_t>(code); | 307 | | // We aleady assigned intrusive_ptr, so counter should be one. | 308 | 187M | result->counter.store(1, std::memory_order_relaxed); | 309 | 187M | result->line_number = line_number; | 310 | 187M | memcpy(result->message, msg.data(), len1); | 311 | 187M | if (len2) { | 312 | 5.30M | result->message[len1] = ':'; | 313 | 5.30M | result->message[len1 + 1] = ' '; | 314 | 5.30M | memcpy(result->message + 2 + len1, msg2.data(), len2); | 315 | 5.30M | } | 316 | 187M | auto errors_start = pointer_cast<uint8_t*>(&result->message[0] + size); | 317 | 187M | auto out = StoreErrors(errors, errors_start); | 318 | 187M | DCHECK_EQ(out, errors_start + errors_size); | 319 | 187M | 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 | 187M | result->file_name = file_name; | 326 | | | 327 | 187M | return result; | 328 | 187M | } |
boost::intrusive_ptr<yb::Status::State> yb::Status::State::Create<yb::Slice>(yb::Status::Code, char const*, int, yb::Slice const&, yb::Slice const&, yb::Slice const&, yb::StronglyTypedBool<yb::DupFileName_Tag>) Line | Count | Source | 292 | 4.04M | const Errors& errors, DupFileName dup_file_name) { | 293 | 4.04M | static constexpr size_t kHeaderSize = offsetof(State, message); | 294 | | | 295 | 4.04M | assert(code != kOk); | 296 | 0 | const size_t len1 = msg.size(); | 297 | 4.04M | const size_t len2 = msg2.size(); | 298 | 4.04M | const size_t size = len1 + (len2 ? (2 + len2)2.66M : 01.37M ); | 299 | 4.04M | const size_t errors_size = ErrorsSize(errors); | 300 | 4.04M | size_t file_name_size = 0; | 301 | 4.04M | if (dup_file_name) { | 302 | 1.01M | file_name_size = strlen(file_name) + 1; | 303 | 1.01M | } | 304 | 4.04M | StatePtr result(static_cast<State*>(malloc(size + kHeaderSize + errors_size + file_name_size))); | 305 | 4.04M | result->message_len = static_cast<uint32_t>(size); | 306 | 4.04M | result->code = static_cast<uint8_t>(code); | 307 | | // We aleady assigned intrusive_ptr, so counter should be one. | 308 | 4.04M | result->counter.store(1, std::memory_order_relaxed); | 309 | 4.04M | result->line_number = line_number; | 310 | 4.04M | memcpy(result->message, msg.data(), len1); | 311 | 4.04M | if (len2) { | 312 | 2.66M | result->message[len1] = ':'; | 313 | 2.66M | result->message[len1 + 1] = ' '; | 314 | 2.66M | memcpy(result->message + 2 + len1, msg2.data(), len2); | 315 | 2.66M | } | 316 | 4.04M | auto errors_start = pointer_cast<uint8_t*>(&result->message[0] + size); | 317 | 4.04M | auto out = StoreErrors(errors, errors_start); | 318 | 4.04M | DCHECK_EQ(out, errors_start + errors_size); | 319 | 4.04M | if (dup_file_name) { | 320 | 1.01M | auto new_file_name = out; | 321 | 1.01M | memcpy(new_file_name, file_name, file_name_size); | 322 | 1.01M | file_name = pointer_cast<char*>(new_file_name); | 323 | 1.01M | } | 324 | | | 325 | 4.04M | result->file_name = file_name; | 326 | | | 327 | 4.04M | return result; | 328 | 4.04M | } |
|
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 | 187M | : state_(State::Create(code, file_name, line_number, msg, msg2, error, dup_file_name)) { |
338 | 187M | #ifndef NDEBUG |
339 | 187M | static const bool print_stack_trace = getenv("YB_STACK_TRACE_ON_ERROR_STATUS") != nullptr; |
340 | 187M | static const boost::optional<std::regex> status_stack_trace_re = |
341 | 187M | StatusStackTraceRegEx(); |
342 | | |
343 | 187M | std::string string_rep; // To avoid calling ToString() twice. |
344 | 187M | if (print_stack_trace || |
345 | 187M | (187M status_stack_trace_re187M && |
346 | 187M | std::regex_search(string_rep = ToString(), *status_stack_trace_re)0 )) { |
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 | 187M | #endif |
362 | 187M | } |
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 | 645k | : state_(State::Create(code, file_name, line_number, msg, Slice(), error, dup_file_name)) { |
371 | 645k | } |
372 | | |
373 | | Status::Status(StatePtr state) |
374 | 3.40M | : state_(std::move(state)) { |
375 | 3.40M | } |
376 | | |
377 | | Status::Status(YBCStatusStruct* state, AddRef add_ref) |
378 | 1.60M | : state_(pointer_cast<State*>(state), add_ref) { |
379 | 1.60M | } |
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: yb::Status::Status(yb::Status::Code, char const*, int, yb::StatusErrorCode const&, yb::StronglyTypedBool<yb::DupFileName_Tag>) yb::Status::Status(yb::Status::Code, char const*, int, yb::StatusErrorCode const&, yb::StronglyTypedBool<yb::DupFileName_Tag>) 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 | 5.25M | : Status(code, file_name, line_number, msg, error.Message(), error, dup_file_name) { |
396 | 5.25M | } Unexecuted instantiation: yb::Status::Status(yb::Status::Code, char const*, int, yb::Slice const&, yb::StatusErrorCode const&, yb::StronglyTypedBool<yb::DupFileName_Tag>) yb::Status::Status(yb::Status::Code, char const*, int, yb::Slice const&, yb::StatusErrorCode const&, yb::StronglyTypedBool<yb::DupFileName_Tag>) Line | Count | Source | 395 | 5.25M | : Status(code, file_name, line_number, msg, error.Message(), error, dup_file_name) { | 396 | 5.25M | } |
|
397 | | |
398 | 8.09k | YBCStatusStruct* Status::RetainStruct() const { |
399 | 8.09k | if (state_) { |
400 | 0 | intrusive_ptr_add_ref(state_.get()); |
401 | 0 | } |
402 | 8.09k | return pointer_cast<YBCStatusStruct*>(state_.get()); |
403 | 8.09k | } |
404 | | |
405 | 226M | YBCStatusStruct* Status::DetachStruct() { |
406 | 226M | return pointer_cast<YBCStatusStruct*>(state_.detach()); |
407 | 226M | } |
408 | | |
409 | 5.68M | const char* Status::CodeAsCString() const { |
410 | 5.68M | switch (code()) { |
411 | 0 | #define YB_STATUS_CODE(name, pb_name, value, message) \ |
412 | 5.68M | case Status::BOOST_PP_CAT(k, name): \ |
413 | 5.68M | return message; |
414 | 5.68M | #include "yb/util/status_codes.h"0 |
415 | 5.68M | #undef YB_STATUS_CODE |
416 | 5.68M | } |
417 | 0 | return nullptr; |
418 | 5.68M | } |
419 | | |
420 | 5.55M | std::string Status::CodeAsString() const { |
421 | 5.55M | auto* cstr = CodeAsCString(); |
422 | 5.55M | return cstr != nullptr ? cstr5.55M : "Incorrect status code " + std::to_string(code())1.07k ; |
423 | 5.55M | } |
424 | | |
425 | 5.12M | std::string Status::ToString(bool include_file_and_line, bool include_code) const { |
426 | 5.12M | std::string result; |
427 | | |
428 | 5.12M | if (include_code) { |
429 | 5.12M | result += CodeAsString(); |
430 | 5.12M | } |
431 | | |
432 | 5.12M | if (state_ == nullptr) { |
433 | 1.60M | return result; |
434 | 1.60M | } |
435 | | |
436 | 3.52M | if (include_file_and_line && state_->file_name != nullptr3.48M && state_->line_number3.48M ) { |
437 | 3.48M | result.append(result.empty() ? "("0 : " ("); |
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 | 3.48M | const char* src_subpath = strstr(state_->file_name, "/src/"); |
445 | 18.4E | result.append(src_subpath != nullptr3.48M ? src_subpath + 53.48M : state_->file_name); |
446 | | |
447 | 3.48M | result.append(":"); |
448 | 3.48M | result.append(std::to_string(state_->line_number)); |
449 | 3.48M | result.append(")"); |
450 | 3.48M | } |
451 | | |
452 | 3.52M | if (!result.empty()) { |
453 | 3.51M | result.append(": "); |
454 | 3.51M | } |
455 | | |
456 | 3.52M | Slice msg = message(); |
457 | 3.52M | 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 | 3.52M | if (result.empty()) { |
461 | 0 | result += CodeAsString(); |
462 | 0 | } |
463 | | |
464 | 3.52M | for (auto slice : state_->error_codes()) { |
465 | 2.66M | result += " ("; |
466 | 2.66M | result += CategoryName(*slice.data()); |
467 | 2.66M | result += ' '; |
468 | 2.66M | result += status_categories().ToString(slice); |
469 | 2.66M | result += ')'; |
470 | 2.66M | } |
471 | | |
472 | 3.52M | return result; |
473 | 5.12M | } |
474 | | |
475 | 11.3M | Slice Status::message() const { |
476 | 11.3M | if (state_ == nullptr) { |
477 | 1 | return Slice(); |
478 | 1 | } |
479 | | |
480 | 11.3M | return Slice(state_->message, state_->message_len); |
481 | 11.3M | } |
482 | | |
483 | 1.86M | const char* Status::file_name() const { |
484 | 18.4E | return state_1.86M ? state_->file_name1.86M : ""; |
485 | 1.86M | } |
486 | | |
487 | 1.86M | int Status::line_number() const { |
488 | 18.4E | return state_1.86M ? state_->line_number1.86M : 0; |
489 | 1.86M | } |
490 | | |
491 | 685M | Status::Code Status::code() const { |
492 | 685M | return !state_ ? kOk398M : static_cast<Code>(state_->code)287M ; |
493 | 685M | } |
494 | | |
495 | 2.64M | Status Status::CloneAndPrepend(const Slice& msg) const { |
496 | 2.64M | return Status(State::Create( |
497 | 2.64M | code(), state_->file_name, state_->line_number, msg, message(), state_->ErrorCodesSlice(), |
498 | 2.64M | DupFileName(file_name_duplicated()))); |
499 | 2.64M | } |
500 | | |
501 | 37 | Status Status::CloneAndReplaceCode(Code code) const { |
502 | 37 | return Status(State::Create( |
503 | 37 | code, state_->file_name, state_->line_number, message(), Slice(), state_->ErrorCodesSlice(), |
504 | 37 | DupFileName(file_name_duplicated()))); |
505 | 37 | } |
506 | | |
507 | 27.2k | Status Status::CloneAndAppend(const Slice& msg) const { |
508 | 27.2k | return Status(State::Create( |
509 | 27.2k | code(), state_->file_name, state_->line_number, message(), msg, state_->ErrorCodesSlice(), |
510 | 27.2k | DupFileName(file_name_duplicated()))); |
511 | 27.2k | } |
512 | | |
513 | 732k | Status Status::CloneAndAddErrorCode(const StatusErrorCode& error_code) const { |
514 | 732k | auto errors_slice = state_->ErrorCodesSlice(); |
515 | 732k | size_t new_errors_size = errors_slice.size() + 1 + error_code.EncodedSize(); |
516 | 732k | auto buffer = static_cast<uint8_t*>(alloca(new_errors_size)); |
517 | 732k | auto out = buffer; |
518 | 732k | bool inserted = false; |
519 | | // Insert encoded error code to existing list of error codes. |
520 | | // Which is ordered by category. |
521 | 732k | for (const auto error : state_->error_codes()) { |
522 | 321k | 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 | 321k | if (!inserted && current_category >= error_code.Category()321k ) { |
526 | 81.8k | size_t size = error.data() - errors_slice.data(); |
527 | 81.8k | memcpy(out, errors_slice.data(), size); |
528 | 81.8k | out += size; |
529 | 81.8k | out = DoEncode(error_code, out); |
530 | | // Copy remaining errors. |
531 | 81.8k | if (current_category != error_code.Category()) { |
532 | 80.2k | size_t size = errors_slice.end() - error.data(); |
533 | 80.2k | memcpy(out, error.data(), size); |
534 | 80.2k | out += size; |
535 | 80.2k | } else { |
536 | | // Skip error with the same code. |
537 | 1.60k | size_t size = errors_slice.end() - error.end(); |
538 | 1.60k | memcpy(out, error.end(), size); |
539 | 1.60k | out += size; |
540 | 1.60k | new_errors_size -= error.size(); |
541 | 1.60k | } |
542 | 81.8k | inserted = true; |
543 | 81.8k | break; |
544 | 81.8k | } |
545 | 321k | } |
546 | | // There is no error code with category greater than added, so add to end of the list. |
547 | 732k | if (!inserted) { |
548 | | // Don't copy terminating zero. |
549 | 650k | memcpy(out, errors_slice.data(), errors_slice.size() - 1); |
550 | 650k | out += errors_slice.size() - 1; |
551 | 650k | out = DoEncode(error_code, out); |
552 | 650k | *out++ = 0; |
553 | 650k | } |
554 | 732k | size_t encoded_size = out - buffer; |
555 | 732k | LOG_IF(DFATAL, encoded_size != new_errors_size) |
556 | 156 | << "New error codes size is expected to be " << new_errors_size << " but " << encoded_size |
557 | 156 | << " bytes were encoded"; |
558 | 732k | return Status(State::Create( |
559 | 732k | code(), state_->file_name, state_->line_number, message(), Slice(), |
560 | 732k | Slice(buffer, new_errors_size), DupFileName(file_name_duplicated()))); |
561 | 732k | } |
562 | | |
563 | 2 | size_t Status::memory_footprint_excluding_this() const { |
564 | 2 | return state_ ? malloc_usable_size(state_.get())1 : 01 ; |
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 | 3.40M | bool Status::file_name_duplicated() const { |
572 | 3.40M | return state_->FileNameDuplicated(); |
573 | 3.40M | } |
574 | | |
575 | 41.5M | const uint8_t* Status::ErrorData(uint8_t category) const { |
576 | 41.5M | if (!state_) { |
577 | 27.8M | return nullptr; |
578 | 27.8M | } |
579 | | |
580 | 16.5M | for (auto slice : state_->error_codes())13.7M { |
581 | 16.5M | if (*slice.data() == category) { |
582 | 6.00M | return slice.data() + 1; |
583 | 6.00M | } |
584 | 16.5M | } |
585 | | |
586 | 7.74M | return nullptr; |
587 | 13.7M | } |
588 | | |
589 | 2.43M | Slice Status::ErrorCodesSlice() const { |
590 | 2.43M | if (!state_) { |
591 | 0 | return Slice(); |
592 | 0 | } |
593 | | |
594 | 2.43M | return state_->ErrorCodesSlice(); |
595 | 2.43M | } |
596 | | |
597 | 445M | void intrusive_ptr_release(Status::State* state) { |
598 | 445M | if (state->counter.fetch_sub(1, std::memory_order_acq_rel) == 1) { |
599 | 191M | free(state); |
600 | 191M | } |
601 | 445M | } |
602 | | |
603 | 446M | void intrusive_ptr_add_ref(Status::State* state) { |
604 | 446M | state->counter.fetch_add(1, std::memory_order_relaxed); |
605 | 446M | } |
606 | | |
607 | 452k | void Status::RegisterCategory(const StatusCategoryDescription& description) { |
608 | 452k | status_categories().Register(description); |
609 | 452k | } |
610 | | |
611 | 2.66M | const std::string& Status::CategoryName(uint8_t category) { |
612 | 2.66M | return status_categories().CategoryName(category); |
613 | 2.66M | } |
614 | | |
615 | 452k | StatusCategoryRegisterer::StatusCategoryRegisterer(const StatusCategoryDescription& description) { |
616 | 452k | Status::RegisterCategory(description); |
617 | 452k | } |
618 | | |
619 | 976 | std::string StringVectorBackedErrorTag::DecodeToString(const uint8_t* source) { |
620 | 976 | return AsString(Decode(source)); |
621 | 976 | } |
622 | | |
623 | 68.4G | void StatusCheck(bool value) { |
624 | 68.4G | CHECK(value); |
625 | 68.4G | } |
626 | | |
627 | | } // namespace yb |