/** * Copyright (c) 2021 OceanBase * OceanBase Database Proxy(ODP) 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 "lib/utility/utility.h" #include "lib/ob_define.h" #include "easy_inet.h" #include "common/ob_rowkey.h" #include "lib/time/ob_time_utility.h" #include "lib/file/file_directory_utils.h" #include "common/ob_range2.h" #include "lib/string/ob_sql_string.h" namespace oceanbase { 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) { int64_t pos = 0; int64_t count = 0; for (int64_t i = 0; i < size; i++) { count = snprintf(buf + pos, len - pos, "0x%lx ", array[i]); if (count >= 0 && pos + count + 1 < len) { pos += count; } else { _OB_LOG(WARN, "buf not enough, len=%ld, array_size=%d", len, size); break; } } buf[pos + 1] = 0; return buf; } char *lbt() { static __thread void *addrs[100]; static __thread char buf[LBT_BUFFER_LENGTH]; int size = backtrace(addrs, 100); return parray(buf, sizeof(buf), (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; const char *start = line; const char *p = NULL; char buffer[OB_MAX_ROW_KEY_LENGTH]; if (NULL == line || NULL == array || size <= 0) { ret = OB_INVALID_ARGUMENT; } 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(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(strtol(buffer, NULL, 10)); } } break; } } } if (OB_SUCC(ret)) { size = idx; } } 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) { 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) { 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; } int64_t lower_align(int64_t input, int64_t align) { int64_t ret = input; ret = (input + align - 1) & ~(align - 1); ret = ret - ((ret - input + align - 1) & ~(align - 1)); return ret; }; int64_t upper_align(int64_t input, int64_t align) { int64_t ret = input; ret = (input + align - 1) & ~(align - 1); return ret; }; bool is2n(int64_t input) { return (((~input + 1) & input) == input); }; int64_t next_pow2(const int64_t x) { return x ? (1ULL << (8 * sizeof(int64_t) - __builtin_clzll(x - 1))) : 1; } 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; } const char *get_file_path(const char *file_dir, const char *file_name) { static __thread char file_path[OB_MAX_FILE_NAME_LENGTH]; file_path[0] = '\0'; if (NULL != file_dir) { IGNORE_RETURN snprintf(file_path, sizeof(file_path), "%s/%s", file_dir, file_name); } return file_path; } 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_r(const uint64_t ipport) { static const int64_t BUFFER_SIZE = 32; static __thread char buffers[2][BUFFER_SIZE]; static __thread uint64_t i = 0; char *buffer = buffers[i++ % 2]; 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, BUFFER_SIZE, "%d.%d.%d.%d:%d", bytes[0], bytes[1], bytes[2], bytes[3], port); } else { IGNORE_RETURN snprintf(buffer, BUFFER_SIZE, "%d.%d.%d.%d:-1", bytes[0], bytes[1], bytes[2], bytes[3]); } return buffer; } const char *inet_ntoa_r(const uint32_t ip) { static const int64_t BUFFER_SIZE = 32; static __thread char buffers[2][BUFFER_SIZE]; static __thread uint64_t i = 0; char *buffer = buffers[i++ % 2]; buffer[0] = '\0'; unsigned char *bytes = (unsigned char *) &ip; IGNORE_RETURN snprintf(buffer, BUFFER_SIZE, "%d.%d.%d.%d", bytes[0], bytes[1], bytes[2], bytes[3]); return buffer; } /** * sockaddr_in to string */ char *easy_inet_addr_to_str(easy_addr_t *addr, char *buffer, int len) { unsigned char *b = NULL; int64_t ret_len = 0; if (AF_INET6 == addr->family) { char tmp[INET6_ADDRSTRLEN]; if (NULL != inet_ntop(AF_INET6, addr->u.addr6, tmp, INET6_ADDRSTRLEN)) { if (addr->port) { ret_len = snprintf(buffer, len, "[%s]:%d", tmp, (ntohs)(addr->port)); if (OB_UNLIKELY(ret_len <= 0) || OB_UNLIKELY(ret_len >= len)) { // do nothing } } else { ret_len = snprintf(buffer, len, "%s", tmp); if (OB_UNLIKELY(ret_len <= 0) || OB_UNLIKELY(ret_len >= len)) { // do nothing } } } } else { b = reinterpret_cast(&addr->u.addr); if (addr->port) { ret_len = snprintf(buffer, len, "%d.%d.%d.%d:%d", b[0], b[1], b[2], b[3], (ntohs)(addr->port)); if (OB_UNLIKELY(ret_len <= 0) || OB_UNLIKELY(ret_len >= len)) { // do nothing } } else { ret_len = snprintf(buffer, len, "%d.%d.%d.%d", b[0], b[1], b[2], b[3]); if (OB_UNLIKELY(ret_len <= 0) || OB_UNLIKELY(ret_len >= len)) { // do nothing } } } return buffer; } const char *inet_ntoa_r(easy_addr_t addr) { static const int64_t BUFFER_SIZE = 64; static __thread char buffers[2][BUFFER_SIZE]; static __thread uint64_t i = 0; char *buffer = buffers[i++ % 2]; buffer[0] = '\0'; return oceanbase::common::easy_inet_addr_to_str(&addr, buffer, BUFFER_SIZE); } const char *time2str(const int64_t time_us, const char *format) { 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]; } const char *obj_time2str(const int64_t time_us) { const char *format = DEFAULT_TIME_FORMAT; static const int32_t BUFFER_SIZE = 1024; static __thread char buffer[BUFFER_SIZE]; buffer[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, BUFFER_SIZE, format, &time_struct); if (pos < BUFFER_SIZE) { IGNORE_RETURN snprintf(&buffer[pos], BUFFER_SIZE - pos, ".%06ld", cur_second_time_us); } } return buffer; } void print_rowkey(FILE *fd, ObString &rowkey) { char *pchar = rowkey.ptr(); for (int i = 0; i < rowkey.length(); ++i, pchar++) { if (isprint(*pchar)) { 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 ¤t_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(((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]; 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) { _OB_LOG(WARN, "path %s not exist", path); 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; } 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] = {}; 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(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) { LOG_ERROR("fid file doesn't exist", K(pidfile)); 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(alloc.alloc(n+1)); if (NULL == buf) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("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(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; } int64_t ObTimeGuard::to_string(char *buf, const int64_t buf_len) const { int64_t pos = 0; int64_t i = 0; while ((i + 8) <= click_count_) { databuff_printf(buf, buf_len, pos, "%d,%d,%d,%d,%d,%d,%d,%d,", click_[i], click_[i+1], click_[i+2], click_[i+3], click_[i+4], click_[i+5], click_[i+6], click_[i+7]); i = i + 8; } switch (click_count_ - i) { case 0: { break; } case 1: { databuff_printf(buf, buf_len, pos, "%d,", click_[i]); break; } case 2: { databuff_printf(buf, buf_len, pos, "%d,%d,", click_[i], click_[i+1]); break; } case 3: { databuff_printf(buf, buf_len, pos, "%d,%d,%d,", click_[i], click_[i+1], click_[i+2]); break; } case 4: { databuff_printf(buf, buf_len, pos, "%d,%d,%d,%d,", click_[i], click_[i+1], click_[i+2], click_[i+3]); break; } case 5: { databuff_printf(buf, buf_len, pos, "%d,%d,%d,%d,%d,", click_[i], click_[i+1], click_[i+2], click_[i+3], click_[i+4]); break; } case 6: { databuff_printf(buf, buf_len, pos, "%d,%d,%d,%d,%d,%d,", click_[i], click_[i+1], click_[i+2], click_[i+3], click_[i+4], click_[i+5]); break; } case 7: { databuff_printf(buf, buf_len, pos, "%d,%d,%d,%d,%d,%d,%d,", click_[i], click_[i+1], click_[i+2], click_[i+3], click_[i+4], click_[i+5], click_[i+6]); break; } default: { // do nothing } } databuff_printf(buf, buf_len, pos, "used=%ld owner=%s", common::ObTimeUtility::current_time() - start_ts_, owner_); return pos; } //////////////////////////////////////////////////////////////////// // BandwidthThrottle ObBandwidthThrottle::ObBandwidthThrottle() : start_time_(0), rate_(0), threshold_(0), lamt_(0), buf_len_(0), inited_(false) { } ObBandwidthThrottle::~ObBandwidthThrottle() { } int ObBandwidthThrottle::init(const int64_t rate, const int64_t buflen) { int ret = OB_SUCCESS; if (inited_) { ret = OB_INIT_TWICE; STORAGE_LOG(WARN, "init throttle twice.", K(ret)); } else if (rate <= 0 || buflen <= 0) { ret = OB_INVALID_ARGUMENT; COMMON_LOG(WARN, "invalid arguments.", K(ret), K(rate), K(buflen)); } else { rate_ = rate; buf_len_ = buflen; start_time_ = 0; inited_ = true; } return ret; } void ObBandwidthThrottle::destroy() { inited_ = false; } int ObBandwidthThrottle::start_task() { int ret = OB_SUCCESS; int64_t current_time = ObTimeUtility::current_time(); if (!inited_) { ret = OB_NOT_INIT; STORAGE_LOG(WARN, "throttle is not initialized.", K(ret)); } else { ObSpinLockGuard guard(lock_); if (0 == start_time_) { start_time_ = current_time; } else { int64_t elapse_time = current_time - start_time_; if (0 == elapse_time) elapse_time = 1; // avoid divide 0 error. int64_t current_speed = lamt_ * 1000 * 1000 / elapse_time; if (current_speed < buf_len_ / 4) { // restart stat. start_time_ = current_time; lamt_ = 0; } } } return ret; } int ObBandwidthThrottle::limit(const int64_t bytes, int64_t &sleep_time) { int ret = OB_SUCCESS; int64_t current_time = ObTimeUtility::current_time(); sleep_time = 0; if (!inited_) { ret = OB_NOT_INIT; STORAGE_LOG(WARN, "throttle is not initialized.", K(ret)); } else if (bytes <= 0) { ret = OB_INVALID_ARGUMENT; COMMON_LOG(WARN, "invalid input bytes.", K(ret), K(bytes)); } else { ObSpinLockGuard guard(lock_); lamt_ += bytes; int64_t elapse_time = current_time - start_time_; int64_t max_band_time = lamt_ * 1000 * 1000 / rate_; if (elapse_time < max_band_time) { sleep_time = max_band_time - elapse_time; } } 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 timezone = static_cast(__daylight ? __timezone - 3600 : __timezone); const int32_t tz_minutes = static_cast(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((*unix_sec) % MINUTES_IN_HOUR); int tmp_i = static_cast((*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 &unix_sec, struct tm *result) { if (OB_LIKELY(NULL != result)) { if (cached_unix_sec == unix_sec) { *result = cached_localtime; } else { cached_unix_sec = unix_sec; cached_localtime = *ob_localtime(&unix_sec, result); } } } //////////////////////////////////////////////////////////////////////////////////////////////////// } // end namespace common } // end namespace oceanbase