Files
oceanbase/src/rootserver/ob_root_inspection.cpp

1968 lines
80 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_root_inspection.h"
#include "lib/string/ob_sql_string.h"
#include "lib/mysqlclient/ob_mysql_proxy.h"
#include "lib/utility/ob_tracepoint.h"
#include "share/inner_table/ob_inner_table_schema.h"
#include "share/schema/ob_multi_version_schema_service.h"
#include "share/schema/ob_schema_getter_guard.h"
#include "share/schema/ob_schema_utils.h"
#include "share/ob_zone_info.h"
#include "share/system_variable/ob_system_variable_factory.h"
#include "share/system_variable/ob_system_variable_init.h"
#include "rootserver/ob_root_utils.h"
#include "rootserver/ob_zone_manager.h"
#include "rootserver/ob_ddl_operator.h"
#include "rootserver/ob_root_service.h"
#include "observer/ob_server_struct.h"
#include "observer/ob_sql_client_decorator.h"
#include "share/ob_primary_zone_util.h"
#include "share/ob_upgrade_utils.h"
#include "share/rc/ob_context.h"
#include "share/schema/ob_schema_mgr.h"
#include "share/ob_schema_status_proxy.h"//ObSchemaStatusProxy
#include "share/ob_global_stat_proxy.h"//ObGlobalStatProxy
#include "share/ob_tenant_info_proxy.h" // ObAllTenantInfoProxy
#include "share/schema/ob_table_schema.h"
namespace oceanbase
{
using namespace common;
using namespace common::sqlclient;
using namespace share;
using namespace share::schema;
using namespace sql;
namespace rootserver
{
////////////////////////////////////////////////////////////////
int ObTenantChecker::inspect(bool &passed, const char* &warning_info)
{
int ret = OB_SUCCESS;
int tmp_ret = OB_SUCCESS;
passed = true;
UNUSED(warning_info);
if (OB_SUCCESS != (tmp_ret = alter_tenant_primary_zone_())) {
ret = OB_SUCC(ret) ? tmp_ret : ret;
LOG_WARN("fail to alter tenant primary_zone", KR(ret), KR(tmp_ret));
}
if (OB_SUCCESS != (tmp_ret = check_create_tenant_end_())) {
ret = OB_SUCC(ret) ? tmp_ret : ret;
LOG_WARN("fail to check create tenant end", KR(ret), KR(tmp_ret));
}
if (OB_SUCCESS != (tmp_ret = check_garbage_tenant_(passed))) {
ret = OB_SUCC(ret) ? tmp_ret : ret;
LOG_WARN("fail to check garbage tenant", KR(ret), KR(tmp_ret));
}
return ret;
}
// If the primary_zone of tenant is null, need to set to 'RANDOM'
int ObTenantChecker::alter_tenant_primary_zone_()
{
int ret = OB_SUCCESS;
ObSchemaGetterGuard schema_guard;
ObArray<uint64_t> tenant_ids;
if (OB_ISNULL(schema_service_)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("schema service not init", K(ret));
} else if (OB_FAIL(schema_service_->get_tenant_schema_guard(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 {
const ObTenantSchema *tenant_schema = NULL;
int64_t affected_rows = 0;
FOREACH_CNT_X(tenant_id, tenant_ids, OB_SUCCESS == ret) {
if (OB_ISNULL(tenant_id)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("tenant_id is null", K(ret));
} else if (OB_FAIL(schema_guard.get_tenant_info(*tenant_id, tenant_schema))) {
LOG_WARN("fail to get tenant info", K(ret), K(*tenant_id));
} else if (OB_ISNULL(tenant_schema)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("tenant schema is null", K(ret), K(*tenant_id));
} else if (tenant_schema->get_primary_zone().empty()) {
ObSqlString sql;
if (OB_FAIL(sql.append_fmt("ALTER TENANT %s set primary_zone = RANDOM",
tenant_schema->get_tenant_name()))) {
LOG_WARN("fail to generate sql", K(ret), K(*tenant_id));
} else if (OB_ISNULL(sql_proxy_)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("sql_proxy is null", K(ret));
} else if (OB_FAIL(sql_proxy_->write(sql.ptr(), affected_rows))) {
LOG_WARN("execute sql failed", K(ret));
} else {
ROOTSERVICE_EVENT_ADD("inspector", "alter_tenant_primary_zone",
"tenant_id", tenant_schema->get_tenant_id(),
"tenant", tenant_schema->get_tenant_name());
}
}
}
}
return ret;
}
int ObTenantChecker::check_create_tenant_end_()
{
int ret = OB_SUCCESS;
ObSchemaGetterGuard schema_guard;
ObArray<uint64_t> tenant_ids;
if (OB_ISNULL(schema_service_)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("schema service not init", K(ret));
} else if (!schema_service_->is_sys_full_schema()) {
// skip
} else if (GCTX.is_standby_cluster()) {
// skip
} else if (OB_FAIL(schema_service_->get_tenant_ids(tenant_ids))) {
LOG_WARN("get_tenant_ids failed", K(ret));
} else if (OB_ISNULL(GCTX.root_service_)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("rootservice is null", KR(ret));
} else {
const ObSimpleTenantSchema *tenant_schema = NULL;
int64_t schema_version = OB_INVALID_VERSION;
int64_t baseline_schema_version = OB_INVALID_VERSION;
FOREACH_CNT(tenant_id, tenant_ids) {
// overwrite ret
if (!GCTX.root_service_->is_full_service()) {
ret = OB_CANCELED;
LOG_WARN("rs is not in full service", KR(ret));
break;
} else if (OB_FAIL(schema_service_->get_tenant_schema_guard(*tenant_id, schema_guard))) {
LOG_WARN("get_schema_guard failed", KR(ret), K(*tenant_id));
} else if (OB_FAIL(schema_guard.get_schema_version(*tenant_id, schema_version))) {
LOG_WARN("fail to get tenant schema version", KR(ret), K(*tenant_id));
} else if (!share::schema::ObSchemaService::is_formal_version(schema_version)) {
// tenant is still in creating
} else if (OB_FAIL(schema_guard.get_tenant_info(*tenant_id, tenant_schema))) {
LOG_WARN("fail to get tenant schema", KR(ret), K(*tenant_id));
} else if (OB_ISNULL(tenant_schema)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("tenant not exist", KR(ret), K(*tenant_id));
} else if (OB_FAIL(schema_service_->get_baseline_schema_version(*tenant_id, false/*auto update*/,
baseline_schema_version))) {
LOG_WARN("fail to get baseline schema_version", KR(ret), K(*tenant_id));
} else if (OB_INVALID_VERSION == baseline_schema_version) {
//baseline_schema_version is not valid, just skip to create this kind of tenant
} else if (tenant_schema->is_creating()) {
obrpc::ObCreateTenantEndArg arg;
arg.exec_tenant_id_ = OB_SYS_TENANT_ID;
arg.tenant_id_ = *tenant_id;
if (OB_FAIL(rpc_proxy_.create_tenant_end(arg))) {
LOG_WARN("fail to execute create tenant end", KR(ret), K(*tenant_id));
} else {
LOG_INFO("execute create_tenant_end", KR(ret), K(*tenant_id), K(schema_version));
ROOTSERVICE_EVENT_ADD("inspector", "tenant_checker", "info", "execute create_tenant_end", "tenant_id", *tenant_id);
}
}
}
}
return ret;
}
int ObTenantChecker::check_garbage_tenant_(bool &passed)
{
int ret = OB_SUCCESS;
if (OB_ISNULL(schema_service_)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("schema service not init", KR(ret));
} else if (!schema_service_->is_sys_full_schema()) {
// skip
} else {
obrpc::ObGetSchemaArg arg;
obrpc::ObTenantSchemaVersions result;
ObSchemaGetterGuard schema_guard;
arg.ignore_fail_ = true;
arg.exec_tenant_id_ = OB_SYS_TENANT_ID;
const int64_t rpc_timeout = GCONF.rpc_timeout * 10;
// There may have multi RootService, so we won't force drop tenant here.
if (OB_FAIL(rpc_proxy_.timeout(rpc_timeout).get_tenant_schema_versions(arg, result))) {
LOG_WARN("fail to get tenant schema versions", KR(ret));
} else if (OB_FAIL(schema_service_->get_tenant_schema_guard(OB_SYS_TENANT_ID, schema_guard))) {
LOG_WARN("get_schema_guard failed", KR(ret));
}
for (int64_t i = 0; OB_SUCC(ret) && i < result.tenant_schema_versions_.count(); i++) {
TenantIdAndSchemaVersion &tenant = result.tenant_schema_versions_.at(i);
int tmp_ret = OB_SUCCESS;
if (!GCTX.root_service_->is_full_service()) {
ret = OB_CANCELED;
LOG_WARN("rs is not in full service", KR(ret));
} else if (!ObSchemaService::is_formal_version(tenant.schema_version_)) {
const ObSimpleTenantSchema *tenant_schema = NULL;
uint64_t tenant_id = tenant.tenant_id_;
if (OB_SUCCESS != (tmp_ret = schema_guard.get_tenant_info(tenant_id, tenant_schema))) {
LOG_WARN("fail to get tenant info", KR(tmp_ret), K(tenant_id));
} else if (OB_ISNULL(tenant_schema)) {
tmp_ret = OB_TENANT_NOT_EXIST;
} else if (tenant_schema->is_restore()) {
LOG_INFO("tenant is in restore", KPC(tenant_schema));
} else if (tenant_schema->is_creating()) {
LOG_ERROR("the tenant may be in the process of creating, if the error reports continuously, please check", K(tenant_id));
LOG_DBA_WARN(OB_ERR_ROOT_INSPECTION, "msg", "the tenant may be in the process of creating, if the error reports continuously, please check",
K(tenant_id), "tenant_name", tenant_schema->get_tenant_name());
ROOTSERVICE_EVENT_ADD("inspector", "tenant_checker",
"info", "the tenant may be in the process of creating, if the error reports continuously, please check",
"tenant_id", tenant_id,
"tenant_name", tenant_schema->get_tenant_name_str());
}
ret = OB_SUCC(ret) ? tmp_ret : ret;
}
} // end for
passed = OB_SUCC(ret);
}
return ret;
}
////////////////////////////////////////////////////////////////
ObTableGroupChecker::ObTableGroupChecker(share::schema::ObMultiVersionSchemaService &schema_service)
: schema_service_(schema_service),
check_part_option_map_(),
part_option_not_match_set_(),
allocator_(ObModIds::OB_SCHEMA),
is_inited_(false)
{
}
int ObTableGroupChecker::init()
{
int ret = OB_SUCCESS;
if (is_inited_) {
ret = OB_INIT_TWICE;
LOG_WARN("init twice", K(ret));
} else if (OB_FAIL(check_part_option_map_.create(TABLEGROUP_BUCKET_NUM, ObModIds::OB_HASH_BUCKET_TABLEGROUP_MAP))) {
LOG_WARN("init check_part_option_map failed", K(ret));
} else if (OB_FAIL(part_option_not_match_set_.create(TABLEGROUP_BUCKET_NUM))) {
LOG_WARN("init part_option_not_match_set failed", K(ret));
} else {
is_inited_ = true;
}
return ret;
}
ObTableGroupChecker::~ObTableGroupChecker()
{
}
int ObTableGroupChecker::inspect(bool &passed, const char* &warning_info)
{
int ret = OB_SUCCESS;
passed = true;
ObArray<uint64_t> tenant_ids;
if (!is_inited_) {
ret = OB_NOT_INIT;
LOG_WARN("tablegroup checker is not init", K(ret));
} else if (OB_FAIL(schema_service_.get_tenant_ids(tenant_ids))) {
LOG_WARN("fail to get tenant ids", KR(ret));
} else {
int tmp_ret = OB_SUCCESS;
FOREACH(tenant_id, tenant_ids) { // ignore error for each tenant
if (OB_SUCCESS != (tmp_ret = inspect_(*tenant_id, passed))) {
LOG_WARN("inspect tablegroup options by tenant failed",
KR(tmp_ret), "tenant_id", *tenant_id);
}
ret = OB_SUCC(ret) ? tmp_ret : ret;
}
if (!passed) {
warning_info = "tablegroup has tables that have different primary_zone/locality/part_option";
}
}
return ret;
}
int ObTableGroupChecker::inspect_(
const uint64_t tenant_id,
bool &passed)
{
int ret = OB_SUCCESS;
ObSchemaGetterGuard schema_guard;
allocator_.reset();
check_part_option_map_.reuse();
part_option_not_match_set_.reuse();
ObArray<uint64_t> table_ids;
if (!is_inited_) {
ret = OB_NOT_INIT;
LOG_WARN("tablegroup checker is not init", KR(ret));
} else if (OB_FAIL(schema_service_.get_tenant_schema_guard(tenant_id, schema_guard))) {
LOG_WARN("get schema guard failed", KR(ret), K(tenant_id));
} else if (OB_FAIL(schema_guard.get_table_ids_in_tenant(tenant_id, table_ids))) {
LOG_WARN("fail to get table_ids", KR(ret), K(tenant_id));
} else if (OB_ISNULL(GCTX.root_service_)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("rootservice is null", KR(ret));
} else if (!GCTX.root_service_->is_full_service()) {
ret = OB_CANCELED;
LOG_WARN("rs is not in full service", KR(ret));
} else {
for (int64_t i = 0; OB_SUCC(ret) && i < table_ids.count(); i++) {
const uint64_t table_id = table_ids.at(i);
const ObTableSchema *table = NULL;
// schema guard cannot be used repeatedly in iterative logic,
// otherwise it will cause a memory hike in schema cache
if (!GCTX.root_service_->is_full_service()) {
ret = OB_CANCELED;
LOG_WARN("rs is not in full service", KR(ret));
} else if (OB_FAIL(schema_service_.get_tenant_schema_guard(tenant_id, schema_guard))) {
LOG_WARN("get schema guard failed", K(ret), K(tenant_id));
} else if (OB_FAIL(schema_guard.get_table_schema(tenant_id, table_id, table))) {
LOG_WARN("get table schema failed", K(ret), KT(table_id));
} else if (OB_ISNULL(table)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("table not exist", KR(ret), K(table_id));
} else if (is_sys_table(table->get_table_id()) || !table->has_partition()) {
// skip, check the partitioned user table
} else if (OB_FAIL(check_part_option(*table, schema_guard))) {
LOG_WARN("check part option fail", KR(ret), KPC(table));
} else {}
}
}
if (OB_SUCC(ret)) {
if (part_option_not_match_set_.size() > 0) {
passed = false;
LOG_WARN("tables part option in one tablegroup are not the same", K(tenant_id), K_(part_option_not_match_set));
ROOTSERVICE_EVENT_ADD("inspector", "check_part_option", K(tenant_id), K_(part_option_not_match_set));
}
}
return ret;
}
// Check the partition_option of tables in the same tablegroup:
// 1. For tablegroups created before 2.0, the part_type and part_num of tables in tablegroup should be same.
// 2. For tablegroups created after 2.0:
// 1) tablegroup is nonpartition, Allow "non partitioned table" or "partitioned table with 1 number of partitions" in tablegroup.
// in addition, the partition_num, partition_type, partition_value and number of expression vectors of tables must be same.
// 2) tablegroup is partitioned, the partition_num, partition_type, partition_value and number of expression vectors
// of tables in tablegroup should be same.
int ObTableGroupChecker::check_part_option(const ObSimpleTableSchemaV2 &table, ObSchemaGetterGuard &schema_guard)
{
int ret = OB_SUCCESS;
int tmp_ret = OB_SUCCESS;
ObSqlString user_error;
const uint64_t tenant_id = table.get_tenant_id();
const uint64_t tablegroup_id = table.get_tablegroup_id();
if (!is_inited_) {
ret = OB_NOT_INIT;
LOG_WARN("tablegroup checker is not init", KR(ret));
} else if (OB_INVALID_ID == tablegroup_id) {
// skip check while tablegroup_id is default value
} else if (!table.is_user_table()) {
// only check user table
} else if (OB_HASH_NOT_EXIST != (tmp_ret = part_option_not_match_set_.exist_refactored(tablegroup_id))) {
//skip check while already in part_option_not_match_set_
if (OB_HASH_EXIST != tmp_ret) {
ret = tmp_ret;
LOG_WARN("fail to check if tablegroup_id exist", KR(ret), K(tablegroup_id));
}
} else {
const ObSimpleTableSchemaV2 *table_in_map = NULL;
bool is_matched = true;
const ObTablegroupSchema *tablegroup = NULL;
const ObSimpleTableSchemaV2 *primary_table_schema = NULL;
if (OB_FAIL(schema_guard.get_tablegroup_schema(tenant_id, tablegroup_id, tablegroup))) {
LOG_WARN("fail to get tablegroup schema", KR(ret), K(tenant_id), KT(tablegroup_id));
} else if (OB_ISNULL(tablegroup)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("tablegroup schema is null", KR(ret), KT(tablegroup_id));
} else if (tablegroup->get_sharding() == OB_PARTITION_SHARDING_NONE) {
//no need to check,just ignore
} else if (tablegroup->get_sharding() == OB_PARTITION_SHARDING_PARTITION
|| tablegroup->get_sharding() == OB_PARTITION_SHARDING_ADAPTIVE) {
bool check_sub_part = tablegroup->get_sharding() == OB_PARTITION_SHARDING_PARTITION ? false : true;
if (OB_FAIL(check_part_option_map_.get_refactored(tablegroup_id, table_in_map))) {
//set to the map while not in check_part_option_map_
if (OB_HASH_NOT_EXIST == ret) {
ObSimpleTableSchemaV2 *new_table_schema = NULL;
if (OB_FAIL(schema_guard.get_primary_table_schema_in_tablegroup(tenant_id, tablegroup_id, primary_table_schema))) {
LOG_WARN("fail to get primary table schema in tablegroup", KR(ret), K(tablegroup_id));
} else if (OB_ISNULL(primary_table_schema)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("primary table schema is NULL", KR(ret), K(tenant_id), K(tablegroup_id));
} else if (OB_FAIL(ObSchemaUtils::alloc_schema(allocator_, *primary_table_schema, new_table_schema))) {
LOG_WARN("alloc schema failed", KR(ret), KPC(primary_table_schema));
} else if (OB_FAIL(check_part_option_map_.set_refactored(tablegroup_id, new_table_schema))) {
LOG_WARN("set table_schema in hashmap fail", KR(ret), K(tablegroup_id), KPC(primary_table_schema));
}
} else {
LOG_WARN("check tablegroup_id in hashmap fail", KR(ret), K(tablegroup_id));
}
} else if (OB_ISNULL(table_in_map)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("table_is_map is NULL", KR(ret), K(tablegroup_id));
} else if (OB_FAIL(ObSimpleTableSchemaV2::compare_partition_option(table, *table_in_map, check_sub_part, is_matched, &user_error))) {
LOG_WARN("fail to check partition option", KR(ret), K(table), KPC(table_in_map));
}
} else {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("sharding type not suit", KR(ret), KPC(tablegroup));
}
if (OB_FAIL(ret) || is_matched) {
//skip
} else if (OB_FAIL(part_option_not_match_set_.set_refactored(tablegroup_id))) {
LOG_WARN("set tablegroup_id in hashset fail", KR(ret));
} else if (OB_ISNULL(table_in_map)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("table_is_map is NULL", KR(ret), K(tablegroup_id));
} else {
LOG_INFO("tables in one tablegroup have different part/subpart option",
K(tablegroup_id), "table_id", table.get_table_id(), K(user_error), K(table_in_map->get_table_id()));
}
}
return ret;
}
////////////////////////////////////////////////////////////////
ObInspector::ObInspector(ObRootService &rs)
:ObAsyncTimerTask(rs.get_inspect_task_queue()),
rs_(rs)
{}
int ObInspector::process()
{
// @todo ObTaskController::get().switch_task(share::ObTaskType::ROOT_SERVICE);
int ret = OB_SUCCESS;
ObTableGroupChecker tablegroup_checker(rs_.get_schema_service());
ObRootInspection system_schema_checker;
ObTenantChecker tenant_checker(rs_.get_schema_service(), rs_.get_sql_proxy(), rs_.get_common_rpc_proxy());
ret = OB_E(EventTable::EN_STOP_ROOT_INSPECTION) OB_SUCCESS;
if (OB_FAIL(ret)) {
} else if (OB_FAIL(tablegroup_checker.init())) {
LOG_WARN("init tablegroup_checker failed", K(ret));
} else if (OB_FAIL(system_schema_checker.init(rs_.get_schema_service(), rs_.get_zone_mgr(),
rs_.get_sql_proxy()))) {
LOG_WARN("init root inspection failed", K(ret));
} else {
ObInspectionTask *inspection_tasks[] = {
&tablegroup_checker,
&system_schema_checker,
&tenant_checker
};
bool passed = true;
const char* warning_info = NULL;
int N = ARRAYSIZEOF(inspection_tasks);
for (int i = 0; i < N; ++i) {
passed = true;
warning_info = NULL;
int tmp_ret = inspection_tasks[i]->inspect(passed, warning_info);
if (OB_SUCCESS != tmp_ret) {
LOG_WARN("inpection task failed", K(tmp_ret), K(i), "task", inspection_tasks[i]->get_task_name());
} else if (passed) {
LOG_INFO("inspection task succ", K(i), "task", inspection_tasks[i]->get_task_name());
} else {
LOG_ERROR(warning_info);
ROOTSERVICE_EVENT_ADD("inspector", inspection_tasks[i]->get_task_name(),
"info", (warning_info == NULL ? "": warning_info));
}
}
}
return ret;
}
ObAsyncTask *ObInspector::deep_copy(char *buf, const int64_t buf_size) const
{
ObInspector *task = NULL;
if (NULL == buf || buf_size < static_cast<int64_t>(sizeof(*this))) {
LOG_WARN_RET(OB_BUF_NOT_ENOUGH, "buffer not large enough", K(buf_size));
} else {
task = new(buf) ObInspector(rs_);
}
return task;
}
////////////////////////////////////////////////////////////////
ObPurgeRecyclebinTask::ObPurgeRecyclebinTask(ObRootService &rs)
:ObAsyncTimerTask(rs.get_inspect_task_queue()),
root_service_(rs)
{}
int ObPurgeRecyclebinTask::process()
{
LOG_INFO("purge recyclebin task begin");
int ret = OB_SUCCESS;
const int64_t PURGE_EACH_TIME = 1000;
int64_t delay = 1 * 60 * 1000 * 1000;
int64_t expire_time = GCONF.recyclebin_object_expire_time;
int64_t purge_interval = GCONF._recyclebin_object_purge_frequency;
if (expire_time > 0 && purge_interval > 0) {
if (OB_FAIL(root_service_.purge_recyclebin_objects(PURGE_EACH_TIME))) {
LOG_WARN("fail to purge recyclebin objects", KR(ret));
}
delay = purge_interval;
}
// the error code is only for outputtion log, the function will return success.
// the task no need retry, because it will be triggered periodically.
if (OB_FAIL(root_service_.schedule_recyclebin_task(delay))) {
LOG_WARN("schedule purge recyclebin task failed", KR(ret), K(delay));
} else {
LOG_INFO("submit purge recyclebin task success", K(delay));
}
LOG_INFO("purge recyclebin task end", K(delay));
return OB_SUCCESS;
}
ObAsyncTask *ObPurgeRecyclebinTask::deep_copy(char *buf, const int64_t buf_size) const
{
ObPurgeRecyclebinTask *task = NULL;
if (NULL == buf || buf_size < static_cast<int64_t>(sizeof(*this))) {
LOG_WARN_RET(OB_BUF_NOT_ENOUGH, "buffer not large enough", K(buf_size));
} else {
task = new(buf) ObPurgeRecyclebinTask(root_service_);
}
return task;
}
ObRootInspection::ObRootInspection()
: inited_(false), stopped_(false), zone_passed_(false),
sys_param_passed_(false), sys_stat_passed_(false),
sys_table_schema_passed_(false), data_version_passed_(false),
all_checked_(false), all_passed_(false), can_retry_(false),
sql_proxy_(NULL), rpc_proxy_(NULL), schema_service_(NULL),
zone_mgr_(NULL)
{
}
ObRootInspection::~ObRootInspection()
{
}
int ObRootInspection::init(ObMultiVersionSchemaService &schema_service,
ObZoneManager &zone_mgr,
ObMySQLProxy &sql_proxy,
obrpc::ObCommonRpcProxy *rpc_proxy)
{
int ret = OB_SUCCESS;
if (inited_) {
ret = OB_INIT_TWICE;
LOG_WARN("init twice", K(ret));
} else {
schema_service_ = &schema_service;
zone_mgr_ = &zone_mgr;
sql_proxy_ = &sql_proxy;
stopped_ = false;
zone_passed_ = false;
sys_param_passed_ = false;
sys_stat_passed_ = false;
sys_table_schema_passed_ = false;
data_version_passed_ = false;
all_checked_ = false;
all_passed_ = false;
can_retry_ = false;
rpc_proxy_ = rpc_proxy;
inited_ = true;
}
return ret;
}
int ObRootInspection::check_all()
{
int ret = OB_SUCCESS;
if (!inited_) {
ret = OB_NOT_INIT;
LOG_WARN("not init", K(ret));
} else if (OB_FAIL(check_cancel())) {
LOG_WARN("check_cancel failed", K(ret));
} else if (OB_ISNULL(schema_service_)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("schema_service is null", K(ret));
} else if (!schema_service_->is_tenant_full_schema(OB_SYS_TENANT_ID)) {
ret = OB_EAGAIN;
LOG_WARN("schema is not ready, try again", K(ret));
} else {
can_retry_ = false;
int tmp = OB_SUCCESS;
// check __all_zone
if (OB_SUCCESS != (tmp = check_zone())) {
LOG_WARN("check_zone failed", K(tmp));
ret = (OB_SUCCESS == ret) ? tmp : ret;
}
zone_passed_ = (OB_SUCCESS == tmp);
// check sys stat
tmp = OB_SUCCESS;
if (OB_SUCCESS != (tmp = check_sys_stat_())) {
LOG_WARN("check_sys_stat failed", K(tmp));
ret = (OB_SUCCESS == ret) ? tmp : ret;
}
sys_stat_passed_ = (OB_SUCCESS == tmp);
// check sys param
tmp = OB_SUCCESS;
if (OB_SUCCESS != (tmp = check_sys_param_())) {
LOG_WARN("check_sys_param failed", K(tmp));
ret = (OB_SUCCESS == ret) ? tmp : ret;
}
sys_param_passed_ = (OB_SUCCESS == tmp);
// check sys schema
tmp = OB_SUCCESS;
if (OB_SUCCESS != (tmp = check_sys_table_schemas_())) {
LOG_WARN("check_sys_table_schemas failed", K(tmp));
ret = (OB_SUCCESS == ret) ? tmp : ret;
}
sys_table_schema_passed_ = (OB_SUCCESS == tmp);
// check tenant's data version
tmp = OB_SUCCESS;
if (OB_SUCCESS != (tmp = check_data_version_())) {
LOG_WARN("check_data_version failed", K(tmp));
ret = (OB_SUCCESS == ret) ? tmp : ret;
}
data_version_passed_ = (OB_SUCCESS == tmp);
// upgrade job may still running, in order to avoid the upgrade process error stuck,
// ignore the 4674 error
for (int64_t i = 0; i < UPGRADE_JOB_TYPE_COUNT; i++) {
tmp = OB_SUCCESS;
ObRsJobType job_type = upgrade_job_type_array[i];
if (job_type > JOB_TYPE_INVALID && job_type < JOB_TYPE_MAX) {
if (OB_SUCCESS != (tmp = check_cancel())) {
LOG_WARN("check_cancel failed", KR(ret), K(tmp));
ret = (OB_SUCCESS == ret) ? tmp : ret;
break;
} else if (OB_SUCCESS != (tmp = ObUpgradeUtils::check_upgrade_job_passed(job_type))) {
LOG_WARN("fail to check upgrade job passed", K(tmp), K(job_type));
if (OB_RUN_JOB_NOT_SUCCESS != tmp) {
ret = (OB_SUCCESS == ret) ? tmp : ret;
} else {
LOG_WARN("upgrade job may still running, check with __all_virtual_uprade_inspection",
K(ret), K(tmp), "job_type", ObRsJobTableOperator::get_job_type_str(job_type));
}
}
}
}
all_checked_ = true;
all_passed_ = OB_SUCC(ret);
}
return ret;
}
int ObRootInspection::check_tenant(const uint64_t tenant_id)
{
int ret = OB_SUCCESS;
if (!inited_) {
ret = OB_NOT_INIT;
LOG_WARN("not init", KR(ret));
} else if (OB_FAIL(check_cancel())) {
LOG_WARN("check_cancel failed", KR(ret));
} else {
int tmp_ret = OB_SUCCESS;
if (OB_TMP_FAIL(check_sys_stat_(tenant_id))) {
LOG_WARN("fail to check sys stat", KR(tmp_ret), K(tenant_id));
ret = OB_SUCC(ret) ? tmp_ret : ret;
}
if (OB_TMP_FAIL(check_sys_param_(tenant_id))) {
LOG_WARN("fail to check param", KR(tmp_ret), K(tenant_id));
ret = OB_SUCC(ret) ? tmp_ret : ret;
}
if (OB_TMP_FAIL(check_sys_table_schemas_(tenant_id))) {
LOG_WARN("fail to check sys table", KR(tmp_ret), K(tenant_id));
ret = OB_SUCC(ret) ? tmp_ret : ret;
}
}
return ret;
}
int ObRootInspection::inspect(bool &passed, const char* &warning_info)
{
int ret = OB_SUCCESS;
if (!GCONF.in_upgrade_mode()) {
ret = check_all();
if (OB_SUCC(ret)) {
passed = all_passed_;
warning_info = "system metadata error";
}
} else {
passed = true;
}
return ret;
}
// standby tenant may stay at lower data version,
// root_inspection won't check standby tenant's schema.
int ObRootInspection::construct_tenant_ids_(
common::ObIArray<uint64_t> &tenant_ids)
{
int ret = OB_SUCCESS;
tenant_ids.reset();
ObArray<uint64_t> standby_tenants;
ObArray<uint64_t> tmp_tenants;
if (!inited_) {
ret = OB_NOT_INIT;
LOG_WARN("not init", KR(ret));
} else if (OB_FAIL(check_cancel())) {
LOG_WARN("check_cancel failed", KR(ret));
} else if (OB_FAIL(ObTenantUtils::get_tenant_ids(schema_service_, tmp_tenants))) {
LOG_WARN("get_tenant_ids failed", KR(ret));
} else {
bool is_standby = false;
for (int64_t i = 0; OB_SUCC(ret) && i < tmp_tenants.count(); i++) {
const uint64_t tenant_id = tmp_tenants.at(i);
if (OB_FAIL(ObAllTenantInfoProxy::is_standby_tenant(sql_proxy_, tenant_id, is_standby))) {
LOG_WARN("fail to check is standby tenant", KR(ret), K(tenant_id));
} else if (is_standby) {
// skip
} else if (OB_FAIL(tenant_ids.push_back(tenant_id))) {
LOG_WARN("fail to push back tenant_id", KR(ret), K(tenant_id));
}
} // end for
}
return ret;
}
int ObRootInspection::check_zone()
{
int ret = OB_SUCCESS;
ObSqlString extra_cond;
HEAP_VAR(ObGlobalInfo, global_zone_info) {
ObArray<ObZoneInfo> zone_infos;
ObArray<const char *> global_zone_item_names;
if (!inited_) {
ret = OB_NOT_INIT;
LOG_WARN("not init", K(ret));
} else if (OB_FAIL(check_cancel())) {
LOG_WARN("check_cancel failed", K(ret));
} else if (OB_FAIL(extra_cond.assign_fmt("zone = '%s'", global_zone_info.zone_.ptr()))) {
LOG_WARN("extra_cond assign_fmt failed", K(ret));
} else if (OB_FAIL(get_names(global_zone_info.list_, global_zone_item_names))) {
LOG_WARN("get global zone item names failed", K(ret));
} else if (OB_FAIL(check_names(OB_SYS_TENANT_ID, OB_ALL_ZONE_TNAME, global_zone_item_names, extra_cond))) {
LOG_WARN("check global zone item names failed", "table_name", OB_ALL_ZONE_TNAME,
K(global_zone_item_names), K(extra_cond), K(ret));
} else if (OB_FAIL(zone_mgr_->get_zone(zone_infos))) {
LOG_WARN("zone manager get_zone failed", K(ret));
} else {
ObArray<const char *> zone_item_names;
FOREACH_CNT_X(zone_info, zone_infos, OB_SUCCESS == ret) {
zone_item_names.reuse();
extra_cond.reset();
if (OB_FAIL(check_cancel())) {
LOG_WARN("check_cancel failed", K(ret));
} else if (OB_FAIL(extra_cond.assign_fmt("zone = '%s'", zone_info->zone_.ptr()))) {
LOG_WARN("extra_cond assign_fmt failed", K(ret));
} else if (OB_FAIL(get_names(zone_info->list_, zone_item_names))) {
LOG_WARN("get zone item names failed", K(ret));
} else if (OB_FAIL(check_names(OB_SYS_TENANT_ID, OB_ALL_ZONE_TNAME, zone_item_names, extra_cond))) {
LOG_WARN("check zone item names failed", "table_name", OB_ALL_ZONE_TNAME,
K(zone_item_names), "zone_info", *zone_info, K(extra_cond), K(ret));
}
}
}
}
return ret;
}
int ObRootInspection::check_sys_stat_()
{
int ret = OB_SUCCESS;
ObArray<uint64_t> tenant_ids;
if (!inited_) {
ret = OB_NOT_INIT;
LOG_WARN("not init", KR(ret));
} else if (OB_ISNULL(schema_service_)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("schema_service is null", KR(ret));
} else if (OB_FAIL(check_cancel())) {
LOG_WARN("check_cancel failed", KR(ret));
} else if (OB_FAIL(construct_tenant_ids_(tenant_ids))) {
LOG_WARN("get_tenant_ids failed", KR(ret));
} else {
int backup_ret = OB_SUCCESS;
int tmp_ret = OB_SUCCESS;
FOREACH_CNT_X(tenant_id, tenant_ids, OB_SUCC(ret)) {
if (OB_FAIL(check_cancel())) {
LOG_WARN("check_cancel failed", KR(ret));
} else if (OB_TMP_FAIL(check_sys_stat_(*tenant_id))) {
LOG_WARN("fail to check sys stat", KR(tmp_ret), K(*tenant_id));
backup_ret = OB_SUCCESS == backup_ret ? tmp_ret : backup_ret;
}
} // end foreach
ret = OB_SUCC(ret) ? backup_ret : ret;
}
return ret;
}
int ObRootInspection::check_sys_stat_(const uint64_t tenant_id)
{
int ret = OB_SUCCESS;
ObArray<const char *> sys_stat_names;
ObSqlString extra_cond;
ObSysStat sys_stat;
const uint64_t exec_tenant_id = ObSchemaUtils::get_exec_tenant_id(tenant_id);
if (!inited_) {
ret = OB_NOT_INIT;
LOG_WARN("not init", KR(ret));
} else if (OB_ISNULL(schema_service_)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("schema_service is null", KR(ret));
} else if (OB_FAIL(check_cancel())) {
LOG_WARN("check_cancel failed", KR(ret));
} else if (OB_FAIL(check_tenant_status_(tenant_id))) {
LOG_WARN("fail to check tenant status", KR(ret), K(tenant_id));
} else if (OB_FAIL(sys_stat.set_initial_values(tenant_id))) {
LOG_WARN("set initial values failed", KR(ret), K(tenant_id));
} else if (OB_FAIL(extra_cond.assign_fmt("tenant_id = %lu",
ObSchemaUtils::get_extract_tenant_id(exec_tenant_id, tenant_id)))) {
LOG_WARN("extra_cond assign_fmt failed", KR(ret), K(tenant_id));
} else if (OB_FAIL(get_names(sys_stat.item_list_, sys_stat_names))) {
LOG_WARN("get sys stat names failed", KR(ret), K(tenant_id));
} else if (OB_FAIL(check_names(tenant_id, OB_ALL_SYS_STAT_TNAME, sys_stat_names, extra_cond))) {
LOG_WARN("check all sys stat names failed", K(ret), K(tenant_id),
"table_name", OB_ALL_SYS_STAT_TNAME, K(sys_stat_names));
}
return ret;
}
int ObRootInspection::check_sys_param_()
{
int ret = OB_SUCCESS;
ObArray<uint64_t> tenant_ids;
if (!inited_) {
ret = OB_NOT_INIT;
LOG_WARN("not init", KR(ret));
} else if (OB_ISNULL(schema_service_)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("schema_service is null", KR(ret));
} else if (OB_FAIL(check_cancel())) {
LOG_WARN("check_cancel failed", KR(ret));
} else if (OB_FAIL(construct_tenant_ids_(tenant_ids))) {
LOG_WARN("get_tenant_ids failed", KR(ret));
} else {
int backup_ret = OB_SUCCESS;
int tmp_ret = OB_SUCCESS;
FOREACH_CNT_X(tenant_id, tenant_ids, OB_SUCC(ret)) {
if (OB_FAIL(check_cancel())) {
LOG_WARN("check_cancel failed", K(ret));
} else if (OB_TMP_FAIL(check_sys_param_(*tenant_id))) {
LOG_WARN("fail to check sys param", KR(tmp_ret), K(*tenant_id));
backup_ret = OB_SUCCESS == backup_ret ? tmp_ret : backup_ret;
}
} // end foreach
ret = OB_SUCC(ret) ? backup_ret : ret;
}
return ret;
}
int ObRootInspection::check_sys_param_(const uint64_t tenant_id)
{
int ret = OB_SUCCESS;
ObArray<uint64_t> tenant_ids;
ObArray<const char *> sys_param_names;
ObSqlString extra_cond;
const uint64_t exec_tenant_id = ObSchemaUtils::get_exec_tenant_id(tenant_id);
if (!inited_) {
ret = OB_NOT_INIT;
LOG_WARN("not init", KR(ret));
} else if (OB_ISNULL(schema_service_)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("schema_service is null", KR(ret));
} else if (OB_FAIL(check_cancel())) {
LOG_WARN("check_cancel failed", KR(ret));
} else if (OB_FAIL(check_tenant_status_(tenant_id))) {
LOG_WARN("fail to check tenant status", KR(ret), K(tenant_id));
} else if (OB_FAIL(extra_cond.assign_fmt("tenant_id = %lu",
ObSchemaUtils::get_extract_tenant_id(exec_tenant_id, tenant_id)))) {
LOG_WARN("extra_cond assign_fmt failed", KR(ret), K(tenant_id));
} else if (OB_FAIL(get_sys_param_names(sys_param_names))) {
LOG_WARN("get sys param names failed", KR(ret), K(tenant_id));
} else if (OB_FAIL(check_names(tenant_id, OB_ALL_SYS_VARIABLE_TNAME,
sys_param_names, extra_cond))) {
LOG_WARN("check all sys params names failed", KR(ret), K(tenant_id),
"table_name", OB_ALL_SYS_VARIABLE_TNAME, K(sys_param_names), K(extra_cond));
}
if (OB_SCHEMA_ERROR != ret) {
} else if (GCONF.in_upgrade_mode()) {
LOG_WARN("check sys_variable failed", KR(ret));
} else {
LOG_DBA_ERROR(OB_ERR_ROOT_INSPECTION, "msg", "system variables are unmatched", KR(ret));
}
return ret;
}
template<typename Item>
int ObRootInspection::get_names(const ObDList<Item> &list, ObIArray<const char*> &names)
{
int ret = OB_SUCCESS;
if (!inited_) {
ret = OB_NOT_INIT;
LOG_WARN("not init", K(ret));
} else if (list.get_size() <= 0) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("list is empty", K(ret));
} else {
const Item *it = list.get_first();
while (OB_SUCCESS == ret && it != list.get_header()) {
if (OB_FAIL(names.push_back(it->name_))) {
LOG_WARN("push_back failed", K(ret));
} else {
it = it->get_next();
}
}
}
return ret;
}
int ObRootInspection::get_sys_param_names(ObIArray<const char *> &names)
{
int ret = OB_SUCCESS;
if (!inited_) {
ret = OB_NOT_INIT;
LOG_WARN("not init", K(ret));
} else {
const int64_t param_count = ObSysVariables::get_amount();
for (int64_t i = 0; OB_SUCC(ret) && i < param_count; ++i) {
if (OB_FAIL(names.push_back(ObSysVariables::get_name(i).ptr()))) {
LOG_WARN("push_back failed", K(ret));
}
}
}
return ret;
}
int ObRootInspection::check_names(const uint64_t tenant_id,
const char *table_name,
const ObIArray<const char *> &names,
const ObSqlString &extra_cond)
{
int ret = OB_SUCCESS;
if (!inited_) {
ret = OB_NOT_INIT;
LOG_WARN("not init", K(ret));
} else if (OB_FAIL(check_cancel())) {
LOG_WARN("check_cancel failed", K(ret));
} else if (NULL == table_name || names.count() <= 0) {
// extra_cond can be empty, so wo don't check it here
ret = OB_INVALID_ARGUMENT;
LOG_WARN("table_name is null or names is empty", KP(table_name), K(names), K(ret));
} else {
ObArray<Name> fetch_names; // Get the data of the internal table
ObArray<Name> extra_names; // data inner table more than hard code
ObArray<Name> miss_names; // data inner table less than hard code
if (OB_FAIL(calc_diff_names(tenant_id, table_name, names, extra_cond,
fetch_names, extra_names, miss_names))) {
LOG_WARN("fail to calc diff names", K(ret), KP(table_name), K(names), K(extra_cond));
} else {
if (fetch_names.count() <= 0) {
// don't need to set ret
LOG_WARN("maybe tenant or zone has been deleted, ignore it",
K(tenant_id), K(table_name), K(extra_cond));
} else {
if (extra_names.count() > 0) {
// don't need to set ret
LOG_WARN("some item exist in table, but not hard coded",
K(tenant_id), K(table_name), K(extra_names));
}
if (miss_names.count() > 0) {
ret = OB_ENTRY_NOT_EXIST;
LOG_WARN("some item exist in hard code, but not exist in inner table",
K(ret), K(tenant_id), K(table_name), K(miss_names));
}
}
}
}
return ret;
}
int ObRootInspection::calc_diff_names(const uint64_t tenant_id,
const char *table_name,
const ObIArray<const char *> &names,
const ObSqlString &extra_cond,
ObIArray<Name> &fetch_names, /* data reading from inner table*/
ObIArray<Name> &extra_names, /* data inner table more than hard code*/
ObIArray<Name> &miss_names /* data inner table less than hard code*/)
{
int ret = OB_SUCCESS;
ObRefreshSchemaStatus schema_status;
schema_status.tenant_id_ = tenant_id;
fetch_names.reset();
if (!inited_) {
ret = OB_NOT_INIT;
LOG_WARN("not init", K(ret));
} else if (OB_INVALID_TENANT_ID == tenant_id) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("invalid tenant_id", KR(ret), K(tenant_id));
} else if (OB_FAIL(check_cancel())) {
LOG_WARN("check_cancel failed", KR(ret), K(tenant_id));
} else if (NULL == table_name || names.count() <= 0) {
// extra_cond can be empty, don't need to check it
ret = OB_INVALID_ARGUMENT;
LOG_WARN("table_name is null or names is empty",
KR(ret), K(tenant_id), KP(table_name), K(names));
} else if (GCTX.is_standby_cluster() && is_user_tenant(tenant_id)) {
if (OB_ISNULL(GCTX.schema_status_proxy_)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("schema status proxy is null", K(ret));
} else if (OB_FAIL(GCTX.schema_status_proxy_->get_refresh_schema_status(tenant_id, schema_status))) {
LOG_WARN("fail to get schema status", KR(ret), K(tenant_id));
}
}
if (OB_SUCC(ret)) {
const uint64_t exec_tenant_id = schema_status.tenant_id_;
int64_t snapshot_timestamp = schema_status.snapshot_timestamp_;
ObSqlString sql;
ObSQLClientRetryWeak sql_client_retry_weak(sql_proxy_,
snapshot_timestamp);
if (OB_FAIL(sql.append_fmt("SELECT name FROM %s%s%s", table_name,
(extra_cond.empty()) ? "" : " WHERE ", extra_cond.ptr()))) {
LOG_WARN("append_fmt failed", KR(ret), K(tenant_id), K(table_name), K(extra_cond));
} else {
SMART_VAR(ObMySQLProxy::MySQLResult, res) {
ObMySQLResult *result = NULL;
if (OB_FAIL(sql_client_retry_weak.read(res, exec_tenant_id, sql.ptr()))) {
LOG_WARN("execute sql failed", KR(ret), K(tenant_id), K(sql));
can_retry_ = true;
} else if (OB_ISNULL(result = res.get_result())) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("result is not expected to be NULL",
KR(ret), K(tenant_id), "result", OB_P(result));
} else {
//only for filling the out parameter,
//Ensure that there is no '\ 0' character in the middle of the corresponding string
int64_t tmp_real_str_len = 0;
Name name;
while (OB_SUCC(ret)) {
if (OB_FAIL(result->next())) {
if (OB_ITER_END == ret) {
ret = OB_SUCCESS;
break;
} else {
LOG_WARN("get next result failed", KR(ret), K(tenant_id));
}
} else {
EXTRACT_STRBUF_FIELD_MYSQL(*result, "name", name.ptr(),
static_cast<int64_t>(NAME_BUF_LEN), tmp_real_str_len);
(void) tmp_real_str_len; // make compiler happy
if (OB_FAIL(fetch_names.push_back(name))) {
LOG_WARN("push_back failed", KR(ret), K(tenant_id));
}
}
}
}
}
}
if (OB_SUCC(ret)) {
if (fetch_names.count() <= 0) {
LOG_WARN("maybe tenant or zone has been deleted, ignore it",
KR(ret), K(schema_status), K(table_name), K(extra_cond));
} else {
extra_names.reset();
miss_names.reset();
FOREACH_CNT_X(fetch_name, fetch_names, OB_SUCCESS == ret) {
bool found = false;
FOREACH_CNT_X(name, names, OB_SUCC(ret)) {
if (Name(*name) == *fetch_name) {
found = true;
break;
}
}
if (!found) {
if (OB_FAIL(extra_names.push_back(*fetch_name))) {
LOG_WARN("fail to push name into fetch_names",
KR(ret), K(tenant_id), K(*fetch_name), K(fetch_names));
}
}
}
FOREACH_CNT_X(name, names, OB_SUCCESS == ret) {
bool found = false;
FOREACH_CNT_X(fetch_name, fetch_names, OB_SUCCESS == ret) {
if (Name(*name) == *fetch_name) {
found = true;
break;
}
}
if (!found) {
if (OB_FAIL(miss_names.push_back(Name(*name)))) {
LOG_WARN("fail to push name into miss_names",
KR(ret), K(tenant_id), K(*name), K(miss_names));
}
}
}
}
}
}
return ret;
}
int ObRootInspection::check_sys_table_schemas_()
{
int ret = OB_SUCCESS;
ObArray<uint64_t> tenant_ids;
if (OB_UNLIKELY(!inited_)) {
ret = OB_NOT_INIT;
LOG_WARN("not init", KR(ret));
} else if (OB_FAIL(check_cancel())) {
LOG_WARN("check_cancel failed", KR(ret));
} else if (OB_ISNULL(schema_service_)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("schema_service is null", KR(ret));
} else if (OB_FAIL(construct_tenant_ids_(tenant_ids))) {
LOG_WARN("get_tenant_ids failed", KR(ret));
} else {
int backup_ret = OB_SUCCESS;
int tmp_ret = OB_SUCCESS;
FOREACH_X(tenant_id, tenant_ids, OB_SUCC(ret)) {
if (OB_FAIL(check_cancel())) {
LOG_WARN("check_cancel failed", KR(ret));
} else if (OB_TMP_FAIL(check_sys_table_schemas_(*tenant_id))) {
LOG_WARN("fail to check sys table schemas by tenant", KR(tmp_ret), K(*tenant_id));
backup_ret = OB_SUCCESS == backup_ret ? tmp_ret : backup_ret;
}
} // end foreach
ret = OB_SUCC(ret) ? backup_ret : ret;
}
return ret;
}
int ObRootInspection::check_sys_table_schemas_(
const uint64_t tenant_id)
{
int ret = OB_SUCCESS;
int64_t schema_version = OB_INVALID_VERSION;
if (OB_UNLIKELY(!inited_)) {
ret = OB_NOT_INIT;
LOG_WARN("not init", KR(ret));
} else if (OB_FAIL(check_cancel())) {
LOG_WARN("check_cancel failed", KR(ret));
} else if (OB_UNLIKELY(
is_virtual_tenant_id(tenant_id)
|| OB_INVALID_TENANT_ID == tenant_id)) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("invalid tenant_id", KR(ret), K(tenant_id));
} else {
const schema_create_func *creator_ptr_array[] = {
share::all_core_table_schema_creator,
share::core_table_schema_creators,
share::sys_table_schema_creators,
share::virtual_table_schema_creators,
share::sys_view_schema_creators,
share::core_index_table_schema_creators,
share::sys_index_table_schema_creators,
NULL };
int back_ret = OB_SUCCESS;
int tmp_ret = OB_SUCCESS;
ObTableSchema table_schema;
bool exist = false;
for (const schema_create_func **creator_ptr_ptr = creator_ptr_array;
OB_SUCC(ret) && OB_NOT_NULL(*creator_ptr_ptr); ++creator_ptr_ptr) {
for (const schema_create_func *creator_ptr = *creator_ptr_ptr;
OB_SUCC(ret) && OB_NOT_NULL(*creator_ptr); ++creator_ptr) {
table_schema.reset();
if (OB_FAIL(check_cancel())) {
LOG_WARN("check_cancel failed", KR(ret));
} else if (OB_FAIL(check_tenant_status_(tenant_id))) {
LOG_WARN("fail to check tenant status", KR(ret), K(tenant_id));
} else if (OB_FAIL((*creator_ptr)(table_schema))) {
LOG_WARN("create table schema failed", KR(ret));
} else if (!is_sys_tenant(tenant_id)
&& OB_FAIL(ObSchemaUtils::construct_tenant_space_full_table(
tenant_id, table_schema))) {
LOG_WARN("fail to construct tenant space table", KR(ret), K(tenant_id));
} else if (OB_FAIL(ObSysTableChecker::is_inner_table_exist(
tenant_id, table_schema, exist))) {
LOG_WARN("fail to check inner table exist",
KR(ret), K(tenant_id), K(table_schema));
} else if (!exist) {
// skip
} else {
if (OB_TMP_FAIL(check_table_schema(tenant_id, table_schema))) {
// don't print table_schema, otherwise log will be too much
LOG_WARN("check table schema failed", KR(tmp_ret), K(tenant_id),
"table_id", table_schema.get_table_id(), "table_name", table_schema.get_table_name());
back_ret = OB_SUCCESS == back_ret ? tmp_ret : back_ret;
}
if (OB_TMP_FAIL(check_sys_view_(tenant_id, table_schema))) {
LOG_WARN("check sys view failed", KR(tmp_ret), K(tenant_id),
"table_id", table_schema.get_table_id(), "table_name", table_schema.get_table_name());
back_ret = OB_SUCCESS == back_ret ? tmp_ret : back_ret;
// sql may has occur other error except OB_SCHEMA_ERROR, we should not continue is such situation.
if (OB_SCHEMA_ERROR != tmp_ret) {
ret = OB_SUCC(ret) ? back_ret : tmp_ret;
}
}
}
} // end for
} // end for
ret = OB_SUCC(ret) ? back_ret : ret;
}
if (OB_SCHEMA_ERROR != ret) {
} else if (GCONF.in_upgrade_mode()) {
LOG_WARN("check sys table schema failed", KR(ret), K(tenant_id));
} else {
LOG_ERROR("check sys table schema failed", KR(ret), K(tenant_id));
LOG_DBA_ERROR(OB_ERR_ROOT_INSPECTION, "msg", "inner tables are unmatched", KR(ret), K(tenant_id));
}
return ret;
}
int ObRootInspection::check_table_schema(
const uint64_t tenant_id,
const ObTableSchema &hard_code_table)
{
int ret = OB_SUCCESS;
const ObTableSchema *table = NULL;
ObSchemaGetterGuard schema_guard;
if (OB_UNLIKELY(!inited_)) {
ret = OB_NOT_INIT;
LOG_WARN("not init", KR(ret));
} else if (OB_UNLIKELY(
is_virtual_tenant_id(tenant_id)
|| OB_INVALID_TENANT_ID == tenant_id)) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("invalid tenant_id", KR(ret), K(tenant_id));
} else if (OB_UNLIKELY(!hard_code_table.is_valid())) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("invalid table_schema", KR(ret), K(tenant_id), K(hard_code_table));
} else if (OB_FAIL(schema_service_->get_tenant_schema_guard(tenant_id, schema_guard))) {
LOG_WARN("failed to get schema guard", KR(ret), K(tenant_id));
} else if (OB_FAIL(schema_guard.get_table_schema(
tenant_id, hard_code_table.get_table_id(), table))) {
LOG_WARN("get_table_schema failed", KR(ret), K(tenant_id),
"table_id", hard_code_table.get_table_id(),
"table_name", hard_code_table.get_table_name());
// fail may cause by load table schema sql, set retry flag.
can_retry_ = true;
} else if (OB_ISNULL(table)) {
ret = OB_SCHEMA_ERROR;
LOG_WARN("table should not be null", KR(ret), K(tenant_id),
"table_id", hard_code_table.get_table_id(),
"table_name", hard_code_table.get_table_name());
can_retry_ = true;
} else if (OB_FAIL(check_table_schema(hard_code_table, *table))) {
LOG_WARN("fail to check table schema", KR(ret), K(tenant_id), K(hard_code_table), KPC(table));
}
return ret;
}
int ObRootInspection::check_table_schema(const ObTableSchema &hard_code_table,
const ObTableSchema &inner_table)
{
int ret = OB_SUCCESS;
if (!hard_code_table.is_valid()
|| !inner_table.is_valid()) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("invalid table_schema", K(hard_code_table), K(inner_table), K(ret));
} else if (OB_FAIL(check_table_options_(inner_table, hard_code_table))) {
LOG_WARN("check_table_options failed", "table_id", hard_code_table.get_table_id(), K(ret));
} else if (!inner_table.is_view_table()) { //view table do not check column info
if (hard_code_table.get_column_count() != inner_table.get_column_count()) {
ret = OB_SCHEMA_ERROR;
LOG_WARN("column count mismatch", "table_id", inner_table.get_table_id(),
"table_name",inner_table.get_table_name(), "table_column_cnt",inner_table.get_column_count(),
"hard_code_table_column_cnt", hard_code_table.get_column_count(), K(ret));
} else {
int back_ret = OB_SUCCESS;
for (int64_t i = 0; OB_SUCC(ret) && i < hard_code_table.get_column_count(); ++i) {
const ObColumnSchemaV2 *hard_code_column = hard_code_table.get_column_schema_by_idx(i);
const ObColumnSchemaV2 *column = NULL;
if (NULL == hard_code_column) {
ret = OB_SCHEMA_ERROR;
LOG_WARN("hard_code_column is null", "hard_code_column", OB_P(hard_code_column), K(ret));
} else if (NULL == (column = inner_table.get_column_schema(
hard_code_column->get_column_name()))) {
ret = OB_SCHEMA_ERROR;
LOG_WARN("hard code column not found", "table_id", hard_code_table.get_table_id(),
"table_name", hard_code_table.get_table_name(), "column",
hard_code_column->get_column_name(), K(ret));
} else {
const bool ignore_column_id = is_virtual_table(hard_code_table.get_table_id());
if (OB_FAIL(check_column_schema_(hard_code_table.get_table_name(),
*column, *hard_code_column, ignore_column_id))) {
LOG_WARN("column schema mismatch with hard code column schema",
"table_name",inner_table.get_table_name(), "column", *column,
"hard_code_column", *hard_code_column, K(ret));
}
}
back_ret = OB_SUCCESS == back_ret ? ret : back_ret;
ret = OB_SUCCESS;
}
ret = back_ret;
}
}
return ret;
}
int ObRootInspection::check_and_get_system_table_column_diff(
const share::schema::ObTableSchema &table_schema,
const share::schema::ObTableSchema &hard_code_schema,
common::ObIArray<uint64_t> &add_column_ids,
common::ObIArray<uint64_t> &alter_column_ids)
{
int ret = OB_SUCCESS;
add_column_ids.reset();
alter_column_ids.reset();
if (!table_schema.is_valid() || !hard_code_schema.is_valid()) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("invalid table_schema", KR(ret), K(table_schema), K(hard_code_schema));
} else if (table_schema.get_tenant_id() != hard_code_schema.get_tenant_id()
|| table_schema.get_table_id() != hard_code_schema.get_table_id()
|| 0 != table_schema.get_table_name_str().compare(hard_code_schema.get_table_name_str())
|| !is_system_table(table_schema.get_table_id())) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("invalid table_schema", KR(ret),
"tenant_id", table_schema.get_tenant_id(),
"table_id", table_schema.get_table_id(),
"table_name", table_schema.get_table_name(),
"hard_code_tenant_id", hard_code_schema.get_tenant_id(),
"hard_code_table_id", hard_code_schema.get_table_id(),
"hard_code_table_name", hard_code_schema.get_table_name());
} else {
const uint64_t tenant_id = table_schema.get_tenant_id();
const uint64_t table_id = table_schema.get_table_id();
const ObColumnSchemaV2 *column = NULL;
const ObColumnSchemaV2 *hard_code_column = NULL;
ObColumnSchemaV2 tmp_column; // check_column_can_be_altered_online() may change dst_column, is ugly.
bool ignore_column_id = false;
// case 1. check if columns should be dropped.
// case 2. check if column can be altered online.
for (int64_t i = 0; OB_SUCC(ret) && i < table_schema.get_column_count(); i++) {
column = table_schema.get_column_schema_by_idx(i);
if (OB_ISNULL(column)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("column schema is null", KR(ret), K(tenant_id), K(table_id), K(i));
} else if (OB_ISNULL(hard_code_column = hard_code_schema.get_column_schema(column->get_column_id()))) {
ret = OB_NOT_SUPPORTED; // case 1
LOG_WARN("can't drop system table's column", KR(ret),
K(tenant_id), K(table_id),
"table_name", table_schema.get_table_name(),
"column_id", column->get_column_id(),
"column_name", column->get_column_name());
} else {
// case 2
int tmp_ret = check_column_schema_(table_schema.get_table_name_str(),
*column,
*hard_code_column,
ignore_column_id);
if (OB_SUCCESS == tmp_ret) {
// not changed
} else if (OB_SCHEMA_ERROR != tmp_ret) {
ret = tmp_ret;
LOG_WARN("fail to check column schema", KR(ret),
K(tenant_id), K(table_id), KPC(column), KPC(hard_code_column));
} else if (OB_FAIL(tmp_column.assign(*hard_code_column))) {
LOG_WARN("fail to assign hard code column schema", KR(ret),
K(tenant_id), K(table_id), "column_id", hard_code_column->get_column_id());
} else if (OB_FAIL(table_schema.check_column_can_be_altered_online(column, &tmp_column))) {
LOG_WARN("fail to check alter column online", KR(ret),
K(tenant_id), K(table_id),
"table_name", table_schema.get_table_name(),
"column_id", column->get_column_id(),
"column_name", column->get_column_name());
} else if (OB_FAIL(alter_column_ids.push_back(column->get_column_id()))) {
LOG_WARN("fail to push back column_id", KR(ret), K(tenant_id), K(table_id),
"column_id", column->get_column_id());
}
}
} // end for
// case 3: check if columns should be added.
for (int64_t i = 0; OB_SUCC(ret) && i < hard_code_schema.get_column_count(); i++) {
hard_code_column = hard_code_schema.get_column_schema_by_idx(i);
if (OB_ISNULL(hard_code_column)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("column schema is null", KR(ret), K(tenant_id), K(table_id), K(i));
} else if (OB_NOT_NULL(column = table_schema.get_column_schema(hard_code_column->get_column_id()))) {
// column exist, just skip
} else {
const uint64_t hard_code_column_id = hard_code_column->get_column_id();
const ObColumnSchemaV2 *last_column = NULL;
if (table_schema.get_column_count() <= 0
|| OB_ISNULL(last_column = table_schema.get_column_schema_by_idx(
table_schema.get_column_count() - 1))) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("invalid column count or column", KR(ret), K(table_schema));
} else if (table_schema.get_max_used_column_id() >= hard_code_column_id
|| last_column->get_column_id() >= hard_code_column_id) {
ret = OB_NOT_SUPPORTED;
LOG_WARN("column should be added at last", KR(ret), KPC(hard_code_column), K(table_schema));
} else if (OB_FAIL(add_column_ids.push_back(hard_code_column_id))) {
LOG_WARN("fail to push back column_id", KR(ret), K(tenant_id), K(table_id),
"column_id", hard_code_column_id);
}
}
} // end for
}
return ret;
}
bool ObRootInspection::check_str_with_lower_case_(const ObString &str)
{
bool bret = false;
if (str.length() > 0) {
for (int64_t i = 0; !bret && i < str.length(); i++) {
if (str.ptr()[i] >= 'a' && str.ptr()[i] <= 'z') {
bret = true;
}
}
}
return bret;
}
int ObRootInspection::check_sys_view_(
const uint64_t tenant_id,
const ObTableSchema &hard_code_table)
{
int ret = OB_SUCCESS;
if (OB_ISNULL(GCTX.root_service_)) {
ret = OB_NOT_INIT;
LOG_WARN("not init", KR(ret));
} else if (hard_code_table.is_view_table()) {
// check view definition
const ObString &table_name = hard_code_table.get_table_name();
const uint64_t table_id = hard_code_table.get_table_id();
const uint64_t database_id = hard_code_table.get_database_id();
bool is_oracle = is_oracle_sys_database_id(database_id);
bool check_lower_case = !is_mysql_database_id(database_id);
SMART_VAR(ObMySQLProxy::MySQLResult, res) {
common::sqlclient::ObMySQLResult *result = NULL;
ObSqlString sql;
// case 0: check expansion of sys view definition
if (is_oracle) {
if (OB_FAIL(sql.assign_fmt("SELECT FIELD FROM \"%s\".\"%s\" WHERE TABLE_ID = %lu",
OB_ORA_SYS_SCHEMA_NAME,
OB_TENANT_VIRTUAL_TABLE_COLUMN_ORA_TNAME,
table_id))) {
LOG_WARN("failed to assign sql", KR(ret), K(sql));
} else if (OB_FAIL(GCTX.root_service_->get_oracle_sql_proxy().read(res, tenant_id, sql.ptr()))) {
LOG_WARN("execute sql failed", KR(ret), K(tenant_id), K(table_name), K(sql));
}
} else {
if (OB_FAIL(sql.assign_fmt("SELECT FIELD FROM `%s`.`%s` WHERE TABLE_ID = %lu",
OB_SYS_DATABASE_NAME,
OB_TENANT_VIRTUAL_TABLE_COLUMN_TNAME,
table_id))) {
LOG_WARN("failed to assign sql", KR(ret), K(sql));
} else if (!is_oracle && OB_FAIL(GCTX.root_service_->get_sql_proxy().read(res, tenant_id, sql.ptr()))) {
LOG_WARN("execute sql failed", KR(ret), K(tenant_id), K(table_name), K(sql));
}
}
if (OB_FAIL(ret)) {
if (OB_ERR_VIEW_INVALID == ret) {
ret = OB_SCHEMA_ERROR;
LOG_ERROR("check sys view: expand failed", KR(ret), K(tenant_id), K(table_name));
} else {
LOG_WARN("check sys view: expand failed", KR(ret), K(tenant_id), K(table_name));
}
} else if (OB_ISNULL(result = res.get_result())) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("failed to get sql result", KR(ret), K(tenant_id));
} else if (check_lower_case) {
// case 1: check column name with lower case
ObString col_name;
while (OB_SUCC(ret) && OB_SUCC(result->next())) {
if (OB_FAIL(result->get_varchar(0L, col_name))) {
LOG_WARN("fail to get filed", KR(ret), K(tenant_id), K(table_name));
} else if (check_str_with_lower_case_(col_name)) {
ret = OB_SCHEMA_ERROR;
LOG_ERROR("check sys view: column name should be uppercase",
KR(ret), K(tenant_id), K(table_name), K(col_name));
}
} // end while
if (OB_ITER_END == ret) {
ret = OB_SUCCESS;
} else {
ret = OB_SUCC(ret) ? OB_ERR_UNEXPECTED : ret;
LOG_WARN("iterate failed", KR(ret));
}
// case 2: check view name with lower case
if (OB_SUCC(ret) && check_str_with_lower_case_(hard_code_table.get_table_name())) {
ret = OB_SCHEMA_ERROR;
LOG_ERROR("check sys view: table name should be uppercase", KR(ret), K(tenant_id), K(table_name));
}
}
}
}
return ret;
}
int ObRootInspection::check_table_options_(const ObTableSchema &table,
const ObTableSchema &hard_code_table)
{
int ret = OB_SUCCESS;
if (!table.is_valid() || !hard_code_table.is_valid()) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("invalid table or invalid hard_code_table", K(table), K(hard_code_table), K(ret));
} else if (table.get_table_id() != hard_code_table.get_table_id()) {
ret = OB_SCHEMA_ERROR;
LOG_WARN("table id not match", "table_id", table.get_table_id(),
"hard_code table_id", hard_code_table.get_table_id(), K(ret));
} else if (table.get_table_name_str() != hard_code_table.get_table_name_str()) {
ret = OB_SCHEMA_ERROR;
LOG_WARN("table name mismatch with hard code table",
"table_id", table.get_table_id(), "table_name", table.get_table_name(),
"hard_code_table name", hard_code_table.get_table_name(), K(ret));
} else {
const ObString &table_name = table.get_table_name_str();
if (table.get_tenant_id() != hard_code_table.get_tenant_id()) {
ret = OB_SCHEMA_ERROR;
LOG_WARN("tenant_id mismatch", K(table_name), "in_memory", table.get_tenant_id(),
"hard_code", hard_code_table.get_tenant_id(), K(ret));
} else if (table.get_database_id() != hard_code_table.get_database_id()) {
ret = OB_SCHEMA_ERROR;
LOG_WARN("database_id mismatch", K(table_name), "in_memory", table.get_database_id(),
"hard_code", hard_code_table.get_database_id(), K(ret));
} else if (table.get_tablegroup_id() != hard_code_table.get_tablegroup_id()) {
ret = OB_SCHEMA_ERROR;
LOG_WARN("tablegroup_id mismatch", K(table_name), "in_memory", table.get_tablegroup_id(),
"hard_code", hard_code_table.get_tablegroup_id(), K(ret));
} else if (table.get_auto_increment() != hard_code_table.get_auto_increment()) {
ret = OB_SCHEMA_ERROR;
LOG_WARN("auto_increment mismatch", K(table_name), "in_memory", table.get_auto_increment(),
"hard_code", hard_code_table.get_auto_increment(), K(ret));
} else if (table.is_read_only() != hard_code_table.is_read_only()) {
ret = OB_SCHEMA_ERROR;
LOG_WARN("read_only mismatch", K(table_name), "in_memory", table.is_read_only(),
"hard code", hard_code_table.is_read_only(), K(ret));
} else if (table.get_load_type() != hard_code_table.get_load_type()) {
ret = OB_SCHEMA_ERROR;
LOG_WARN("load_type mismatch", K(table_name), "in_memory", table.get_load_type(),
"hard_code", hard_code_table.get_load_type(), K(ret));
} else if (table.get_table_type() != hard_code_table.get_table_type()) {
ret = OB_SCHEMA_ERROR;
LOG_WARN("table_type mismatch", K(table_name), "in_memory", table.get_table_type(),
"hard_code", hard_code_table.get_table_type(), K(ret));
} else if (table.get_index_type() != hard_code_table.get_index_type()) {
ret = OB_SCHEMA_ERROR;
LOG_WARN("index_type mismatch", K(table_name), "in_memory", table.get_index_type(),
"hard_code", hard_code_table.get_index_type(), K(ret));
} else if (table.get_index_using_type() != hard_code_table.get_index_using_type()) {
ret = OB_SCHEMA_ERROR;
LOG_WARN("index_using_type mismatch", K(table_name), "in_memory", table.get_index_using_type(),
"hard_code", hard_code_table.get_index_using_type(), K(ret));
} else if (table.get_def_type() != hard_code_table.get_def_type()) {
ret = OB_SCHEMA_ERROR;
LOG_WARN("def_type mismatch", K(table_name), "in_memory", table.get_def_type(),
"hard_code", hard_code_table.get_def_type(), K(ret));
} else if (table.get_data_table_id() != hard_code_table.get_data_table_id()) {
ret = OB_SCHEMA_ERROR;
LOG_WARN("data_table_id mismatch", K(table_name), "in_memory", table.get_data_table_id(),
"hard_code", hard_code_table.get_data_table_id(), K(ret));
} else if (table.get_tablegroup_name() != hard_code_table.get_tablegroup_name()) {
ret = OB_SCHEMA_ERROR;
LOG_WARN("tablegroup_name mismatch", K(table_name), "in_memory", table.get_tablegroup_name(),
"hard_code", hard_code_table.get_tablegroup_name(), K(ret));
} else if (table.get_view_schema() != hard_code_table.get_view_schema()) {
ret = OB_SCHEMA_ERROR;
LOG_WARN("view_schema mismatch", K(table_name), "in_memory", table.get_view_schema(),
"hard_code", hard_code_table.get_view_schema(), K(ret));
} else if (table.get_part_level() != hard_code_table.get_part_level()) {
ret = OB_SCHEMA_ERROR;
LOG_WARN("part_level mismatch", K(table_name), "in_memory", table.get_part_level(),
"hard_code", hard_code_table.get_part_level(), K(ret));
} else if ((table.get_part_option().get_part_func_expr_str()
!= hard_code_table.get_part_option().get_part_func_expr_str())
|| (table.get_part_option().get_part_func_type()
!= hard_code_table.get_part_option().get_part_func_type())) {
ret = OB_SCHEMA_ERROR;
LOG_WARN("part_expr mismatch", K(table_name), "in_memory",
table.get_part_option(), "hard_code", hard_code_table.get_part_option(), K(ret));
} else if ((table.get_sub_part_option().get_part_func_expr_str()
!= hard_code_table.get_sub_part_option().get_part_func_expr_str())
|| (table.get_sub_part_option().get_part_func_type()
!= hard_code_table.get_sub_part_option().get_part_func_type())) {
ret = OB_SCHEMA_ERROR;
LOG_WARN("sub_part_expr mismatch", K(table_name), "in_memory",
table.get_sub_part_option(), "hard_code", hard_code_table.get_sub_part_option(), K(ret));
} else if (table.is_view_table()) {
// view table do not check column info
} else if (table.get_max_used_column_id() < hard_code_table.get_max_used_column_id()) {
ret = OB_SCHEMA_ERROR;
LOG_WARN("max_used_column_id mismatch", K(table_name), "in_memory",
table.get_max_used_column_id(), "hard_code",
hard_code_table.get_max_used_column_id(), K(ret));
} else if (table.get_rowkey_column_num() != hard_code_table.get_rowkey_column_num()) {
ret = OB_SCHEMA_ERROR;
LOG_WARN("rowkey_column_num mismatch", K(table_name), "in_memory",
table.get_rowkey_column_num(), "hard_code",
hard_code_table.get_rowkey_column_num(), K(ret));
} else if (table.get_index_column_num() != hard_code_table.get_index_column_num()) {
ret = OB_SCHEMA_ERROR;
LOG_WARN("index_column_num mismatch", K(table_name), "in_memory",
table.get_index_column_num(), "hard_code",
hard_code_table.get_index_column_num(), K(ret));
} else if (table.get_rowkey_split_pos() != hard_code_table.get_rowkey_split_pos()) {
ret = OB_SCHEMA_ERROR;
LOG_WARN("rowkey_split_pos mismatch", K(table_name), "in_memory",
table.get_rowkey_split_pos(), "hard_code",
hard_code_table.get_rowkey_split_pos(), K(ret));
} else if (table.get_partition_key_column_num()
!= hard_code_table.get_partition_key_column_num()) {
ret = OB_SCHEMA_ERROR;
LOG_WARN("partition_key_column_num mismatch", K(table_name), "in_memory",
table.get_partition_key_column_num(), "hard_code",
hard_code_table.get_partition_key_column_num(), K(ret));
} else if (table.get_subpartition_key_column_num()
!= hard_code_table.get_subpartition_key_column_num()) {
ret = OB_SCHEMA_ERROR;
LOG_WARN("partition_key_column_num mismatch", K(table_name), "in_memory",
table.get_subpartition_key_column_num(), "hard_code",
hard_code_table.get_subpartition_key_column_num(), K(ret));
} else if (table.get_autoinc_column_id() != hard_code_table.get_autoinc_column_id()) {
ret = OB_SCHEMA_ERROR;
LOG_WARN("autoinc_column_id mismatch", K(table_name), "in_memory",
table.get_autoinc_column_id(), "hard_code",
hard_code_table.get_autoinc_column_id(), K(ret));
}
// options may be different between different ob instance, don't check
// block_size
// is_user_bloomfilter
// progressive_merge_num
// replica_num
// index_status
// name_case_mode
// charset_type
// collation_type
// schema_version
// comment
// compress_func_name
// expire_info
// zone_list
// primary_zone
// part_expr.part_num_
// sub_part_expr.part_num_
// store_format
// row_store_type
// progressive_merge_round
// storage_format_version
}
return ret;
}
int ObRootInspection::check_column_schema_(const ObString &table_name,
const ObColumnSchemaV2 &column,
const ObColumnSchemaV2 &hard_code_column,
const bool ignore_column_id)
{
int ret = OB_SUCCESS;
if (table_name.empty() || !column.is_valid() || !hard_code_column.is_valid()) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("table_name is empty or invalid column or invalid hard_code_column",
KR(ret), K(table_name), K(column), K(hard_code_column));
} else {
#define CMP_COLUMN_ATTR(attr) \
if (OB_SUCC(ret)) { \
if (column.get_##attr() != hard_code_column.get_##attr()) { \
ret = OB_SCHEMA_ERROR; \
LOG_WARN(#attr " mismatch", KR(ret), K(table_name), "column_name", column.get_column_name(), \
"in_memory", column.get_##attr(), "hard_code", hard_code_column.get_##attr()); \
} \
}
#define CMP_COLUMN_IS_ATTR(attr) \
if (OB_SUCC(ret)) { \
if (column.is_##attr() != hard_code_column.is_##attr()) { \
ret = OB_SCHEMA_ERROR; \
LOG_WARN(#attr " mismatch", KR(ret), K(table_name), "column_name", column.get_column_name(), \
"in_memory", column.is_##attr(), "hard_code", hard_code_column.is_##attr()); \
} \
}
if (OB_SUCC(ret)) {
if (column.get_column_name_str() != hard_code_column.get_column_name_str()) {
ret = OB_SCHEMA_ERROR;
LOG_WARN("column_name mismatch", KR(ret), K(table_name),
"in_memory", column.get_column_name(),
"hard_code", hard_code_column.get_column_name());
}
}
if (!ignore_column_id) {
CMP_COLUMN_ATTR(column_id);
}
CMP_COLUMN_ATTR(tenant_id);
CMP_COLUMN_ATTR(table_id);
// don't need to check schema version
CMP_COLUMN_ATTR(rowkey_position);
CMP_COLUMN_ATTR(index_position);
CMP_COLUMN_ATTR(order_in_rowkey);
CMP_COLUMN_ATTR(tbl_part_key_pos);
CMP_COLUMN_ATTR(meta_type);
CMP_COLUMN_ATTR(accuracy);
CMP_COLUMN_ATTR(data_length);
CMP_COLUMN_IS_ATTR(nullable);
CMP_COLUMN_IS_ATTR(zero_fill);
CMP_COLUMN_IS_ATTR(autoincrement);
CMP_COLUMN_IS_ATTR(hidden);
CMP_COLUMN_IS_ATTR(on_update_current_timestamp);
CMP_COLUMN_ATTR(charset_type);
// don't need to check orig default value
if (ObString("row_store_type") == column.get_column_name()
&& (ObString("__all_table") == table_name || ObString("__all_table_history") == table_name)) {
// row_store_type may have two possible default values
} else {
CMP_COLUMN_ATTR(cur_default_value);
}
CMP_COLUMN_ATTR(comment);
}
#undef CMP_COLUMN_IS_ATTR
#undef CMP_COLUMN_INT_ATTR
return ret;
}
int ObRootInspection::check_data_version_()
{
int ret = OB_SUCCESS;
ObArray<uint64_t> tenant_ids;
if (OB_UNLIKELY(!inited_)) {
ret = OB_NOT_INIT;
LOG_WARN("not init", KR(ret));
} else if (OB_FAIL(check_cancel())) {
LOG_WARN("check_cancel failed", KR(ret));
} else if (OB_ISNULL(schema_service_)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("schema_service is null", KR(ret));
} else if (OB_FAIL(construct_tenant_ids_(tenant_ids))) {
LOG_WARN("get_tenant_ids failed", KR(ret));
} else {
int backup_ret = OB_SUCCESS;
int tmp_ret = OB_SUCCESS;
FOREACH_X(tenant_id, tenant_ids, OB_SUCC(ret)) {
if (OB_FAIL(check_cancel())) {
LOG_WARN("check_cancel failed", KR(ret));
} else if (OB_FAIL(check_tenant_status_(*tenant_id))) {
LOG_WARN("fail to check tenant status", KR(ret), K(*tenant_id));
} else if (OB_TMP_FAIL(check_data_version_(*tenant_id))) {
LOG_WARN("fail to check data version by tenant", KR(tmp_ret), K(*tenant_id));
backup_ret = OB_SUCCESS == backup_ret ? tmp_ret : backup_ret;
}
} // end foreach
ret = OB_SUCC(ret) ? backup_ret : ret;
}
return ret;
}
int ObRootInspection::check_data_version_(
const uint64_t tenant_id)
{
int ret = OB_SUCCESS;
if (OB_UNLIKELY(!inited_)) {
ret = OB_NOT_INIT;
LOG_WARN("not init", KR(ret));
} else if (OB_FAIL(check_cancel())) {
LOG_WARN("check_cancel failed", KR(ret));
} else {
share::ObGlobalStatProxy proxy(*sql_proxy_, tenant_id);
uint64_t target_data_version = 0;
uint64_t current_data_version = 0;
uint64_t compatible_version = 0;
bool for_update = false;
if (OB_FAIL(proxy.get_target_data_version(for_update, target_data_version))) {
LOG_WARN("fail to get target data version", KR(ret), K(tenant_id));
} else if (OB_FAIL(proxy.get_current_data_version(current_data_version))) {
LOG_WARN("fail to get current data version", KR(ret), K(tenant_id));
} else if (OB_FAIL(GET_MIN_DATA_VERSION(tenant_id, compatible_version))) {
LOG_WARN("fail to get min data version", KR(ret), K(tenant_id));
} else if (target_data_version != current_data_version
|| target_data_version != compatible_version
|| target_data_version != DATA_CURRENT_VERSION) {
ret = OB_STATE_NOT_MATCH;
LOG_WARN("data_version not match, upgrade process should be run",
KR(ret), K(tenant_id), K(target_data_version),
K(current_data_version), K(compatible_version));
}
}
return ret;
}
int ObRootInspection::check_cancel()
{
int ret = OB_SUCCESS;
if (stopped_) {
ret = OB_CANCELED;
} else if (OB_ISNULL(GCTX.root_service_)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("rootservice is null", KR(ret));
} else if (!GCTX.root_service_->is_full_service()) {
ret = OB_CANCELED;
}
return ret;
}
int ObRootInspection::check_tenant_status_(const uint64_t tenant_id)
{
int ret = OB_SUCCESS;
ObSchemaGetterGuard guard;
const ObSimpleTenantSchema *tenant = NULL;
int64_t schema_version = OB_INVALID_VERSION;
if (OB_ISNULL(schema_service_)) {
ret = OB_NOT_INIT;
LOG_WARN("schema service is null", KR(ret));
} else if (OB_FAIL(schema_service_->get_tenant_schema_guard(OB_SYS_TENANT_ID, guard))) {
LOG_WARN("fail to get schema guard", KR(ret));
} else if (OB_FAIL(guard.get_tenant_info(tenant_id, tenant))) {
LOG_WARN("fail to get tenant schema", KR(ret), K(tenant_id));
} else if (OB_ISNULL(tenant)) {
// tenant may has been dropped;
ret = OB_EAGAIN;
LOG_WARN("tenant may be dropped, don't continue", KR(ret), K(tenant_id));
} else if (!tenant->is_normal()) {
ret = OB_EAGAIN;
LOG_WARN("tenant status is not noraml, should check next round", KR(ret), K(tenant_id));
} else if (OB_FAIL(schema_service_->get_tenant_refreshed_schema_version(tenant_id, schema_version))) {
LOG_WARN("fail to get tenant schema version", KR(ret), K(tenant_id));
} else if (!ObSchemaService::is_formal_version(schema_version)) {
ret = OB_EAGAIN;
LOG_WARN("schema version is not formal, observer may be restarting or inner table schema changed, "
"should check next round", KR(ret), K(tenant_id), K(schema_version));
}
return ret;
}
ObUpgradeInspection::ObUpgradeInspection()
: inited_(false), schema_service_(NULL), root_inspection_(NULL)
{
}
ObUpgradeInspection::~ObUpgradeInspection()
{
}
int ObUpgradeInspection::init(ObMultiVersionSchemaService &schema_service,
ObRootInspection &root_inspection)
{
int ret = OB_SUCCESS;
if (inited_) {
ret = OB_INIT_TWICE;
LOG_WARN("init twice", K(ret));
} else {
schema_service_ = &schema_service;
root_inspection_ = &root_inspection;
inited_ = true;
}
return ret;
}
int ObUpgradeInspection::inner_get_next_row(common::ObNewRow *&row)
{
int ret = OB_SUCCESS;
ObSchemaGetterGuard schema_guard;
if (NULL == allocator_) {
ret = OB_NOT_INIT;
LOG_WARN("not init, allocator is null", K(ret));
} else if (!inited_) {
ret = OB_NOT_INIT;
LOG_WARN("not init", K(ret));
} else if (OB_FAIL(schema_service_->get_tenant_schema_guard(OB_SYS_TENANT_ID, schema_guard))) {
LOG_WARN("get schema guard error", K(ret));
} else if (!start_to_read_) {
const ObTableSchema *table_schema = NULL;
const uint64_t table_id = OB_ALL_VIRTUAL_UPGRADE_INSPECTION_TID;
if (OB_FAIL(schema_guard.get_table_schema(OB_SYS_TENANT_ID, table_id, table_schema))) {
LOG_WARN("get_table_schema failed", K(table_id), K(ret));
} else if (NULL == table_schema) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("table_schema is null", KP(table_schema), K(ret));
} else {
ObArray<Column> columns;
#define ADD_ROW(name, info) \
do { \
columns.reuse(); \
if (OB_FAIL(ret)) { \
} else if (OB_FAIL(get_full_row(table_schema, name, info, columns))) { \
LOG_WARN("get_full_row failed", "table_schema", *table_schema, \
K(name), K(info), K(ret)); \
} else if (OB_FAIL(project_row(columns, cur_row_))) { \
LOG_WARN("project_row failed", K(columns), K(ret)); \
} else if (OB_FAIL(scanner_.add_row(cur_row_))) { \
LOG_WARN("add_row failed", K(cur_row_), K(ret)); \
} \
} while (false)
#define CHECK_RESULT(checked, value) (checked ? (value ? "succeed" : "failed") : "checking")
ADD_ROW("zone_check", CHECK_RESULT(root_inspection_->is_all_checked(),
root_inspection_->is_zone_passed()));
ADD_ROW("sys_stat_check", CHECK_RESULT(root_inspection_->is_all_checked(),
root_inspection_->is_sys_stat_passed()));
ADD_ROW("sys_param_check", CHECK_RESULT(root_inspection_->is_all_checked(),
root_inspection_->is_sys_param_passed()));
ADD_ROW("sys_table_schema_check", CHECK_RESULT(root_inspection_->is_all_checked(),
root_inspection_->is_sys_table_schema_passed()));
ADD_ROW("data_version_check", CHECK_RESULT(root_inspection_->is_all_checked(),
root_inspection_->is_data_version_passed()));
bool upgrade_job_passed = true;
for (int64_t i = 0; OB_SUCC(ret) && i < UPGRADE_JOB_TYPE_COUNT; i++) {
int tmp = OB_SUCCESS;
ObRsJobType job_type = upgrade_job_type_array[i];
if (job_type > JOB_TYPE_INVALID && job_type < JOB_TYPE_MAX) {
if (OB_SUCCESS != (tmp = ObUpgradeUtils::check_upgrade_job_passed(job_type))) {
LOG_WARN("fail to check upgrade job passed", K(tmp), K(job_type));
upgrade_job_passed = false;
}
ADD_ROW(ObRsJobTableOperator::get_job_type_str(job_type),
CHECK_RESULT(root_inspection_->is_all_checked(), (OB_SUCCESS == tmp)));
}
}
ADD_ROW("all_check", CHECK_RESULT(root_inspection_->is_all_checked(),
(root_inspection_->is_all_passed() && upgrade_job_passed)));
#undef CHECK_RESULT
#undef ADD_ROW
}
if (OB_SUCC(ret)) {
scanner_it_ = scanner_.begin();
start_to_read_ = true;
}
}
if (OB_SUCC(ret)) {
if (OB_FAIL(scanner_it_.get_next_row(cur_row_))) {
if (OB_ITER_END != ret) {
LOG_WARN("get_next_row failed", K(ret));
}
} else {
row = &cur_row_;
}
}
return ret;
}
int ObUpgradeInspection::get_full_row(const share::schema::ObTableSchema *table,
const char *name, const char *info,
ObIArray<Column> &columns)
{
int ret = OB_SUCCESS;
if (!inited_) {
ret = OB_NOT_INIT;
LOG_WARN("not init", K(ret));
} else if (NULL == table || NULL == name || NULL == info) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("invalid argument", KP(table), KP(name), KP(info), K(ret));
} else {
ADD_COLUMN(set_varchar, table, "name", name, columns);
ADD_COLUMN(set_varchar, table, "info", info, columns);
}
return ret;
}
}//end namespace rootserver
}//end namespace oceanbase