YugabyteDB (2.13.0.0-b42, bfc6a6643e7399ac8a0e81d06a3ee6d6571b33ab)

Coverage Report

Created: 2022-03-09 17:30

/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