1918 lines
52 KiB
C++
1918 lines
52 KiB
C++
/**
|
|
* Copyright (c) 2021 OceanBase
|
|
* OceanBase CE is licensed under Mulan PubL v2.
|
|
* You can use this software according to the terms and conditions of the Mulan PubL v2.
|
|
* You may obtain a copy of Mulan PubL v2 at:
|
|
* http://license.coscl.org.cn/MulanPubL-2.0
|
|
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
|
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
|
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
|
* See the Mulan PubL v2 for more details.
|
|
*/
|
|
|
|
#define USING_LOG_PREFIX LIB
|
|
|
|
#include "dirent.h"
|
|
#include "lib/utility/utility.h"
|
|
#include "lib/ob_define.h"
|
|
#include "util/easy_inet.h"
|
|
#include "common/rowkey/ob_rowkey.h"
|
|
#include "lib/time/ob_time_utility.h"
|
|
#include "lib/file/file_directory_utils.h"
|
|
#include "common/ob_range.h"
|
|
#include "lib/string/ob_sql_string.h"
|
|
#include "lib/stat/ob_diagnose_info.h"
|
|
#include "common/object/ob_object.h"
|
|
#include "lib/net/ob_addr.h"
|
|
#include "lib/json/ob_yson.h"
|
|
|
|
namespace oceanbase {
|
|
using namespace lib;
|
|
namespace common {
|
|
extern "C" {
|
|
void do_breakpad_init() __attribute__((weak));
|
|
void do_breakpad_init()
|
|
{}
|
|
}
|
|
char* parray(char* buf, int64_t len, int64_t* array, int size)
|
|
{
|
|
// As used in lbt, and lbt used when print error log.
|
|
// Can not print error log this function.
|
|
if (NULL != buf && len > 0 && NULL != array) {
|
|
int64_t pos = 0;
|
|
int64_t count = 0;
|
|
for (int64_t i = 0; i < size; i++) {
|
|
if (0 == i) {
|
|
count = snprintf(buf + pos, len - pos, "0x%lx", array[i]);
|
|
} else {
|
|
count = snprintf(buf + pos, len - pos, " 0x%lx", array[i]);
|
|
}
|
|
if (count >= 0 && pos + count < len) {
|
|
pos += count;
|
|
} else {
|
|
// buf not enough
|
|
break;
|
|
}
|
|
}
|
|
buf[pos] = 0;
|
|
}
|
|
return buf;
|
|
}
|
|
|
|
static __thread void* addrs[100];
|
|
|
|
char* lbt()
|
|
{
|
|
// As lbt used when print error log, can not print error log
|
|
// in this function and functions called.
|
|
static __thread char buf[LBT_BUFFER_LENGTH];
|
|
int size = backtrace(addrs, ARRAYSIZEOF(addrs));
|
|
return parray(buf, sizeof(buf), (int64_t*)addrs, size);
|
|
}
|
|
|
|
char* lbt(char* buf, int32_t len)
|
|
{
|
|
int size = backtrace(addrs, ARRAYSIZEOF(addrs));
|
|
return parray(buf, len, (int64_t*)addrs, size);
|
|
}
|
|
|
|
void hex_dump(const void* data, const int32_t size, const bool char_type /*= true*/,
|
|
const int32_t log_level /*= OB_LOG_LEVEL_DEBUG*/)
|
|
{
|
|
if (OB_LOGGER.get_log_level() < log_level) {
|
|
return;
|
|
}
|
|
/* dumps size bytes of *data to stdout. Looks like:
|
|
* [0000] 75 6E 6B 6E 6F 77 6E 20
|
|
* 30 FF 00 00 00 00 39 00 unknown 0.....9.
|
|
* (in a single line of course)
|
|
*/
|
|
|
|
unsigned const char* p = (unsigned char*)data;
|
|
unsigned char c = 0;
|
|
int n = 0;
|
|
char bytestr[4] = {0};
|
|
char addrstr[10] = {0};
|
|
char hexstr[16 * 3 + 5] = {0};
|
|
char charstr[16 * 1 + 5] = {0};
|
|
|
|
for (n = 1; n <= size; n++) {
|
|
if (n % 16 == 1) {
|
|
/* store address for this line */
|
|
IGNORE_RETURN snprintf(addrstr, sizeof(addrstr), "%.4x", (int)((unsigned long)p - (unsigned long)data));
|
|
}
|
|
|
|
c = *p;
|
|
if (isprint(c) == 0) {
|
|
c = '.';
|
|
}
|
|
|
|
/* store hex str (for left side) */
|
|
IGNORE_RETURN snprintf(bytestr, sizeof(bytestr), "%02X ", *p);
|
|
strncat(hexstr, bytestr, sizeof(hexstr) - strlen(hexstr) - 1);
|
|
|
|
/* store char str (for right side) */
|
|
IGNORE_RETURN snprintf(bytestr, sizeof(bytestr), "%c", c);
|
|
strncat(charstr, bytestr, sizeof(charstr) - strlen(charstr) - 1);
|
|
|
|
if (n % 16 == 0) {
|
|
/* line completed */
|
|
if (char_type)
|
|
_OB_NUM_LEVEL_LOG(log_level, "[%ld] [%4.4s] %-50.50s %s\n", pthread_self(), addrstr, hexstr, charstr);
|
|
else
|
|
_OB_NUM_LEVEL_LOG(log_level, "[%ld] [%4.4s] %-50.50s\n", pthread_self(), addrstr, hexstr);
|
|
hexstr[0] = 0;
|
|
charstr[0] = 0;
|
|
} else if (n % 8 == 0) {
|
|
/* half line: add whitespaces */
|
|
strncat(hexstr, " ", sizeof(hexstr) - strlen(hexstr) - 1);
|
|
strncat(charstr, " ", sizeof(charstr) - strlen(charstr) - 1);
|
|
}
|
|
p++; /* next byte */
|
|
}
|
|
|
|
if (strlen(hexstr) > 0) {
|
|
/* print rest of buffer if not empty */
|
|
if (char_type)
|
|
_OB_NUM_LEVEL_LOG(log_level, "[%ld] [%4.4s] %-50.50s %s\n", pthread_self(), addrstr, hexstr, charstr);
|
|
else
|
|
_OB_NUM_LEVEL_LOG(log_level, "[%ld] [%4.4s] %-50.50s\n", pthread_self(), addrstr, hexstr);
|
|
}
|
|
}
|
|
int32_t parse_string_to_int_array(const char* line, const char del, int32_t* array, int32_t& size)
|
|
{
|
|
int ret = 0;
|
|
ObArenaAllocator allocator;
|
|
const char* start = line;
|
|
const char* p = NULL;
|
|
char* buffer = NULL;
|
|
|
|
if (NULL == line || NULL == array || size <= 0) {
|
|
ret = OB_INVALID_ARGUMENT;
|
|
}
|
|
|
|
if (NULL == (buffer = static_cast<char*>(allocator.alloc(OB_MAX_ROW_KEY_LENGTH)))) {
|
|
ret = OB_ALLOCATE_MEMORY_FAILED;
|
|
}
|
|
|
|
int32_t idx = 0;
|
|
if (OB_SUCC(ret)) {
|
|
while (OB_SUCC(ret) && NULL != start) {
|
|
p = strchr(start, del);
|
|
if (NULL != p) {
|
|
memset(buffer, 0, OB_MAX_ROW_KEY_LENGTH);
|
|
strncpy(buffer, start, p - start);
|
|
if (strlen(buffer) > 0) {
|
|
if (idx >= size) {
|
|
ret = OB_SIZE_OVERFLOW;
|
|
break;
|
|
} else {
|
|
array[idx++] = static_cast<int32_t>(strtol(buffer, NULL, 10));
|
|
}
|
|
}
|
|
start = p + 1;
|
|
} else {
|
|
if (strlen(start) > OB_MAX_ROW_KEY_LENGTH - 1) {
|
|
ret = OB_SIZE_OVERFLOW;
|
|
break;
|
|
} else {
|
|
memset(buffer, 0, OB_MAX_ROW_KEY_LENGTH);
|
|
strcpy(buffer, start);
|
|
if (strlen(buffer) > 0) {
|
|
if (idx >= size) {
|
|
ret = OB_SIZE_OVERFLOW;
|
|
break;
|
|
} else {
|
|
array[idx++] = static_cast<int32_t>(strtol(buffer, NULL, 10));
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (OB_SUCC(ret)) {
|
|
size = idx;
|
|
}
|
|
}
|
|
|
|
if (NULL != buffer) {
|
|
allocator.free(buffer);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int escape_enter_symbol(char* buffer, const int64_t length, int64_t& pos, const char* src)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
int64_t copy_size = pos;
|
|
int64_t src_len = strlen(src);
|
|
if (pos + src_len >= length || NULL == buffer) {
|
|
ret = OB_BUF_NOT_ENOUGH;
|
|
} else {
|
|
char escape = 0;
|
|
for (int i = 0; OB_SUCC(ret) && i < src_len; ++i) {
|
|
escape = 0;
|
|
switch (src[i]) {
|
|
case '\n':
|
|
escape = 'n';
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
if (escape != 0) {
|
|
if (copy_size >= length - 2) {
|
|
ret = OB_BUF_NOT_ENOUGH;
|
|
break;
|
|
}
|
|
buffer[pos++] = '\\';
|
|
buffer[pos++] = escape;
|
|
copy_size += 2;
|
|
} else {
|
|
if (copy_size >= length - 1) {
|
|
ret = OB_BUF_NOT_ENOUGH;
|
|
break;
|
|
}
|
|
buffer[pos++] = src[i];
|
|
copy_size += 1;
|
|
}
|
|
}
|
|
if (copy_size < length) {
|
|
buffer[pos] = '\0';
|
|
} else {
|
|
ret = OB_BUF_NOT_ENOUGH;
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
/**
|
|
* only escape " and \, used to stringify range2str
|
|
*/
|
|
int escape_range_string(char* buffer, const int64_t length, int64_t& pos, const ObString& in)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
int64_t copy_size = 0;
|
|
if (pos + in.length() >= length || NULL == buffer) {
|
|
ret = OB_BUF_NOT_ENOUGH;
|
|
} else {
|
|
char escape = 0;
|
|
;
|
|
for (int i = 0; OB_SUCC(ret) && i < in.length(); ++i) {
|
|
escape = 0;
|
|
switch (in.ptr()[i]) {
|
|
case '"':
|
|
escape = '"';
|
|
break;
|
|
case '\\':
|
|
escape = '\\';
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
if (escape != 0) {
|
|
if (copy_size >= length - 2) {
|
|
ret = OB_BUF_NOT_ENOUGH;
|
|
break;
|
|
}
|
|
buffer[pos++] = '\\';
|
|
buffer[pos++] = escape;
|
|
copy_size += 2;
|
|
} else {
|
|
if (copy_size >= length - 1) {
|
|
ret = OB_BUF_NOT_ENOUGH;
|
|
break;
|
|
}
|
|
buffer[pos++] = in.ptr()[i];
|
|
copy_size += 1;
|
|
}
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int convert_comment_str(char* comment_str)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
if (comment_str == NULL) {
|
|
ret = OB_INVALID_ARGUMENT;
|
|
} else if (OB_SUCCESS != (ret = replace_str(comment_str, strlen(comment_str), "\\n", "\n"))) {
|
|
_OB_LOG(WARN, "replace \\n to enter failed, src_str=%s, ret=%d", comment_str, ret);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
bool is2n(int64_t input)
|
|
{
|
|
return (((~input + 1) & input) == input);
|
|
};
|
|
|
|
bool all_zero(const char* buffer, const int64_t size)
|
|
{
|
|
bool bret = true;
|
|
const char* buffer_end = buffer + size;
|
|
const char* start = (char*)upper_align((int64_t)buffer, sizeof(int64_t));
|
|
start = std::min(start, buffer_end);
|
|
const char* end = (char*)lower_align((int64_t)(buffer + size), sizeof(int64_t));
|
|
end = std::max(end, buffer);
|
|
|
|
bret = all_zero_small(buffer, start - buffer);
|
|
if (bret) {
|
|
bret = all_zero_small(end, buffer + size - end);
|
|
}
|
|
if (bret) {
|
|
const char* iter = start;
|
|
while (iter < end) {
|
|
if (0 != *((int64_t*)iter)) {
|
|
bret = false;
|
|
break;
|
|
}
|
|
iter += sizeof(int64_t);
|
|
}
|
|
}
|
|
return bret;
|
|
};
|
|
|
|
bool all_zero_small(const char* buffer, const int64_t size)
|
|
{
|
|
bool bret = true;
|
|
if (NULL != buffer) {
|
|
for (int64_t i = 0; i < size; i++) {
|
|
if (0 != *(buffer + i)) {
|
|
bret = false;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return bret;
|
|
}
|
|
|
|
char* str_trim(char* str)
|
|
{
|
|
char *p = str, *sa = str;
|
|
while (*p) {
|
|
if (*p != ' ') {
|
|
*str++ = *p;
|
|
}
|
|
p++;
|
|
}
|
|
*str = 0;
|
|
return sa;
|
|
}
|
|
|
|
char* ltrim(char* str)
|
|
{
|
|
char* p = str;
|
|
while (p != NULL && *p != '\0' && isspace(*p)) {
|
|
++p;
|
|
}
|
|
return p;
|
|
}
|
|
|
|
char* rtrim(char* str)
|
|
{
|
|
if ((str != NULL) && *str != '\0') {
|
|
char* p = str + strlen(str) - 1;
|
|
while ((p > str) && isspace(*p)) {
|
|
--p;
|
|
}
|
|
*(p + 1) = '\0';
|
|
}
|
|
return str;
|
|
}
|
|
const char* inet_ntoa_s(char* buffer, size_t n, const uint64_t ipport)
|
|
{
|
|
buffer[0] = '\0';
|
|
uint32_t ip = (uint32_t)(ipport & 0xffffffff);
|
|
int port = (int)((ipport >> 32) & 0xffff);
|
|
unsigned char* bytes = (unsigned char*)&ip;
|
|
if (port > 0) {
|
|
IGNORE_RETURN snprintf(buffer, n, "%d.%d.%d.%d:%d", bytes[0], bytes[1], bytes[2], bytes[3], port);
|
|
} else {
|
|
IGNORE_RETURN snprintf(buffer, n, "%d.%d.%d.%d:-1", bytes[0], bytes[1], bytes[2], bytes[3]);
|
|
}
|
|
return buffer;
|
|
}
|
|
|
|
const char* inet_ntoa_s(char* buffer, size_t n, const uint32_t ip)
|
|
{
|
|
buffer[0] = '\0';
|
|
unsigned char* bytes = (unsigned char*)&ip;
|
|
IGNORE_RETURN snprintf(buffer, n, "%d.%d.%d.%d", bytes[0], bytes[1], bytes[2], bytes[3]);
|
|
return buffer;
|
|
}
|
|
|
|
const char* time2str(const int64_t time_us, const char* format)
|
|
{
|
|
// FIXME: To Be Removed
|
|
static const int32_t BUFFER_SIZE = 1024;
|
|
static __thread char buffer[10][BUFFER_SIZE];
|
|
static __thread uint64_t i = 0;
|
|
buffer[i % 10][0] = '\0';
|
|
struct tm time_struct;
|
|
int64_t time_s = time_us / 1000000;
|
|
int64_t cur_second_time_us = time_us % 1000000;
|
|
if (NULL != localtime_r(&time_s, &time_struct)) {
|
|
int64_t pos = strftime(buffer[i % 10], BUFFER_SIZE, format, &time_struct);
|
|
if (pos < BUFFER_SIZE) {
|
|
IGNORE_RETURN snprintf(&buffer[i % 10][pos], BUFFER_SIZE - pos, ".%ld %ld", cur_second_time_us, time_us);
|
|
}
|
|
}
|
|
return buffer[i++ % 10];
|
|
}
|
|
|
|
void print_rowkey(FILE* fd, ObString& rowkey)
|
|
{
|
|
char* pchar = rowkey.ptr();
|
|
for (int i = 0; i < rowkey.length(); ++i, pchar++) {
|
|
if (isprint(*pchar) != 0) {
|
|
fprintf(fd, "%c", *pchar);
|
|
} else {
|
|
fprintf(fd, "\\%hhu", *pchar);
|
|
}
|
|
}
|
|
}
|
|
|
|
int mem_chunk_serialize(char* buf, int64_t len, int64_t& pos, const char* data, int64_t data_len)
|
|
{
|
|
int err = OB_SUCCESS;
|
|
int64_t tmp_pos = pos;
|
|
if (NULL == buf || len <= 0 || pos < 0 || pos > len || NULL == data || 0 > data_len) {
|
|
err = OB_INVALID_ARGUMENT;
|
|
} else if (OB_SUCCESS != (err = serialization::encode_i64(buf, len, tmp_pos, data_len))) {
|
|
_OB_LOG(ERROR, "encode_i64(buf=%p, len=%ld, pos=%ld, i=%ld)=>%d", buf, len, tmp_pos, data_len, err);
|
|
} else if (tmp_pos + data_len > len) {
|
|
err = OB_SERIALIZE_ERROR;
|
|
} else {
|
|
MEMCPY(buf + tmp_pos, data, data_len);
|
|
tmp_pos += data_len;
|
|
pos = tmp_pos;
|
|
}
|
|
return err;
|
|
}
|
|
|
|
int mem_chunk_deserialize(const char* buf, int64_t len, int64_t& pos, char* data, int64_t data_len, int64_t& real_len)
|
|
{
|
|
int err = OB_SUCCESS;
|
|
int64_t tmp_pos = pos;
|
|
if (NULL == buf || len <= 0 || pos < 0 || pos > len || NULL == data || data_len < 0) {
|
|
err = OB_INVALID_ARGUMENT;
|
|
} else if (OB_SUCCESS != (err = serialization::decode_i64(buf, len, tmp_pos, &real_len))) {
|
|
_OB_LOG(ERROR, "decode_i64(buf=%p, len=%ld, pos=%ld, i=%ld)=>%d", buf, len, tmp_pos, real_len, err);
|
|
} else if (real_len > data_len || tmp_pos + real_len > len) {
|
|
err = OB_DESERIALIZE_ERROR;
|
|
} else {
|
|
MEMCPY(data, buf + tmp_pos, real_len);
|
|
tmp_pos += real_len;
|
|
pos = tmp_pos;
|
|
}
|
|
return err;
|
|
}
|
|
|
|
int64_t min(const int64_t x, const int64_t y)
|
|
{
|
|
return x > y ? y : x;
|
|
}
|
|
|
|
int64_t max(const int64_t x, const int64_t y)
|
|
{
|
|
return x < y ? y : x;
|
|
}
|
|
|
|
int get_double_expand_size(int64_t& current_size, const int64_t limit_size)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
int64_t new_size = current_size << 1;
|
|
if (current_size > limit_size) {
|
|
ret = OB_SIZE_OVERFLOW;
|
|
} else if (new_size > limit_size) {
|
|
current_size = limit_size;
|
|
} else {
|
|
current_size = new_size;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
uint16_t bswap16(uint16_t a)
|
|
{
|
|
return static_cast<uint16_t>(((a >> 8) & 0xFFU) | ((a << 8) & 0xFF00U));
|
|
}
|
|
|
|
bool str_isprint(const char* str, const int64_t length)
|
|
{
|
|
bool bret = false;
|
|
if (NULL != str && 0 != length) {
|
|
bret = true;
|
|
for (int64_t i = 0; i < length; i++) {
|
|
if (!isprint(str[i])) {
|
|
bret = false;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return bret;
|
|
}
|
|
|
|
int replace_str(char* src_str, const int64_t src_str_buf_size, const char* match_str, const char* replace_str)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
int64_t str_len = 0;
|
|
int64_t match_str_len = 0;
|
|
int64_t replace_str_len = 0;
|
|
const char* find_pos = NULL;
|
|
char new_str[OB_MAX_EXPIRE_INFO_STRING_LENGTH];
|
|
|
|
if (NULL == src_str || src_str_buf_size <= 0 || NULL == match_str || NULL == replace_str) {
|
|
_OB_LOG(WARN,
|
|
"invalid param, src_str=%p, src_str_buf_size=%ld, "
|
|
"match_str=%p, replace_str=%p",
|
|
src_str,
|
|
src_str_buf_size,
|
|
match_str,
|
|
replace_str);
|
|
ret = OB_ERROR;
|
|
} else if (NULL != (find_pos = strstr(src_str, match_str))) {
|
|
match_str_len = strlen(match_str);
|
|
replace_str_len = strlen(replace_str);
|
|
while (OB_SUCC(ret) && NULL != find_pos) {
|
|
str_len = find_pos - src_str + replace_str_len + strlen(find_pos + match_str_len);
|
|
if (str_len >= OB_MAX_EXPIRE_INFO_STRING_LENGTH || str_len >= src_str_buf_size) {
|
|
_OB_LOG(WARN,
|
|
"str after replace is too large, new_size=%ld, "
|
|
"new_buf_size=%ld, src_str_buf_size=%ld",
|
|
str_len,
|
|
OB_MAX_EXPIRE_INFO_STRING_LENGTH,
|
|
src_str_buf_size);
|
|
ret = OB_ERROR;
|
|
break;
|
|
} else {
|
|
memset(new_str, 0, OB_MAX_EXPIRE_INFO_STRING_LENGTH);
|
|
strncpy(new_str, src_str, find_pos - src_str);
|
|
strcat(new_str, replace_str);
|
|
strcat(new_str, find_pos + match_str_len);
|
|
strcpy(src_str, new_str);
|
|
}
|
|
|
|
find_pos = strstr(src_str, match_str);
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int get_ethernet_speed(const char* devname, int64_t& speed)
|
|
{
|
|
int rc = OB_SUCCESS;
|
|
if (NULL == devname) {
|
|
_OB_LOG(WARN, "invalid devname %p", devname);
|
|
rc = OB_INVALID_ARGUMENT;
|
|
} else {
|
|
rc = get_ethernet_speed(ObString::make_string(devname), speed);
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
int get_ethernet_speed(const ObString& devname, int64_t& speed)
|
|
{
|
|
int rc = OB_SUCCESS;
|
|
bool exist = false;
|
|
char path[OB_MAX_FILE_NAME_LENGTH];
|
|
static int dev_file_exist = 1;
|
|
if (0 == devname.length()) {
|
|
_OB_LOG(WARN, "empty devname");
|
|
rc = OB_INVALID_ARGUMENT;
|
|
} else {
|
|
IGNORE_RETURN snprintf(path, sizeof(path), "/sys/class/net/%.*s", devname.length(), devname.ptr());
|
|
if (OB_SUCCESS != (rc = FileDirectoryUtils::is_exists(path, exist)) || !exist) {
|
|
if (dev_file_exist) {
|
|
_OB_LOG(WARN, "path %s not exist", path);
|
|
dev_file_exist = 0;
|
|
}
|
|
rc = OB_FILE_NOT_EXIST;
|
|
}
|
|
}
|
|
if (OB_SUCCESS != rc) {
|
|
} else {
|
|
CharArena alloc;
|
|
ObString str;
|
|
IGNORE_RETURN snprintf(path, sizeof(path), "/sys/class/net/%.*s/bonding/", devname.length(), devname.ptr());
|
|
if (OB_SUCCESS != (rc = FileDirectoryUtils::is_exists(path, exist))) {
|
|
LIB_LOG(WARN, "check net file if exists failed.", K(rc));
|
|
} else if (exist) {
|
|
IGNORE_RETURN snprintf(path, sizeof(path), "/sys/class/net/%.*s/bonding/slaves", devname.length(), devname.ptr());
|
|
if (OB_SUCCESS != (rc = load_file_to_string(path, alloc, str))) {
|
|
_OB_LOG(WARN, "load file %s failed, rc %d", path, rc);
|
|
} else if (0 == str.length()) {
|
|
_OB_LOG(WARN, "can't get slave ethernet");
|
|
rc = OB_ERROR;
|
|
} else {
|
|
int len = 0;
|
|
while (len < str.length() && !isspace(str.ptr()[len])) {
|
|
len++;
|
|
}
|
|
IGNORE_RETURN snprintf(path, sizeof(path), "/sys/class/net/%.*s/speed", len, str.ptr());
|
|
}
|
|
} else {
|
|
IGNORE_RETURN snprintf(path, sizeof(path), "/sys/class/net/%.*s/speed", devname.length(), devname.ptr());
|
|
}
|
|
if (OB_SUCCESS == rc) {
|
|
if (OB_SUCCESS != (rc = load_file_to_string(path, alloc, str))) {
|
|
_OB_LOG(WARN, "load file %s failed, rc %d", path, rc);
|
|
} else {
|
|
speed = atoll(str.ptr());
|
|
speed = speed * 1024 * 1024 / 8;
|
|
}
|
|
}
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
int deep_copy_obj(ObIAllocator& allocator, const ObObj& src, ObObj& dst)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
if (!src.need_deep_copy()) {
|
|
dst = src;
|
|
} else {
|
|
char* buf = NULL;
|
|
int64_t size = src.get_deep_copy_size();
|
|
int64_t pos = 0;
|
|
if (size > 0) {
|
|
if (NULL == (buf = static_cast<char*>(allocator.alloc(size)))) {
|
|
ret = OB_ALLOCATE_MEMORY_FAILED;
|
|
LOG_ERROR("Fail to allocate memory, ", K(size), K(ret));
|
|
} else if (OB_FAIL(dst.deep_copy(src, buf, size, pos))) {
|
|
LOG_WARN("Fail to deep copy obj, ", K(ret));
|
|
} else {
|
|
} // do nothing
|
|
} else {
|
|
dst = src;
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int deep_copy_objparam(ObIAllocator& allocator, const ObObjParam& src, ObObjParam& dst)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
if (!src.need_deep_copy()) {
|
|
dst = src;
|
|
} else if (OB_FAIL(deep_copy_obj(allocator, src, dst))) {
|
|
LOG_WARN("failed to deep copy obj", K(ret));
|
|
} else {
|
|
dst.set_accuracy(src.get_accuracy());
|
|
dst.unset_result_flag(dst.get_result_flag());
|
|
dst.set_result_flag(src.get_result_flag());
|
|
dst.set_param_flag(src.get_param_flag());
|
|
dst.set_param_meta(src.get_param_meta());
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
bool is_case_space_equal(const char* s1, int64_t s1_len, const char* s2, int64_t s2_len)
|
|
{
|
|
int result = true;
|
|
|
|
// Check input
|
|
if (NULL == s1 || NULL == s2 || s1_len < 0 || s2_len < 0) {
|
|
result = false;
|
|
_OB_LOG(ERROR, "Invalid argument, input arguments include NULL pointer or string length is less than zero.");
|
|
} else if (s1 != s2) { // If s1 == s2,return 1
|
|
while (1) {
|
|
// Left trim
|
|
while (s1_len != 0 && isspace(*s1)) {
|
|
--s1_len;
|
|
++s1;
|
|
}
|
|
|
|
while (s2_len != 0 && isspace(*s2)) {
|
|
--s2_len;
|
|
++s2;
|
|
}
|
|
|
|
// To stop while(1).
|
|
if (0 == s1_len && 0 == s2_len) {
|
|
result = true;
|
|
break;
|
|
} else if (0 == s1_len || 0 == s2_len) {
|
|
result = false;
|
|
break;
|
|
}
|
|
|
|
if (false == result) {
|
|
break;
|
|
}
|
|
|
|
// Compare chars bettween s1 and s2
|
|
while (s1_len != 0 && s2_len != 0) {
|
|
if (tolower(*s1) != tolower(*s2)) {
|
|
result = false;
|
|
break;
|
|
}
|
|
|
|
int s1_is_space = 0;
|
|
int s2_is_space = 0;
|
|
|
|
if (--s1_len != 0) {
|
|
s1_is_space = isspace(*(++s1));
|
|
}
|
|
|
|
if (--s2_len != 0) {
|
|
s2_is_space = isspace(*(++s2));
|
|
}
|
|
|
|
if (s1_is_space != s2_is_space) {
|
|
result = false;
|
|
break;
|
|
} else if (s1_is_space && s2_is_space) {
|
|
break;
|
|
}
|
|
} // end of while (s1_len != 0 && s2_len != 0)
|
|
} // end of while(1)
|
|
} // end of else if (s1 != s2)
|
|
|
|
return result;
|
|
}
|
|
|
|
bool is_n_case_space_equal(const char* s1, int64_t s1_len, const char* s2, int64_t s2_len, int64_t cmp_len)
|
|
{
|
|
bool result = true;
|
|
|
|
// Check input
|
|
if (NULL == s1 || NULL == s2 || s1_len < 0 || s2_len < 0) {
|
|
result = false;
|
|
_OB_LOG(ERROR, "Invalid argument, input arguments include NULL pointer or string length is less than zero.");
|
|
} else if (s1 != s2) { // If s1 == s2,return 1
|
|
while (1) {
|
|
// Left trim
|
|
while (s1_len != 0 && isspace(*s1)) {
|
|
--s1_len;
|
|
++s1;
|
|
}
|
|
|
|
while (s2_len != 0 && isspace(*s2)) {
|
|
--s2_len;
|
|
++s2;
|
|
}
|
|
|
|
// To stop while(1).
|
|
if (cmp_len <= 0 || (0 == s1_len && 0 == s2_len)) {
|
|
result = true;
|
|
break;
|
|
} else if (0 == s1_len || 0 == s2_len) {
|
|
result = false;
|
|
break;
|
|
}
|
|
|
|
if (false == result) {
|
|
break;
|
|
}
|
|
|
|
// Compare chars bettween s1 and s2
|
|
while (cmp_len > 0 && s1_len != 0 && s2_len != 0) {
|
|
if (tolower(*s1) != tolower(*s2)) {
|
|
result = false;
|
|
break;
|
|
}
|
|
|
|
--cmp_len;
|
|
|
|
int s1_is_space = 0;
|
|
int s2_is_space = 0;
|
|
|
|
if (--s1_len != 0) {
|
|
s1_is_space = isspace(*(++s1));
|
|
}
|
|
|
|
if (--s2_len != 0) {
|
|
s2_is_space = isspace(*(++s2));
|
|
}
|
|
|
|
if (s1_is_space != s2_is_space) {
|
|
result = false;
|
|
break;
|
|
} else if (s1_is_space && s2_is_space) {
|
|
--cmp_len;
|
|
break;
|
|
}
|
|
} // end of while (cmp_len > 0 && s1_len != 0 && s2_len != 0)
|
|
} // end of while(1)
|
|
} // end of if (s1 != s2)
|
|
|
|
return result;
|
|
}
|
|
|
|
int wild_compare(const char* str, const char* wild_str, const bool str_is_pattern)
|
|
{
|
|
const char wild_many = '%';
|
|
const char wild_one = '_';
|
|
const char wild_prefix = '\\';
|
|
char cmp = 0;
|
|
const int EQUAL = 0;
|
|
const int UNEQUAL = 1;
|
|
const int UNKOWN = -1;
|
|
int ret = UNKOWN;
|
|
if (NULL != str && NULL != wild_str) {
|
|
while (*wild_str) {
|
|
while (*wild_str && *wild_str != wild_many && *wild_str != wild_one) {
|
|
if (*wild_str == wild_prefix && wild_str[1]) {
|
|
wild_str++;
|
|
if (str_is_pattern && *str++ != wild_prefix) {
|
|
ret = UNEQUAL;
|
|
break;
|
|
}
|
|
}
|
|
if (*wild_str++ != *str++) {
|
|
ret = UNEQUAL;
|
|
break;
|
|
}
|
|
}
|
|
if (UNKOWN != ret) {
|
|
break;
|
|
}
|
|
if (!*wild_str) {
|
|
ret = (*str != 0) ? UNEQUAL : EQUAL;
|
|
break;
|
|
}
|
|
if (*wild_str++ == wild_one) {
|
|
if (!*str || (str_is_pattern && *str == wild_many)) {
|
|
ret = UNEQUAL; // One char; skip
|
|
break;
|
|
}
|
|
if (*str++ == wild_prefix && str_is_pattern && *str) {
|
|
str++;
|
|
}
|
|
} else { // Found wild_many
|
|
while (str_is_pattern && *str == wild_many) {
|
|
str++;
|
|
}
|
|
for (; *wild_str == wild_many || *wild_str == wild_one; wild_str++) {
|
|
if (*wild_str == wild_many) {
|
|
while (str_is_pattern && *str == wild_many)
|
|
str++;
|
|
} else {
|
|
if (str_is_pattern && *str == wild_prefix && str[1]) {
|
|
str += 2;
|
|
} else if (!*str++) {
|
|
ret = UNEQUAL;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (!*wild_str) {
|
|
ret = EQUAL; // wild_many as last char: OK
|
|
break;
|
|
}
|
|
if ((cmp = *wild_str) == wild_prefix && wild_str[1] && !str_is_pattern) {
|
|
cmp = wild_str[1];
|
|
}
|
|
for (;; str++) {
|
|
while (*str && *str != cmp) {
|
|
str++;
|
|
}
|
|
if (!*str) {
|
|
ret = UNEQUAL;
|
|
break;
|
|
}
|
|
if (wild_compare(str, wild_str, str_is_pattern) == 0) {
|
|
ret = EQUAL;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (UNKOWN == ret) {
|
|
ret = (*str != 0) ? UNEQUAL : EQUAL;
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int wild_compare(const ObString& str, const ObString& wild_str, const bool str_is_pattern)
|
|
{
|
|
const char wild_many = '%';
|
|
const char wild_one = '_';
|
|
const char wild_prefix = '\\';
|
|
char cmp = 0;
|
|
const int EQUAL = 0;
|
|
const int UNEQUAL = 1;
|
|
const int UNKOWN = -1;
|
|
int ret = UNKOWN;
|
|
const char* str_ptr = str.ptr();
|
|
const char* wild_ptr = wild_str.ptr();
|
|
const ObString::obstr_size_t str_length = str.length();
|
|
const ObString::obstr_size_t wild_length = wild_str.length();
|
|
ObString::obstr_size_t str_pos = 0;
|
|
ObString::obstr_size_t wild_pos = 0;
|
|
#define INC_STR() \
|
|
str_ptr++; \
|
|
str_pos++;
|
|
|
|
#define INC_WILD() \
|
|
wild_ptr++; \
|
|
wild_pos++;
|
|
|
|
if (NULL != str_ptr && NULL != wild_ptr) {
|
|
while (wild_pos < wild_length) {
|
|
// check char without wild_many or wild_one.
|
|
while (wild_pos < wild_length && *wild_ptr != wild_many && *wild_ptr != wild_one) {
|
|
if (*wild_ptr == wild_prefix && (wild_pos + 1 < wild_length)) {
|
|
INC_WILD();
|
|
if (str_is_pattern) {
|
|
if (str_pos == str_length || (str_pos < str_length && *str_ptr != wild_prefix)) {
|
|
ret = UNEQUAL;
|
|
break;
|
|
}
|
|
INC_STR();
|
|
}
|
|
}
|
|
if ((str_pos >= str_length || (str_pos < str_length && wild_pos < wild_length && *wild_ptr != *str_ptr))) {
|
|
ret = UNEQUAL;
|
|
break;
|
|
}
|
|
INC_STR();
|
|
INC_WILD();
|
|
}
|
|
|
|
if (UNKOWN != ret) {
|
|
break;
|
|
}
|
|
if (wild_pos >= wild_length) {
|
|
ret = (str_pos < str_length) ? UNEQUAL : EQUAL;
|
|
break;
|
|
}
|
|
if (wild_pos < wild_length && *wild_ptr == wild_one) {
|
|
INC_WILD();
|
|
if (str_pos >= str_length || (str_is_pattern && (str_pos < str_length && *str_ptr == wild_many))) {
|
|
ret = UNEQUAL; // One char; skip
|
|
break;
|
|
}
|
|
if (str_pos + 1 < str_length && *str_ptr == wild_prefix && str_is_pattern) {
|
|
INC_STR();
|
|
}
|
|
INC_STR();
|
|
} else {
|
|
INC_WILD();
|
|
while (str_is_pattern && str_pos < str_length && *str_ptr == wild_many) {
|
|
INC_STR();
|
|
}
|
|
for (; wild_pos < wild_length && (*wild_ptr == wild_many || *wild_ptr == wild_one); wild_ptr++, wild_pos++) {
|
|
if (*wild_ptr == wild_many) {
|
|
while (str_is_pattern && str_pos < str_length && *str_ptr == wild_many) {
|
|
INC_STR();
|
|
}
|
|
} else {
|
|
if (str_is_pattern && str_pos + 1 < str_length && *str_ptr == wild_prefix) {
|
|
INC_STR();
|
|
} else if (str_pos >= str_length) {
|
|
ret = UNEQUAL;
|
|
break;
|
|
}
|
|
INC_STR();
|
|
}
|
|
}
|
|
if (wild_pos >= wild_length) {
|
|
ret = EQUAL; // wild_many as last char: OK
|
|
break;
|
|
}
|
|
if ((cmp = *wild_ptr) == wild_prefix && wild_pos + 1 < wild_length && !str_is_pattern) {
|
|
cmp = wild_ptr[1];
|
|
}
|
|
for (;; str_pos++, str_ptr++) {
|
|
while (str_pos < str_length && *str_ptr != cmp) {
|
|
INC_STR();
|
|
}
|
|
if (str_pos >= str_length) {
|
|
ret = EQUAL;
|
|
break;
|
|
}
|
|
if (wild_compare(ObString(str_length - str_pos, str_ptr),
|
|
ObString(wild_length - wild_pos, wild_ptr),
|
|
str_is_pattern) == 0) {
|
|
ret = EQUAL;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (UNKOWN == ret) {
|
|
ret = (str_pos < str_length) ? UNEQUAL : EQUAL;
|
|
}
|
|
}
|
|
#undef INC_STR
|
|
#undef INC_WILD
|
|
return ret;
|
|
}
|
|
|
|
uint64_t get_sort(uint count, ...)
|
|
{
|
|
const char wild_many = '%';
|
|
const char wild_one = '_';
|
|
const char wild_prefix = '\\';
|
|
va_list args;
|
|
va_start(args, count);
|
|
ulong sort = 0;
|
|
|
|
// Should not use this function with more than 8 arguments for compare.
|
|
if (count <= 8) {
|
|
while (count--) {
|
|
char* start = NULL;
|
|
char* str = va_arg(args, char*);
|
|
uint chars = 0;
|
|
uint wild_pos = 0; // first wildcard position
|
|
|
|
if ((start = str)) {
|
|
for (; *str; str++) {
|
|
if (*str == wild_prefix && str[1]) {
|
|
str++;
|
|
} else if (*str == wild_many || *str == wild_one) {
|
|
wild_pos = (uint)(str - start) + 1;
|
|
break;
|
|
}
|
|
chars = 128; // Marker that chars existed
|
|
}
|
|
}
|
|
sort = (sort << 8) + (wild_pos ? min(wild_pos, 127) : chars);
|
|
}
|
|
}
|
|
va_end(args);
|
|
return sort;
|
|
}
|
|
|
|
uint64_t get_sort(const ObString& str)
|
|
{
|
|
const char wild_many = '%';
|
|
const char wild_one = '_';
|
|
const char wild_prefix = '\\';
|
|
uint64_t sort = 0;
|
|
if (str.length() > 0) {
|
|
const char* str_ptr = str.ptr();
|
|
ObString::obstr_size_t str_pos = 0;
|
|
const ObString::obstr_size_t str_length = str.length();
|
|
uint32_t specific_chars = 128;
|
|
uint32_t wild_pos = 0; // first wildcard position
|
|
|
|
for (; str_pos < str_length; str_ptr++, str_pos++) {
|
|
if (str_pos + 1 < str_length && *str_ptr == wild_prefix) {
|
|
str_ptr++;
|
|
str_pos++;
|
|
} else if (str_pos < str_length && (*str_ptr == wild_many || *str_ptr == wild_one)) {
|
|
wild_pos = str_pos + 1;
|
|
break;
|
|
}
|
|
}
|
|
sort = wild_pos ? min(wild_pos, 127) : specific_chars;
|
|
}
|
|
return sort;
|
|
}
|
|
|
|
bool prefix_match(const char* prefix, const char* str)
|
|
{
|
|
bool b_ret = false;
|
|
if (NULL == prefix || NULL == str) {
|
|
|
|
} else {
|
|
size_t prefix_len = strlen(prefix);
|
|
size_t str_len = strlen(str);
|
|
if (prefix_len > str_len) {
|
|
|
|
} else if (0 == MEMCMP(prefix, str, prefix_len)) {
|
|
b_ret = true;
|
|
}
|
|
}
|
|
return b_ret;
|
|
}
|
|
|
|
int str_cmp(const void* v1, const void* v2)
|
|
{
|
|
int ret = 0;
|
|
if (NULL == v1) {
|
|
ret = -1;
|
|
} else if (NULL == v2) {
|
|
ret = 1;
|
|
} else {
|
|
ret = strcmp((const char*)v1, (const char*)v2);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
const char* get_default_if()
|
|
{
|
|
static char ifname[128] = {};
|
|
int found = 0;
|
|
FILE* file = NULL;
|
|
file = fopen("/proc/net/route", "r");
|
|
if (file) {
|
|
char dest[16] = {};
|
|
char gw[16] = {};
|
|
char remain[1024 + 1] = {};
|
|
if (1 == fscanf(file, "%1024[^\n]\n", remain)) {
|
|
while (1) {
|
|
int r = fscanf(file, "%127s\t%15s\t%15s\t%1023[^\n]\n", ifname, dest, gw, remain);
|
|
if (r < 4) {
|
|
break;
|
|
}
|
|
if (MEMCMP(gw, "00000000", 8) != 0) {
|
|
found = 1;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
fclose(file);
|
|
}
|
|
if (!found) {
|
|
ifname[0] = '\0';
|
|
}
|
|
return ifname;
|
|
}
|
|
|
|
int sql_append_hex_escape_str(const ObString& str, ObSqlString& sql)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
const int64_t need_len = sql.length() + str.length() * 2 + 3; // X''
|
|
|
|
if (OB_FAIL(sql.reserve(need_len))) {
|
|
LOG_WARN("reserve sql failed, ", K(ret));
|
|
} else if (OB_FAIL(sql.append("X'"))) {
|
|
LOG_WARN("append string failed", K(ret));
|
|
} else {
|
|
for (int64_t i = 0; OB_SUCC(ret) && i < str.length(); ++i) {
|
|
if (OB_FAIL(sql.append_fmt("%02X", static_cast<uint8_t>(str.ptr()[i])))) {
|
|
LOG_WARN("append string failed", K(ret), K(i));
|
|
}
|
|
}
|
|
}
|
|
if (OB_SUCC(ret)) {
|
|
if (OB_FAIL(sql.append("'"))) {
|
|
LOG_WARN("append string failed", K(ret));
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
static int pidfile_test(const char* pidfile)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
int fd = open(pidfile, O_RDONLY);
|
|
|
|
if (fd < 0) {
|
|
ret = OB_FILE_NOT_EXIST;
|
|
} else {
|
|
if (lockf(fd, F_TEST, 0) != 0) {
|
|
ret = OB_ERROR;
|
|
}
|
|
close(fd);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int read_pid(const char* pidfile, long& pid)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
char buf[32] = {};
|
|
int fd = open(pidfile, O_RDONLY);
|
|
|
|
if (fd < 0) {
|
|
LOG_ERROR("can't open pid file", K(pidfile), K(errno));
|
|
ret = OB_FILE_NOT_EXIST;
|
|
} else if (read(fd, buf, sizeof(buf)) <= 0) {
|
|
LOG_ERROR("fail to read pid from file", K(pidfile), K(errno));
|
|
ret = OB_IO_ERROR;
|
|
} else {
|
|
pid = strtol(buf, NULL, 10);
|
|
}
|
|
|
|
if (fd > 0) {
|
|
close(fd);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int use_daemon()
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
const int nochdir = 1;
|
|
const int noclose = 0;
|
|
if (daemon(nochdir, noclose) < 0) {
|
|
LOG_ERROR("create daemon process fail", K(errno));
|
|
ret = OB_ERR_SYS;
|
|
}
|
|
reset_tid_cache();
|
|
// bt("enable_preload_bt") = 1;
|
|
return ret;
|
|
}
|
|
|
|
int start_daemon(const char* pidfile)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
|
|
ret = pidfile_test(pidfile);
|
|
|
|
if (ret != OB_SUCCESS && ret != OB_FILE_NOT_EXIST) {
|
|
LOG_ERROR("pid already exists");
|
|
} else {
|
|
ret = OB_SUCCESS;
|
|
}
|
|
|
|
// start daemon
|
|
if (OB_SUCC(ret) && OB_FAIL(use_daemon())) {
|
|
LOG_ERROR("create daemon process fail", K(ret));
|
|
}
|
|
|
|
if (OB_SUCC(ret)) {
|
|
int fd = open(pidfile, O_RDWR | O_CREAT, 0600);
|
|
|
|
if (fd < 0) { // open pidfile fail
|
|
LOG_ERROR("can't open pid file", K(pidfile), K(fd), K(errno));
|
|
ret = OB_IO_ERROR;
|
|
} else if (lockf(fd, F_TLOCK, 0) < 0) { // other process has locked it
|
|
long pid = 0;
|
|
if (OB_FAIL(read_pid(pidfile, pid))) {
|
|
LOG_ERROR("read pid fail", K(pidfile), K(ret));
|
|
} else {
|
|
LOG_ERROR("process is running", K(pid));
|
|
}
|
|
close(fd);
|
|
} else { // I hold the lock, won't close this fd.
|
|
if (ftruncate(fd, 0) < 0) {
|
|
LOG_ERROR("ftruncate pid file fail", K(pidfile), K(errno));
|
|
ret = OB_IO_ERROR;
|
|
} else {
|
|
char buf[32] = {};
|
|
IGNORE_RETURN snprintf(buf, sizeof(buf), "%d", getpid());
|
|
ssize_t len = strlen(buf);
|
|
ssize_t nwrite = write(fd, buf, len);
|
|
if (len != nwrite) {
|
|
LOG_ERROR("write pid file fail", K(pidfile), K(errno));
|
|
ret = OB_IO_ERROR;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int ob_alloc_printf(ObString& result, ObIAllocator& alloc, const char* fmt, va_list ap)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
va_list ap2;
|
|
va_copy(ap2, ap);
|
|
int64_t n = vsnprintf(NULL, 0, fmt, ap);
|
|
if (n < 0) {
|
|
LOG_ERROR("vsnprintf failed", K(n), K(errno));
|
|
ret = OB_ERR_SYS;
|
|
} else {
|
|
char* buf = static_cast<char*>(alloc.alloc(n + 1));
|
|
if (NULL == buf) {
|
|
ret = OB_ALLOCATE_MEMORY_FAILED;
|
|
LOG_ERROR("no memory");
|
|
} else {
|
|
int64_t n2 = vsnprintf(buf, n + 1, fmt, ap2);
|
|
if (n2 < 0) {
|
|
LOG_ERROR("vsnprintf failed", K(n), K(errno));
|
|
ret = OB_ERR_SYS;
|
|
} else if (n != n2) {
|
|
LOG_ERROR("vsnprintf failed", K(n), K(n2));
|
|
ret = OB_ERR_SYS;
|
|
} else {
|
|
result.assign_ptr(buf, static_cast<int32_t>(n));
|
|
}
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ob_alloc_printf(ObString& result, ObIAllocator& alloc, const char* fmt, ...)
|
|
{
|
|
va_list ap;
|
|
va_start(ap, fmt);
|
|
int ret = ob_alloc_printf(result, alloc, fmt, ap);
|
|
va_end(ap);
|
|
return ret;
|
|
}
|
|
|
|
#define CLICK_STR(i) has_click_str ? click_str_[(i)] : ""
|
|
#define EQUAL_STR has_click_str ? "=" : ""
|
|
#define COMMA_STR has_click_str ? ", " : ","
|
|
#define COMMA_STR_LEN has_click_str ? 2 : 1
|
|
|
|
#define FSTR "%s%s%d%s"
|
|
#define VSTR(i) CLICK_STR(i), EQUAL_STR, click_[i], COMMA_STR
|
|
|
|
int64_t ObTimeGuard::to_string(char* buf, const int64_t buf_len) const
|
|
{
|
|
int64_t pos = 0;
|
|
int64_t i = 0;
|
|
bool has_click_str = (click_count_ > 0 && NULL != click_str_[0]);
|
|
|
|
databuff_printf(buf,
|
|
buf_len,
|
|
pos,
|
|
"time guard '%s' cost too much time, used=%ld%s",
|
|
owner_,
|
|
common::ObTimeUtility::fast_current_time() - start_ts_,
|
|
click_count_ > 0 ? ", time_dist: " : "");
|
|
|
|
while ((i + 8) <= click_count_) {
|
|
databuff_printf(buf,
|
|
buf_len,
|
|
pos,
|
|
FSTR FSTR FSTR FSTR FSTR FSTR FSTR FSTR,
|
|
VSTR(i),
|
|
VSTR(i + 1),
|
|
VSTR(i + 2),
|
|
VSTR(i + 3),
|
|
VSTR(i + 4),
|
|
VSTR(i + 5),
|
|
VSTR(i + 6),
|
|
VSTR(i + 7));
|
|
i = i + 8;
|
|
}
|
|
switch (click_count_ - i) {
|
|
case 0: {
|
|
break;
|
|
}
|
|
case 1: {
|
|
databuff_printf(buf, buf_len, pos, FSTR, VSTR(i));
|
|
break;
|
|
}
|
|
case 2: {
|
|
databuff_printf(buf, buf_len, pos, FSTR FSTR, VSTR(i), VSTR(i + 1));
|
|
break;
|
|
}
|
|
case 3: {
|
|
databuff_printf(buf, buf_len, pos, FSTR FSTR FSTR, VSTR(i), VSTR(i + 1), VSTR(i + 2));
|
|
break;
|
|
}
|
|
case 4: {
|
|
databuff_printf(buf, buf_len, pos, FSTR FSTR FSTR FSTR, VSTR(i), VSTR(i + 1), VSTR(i + 2), VSTR(i + 3));
|
|
break;
|
|
}
|
|
case 5: {
|
|
databuff_printf(
|
|
buf, buf_len, pos, FSTR FSTR FSTR FSTR FSTR, VSTR(i), VSTR(i + 1), VSTR(i + 2), VSTR(i + 3), VSTR(i + 4));
|
|
break;
|
|
}
|
|
case 6: {
|
|
databuff_printf(buf,
|
|
buf_len,
|
|
pos,
|
|
FSTR FSTR FSTR FSTR FSTR FSTR,
|
|
VSTR(i),
|
|
VSTR(i + 1),
|
|
VSTR(i + 2),
|
|
VSTR(i + 3),
|
|
VSTR(i + 4),
|
|
VSTR(i + 5));
|
|
break;
|
|
}
|
|
case 7: {
|
|
databuff_printf(buf,
|
|
buf_len,
|
|
pos,
|
|
FSTR FSTR FSTR FSTR FSTR FSTR FSTR,
|
|
VSTR(i),
|
|
VSTR(i + 1),
|
|
VSTR(i + 2),
|
|
VSTR(i + 3),
|
|
VSTR(i + 4),
|
|
VSTR(i + 5),
|
|
VSTR(i + 6));
|
|
break;
|
|
}
|
|
default: {
|
|
// do nothing
|
|
}
|
|
}
|
|
// Remove the last comma
|
|
if (click_count_ > 0) {
|
|
pos -= COMMA_STR_LEN;
|
|
}
|
|
return pos;
|
|
}
|
|
|
|
DEFINE_TO_YSON_KV(ObTimeGuard, OB_ID(click), common::ObArrayWrap<int32_t>(click_, click_count_));
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// BandwidthThrottle
|
|
ObBandwidthThrottle::ObBandwidthThrottle()
|
|
: lock_(ObLatchIds::BANDWIDTH_THROTTLE_LOCK),
|
|
rate_(0),
|
|
next_avaliable_timestamp_(0),
|
|
unlimit_bytes_(0),
|
|
total_bytes_(0),
|
|
total_sleep_ms_(0),
|
|
last_printed_bytes_(0),
|
|
last_printed_sleep_ms_(0),
|
|
last_printed_ts_(0),
|
|
inited_(false)
|
|
{}
|
|
|
|
ObBandwidthThrottle::~ObBandwidthThrottle()
|
|
{}
|
|
|
|
int ObBandwidthThrottle::init(const int64_t rate, const char* comment)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
if (inited_) {
|
|
ret = OB_INIT_TWICE;
|
|
COMMON_LOG(WARN, "init throttle twice.", K(ret));
|
|
} else if (rate < 0 || OB_ISNULL(comment)) {
|
|
ret = OB_INVALID_ARGUMENT;
|
|
COMMON_LOG(WARN, "invalid arguments.", K(ret), K(rate), KP(comment));
|
|
} else {
|
|
ObSpinLockGuard guard(lock_);
|
|
rate_ = rate;
|
|
next_avaliable_timestamp_ = ObTimeUtility::current_time();
|
|
unlimit_bytes_ = 0;
|
|
last_printed_bytes_ = 0;
|
|
last_printed_ts_ = ObTimeUtility::current_time();
|
|
total_bytes_ = 0;
|
|
databuff_printf(comment_, OB_MAX_TASK_COMMENT_LENGTH, "%s", comment);
|
|
inited_ = true;
|
|
|
|
COMMON_LOG(INFO, "init bandwidth", K(rate_), K(comment_));
|
|
if (0 == rate_) {
|
|
LOG_ERROR("bandwidth throttle rate is zero, please make sure is the config right?");
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObBandwidthThrottle::set_rate(const int64_t rate)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
|
|
if (!inited_) {
|
|
ret = OB_NOT_INIT;
|
|
COMMON_LOG(WARN, "not inited", K(ret));
|
|
} else if (rate < 0) {
|
|
ret = OB_INVALID_ARGUMENT;
|
|
COMMON_LOG(WARN, "invalid args", K(ret), K(rate));
|
|
} else {
|
|
ObSpinLockGuard guard(lock_);
|
|
if (rate_ != rate) {
|
|
COMMON_LOG(INFO, "set bandwidth", "old rate", rate_, "new rate", rate);
|
|
rate_ = rate;
|
|
next_avaliable_timestamp_ = ObTimeUtility::current_time();
|
|
unlimit_bytes_ = 0;
|
|
if (0 == rate_) {
|
|
LOG_ERROR("bandwidth throttle rate is zero, please make sure is the config right?");
|
|
}
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
void ObBandwidthThrottle::destroy()
|
|
{
|
|
ObSpinLockGuard guard(lock_);
|
|
COMMON_LOG(INFO, "destroy bandwidth throttle");
|
|
inited_ = false;
|
|
}
|
|
|
|
int ObBandwidthThrottle::limit_and_sleep(
|
|
const int64_t bytes, const int64_t last_active_time, const int64_t max_idle_time, int64_t& sleep_us)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
const int64_t PRINT_LOG_INTERVAL_MS = 1000; // 1s
|
|
int64_t avaliable_timestamp = 0;
|
|
sleep_us = 0;
|
|
|
|
if (!inited_) {
|
|
ret = OB_NOT_INIT;
|
|
COMMON_LOG(WARN, "throttle is not initialized.", K(ret));
|
|
} else if (OB_FAIL(cal_limit(bytes, avaliable_timestamp))) {
|
|
LOG_WARN("failed to cal limit", K(ret));
|
|
} else if (OB_FAIL(do_sleep(avaliable_timestamp, last_active_time, max_idle_time, sleep_us))) {
|
|
LOG_WARN("failed to do sleep", K(ret));
|
|
} else {
|
|
ObSpinLockGuard guard(lock_);
|
|
const int64_t cur_time = ObTimeUtility::current_time();
|
|
const int64_t print_interval_ms = (cur_time - last_printed_ts_) / 1000;
|
|
|
|
total_bytes_ += bytes;
|
|
total_sleep_ms_ += sleep_us / 1000;
|
|
if (print_interval_ms > PRINT_LOG_INTERVAL_MS) {
|
|
const int64_t copy_KB = (total_bytes_ - last_printed_bytes_) / 1024;
|
|
const int64_t speed_KB_per_s = copy_KB * 1000 / print_interval_ms;
|
|
const int64_t sleep_ms_sum = total_sleep_ms_ - last_printed_sleep_ms_;
|
|
COMMON_LOG(INFO,
|
|
"print band limit",
|
|
K_(comment),
|
|
K(copy_KB),
|
|
K(sleep_ms_sum),
|
|
K(speed_KB_per_s),
|
|
K_(total_sleep_ms),
|
|
K_(total_bytes),
|
|
"rate_KB/s",
|
|
rate_,
|
|
K(print_interval_ms));
|
|
last_printed_bytes_ = total_bytes_;
|
|
last_printed_sleep_ms_ = total_sleep_ms_;
|
|
last_printed_ts_ = cur_time;
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObBandwidthThrottle::cal_limit(const int64_t bytes, int64_t& avaliable_timestamp)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
avaliable_timestamp = 0;
|
|
|
|
ObSpinLockGuard guard(lock_);
|
|
if (!inited_) {
|
|
ret = OB_NOT_INIT;
|
|
COMMON_LOG(WARN, "throttle is not initialized.", K(ret));
|
|
} else if (bytes < 0 || bytes > 1024 * 1024 * 1024LL /* 1G */) {
|
|
ret = OB_INVALID_ARGUMENT;
|
|
COMMON_LOG(WARN, "invalid input bytes.", K(ret), K(bytes));
|
|
} else if (0 == rate_) {
|
|
avaliable_timestamp = INT64_MAX;
|
|
} else {
|
|
int64_t cur_time = ObTimeUtility::current_time();
|
|
unlimit_bytes_ += bytes;
|
|
|
|
if (unlimit_bytes_ > INT64_MAX / 1000 / 1000) {
|
|
COMMON_LOG(ERROR, "unlimit_bytes_ is too large, cannot limit it...", K(bytes), K(rate_), K(unlimit_bytes_));
|
|
next_avaliable_timestamp_ = cur_time;
|
|
unlimit_bytes_ = 0;
|
|
} else if (unlimit_bytes_ * 1000 * 1000 >=
|
|
200 * rate_) { // The minimum calculation unit is 200us, and the fragments smaller than the limit will
|
|
// be calculated next time
|
|
next_avaliable_timestamp_ = next_avaliable_timestamp_ + unlimit_bytes_ * 1000 * 1000 / rate_ + 1;
|
|
unlimit_bytes_ = 0;
|
|
|
|
if (cur_time > next_avaliable_timestamp_ + 200) { // Update the time stamp of the record when it exceeds 200us
|
|
next_avaliable_timestamp_ = cur_time - 200;
|
|
}
|
|
}
|
|
|
|
if (cur_time > next_avaliable_timestamp_) {
|
|
avaliable_timestamp = cur_time;
|
|
} else {
|
|
avaliable_timestamp = next_avaliable_timestamp_;
|
|
}
|
|
|
|
if (avaliable_timestamp - cur_time > UINT32_MAX) {
|
|
COMMON_LOG(ERROR,
|
|
"invalid limit time, maybe callers does not sleep properly after call this func",
|
|
K(ret),
|
|
K(bytes),
|
|
K(avaliable_timestamp),
|
|
K(next_avaliable_timestamp_),
|
|
K(unlimit_bytes_));
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int ObBandwidthThrottle::do_sleep(
|
|
const int64_t next_avaliable_ts, const int64_t last_active_time, const int64_t max_idle_time, int64_t& sleep_us)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
|
|
int64_t cur_time = ObTimeUtility::current_time();
|
|
int64_t max_wait_time =
|
|
cur_time - last_active_time > 0 ? max_idle_time - (cur_time - last_active_time) : max_idle_time;
|
|
int64_t sleep_time = next_avaliable_ts - cur_time;
|
|
int64_t real_sleep_time = std::min(sleep_time, max_wait_time);
|
|
sleep_us = 0;
|
|
|
|
if (real_sleep_time > 0 && real_sleep_time <= UINT32_MAX) {
|
|
COMMON_LOG(DEBUG, "do band limit sleep", K(max_wait_time), K(sleep_time), K(real_sleep_time), K(last_active_time));
|
|
sleep_us = real_sleep_time;
|
|
this_routine::usleep(static_cast<uint32_t>(real_sleep_time));
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
ObInOutBandwidthThrottle::ObInOutBandwidthThrottle() : in_throttle_(), out_throttle_()
|
|
{}
|
|
|
|
ObInOutBandwidthThrottle::~ObInOutBandwidthThrottle()
|
|
{}
|
|
|
|
int ObInOutBandwidthThrottle::init(const int64_t rate)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
|
|
if (OB_FAIL(in_throttle_.init(rate, "in"))) {
|
|
COMMON_LOG(WARN, "failed to init in_throttle_", K(ret));
|
|
} else if (OB_FAIL(out_throttle_.init(rate, "out"))) {
|
|
COMMON_LOG(WARN, "failed to init out_throttle_", K(ret));
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObInOutBandwidthThrottle::set_rate(const int64_t rate)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
|
|
if (OB_FAIL(in_throttle_.set_rate(rate))) {
|
|
COMMON_LOG(WARN, "failed to set in_throttle_ rate", K(ret));
|
|
} else if (OB_FAIL(out_throttle_.set_rate(rate))) {
|
|
COMMON_LOG(WARN, "failed to set out_throttle_", K(ret));
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObInOutBandwidthThrottle::limit_in_and_sleep(
|
|
const int64_t bytes, const int64_t last_active_time, const int64_t max_idle_time)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
int64_t sleep_us = 0;
|
|
|
|
if (OB_FAIL(in_throttle_.limit_and_sleep(bytes, last_active_time, max_idle_time, sleep_us))) {
|
|
COMMON_LOG(WARN, "failed to limit in_throttle_", K(ret));
|
|
}
|
|
|
|
EVENT_ADD(BANDWIDTH_IN_THROTTLE, bytes);
|
|
EVENT_ADD(BANDWIDTH_IN_SLEEP_US, sleep_us);
|
|
return ret;
|
|
}
|
|
|
|
int ObInOutBandwidthThrottle::limit_out_and_sleep(
|
|
const int64_t bytes, const int64_t last_active_time, const int64_t max_idle_time)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
int64_t sleep_us = 0;
|
|
|
|
if (OB_FAIL(out_throttle_.limit_and_sleep(bytes, last_active_time, max_idle_time, sleep_us))) {
|
|
COMMON_LOG(WARN, "failed to limit out_throttle_", K(ret));
|
|
}
|
|
|
|
EVENT_ADD(BANDWIDTH_OUT_THROTTLE, bytes);
|
|
EVENT_ADD(BANDWIDTH_OUT_SLEEP_US, sleep_us);
|
|
return ret;
|
|
}
|
|
|
|
void ObInOutBandwidthThrottle::destroy()
|
|
{
|
|
in_throttle_.destroy();
|
|
out_throttle_.destroy();
|
|
}
|
|
|
|
char* ltoa10(int64_t val, char* dst, const bool is_signed)
|
|
{
|
|
char buffer[65];
|
|
uint64_t uval = (uint64_t)val;
|
|
|
|
if (is_signed) {
|
|
if (val < 0) {
|
|
*dst++ = '-';
|
|
/* Avoid integer overflow in (-val) for LONGLONG_MIN*/
|
|
uval = (uint64_t)0 - uval;
|
|
}
|
|
}
|
|
|
|
char* p = &buffer[sizeof(buffer) - 1];
|
|
*p = '\0';
|
|
int64_t new_val = (int64_t)(uval / 10);
|
|
*--p = (char)('0' + (uval - (uint64_t)new_val * 10));
|
|
val = new_val;
|
|
|
|
while (val != 0) {
|
|
new_val = val / 10;
|
|
*--p = (char)('0' + (val - new_val * 10));
|
|
val = new_val;
|
|
}
|
|
while ((*dst++ = *p++) != 0)
|
|
;
|
|
return dst - 1;
|
|
}
|
|
|
|
int long_to_str10(int64_t val, char* dst, const int64_t buf_len, const bool is_signed, int64_t& length)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
length = 0;
|
|
if (OB_ISNULL(dst) || buf_len < 2) { // at least one char and '\0'
|
|
ret = OB_INVALID_ARGUMENT;
|
|
LOG_WARN("Input invalid", K(dst), K(buf_len), K(ret));
|
|
} else {
|
|
char buffer[65];
|
|
uint64_t uval = (uint64_t)val;
|
|
|
|
if (is_signed) {
|
|
if (val < 0) {
|
|
*dst = '-';
|
|
++length;
|
|
/* Avoid integer overflow in (-val) for LONGLONG_MIN*/
|
|
uval = (uint64_t)0 - uval;
|
|
}
|
|
}
|
|
|
|
char* p = &buffer[sizeof(buffer) - 1];
|
|
*p = '\0';
|
|
int64_t new_val = (int64_t)(uval / 10);
|
|
*--p = (char)('0' + (uval - (uint64_t)new_val * 10));
|
|
val = new_val;
|
|
|
|
while (val != 0) {
|
|
new_val = val / 10;
|
|
*--p = (char)('0' + (val - new_val * 10));
|
|
val = new_val;
|
|
}
|
|
|
|
while (length < buf_len && (*(dst + length++) = *p++) != 0)
|
|
;
|
|
--length;
|
|
if (*(dst + length) != 0) {
|
|
ret = OB_SIZE_OVERFLOW;
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
const char* replica_type_to_str(const ObReplicaType& type)
|
|
{
|
|
const char* str = "";
|
|
|
|
switch (type) {
|
|
case REPLICA_TYPE_FULL:
|
|
str = "REPLICA_TYPE_FULL";
|
|
break;
|
|
case REPLICA_TYPE_BACKUP:
|
|
str = "REPLICA_TYPE_BACKUP";
|
|
break;
|
|
case REPLICA_TYPE_LOGONLY:
|
|
str = "REPLICA_TYPE_LOGONLY";
|
|
break;
|
|
case REPLICA_TYPE_READONLY:
|
|
str = "REPLICA_TYPE_READONLY";
|
|
break;
|
|
case REPLICA_TYPE_MEMONLY:
|
|
str = "REPLICA_TYPE_MEMONLY";
|
|
break;
|
|
default:
|
|
str = "REPLICA_TYPE_UNKNOWN";
|
|
}
|
|
return str;
|
|
}
|
|
|
|
void get_addr_by_proxy_sessid(const uint64_t session_id, ObAddr& addr)
|
|
{
|
|
const int32_t ip = static_cast<int32_t>((session_id >> 32) & 0xFFFFFFFF);
|
|
const int32_t port = static_cast<int32_t>((session_id >> 16) & 0xFFFF);
|
|
IGNORE_RETURN addr.set_ipv4_addr(ip, port);
|
|
}
|
|
|
|
int ob_strtoll(const char* str, char*& endptr, int64_t& res)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
res = 0;
|
|
if (OB_ISNULL(str)) {
|
|
ret = OB_INVALID_ARGUMENT;
|
|
} else {
|
|
res = strtoll(str, &endptr, 10);
|
|
if (INT64_MAX == res) {
|
|
ret = OB_SIZE_OVERFLOW;
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ob_strtoull(const char* str, char*& endptr, uint64_t& res)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
res = 0;
|
|
int64_t tmp_res = 0;
|
|
if (OB_ISNULL(str)) {
|
|
ret = OB_INVALID_ARGUMENT;
|
|
} else {
|
|
tmp_res = strtoull(str, &endptr, 10);
|
|
if (UINT64_MAX == tmp_res) {
|
|
ret = OB_SIZE_OVERFLOW;
|
|
} else {
|
|
res = tmp_res;
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ob_atoll(const char* str, int64_t& res)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
char* endptr = NULL;
|
|
int64_t val = 0;
|
|
if (OB_ISNULL(str)) {
|
|
ret = OB_INVALID_ARGUMENT;
|
|
} else if (OB_FAIL(ob_strtoll(str, endptr, val))) {
|
|
LIB_LOG(WARN, "failed to strtoll", K(ret), K(str));
|
|
} else if (str == endptr || OB_ISNULL(endptr) || OB_UNLIKELY('\0' != *endptr)) {
|
|
ret = OB_INVALID_ARGUMENT;
|
|
} else {
|
|
res = val;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
// ref: https://www.cnblogs.com/westfly/p/5139645.html
|
|
struct tm* ob_localtime(const time_t* unix_sec, struct tm* result)
|
|
{
|
|
static const int HOURS_IN_DAY = 24;
|
|
static const int MINUTES_IN_HOUR = 60;
|
|
static const int DAYS_FROM_UNIX_TIME = 2472632;
|
|
static const int DAYS_FROM_YEAR = 153;
|
|
static const int MAGIC_UNKONWN_FIRST = 146097;
|
|
static const int MAGIC_UNKONWN_SEC = 1461;
|
|
// use __timezone from glibc/time/tzset.c, default value is -480 for china
|
|
const int32_t tz_minutes = static_cast<int32_t>(__timezone / 60);
|
|
|
|
// only support time > 1970/1/1 8:0:0
|
|
if (OB_LIKELY(NULL != result) && OB_LIKELY(NULL != unix_sec) && OB_LIKELY(*unix_sec > 0)) {
|
|
result->tm_sec = static_cast<int>((*unix_sec) % MINUTES_IN_HOUR);
|
|
int tmp_i = static_cast<int>((*unix_sec) / MINUTES_IN_HOUR) - tz_minutes;
|
|
result->tm_min = tmp_i % MINUTES_IN_HOUR;
|
|
tmp_i /= MINUTES_IN_HOUR;
|
|
result->tm_hour = tmp_i % HOURS_IN_DAY;
|
|
result->tm_mday = tmp_i / HOURS_IN_DAY;
|
|
int tmp_a = result->tm_mday + DAYS_FROM_UNIX_TIME;
|
|
int tmp_b = (tmp_a * 4 + 3) / MAGIC_UNKONWN_FIRST;
|
|
int tmp_c = tmp_a - (tmp_b * MAGIC_UNKONWN_FIRST) / 4;
|
|
int tmp_d = ((tmp_c * 4 + 3) / MAGIC_UNKONWN_SEC);
|
|
int tmp_e = tmp_c - (tmp_d * MAGIC_UNKONWN_SEC) / 4;
|
|
int tmp_m = (5 * tmp_e + 2) / DAYS_FROM_YEAR;
|
|
result->tm_mday = tmp_e + 1 - (DAYS_FROM_YEAR * tmp_m + 2) / 5;
|
|
result->tm_mon = tmp_m + 2 - (tmp_m / 10) * 12;
|
|
result->tm_year = tmp_b * 100 + tmp_d - 6700 + (tmp_m / 10);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
void ob_fast_localtime(
|
|
time_t& cached_unix_sec, struct tm& cached_localtime, const time_t& input_unix_sec, struct tm* output_localtime)
|
|
{
|
|
if (OB_LIKELY(NULL != output_localtime)) {
|
|
if (cached_unix_sec == input_unix_sec) {
|
|
*output_localtime = cached_localtime;
|
|
} else if (OB_UNLIKELY(0 == cached_unix_sec)) { // init
|
|
cached_unix_sec = input_unix_sec;
|
|
localtime_r(&input_unix_sec, output_localtime);
|
|
cached_localtime = *output_localtime;
|
|
;
|
|
} else {
|
|
cached_unix_sec = input_unix_sec;
|
|
cached_localtime = *ob_localtime(&input_unix_sec, output_localtime);
|
|
}
|
|
}
|
|
}
|
|
|
|
int is_dir_empty(const char* dirname, bool& is_empty)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
if (NULL == dirname) {
|
|
ret = OB_INVALID_ARGUMENT;
|
|
} else {
|
|
is_empty = true;
|
|
DIR* dir = opendir(dirname);
|
|
if (NULL == dir) {
|
|
if (ENOENT == errno) {
|
|
is_empty = true;
|
|
} else {
|
|
ret = OB_IO_ERROR;
|
|
LIB_LOG(ERROR, "opendir failed", K(ret), K(errno), KP(dirname));
|
|
}
|
|
} else {
|
|
while (OB_SUCC(ret)) {
|
|
struct dirent entry;
|
|
struct dirent* pentry = &entry;
|
|
memset(&entry, 0, sizeof(struct dirent));
|
|
if (0 != readdir_r(dir, pentry, &pentry)) {
|
|
ret = OB_IO_ERROR;
|
|
LIB_LOG(WARN, "readdir_r failed", K(ret), K(errno), KP(dirname));
|
|
} else if (NULL == pentry) {
|
|
ret = OB_ITER_END;
|
|
} else if (strcmp(".", pentry->d_name) == 0 || strcmp("..", pentry->d_name) == 0) {
|
|
continue;
|
|
} else {
|
|
is_empty = false;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (OB_ITER_END == ret) {
|
|
ret = OB_SUCCESS;
|
|
}
|
|
|
|
if (0 != closedir(dir)) {
|
|
ret = OB_IO_ERROR;
|
|
LIB_LOG(ERROR, "closedir failed", K(ret), K(errno), KP(dirname));
|
|
} else {
|
|
dir = NULL;
|
|
}
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
} // end namespace common
|
|
} // end namespace oceanbase
|