YugabyteDB (2.13.1.0-b60, 21121d69985fbf76aa6958d8f04a9bfa936293b5)

Coverage Report

Created: 2022-03-22 16:43

/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
20.1k
void ChangeWorkingDir(const char* dir) {
57
20.1k
  int chdir_result = chdir(dir);
58
20.1k
  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
20.1k
}
63
64
4.89k
void WriteCurrentProcessInfo(const string& destination_dir) {
65
4.89k
  string executable_path;
66
4.89k
  if (Env::Default()->GetExecutablePath(&executable_path).ok()) {
67
4.89k
    const auto destination_file = Format("$0/$1", destination_dir, getpid());
68
4.89k
    std::ofstream out(destination_file, std::ios_base::out);
69
4.89k
    out << executable_path;
70
4.89k
    if (
out4.89k
) {
71
4.89k
      LOG(INFO) << "Process info is written to " << destination_file;
72
4.89k
      return;
73
4.89k
    }
74
4.89k
  }
75
18.4E
  LOG(WARNING) << "Unable to write process info to "
76
18.4E
               << destination_dir << " dir: error " << errno << " " << std::strerror(errno);
77
18.4E
}
78
79
10.0k
Status InitGFlags(const char* argv0) {
80
81
10.0k
  const char* executable_path = argv0;
82
10.0k
  std::string executable_path_str;
83
10.0k
  if (executable_path == nullptr) {
84
1.99k
    RETURN_NOT_OK(Env::Default()->GetExecutablePath(&executable_path_str));
85
1.99k
    executable_path = executable_path_str.c_str();
86
1.99k
  }
87
10.0k
  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
10.0k
  char pg_working_dir[PATH_MAX];
92
10.0k
  CHECK(getcwd(pg_working_dir, sizeof(pg_working_dir)) != nullptr);
93
10.0k
  const char* yb_working_dir = getenv("YB_WORKING_DIR");
94
10.0k
  if (yb_working_dir) {
95
10.0k
    ChangeWorkingDir(yb_working_dir);
96
10.0k
  }
97
10.0k
  auto se = ScopeExit([&pg_working_dir] {
98
    // Restore PG data dir as current directory.
99
10.0k
    ChangeWorkingDir(pg_working_dir);
100
10.0k
  });
101
102
  // Also allow overriding flags on the command line using the appropriate environment variables.
103
10.0k
  std::vector<google::CommandLineFlagInfo> flag_infos;
104
10.0k
  google::GetAllFlags(&flag_infos);
105
3.16M
  for (auto& flag_info : flag_infos) {
106
3.16M
    string env_var_name = "FLAGS_" + flag_info.name;
107
3.16M
    const char* env_var_value = getenv(env_var_name.c_str());
108
3.16M
    if (env_var_value) {
109
267k
      google::SetCommandLineOption(flag_info.name.c_str(), env_var_value);
110
267k
    }
111
3.16M
  }
112
113
10.0k
  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
10.0k
  if (suppress_nonpg_logs) {
121
0
    yb::InitGoogleLoggingSafeBasicSuppressNonNativePostgresLogs(executable_path);
122
10.0k
  } else {
123
10.0k
    yb::InitGoogleLoggingSafeBasic(executable_path);
124
10.0k
  }
125
126
10.0k
  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
10.0k
  return Status::OK();
138
10.0k
}
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
1.47M
  explicit StatusWrapper(YBCStatus s) : status_(s, AddRef::kFalse) {}
152
153
1.47M
  ~StatusWrapper() {
154
1.47M
    status_.DetachStruct();
155
1.47M
  }
156
157
1.42M
  Status* operator->() {
158
1.42M
    return &status_;
159
1.42M
  }
160
161
121k
  Status& operator*() {
162
121k
    return status_;
163
121k
  }
164
165
 private:
166
  Status status_;
167
};
168
169
862k
bool YBCStatusIsOK(YBCStatus s) {
170
862k
  return StatusWrapper(s)->IsOk();
171
862k
}
172
173
4.18k
bool YBCStatusIsNotFound(YBCStatus s) {
174
4.18k
  return StatusWrapper(s)->IsNotFound();
175
4.18k
}
176
177
0
bool YBCStatusIsDuplicateKey(YBCStatus s) {
178
0
  return StatusWrapper(s)->IsAlreadyPresent();
179
0
}
180
181
121k
uint32_t YBCStatusPgsqlError(YBCStatus s) {
182
121k
  StatusWrapper wrapper(s);
183
121k
  const uint8_t* pg_err_ptr = wrapper->ErrorData(PgsqlErrorTag::kCategory);
184
  // If we have PgsqlError explicitly set, we decode it
185
121k
  YBPgErrorCode result = pg_err_ptr != nullptr ? 
PgsqlErrorTag::Decode(pg_err_ptr)50.3k
186
121k
                                               : 
YBPgErrorCode::YB_PG_INTERNAL_ERROR71.6k
;
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
121k
  if (result == YBPgErrorCode::YB_PG_INTERNAL_ERROR) {
191
73.0k
    const uint8_t* txn_err_ptr = wrapper->ErrorData(TransactionErrorTag::kCategory);
192
73.0k
    if (txn_err_ptr != nullptr) {
193
72.5k
      switch (TransactionErrorTag::Decode(txn_err_ptr)) {
194
5.97k
        case TransactionErrorCode::kAborted: FALLTHROUGH_INTENDED;
195
7.35k
        case TransactionErrorCode::kReadRestartRequired: FALLTHROUGH_INTENDED;
196
72.4k
        case TransactionErrorCode::kConflict:
197
72.4k
          result = YBPgErrorCode::YB_PG_T_R_SERIALIZATION_FAILURE;
198
72.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
38
        default:
204
38
          result = YBPgErrorCode::YB_PG_INTERNAL_ERROR;
205
72.5k
      }
206
72.5k
    }
207
73.0k
  }
208
121k
  return static_cast<uint32_t>(result);
209
121k
}
210
211
121k
uint16_t YBCStatusTransactionError(YBCStatus s) {
212
121k
  const TransactionError txn_err(*StatusWrapper(s));
213
121k
  return static_cast<uint16_t>(txn_err.value());
214
121k
}
215
216
121k
void YBCFreeStatus(YBCStatus s) {
217
121k
  FreeYBCStatus(s);
218
121k
}
219
220
121k
size_t YBCStatusMessageLen(YBCStatus s) {
221
121k
  return StatusWrapper(s)->message().size();
222
121k
}
223
224
121k
const char* YBCStatusMessageBegin(YBCStatus s) {
225
121k
  return StatusWrapper(s)->message().cdata();
226
121k
}
227
228
121k
const char* YBCStatusCodeAsCString(YBCStatus s) {
229
121k
  return StatusWrapper(s)->CodeAsCString();
230
121k
}
231
232
121k
char* DupYBStatusMessage(YBCStatus status, bool message_only) {
233
121k
  const char* const code_as_cstring = YBCStatusCodeAsCString(status);
234
121k
  const size_t code_strlen = strlen(code_as_cstring);
235
121k
  const size_t status_len = YBCStatusMessageLen(status);
236
121k
  size_t sz = code_strlen + status_len + 3;
237
121k
  if (message_only) {
238
11.1k
    sz -= 2 + code_strlen;
239
11.1k
  }
240
121k
  char* const msg_buf = reinterpret_cast<char*>(YBCPAlloc(sz));
241
121k
  char* pos = msg_buf;
242
121k
  if (!message_only) {
243
110k
    memcpy(msg_buf, code_as_cstring, code_strlen);
244
110k
    pos += code_strlen;
245
110k
    *pos++ = ':';
246
110k
    *pos++ = ' ';
247
110k
  }
248
121k
  memcpy(pos, YBCStatusMessageBegin(status), status_len);
249
121k
  pos[status_len] = 0;
250
121k
  return msg_buf;
251
121k
}
252
253
196k
bool YBCIsRestartReadError(uint16_t txn_errcode) {
254
196k
  return txn_errcode == static_cast<uint16_t>(TransactionErrorCode::kReadRestartRequired);
255
196k
}
256
257
1.99k
YBCStatus YBCInitGFlags(const char* argv0) {
258
1.99k
  return ToYBCStatus(yb::InitGFlags(argv0));
259
1.99k
}
260
261
198k
bool YBCIsTxnConflictError(uint16_t txn_errcode) {
262
198k
  return txn_errcode == to_underlying(TransactionErrorCode::kConflict);
263
198k
}
264
265
38
bool YBCIsTxnSkipLockingError(uint16_t txn_errcode) {
266
38
  return txn_errcode == to_underlying(TransactionErrorCode::kSkipLocking);
267
38
}
268
269
2.83k
uint16_t YBCGetTxnConflictErrorCode() {
270
2.83k
  return to_underlying(TransactionErrorCode::kConflict);
271
2.83k
}
272
273
YBCStatus YBCInit(const char* argv0,
274
                  YBCPAllocFn palloc_fn,
275
8.08k
                  YBCCStringToTextWithLenFn cstring_to_text_with_len_fn) {
276
8.08k
  YBCSetPAllocFn(palloc_fn);
277
8.09k
  if (
cstring_to_text_with_len_fn8.08k
) {
278
8.09k
    YBCSetCStringToTextWithLenFn(cstring_to_text_with_len_fn);
279
8.09k
  }
280
8.08k
  auto status = yb::InitGFlags(argv0);
281
8.09k
  if (
status.ok()8.08k
&& !FLAGS_TEST_process_info_dir.empty()) {
282
4.89k
    WriteCurrentProcessInfo(FLAGS_TEST_process_info_dir);
283
4.89k
  }
284
8.08k
  return ToYBCStatus(status);
285
8.08k
}
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
5.08k
    ...) {
294
5.08k
  va_list argptr;
295
5.08k
  va_start(argptr, format); \
296
5.08k
  string buf;
297
5.08k
  StringAppendV(&buf, format, argptr);
298
5.08k
  va_end(argptr);
299
5.08k
  google::LogMessage log_msg(file, line, severity);
300
5.08k
  log_msg.stream() << buf;
301
5.08k
  if (with_stack_trace) {
302
0
    log_msg.stream() << "\n" << yb::GetStackTrace();
303
0
  }
304
5.08k
}
305
306
0
const char* YBCFormatBytesAsStr(const char* data, size_t size) {
307
0
  return YBCPAllocStdString(FormatBytesAsStr(data, size));
308
0
}
309
310
6
const char* YBCGetStackTrace() {
311
6
  return YBCPAllocStdString(yb::GetStackTrace());
312
6
}
313
314
1.99k
void YBCResolveHostname() {
315
1.99k
  string fqdn;
316
1.99k
  auto status = GetFQDN(&fqdn);
317
1.99k
  if (!status.ok()) {
318
0
    LOG(WARNING) << "Failed to get fully qualified domain name of the local hostname: "
319
0
                 << status;
320
0
  }
321
1.99k
}
322
323
65
inline double YBCGetNumHashBuckets() {
324
65
  return 64.0;
325
65
}
326
327
/* Gets the number of hash buckets for a DocDB table */
328
130
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
130
  return hash_val >> 10;
335
130
}
336
337
65
double YBCEvalHashValueSelectivity(int32_t hash_low, int32_t hash_high) {
338
65
      hash_high = hash_high <= USHRT_MAX ? 
hash_high52
: USHRT_MAX;
339
65
      hash_high = hash_high >= 0 ? hash_high : 
00
;
340
65
      hash_low = hash_low >= 0 ? 
hash_low15
:
050
;
341
65
      hash_low = hash_low <= USHRT_MAX ? hash_low : USHRT_MAX;
342
343
65
      uint32_t greatest_bucket = YBCGetHashBucketFromValue(hash_high);
344
65
      uint32_t lowest_bucket = YBCGetHashBucketFromValue(hash_low);
345
65
      return hash_high >= hash_low ?
346
65
          ((greatest_bucket - lowest_bucket + 1.0) / YBCGetNumHashBuckets())
347
65
          : 
0.00
;
348
65
}
349
350
1.99k
void YBCInitThreading() {
351
1.99k
  InitThreading();
352
1.99k
}
353
354
} // extern "C"
355
356
} // namespace yb