YugabyteDB (2.13.0.0-b42, bfc6a6643e7399ac8a0e81d06a3ee6d6571b33ab)

Coverage Report

Created: 2022-03-09 17:30

/Users/deen/code/yugabyte-db/src/yb/common/ybc_util.cc
Line
Count
Source (jump to first uncovered line)
1
// Copyright (c) YugaByte, Inc.
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
4
// in compliance with the License.  You may obtain a copy of the License at
5
//
6
// http://www.apache.org/licenses/LICENSE-2.0
7
//
8
// Unless required by applicable law or agreed to in writing, software distributed under the License
9
// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
10
// or implied.  See the License for the specific language governing permissions and limitations
11
// under the License.
12
13
#include "yb/common/ybc_util.h"
14
15
#include <stdarg.h>
16
17
#include <fstream>
18
19
#include "yb/common/pgsql_error.h"
20
#include "yb/common/transaction_error.h"
21
#include "yb/common/ybc-internal.h"
22
23
#include "yb/gutil/stringprintf.h"
24
25
#include "yb/util/bytes_formatter.h"
26
#include "yb/util/debug-util.h"
27
#include "yb/util/env.h"
28
#include "yb/util/flag_tags.h"
29
#include "yb/util/init.h"
30
#include "yb/util/logging.h"
31
#include "yb/util/net/net_util.h"
32
#include "yb/util/scope_exit.h"
33
#include "yb/util/status_format.h"
34
#include "yb/util/thread.h"
35
36
using std::string;
37
DEFINE_test_flag(string, process_info_dir, string(),
38
                 "Directory where all postgres process will writes their PIDs and executable name");
39
40
bool yb_debug_log_docdb_requests = false;
41
42
bool yb_non_ddl_txn_for_sys_tables_allowed = false;
43
44
bool yb_format_funcs_include_yb_metadata = false;
45
46
bool yb_force_global_transaction = false;
47
48
bool suppress_nonpg_logs = false;
49
50
bool yb_binary_restore = false;
51
52
namespace yb {
53
54
namespace {
55
56
6.91k
void ChangeWorkingDir(const char* dir) {
57
6.91k
  int chdir_result = chdir(dir);
58
6.91k
  if (chdir_result != 0) {
59
0
    LOG(WARNING) << "Failed to change working directory to " << dir << ", error was "
60
0
                 << errno << " " << std::strerror(errno) << "!";
61
0
  }
62
6.91k
}
63
64
1.65k
void WriteCurrentProcessInfo(const string& destination_dir) {
65
1.65k
  string executable_path;
66
1.65k
  if (Env::Default()->GetExecutablePath(&executable_path).ok()) {
67
1.65k
    const auto destination_file = Format("$0/$1", destination_dir, getpid());
68
1.65k
    std::ofstream out(destination_file, std::ios_base::out);
69
1.65k
    out << executable_path;
70
1.65k
    if (out) {
71
1.65k
      LOG(INFO) << "Process info is written to " << destination_file;
72
1.65k
      return;
73
1.65k
    }
74
0
  }
75
0
  LOG(WARNING) << "Unable to write process info to "
76
0
               << destination_dir << " dir: error " << errno << " " << std::strerror(errno);
77
0
}
78
79
3.45k
Status InitGFlags(const char* argv0) {
80
81
3.45k
  const char* executable_path = argv0;
82
3.45k
  std::string executable_path_str;
83
3.45k
  if (executable_path == nullptr) {
84
902
    RETURN_NOT_OK(Env::Default()->GetExecutablePath(&executable_path_str));
85
902
    executable_path = executable_path_str.c_str();
86
902
  }
87
3.45k
  RSTATUS_DCHECK(executable_path != nullptr, RuntimeError, "Unable to get path to executable");
88
89
  // Change current working directory from postgres data dir (as set by postmaster)
90
  // to the one from yb-tserver so that relative paths in gflags would be resolved in the same way.
91
3.45k
  char pg_working_dir[PATH_MAX];
92
3.45k
  CHECK(getcwd(pg_working_dir, sizeof(pg_working_dir)) != nullptr);
93
3.45k
  const char* yb_working_dir = getenv("YB_WORKING_DIR");
94
3.45k
  if (yb_working_dir) {
95
3.45k
    ChangeWorkingDir(yb_working_dir);
96
3.45k
  }
97
3.45k
  auto se = ScopeExit([&pg_working_dir] {
98
    // Restore PG data dir as current directory.
99
3.45k
    ChangeWorkingDir(pg_working_dir);
100
3.45k
  });
101
102
  // Also allow overriding flags on the command line using the appropriate environment variables.
103
3.45k
  std::vector<google::CommandLineFlagInfo> flag_infos;
104
3.45k
  google::GetAllFlags(&flag_infos);
105
1.08M
  for (auto& flag_info : flag_infos) {
106
1.08M
    string env_var_name = "FLAGS_" + flag_info.name;
107
1.08M
    const char* env_var_value = getenv(env_var_name.c_str());
108
1.08M
    if (env_var_value) {
109
85.5k
      google::SetCommandLineOption(flag_info.name.c_str(), env_var_value);
110
85.5k
    }
111
1.08M
  }
112
113
3.45k
  RETURN_NOT_OK(CheckCPUFlags());
114
  // Use InitGoogleLoggingSafeBasic() instead of InitGoogleLoggingSafe() to avoid calling
115
  // google::InstallFailureSignalHandler(). This will prevent interference with PostgreSQL's
116
  // own signal handling.
117
  // Use InitGoogleLoggingSafeBasicSuppressNonNativePostgresLogs() over
118
  // InitGoogleLoggingSafeBasic() when the "suppress_nonpg_logs" flag is set.
119
  // This will suppress non-Postgres logs from the Postgres log file.
120
3.45k
  if (suppress_nonpg_logs) {
121
0
    yb::InitGoogleLoggingSafeBasicSuppressNonNativePostgresLogs(executable_path);
122
3.45k
  } else {
123
3.45k
    yb::InitGoogleLoggingSafeBasic(executable_path);
124
3.45k
  }
125
126
0
  if (VLOG_IS_ON(1)) {
127
0
    for (auto& flag_info : flag_infos) {
128
0
      string env_var_name = "FLAGS_" + flag_info.name;
129
0
      const char* env_var_value = getenv(env_var_name.c_str());
130
0
      if (env_var_value) {
131
0
        VLOG(1) << "Setting flag " << flag_info.name << " to the value of the env var "
132
0
                << env_var_name << ": " << env_var_value;
133
0
      }
134
0
    }
135
0
  }
136
137
3.45k
  return Status::OK();
138
3.45k
}
139
140
} // anonymous namespace
141
142
extern "C" {
143
144
YBCStatus YBCStatus_OK = nullptr;
145
146
// Wraps Status object created by YBCStatus.
147
// Uses trick with AddRef::kFalse and DetachStruct, to avoid incrementing and decrementing
148
// ref counter.
149
class StatusWrapper {
150
 public:
151
269k
  explicit StatusWrapper(YBCStatus s) : status_(s, AddRef::kFalse) {}
152
153
269k
  ~StatusWrapper() {
154
269k
    status_.DetachStruct();
155
269k
  }
156
157
252k
  Status* operator->() {
158
252k
    return &status_;
159
252k
  }
160
161
53.6k
  Status& operator*() {
162
53.6k
    return status_;
163
53.6k
  }
164
165
 private:
166
  Status status_;
167
};
168
169
0
bool YBCStatusIsOK(YBCStatus s) {
170
0
  return StatusWrapper(s)->IsOk();
171
0
}
172
173
1.17k
bool YBCStatusIsNotFound(YBCStatus s) {
174
1.17k
  return StatusWrapper(s)->IsNotFound();
175
1.17k
}
176
177
0
bool YBCStatusIsDuplicateKey(YBCStatus s) {
178
0
  return StatusWrapper(s)->IsAlreadyPresent();
179
0
}
180
181
53.6k
uint32_t YBCStatusPgsqlError(YBCStatus s) {
182
53.6k
  StatusWrapper wrapper(s);
183
53.6k
  const uint8_t* pg_err_ptr = wrapper->ErrorData(PgsqlErrorTag::kCategory);
184
  // If we have PgsqlError explicitly set, we decode it
185
17.0k
  YBPgErrorCode result = pg_err_ptr != nullptr ? PgsqlErrorTag::Decode(pg_err_ptr)
186
36.6k
                                               : YBPgErrorCode::YB_PG_INTERNAL_ERROR;
187
188
  // If the error is the default generic YB_PG_INTERNAL_ERROR (as we also set in AsyncRpc::Failed)
189
  // then we try to deduce it from a transaction error.
190
53.6k
  if (result == YBPgErrorCode::YB_PG_INTERNAL_ERROR) {
191
36.6k
    const uint8_t* txn_err_ptr = wrapper->ErrorData(TransactionErrorTag::kCategory);
192
36.6k
    if (txn_err_ptr != nullptr) {
193
36.5k
      switch (TransactionErrorTag::Decode(txn_err_ptr)) {
194
2.52k
        case TransactionErrorCode::kAborted: FALLTHROUGH_INTENDED;
195
2.52k
        case TransactionErrorCode::kReadRestartRequired: FALLTHROUGH_INTENDED;
196
36.4k
        case TransactionErrorCode::kConflict:
197
36.4k
          result = YBPgErrorCode::YB_PG_T_R_SERIALIZATION_FAILURE;
198
36.4k
          break;
199
0
        case TransactionErrorCode::kSnapshotTooOld:
200
0
          result = YBPgErrorCode::YB_PG_SNAPSHOT_TOO_OLD;
201
0
          break;
202
0
        case TransactionErrorCode::kNone: FALLTHROUGH_INTENDED;
203
76
        default:
204
76
          result = YBPgErrorCode::YB_PG_INTERNAL_ERROR;
205
36.5k
      }
206
36.5k
    }
207
36.6k
  }
208
53.6k
  return static_cast<uint32_t>(result);
209
53.6k
}
210
211
53.6k
uint16_t YBCStatusTransactionError(YBCStatus s) {
212
53.6k
  const TransactionError txn_err(*StatusWrapper(s));
213
53.6k
  return static_cast<uint16_t>(txn_err.value());
214
53.6k
}
215
216
53.5k
void YBCFreeStatus(YBCStatus s) {
217
53.5k
  FreeYBCStatus(s);
218
53.5k
}
219
220
53.6k
size_t YBCStatusMessageLen(YBCStatus s) {
221
53.6k
  return StatusWrapper(s)->message().size();
222
53.6k
}
223
224
53.6k
const char* YBCStatusMessageBegin(YBCStatus s) {
225
53.6k
  return StatusWrapper(s)->message().cdata();
226
53.6k
}
227
228
53.6k
const char* YBCStatusCodeAsCString(YBCStatus s) {
229
53.6k
  return StatusWrapper(s)->CodeAsCString();
230
53.6k
}
231
232
53.6k
char* DupYBStatusMessage(YBCStatus status, bool message_only) {
233
53.6k
  const char* const code_as_cstring = YBCStatusCodeAsCString(status);
234
53.6k
  const size_t code_strlen = strlen(code_as_cstring);
235
53.6k
  const size_t status_len = YBCStatusMessageLen(status);
236
53.6k
  size_t sz = code_strlen + status_len + 3;
237
53.6k
  if (message_only) {
238
1.02k
    sz -= 2 + code_strlen;
239
1.02k
  }
240
53.6k
  char* const msg_buf = reinterpret_cast<char*>(YBCPAlloc(sz));
241
53.6k
  char* pos = msg_buf;
242
53.6k
  if (!message_only) {
243
52.5k
    memcpy(msg_buf, code_as_cstring, code_strlen);
244
52.5k
    pos += code_strlen;
245
52.5k
    *pos++ = ':';
246
52.5k
    *pos++ = ' ';
247
52.5k
  }
248
53.6k
  memcpy(pos, YBCStatusMessageBegin(status), status_len);
249
53.6k
  pos[status_len] = 0;
250
53.6k
  return msg_buf;
251
53.6k
}
252
253
91.8k
bool YBCIsRestartReadError(uint16_t txn_errcode) {
254
91.8k
  return txn_errcode == static_cast<uint16_t>(TransactionErrorCode::kReadRestartRequired);
255
91.8k
}
256
257
902
YBCStatus YBCInitGFlags(const char* argv0) {
258
902
  return ToYBCStatus(yb::InitGFlags(argv0));
259
902
}
260
261
96.6k
bool YBCIsTxnConflictError(uint16_t txn_errcode) {
262
96.6k
  return txn_errcode == to_underlying(TransactionErrorCode::kConflict);
263
96.6k
}
264
265
76
bool YBCIsTxnSkipLockingError(uint16_t txn_errcode) {
266
76
  return txn_errcode == to_underlying(TransactionErrorCode::kSkipLocking);
267
76
}
268
269
4.67k
uint16_t YBCGetTxnConflictErrorCode() {
270
4.67k
  return to_underlying(TransactionErrorCode::kConflict);
271
4.67k
}
272
273
YBCStatus YBCInit(const char* argv0,
274
                  YBCPAllocFn palloc_fn,
275
2.55k
                  YBCCStringToTextWithLenFn cstring_to_text_with_len_fn) {
276
2.55k
  YBCSetPAllocFn(palloc_fn);
277
2.55k
  if (cstring_to_text_with_len_fn) {
278
2.55k
    YBCSetCStringToTextWithLenFn(cstring_to_text_with_len_fn);
279
2.55k
  }
280
2.55k
  auto status = yb::InitGFlags(argv0);
281
2.55k
  if (status.ok() && !FLAGS_TEST_process_info_dir.empty()) {
282
1.65k
    WriteCurrentProcessInfo(FLAGS_TEST_process_info_dir);
283
1.65k
  }
284
2.55k
  return ToYBCStatus(status);
285
2.55k
}
286
287
void YBCLogImpl(
288
    google::LogSeverity severity,
289
    const char* file,
290
    int line,
291
    bool with_stack_trace,
292
    const char* format,
293
1.55k
    ...) {
294
1.55k
  va_list argptr;
295
1.55k
  va_start(argptr, format); \
296
1.55k
  string buf;
297
1.55k
  StringAppendV(&buf, format, argptr);
298
1.55k
  va_end(argptr);
299
1.55k
  google::LogMessage log_msg(file, line, severity);
300
1.55k
  log_msg.stream() << buf;
301
1.55k
  if (with_stack_trace) {
302
0
    log_msg.stream() << "\n" << yb::GetStackTrace();
303
0
  }
304
1.55k
}
305
306
0
const char* YBCFormatBytesAsStr(const char* data, size_t size) {
307
0
  return YBCPAllocStdString(FormatBytesAsStr(data, size));
308
0
}
309
310
0
const char* YBCGetStackTrace() {
311
0
  return YBCPAllocStdString(yb::GetStackTrace());
312
0
}
313
314
902
void YBCResolveHostname() {
315
902
  string fqdn;
316
902
  auto status = GetFQDN(&fqdn);
317
902
  if (!status.ok()) {
318
0
    LOG(WARNING) << "Failed to get fully qualified domain name of the local hostname: "
319
0
                 << status;
320
0
  }
321
902
}
322
323
0
inline double YBCGetNumHashBuckets() {
324
0
  return 64.0;
325
0
}
326
327
/* Gets the number of hash buckets for a DocDB table */
328
0
inline double YBCGetHashBucketFromValue(uint32_t hash_val) {
329
  /*
330
  * Since hash values are 16 bit for now and there are (1 << 6)
331
  * buckets, we must right shift a hash value by 16 - 6 = 10 to
332
  * obtain its bucket number
333
  */
334
0
  return hash_val >> 10;
335
0
}
336
337
0
double YBCEvalHashValueSelectivity(int32_t hash_low, int32_t hash_high) {
338
0
      hash_high = hash_high <= USHRT_MAX ? hash_high : USHRT_MAX;
339
0
      hash_high = hash_high >= 0 ? hash_high : 0;
340
0
      hash_low = hash_low >= 0 ? hash_low : 0;
341
0
      hash_low = hash_low <= USHRT_MAX ? hash_low : USHRT_MAX;
342
343
0
      uint32_t greatest_bucket = YBCGetHashBucketFromValue(hash_high);
344
0
      uint32_t lowest_bucket = YBCGetHashBucketFromValue(hash_low);
345
0
      return hash_high >= hash_low ?
346
0
          ((greatest_bucket - lowest_bucket + 1.0) / YBCGetNumHashBuckets())
347
0
          : 0.0;
348
0
}
349
350
902
void YBCInitThreading() {
351
902
  InitThreading();
352
902
}
353
354
} // extern "C"
355
356
} // namespace yb