From 47089d39312fc06fdcbc193a79d22218f6f49aea Mon Sep 17 00:00:00 2001 From: hamstersox <673144759@qq.com> Date: Fri, 15 Sep 2023 11:10:24 +0000 Subject: [PATCH] fix some recover table bugs --- src/observer/mysql/obmp_connect.cpp | 6 +++ src/rootserver/ddl_task/ob_ddl_scheduler.cpp | 8 +++ src/rootserver/ob_ddl_service.cpp | 7 --- .../restore/ob_import_table_job_scheduler.cpp | 11 ++++ .../ob_import_table_task_generator.cpp | 49 ++++++++++++++++-- .../restore/ob_import_table_task_generator.h | 4 ++ .../ob_recover_table_job_scheduler.cpp | 20 ++++++++ .../restore/ob_recover_table_job_scheduler.h | 1 + src/share/restore/ob_import_util.cpp | 51 ++++++++++++++++++- src/share/restore/ob_import_util.h | 3 ++ unittest/rootserver/test_import_table.cpp | 18 +++++++ 11 files changed, 167 insertions(+), 11 deletions(-) diff --git a/src/observer/mysql/obmp_connect.cpp b/src/observer/mysql/obmp_connect.cpp index 1d9ca1222..59a52ea9f 100644 --- a/src/observer/mysql/obmp_connect.cpp +++ b/src/observer/mysql/obmp_connect.cpp @@ -533,6 +533,12 @@ int ObMPConnect::load_privilege_info(ObSQLSessionInfo &session) tenant_name_ = ObString::make_string(OB_SYS_TENANT_NAME); OB_LOG(INFO, "no tenant name set, use default tenant name", K_(tenant_name)); } + + if (OB_NOT_NULL(tenant_name_.find('$'))) { + ret = OB_ERR_INVALID_TENANT_NAME; + LOG_WARN("invalid tenant name. “$” is not allowed in tenant name.", K(ret), K_(tenant_name)); + } + //在oracle租户下需要转换db_name和user_name,处理双引号和大小写 //在mysql租户下不会作任何处理,只简单拷贝下~ if (OB_SUCC(ret)) { diff --git a/src/rootserver/ddl_task/ob_ddl_scheduler.cpp b/src/rootserver/ddl_task/ob_ddl_scheduler.cpp index 77bda9803..c2d030b5f 100755 --- a/src/rootserver/ddl_task/ob_ddl_scheduler.cpp +++ b/src/rootserver/ddl_task/ob_ddl_scheduler.cpp @@ -31,6 +31,7 @@ #include "share/ob_rpc_struct.h" #include "share/longops_mgr/ob_longops_mgr.h" #include "share/scheduler/ob_sys_task_stat.h" +#include "share/restore/ob_import_util.h" namespace oceanbase { @@ -1747,6 +1748,7 @@ int ObDDLScheduler::recover_task() int64_t tenant_schema_version = 0; int64_t table_task_status = 0; int64_t execution_id = -1; + bool is_recover_table_aux_tenant = false; ObMySQLTransaction trans; if (OB_FAIL(schema_service.get_tenant_schema_version(cur_record.tenant_id_, tenant_schema_version))) { LOG_WARN("failed to get tenant schema version", K(ret), K(cur_record)); @@ -1755,6 +1757,12 @@ int ObDDLScheduler::recover_task() } else if (tenant_schema_version < cur_record.schema_version_) { // schema has not publish, by pass now LOG_INFO("skip schedule ddl task, because tenant schema version too old", K(tenant_schema_version), K(cur_record)); + } else if (OB_FAIL(ObImportTableUtil::check_is_recover_table_aux_tenant(schema_service, + cur_record.tenant_id_, + is_recover_table_aux_tenant))) { + LOG_WARN("failed to check is recover table aux tenant", K(ret), K(cur_record)); + } else if (is_recover_table_aux_tenant) { + LOG_INFO("tenant is recover table aux tenant, skip schedule ddl task", K(cur_record)); } else if (OB_FAIL(trans.start(&root_service_->get_sql_proxy(), cur_record.tenant_id_))) { LOG_WARN("start transaction failed", K(ret)); } else if (OB_FAIL(ObDDLTaskRecordOperator::select_for_update(trans, diff --git a/src/rootserver/ob_ddl_service.cpp b/src/rootserver/ob_ddl_service.cpp index 96c88483f..57b1c65ed 100755 --- a/src/rootserver/ob_ddl_service.cpp +++ b/src/rootserver/ob_ddl_service.cpp @@ -321,16 +321,9 @@ int ObDDLService::get_tenant_schema_guard_with_version_in_inner_table( int ret = OB_SUCCESS; src_tenant_schema_guard = nullptr; dst_tenant_schema_guard = nullptr; - bool is_standby = false; if (OB_UNLIKELY(OB_INVALID_TENANT_ID == src_tenant_id || OB_INVALID_TENANT_ID == dst_tenant_id)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid tenant_id", K(ret), K(src_tenant_id), K(dst_tenant_id)); - } else if (src_tenant_id != dst_tenant_id - && OB_FAIL(ObAllTenantInfoProxy::is_standby_tenant(sql_proxy_, src_tenant_id, is_standby))) { - LOG_WARN("check tenant standby failed", K(ret), K(src_tenant_id), K(dst_tenant_id)); - } else if (src_tenant_id != dst_tenant_id && !is_standby) { - ret = OB_INVALID_ARGUMENT; - LOG_WARN("invalid arg, src tenant should be standby", K(ret), K(src_tenant_id), K(dst_tenant_id)); } else if (OB_FAIL(get_tenant_schema_guard_with_version_in_inner_table(dst_tenant_id, hold_buf_dst_tenant_schema_guard))) { LOG_WARN("get tenant schema guard failed", K(dst_tenant_id)); } else if (src_tenant_id == dst_tenant_id) { diff --git a/src/rootserver/restore/ob_import_table_job_scheduler.cpp b/src/rootserver/restore/ob_import_table_job_scheduler.cpp index fbf008d2f..066e5f7dc 100644 --- a/src/rootserver/restore/ob_import_table_job_scheduler.cpp +++ b/src/rootserver/restore/ob_import_table_job_scheduler.cpp @@ -215,6 +215,17 @@ int ObImportTableJobScheduler::gen_import_table_task_(share::ObImportTableJob &j int tmp_ret = OB_SUCCESS; ObImportTableJobStatus next_status(ObImportTableJobStatus::IMPORT_FINISH); job.set_end_ts(ObTimeUtility::current_time()); + + if (!job.get_result().is_comment_setted()) { + share::ObTaskId trace_id(*ObCurTraceId::get_trace_id()); + ObImportResult result; + if (OB_TMP_FAIL(result.set_result(ret, trace_id, GCONF.self_addr_))) { + LOG_WARN("failed to set result", K(ret)); + } else { + job.set_result(result); + } + } + if (OB_TMP_FAIL(advance_status_(*sql_proxy_, job, next_status))) { LOG_WARN("failed to advance status", K(ret)); } diff --git a/src/rootserver/restore/ob_import_table_task_generator.cpp b/src/rootserver/restore/ob_import_table_task_generator.cpp index 9c6c8481d..2f491f7e3 100644 --- a/src/rootserver/restore/ob_import_table_task_generator.cpp +++ b/src/rootserver/restore/ob_import_table_task_generator.cpp @@ -287,9 +287,8 @@ int ObImportTableTaskGenerator::fill_import_task_( share::ObImportTableTask &import_task) { int ret = OB_SUCCESS; - if (!table_schema.is_user_table()) { - ret = OB_OP_NOT_ALLOW; - LOG_WARN("import not user table is not allowed"); + if (OB_FAIL(check_src_table_schema_(import_job, table_schema, table_item))) { + LOG_WARN("failed to check src table schema", K(ret)); } else if (OB_FAIL(import_task.set_src_database(table_item.database_name_))) { LOG_WARN("failed to set src database name", K(ret)); } else if (OB_FAIL(import_task.set_src_table(table_item.table_name_))) { @@ -311,6 +310,50 @@ int ObImportTableTaskGenerator::fill_import_task_( return ret; } +int ObImportTableTaskGenerator::check_src_table_schema_( + share::ObImportTableJob &import_job, + const share::schema::ObTableSchema &table_schema, + const share::ObImportTableItem &table_item) +{ + int ret = OB_SUCCESS; + int tmp_ret = OB_SUCCESS; + if (!table_schema.is_user_table()) { + ret = OB_OP_NOT_ALLOW; + LOG_WARN("import not user table is not allowed", K(ret), K(table_item)); + ObImportResult::Comment comment; + if (OB_TMP_FAIL(databuff_printf(comment.ptr(), comment.capacity(), "import table %.*s.%.*s is not user table", + table_item.database_name_.length(), table_item.database_name_.ptr(), + table_item.table_name_.length(), table_item.table_name_.ptr()))) { + LOG_WARN("failed to databuff printf", K(ret)); + } else { + import_job.get_result().set_result(false/*failed*/, comment); + } + } else if (table_schema.is_in_recyclebin()) { + ret = OB_OP_NOT_ALLOW; + LOG_WARN("import table in recyclebin is not allowed", K(ret), K(table_item)); + ObImportResult::Comment comment; + if (OB_TMP_FAIL(databuff_printf(comment.ptr(), comment.capacity(), "import table %.*s.%.*s is in recyclebin", + table_item.database_name_.length(), table_item.database_name_.ptr(), + table_item.table_name_.length(), table_item.table_name_.ptr()))) { + LOG_WARN("failed to databuff printf", K(ret)); + } else { + import_job.get_result().set_result(false/*failed*/, comment); + } + } else if (table_schema.is_user_hidden_table()) { + ret = OB_OP_NOT_ALLOW; + LOG_WARN("import hidden user table is not allowed", K(ret), K(table_item)); + ObImportResult::Comment comment; + if (OB_TMP_FAIL(databuff_printf(comment.ptr(), comment.capacity(), "import table %.*s.%.*s is hidden table", + table_item.database_name_.length(), table_item.database_name_.ptr(), + table_item.table_name_.length(), table_item.table_name_.ptr()))) { + LOG_WARN("failed to databuff printf", K(ret)); + } else { + import_job.get_result().set_result(false/*failed*/, comment); + } + } + return ret; +} + int ObImportTableTaskGenerator::check_target_schema_( share::ObImportTableJob &import_job, const share::ObImportTableTask &task) diff --git a/src/rootserver/restore/ob_import_table_task_generator.h b/src/rootserver/restore/ob_import_table_task_generator.h index 09f40db1f..669866cc1 100644 --- a/src/rootserver/restore/ob_import_table_task_generator.h +++ b/src/rootserver/restore/ob_import_table_task_generator.h @@ -94,6 +94,10 @@ private: const share::ObImportTableItem &table_item, const share::ObImportTableItem &remap_table_item, share::ObImportTableTask &import_task); + int check_src_table_schema_( + share::ObImportTableJob &import_job, + const share::schema::ObTableSchema &table_schema, + const share::ObImportTableItem &table_item); int fill_common_para_( const share::ObImportTableJob &import_job, const share::schema::ObTableSchema &table_schema, diff --git a/src/rootserver/restore/ob_recover_table_job_scheduler.cpp b/src/rootserver/restore/ob_recover_table_job_scheduler.cpp index de4a4b3df..376e081a9 100644 --- a/src/rootserver/restore/ob_recover_table_job_scheduler.cpp +++ b/src/rootserver/restore/ob_recover_table_job_scheduler.cpp @@ -530,6 +530,8 @@ int ObRecoverTableJobScheduler::restore_aux_tenant_(share::ObRecoverTableJob &jo job.get_result().set_result(false, restore_history_info.comment_); } else if (OB_FAIL(check_aux_tenant_(job, aux_tenant_id))) { LOG_WARN("failed to check aux tenant", K(ret), K(aux_tenant_id)); + } else if (OB_FAIL(failover_to_leader_(job, aux_tenant_id))) { + LOG_WARN("failed to failover to leader", K(ret)); } int tmp_ret = OB_SUCCESS; @@ -540,6 +542,24 @@ int ObRecoverTableJobScheduler::restore_aux_tenant_(share::ObRecoverTableJob &jo return ret; } +int ObRecoverTableJobScheduler::failover_to_leader_( + share::ObRecoverTableJob &job, const uint64_t aux_tenant_id) +{ + int ret = OB_SUCCESS; + common::ObAddr leader; + obrpc::ObSwitchTenantArg switch_tenant_arg; + MTL_SWITCH(OB_SYS_TENANT_ID) { + if (OB_FAIL(switch_tenant_arg.init(aux_tenant_id, obrpc::ObSwitchTenantArg::OpType::FAILOVER_TO_PRIMARY, "", false))) { + LOG_WARN("failed to init switch tenant arg", K(ret), K(aux_tenant_id)); + } else if (OB_FAIL(OB_PRIMARY_STANDBY_SERVICE.switch_tenant(switch_tenant_arg))) { + LOG_WARN("failed to switch_tenant", KR(ret), K(switch_tenant_arg)); + } else { + LOG_INFO("[RECOVER_TABLE]succeed to switch aux tenant role to primary", K(aux_tenant_id), K(job)); + } + } + return ret; +} + int ObRecoverTableJobScheduler::check_aux_tenant_(share::ObRecoverTableJob &job, const uint64_t aux_tenant_id) { int ret = OB_SUCCESS; diff --git a/src/rootserver/restore/ob_recover_table_job_scheduler.h b/src/rootserver/restore/ob_recover_table_job_scheduler.h index 28f7f977f..c44a5516f 100644 --- a/src/rootserver/restore/ob_recover_table_job_scheduler.h +++ b/src/rootserver/restore/ob_recover_table_job_scheduler.h @@ -71,6 +71,7 @@ private: int user_prepare_(share::ObRecoverTableJob &job); int restore_aux_tenant_(share::ObRecoverTableJob &job); int check_aux_tenant_(share::ObRecoverTableJob &job, const uint64_t aux_tenant_id); + int failover_to_leader_(share::ObRecoverTableJob &job, const uint64_t aux_tenant_id); int check_tenant_compatibility( share::schema::ObSchemaGetterGuard &aux_tenant_guard, share::schema::ObSchemaGetterGuard &recover_tenant_guard, diff --git a/src/share/restore/ob_import_util.cpp b/src/share/restore/ob_import_util.cpp index 2ae8f77f7..d4bc50694 100644 --- a/src/share/restore/ob_import_util.cpp +++ b/src/share/restore/ob_import_util.cpp @@ -152,4 +152,53 @@ int ObImportTableUtil::get_tenant_name_case_mode(const uint64_t tenant_id, ObNam LOG_WARN("faield to get tenant schema guard", K(ret), K(tenant_id)); } return ret; -} \ No newline at end of file +} + +int ObImportTableUtil::check_is_recover_table_aux_tenant( + share::schema::ObMultiVersionSchemaService &schema_service, + const uint64_t tenant_id, + bool &is_recover_table_aux_tenant) +{ + int ret = OB_SUCCESS; + schema::ObSchemaGetterGuard guard; + const schema::ObTenantSchema *tenant_schema = nullptr; + is_recover_table_aux_tenant = false; + if (!is_valid_tenant_id(tenant_id)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid tenant id", K(ret), K(tenant_id)); + } else if (!is_user_tenant(tenant_id)) { // skip sys tenant and meta tenant + } else if (OB_FAIL(schema_service.get_tenant_schema_guard(OB_SYS_TENANT_ID, guard))) { + LOG_WARN("failed to get tenant schema guard", K(tenant_id), K(ret)); + } else if (OB_FAIL(guard.get_tenant_info(tenant_id, tenant_schema))) { + LOG_WARN("failed to get tenant info", K(ret), K(tenant_id)); + } else if (OB_ISNULL(tenant_schema)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("tenant schema must not be nullptr", K(ret)); + } else if (OB_FAIL(check_is_recover_table_aux_tenant_name(tenant_schema->get_tenant_name_str(), + is_recover_table_aux_tenant))) { + LOG_WARN("failed to check is recover table aux tenant name", K(ret)); + } + return ret; +} + +int ObImportTableUtil::check_is_recover_table_aux_tenant_name( + const ObString &tenant_name, + bool &is_recover_table_aux_tenant) +{ + int ret = OB_SUCCESS; + int64_t timestamp = 0; + is_recover_table_aux_tenant = false; + char buf[OB_MAX_TENANT_NAME_LENGTH] = ""; + const ObString AUX_TENANT_NAME_PREFIX("AUX_RECOVER$"); + if (tenant_name.length() > OB_MAX_TENANT_NAME_LENGTH || tenant_name.empty()) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid tenant name", K(ret), K(tenant_name)); + } else if (!tenant_name.prefix_match(AUX_TENANT_NAME_PREFIX)) { + // not recover table aux tenant, skip + } else if (1 != sscanf(tenant_name.ptr(), "AUX_RECOVER$%ld%s", ×tamp, buf)) { + // not recover table aux tenant, skip + } else { + is_recover_table_aux_tenant = true; + } + return ret; +} diff --git a/src/share/restore/ob_import_util.h b/src/share/restore/ob_import_util.h index 78aa0c5f4..238cc0d2f 100644 --- a/src/share/restore/ob_import_util.h +++ b/src/share/restore/ob_import_util.h @@ -33,6 +33,9 @@ static int check_tablegroup_exist(share::schema::ObMultiVersionSchemaService &sc static int check_tablespace_exist(share::schema::ObMultiVersionSchemaService &schema_service, uint64_t tenant_id, const ObString &tablespace, bool &is_exist); static int get_tenant_name_case_mode(const uint64_t tenant_id, ObNameCaseMode &name_case_mode); +static int check_is_recover_table_aux_tenant( + share::schema::ObMultiVersionSchemaService &schema_service, const uint64_t tenant_id, bool &is_recover_table_aux_tenant); +static int check_is_recover_table_aux_tenant_name(const ObString &tenant_name, bool &is_recover_table_aux_tenant); }; } diff --git a/unittest/rootserver/test_import_table.cpp b/unittest/rootserver/test_import_table.cpp index 66627cca9..8957de133 100644 --- a/unittest/rootserver/test_import_table.cpp +++ b/unittest/rootserver/test_import_table.cpp @@ -17,6 +17,7 @@ #include #include "share/ob_errno.h" #include "share/restore/ob_import_arg.h" +#include "share/restore/ob_import_util.h" using namespace oceanbase; @@ -458,6 +459,23 @@ TEST_F(ImportTableTest, test_namecase_mode) ASSERT_EQ(OB_BACKUP_CONFLICT_VALUE, arg.add_remap_database(remap_db2)); } +TEST_F(ImportTableTest, test_check_aux_tenant) +{ + const ObString tenant_name_1("AUX_RECOVER$1694673215667468"); + bool is_recover_table_aux_tenant = false; + ASSERT_EQ(OB_SUCCESS, ObImportTableUtil::check_is_recover_table_aux_tenant_name(tenant_name_1, is_recover_table_aux_tenant)); + ASSERT_EQ(true, is_recover_table_aux_tenant); + const ObString tenant_name_2("AUX_RECOVER$1694673215667468aaa"); + ASSERT_EQ(OB_SUCCESS, ObImportTableUtil::check_is_recover_table_aux_tenant_name(tenant_name_2, is_recover_table_aux_tenant)); + ASSERT_EQ(false, is_recover_table_aux_tenant); + const ObString tenant_name_3("AUX_RECOVER1694673215667468aaa"); + ASSERT_EQ(OB_SUCCESS, ObImportTableUtil::check_is_recover_table_aux_tenant_name(tenant_name_3, is_recover_table_aux_tenant)); + ASSERT_EQ(false, is_recover_table_aux_tenant); + const ObString tenant_name_4("AUX_RECOVER$aaa"); + ASSERT_EQ(OB_SUCCESS, ObImportTableUtil::check_is_recover_table_aux_tenant_name(tenant_name_4, is_recover_table_aux_tenant)); + ASSERT_EQ(false, is_recover_table_aux_tenant); +} + int main(int argc, char **argv) {