806 lines
24 KiB
C++
806 lines
24 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.
|
|
*/
|
|
|
|
#include "ob_log_table_matcher.h"
|
|
|
|
#include "share/ob_define.h"
|
|
|
|
#include "ob_log_utils.h" // ob_log_malloc
|
|
|
|
#define _STAT(level, fmt, args...) _OBLOG_LOG(level, "[STAT] [TABLE_MATCHER] " fmt, ##args)
|
|
#define _ISTAT(fmt, args...) _STAT(INFO, fmt, ##args)
|
|
#define _DSTAT(fmt, args...) _STAT(DEBUG, fmt, ##args)
|
|
|
|
namespace oceanbase
|
|
{
|
|
namespace liboblog
|
|
{
|
|
using namespace common;
|
|
|
|
ObLogTableMatcher::ObLogTableMatcher() :
|
|
patterns_(),
|
|
buf_(NULL),
|
|
buf_size_(0),
|
|
black_patterns_(),
|
|
black_buf_(NULL),
|
|
black_buf_size_(0),
|
|
pg_patterns_(),
|
|
pg_buf_(NULL),
|
|
pg_buf_size_(0),
|
|
black_pg_patterns_(),
|
|
black_pg_buf_(NULL),
|
|
black_pg_buf_size_(0)
|
|
{ }
|
|
|
|
ObLogTableMatcher::~ObLogTableMatcher()
|
|
{
|
|
(void)destroy();
|
|
}
|
|
|
|
int ObLogTableMatcher::table_match_pattern_(const bool is_black,
|
|
const char* tenant_name,
|
|
const char* db_name,
|
|
const char* tb_name,
|
|
bool& matched,
|
|
const int fnmatch_flags)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
|
|
if (OB_ISNULL(tenant_name) || OB_ISNULL(db_name) || OB_ISNULL(tb_name)) {
|
|
OBLOG_LOG(ERROR, "invalid arguments", K(tenant_name), K(db_name), K(tb_name));
|
|
ret = OB_INVALID_ARGUMENT;
|
|
} else {
|
|
PatternArray *ptns = is_black ? &black_patterns_ : &patterns_;
|
|
|
|
matched = false;
|
|
|
|
for (int64_t idx = 0, cnt = ptns->count(); OB_SUCCESS == ret && !matched && idx < cnt; ++idx) {
|
|
const Pattern &pattern = ptns->at(idx);
|
|
int err = 0;
|
|
const char *not_match_part = "UNKNOW";
|
|
|
|
// Tenant name.
|
|
if (0 != (err = fnmatch(pattern.tenant_pattern_.ptr(),
|
|
tenant_name,
|
|
fnmatch_flags))) {
|
|
// Not matched.
|
|
not_match_part = "TENANT_PATTERN";
|
|
}
|
|
// Database name.
|
|
else if (0 != (err = fnmatch(pattern.database_pattern_.ptr(),
|
|
db_name,
|
|
fnmatch_flags))) {
|
|
// Not matched.
|
|
not_match_part = "DATABASE_PATTERN";
|
|
}
|
|
// Table name.
|
|
else if (0 != (err = fnmatch(pattern.table_pattern_.ptr(),
|
|
tb_name,
|
|
fnmatch_flags))) {
|
|
// Not matched.
|
|
not_match_part = "TABLE_PATTERN";
|
|
}
|
|
else {
|
|
// Matched.
|
|
matched = true;
|
|
}
|
|
|
|
if (matched) {
|
|
_ISTAT("[%s_PATTERN_MATCHED] PATTERN='%s.%s.%s' TABLE='%s.%s.%s'",
|
|
is_black ? "BLACK" : "WHITE",
|
|
pattern.tenant_pattern_.ptr(), pattern.database_pattern_.ptr(),
|
|
pattern.table_pattern_.ptr(),
|
|
tenant_name, db_name, tb_name);
|
|
} else {
|
|
_ISTAT("[%s_PATTERN_NOT_MATCH] PATTERN='%s.%s.%s' TABLE='%s.%s.%s' NOT_MATCH_PATTERN=%s",
|
|
is_black ? "BLACK" : "WHITE",
|
|
pattern.tenant_pattern_.ptr(), pattern.database_pattern_.ptr(),
|
|
pattern.table_pattern_.ptr(),
|
|
tenant_name, db_name, tb_name,
|
|
not_match_part);
|
|
}
|
|
|
|
// fnmatch() err.
|
|
// OB_SUCCESS == 0.
|
|
if (OB_SUCCESS != err && FNM_NOMATCH != err) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
OBLOG_LOG(ERROR, "err exec fnmatch", KR(ret), K(err));
|
|
}
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int ObLogTableMatcher::tenant_match_pattern_(const bool is_black,
|
|
const char* tenant_name,
|
|
bool& matched,
|
|
const int fnmatch_flags)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
|
|
if (OB_ISNULL(tenant_name)) {
|
|
OBLOG_LOG(ERROR, "invalid arguments", K(tenant_name));
|
|
ret = OB_INVALID_ARGUMENT;
|
|
} else {
|
|
PatternArray *ptns = is_black ? &black_patterns_ : &patterns_;
|
|
|
|
matched = false;
|
|
|
|
for (int64_t idx = 0, cnt = ptns->count(); OB_SUCCESS == ret && !matched && idx < cnt; ++idx) {
|
|
const Pattern &pattern = ptns->at(idx);
|
|
int err = 0;
|
|
|
|
// Tenant name.
|
|
if (0 != (err = fnmatch(pattern.tenant_pattern_.ptr(),
|
|
tenant_name,
|
|
fnmatch_flags))) {
|
|
// Not matched.
|
|
}
|
|
else {
|
|
// Matched.
|
|
matched = true;
|
|
}
|
|
|
|
if (matched) {
|
|
_ISTAT("[%s_PATTERN_MATCHED] PATTERN='%s' TENANT='%s'",
|
|
is_black ? "BLACK" : "WHITE",
|
|
pattern.tenant_pattern_.ptr(), tenant_name);
|
|
} else {
|
|
_ISTAT("[%s_PATTERN_NOT_MATCH] PATTERN='%s' TENANT='%s'",
|
|
is_black ? "BLACK" : "WHITE",
|
|
pattern.tenant_pattern_.ptr(), tenant_name);
|
|
}
|
|
|
|
// fnmatch() err.
|
|
// OB_SUCCESS == 0.
|
|
if (OB_SUCCESS != err && FNM_NOMATCH != err) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
OBLOG_LOG(ERROR, "err exec fnmatch", KR(ret), K(err));
|
|
}
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int ObLogTableMatcher::table_match(const char* tenant_name,
|
|
const char* db_name,
|
|
const char* tb_name,
|
|
bool& matched,
|
|
const int fnmatch_flags)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
bool white_matched = false;
|
|
bool black_matched = false;
|
|
|
|
matched = false;
|
|
|
|
// First filter by whitelist, if whitelist matches, match blacklist
|
|
if (OB_FAIL(table_match_pattern_(false, tenant_name, db_name, tb_name, white_matched, fnmatch_flags))) {
|
|
OBLOG_LOG(ERROR, "match white pattern fail", KR(ret), K(tenant_name), K(db_name), K(tb_name),
|
|
K(white_matched), K(fnmatch_flags));
|
|
} else if (white_matched && OB_FAIL(table_match_pattern_(true, tenant_name, db_name, tb_name,
|
|
black_matched, fnmatch_flags))) {
|
|
OBLOG_LOG(ERROR, "match black pattern fail", KR(ret), K(tenant_name), K(db_name), K(tb_name),
|
|
K(white_matched), K(fnmatch_flags));
|
|
} else {
|
|
matched = (white_matched && ! black_matched);
|
|
|
|
_ISTAT("[%sTABLE_PATTERNS_MATCHED] TABLE='%s.%s.%s' WHITE_PATTERN_COUNT=%ld "
|
|
"BLACK_PATTERN_COUNT=%ld WHITE_MATCHED=%d BLACK_MATCHED=%d",
|
|
matched ? "" : "NO_",
|
|
tenant_name, db_name, tb_name, patterns_.count(), black_patterns_.count(),
|
|
white_matched, black_matched);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int ObLogTableMatcher::tenant_match(const char* tenant_name,
|
|
bool& matched,
|
|
const int fnmatch_flags)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
bool white_matched = false;
|
|
bool black_matched = false;
|
|
|
|
matched = false;
|
|
|
|
// Tenant matching is only considered for whitelisting, as tenants may be duplicated
|
|
if (OB_FAIL(tenant_match_pattern_(false, tenant_name, white_matched, fnmatch_flags))) {
|
|
OBLOG_LOG(ERROR, "match white pattern fail", KR(ret), K(tenant_name), K(white_matched),
|
|
K(fnmatch_flags));
|
|
} else {
|
|
//make blacklists always mismatch
|
|
matched = (white_matched && ! black_matched);
|
|
|
|
_ISTAT("[%sTENANT_PATTERNS_MATCHED] TENANT='%s' WHITE_PATTERN_COUNT=%ld "
|
|
"BLACK_PATTERN_COUNT=%ld WHITE_MATCHED=%d BLACK_MATCHED=%d",
|
|
matched ? "" : "NO_",
|
|
tenant_name, patterns_.count(), black_patterns_.count(),
|
|
white_matched, black_matched);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int ObLogTableMatcher::match(const char* pattern1,
|
|
const ObIArray<ObString>& pattern2,
|
|
bool& matched,
|
|
const int fnmatch_flags)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
matched = false;
|
|
|
|
// Param check.
|
|
if (NULL == pattern1) {
|
|
ret = OB_INVALID_ARGUMENT;
|
|
OBLOG_LOG(ERROR, "invalid args", KR(ret), K(pattern1));
|
|
} else if (pattern2.count() <= 0) {
|
|
matched = false;
|
|
} else {
|
|
// Copy.
|
|
char *pattern_buf = NULL;
|
|
int64_t pattern_buf_size = 0;
|
|
if (OB_SUCC(ret)) {
|
|
int tmp_ret = 0;
|
|
pattern_buf_size = 1 + static_cast<int64_t>(strlen(pattern1));
|
|
if (NULL == (pattern_buf =
|
|
reinterpret_cast<char*>(ob_log_malloc(pattern_buf_size)))) {
|
|
ret = OB_ALLOCATE_MEMORY_FAILED;
|
|
OBLOG_LOG(ERROR, "err alloc pattern buf", KR(ret), K(pattern_buf_size));
|
|
}
|
|
else if (pattern_buf_size <= (tmp_ret =
|
|
snprintf(pattern_buf, pattern_buf_size, "%s", pattern1)) || (tmp_ret < 0)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
OBLOG_LOG(ERROR, "err copy pattern", KR(ret), K(tmp_ret));
|
|
}
|
|
else {
|
|
_OBLOG_LOG(INFO, "[STAT] [PATTERN_MATCH] PATTERN=%s", pattern_buf);
|
|
}
|
|
}
|
|
|
|
// Cut pattern1.
|
|
const char delimiter = '|';
|
|
if (OB_SUCC(ret)) {
|
|
for (int64_t idx = 0, cnt = pattern_buf_size; idx < cnt; ++idx) {
|
|
char &cur = pattern_buf[idx];
|
|
if (delimiter == cur) {
|
|
cur = '\0';
|
|
}
|
|
}
|
|
}
|
|
|
|
// Match.
|
|
int64_t iter = 0;
|
|
while (OB_SUCCESS == ret && iter < pattern_buf_size && !matched) {
|
|
const char *p1 = pattern_buf + iter;
|
|
const char *p2 = NULL;
|
|
for (int64_t idx = 0, cnt = pattern2.count();
|
|
OB_SUCCESS == ret && idx < cnt && !matched;
|
|
++idx) {
|
|
const ObString &pattern2_str = pattern2.at(idx);
|
|
p2 = pattern2_str.ptr();
|
|
// fnmatch.
|
|
int tmp_ret = 0;
|
|
if (0 == (tmp_ret = fnmatch(p1, p2, fnmatch_flags))) {
|
|
matched = true;
|
|
}
|
|
else if (FNM_NOMATCH == tmp_ret) {
|
|
// Not matched.
|
|
}
|
|
else {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
OBLOG_LOG(ERROR, "err exec fnmatch", KR(ret), K(tmp_ret), K(p1), K(p2));
|
|
}
|
|
|
|
_OBLOG_LOG(INFO, "[STAT] [PATTERN_MATCH] MATCH('%s', '%s') => %s",
|
|
p1, p2, matched ? "true" : "false");
|
|
}
|
|
// Move to next pattern.
|
|
if (OB_SUCCESS == ret && !matched) {
|
|
iter += (1 + static_cast<int64_t>(strlen(p1)));
|
|
}
|
|
}
|
|
|
|
// Release mem.
|
|
if (NULL != pattern_buf) {
|
|
ob_log_free(pattern_buf);
|
|
pattern_buf = NULL;
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int ObLogTableMatcher::tablegroup_match(const char *tenant_name,
|
|
const char *tablegroup_name,
|
|
bool &matched,
|
|
const int fnmatch_flags)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
bool white_matched = false;
|
|
bool black_matched = false;
|
|
|
|
matched = false;
|
|
|
|
// First filter by whitelist, if whitelist matches, match blacklist
|
|
if (OB_FAIL(tablegroup_match_pattern_(false, tenant_name, tablegroup_name, white_matched, fnmatch_flags))) {
|
|
OBLOG_LOG(ERROR, "match white pattern fail", KR(ret), K(tenant_name), K(tablegroup_name),
|
|
K(white_matched), K(fnmatch_flags));
|
|
} else if (white_matched && OB_FAIL(tablegroup_match_pattern_(true, tenant_name, tablegroup_name,
|
|
black_matched, fnmatch_flags))) {
|
|
OBLOG_LOG(ERROR, "match black pattern fail", KR(ret), K(tenant_name), K(tablegroup_name),
|
|
K(white_matched), K(fnmatch_flags));
|
|
} else {
|
|
matched = (white_matched && ! black_matched);
|
|
|
|
_ISTAT("[%sPG_PATTERNS_MATCHED] TABLEGROUP='%s.%s' WHITE_PATTERN_COUNT=%ld "
|
|
"BLACK_PATTERN_COUNT=%ld WHITE_MATCHED=%d BLACK_MATCHED=%d",
|
|
matched ? "" : "NO_",
|
|
tenant_name, tablegroup_name, pg_patterns_.count(), black_pg_patterns_.count(),
|
|
white_matched, black_matched);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int ObLogTableMatcher::tablegroup_match_pattern_(const bool is_black,
|
|
const char* tenant_name,
|
|
const char* tablegroup_name,
|
|
bool& matched,
|
|
const int fnmatch_flags)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
|
|
if (OB_ISNULL(tenant_name) || OB_ISNULL(tablegroup_name)) {
|
|
OBLOG_LOG(ERROR, "invalid arguments", K(tenant_name), K(tablegroup_name));
|
|
ret = OB_INVALID_ARGUMENT;
|
|
} else {
|
|
PgPatternArray *ptns = is_black ? &black_pg_patterns_ : &pg_patterns_;
|
|
|
|
matched = false;
|
|
|
|
for (int64_t idx = 0, cnt = ptns->count(); OB_SUCC(ret) && !matched && idx < cnt; ++idx) {
|
|
const PgPattern &pattern = ptns->at(idx);
|
|
int err = 0;
|
|
const char *not_match_part = "UNKNOW";
|
|
|
|
// Tenant name.
|
|
if (0 != (err = fnmatch(pattern.tenant_pattern_.ptr(),
|
|
tenant_name,
|
|
fnmatch_flags))) {
|
|
// Not matched.
|
|
not_match_part = "TENANT_PATTERN";
|
|
}
|
|
// TableGroup name.
|
|
else if (0 != (err = fnmatch(pattern.tablegroup_pattern_.ptr(),
|
|
tablegroup_name,
|
|
fnmatch_flags))) {
|
|
// Not matched.
|
|
not_match_part = "TABLEGROUP_PATTERN";
|
|
}
|
|
else {
|
|
// Matched.
|
|
matched = true;
|
|
}
|
|
|
|
if (matched) {
|
|
_ISTAT("[%s_PG_PATTERN_MATCHED] PATTERN='%s.%s' TABLEGROUP='%s.%s'",
|
|
is_black ? "BLACK" : "WHITE",
|
|
pattern.tenant_pattern_.ptr(), pattern.tablegroup_pattern_.ptr(),
|
|
tenant_name, tablegroup_name);
|
|
} else {
|
|
_ISTAT("[%s_PG_PATTERN_NOT_MATCH] PATTERN='%s.%s' TABLEGROUP='%s.%s' NOT_MATCH_PATTERN=%s",
|
|
is_black ? "BLACK" : "WHITE",
|
|
pattern.tenant_pattern_.ptr(), pattern.tablegroup_pattern_.ptr(),
|
|
tenant_name, tablegroup_name,
|
|
not_match_part);
|
|
}
|
|
|
|
// fnmatch() err.
|
|
// OB_SUCCESS == 0.
|
|
if (OB_SUCCESS != err && FNM_NOMATCH != err) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
OBLOG_LOG(ERROR, "err exec fnmatch", KR(ret), K(err));
|
|
}
|
|
} // for
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int ObLogTableMatcher::cluster_match(bool &matched)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
matched = false;
|
|
const int64_t idx = 0;
|
|
|
|
if (1 != patterns_.count()) {
|
|
matched = false;
|
|
} else {
|
|
const Pattern &pattern = patterns_.at(idx);
|
|
// always ensure that patterns are strings ending in \0, see build_patterns_() for implementation
|
|
// so build the same format, ObString::case_compare will compare the lengths
|
|
char tmp_str[2];
|
|
tmp_str[0] = '*';
|
|
tmp_str[1] = '\0';
|
|
ObString match_all_str(0, 2, tmp_str);
|
|
|
|
if ((0 == pattern.tenant_pattern_.case_compare(match_all_str))
|
|
&& (0 == pattern.database_pattern_.case_compare(match_all_str))
|
|
&& (0 == pattern.table_pattern_.case_compare(match_all_str))
|
|
&& (0 == strcmp(black_buf_, "|"))) {
|
|
OBLOG_LOG(INFO, "[TABLE_MATCHER] cluster_match succ", K(pattern), K(black_buf_));
|
|
matched = true;
|
|
} else {
|
|
OBLOG_LOG(INFO, "[TABLE_MATCHER] cluster_match false", K(pattern), K(black_buf_));
|
|
matched = false;
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int ObLogTableMatcher::init(const char *tb_white_list,
|
|
const char *tb_black_list,
|
|
const char *tg_white_list,
|
|
const char *tg_black_list)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
|
|
if (OB_ISNULL(tb_white_list) || OB_ISNULL(tb_black_list)
|
|
|| OB_ISNULL(tg_white_list) || OB_ISNULL(tg_black_list)) {
|
|
OBLOG_LOG(ERROR, "invalid_argument", K(tb_white_list), K(tb_black_list),
|
|
K(tg_white_list), K(tg_black_list));
|
|
ret = OB_INVALID_ARGUMENT;
|
|
} else if (OB_FAIL(set_pattern_(tb_white_list))) {
|
|
OBLOG_LOG(ERROR, "set table white list pattern fail", KR(ret), K(tb_white_list));
|
|
} else if (OB_FAIL(set_black_pattern_(tb_black_list))) {
|
|
OBLOG_LOG(ERROR, "set table black list pattern fail", KR(ret), K(tb_black_list));
|
|
} else if (OB_FAIL(set_pg_pattern_(tg_white_list))) {
|
|
OBLOG_LOG(ERROR, "set tablegroup white list pattern fail", KR(ret), K(tg_white_list));
|
|
} else if (OB_FAIL(set_black_pg_pattern_(tg_black_list))) {
|
|
OBLOG_LOG(ERROR, "set tablegroup black list pattern fail", KR(ret), K(tg_black_list));
|
|
} else {
|
|
// succ
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int ObLogTableMatcher::destroy()
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
|
|
// Free pattern buffer.
|
|
if (NULL != buf_) {
|
|
ob_log_free(buf_);
|
|
buf_ = NULL;
|
|
}
|
|
|
|
buf_size_ = 0;
|
|
|
|
// Free pattern array.
|
|
patterns_.reset();
|
|
|
|
// Free pattern buffer.
|
|
if (NULL != black_buf_) {
|
|
ob_log_free(black_buf_);
|
|
black_buf_ = NULL;
|
|
}
|
|
|
|
black_buf_size_ = 0;
|
|
|
|
black_patterns_.reset();
|
|
|
|
return ret;
|
|
}
|
|
|
|
int ObLogTableMatcher::set_pattern_(const char* pattern_str)
|
|
{
|
|
bool is_black = false;
|
|
bool is_pg = false;
|
|
|
|
return set_pattern_internal_(pattern_str, is_pg, is_black);
|
|
}
|
|
|
|
int ObLogTableMatcher::set_black_pattern_(const char* black_pattern_str)
|
|
{
|
|
bool is_black = true;
|
|
bool is_pg = false;
|
|
|
|
return set_pattern_internal_(black_pattern_str, is_pg, is_black);
|
|
}
|
|
|
|
int ObLogTableMatcher::set_pg_pattern_(const char* pattern_str)
|
|
{
|
|
bool is_black = false;
|
|
bool is_pg = true;
|
|
|
|
return set_pattern_internal_(pattern_str, is_pg, is_black);
|
|
}
|
|
|
|
int ObLogTableMatcher::set_black_pg_pattern_(const char* black_pattern_str)
|
|
{
|
|
bool is_black = true;
|
|
bool is_pg = true;
|
|
|
|
return set_pattern_internal_(black_pattern_str, is_pg, is_black);
|
|
}
|
|
|
|
int ObLogTableMatcher::set_pattern_internal_(const char* pattern_str,
|
|
const bool is_pg,
|
|
const bool is_black)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
char **buffer = NULL;
|
|
int64_t *buffer_size = NULL;
|
|
|
|
if (! is_pg) {
|
|
buffer = is_black ? &black_buf_ : &buf_;
|
|
buffer_size = is_black ? &black_buf_size_ : &buf_size_;
|
|
} else {
|
|
buffer = is_black ? &black_pg_buf_ : &pg_buf_;
|
|
buffer_size = is_black ? &black_pg_buf_size_ : &pg_buf_size_;
|
|
}
|
|
|
|
if (OB_ISNULL(pattern_str)) {
|
|
ret = OB_INVALID_ARGUMENT;
|
|
OBLOG_LOG(ERROR, "NULL pattern", KR(ret), K(pattern_str));
|
|
}
|
|
// Copy pattern string.
|
|
else {
|
|
int tmp_ret = 0;
|
|
*buffer_size = strlen(pattern_str) + 1;
|
|
// Alloc buffer.
|
|
if (OB_ISNULL(*buffer = reinterpret_cast<char*>(ob_log_malloc(*buffer_size)))) {
|
|
ret = OB_ALLOCATE_MEMORY_FAILED;
|
|
OBLOG_LOG(ERROR, "err alloc pattern string buffer", KR(ret), K(buffer_size));
|
|
}
|
|
// Copy.
|
|
else if (*buffer_size <= (tmp_ret = snprintf(*buffer, *buffer_size, "%s", pattern_str))
|
|
|| (tmp_ret < 0)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
OBLOG_LOG(ERROR, "err snprintf", KR(ret), K(tmp_ret), K(buffer_size), K(pattern_str));
|
|
}
|
|
else {
|
|
OBLOG_LOG(DEBUG, "pattern string", K(pattern_str), K(is_black));
|
|
}
|
|
}
|
|
|
|
if (OB_SUCC(ret)) {
|
|
// Split string.
|
|
if (! is_pg) {
|
|
if (OB_FAIL(build_patterns_(is_black))) {
|
|
OBLOG_LOG(ERROR, "err build patterns", KR(ret), K(is_pg), K(is_black));
|
|
}
|
|
} else {
|
|
if (OB_FAIL(build_pg_patterns_(is_black))) {
|
|
OBLOG_LOG(ERROR, "err build patterns", KR(ret), K(is_pg), K(is_black));
|
|
}
|
|
}
|
|
}
|
|
|
|
// Free buf on error.
|
|
if (OB_SUCCESS != ret && NULL != *buffer) {
|
|
ob_log_free(*buffer);
|
|
*buffer = NULL;
|
|
*buffer_size = 0;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int ObLogTableMatcher::build_patterns_(const bool is_black)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
const char pattern_delimiter = '|';
|
|
const char name_delimiter = '.';
|
|
bool done = false;
|
|
|
|
PatternArray *ptrn_array = is_black ? &black_patterns_ : &patterns_;
|
|
|
|
if ((is_black && OB_ISNULL(black_buf_)) || (! is_black && OB_ISNULL(buf_))) {
|
|
OBLOG_LOG(ERROR, "invalid buffer", K(is_black), K(black_buf_), K(buf_));
|
|
ret = OB_ERR_UNEXPECTED;
|
|
} else {
|
|
char **buffer = is_black ? &black_buf_ : &buf_;
|
|
|
|
ObString remain(strlen(*buffer), *buffer);
|
|
Pattern pattern;
|
|
ObString cur_pattern;
|
|
|
|
// Skip empty blacklist
|
|
if (0 == strcmp(*buffer, "|")) {
|
|
done = true;
|
|
}
|
|
|
|
while (OB_SUCCESS == ret && !done) {
|
|
// Split Pattern & get current pattern.
|
|
cur_pattern = remain.split_on(pattern_delimiter);
|
|
if (cur_pattern.empty()) {
|
|
cur_pattern = remain;
|
|
done = true;
|
|
}
|
|
if (OB_SUCC(ret)) {
|
|
ObString &str = cur_pattern;
|
|
*(str.ptr() + str.length()) = '\0';
|
|
str.set_length(1 + str.length());
|
|
}
|
|
|
|
// Split names.
|
|
pattern.reset();
|
|
// Tenant name.
|
|
if (OB_SUCC(ret)) {
|
|
pattern.tenant_pattern_ = cur_pattern.split_on(name_delimiter);
|
|
if (pattern.tenant_pattern_.empty()) {
|
|
ret = OB_INVALID_ARGUMENT;
|
|
OBLOG_LOG(ERROR, "invalid argment", KR(ret), K(cur_pattern));
|
|
}
|
|
else {
|
|
ObString &str = pattern.tenant_pattern_;
|
|
*(str.ptr() + str.length()) = '\0';
|
|
// Here set_length does not change the length, because the split_on implementation ensures that the buffer_size and length are the same
|
|
// set_length will check the buffer_size. redirect
|
|
str.assign_ptr(str.ptr(), 1 + str.length());
|
|
}
|
|
}
|
|
// Database name.
|
|
if (OB_SUCC(ret)) {
|
|
pattern.database_pattern_ = cur_pattern.split_on(name_delimiter);
|
|
if (pattern.database_pattern_.empty()) {
|
|
ret = OB_INVALID_ARGUMENT;
|
|
OBLOG_LOG(ERROR, "invalid argment", KR(ret), K(cur_pattern));
|
|
}
|
|
else {
|
|
ObString &str = pattern.database_pattern_;
|
|
*(str.ptr() + str.length()) = '\0';
|
|
// Here set_length does not change the length, because the split_on implementation ensures that the buffer_size and length are the same
|
|
// set_length will check the buffer_size. redirect
|
|
str.assign_ptr(str.ptr(), 1 + str.length());
|
|
}
|
|
}
|
|
// Table name.
|
|
if (OB_SUCC(ret)) {
|
|
pattern.table_pattern_= cur_pattern;
|
|
if (pattern.table_pattern_.empty()) {
|
|
ret = OB_INVALID_ARGUMENT;
|
|
OBLOG_LOG(ERROR, "invalid argment", KR(ret), K(cur_pattern));
|
|
}
|
|
else {
|
|
ObString &str = pattern.table_pattern_;
|
|
*(str.ptr() + str.length()) = '\0';
|
|
str.assign_ptr(str.ptr(), 1 + str.length());
|
|
}
|
|
}
|
|
|
|
if (OB_SUCC(ret)) {
|
|
// Save pattern.
|
|
if (OB_SUCCESS != (ret = ptrn_array->push_back(pattern))) {
|
|
OBLOG_LOG(ERROR, "err push back pattern", KR(ret));
|
|
}
|
|
else {
|
|
_ISTAT("[ADD_PATTERN] IS_BLACK=%d TENANT='%s' DATABASE='%s' TABLE='%s'",
|
|
is_black,
|
|
pattern.tenant_pattern_.ptr(),
|
|
pattern.database_pattern_.ptr(),
|
|
pattern.table_pattern_.ptr());
|
|
}
|
|
}
|
|
} // while
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int ObLogTableMatcher::build_pg_patterns_(const bool is_black)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
const char pattern_delimiter = '|';
|
|
const char name_delimiter = '.';
|
|
bool done = false;
|
|
|
|
PgPatternArray *ptrn_array = is_black ? &black_pg_patterns_ : &pg_patterns_;
|
|
|
|
if ((is_black && OB_ISNULL(black_pg_buf_)) || (! is_black && OB_ISNULL(pg_buf_))) {
|
|
OBLOG_LOG(ERROR, "invalid buffer", K(is_black), K(black_pg_buf_), K(pg_buf_));
|
|
ret = OB_ERR_UNEXPECTED;
|
|
} else {
|
|
char **buffer = is_black ? &black_pg_buf_ : &pg_buf_;
|
|
|
|
ObString remain(strlen(*buffer), *buffer);
|
|
PgPattern pattern;
|
|
ObString cur_pattern;
|
|
|
|
// skip empty blacklist
|
|
if (0 == strcmp(*buffer, "|")) {
|
|
done = true;
|
|
}
|
|
|
|
while (OB_SUCCESS == ret && !done) {
|
|
// Split Pattern & get current pattern.
|
|
cur_pattern = remain.split_on(pattern_delimiter);
|
|
if (cur_pattern.empty()) {
|
|
cur_pattern = remain;
|
|
done = true;
|
|
}
|
|
if (OB_SUCC(ret)) {
|
|
ObString &str = cur_pattern;
|
|
*(str.ptr() + str.length()) = '\0';
|
|
str.set_length(1 + str.length());
|
|
}
|
|
|
|
// Split names.
|
|
pattern.reset();
|
|
// Tenant name.
|
|
if (OB_SUCC(ret)) {
|
|
pattern.tenant_pattern_ = cur_pattern.split_on(name_delimiter);
|
|
if (pattern.tenant_pattern_.empty()) {
|
|
ret = OB_INVALID_ARGUMENT;
|
|
OBLOG_LOG(ERROR, "invalid argment", KR(ret), K(cur_pattern));
|
|
}
|
|
else {
|
|
ObString &str = pattern.tenant_pattern_;
|
|
*(str.ptr() + str.length()) = '\0';
|
|
str.set_length(1 + str.length());
|
|
}
|
|
}
|
|
// Tablegroup name.
|
|
if (OB_SUCC(ret)) {
|
|
pattern.tablegroup_pattern_= cur_pattern;
|
|
if (pattern.tablegroup_pattern_.empty()) {
|
|
ret = OB_INVALID_ARGUMENT;
|
|
OBLOG_LOG(ERROR, "invalid argment", KR(ret), K(cur_pattern));
|
|
}
|
|
else {
|
|
ObString &str = pattern.tablegroup_pattern_;
|
|
*(str.ptr() + str.length()) = '\0';
|
|
str.set_length(1 + str.length());
|
|
}
|
|
}
|
|
|
|
if (OB_SUCC(ret)) {
|
|
// Save pattern.
|
|
if (OB_FAIL(ptrn_array->push_back(pattern))) {
|
|
OBLOG_LOG(ERROR, "err push back pattern", KR(ret));
|
|
}
|
|
else {
|
|
_ISTAT("[ADD_PG_PATTERN] IS_BLACK=%d TENANT='%s' TABLEGROUP='%s'",
|
|
is_black,
|
|
pattern.tenant_pattern_.ptr(),
|
|
pattern.tablegroup_pattern_.ptr());
|
|
}
|
|
}
|
|
} // while
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
void ObLogTableMatcher::Pattern::reset()
|
|
{
|
|
tenant_pattern_.reset();
|
|
database_pattern_.reset();
|
|
table_pattern_.reset();
|
|
}
|
|
|
|
void ObLogTableMatcher::PgPattern::reset()
|
|
{
|
|
tenant_pattern_.reset();
|
|
tablegroup_pattern_.reset();
|
|
}
|
|
|
|
} // namespace liboblog
|
|
} // namespace oceanbase
|