/** * 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 "share/config/ob_system_config.h" #include "share/config/ob_config.h" #include "share/config/ob_server_config.h" #include "share/ob_task_define.h" namespace oceanbase { namespace common { #define GET_CONFIG_COLUMN_VALUE(type, name, cmd)\ if (OB_SUCC(ret)) {\ if (OB_SUCC(rs->get_##type(#name, val_##type))) {\ cmd;\ } else if (OB_ERR_NULL_VALUE == ret) {\ SHARE_LOG(DEBUG, "row " #name " :value is null");\ ret = OB_SUCCESS;\ } else {\ SHARE_LOG(WARN, "failed to get " #name " from __all_sys_parameter", K(ret));\ }\ } int ObSystemConfig::update(ObMySQLProxy::MySQLResult &result) { int ret = OB_SUCCESS; if (OB_ISNULL(result.get_result())) { ret = OB_ERR_UNEXPECTED; SHARE_LOG(WARN, "system config result is null", K(ret)); } while (OB_SUCC(ret) && OB_SUCC(result.get_result()->next())) { ObSystemConfigKey key; SMART_VAR(ObSystemConfigValue, value) { ObString val_varchar; int64_t val_int = 0; common::sqlclient::ObMySQLResult *rs = result.get_result(); if (OB_ISNULL(rs)) { ret = OB_ERR_UNEXPECTED; SHARE_LOG(WARN, "system config result is null", K(ret)); } GET_CONFIG_COLUMN_VALUE(varchar, name, key.set_name(val_varchar)); GET_CONFIG_COLUMN_VALUE(varchar, svr_type, key.set_server_type(val_varchar)); GET_CONFIG_COLUMN_VALUE(varchar, svr_ip, key.set_server_ip(val_varchar)); GET_CONFIG_COLUMN_VALUE(varchar, value, value.set_value(val_varchar)); GET_CONFIG_COLUMN_VALUE(varchar, info, value.set_info(val_varchar)); GET_CONFIG_COLUMN_VALUE(varchar, section, value.set_section(val_varchar)); GET_CONFIG_COLUMN_VALUE(varchar, scope, value.set_scope(val_varchar)); GET_CONFIG_COLUMN_VALUE(varchar, source, value.set_source(val_varchar)); GET_CONFIG_COLUMN_VALUE(varchar, edit_level, value.set_edit_level(val_varchar)); if (OB_SUCC(ret)) { if (OB_FAIL(rs->get_varchar("zone", val_varchar))) { if (OB_ERR_NULL_VALUE == ret) { ret = OB_SUCCESS; } else { SHARE_LOG(WARN, "failed to get zone from __all_sys_parameter", K(ret)); } } else if (OB_FAIL(key.set_zone(val_varchar))) { SHARE_LOG(WARN, "set zone failed", K(ret), K(val_varchar)); } } GET_CONFIG_COLUMN_VALUE(int, svr_port, key.set_int(ObString::make_string("svr_port"), val_int)); if (OB_SUCC(ret)) { if (OB_SUCC(rs->get_int("config_version", val_int))) { key.set_version(val_int); version_ = max(version_, val_int); } else { SHARE_LOG(WARN, "failed to get config_version from __all_sys_parameter", K(ret)); } } if (OB_SUCC(ret)) { ret = update_value(key, value); } } } if (OB_ITER_END == ret) { ret = OB_SUCCESS; } else { SHARE_LOG(WARN, "failed to get result from result set", K(ret)); } return ret; } int ObSystemConfig::find_newest(const ObSystemConfigKey &key, const ObSystemConfigValue *&pvalue, int64_t &max_version) const { int ret = OB_SEARCH_NOT_FOUND; hashmap::const_iterator it = map_.begin(); hashmap::const_iterator last = map_.end(); max_version = key.get_version(); pvalue = NULL; for (; it != last; ++it) { if (it->first.match(key) && it->first.get_version() > max_version) { max_version = it->first.get_version(); pvalue = it->second; // for循环旨在找到最新版本,需要迭代完,不需要OB_SUCC(ret) ret = OB_SUCCESS; } } return ret; } int ObSystemConfig::find(const ObSystemConfigKey &key, const ObSystemConfigValue *&pvalue) const { int ret = OB_SUCCESS; hashmap::const_iterator it = map_.begin(); hashmap::const_iterator last = map_.end(); pvalue = NULL; if (OB_ISNULL(pvalue)) { // check if ip and port both matched for (it = map_.begin(); it != last; ++it) { if (it->first.match_ip_port(key)) { pvalue = it->second; break; } } } if (OB_ISNULL(pvalue)) { /* check if server type matched */ for (it = map_.begin(); it != last; ++it) { if (it->first.match_server_type(key)) { pvalue = it->second; break; } } } if (OB_ISNULL(pvalue)) { /* check if zone matched */ for (it = map_.begin(); it != last; ++it) { if (it->first.match_zone(key)) { pvalue = it->second; break; } } } if (OB_ISNULL(pvalue)) { /* check if matched */ for (it = map_.begin(); it != last; ++it) { if (it->first.match(key)) { pvalue = it->second; break; } } } if (OB_ISNULL(pvalue)) { ret = OB_NO_RESULT; } return ret; } int ObSystemConfig::update_value(const ObSystemConfigKey &key, const ObSystemConfigValue &value) { int ret = OB_SUCCESS; int hash_ret = OB_SUCCESS; ObSystemConfigValue *sys_value = nullptr; hash_ret = map_.get_refactored(key, sys_value); if (OB_SUCCESS != hash_ret) { if (OB_HASH_NOT_EXIST == hash_ret) { void *ptr = allocator_.alloc(sizeof(ObSystemConfigValue)); if (OB_ISNULL(ptr)) { ret = OB_ALLOCATE_MEMORY_FAILED; SHARE_LOG(WARN, "alloc memory failed"); } else { sys_value = new (ptr) ObSystemConfigValue(); sys_value->set_value(value.value()); hash_ret = map_.set_refactored(key, sys_value); if (OB_SUCCESS != hash_ret) { if (OB_HASH_EXIST == hash_ret) { SHARE_LOG(WARN, "sys config insert repeatly", "name", key.name(), K(hash_ret)); } else { ret = hash_ret; SHARE_LOG(WARN, "sys config map set failed", "name", key.name(), K(ret)); } } } } else { ret = hash_ret; SHARE_LOG(WARN, "sys config map get failed", "name", key.name(), K(ret)); } } else { sys_value->set_value(value.value()); } return ret; } int ObSystemConfig::reload(FILE *fp) { int ret = OB_SUCCESS; size_t cnt = 0; if (OB_ISNULL(fp)) { ret = OB_ERR_UNEXPECTED; SHARE_LOG(ERROR, "Got NULL file pointer", K(ret)); } else { ObSystemConfigKey key; SMART_VAR(ObSystemConfigValue, value) { while (1) { // 设计上单个config reload失败不影响下一个,故未判断OB_SUCC(ret) if (1 != (cnt = fread(&key, sizeof(key), 1, fp))) { if (0 == cnt) { break; } else { ret = OB_ERR_UNEXPECTED; SHARE_LOG(WARN, "fail to read config from file", KERRMSG, K(ret)); } } else if (1 != (cnt = fread(&value, sizeof(value), 1, fp))) { ret = OB_ERR_UNEXPECTED; SHARE_LOG(WARN, "fail to read config from file", KERRMSG, K(ret)); } else { ret = update_value(key, value); } } } } return ret; } int ObSystemConfig::read_int32(const ObSystemConfigKey &key, int32_t &value, const int32_t &def) const { int ret = OB_SUCCESS; const ObSystemConfigValue *pvalue = NULL; int64_t version = 0; char *p = NULL; if (OB_SUCC(find_newest(key, pvalue, version)) && OB_LIKELY(NULL != pvalue)) { value = static_cast(strtol(pvalue->value(), &p, 0)); if (p == pvalue->value()) { SHARE_LOG(ERROR, "config is not integer", "name", key.name(), "value", p); } else if (OB_ISNULL(p) || OB_UNLIKELY('\0' != *p)) { SHARE_LOG(WARN, "config was truncated", "name", key.name(), "value", p); } else { SHARE_LOG(INFO, "use internal config", "name", key.name(), K(value)); } } else { value = def; SHARE_LOG(INFO, "use default config", "name", key.name(), K(value), K(pvalue), K(ret)); ret = OB_SUCCESS; } return ret; } int ObSystemConfig::read_int64(const ObSystemConfigKey &key, int64_t &value, const int64_t &def) const { int ret = OB_SUCCESS; const ObSystemConfigValue *pvalue = NULL; int64_t version = 0; char *p = NULL; if (OB_SUCC(find_newest(key, pvalue, version)) && OB_LIKELY(NULL != pvalue)) { value = strtoll(pvalue->value(), &p, 0); if (p == pvalue->value()) { SHARE_LOG(ERROR, "config is not integer", "name", key.name(), "value", p); } else if (OB_ISNULL(p) || OB_UNLIKELY('\0' != *p)) { SHARE_LOG(WARN, "config was truncated", "name", key.name(), "value", p); } else { SHARE_LOG(INFO, "use internal config", "name", key.name(), K(value)); } } else { value = def; SHARE_LOG(INFO, "use default config", "name", key.name(), K(value), K(pvalue), K(ret)); ret = OB_SUCCESS; } return ret; } int ObSystemConfig::read_str(const ObSystemConfigKey &key, char buf[], int64_t len, const char *def) const { int ret = OB_SUCCESS; const ObSystemConfigValue *pvalue = NULL; int64_t version = 0; if (OB_SUCC(find_newest(key, pvalue, version)) && OB_LIKELY(NULL != pvalue)) { int wlen = 0; if ((wlen = snprintf(buf, len, "%s", pvalue->value())) < 0) { SHARE_LOG(ERROR, "reload config error", "name", key.name()); } else if (wlen >= len) { SHARE_LOG(WARN, "config was truncated", "name", key.name()); } else { SHARE_LOG(INFO, "use internal config", "name", key.name(), K(buf)); } /* for safe */ buf[len - 1] = '\0'; } else { if (buf != def) { int64_t pos = 0; if(OB_FAIL(databuff_printf(buf, len, pos, "%s", def))) { SHARE_LOG(WARN, "buf is not long enough", K(key.name()), K(def), K(pvalue), K(ret)); } } SHARE_LOG(INFO, "use default config", "name", key.name(), K(def), K(pvalue), K(ret)); ret = OB_SUCCESS; // by design } return ret; } // tenant_id is OB_INVALID_TENANT_ID(0) means it's cluster parameter int ObSystemConfig::read_config( const uint64_t tenant_id, const ObSystemConfigKey &key, ObConfigItem &item) const { int ret = OB_SUCCESS; const ObSystemConfigValue *pvalue = NULL; int64_t version = 0; // key 中带上了当前 item 的版本号,如果记录的所有 // newest 值的版本都不比 key 中的版本大,那么 find_newest // 直接返回 OB_SEARCH_NOT_FOUND,外部选择忽略该错误或做对应处理 // // version 机制的用途之一是避免重复将 pvalue 写到 item 中, // 如果 version 没变,并不需要重复更新 item。 if (OB_SUCC(find_newest(key, pvalue, version))) { if (OB_ISNULL(pvalue)) { ret = OB_ERR_UNEXPECTED; } else { if (item.reboot_effective()) { // 每次都要将最新值更新到 reboot_value 中,用于写入 spfile if (!item.set_reboot_value(pvalue->value())) { ret = OB_ERR_UNEXPECTED; SHARE_LOG(WARN, "set config item reboot value failed", K(ret), K(key.name()), K(pvalue->value()), K(version)); } else { item.set_value_updated(); item.set_version(version); } } const ObString compatible_cfg(COMPATIBLE); if (compatible_cfg.case_compare(key.name()) == 0) { if (!item.set_dump_value(pvalue->value())) { ret = OB_ERR_UNEXPECTED; SHARE_LOG(WARN, "set config item dump value failed", K(ret), K(key.name()), K(pvalue->value()), K(version)); } else { item.set_dump_value_updated(); item.set_version(version); share::ObTaskController::get().allow_next_syslog(); SHARE_LOG(INFO, "[COMPATIBLE] read data_version", KR(ret), K(tenant_id), "version", item.version(), "value", item.str(), "value_updated", item.value_updated(), "dump_version", item.dumped_version(), "dump_value", item.spfile_str(), "dump_value_updated", item.dump_value_updated()); } } else if (item.reboot_effective()) { // 以 STATIC_EFFECTIVE 的 stack_size 举例说明: // > show parameters like 'stack_size' // stack_size = 4M // > alter system set stack_size = '5M' // > show parameters like 'stack_size' // stack_size = 4M // > obs0.restart // > show parameters like 'stack_size' // stack_size = 5M // // 为了实现上述行为, // stack_size 只会在 restart 后首次时调用 set_value 时将 value 保存到 item 中, // 之后无论 stack_size 被用户修改成什么,都不会写入 item, // 通过 show parameter 只能看到旧值 4M ,必须 restart 后才能 // 看到更新后的值 5M。 } else { item.set_version(version); if (!item.set_value(pvalue->value())) { // without set ret SHARE_LOG(WARN, "set config item value failed", K(key.name()), K(pvalue->value()), K(version)); } else { item.set_value_updated(); } } // 双关,既表示 root_value 被设置过 (if any),也表示 value 被设置过(if any) item.initial_value_set(); } } return ret; } int64_t ObSystemConfig::to_string(char *buf, const int64_t len) const { int64_t pos = 0; hashmap::const_iterator it = map_.begin(); hashmap::const_iterator last = map_.end(); pos += snprintf(buf + pos, len - pos, "total: [%ld]\n", map_.size()); for (; it != last; ++it) { pos += snprintf(buf + pos, len - pos, "name: [%s], value: [%s]\n", it->first.name(), it->second->value()); } return pos; } } // end of namespace common } // end of namespace oceanbase