YugabyteDB (2.13.1.0-b60, 21121d69985fbf76aa6958d8f04a9bfa936293b5)

Coverage Report

Created: 2022-03-22 16:43

/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