国产亚洲精品福利在线无卡一,国产精久久一区二区三区,亚洲精品无码国模,精品久久久久久无码专区不卡

當前位置: 首頁 > news >正文

如何做網(wǎng)站微信支付鄭州百度快照優(yōu)化

如何做網(wǎng)站微信支付,鄭州百度快照優(yōu)化,laravel網(wǎng)站怎么做項目,萬網(wǎng) 做網(wǎng)站本專題的第一篇文章,配置項的定義及使用方法,詳細闡述了配置項的基礎(chǔ)用法。對于那些對源碼抱有濃厚興趣的同學來說,或許還希望深入了解配置項的實現(xiàn)原理,甚至渴望親自添加新的配置項,以滿足個性化的功能需求。 本文通…

本專題的第一篇文章,配置項的定義及使用方法,詳細闡述了配置項的基礎(chǔ)用法。對于那些對源碼抱有濃厚興趣的同學來說,或許還希望深入了解配置項的實現(xiàn)原理,甚至渴望親自添加新的配置項,以滿足個性化的功能需求。

本文通過剖析“如何新增配置項”這一話題,并結(jié)合配置項源碼的具體實現(xiàn),來詳細講解配置項的定義、初始化、內(nèi)部訪問及同步機制。

如何新增配置項?

要新增一個配置項,首先在 src/share/parameter/ob_parameter_seed.ipp 文件中,按照下面的格式定義配置項。

// 定義一個集群級別的、INT類型的配置項,動態(tài)生效
DEF_INT(cpu_count, OB_CLUSTER_PARAMETER, "0", "[0,]","the number of CPU\\'s in the system. ""If this parameter is set to zero, the number will be set according to sysconf; ""otherwise, this parameter is used. Range: [0,+∞) in integer",ObParameterAttr(Section::OBSERVER, Source::DEFAULT, EditLevel::DYNAMIC_EFFECTIVE));// 定義一個租戶級別的、TIME類型的配置項,動態(tài)生效,并附帶一個合法性檢查類 ObConfigStaleTimeChecker
DEF_TIME_WITH_CHECKER(max_stale_time_for_weak_consistency, OB_TENANT_PARAMETER, "5s",common::ObConfigStaleTimeChecker,"[5s,)","the max data stale time that cluster weak read version behind current timestamp,""no smaller than weak_read_version_refresh_interval, range: [5s, +∞)",ObParameterAttr(Section::TENANT, Source::DEFAULT, EditLevel::DYNAMIC_EFFECTIVE));

其中每個參數(shù)的含義如下:

參數(shù)說明舉例
配置項宏定義配置的宏,可以選擇附帶合法性檢查函數(shù)DEF_XXX、DEF_XXX_WITH_CHECKER
配置項名配置項的名字一般格式:xxx_xxx_xxx
生效范圍租戶配置項 or 集群配置項OB_CLUSTER_PARAMETER、OB_TENANT_PARAMETER
默認值默認值必須在取值范圍中"0", "True", "100ms", "20GB", "random"
取值范圍布爾類型和字符串類型不需要取值范圍"[0,]", "[0M,]", "[1s, 180s]"
描述介紹該配置項的功能和注意事項"enable xxx"
配置項屬性① Section:所屬模塊;
② Source:來源;
③ EditLevel:生效方式;
① OBSERVER、TENANT、TRANS
② DEFAULT
③ DYNAMIC_EFFECTIVE、STATIC_EFFECTIVE

DEF_XXX 宏最終展開是一個類的聲明,并同時定義一個對象,對象名就是配置項名。

比如 DEF_TIME_WITH_CHECKER 宏,最終展開是一個 ObConfigTimeItem 類,重載 operator= 操作符讓該類可以像基礎(chǔ)數(shù)據(jù)類型一樣進行賦值操作。

#define _DEF_PARAMETER_CHECKER_EASY(access_specifier, param, scope, name, def, checker, args...) \
access_specifier:                                                                          \class ObConfig ## param ## Item ## _ ## name                                 \: public common::ObConfig ## param ## Item                               \{                                                                            \public:                                                                     \ObConfig ## param ## Item ## _ ## name()                                   \: common::ObConfig ## param ## Item(                                   \local_container(), scope, #name, def, args)                        \{                                                                          \add_checker(OB_NEW(checker, g_config_mem_attr));                         \}                                                                          \template <class T>                                                         \ObConfig ## param ## Item ## _ ## name& operator=(T value)                 \{                                                                          \common::ObConfig ## param ## Item::operator=(value);                     \return *this;                                                            \}                                                                          \} name;

ObConfigTimeItemXxx 繼承的是一個 ObConfigIntegralItem 類,所以 time 類型的數(shù)據(jù)本質(zhì)上是一個 int64_t 變量。

class ObConfigTimeItem: public ObConfigIntegralItem
{
public:......static const uint64_t VALUE_BUF_SIZE = 32UL;char value_str_[VALUE_BUF_SIZE];char value_reboot_str_[VALUE_BUF_SIZE];
};

ObConfigIntegralItem 類重載了操作符 operator const int64_t &() const,在代碼中訪問該類對象的對象名時,實際上返回的是對象的 value_值。

class ObConfigIntegralItem: public ObConfigItem
{// get_value() return the real-time valueint64_t get_value() const { return value_; }// get() return the real-time value if it does not need reboot, otherwise it return initial_valueint64_t get() const { return value_; }operator const int64_t &() const { return value_; }private:int64_t value_;

配置項定義完成后,重新編譯部署 OBServer,就可以對這個配置項進行查詢和修改了。不過現(xiàn)在這個配置項沒有任何功能,還需要在代碼中用起來才能生效。

配置項初始化

集群配置項 ObServerConfig

集群配置項在 OBServer 啟動時進行初始化,首先會從配置項的定義中獲取默認值,然后從持久化配置文件中獲取歷史值(非首次啟動),最后從 OBServer 的執(zhí)行參數(shù)中獲取最新值。它們的優(yōu)先級是:執(zhí)行參數(shù) > 持久化配置文件 > 默認值。

配置項對象構(gòu)造

集群配置項定義在 ObServerConfig 類中,通過在 ObConfigManager 類中定義了一個 ObServerConfig 實例,當 OBServer 啟動時,它們及其成員變量的構(gòu)造函數(shù)就會被調(diào)用。

class ObServerConfig : public ObCommonConfig
{
public:friend class ObServerMemoryConfig;int init(const ObSystemConfig &config);static ObServerConfig &get_instance();#undef OB_CLUSTER_PARAMETER
#define OB_CLUSTER_PARAMETER(args...) args
#include "share/parameter/ob_parameter_seed.ipp"
#undef OB_CLUSTER_PARAMETER
}

每個配置項都有默認值,在配置項的構(gòu)造函數(shù)中會將 value_ 置為默認值。

以下是相關(guān)函數(shù)的調(diào)用流程,以及關(guān)鍵函數(shù)的代碼解析。有的函數(shù)只是省略了參數(shù)列表,不代表沒有參數(shù)。

  • ObConfigTimeItem::ObConfigTimeItem()
  • ObConfigIntegralItem::init()
  • ObConfigItem::init()
  • ObConfigItem::set_value(const char *str)
  • ObConfigIntegralItem::set(const char *str)

其中 str 就是一開始定義的配置項默認值,將 str 中的字符串轉(zhuǎn)化為對應類型的數(shù)據(jù),然后賦值給 value_。

inline bool ObConfigIntegralItem::set(const char *str)
{bool valid = true;const int64_t value = parse(str, valid);if (valid) {value_ = value;}return valid;
}

配置文件解析

當集群配置項都構(gòu)造完成后,再從持久化的配置文件中 etc/observer.config.bin 加載配置項。(在 OBServer 初次啟動時,配置文件為空,所以不會執(zhí)行這一步)

  • ObServer::init()
  • ObServer::init_config()
  • ObConfigManager::load_config(const char *path)
  • ObServerConfig::deserialize_with_compat()
  • OB_DEF_DESERIALIZE(ObServerConfig)

先調(diào)用 ObCommonConfig::deserialize() 函數(shù)解析集群配置項,再調(diào)用 OTC_MGR.deserialize() 函數(shù)解析租戶配置項。

OB_DEF_DESERIALIZE(ObServerConfig)
{} else if (OB_FAIL(ObCommonConfig::deserialize(buf, data_len, pos))) {LOG_ERROR("deserialize cluster config failed", K(ret));} else if (OB_FAIL(OTC_MGR.deserialize(buf, data_len, pos))){LOG_ERROR("deserialize tenant config failed", K(ret));}
  • OB_DEF_DESERIALIZE(ObCommonConfig)
  • ObCommonConfig::add_extra_config()

將文件中集群配置項的值加載到內(nèi)存數(shù)據(jù)結(jié)構(gòu)中。

int ObCommonConfig::add_extra_config(const char *config_str,int64_t version /* = 0 */ ,bool check_name /* = false */,bool check_unit /* = true */)
{......while (OB_SUCC(ret) && OB_NOT_NULL(token)) {if (strncmp(token, "enable_production_mode=", 23) == 0) {......} else if (OB_ISNULL(pp_item = container_.get(ObConfigStringKey(name)))) {......if (OB_FAIL(ret) || OB_ISNULL(pp_item)) {} else if (check_unit && !(*pp_item)->check_unit(value)) {ret = OB_INVALID_CONFIG;LOG_ERROR("Invalid config value", K(name), K(value), K(ret));} else if (!(*pp_item)->set_value(value)) {ret = OB_INVALID_CONFIG;LOG_ERROR("Invalid config value", K(name), K(value), K(ret));} else if (!(*pp_item)->check()) {ret = OB_INVALID_CONFIG;const char* range = (*pp_item)->range();if (OB_ISNULL(range) || strlen(range) == 0) {LOG_ERROR("Invalid config, value out of range", K(name), K(value), K(ret));} else {_LOG_ERROR("Invalid config, value out of %s (for reference only). name=%s, value=%s, ret=%d", range, name, value, ret);}} else {(*pp_item)->set_version(version);LOG_INFO("Load config succ", K(name), K(value));}

執(zhí)行參數(shù)解析

當配置文件中的數(shù)據(jù)加載完成后,再解析 OBServer 執(zhí)行命令中的配置項參數(shù)。

  • ObServer::init_config()

其中 config_.add_extra_config(opts_.optstr_, start_time_) 函數(shù)將參數(shù)解析為配置項的值,然后加載到配置項結(jié)構(gòu)中。最后調(diào)用 dump2file() 函數(shù),將前面解析出來的配置項全部持久化到"etc/observer.config.bin"文件中。

int ObServer::init_config()
{int ret = OB_SUCCESS;bool has_config_file = true;// set dump pathconst char *dump_path = "etc/observer.config.bin";config_mgr_.set_dump_path(dump_path);if (OB_FILE_NOT_EXIST == (ret = config_mgr_.load_config())) {has_config_file = false;ret = OB_SUCCESS;}......if (opts_.optstr_ && strlen(opts_.optstr_) > 0) {if (OB_FAIL(config_.add_extra_config(opts_.optstr_, start_time_))) {LOG_ERROR("invalid config from cmdline options", K(opts_.optstr_), KR(ret));}}......if (is_arbitration_mode()) {// arbitration mode, dump config params to file directlyif (OB_FAIL(config_mgr_.dump2file())) {LOG_ERROR("config_mgr_ dump2file failed", KR(ret));} else {LOG_INFO("config_mgr_ dump2file success", KR(ret));}

如果是用 OBD 部署集群,OBServer 第一次啟動時,命令中會帶上"xxx.yaml"文件中的啟動參數(shù)。例如:

/data/user/observer1/bin/observer -p 23400 -P 23401 -z zone1 -c 1 -d /data/user/observer1/store -i lo -r 127.0.0.1:23401:23400 -o __min_full_resource_pool_memory=268435456,major_freeze_duty_time=Disable,datafile_size=20G,memory_limit=10G,system_memory=5G,cpu_count=24,stack_size=512K,cache_wash_threshold=1G,workers_per_cpu_quota=10,schema_history_expire_time=1d,net_thread_count=4,minor_freeze_times=10,enable_separate_sys_clog=False,enable_merge_by_turn=False,syslog_io_bandwidth_limit=10G,enable_async_syslog=False

集群第一次部署完成之后,"etc/observer.config.bin"文件才會被創(chuàng)建,之后重啟 OBServer 就可以不帶參數(shù)了,進程會從該文件中讀取修改后的配置項。

租戶配置項 ObTenantConfig

創(chuàng)建租戶時初始化

租戶級別配置項首先在創(chuàng)建租戶時進行初始化,在代碼中是一個 ObTenantConfig 對象。

(不只這一條調(diào)用路徑,但最終會調(diào)用 add_tenant_config() 函數(shù))

  • ObRpcNotifyTenantServerUnitResourceP::process()
  • ObTenantNodeBalancer::notify_create_tenant(oceanbase::obrpc::TenantServerUnitConfig const&)
  • ObTenantNodeBalancer::check_new_tenant(oceanbase::share::ObUnitInfoGetter::ObTenantConfig const&, long)
  • ObMultiTenant::create_tenant(oceanbase::omt::ObTenantMeta const&, bool, long)
  • ObTenantConfigMgr::add_tenant_config(uint64_t tenant_id)

申請一個新的 ObTenantConfig 對象,調(diào)用 init() 初始化,然后添加到 config_map_中。

int ObTenantConfigMgr::add_tenant_config(uint64_t tenant_id)
{int ret = OB_SUCCESS;ObTenantConfig *const *config = nullptr;DRWLock::WRLockGuard guard(rwlock_);if (is_virtual_tenant_id(tenant_id)|| OB_NOT_NULL(config = config_map_.get(ObTenantID(tenant_id)))) {if (nullptr != config) {ObTenantConfig *new_config = *config;new_config->set_deleting(false);}} else {ObTenantConfig *new_config = nullptr;new_config = OB_NEW(ObTenantConfig, SET_USE_UNEXPECTED_500("TenantConfig"), tenant_id);if (OB_NOT_NULL(new_config)) {if(OB_FAIL(new_config->init(this))) {LOG_WARN("new tenant config init failed", K(ret));} else if (OB_FAIL(config_map_.set_refactored(ObTenantID(tenant_id),new_config, 0))) {LOG_WARN("add new tenant config failed", K(ret));}......

因為 ObTenantConfig 引入了租戶配置項的定義,因此在構(gòu)造 ObTenantConfig 對象時就完成了配置項的構(gòu)造。

class ObTenantConfig : public ObCommonConfig
{#undef OB_TENANT_PARAMETER
#define OB_TENANT_PARAMETER(args...) args
#include "share/parameter/ob_parameter_seed.ipp"
#undef OB_TENANT_PARAMETER
};

重啟時初始化

在 OBServer 重新啟動時,已有租戶的配置項也會進行初始化。

  • OB_DEF_DESERIALIZE(ObServerConfig)

調(diào)用 OTC_MGR.deserialize() 函數(shù)。

OB_DEF_DESERIALIZE(ObServerConfig)
{} else if (OB_FAIL(ObCommonConfig::deserialize(buf, data_len, pos))) {LOG_ERROR("deserialize cluster config failed", K(ret));} else if (OB_FAIL(OTC_MGR.deserialize(buf, data_len, pos))){LOG_ERROR("deserialize tenant config failed", K(ret));}
  • OB_DEF_DESERIALIZE(ObTenantConfigMgr)

讀取文件中租戶配置項,根據(jù) tenant_id 獲取 config,然后將buf中的配置項解析到 config 中。

OB_DEF_DESERIALIZE(ObTenantConfigMgr)
{int ret = OB_SUCCESS;if (data_len == 0 || pos >= data_len) {} else {while(OB_SUCC(ret) && pos < data_len) {......ObTenantConfig *config = nullptr;if (OB_FAIL(config_map_.get_refactored(ObTenantID(tenant_id), config))) {if (ret != OB_HASH_NOT_EXIST || OB_FAIL(add_tenant_config(tenant_id))) {LOG_ERROR("get tenant config failed", K(tenant_id),  K(ret));break;}ret = config_map_.get_refactored(ObTenantID(tenant_id), config);}if (OB_SUCC(ret)) {pos = saved_pos;ret = config->deserialize(buf, data_len, pos);}......

在代碼中查詢配置項

外部查詢

當用戶使用"show ..."類型的命令時,OBServer 內(nèi)部有統(tǒng)一的處理函數(shù):ObShowResolver::resolve()。查詢配置項的命令會被解析為 T_SHOW_PARAMETERS 類型,通過查詢 __all_virtual_tenant_parameter_stat 表獲取配置項的值。

int ObShowResolver::resolve(const ParseNode &parse_tree)
{......case T_SHOW_PARAMETERS: {......if (params_.show_seed_) {char local_ip[OB_MAX_SERVER_ADDR_SIZE] = "";if (OB_UNLIKELY(true != GCONF.self_addr_.ip_to_string(local_ip, sizeof(local_ip)))) {ret = OB_CONVERT_ERROR;} else {GEN_SQL_STEP_1(ObShowSqlSet::SHOW_PARAMETERS_SEED);GEN_SQL_STEP_2(ObShowSqlSet::SHOW_PARAMETERS_SEED, REAL_NAME(OB_SYS_DATABASE_NAME, OB_ORA_SYS_SCHEMA_NAME), REAL_NAME(OB_ALL_VIRTUAL_TENANT_PARAMETER_STAT_TNAME, OB_ALL_VIRTUAL_TENANT_PARAMETER_STAT_ORA_TNAME),local_ip, GCONF.self_addr_.get_port());}} else if (OB_SYS_TENANT_ID == show_tenant_id) {GEN_SQL_STEP_1(ObShowSqlSet::SHOW_PARAMETERS);GEN_SQL_STEP_2(ObShowSqlSet::SHOW_PARAMETERS,REAL_NAME(OB_SYS_DATABASE_NAME, OB_ORA_SYS_SCHEMA_NAME),REAL_NAME(OB_ALL_VIRTUAL_TENANT_PARAMETER_STAT_TNAME, OB_ALL_VIRTUAL_TENANT_PARAMETER_STAT_ORA_TNAME),show_tenant_id);} else {GEN_SQL_STEP_1(ObShowSqlSet::SHOW_PARAMETERS);GEN_SQL_STEP_2(ObShowSqlSet::SHOW_PARAMETERS,REAL_NAME(OB_SYS_DATABASE_NAME, OB_ORA_SYS_SCHEMA_NAME),REAL_NAME(OB_ALL_VIRTUAL_TENANT_PARAMETER_STAT_TNAME, OB_ALL_VIRTUAL_TENANT_PARAMETER_STAT_ORA_TNAME),show_tenant_id);}
}// 最終查詢的虛擬表為 __all_virtual_tenant_parameter_stat
const char *const OB_ALL_VIRTUAL_TENANT_PARAMETER_STAT_TNAME = "__all_virtual_tenant_parameter_stat";

查詢該虛擬表需要先初始化一個 ObAllVirtualTenantParameterStat 對象,然后調(diào)用 inner_open() 函數(shù),再循環(huán)調(diào)用 inner_get_next_row() 函數(shù)遍歷虛擬表。

  • ObVirtualTableIterator::get_next_row(common::ObNewRow*&)
  • ObAllVirtualTenantParameterStat::inner_get_next_row(common::ObNewRow*&)

其中 inner_sys_get_next_row() 函數(shù)獲取集群配置項,inner_tenant_get_next_row() 函數(shù)獲取租戶配置項,最后根據(jù)查詢條件進行篩選,返回滿足條件的配置項。

int ObAllVirtualTenantParameterStat::inner_get_next_row(ObNewRow *&row)
{int ret = OB_SUCCESS;if (OB_UNLIKELY(!inited_)) {ret = OB_NOT_INIT;SERVER_LOG(WARN, "not inited", K(inited_), KR(ret));} else if (show_seed_) {ret = inner_seed_get_next_row(row);} else {if (OB_SUCC(inner_sys_get_next_row(row))) {} else if (OB_ITER_END == ret) {ret = inner_tenant_get_next_row(row);}}return ret;
}
  • ObAllVirtualTenantParameterStat::inner_sys_get_next_row(common::ObNewRow*&)

從 GCONF 中獲取集群配置項。

int ObAllVirtualTenantParameterStat::inner_sys_get_next_row(common::ObNewRow *&row)
{/*cluster parameter does not belong to any tenant*/return fill_row_(row, sys_iter_, GCONF.get_container(), NULL);
}// 集群配置項迭代器也就是 GCONF 中一個 hashmap 的迭代器sys_iter_ = GCONF.get_container().begin();
  • ObAllVirtualTenantParameterStat::inner_tenant_get_next_row(common::ObNewRow *&row)

從 tenant_config_中獲取租戶配置項。

int ObAllVirtualTenantParameterStat::inner_tenant_get_next_row(common::ObNewRow *&row)
{// 租戶配置項迭代器也就是 tenant_config_ 中一個 hashmap 的迭代器if (cur_tenant_idx_ < 0 // first come-in// current tenant is over|| (tenant_config_.is_valid() && tenant_iter_ == tenant_config_->get_container().end())) {// find next valid tenantwhile (OB_SUCC(ret) && ++cur_tenant_idx_ < tenant_id_list_.count()) {uint64_t tenant_id = tenant_id_list_.at(cur_tenant_idx_);tenant_config_.set_config(TENANT_CONF(tenant_id));if (tenant_config_.is_valid()) {tenant_iter_ = tenant_config_->get_container().begin();......}......} else {const uint64_t tenant_id = tenant_id_list_.at(cur_tenant_idx_);if (OB_FAIL(fill_row_(row,tenant_iter_,tenant_config_->get_container(),&tenant_id))) {SERVER_LOG(WARN, "fill row fail", KR(ret), K(tenant_id), K(tenant_config_->get_tenant_id()),K(cur_tenant_idx_), K(tenant_id_list_));}

內(nèi)部獲取

集群配置項

因為配置項重載了操作符 operator &(),所以集群配置項直接通過 GCONF.xxx 的形式訪問即可。

#include "share/config/ob_server_config.h"GCONF.enable_sql_audit 

在代碼中有需要的地方,可以用“if (GCONF.enable_xxx)”來控制分支的走向,或者用“GCONF.xxx_time”來進行時間的計算,這樣就可以把配置項使用起來了。

租戶配置項

訪問租戶配置項需要先調(diào)用 OTC_MGR.read_tenant_config() 函數(shù)獲取租戶的 config,然后從 config 中獲取指定的配置項。以租戶配置項 max_stale_time_for_weak_consistency 為例,為其封裝一個取值函數(shù)。

  • ObWeakReadUtil::max_stale_time_for_weak_consistency(const uint64_t tenant_id, int64_t ignore_warn)

如果獲取租戶 config 成功,則從 config 中獲取配置項的值,否則返回配置項的默認值并打印日志。

int64_t ObWeakReadUtil::max_stale_time_for_weak_consistency(const uint64_t tenant_id, int64_t ignore_warn)
{int64_t max_stale_time = 0;OTC_MGR.read_tenant_config(tenant_id,oceanbase::omt::ObTenantConfigMgr::default_fallback_tenant_id(),/* success */ [&max_stale_time](const omt::ObTenantConfig &config) mutable {max_stale_time = config.max_stale_time_for_weak_consistency;},/* failure */ [tenant_id, ignore_warn, &max_stale_time]() mutable {max_stale_time = DEFAULT_MAX_STALE_TIME_FOR_WEAK_CONSISTENCY;if (IGNORE_TENANT_EXIST_WARN != ignore_warn && REACH_TIME_INTERVAL(1 * 1000 * 1000L)) {TRANS_LOG_RET(WARN, OB_ERR_UNEXPECTED, "tenant not exist when get max stale time for weak consistency,"" use default max stale time instead",K(tenant_id), K(max_stale_time), K(lbt()));}});return max_stale_time;
}
  • ObTenantConfigMgr::read_tenant_config()

從 config_map_中獲取 tenant_id 對應的config,成功則調(diào)用 SuccessFunctor,失敗則調(diào)用 FailureFunctor。

int ObTenantConfigMgr::read_tenant_config(const uint64_t tenant_id,const uint64_t fallback_tenant_id,const SuccessFunctor &on_success,const FailureFunctor &on_failure) const
{int ret = OB_SUCCESS;ObTenantConfig *config = nullptr;DRWLock::RDLockGuard guard(rwlock_);if (OB_FAIL(config_map_.get_refactored(ObTenantID(tenant_id), config))) {if (fallback_tenant_id > 0 && OB_INVALID_ID != fallback_tenant_id) {if (OB_FAIL(config_map_.get_refactored(ObTenantID(fallback_tenant_id), config))) {LOG_WARN("failed to get tenant config", K(fallback_tenant_id), K(ret), K(lbt()));}} else {LOG_WARN("failed to get tenant config", K(tenant_id), K(ret));}}if (OB_SUCC(ret) && OB_NOT_NULL(config)) {on_success(*config);} else {on_failure();LOG_WARN("fail read tenant config", K(tenant_id), K(ret));}return ret;
}

在代碼中修改配置項

外部修改

修改集群配置項

系統(tǒng)租戶執(zhí)行修改集群配置項命令時,內(nèi)部會向 __all_sys_parameter 表中插入一條記錄(該表只記錄增量數(shù)據(jù)),實際執(zhí)行的是以下sql命令。

select config_version, zone, svr_type, svr_ip, svr_port, name, data_type, value, info, section, scope, source, edit_level from __all_sys_parameter
INSERT INTO __all_sys_parameter (zone, svr_type, svr_ip, svr_port, name, data_type, value, info, config_version, gmt_modified, section, scope, source, edit_level) VALUES ('', 'observer', 'ANY', 0, 'cpu_count', 'varchar', '9', '', 1689734424757370, usec_to_time(1689734424757370), 'OBSERVER', 'CLUSTER', 'DEFAULT', 'DYNAMIC_EFFECTIVE') ON DUPLICATE KEY UPDATE data_type = 'varchar', value = '9', info = '', config_version = 1689734424757370, gmt_modified = usec_to_time(1689734424757370), section = 'OBSERVER', scope = 'CLUSTER', source = 'DEFAULT', edit_level = 'DYNAMIC_EFFECTIVE'
select config_version, zone, svr_type, svr_ip, svr_port, name, data_type, value, info, section, scope, source, edit_level from __all_sys_parameter
select config_version, zone, svr_type, svr_ip, svr_port, name, data_type, value, info, section, scope, source, edit_level from __all_sys_parameter

將修改后的值插入內(nèi)部表之后,修改配置項命令就執(zhí)行完成了。之后內(nèi)部會將表中的增量數(shù)據(jù)刷新到各節(jié)點的本地數(shù)據(jù)結(jié)構(gòu)中,此時才算真正完成了集群配置項更新。

修改租戶配置項

執(zhí)行租戶配置項修改命令后,內(nèi)部會執(zhí)行兩條sql,先往 __tenant_parameter 內(nèi)部表中插入一行數(shù)據(jù)(該表只記錄增量數(shù)據(jù)),然后往 __all_rootservice_event_history 內(nèi)部表中插入一條修改記錄。

INSERT INTO __tenant_parameter (tenant_id, zone, svr_type, svr_ip, svr_port, name, data_type, value, info, config_version, gmt_modified, section, scope, source, edit_level) VALUES (1004, '', 'observer', 'ANY', 0, 'max_stale_time_for_weak_consistency', 'varchar', '7s', '', 1689732907024711, usec_to_time(1689732907024711), 'TENANT', 'TENANT', 'DEFAULT', 'DYNAMIC_EFFECTIVE') ON DUPLICATE KEY UPDATE data_type = 'varchar', value = '7s', info = '', config_version = 1689732907024711, gmt_modified = usec_to_time(1689732907024711), section = 'TENANT', scope = 'TENANT', source = 'DEFAULT', edit_level = 'DYNAMIC_EFFECTIVE'
INSERT INTO __all_rootservice_event_history (gmt_create, module, event, name1, value1, name2, value2, rs_svr_ip, rs_svr_port) VALUES (usec_to_time(1689732907031822), 'root_service', 'admin_set_config', 'ret', 0, 'arg', '{items:[{name:"max_stale_time_for_weak_consistency", value:"7s", comment:"", zone:"", server:"0.0.0.0:0", tenant_name:"", exec_tenant_id:1004, tenant_ids:[1004]}], is_inner:false}', '127.0.0.1', 23401

同樣的,修改內(nèi)部表之后SQL命令就會返回,之后再由后臺線程刷新各節(jié)點的租戶配置項。

內(nèi)部更新(同步機制)

內(nèi)部主動更新配置項,就是把 __tenant_parameter 和 __all_sys_parameter 內(nèi)部表中的增量配置項同步到本地的過程。

集群配置項同步
  • ObLeaseStateMgr::start_heartbeat()

后臺任務 hb_ 每2s執(zhí)行一次。

int ObLeaseStateMgr::start_heartbeat()
{int ret = OB_SUCCESS;if (!inited_) {ret = OB_NOT_INIT;LOG_WARN("not init", K(ret));} else {const bool repeat = false;if (OB_FAIL(hb_timer_.schedule(hb_, DELAY_TIME, repeat))) {LOG_WARN("schedule failed", LITERAL_K(DELAY_TIME), K(repeat), K(ret));}}return ret;
}static const int64_t DELAY_TIME = 2 * 1000 * 1000;//2s
  • ObLeaseStateMgr::HeartBeat::runTimerTask()

......

  • ObHeartBeatProcess::do_heartbeat_event(oceanbase::share::ObLeaseResponse const&)
  • ObHeartBeatProcess::ObZoneLeaseInfoUpdateTask::runTimerTask()

......

  • ObConfigManager::got_version(long, bool)
  • ObConfigManager::UpdateTask::runTimerTask()

該函數(shù)是刷新配置項的后臺定時任務,會調(diào)用 update_local() 函數(shù),將內(nèi)部表中的數(shù)據(jù)同步到本地配置項中。

void ObConfigManager::UpdateTask::runTimerTask()
{......} else if (update_local_) {config_mgr_->current_version_ = version;if (OB_FAIL(config_mgr_->system_config_.clear())) {// just print log, ignore retLOG_WARN("Clear system config map failed", K(ret));} else {// do nothing}if (OB_FAIL(config_mgr_->update_local(version))) {LOG_WARN("Update local config failed", K(ret));// recovery current_version_config_mgr_->current_version_ = old_current_version;// retry update local config in 1s laterif (OB_FAIL(TG_SCHEDULE(lib::TGDefIDs::CONFIG_MGR, *this, 1000 * 1000L, false))) {LOG_WARN("Reschedule update local config failed", K(ret));}
  • ObConfigManager::update_local(int64_t expected_version)

該函數(shù)主要做了以下操作:

  1. sql_client_retry_weak.read():從 __all_sys_parameter 內(nèi)部表中讀取增量配置項;
  2. system_config_.update():將配置項的新值更新到本地;
  3. reload_config():重新加載和校驗配置項;
  4. dump2file():將配置項同步到 observer.config.bin 文件中;
int ObConfigManager::update_local(int64_t expected_version)
{int ret = OB_SUCCESS;if (OB_ISNULL(sql_proxy_)) {ret = OB_NOT_INIT;LOG_WARN("sql proxy is null", K(ret));} else {ObSQLClientRetryWeak sql_client_retry_weak(sql_proxy_);SMART_VAR(ObMySQLProxy::MySQLResult, result) {int64_t start = ObTimeUtility::current_time();const char *sqlstr = "select config_version, zone, svr_type, svr_ip, svr_port, name, ""data_type, value, info, section, scope, source, edit_level ""from __all_sys_parameter";if (OB_FAIL(sql_client_retry_weak.read(result, sqlstr))) {LOG_WARN("read config from __all_sys_parameter failed", K(sqlstr), K(ret));} else if (OB_FAIL(system_config_.update(result))) {LOG_WARN("failed to load system config", K(ret));......if (OB_SUCC(ret)) {if ('\0' == dump_path_[0]) {ret = OB_NOT_INIT;LOG_ERROR("Dump path doesn't set, stop read config", K(ret));} else if (OB_FAIL(server_config_.read_config())) {LOG_ERROR("Read server config failed", K(ret));} else if (OB_FAIL(reload_config())) {LOG_WARN("Reload configuration failed", K(ret));} else {DRWLock::RDLockGuard guard(OTC_MGR.rwlock_); // need protect tenant config because it will also serialize tenant configif (OB_FAIL(dump2file())) {LOG_WARN("Dump to file failed", K_(dump_path), K(ret));......

租戶配置項同步
  • ObLeaseStateMgr::HeartBeat::runTimerTask()

......

  • ObTenantConfig::got_version(long, bool)
  • ObTenantConfig::TenantConfigUpdateTask::runTimerTask()

租戶配置項同樣有一個后臺定時任務,只要配置項的最新版本大于本地版本,就會觸發(fā)更新操作。

void ObTenantConfig::TenantConfigUpdateTask::runTimerTask()
{int ret = OB_SUCCESS;if (OB_ISNULL(config_mgr_)) {ret = OB_NOT_INIT;LOG_WARN("invalid argument", K_(config_mgr), K(ret));} else if (OB_ISNULL(tenant_config_)){ret = OB_NOT_INIT;LOG_WARN("invalid argument", K_(tenant_config), K(ret));} else {const int64_t saved_current_version = tenant_config_->current_version_;const int64_t version = version_;THIS_WORKER.set_timeout_ts(INT64_MAX);if (tenant_config_->current_version_ >= version) {ret = OB_ALREADY_DONE;} else if (update_local_) {tenant_config_->current_version_ = version;if (OB_FAIL(tenant_config_->system_config_.clear())) {LOG_WARN("Clear system config map failed", K(ret));} else if (OB_FAIL(config_mgr_->update_local(tenant_config_->tenant_id_, version))) {LOG_WARN("ObTenantConfigMgr update_local failed", K(ret), K(tenant_config_));} else {config_mgr_->notify_tenant_config_changed(tenant_config_->tenant_id_);}
  • ObTenantConfigMgr::update_local(uint64_t tenant_id, int64_t expected_version)

查詢 __tenant_parameter 內(nèi)部表獲取當前租戶的 config,然后將新的數(shù)據(jù)更新到 config中。

int ObTenantConfigMgr::update_local(uint64_t tenant_id, int64_t expected_version)
{SMART_VAR(ObMySQLProxy::MySQLResult, result) {if (OB_FAIL(sql.assign_fmt("select config_version, zone, svr_type, svr_ip, svr_port, name, ""data_type, value, info, section, scope, source, edit_level ""from %s where tenant_id = '%lu'", OB_TENANT_PARAMETER_TNAME, tenant_id))) {} else if (OB_FAIL(sql_client_retry_weak.read(result, exec_tenant_id, sql.ptr()))) {LOG_WARN("read config from __tenant_parameter failed",KR(ret), K(tenant_id), K(exec_tenant_id), K(sql));} else {DRWLock::WRLockGuard guard(rwlock_);ret = config_map_.get_refactored(ObTenantID(tenant_id), config);if (OB_FAIL(ret)) {LOG_ERROR("failed to get tenant config", K(tenant_id), K(ret));} else {ret = config->update_local(expected_version, result);}
  • ObTenantConfig::update_local()

調(diào)用 system_config_.update() 函數(shù)將配置項更新到本地,然后調(diào)用 dump2file() 將配置項持久化到文件中。

int ObTenantConfig::update_local(int64_t expected_version, ObMySQLProxy::MySQLResult &result,bool save2file /* = true */)
{int ret = OB_SUCCESS;if (OB_FAIL(system_config_.update(result))) {LOG_WARN("failed to load system config", K(ret));if (OB_SUCC(ret)) {if (OB_FAIL(read_config())) {LOG_ERROR("Read tenant config failed", K_(tenant_id), K(ret));} else if (save2file && OB_FAIL(config_mgr_->dump2file())) {LOG_WARN("Dump to file failed", K(ret));

小結(jié)

新增配置項并不復雜,代碼中已經(jīng)實現(xiàn)了成熟的訪問和同步機制,只需要使用合適的宏并填上一些參數(shù)就可以定義新配置項了,而后續(xù)如何使用這個配置項才是實現(xiàn)新功能的關(guān)鍵。在修改配置項的過程中,實際上還會進行一些合法性檢查,這部分會在后面的文章中與系統(tǒng)變量一起進行說明。

本專題下一篇文章是關(guān)于“系統(tǒng)變量的定義和源碼解析”,系統(tǒng)變量的機制有別于配置項,還有全局級和會話級的區(qū)分,感興趣的同學歡迎繼續(xù)關(guān)注。

參考資料

  1. 配置項總覽
  2. OceanBase源碼
http://m.aloenet.com.cn/news/29215.html

相關(guān)文章:

  • 電子商務系統(tǒng) 網(wǎng)站建設(shè)百度教育會員
  • 開源網(wǎng)站github最近一周國內(nèi)熱點新聞
  • 濰坊網(wǎng)站建設(shè)公司有哪些內(nèi)容網(wǎng)店培訓教程
  • 個人興趣圖片集網(wǎng)站建設(shè)b站推廣鏈接
  • 網(wǎng)站頁面描述深圳網(wǎng)絡營銷推廣招聘網(wǎng)
  • 主流網(wǎng)站開發(fā)語言企業(yè)網(wǎng)站有哪些功能
  • 價錢網(wǎng)站建設(shè)百度官方網(wǎng)首頁
  • 做商城網(wǎng)站公司seo刷關(guān)鍵詞排名軟件
  • 網(wǎng)站建設(shè)歷史友情鏈接推廣平臺
  • 個人網(wǎng)站做電影網(wǎng)站南京seo排名優(yōu)化公司
  • 可以做本地生活服務的有哪些網(wǎng)站營銷型網(wǎng)站建設(shè)服務
  • 怎么登陸建設(shè)工程網(wǎng)站成都網(wǎng)站快速排名優(yōu)化
  • 零遁nas做網(wǎng)站百度開放平臺登錄
  • 網(wǎng)絡咨詢網(wǎng)站如何做網(wǎng)絡營銷?
  • WordPress如何設(shè)置站點名稱免費b站推廣網(wǎng)站2023
  • 中山網(wǎng)站代運營百度域名注冊
  • 濟寧網(wǎng)站建設(shè)案例展示產(chǎn)品營銷方案策劃
  • 企業(yè)宣傳片拍攝思路網(wǎng)站如何做seo排名
  • 做視頻網(wǎng)站如何賺錢品牌推廣的渠道有哪些
  • 基于PHP的家教網(wǎng)站開發(fā)環(huán)境谷歌seo服務商
  • 用六類網(wǎng)站做電話可以嗎長尾關(guān)鍵詞搜索網(wǎng)站
  • seo網(wǎng)站優(yōu)化推廣怎么做東莞seo優(yōu)化案例
  • 最新新聞熱點事件2024摘抄優(yōu)化大師好用嗎
  • 簡單的網(wǎng)頁設(shè)計代碼記事本專業(yè)的網(wǎng)站優(yōu)化公司排名
  • 做網(wǎng)站口碑比較好的大公司百度聯(lián)系電話多少
  • 知果果網(wǎng)站誰做的軟文編輯
  • 淘外網(wǎng)站怎么做網(wǎng)站怎么申請怎么注冊
  • 個人做購物網(wǎng)站犯法嗎交換鏈接平臺
  • 做網(wǎng)站用小公司還是大公司2022最火營銷方案
  • 2_網(wǎng)站建設(shè)的一般步驟包含哪些刷seo快速排名