Files
oceanbase/src/rootserver/ob_common_ls_service.cpp
2024-02-07 20:19:21 +00:00

305 lines
13 KiB
C++
Executable File

/**
* Copyright (c) 2021 OceanBase
* OceanBase CE is licensed under Mulan PubL v2.
* You can use this software according to the terms and conditions of the Mulan PubL v2.
* You may obtain a copy of Mulan PubL v2 at:
* http://license.coscl.org.cn/MulanPubL-2.0
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PubL v2 for more details.
*/
#define USING_LOG_PREFIX RS
#include "ob_common_ls_service.h"
#include "ob_ls_service_helper.h"
#include "ob_balance_ls_primary_zone.h"
#include "lib/profile/ob_trace_id.h"
#include "share/ob_errno.h"
#include "share/ob_max_id_fetcher.h"
#include "share/schema/ob_schema_struct.h"//ObTenantInfo
#include "share/ls/ob_ls_creator.h" //ObLSCreator
#include "share/ls/ob_ls_life_manager.h"//ObLSLifeAgentManager
#include "share/ob_primary_zone_util.h"//ObPrimaryZoneUtil
#include "share/ob_share_util.h"//ObShareUtil
#include "share/ob_tenant_info_proxy.h"//ObAllTenantInfo
#include "share/ob_common_rpc_proxy.h"//common_rpc_proxy
#include "observer/ob_server_struct.h"//GCTX
#include "logservice/palf/palf_base_info.h"//PalfBaseInfo
namespace oceanbase
{
using namespace common;
using namespace share;
using namespace transaction;
using namespace palf;
namespace rootserver
{
//////////////ObCommonLSService
int ObCommonLSService::init()
{
int ret = OB_SUCCESS;
if (OB_UNLIKELY(inited_)) {
ret = OB_INIT_TWICE;
LOG_WARN("has inited", KR(ret));
} else if (OB_FAIL(ObTenantThreadHelper::create("COMMONLSSe",
lib::TGDefIDs::SimpleLSService, *this))) {
LOG_WARN("failed to create thread", KR(ret));
} else if (OB_FAIL(ObTenantThreadHelper::start())) {
LOG_WARN("fail to start", KR(ret));
} else {
tenant_id_ = MTL_ID();
inited_ = true;
}
return ret;
}
void ObCommonLSService::destroy()
{
ObTenantThreadHelper::destroy();
tenant_id_ = OB_INVALID_TENANT_ID;
inited_ = false;
}
void ObCommonLSService::do_work()
{
int ret = OB_SUCCESS;
if (OB_UNLIKELY(!inited_)) {
ret = OB_NOT_INIT;
LOG_WARN("not init", K(ret));
} else if (is_user_tenant(tenant_id_)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("is user tenant", KR(ret), K(tenant_id_));
} else if (OB_FAIL(wait_tenant_schema_and_version_ready_(tenant_id_, DATA_VERSION_4_1_0_0))) {
LOG_WARN("failed to wait tenant schema version ready", KR(ret), K(tenant_id_), K(DATA_CURRENT_VERSION));
} else {
int64_t idle_time_us = 1000 * 1000L;//1s
share::schema::ObTenantSchema user_tenant_schema;
int tmp_ret = OB_SUCCESS;
while (!has_set_stop()) {
ret = OB_SUCCESS;
ObCurTraceId::init(GCONF.self_addr_);
if (is_meta_tenant(tenant_id_)) {
const uint64_t user_tenant_id = gen_user_tenant_id(tenant_id_);
if (OB_FAIL(check_can_do_recovery_(user_tenant_id))) {
LOG_WARN("can not do recovery now", KR(ret), K(user_tenant_id));
} else if (OB_FAIL(get_tenant_schema(user_tenant_id, user_tenant_schema))) {
LOG_WARN("failed to get user tenant schema", KR(ret), K(user_tenant_id));
} else if (user_tenant_schema.is_dropping()) {
if (OB_TMP_FAIL(try_force_drop_tenant_(user_tenant_schema))) {
LOG_WARN("failed to force drop tenant", KR(ret), KR(tmp_ret), K(user_tenant_id));
}
} else if (OB_TMP_FAIL(try_create_ls_(user_tenant_schema))) {
LOG_WARN("failed to create ls", KR(ret), KR(tmp_ret), K(user_tenant_schema));
}
if (OB_SUCC(ret) && !user_tenant_schema.is_dropping()) {
if (OB_TMP_FAIL(ObBalanceLSPrimaryZone::try_adjust_user_ls_primary_zone(user_tenant_schema))) {
LOG_WARN("failed to adjust user tenant primary zone", KR(ret), KR(tmp_ret), K(user_tenant_schema));
}
if (OB_TMP_FAIL(try_modify_ls_unit_group_(user_tenant_schema))) {
LOG_WARN("failed to modify ls unit group", KR(ret), KR(tmp_ret), K(user_tenant_schema));
}
}
}
if (OB_TMP_FAIL(ObBalanceLSPrimaryZone::try_update_sys_ls_primary_zone(tenant_id_))) {
LOG_WARN("failed to update sys ls primary zone", KR(ret), KR(tmp_ret), K(tenant_id_));
}
user_tenant_schema.reset();
LOG_INFO("[COMMON_LS_SERVICE] finish one round", KR(ret), KR(tmp_ret), K(idle_time_us));
idle(idle_time_us);
} // end while
}
}
int ObCommonLSService::try_create_ls_(const share::schema::ObTenantSchema &tenant_schema)
{
int ret = OB_SUCCESS;
const uint64_t tenant_id = tenant_schema.get_tenant_id();
if (OB_ISNULL(GCTX.sql_proxy_)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("sql proxy is null", KR(ret), KP(GCTX.sql_proxy_));
} else if (!is_user_tenant(tenant_id) || !tenant_schema.is_valid()) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("tenant is invalid", KR(ret), K(tenant_id), K(tenant_schema));
} else {
share::ObLSStatusInfoArray status_info_array;
share::ObLSStatusOperator ls_op;
ObLSRecoveryStat recovery_stat;
ObLSRecoveryStatOperator ls_recovery_operator;
palf::PalfBaseInfo palf_base_info;
int tmp_ret = OB_SUCCESS;
if (OB_FAIL(ls_op.get_all_ls_status_by_order(
tenant_id, status_info_array, *GCTX.sql_proxy_))) {
LOG_WARN("failed to get all ls status", KR(ret), K(tenant_id));
}
for (int64_t i = 0; OB_SUCC(ret) && i < status_info_array.count(); ++i) {
const ObLSStatusInfo &status_info = status_info_array.at(i);
if (status_info.ls_is_creating()) {
recovery_stat.reset();
if (OB_FAIL(ls_recovery_operator.get_ls_recovery_stat(
tenant_id, status_info.ls_id_, false /*for_update*/,
recovery_stat, *GCTX.sql_proxy_))) {
LOG_WARN("failed to get ls recovery stat", KR(ret), K(tenant_id),
K(status_info));
} else if (OB_FAIL(do_create_user_ls(tenant_schema, status_info,
recovery_stat.get_create_scn(),
false, palf_base_info, OB_INVALID_TENANT_ID/*source_tenant_id*/))) {
LOG_WARN("failed to create new ls", KR(ret), K(status_info),
K(recovery_stat));
}
}
} // end for
}
return ret;
}
//不管是主库还是备库都有概率存在一个日志流组内的日志流记录的unit_group不一致的情况
//所有的日志流都对齐日志流id最小的日志流,虽然不是最优,但是可以保证最终一致性
int ObCommonLSService::try_modify_ls_unit_group_(
const share::schema::ObTenantSchema &tenant_schema)
{
int ret = OB_SUCCESS;
const uint64_t tenant_id = tenant_schema.get_tenant_id();
if (OB_UNLIKELY(!inited_)) {
ret = OB_NOT_INIT;
LOG_WARN("not init", KR(ret));
} else if (OB_ISNULL(GCTX.sql_proxy_)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("ptr is null", KR(ret), KP(GCTX.sql_proxy_));
} else if (!is_user_tenant(tenant_id) || !tenant_schema.is_valid()
|| tenant_schema.is_dropping()) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("tenant is invalid", KR(ret), K(tenant_id), K(tenant_schema));
} else {
ObTenantLSInfo tenant_info(GCTX.sql_proxy_, &tenant_schema, tenant_id);
share::ObLSStatusOperator status_op;
if (OB_FAIL(tenant_info.gather_stat())) {
LOG_WARN("failed to gather stat", KR(ret));
} else {
ObLSGroupInfoArray &ls_group_array = tenant_info.get_ls_group_array();
int64_t index = 0;//no used
share::ObLSStatusInfo ls_status;
for (int64_t i = 0; OB_SUCC(ret) && i < ls_group_array.count(); ++i) {
const uint64_t unit_group_id = ls_group_array.at(i).unit_group_id_;
const uint64_t ls_group_id = ls_group_array.at(i).ls_group_id_;
const ObArray<share::ObLSID> &ls_ids = ls_group_array.at(i).ls_ids_;
for (int64_t j = 0; OB_SUCC(ret) && j < ls_ids.count(); ++j) {
const share::ObLSID ls_id = ls_ids.at(j);
if (OB_FAIL(tenant_info.get_ls_status_info(ls_id, ls_status, index))) {
LOG_WARN("failed to get ls status info", KR(ret), K(ls_id));
} else if (ls_status.unit_group_id_ != unit_group_id) {
FLOG_INFO("ls group has different unit group id, need process", K(ls_status), K(unit_group_id));
if (OB_FAIL(status_op.alter_unit_group_id(tenant_id, ls_id, ls_group_id,
ls_status.unit_group_id_, unit_group_id, *GCTX.sql_proxy_))) {
LOG_WARN("failed to alter unit group", KR(ret), K(tenant_id), K(ls_id),
K(ls_group_id), K(unit_group_id), K(ls_status));
}
}
}//end for j
}//end for i
}
}
return ret;
}
int ObCommonLSService::do_create_user_ls(
const share::schema::ObTenantSchema &tenant_schema,
const share::ObLSStatusInfo &info, const SCN &create_scn,
bool create_with_palf, const palf::PalfBaseInfo &palf_base_info,
const uint64_t source_tenant_id)
{
int ret = OB_SUCCESS;
LOG_INFO("[COMMON_LS_SERVICE] start to create ls", K(info), K(create_scn));
const int64_t start_time = ObTimeUtility::fast_current_time();
if (OB_UNLIKELY(!info.is_valid() || !info.ls_is_creating())) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("info not valid", KR(ret), K(info));
} else {
CK(OB_NOT_NULL(GCTX.sql_proxy_), OB_NOT_NULL(GCTX.srv_rpc_proxy_))
common::ObArray<share::ObZoneReplicaAttrSet> locality_array;
int64_t paxos_replica_num = 0;
ObSchemaGetterGuard guard;//nothing
if (FAILEDx(tenant_schema.get_zone_replica_attr_array(
locality_array))) {
LOG_WARN("failed to get zone locality array", KR(ret));
} else if (OB_FAIL(tenant_schema.get_paxos_replica_num(
guard, paxos_replica_num))) {
LOG_WARN("failed to get paxos replica num", KR(ret));
} else {
ObLSCreator creator(*GCTX.srv_rpc_proxy_, info.tenant_id_,
info.ls_id_, GCTX.sql_proxy_);
if (OB_FAIL(creator.create_user_ls(info, paxos_replica_num,
locality_array, create_scn,
tenant_schema.get_compatibility_mode(),
create_with_palf,
palf_base_info,
source_tenant_id))) {
LOG_WARN("failed to create user ls", KR(ret), K(info), K(locality_array), K(create_scn),
K(palf_base_info), K(create_with_palf), K(source_tenant_id));
}
}
}
const int64_t cost = ObTimeUtility::fast_current_time() - start_time;
LOG_INFO("[COMMON_LS_SERVICE] end to create ls", KR(ret), K(info), K(cost));
return ret;
}
int ObCommonLSService::try_force_drop_tenant_(
const share::schema::ObTenantSchema &tenant_schema)
{
int ret = OB_SUCCESS;
ObTimeoutCtx ctx;
const uint64_t tenant_id = tenant_schema.get_tenant_id();
if (OB_UNLIKELY(!inited_)) {
ret = OB_NOT_INIT;
LOG_WARN("not init", KR(ret));
} else if (OB_ISNULL(GCTX.sql_proxy_)
|| OB_ISNULL(GCTX.rs_rpc_proxy_)
|| OB_ISNULL(GCTX.schema_service_)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("ptr is null", KR(ret), KP(GCTX.sql_proxy_), KP(GCTX.rs_rpc_proxy_),
KP(GCTX.schema_service_));
} else if (!is_user_tenant(tenant_id) || !tenant_schema.is_valid()
|| !tenant_schema.is_dropping()) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("tenant is invalid", KR(ret), K(tenant_id), K(tenant_schema));
} else {
ObLSStatusOperator op;
share::ObLSStatusInfoArray ls_array;
const int64_t start_time = ObTimeUtility::fast_current_time();
if (OB_FAIL(ObShareUtil::set_default_timeout_ctx(ctx, GCONF.internal_sql_execute_timeout))) {
LOG_WARN("fail to set timeout ctx", KR(ret), K(tenant_id));
} else if (OB_FAIL(op.get_all_ls_status_by_order(tenant_id, ls_array, *GCTX.sql_proxy_))) {
LOG_WARN("fail to get all ls status", KR(ret), K(tenant_id));
} else if (ls_array.count() <= 0) {
obrpc::ObDropTenantArg arg;
arg.exec_tenant_id_ = OB_SYS_TENANT_ID;
arg.tenant_name_ = tenant_schema.get_tenant_name();
arg.tenant_id_ = tenant_schema.get_tenant_id();
arg.if_exist_ = true;
arg.delay_to_drop_ = false;
ObSqlString sql;
const int64_t timeout_ts = ctx.get_timeout();
if (OB_FAIL(sql.append_fmt("DROP TENANT IF EXISTS %s FORCE", arg.tenant_name_.ptr()))) {
LOG_WARN("fail to generate sql", KR(ret), K(arg));
} else if (FALSE_IT(arg.ddl_stmt_str_ = sql.string())) {
} else if (OB_FAIL(GCTX.rs_rpc_proxy_->timeout(timeout_ts).drop_tenant(arg))) {
LOG_WARN("fail to drop tenant", KR(ret), K(arg), K(timeout_ts));
}
} else {
// tenant's logstream is still dropping, check next round
}
const int64_t cost = ObTimeUtility::fast_current_time() - start_time;
LOG_INFO("finish try drop tenant", KR(ret), K(tenant_id), K(ls_array),
"timeout", ctx.get_timeout(), K(cost));
}
return ret;
}
}//end of rootserver
}