Files
oceanbase/src/rootserver/ob_schema_revise_executor.cpp
oceanbase-admin cea7de1475 init push
2021-05-31 22:56:52 +08:00

651 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.
*/
#define USING_LOG_PREFIX RS
#include "lib/mysqlclient/ob_mysql_result.h"
#include "share/ob_rpc_struct.h"
#include "share/ob_common_rpc_proxy.h"
#include "share/ob_upgrade_utils.h"
#include "share/config/ob_server_config.h"
#include "share/schema/ob_schema_getter_guard.h"
#include "rootserver/ob_rs_job_table_operator.h"
#include "rootserver/ob_schema_revise_executor.h"
#include "rootserver/ob_ddl_service.h"
#include "sql/engine/ob_exec_context.h"
#include "sql/resolver/expr/ob_raw_expr_util.h"
using namespace oceanbase::common;
using namespace oceanbase::share;
using namespace oceanbase::share::schema;
using namespace oceanbase::rootserver;
using namespace oceanbase::obrpc;
using namespace oceanbase::sql;
int64_t ObSchemaReviseTask::get_deep_copy_size() const
{
return sizeof(*this);
}
ObAsyncTask* ObSchemaReviseTask::deep_copy(char* buf, const int64_t buf_size) const
{
ObAsyncTask* task = nullptr;
int ret = OB_SUCCESS;
const int64_t deep_copy_size = get_deep_copy_size();
if (OB_ISNULL(buf) || buf_size < deep_copy_size) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("invalid arguments", K(ret), KP(buf), K(deep_copy_size), K(buf_size));
} else {
task = new (buf) ObSchemaReviseTask(*executor_);
}
return task;
}
int ObSchemaReviseTask::process()
{
int ret = OB_SUCCESS;
const int64_t start = ObTimeUtility::current_time();
LOG_INFO("[UPGRADE] start to execute revise schema task", K(start));
if (OB_ISNULL(executor_)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("error unexpected, executor must not be NULL", K(ret));
} else if (OB_FAIL(executor_->execute())) {
LOG_WARN("fail to execute revise schema task", K(ret));
}
LOG_INFO("[UPGRADE] finish revise schema task", K(ret), "cost_time", ObTimeUtility::current_time() - start);
return ret;
}
ObSchemaReviseExecutor::ObSchemaReviseExecutor()
: is_inited_(false),
is_stopped_(false),
execute_(false),
rwlock_(),
schema_service_(nullptr),
ddl_service_(nullptr),
sql_proxy_(nullptr),
rpc_proxy_(nullptr),
server_mgr_(nullptr)
{}
int ObSchemaReviseExecutor::init(share::schema::ObMultiVersionSchemaService& schema_service, ObDDLService& ddl_service,
common::ObMySQLProxy& sql_proxy, obrpc::ObSrvRpcProxy& rpc_proxy, ObServerManager& server_mgr)
{
int ret = OB_SUCCESS;
if (OB_UNLIKELY(is_inited_)) {
ret = OB_INIT_TWICE;
LOG_WARN("ObSchemaReviseExecutor has been inited twice", K(ret));
} else {
is_inited_ = true;
is_stopped_ = false;
schema_service_ = &schema_service;
ddl_service_ = &ddl_service;
sql_proxy_ = &sql_proxy;
rpc_proxy_ = &rpc_proxy;
server_mgr_ = &server_mgr;
}
return ret;
}
int ObSchemaReviseExecutor::stop()
{
int ret = OB_SUCCESS;
const uint64_t WAIT_US = 100 * 1000L; // 100ms
const uint64_t MAX_WAIT_US = 10 * 1000 * 1000L; // 10s
const int64_t start = ObTimeUtility::current_time();
{
SpinWLockGuard guard(rwlock_);
is_stopped_ = true;
}
while (OB_SUCC(ret)) {
if (ObTimeUtility::current_time() - start > MAX_WAIT_US) {
ret = OB_TIMEOUT;
LOG_WARN("use too much time", K(ret), "cost_us", ObTimeUtility::current_time() - start);
} else if (!execute_) {
break;
} else {
usleep(WAIT_US);
}
}
return ret;
}
int ObSchemaReviseExecutor::check_stop()
{
int ret = OB_SUCCESS;
bool enable_ddl = GCONF.enable_ddl;
SpinRLockGuard guard(rwlock_);
if (!is_inited_) {
ret = OB_NOT_INIT;
LOG_WARN("not init", K(ret));
} else if (is_stopped_) {
ret = OB_CANCELED;
LOG_WARN("executor should stopped", K(ret));
} else if (enable_ddl) {
ret = OB_CANCELED;
LOG_WARN("executor should stopped", K(ret));
}
return ret;
}
void ObSchemaReviseExecutor::start()
{
SpinWLockGuard guard(rwlock_);
is_stopped_ = false;
}
int ObSchemaReviseExecutor::set_execute_mark()
{
int ret = OB_SUCCESS;
SpinWLockGuard guard(rwlock_);
if (!is_inited_) {
ret = OB_NOT_INIT;
LOG_WARN("not init", K(ret));
} else if (is_stopped_ || execute_) {
ret = OB_OP_NOT_ALLOW;
LOG_WARN("can't run job at the same time", K(ret), K(is_stopped_), K(execute_));
} else {
execute_ = true;
}
return ret;
}
int ObSchemaReviseExecutor::execute()
{
ObCurTraceId::init(GCONF.self_addr_);
int ret = OB_SUCCESS;
if (OB_UNLIKELY(!is_inited_)) {
ret = OB_NOT_INIT;
LOG_WARN("ObSchemaReviseExecutor has not been inited", K(ret));
} else if (OB_FAIL(set_execute_mark())) {
LOG_WARN("fail to set execute mark", K(ret));
} else {
int64_t job_id = OB_INVALID_ID;
bool can_run_job = false;
ObRsJobType job_type = ObRsJobType::JOB_TYPE_SCHEMA_REVISE;
if (OB_FAIL(ObUpgradeUtils::can_run_upgrade_job(job_type, can_run_job))) {
LOG_WARN("fail to check if can run upgrade job now", K(ret), K(job_type));
} else if (!can_run_job) {
ret = OB_OP_NOT_ALLOW;
LOG_WARN("no job exist or success job exist", K(ret));
} else if (OB_FAIL(RS_JOB_CREATE_WITH_RET(job_id, job_type, *sql_proxy_, "tenant_id", 0))) {
LOG_WARN("fail to create rs job", K(ret));
} else if (job_id <= 0) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("job is is invalid", K(ret), K(job_id));
} else if (OB_FAIL(do_schema_revise())) {
LOG_WARN("fail to do schema revise job", K(ret));
}
if (job_id > 0) {
int tmp_ret = OB_SUCCESS;
if (OB_SUCCESS != (tmp_ret = RS_JOB_COMPLETE(job_id, ret, *sql_proxy_))) {
LOG_ERROR("fail to complete job", K(tmp_ret), K(ret), K(job_id));
ret = OB_SUCCESS == ret ? tmp_ret : ret;
}
}
execute_ = false;
}
return ret;
}
int ObSchemaReviseExecutor::check_standby_dml_sync(const obrpc::ObClusterTenantStats& primary_tenant_stats,
const obrpc::ObClusterTenantStats& standby_tenant_stats, bool& schema_sync)
{
int ret = OB_SUCCESS;
int64_t primary_tenant_cnt = primary_tenant_stats.tenant_stats_array_.count();
int64_t standby_tenant_cnt = standby_tenant_stats.tenant_stats_array_.count();
if (primary_tenant_cnt <= 0 || standby_tenant_cnt <= 0) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("invalid cnt", K(ret));
} else if (OB_FAIL(check_stop())) {
LOG_WARN("executor should stopped", K(ret));
} else if (primary_tenant_cnt != standby_tenant_cnt) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN(
"primary_tenant_cnt is not equal to standby_tenant_cnt", K(ret), K(primary_tenant_cnt), K(standby_tenant_cnt));
} else {
schema_sync = true;
for (int64_t i = 0; schema_sync && OB_SUCC(ret) && i < primary_tenant_cnt; i++) {
const TenantIdAndStats& primary = primary_tenant_stats.tenant_stats_array_.at(i);
const TenantIdAndStats& standby = primary_tenant_stats.tenant_stats_array_.at(i);
if (OB_SYS_TENANT_ID == primary.tenant_id_) {
// check normal tenant only
continue;
} else if (primary.tenant_id_ != standby.tenant_id_) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("primary.tenant_id_ is not equal to stanby.tenant_id_",
K(ret),
K(primary.tenant_id_),
K(standby.tenant_id_));
} else {
schema_sync = (primary.min_sys_table_scn_ <= standby.min_sys_table_scn_);
LOG_INFO("check if tenant schema is sync",
K(ret),
K(primary.min_sys_table_scn_),
K(standby.min_sys_table_scn_),
K(schema_sync));
}
}
}
return ret;
}
int ObSchemaReviseExecutor::check_schema_sync()
{
const int64_t start = ObTimeUtility::current_time();
LOG_INFO("[UPGRADE] start to check schema sync", K(start));
int ret = OB_SUCCESS;
bool enable_ddl = GCONF.enable_ddl;
if (!is_inited_) {
ret = OB_NOT_INIT;
LOG_WARN("not inited", K(ret));
} else if (enable_ddl) {
ret = OB_OP_NOT_ALLOW;
LOG_WARN("ddl should disable now", K(ret), K(enable_ddl));
} else {
const int64_t WAIT_US = 1000 * 1000L; // 1 second
bool is_sync = false;
while (OB_SUCC(ret)) {
if (OB_FAIL(check_stop())) {
LOG_WARN("executor is stop", K(ret));
} else if (OB_FAIL(ObUpgradeUtils::check_schema_sync(is_sync))) {
LOG_WARN("fail to check schema sync", K(ret));
} else if (is_sync) {
break;
} else {
LOG_INFO("schema not sync, should wait", K(ret));
usleep(static_cast<useconds_t>((WAIT_US)));
}
}
}
LOG_INFO("[UPGRADE] check schema sync finish", K(ret), "cost_us", ObTimeUtility::current_time() - start);
return ret;
}
int ObSchemaReviseExecutor::compute_check_cst_count_by_tenant(const uint64_t tenant_id, int64_t& check_constraint_count)
{
int ret = OB_SUCCESS;
ObSqlString sql;
SMART_VAR(ObMySQLProxy::MySQLResult, res)
{
common::sqlclient::ObMySQLResult* result = NULL;
if (OB_FAIL(sql.append_fmt("SELECT count(*) as check_constraint_count FROM"))) {
LOG_WARN("failed to append sql", K(ret));
} else if (OB_FAIL(sql.append_fmt(" %s WHERE CONSTRAINT_TYPE = %d AND TENANT_ID = %lu",
OB_ALL_CONSTRAINT_TNAME,
CONSTRAINT_TYPE_CHECK,
tenant_id))) {
LOG_WARN("failed to append sql", K(ret), K(OB_ALL_CONSTRAINT_TNAME), K(tenant_id));
} else if (OB_FAIL(sql_proxy_->read(res, tenant_id, sql.ptr()))) {
LOG_WARN("failed to execute sql", K(ret), K(sql));
} else if (OB_ISNULL(result = res.get_result())) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("failed to get result", K(ret));
} else {
if (OB_SUCC(ret) && OB_SUCC(ret = result->next())) {
EXTRACT_INT_FIELD_MYSQL(*result, "check_constraint_count", check_constraint_count, int64_t);
}
if (OB_SUCC(ret)) {
if (OB_SUCC(ret = result->next())) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("sql result should be only one row", K(ret), K(sql));
} else if (OB_ITER_END == ret) {
ret = OB_SUCCESS;
LOG_INFO("get sql result", K(ret), K(sql));
} else {
LOG_WARN("iter quit", K(ret), K(sql));
}
}
}
}
return ret;
}
// Generate a constraint schema with constraint column information
int ObSchemaReviseExecutor::generate_constraint_schema(
const uint64_t tenant_id, ObIAllocator& allocator, ObSchemaGetterGuard& schema_guard, ObSArray<ObConstraint>& csts)
{
int ret = OB_SUCCESS;
ObRawExprFactory expr_factory(allocator);
ObSQLSessionInfo session;
ObRawExpr* expr = NULL;
ObSqlString sql;
if (OB_FAIL(
session.init(0 /*default session version*/, 0 /*default session id*/, 0 /*default proxy id*/, &allocator))) {
LOG_WARN("init session failed", K(ret));
} else if (OB_FAIL(session.load_default_sys_variable(false, false))) {
LOG_WARN("session load default system variable failed", K(ret));
} else {
// Generate a check constraint object with complete column information
ObResolverParams params;
params.expr_factory_ = &expr_factory;
params.allocator_ = &allocator;
params.session_info_ = &session;
sql.reset();
// Used to query the smallest row of schema version in each check constraint that has not been deleted from
// __all_constraint_history
const static char* SELECT_CST_INFO_SQL =
"SELECT table_id, constraint_id, check_expr, min(schema_version) as schema_version "
"FROM %s "
"WHERE constraint_type = %d or constraint_type is null "
"GROUP BY tenant_id, table_id, constraint_id HAVING SUM(is_deleted) = 0";
SMART_VAR(ObMySQLProxy::MySQLResult, res)
{
common::sqlclient::ObMySQLResult* result = NULL;
if (OB_FAIL(sql.append_fmt(SELECT_CST_INFO_SQL, OB_ALL_CONSTRAINT_HISTORY_TNAME, CONSTRAINT_TYPE_CHECK))) {
LOG_WARN("failed to append sql", K(ret), K(tenant_id));
} else if (OB_FAIL(sql_proxy_->read(res, tenant_id, sql.ptr()))) {
LOG_WARN("failed to execute sql", K(ret), K(sql));
} else if (OB_ISNULL(result = res.get_result())) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("failed to get result", K(ret));
} else {
oceanbase::lib::Worker::CompatMode compat_mode;
while (OB_SUCC(ret) && OB_SUCC(ret = result->next())) {
ObConstraint cst;
const ParseNode* node = NULL;
ObRawExpr* check_constraint_expr = NULL;
const ObTableSchema* table_schema = NULL;
cst.set_tenant_id(tenant_id);
EXTRACT_INT_FIELD_TO_CLASS_MYSQL_WITH_TENANT_ID(*result, table_id, cst, tenant_id);
EXTRACT_INT_FIELD_TO_CLASS_MYSQL(*result, constraint_id, cst, uint64_t);
EXTRACT_INT_FIELD_TO_CLASS_MYSQL(*result, schema_version, cst, int64_t);
EXTRACT_STRBUF_FIELD_TO_CLASS_MYSQL(*result, check_expr, cst, OB_MAX_CONSTRAINT_EXPR_LENGTH);
if (OB_SUCC(ret)) {
if (OB_FAIL(schema_guard.get_tenant_compat_mode(tenant_id, compat_mode))) {
LOG_WARN("get tenant compat mode failed", K(ret));
}
share::CompatModeGuard g(compat_mode);
if (OB_FAIL(ret)) {
} else if (OB_FAIL(check_stop())) {
LOG_WARN("executor is stopped", K(ret));
} else if (OB_FAIL(ObRawExprUtils::parse_bool_expr_node_from_str(
cst.get_check_expr_str(), *params.allocator_, node))) {
LOG_WARN("parse expr node from string failed", K(ret), K(cst));
} else if (OB_FAIL(schema_guard.get_table_schema(cst.get_table_id(), table_schema))) {
LOG_WARN("get table schema failed", K(ret));
} else if (OB_ISNULL(table_schema)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("table_schema is null", K(ret));
} else if (OB_FAIL(ObResolverUtils::resolve_check_constraint_expr(
params, node, *table_schema, cst, check_constraint_expr))) {
LOG_WARN("resolve check constraint expr", K(ret), K(cst));
} else if (OB_FAIL(csts.push_back(cst))) {
LOG_WARN("push back cst to csts failed", K(ret), K(cst));
}
}
}
if (ret != OB_ITER_END) {
LOG_WARN("fail to get sql result, iter quit", K(ret), K(sql));
} else {
ret = OB_SUCCESS;
LOG_INFO("get sql result", K(ret), K(sql));
}
}
}
}
return ret;
}
int ObSchemaReviseExecutor::replace_constraint_column_info_in_inner_table(
const uint64_t tenant_id, ObSArray<ObConstraint>& csts, bool is_history)
{
int ret = OB_SUCCESS;
// Batch replace, replace 100 check constraints at a time
int64_t cst_count = csts.count();
int64_t i = 0;
// First history and then non-history to ensure re-entry
share::ObDMLSqlSplicer dml;
share::ObDMLSqlSplicer history_dml;
ObSqlString sql;
int64_t affected_rows = 0;
const int64_t is_deleted = 0;
const uint64_t exec_tenant_id = ObSchemaUtils::get_exec_tenant_id(tenant_id);
if (OB_ISNULL(sql_proxy_)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("proxy is null", K(ret));
} else {
const int64_t batch_replace_num = 100;
const char* table_name;
if (is_history) {
table_name = OB_ALL_TENANT_CONSTRAINT_COLUMN_HISTORY_TNAME;
} else {
table_name = OB_ALL_TENANT_CONSTRAINT_COLUMN_TNAME;
}
int64_t i = 0;
for (; OB_SUCC(ret) && i < cst_count; ++i) {
for (ObConstraint::const_cst_col_iterator iter = csts.at(i).cst_col_begin();
OB_SUCC(ret) && (iter != csts.at(i).cst_col_end());
++iter) {
if (OB_FAIL(check_stop())) {
LOG_WARN("executor is stopped", K(ret));
} else if (OB_FAIL(dml.add_pk_column("tenant_id",
ObSchemaUtils::get_extract_tenant_id(exec_tenant_id, csts.at(i).get_tenant_id()))) ||
OB_FAIL(dml.add_pk_column(
"table_id", ObSchemaUtils::get_extract_schema_id(exec_tenant_id, csts.at(i).get_table_id()))) ||
OB_FAIL(dml.add_pk_column("constraint_id", csts.at(i).get_constraint_id())) ||
OB_FAIL(dml.add_pk_column("column_id", *iter)) ||
OB_FAIL(dml.add_column("schema_version", csts.at(i).get_schema_version())) ||
OB_FAIL(dml.add_gmt_create()) || OB_FAIL(dml.add_gmt_modified())) {
LOG_WARN("dml add constraint column failed", K(ret));
} else if (is_history && OB_FAIL(dml.add_column("is_deleted", is_deleted))) {
LOG_WARN("add is_deleted column failed", K(ret));
} else if (dml.finish_row()) {
LOG_WARN("fail to finish row", K(ret));
}
}
if (OB_FAIL(ret)) {
} else if (0 == ((i + 1) % batch_replace_num)) {
if (OB_FAIL(check_stop())) {
LOG_WARN("executor is stopped", K(ret));
} else if (OB_FAIL(dml.splice_batch_replace_sql_without_plancache(table_name, sql))) {
LOG_WARN("splice sql failed", K(ret));
} else if (OB_FAIL(sql_proxy_->write(tenant_id, sql.ptr(), affected_rows))) {
LOG_WARN("execute sql failed", K(sql), K(ret));
} else {
dml.reset();
sql.reset();
LOG_INFO("[UPGRADE] batch replace rows", K(ret), K(tenant_id), K(table_name), K(sql));
}
}
}
if (OB_SUCC(ret)) {
if (0 != (i % batch_replace_num)) {
if (OB_FAIL(check_stop())) {
LOG_WARN("executor is stopped", K(ret));
} else if (OB_FAIL(dml.splice_batch_replace_sql_without_plancache(table_name, sql))) {
LOG_WARN("splice sql failed", K(ret));
} else if (OB_FAIL(sql_proxy_->write(tenant_id, sql.ptr(), affected_rows))) {
LOG_WARN("execute sql failed", K(sql), K(ret));
} else {
dml.reset();
LOG_INFO("[UPGRADE] batch replace rows", K(ret), K(tenant_id), K(table_name), K(sql));
}
}
}
}
return ret;
}
int ObSchemaReviseExecutor::do_inner_table_revise_by_tenant(
const uint64_t tenant_id, ObIAllocator& allocator, ObSchemaGetterGuard& schema_guard)
{
int ret = OB_SUCCESS;
ObSqlString sql;
int64_t check_constraint_count = 0;
ObSArray<ObConstraint> csts;
if (OB_FAIL(compute_check_cst_count_by_tenant(tenant_id, check_constraint_count))) {
LOG_WARN("compute check cst count in tenant failed", K(ret), K(tenant_id), K(check_constraint_count));
} else if (OB_FAIL(csts.reserve(check_constraint_count))) {
LOG_WARN("reserve failed for csts", K(ret), K(check_constraint_count));
} else if (OB_FAIL(generate_constraint_schema(tenant_id, allocator, schema_guard, csts))) {
LOG_WARN("generate constraint schema failed", K(ret), K(tenant_id), K(csts));
} else if (OB_FAIL(replace_constraint_column_info_in_inner_table(tenant_id, csts, true))) {
LOG_WARN("replace constraint_column_info in __all_tenant_constraint_column failed", K(ret), K(tenant_id), K(csts));
} else if (OB_FAIL(replace_constraint_column_info_in_inner_table(tenant_id, csts, false))) {
LOG_WARN("replace constraint_column_info in __all_tenant_constraint_column_history failed",
K(ret),
K(tenant_id),
K(csts));
} else {
LOG_INFO("[UPGRRADE] do inner table revise for one tenant finish", K(ret), K(tenant_id));
}
return ret;
}
// Supplementary data:
// If it is the main database:
// need to go to each tenant to supplement the data;
// if it is the standby database:
// need to process the process of sys tenant supplement data,
// and other tenants will synchronize to the standby database according to the modification of the main database.
int ObSchemaReviseExecutor::do_inner_table_revise()
{
int ret = OB_SUCCESS;
ObSchemaGetterGuard schema_guard;
ObArray<uint64_t> tenant_ids;
ObArenaAllocator allocator(ObModIds::OB_SQL_EXPR);
if (OB_ISNULL(ddl_service_)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("schema_service is null", K(ret));
} else if (OB_FAIL(
ddl_service_->get_tenant_schema_guard_with_version_in_inner_table(OB_SYS_TENANT_ID, schema_guard))) {
LOG_WARN("get schema guard failed", K(ret));
} else if (OB_FAIL(schema_guard.get_tenant_ids(tenant_ids))) {
LOG_WARN("get tenant ids failed", K(ret));
} else {
bool is_standby_cluster = GCTX.is_standby_cluster();
for (int64_t i = tenant_ids.size() - 1; (i >= 0) && OB_SUCC(ret); --i) {
const uint64_t tenant_id = tenant_ids.at(i);
if (OB_FAIL(check_stop())) {
LOG_WARN("executor should stopped", K(ret));
} else if (is_standby_cluster && (OB_SYS_TENANT_ID == tenant_id)) {
LOG_INFO("skip normal tenant in standby cluster", K(ret), K(tenant_id));
} else if (OB_FAIL(check_schema_sync())) {
LOG_WARN("fail to check schema sync", K(ret));
} else if (OB_FAIL(ddl_service_->get_tenant_schema_guard_with_version_in_inner_table(tenant_id, schema_guard))) {
LOG_WARN("fail to get tenant schema guard", K(ret), K(tenant_id));
} else if (OB_FAIL(do_inner_table_revise_by_tenant(tenant_id, allocator, schema_guard))) {
LOG_WARN("fail to do inner table revise", K(ret), K(tenant_id));
}
}
if (OB_SUCC(ret)) {
LOG_INFO("[UPGRRADE] do inner table revise for all tenants finish", K(ret));
}
}
return ret;
}
int ObSchemaReviseExecutor::flush_schema_kv_cache()
{
int ret = OB_SUCCESS;
const int64_t TIMEOUT = 100 * 1000 * 1000L; // 100s for handle flush schema kv cache
if (OB_ISNULL(GCTX.rs_rpc_proxy_) || OB_ISNULL(GCTX.rs_mgr_)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("invalid global context", K(ret));
} else {
int tmp_ret;
int64_t retry_times_left = 10;
obrpc::ObFlushCacheArg arg;
arg.cache_type_ = CACHE_TYPE_SCHEMA;
ObSEArray<ObAddr, SEARRAY_INIT_NUM> active_server_list;
ObSEArray<ObAddr, SEARRAY_INIT_NUM> inactive_server_list;
if (OB_FAIL(server_mgr_->get_servers_by_status(active_server_list, inactive_server_list))) {
LOG_WARN("fail to get all servers", K(ret));
} else if (inactive_server_list.count() > 0) {
ret = OB_NOT_SUPPORTED;
LOG_ERROR("cannot do this job when exist a server is inactive", K(ret), K(inactive_server_list));
} else {
for (int64_t i = 0; OB_SUCC(ret) && (i < active_server_list.count()); ++i) {
retry_times_left = 10;
while (OB_SUCC(ret) && (retry_times_left > 0)) {
if (OB_FAIL(rpc_proxy_->to(active_server_list.at(i)).timeout(TIMEOUT).flush_cache(arg))) {
if (OB_TIMEOUT == ret || OB_WAITQUEUE_TIMEOUT == ret) {
LOG_INFO("flush schema kv cache timeout, need retry",
K(ret),
K(retry_times_left),
K(active_server_list.at(i)));
--retry_times_left;
tmp_ret = ret;
ret = OB_SUCCESS;
} else {
LOG_WARN("fail to flush schema kv cache", K(ret), K(active_server_list.at(i)));
}
} else {
LOG_INFO("[UPGRRADE] flush schema kv cache of observer finish", K(ret), K(active_server_list.at(i)));
break;
}
}
if (OB_SUCC(ret) && (0 == retry_times_left)) {
ret = tmp_ret;
LOG_WARN("fail to flush schema kv cache", K(ret), K(active_server_list.at(i)));
}
}
}
}
return ret;
}
int ObSchemaReviseExecutor::do_schema_revise()
{
int ret = OB_SUCCESS;
bool enable_ddl = GCONF.enable_ddl;
const int64_t start = ObTimeUtility::current_time();
LOG_INFO("[UPGRADE] execute job schema_revise start", K(start));
if (!is_inited_) {
ret = OB_NOT_INIT;
LOG_WARN("not init", K(ret));
} else if (OB_FAIL(check_stop())) {
LOG_WARN("executor should stopped", K(ret));
} else if (enable_ddl) {
ret = OB_OP_NOT_ALLOW;
LOG_WARN("split schema while enable_ddl is on not allowed", K(ret), K(enable_ddl));
} else if (OB_FAIL(do_inner_table_revise())) {
LOG_WARN("do inner table revise failed", K(ret));
} else if (OB_FAIL(flush_schema_kv_cache())) {
LOG_WARN("flush schema kv cache failed", K(ret));
}
LOG_INFO("[UPGRADE] execute job schema_revise finish", K(ret), "cost_us", ObTimeUtility::current_time() - start);
return ret;
}
int ObSchemaReviseExecutor::can_execute()
{
int ret = OB_SUCCESS;
SpinWLockGuard guard(rwlock_);
if (!is_inited_) {
ret = OB_NOT_INIT;
LOG_WARN("not init", K(ret));
} else if (is_stopped_) {
ret = OB_OP_NOT_ALLOW;
LOG_WARN("status not matched", K(ret), "stopped", is_stopped_ ? "true" : "false");
}
return ret;
}