/** * 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 STORAGE #include "lib/utility/ob_tracepoint.h" #include "lib/hash/ob_hashset.h" #include "share/ob_force_print_log.h" #include "storage/ob_partition_backup.h" #include "storage/ob_partition_service.h" #include "storage/ob_partition_log.h" #include "storage/ob_partition_base_data_ob_reader.h" #include "observer/ob_server_struct.h" #include "observer/ob_server.h" #include "clog/ob_clog_history_reporter.h" #include "share/scheduler/ob_sys_task_stat.h" #include "share/partition_table/ob_united_pt_operator.h" #include "storage/ob_partition_base_data_restore_reader.h" #include "storage/ob_partition_base_data_backup.h" #include "share/ob_task_define.h" #include "share/backup/ob_backup_struct.h" #include "ob_table_mgr.h" #include "ob_migrate_macro_block_writer.h" #include "share/ob_debug_sync_point.h" #include "ob_storage_struct.h" #include "observer/omt/ob_tenant_node_balancer.h" #include "storage/ob_partition_migration_status.h" #include "storage/ob_pg_all_meta_checkpoint_reader.h" #include "share/backup/ob_backup_path.h" #include "storage/ob_partition_base_data_physical_restore.h" #include "storage/ob_pg_storage.h" namespace oceanbase { using namespace common; using namespace common::hash; using namespace share; using namespace obrpc; using namespace blocksstable; using namespace oceanbase::share::schema; using namespace omt; using namespace transaction; namespace storage { ObPartGroupBackupTask::ObPartGroupBackupTask() : ObPartGroupTask() {} ObPartGroupBackupTask::~ObPartGroupBackupTask() {} int ObPartGroupBackupTask::init(const ObIArray& task_list, const bool is_batch_mode, storage::ObPartitionService* partition_service, const share::ObTaskId& task_id) { int ret = OB_SUCCESS; const int64_t MAX_MAP_BUCKET_NUM = 1280; SMART_VAR(ObPartMigrationTask, tmp_task) { ObChangeMemberOption change_member_option = NORMAL_CHANGE_MEMBER_LIST; common::SpinWLockGuard guard(lock_); if (is_inited_) { ret = OB_INIT_TWICE; STORAGE_LOG(WARN, "cannot init twice", K(ret)); } else if (NULL == partition_service || task_list.empty() || task_id.is_invalid()) { ret = OB_INVALID_ARGUMENT; STORAGE_LOG(WARN, "invalid args", K(ret), K(is_batch_mode), KP(partition_service), K(task_id), K(task_list)); } else if (OB_FAIL(cond_.init(ObWaitEventIds::GROUP_MIGRATE_TASK_IDLE_WAIT))) { STORAGE_LOG(WARN, "failed to init cond", K(ret)); } else { for (int64_t i = 0; OB_SUCC(ret) && i < task_list.count(); ++i) { tmp_task.arg_ = task_list.at(i); tmp_task.arg_.cluster_id_ = (tmp_task.arg_.cluster_id_ == OB_INVALID_CLUSTER_ID) ? GCONF.cluster_id : tmp_task.arg_.cluster_id_; tmp_task.status_ = ObPartMigrationTask::INIT; tmp_task.result_ = OB_SUCCESS; if (OB_FAIL(task_list_.push_back(tmp_task))) { STORAGE_LOG(WARN, "failed to add task list", K(ret)); } if (OB_SUCC(ret)) { if (0 == i) { type_ = task_list.at(i).type_; tenant_id_ = task_list.at(i).key_.get_tenant_id(); change_member_option = task_list.at(i).change_member_option_; if (!is_replica_op_valid(type_)) { ret = OB_ERR_SYS; STORAGE_LOG(ERROR, "invalid type", K(ret), K(i), K(type_), K(task_list)); } } else if (type_ != task_list.at(i).type_ || tenant_id_ != task_list.at(i).key_.get_tenant_id() || change_member_option != task_list.at(i).change_member_option_) { ret = OB_ERR_SYS; STORAGE_LOG(ERROR, "migration type or tenant_id or skip_change_member_list not same in task list", K(ret), K(i), K(task_list)); } } } if (OB_SUCC(ret)) { is_inited_ = true; is_batch_mode_ = is_batch_mode; partition_service_ = partition_service; first_error_code_ = OB_SUCCESS; task_id_ = task_id; is_finished_ = false; need_idle_ = true; change_member_option_ = change_member_option; STORAGE_LOG(INFO, "succeed to init pg group backup task", K(*this)); } } } return ret; } int ObPartGroupBackupTask::check_partition_validation() { int ret = OB_SUCCESS; if (!is_inited_) { ret = OB_NOT_INIT; STORAGE_LOG(ERROR, "not inited", K(ret)); } else { ObRecoveryPointSchemaFilter backup_filter; const ObPhysicalBackupArg& backup_arg = task_list_[0].arg_.backup_arg_; if (OB_FAIL(backup_filter.init(backup_arg.tenant_id_, backup_arg.backup_schema_version_, /*backup_schema_version*/ backup_arg.backup_schema_version_ /*current_schema_version*/))) { STORAGE_LOG(WARN, "backup schema filter init fail", K(ret)); } for (int64_t i = 0; OB_SUCC(ret) && i < task_list_.count(); ++i) { ObPartMigrationTask& sub_task = task_list_[i]; ObPartitionKey& pkey = sub_task.arg_.key_; bool in_member_list = false; bool is_working_partition = partition_service_->is_working_partition(pkey); if (ObPartGroupMigrator::get_instance().is_stop()) { ret = OB_SERVER_IS_STOPPING; STORAGE_LOG(WARN, "server is stopping", K(ret)); } else if (BACKUP_REPLICA_OP != sub_task.arg_.type_) { ret = OB_ERR_SYS; LOG_ERROR("replica op type is not backup", K(ret), "arg", sub_task.arg_); } else { if (OB_UNLIKELY(!partition_service_->is_partition_exist(pkey))) { ret = OB_ENTRY_NOT_EXIST; ObTaskController::get().allow_next_syslog(); STORAGE_LOG(WARN, "can not backup replica which is not exsit", K(ret), K(pkey), K(sub_task)); } else { // backup filter base on target version schema bool is_exist = false; if (OB_FAIL(backup_filter.check_partition_exist(pkey, is_exist))) { STORAGE_LOG(WARN, "backup filter check partition failed", K(ret), K(pkey)); } else if (OB_UNLIKELY(!is_exist)) { ret = OB_PARTITION_NOT_EXIST; STORAGE_LOG(WARN, "backup partition is not exist after filter", K(ret), K(pkey), K(sub_task)); } } } } #ifdef ERRSIM if (OB_SUCC(ret)) { ret = E(EventTable::EN_CHECK_SUB_MIGRATION_TASK) OB_SUCCESS; if (OB_FAIL(ret)) { STORAGE_LOG(ERROR, "fake EN_CHECK_SUB_MIGRATION_TASK", K(ret)); } } #endif } return ret; } int ObPartGroupBackupTask::do_task() { int ret = OB_SUCCESS; int tmp_ret = OB_SUCCESS; const int64_t start_ts = ObTimeUtility::current_time(); ObTaskController::get().switch_task(share::ObTaskType::DATA_MAINTAIN); ObCurTraceId::set(task_id_); ObTaskController::get().allow_next_syslog(); LOG_INFO("start pg group backup task", K(*this)); if (!is_inited_) { ret = OB_NOT_INIT; STORAGE_LOG(WARN, "not inited", K(ret)); } else if (OB_FAIL(check_before_do_task())) { LOG_WARN("Failed to check_before_do_task", K(ret)); } else if (OB_FAIL(check_all_pg_backup_point_created())) { LOG_WARN("failed to check all pg backup point created", K(ret)); } else if (OB_FAIL(do_part_group_backup_minor_task())) { LOG_WARN("failed to do part group backup minor task", K(ret)); } else if (OB_FAIL(do_backup_pg_metas())) { LOG_WARN("failed to do backup pg metas", K(ret)); } else if (OB_FAIL(do_part_group_backup_major_task())) { LOG_WARN("failed to do part group backup major task", K(ret)); } if (OB_FAIL(ret)) { common::SpinWLockGuard guard(lock_); if (OB_SUCCESS == first_error_code_) { first_error_code_ = ret; LOG_INFO("set first error code", K(ret), K(first_error_code_)); } } if (OB_SUCCESS != (tmp_ret = finish_group_backup_task())) { LOG_ERROR("failed to finish group backup task", K(ret)); } ObTaskController::get().allow_next_syslog(); const int64_t cost_ts = ObTimeUtility::current_time() - start_ts; LOG_INFO("group backup task finish", K(cost_ts), K(*this)); return ret; } int ObPartGroupBackupTask::check_before_do_task() { int ret = OB_SUCCESS; if (!is_inited_) { ret = OB_NOT_INIT; STORAGE_LOG(ERROR, "not inited", K(ret)); } else if (OB_FAIL(check_partition_validation())) { STORAGE_LOG(WARN, "failed to check_partition_validation", K(ret)); } if (OB_FAIL(ret)) { ObTaskController::get().allow_next_syslog(); first_error_code_ = ret; STORAGE_LOG(WARN, "failed to check task, mark fail", K(ret), K(*this)); } return ret; } int ObPartGroupBackupTask::do_backup_task(const ObBackupDataType& backup_data_type) { int ret = OB_SUCCESS; int tmp_ret = OB_SUCCESS; bool is_finished = false; const int64_t start_ts = ObTimeUtility::current_time(); ObTaskController::get().switch_task(share::ObTaskType::DATA_MAINTAIN); ObTaskController::get().allow_next_syslog(); LOG_INFO("start pg group backup task", K(*this)); if (!is_inited_) { ret = OB_NOT_INIT; STORAGE_LOG(WARN, "not inited", K(ret)); } else { while (!is_finished) { if (OB_SUCCESS != (tmp_ret = check_is_task_cancel())) { STORAGE_LOG(WARN, "failed to check is task cancel", K(tmp_ret)); } if (OB_SUCCESS != (tmp_ret = try_schedule_new_partition_backup(backup_data_type))) { STORAGE_LOG(WARN, "failed to try_schedule_new_partition_migration", K(tmp_ret)); } if (OB_SUCCESS != (tmp_ret = try_finish_group_backup(is_finished))) { STORAGE_LOG(WARN, "failed to try_finish_group_backup", K(tmp_ret)); } if (!is_finished) { share::dag_yield(); ObThreadCondGuard guard(cond_); if (need_idle_) { if (OB_SUCCESS != (tmp_ret = cond_.wait(PART_GROUP_TASK_IDLE_TIME_MS))) { if (OB_TIMEOUT != tmp_ret) { STORAGE_LOG(WARN, "failed to idle", K(tmp_ret)); } } } need_idle_ = true; } } } ObTaskController::get().allow_next_syslog(); const int64_t cost_ts = ObTimeUtility::current_time() - start_ts; LOG_INFO("group backup task finish", K(cost_ts), K(task_list_), K(backup_data_type)); return ret; } int ObPartGroupBackupTask::do_part_group_backup_minor_task() { int ret = OB_SUCCESS; ObBackupDataType backup_data_type; int first_error_code = OB_SUCCESS; if (!is_inited_) { ret = OB_NOT_INIT; STORAGE_LOG(WARN, "not inited", K(ret)); } else if (FALSE_IT(reset_tasks_status())) { } else if (FALSE_IT(backup_data_type.set_minor_data_backup())) { } else if (OB_FAIL(do_backup_task(backup_data_type))) { STORAGE_LOG(WARN, "failed to do backup task", K(ret)); } else { { common::SpinRLockGuard guard(lock_); first_error_code = first_error_code_; } if (OB_SUCCESS != first_error_code) { ret = first_error_code; STORAGE_LOG(WARN, "first error code has set, set failed", K(ret), K(first_error_code)); } } return ret; } int ObPartGroupBackupTask::do_part_group_backup_major_task() { int ret = OB_SUCCESS; ObBackupDataType backup_data_type; int first_error_code = OB_SUCCESS; if (!is_inited_) { ret = OB_NOT_INIT; STORAGE_LOG(WARN, "not inited", K(ret)); } else if (FALSE_IT(reset_tasks_status())) { } else if (FALSE_IT(backup_data_type.set_major_data_backup())) { } else if (OB_FAIL(do_backup_task(backup_data_type))) { STORAGE_LOG(WARN, "failed to do backup task", K(ret)); } else { { common::SpinRLockGuard guard(lock_); first_error_code = first_error_code_; } if (OB_SUCCESS != first_error_code) { ret = first_error_code; STORAGE_LOG(WARN, "first error code has set, set failed", K(ret), K(first_error_code)); } } return ret; } int ObPartGroupBackupTask::set_task_list_result( const int32_t first_error_code, const common::ObIArray& task_list) { int ret = OB_SUCCESS; if (!is_inited_) { ret = OB_NOT_INIT; STORAGE_LOG(WARN, "not inited", K(ret)); } else if (task_list_.count() != task_list.count()) { ret = OB_ERR_UNEXPECTED; LOG_WARN("backup task list num is not equal", K(ret), K(task_list_.count()), K(task_list.count())); } else { for (int64_t i = 0; OB_SUCC(ret) && i < task_list.count(); ++i) { const ObPartMigrationTask& tmp_task = task_list.at(i); ObPartMigrationTask& task = task_list_.at(i); if (tmp_task.arg_.key_ != task.arg_.key_ || tmp_task.arg_.type_ != task.arg_.type_) { ret = OB_ERR_UNEXPECTED; LOG_WARN("backup task is not same", K(ret), K(task), K(tmp_task)); } else { task.during_migrating_ = tmp_task.during_migrating_; task.need_reset_migrate_status_ = tmp_task.need_reset_migrate_status_; task.result_ = tmp_task.result_; task.status_ = tmp_task.status_; } } if (OB_SUCC(ret)) { common::SpinWLockGuard guard(lock_); if (OB_SUCCESS == first_error_code_) { first_error_code_ = first_error_code; STORAGE_LOG(WARN, "set first_error_code_", K(ret)); } } } return ret; } int ObPartGroupBackupTask::finish_group_backup_task() { int ret = OB_SUCCESS; int first_error_code = OB_SUCCESS; if (!is_inited_) { ret = OB_NOT_INIT; STORAGE_LOG(WARN, "not inited", K(ret)); } else { { common::SpinRLockGuard guard(lock_); first_error_code = first_error_code_; } SMART_VAR(ObReportPartMigrationTask, tmp_task) { if (OB_FAIL(report_list_.reserve(task_list_.count()))) { STORAGE_LOG(WARN, "failed to reserve report list", K(ret)); } for (int64_t i = 0; OB_SUCC(ret) && i < task_list_.count(); ++i) { ObPartMigrationTask& sub_task = task_list_[i]; if (ObIPartMigrationTask::INIT == sub_task.status_) { sub_task.result_ = first_error_code; } tmp_task.arg_ = sub_task.arg_; tmp_task.status_ = ObIPartMigrationTask::FINISH; tmp_task.result_ = sub_task.result_; tmp_task.need_report_checksum_ = sub_task.ctx_.need_report_checksum_; tmp_task.ctx_ = &sub_task.ctx_; if (OB_FAIL(report_list_.push_back(tmp_task))) { // report_list is reserved before, should not fail here STORAGE_LOG(ERROR, "failed to add report list", K(ret)); } } if (OB_SUCC(ret)) { is_finished_ = true; } } } return ret; } int ObPartGroupBackupTask::do_backup_pg_metas() { int ret = OB_SUCCESS; int tmp_ret = OB_SUCCESS; // backup meta if (!is_inited_) { ret = OB_NOT_INIT; STORAGE_LOG(WARN, "not inited", K(ret)); } else if (OB_UNLIKELY(BACKUP_REPLICA_OP != type_)) { ret = OB_ERR_UNEXPECTED; STORAGE_LOG(WARN, "type must be backup", K(ret), K(type_)); } else if (FALSE_IT(reset_tasks_status())) { } else { common::SpinRLockGuard guard(lock_); SMART_VAR(ObBackupMetaWriter, meta_writer) { common::ObInOutBandwidthThrottle* throttle = ObPartitionMigrator::get_instance().get_bandwidth_throttle(); if (OB_ISNULL(throttle)) { ret = OB_ERR_UNEXPECTED; STORAGE_LOG(WARN, "BandwidthThrottle should not be null here", K(ret)); } else if (OB_FAIL(meta_writer.open(*throttle, task_list_))) { STORAGE_LOG(WARN, "init meta writer fail", K(ret)); } else { if (OB_FAIL(meta_writer.process())) { STORAGE_LOG(WARN, "write meta data fail", K(ret)); } if (OB_SUCCESS != (tmp_ret = meta_writer.close())) { LOG_WARN("failed to close meta writer", K(tmp_ret), K(ret)); if (OB_SUCC(ret)) { ret = tmp_ret; } } } } } return ret; } int ObPartGroupBackupTask::try_schedule_new_partition_backup(const ObBackupDataType& backup_data_type) { int ret = OB_SUCCESS; if (!is_inited_) { ret = OB_NOT_INIT; STORAGE_LOG(WARN, "part group backup task do not init", K(ret)); } else if (!backup_data_type.is_valid()) { ret = OB_INVALID_ARGUMENT; STORAGE_LOG(WARN, "try schedule new partition backup get invalid argument", K(ret), K(backup_data_type)); } else { { common::SpinRLockGuard guard(lock_); if (OB_SUCCESS != first_error_code_) { ret = first_error_code_; STORAGE_LOG(WARN, "first_error_code_ is set, skip schedule new partition backup", K(ret)); } } if (OB_SUCC(ret)) { if (OB_FAIL(try_schedule_partition_backup(backup_data_type))) { STORAGE_LOG(WARN, "failed to try schedule partition backup", K(ret)); } } } return ret; } int ObPartGroupBackupTask::try_schedule_partition_backup(const ObBackupDataType& backup_data_type) { int ret = OB_SUCCESS; bool need_schedule = true; ObPartMigrationTask* task = NULL; int64_t data_backup_concurrency = GCONF.backup_concurrency; int32_t up_limit = 0; if (OB_FAIL(ObDagScheduler::get_instance().get_up_limit(ObIDag::DAG_ULT_BACKUP, up_limit))) { STORAGE_LOG(WARN, "failed to get up limit", K(ret)); } else { data_backup_concurrency = data_backup_concurrency == 0 ? up_limit : data_backup_concurrency; FLOG_INFO("backup concurrency", K(data_backup_concurrency), K(up_limit)); } while (OB_SUCC(ret) && need_schedule && ObDagScheduler::get_instance().get_dag_count(ObIDag::DAG_TYPE_BACKUP) < data_backup_concurrency) { if (OB_FAIL(inner_schedule_partition(task, need_schedule))) { STORAGE_LOG(WARN, "failed to inner schedule partition", K(ret)); } else if (!need_schedule) { // do nothing } else if (OB_ISNULL(task)) { ret = OB_ERR_UNEXPECTED; STORAGE_LOG(WARN, "task need schedule but is NULL", K(ret), KP(task)); } else if (OB_FAIL(schedule_backup_dag(backup_data_type, task->ctx_))) { STORAGE_LOG(WARN, "failed to schedule backup dag", K(ret), K(task->arg_)); } } return ret; } int ObPartGroupBackupTask::inner_schedule_partition(ObPartMigrationTask*& task, bool& need_schedule) { int ret = OB_SUCCESS; need_schedule = false; task = NULL; common::SpinRLockGuard guard(lock_); for (int64_t i = 0; OB_SUCC(ret) && i < task_list_.count(); ++i) { task = &task_list_.at(i); bool as_data_source = false; if (type_ != task->arg_.type_ || !is_replica_op_valid(task->arg_.type_)) { ret = OB_ERR_SYS; STORAGE_LOG(ERROR, "invalid type, cannot handle this task", K(ret), K(i), K(*task)); } else if (REMOVE_REPLICA_OP == type_) { // do nothing // TODO() remove replica op backup need cancel all task and notice rs need retry } else if (OB_FAIL(check_can_as_data_source(type_, task->arg_.data_src_.get_replica_type(), task->arg_.dst_.get_replica_type(), as_data_source))) { STORAGE_LOG(WARN, "fail to check can as data source", K(ret), K(task->arg_)); } else if (!as_data_source) { ret = OB_NOT_SUPPORTED; first_error_code_ = ret; LOG_ERROR("invalid data src", K(ret), K(task->arg_)); } else if (ObPartMigrationTask::INIT == task->status_) { if (OB_FAIL(build_migrate_ctx(task->arg_, task->ctx_))) { STORAGE_LOG(WARN, "fail to build migrate ctx", K(ret)); } else { need_schedule = true; break; } } } return ret; } // caller must not hold wlock int ObPartGroupBackupTask::schedule_backup_dag(const ObBackupDataType& backup_data_type, ObMigrateCtx& migrate_ctx) { int ret = OB_SUCCESS; int tmp_ret = OB_SUCCESS; if (!is_inited_) { ret = OB_NOT_INIT; LOG_ERROR("not inited", K(ret)); } else if (OB_FAIL(check_partition_checksum(migrate_ctx.replica_op_arg_.key_))) { STORAGE_LOG(WARN, "failed to check partition checksum, cannot schedule backup", K(ret), K(migrate_ctx.replica_op_arg_.key_)); } else if (OB_FAIL(migrate_ctx.generate_and_schedule_backup_dag(backup_data_type))) { STORAGE_LOG(WARN, "failed to generate backup dag", K(ret)); } if (OB_FAIL(ret)) { share::ObTaskId fake_task_id; const bool during_migrating = false; const int64_t fake_backup_set_id = 0; if (OB_SUCCESS != (tmp_ret = set_part_task_finish( migrate_ctx.replica_op_arg_.key_, ret, fake_task_id, during_migrating, fake_backup_set_id))) { LOG_WARN("failed to finish part task", K(ret)); } } return ret; } int ObPartGroupBackupTask::try_finish_group_backup(bool& is_finished) { int ret = OB_SUCCESS; bool is_sub_task_finish = true; report_list_.reset(); is_finished = false; if (!is_inited_) { ret = OB_NOT_INIT; STORAGE_LOG(ERROR, "not inited", K(ret)); } else { common::SpinWLockGuard guard(lock_); for (int64_t i = 0; OB_SUCC(ret) && i < task_list_.count(); ++i) { ObPartMigrationTask& task = task_list_.at(i); if (ObPartMigrationTask::FINISH != task.status_) { if (OB_SUCCESS != first_error_code_ && ObPartMigrationTask::INIT == task.status_) { task.status_ = ObPartMigrationTask::FINISH; task.result_ = first_error_code_; } else { is_sub_task_finish = false; } } else if (OB_SUCCESS != task.result_) { if (OB_SUCCESS == first_error_code_) { first_error_code_ = OB_ERR_SYS; STORAGE_LOG(ERROR, "sub task has error , but first_error_code_ is succ, use OB_ERR_SYS", K(*this)); } } } if (OB_SUCC(ret) && is_sub_task_finish) { is_finished = true; } } return ret; } void ObPartGroupBackupTask::reset_tasks_status() { common::SpinWLockGuard guard(lock_); for (int64_t i = 0; i < task_list_.count(); ++i) { ObPartMigrationTask& task = task_list_.at(i); task.ctx_.rebuild_migrate_ctx(); task.status_ = ObPartMigrationTask::INIT; task.result_ = OB_SUCCESS; task.need_reset_migrate_status_ = false; task.during_migrating_ = false; } } // TODO() wait for backup point created int ObPartGroupBackupTask::check_all_pg_backup_point_created() { int ret = OB_SUCCESS; const int64_t start_ts = ObTimeUtility::current_time(); ObTaskController::get().allow_next_syslog(); LOG_INFO("start check all pg backup point created", K(*this)); if (!is_inited_) { ret = OB_NOT_INIT; STORAGE_LOG(WARN, "not inited", K(ret)); } else { common::SpinRLockGuard guard(lock_); for (int64_t i = 0; OB_SUCC(ret) && i < task_list_.count(); ++i) { ObPartMigrationTask& task = task_list_.at(i); const ObPartitionKey& pkey = task.arg_.key_; const int64_t backup_snapshot_version = task.arg_.backup_arg_.backup_snapshot_version_; if (OB_FAIL(check_pg_backup_point_created(pkey, backup_snapshot_version))) { LOG_WARN("failed to check pg backup point created", K(ret), K(pkey), K(backup_snapshot_version)); } } } ObTaskController::get().allow_next_syslog(); const int64_t cost_ts = ObTimeUtility::current_time() - start_ts; LOG_INFO("end check all pg backup point created", K(cost_ts), K(task_list_.count())); return ret; } int ObPartGroupBackupTask::check_pg_backup_point_created( const ObPartitionKey& pg_key, const int64_t backup_snapshot_version) { int ret = OB_SUCCESS; int tmp_ret = OB_SUCCESS; bool is_exist = false; // TODO() need wakeup minor merge if (!is_inited_) { ret = OB_NOT_INIT; STORAGE_LOG(WARN, "not inited", K(ret)); } else if (!pg_key.is_valid() || backup_snapshot_version <= 0) { ret = OB_INVALID_ARGUMENT; STORAGE_LOG( WARN, "check pg backup point created get invalid argument", K(ret), K(pg_key), K(backup_snapshot_version)); } else { while (OB_SUCC(ret)) { // check_backup_point exist if (ObPartGroupMigrator::get_instance().is_stop()) { ret = OB_SERVER_IS_STOPPING; STORAGE_LOG(WARN, "server is stopping", K(ret)); } else { ObIPartitionGroupGuard guard; ObIPartitionGroup* partition_group = NULL; if (OB_FAIL(ObPartitionService::get_instance().get_partition(pg_key, guard))) { LOG_WARN("failed to get partition guard", K(ret), K(pg_key)); } else if (OB_ISNULL(partition_group = guard.get_partition_group())) { ret = OB_ERR_SYS; LOG_ERROR("partition must not null", K(ret), K(pg_key)); } else if (OB_FAIL(partition_group->get_pg_storage().get_recovery_data_mgr().check_backup_point_exist( backup_snapshot_version, is_exist))) { LOG_WARN("failed to check backup point exist", K(ret), K(pg_key)); } } if (OB_FAIL(ret)) { } else if (is_exist) { break; } else { if (REACH_TIME_INTERVAL(10 * 1000 * 1000)) { // 10s LOG_INFO("backup point is not exist, need wait", K(backup_snapshot_version), K(pg_key)); } share::dag_yield(); ObThreadCondGuard guard(cond_); if (need_idle_) { if (OB_SUCCESS != (tmp_ret = cond_.wait(PART_GROUP_BACKUP_POINT_CHECK_TIME_MS))) { if (OB_TIMEOUT != tmp_ret) { STORAGE_LOG(WARN, "failed to idle", K(tmp_ret)); } } } need_idle_ = true; } } } return ret; } ObBackupPrepareTask::ObBackupPrepareTask() : ObITask(TASK_TYPE_MIGRATE_PREPARE), is_inited_(false), ctx_(NULL), cp_fty_(NULL), bandwidth_throttle_(NULL), partition_service_(NULL), backup_meta_reader_(NULL) {} ObBackupPrepareTask::~ObBackupPrepareTask() { if (NULL != cp_fty_) { if (NULL != backup_meta_reader_) { cp_fty_->free(backup_meta_reader_); } } } int ObBackupPrepareTask::init(ObIPartitionComponentFactory& cp_fty, common::ObInOutBandwidthThrottle& bandwidth_throttle, ObPartitionService& partition_service) { int ret = OB_SUCCESS; if (is_inited_) { ret = OB_INIT_TWICE; LOG_ERROR("cannot init twice", K(ret)); } else if (ObIDag::DAG_TYPE_BACKUP != dag_->get_type()) { ret = OB_ERR_SYS; LOG_ERROR("dag type not match", K(ret), K(*dag_)); } else { ctx_ = static_cast(dag_)->get_ctx(); is_inited_ = true; bandwidth_throttle_ = &bandwidth_throttle; partition_service_ = &partition_service; cp_fty_ = &cp_fty; } return ret; } int ObBackupPrepareTask::prepare_backup_reader() { int ret = OB_SUCCESS; if (!is_inited_) { ret = OB_NOT_INIT; STORAGE_LOG(ERROR, "not inited", K(ret)); } else if (BACKUP_REPLICA_OP == ctx_->replica_op_arg_.type_) { if (OB_ISNULL(ctx_->backup_meta_reader_ = cp_fty_->get_partition_group_meta_backup_reader())) { ret = OB_ERR_UNEXPECTED; STORAGE_LOG(WARN, "pg meta reader should not be NULL", K(ret)); } else if (OB_FAIL(ctx_->backup_meta_reader_->init(ctx_->pg_meta_, ctx_->replica_op_arg_.backup_arg_))) { STORAGE_LOG(WARN, "fail to init backup meta reader", K(ret)); } } return ret; } int ObBackupPrepareTask::process() { int ret = OB_SUCCESS; int tmp_ret = OB_SUCCESS; ObITask* last_task = nullptr; if (NULL != ctx_) { ctx_->action_ = ObMigrateCtx::PREPARE; if (NULL != dag_) { ctx_->task_id_ = dag_->get_dag_id(); } if (OB_SUCCESS != (tmp_ret = (ctx_->trace_id_array_.push_back(*ObCurTraceId::get_trace_id())))) { STORAGE_LOG(WARN, "failed to push back trace id to array", K(tmp_ret)); } LOG_INFO("start ObBackupPrepareTask process", "arg", ctx_->replica_op_arg_); } if (!is_inited_) { ret = OB_NOT_INIT; LOG_ERROR("not inited", K(ret)); } else if (OB_FAIL(add_backup_status(ctx_))) { LOG_WARN("failed to add backup status", K(ret)); } else if (OB_FAIL(prepare_backup())) { LOG_WARN("failed to prepare backup", K(ret)); } else if (OB_FAIL(schedule_backup_tasks())) { LOG_WARN("failed to schedule backup tasks", K(ret), K(*ctx_)); } if (OB_SUCC(ret)) { ObTaskController::get().allow_next_syslog(); LOG_INFO("finish prepare task", K(*ctx_)); } if (OB_FAIL(ret) && NULL != ctx_) { if (ctx_->is_need_retry(ret)) { ctx_->need_rebuild_ = true; LOG_INFO("migrate prepare task need retry", K(ret), K(*ctx_)); } ctx_->set_result_code(ret); } LOG_INFO("end ObBackupPrepareTask process", K(ret)); return ret; } int ObBackupPrepareTask::prepare_backup() { int ret = OB_SUCCESS; const bool is_write_lock = true; if (!is_inited_) { ret = OB_NOT_INIT; STORAGE_LOG(WARN, "not inited", K(ret)); } else { ObMigrateCtxGuard guard(is_write_lock, *ctx_); ctx_->use_slave_safe_read_ts_ = false; // disable logical migrate if (!ctx_->is_valid()) { ret = OB_ERR_SYS; STORAGE_LOG(ERROR, "invalid migrate ctx", K(ret), K(*this), K(*ctx_)); } else if (1 != ctx_->doing_task_cnt_) { ret = OB_ERR_SYS; STORAGE_LOG(ERROR, "doing task must be 1 during prepare action", K(ret), K(*this), K(*ctx_)); } else if (REMOVE_REPLICA_OP == ctx_->replica_op_arg_.type_) { ret = OB_ERR_SYS; STORAGE_LOG(ERROR, "should not prepare migrate for remove replica", K(ret), K(ctx_->replica_op_arg_)); } else if (OB_FAIL(build_backup_prepare_context())) { LOG_WARN("failed to build backup prepare context", K(ret)); } else if (OB_FAIL(prepare_backup_reader())) { LOG_WARN("failed to prepare backup reader", K(ret)); } else if (OB_FAIL(check_backup_data_continues())) { LOG_WARN("failed to check backup data continues", K(ret)); } else if (OB_FAIL(build_backup_pg_partition_info())) { LOG_WARN("failed to build backup pg partition info", K(ret), K(*ctx_)); } else { ctx_->need_rebuild_ = false; ObTaskController::get().allow_next_syslog(); STORAGE_LOG(INFO, "finish prepare backup", "pkey", ctx_->replica_op_arg_.key_, K(*ctx_)); } if (OB_FAIL(ret)) { if (NULL != ctx_) { ctx_->result_ = ret; } } } return ret; } int ObBackupPrepareTask::add_backup_status(ObMigrateCtx* ctx) { int ret = OB_SUCCESS; if (!is_inited_) { ret = OB_NOT_INIT; STORAGE_LOG(WARN, "not inited", K(ret)); } else if (NULL == ctx) { ret = OB_INVALID_ARGUMENT; STORAGE_LOG(WARN, "invalid arg", K(ret)); } else if (!ctx->is_valid()) { ret = OB_INVALID_ARGUMENT; STORAGE_LOG(WARN, "invalid args", K(ret), K(*ctx)); } else if (OB_FAIL(add_partition_backup_status(*ctx))) { STORAGE_LOG(WARN, "failed to add partition_backup_status", K(ret), K(*ctx)); } else { STORAGE_LOG(INFO, "succeed to add backup ctx", KP(ctx), K(*ctx)); } return ret; } int ObBackupPrepareTask::add_partition_backup_status(const ObMigrateCtx& ctx) { int ret = OB_SUCCESS; int tmp_ret = OB_SUCCESS; if (!is_inited_) { ret = OB_NOT_INIT; STORAGE_LOG(WARN, "not inited", K(ret)); } else if (!ctx.is_valid()) { ret = OB_INVALID_ARGUMENT; STORAGE_LOG(WARN, "invalid args", K(ret), K(ctx)); } else { ObPartitionMigrationStatus task; task.task_id_ = ctx.task_id_; task.migrate_type_ = ctx.replica_op_arg_.get_replica_op_type_str(); task.pkey_ = ctx.replica_op_arg_.key_; task.clog_parent_.reset(); // we don't know it now task.src_.reset(); // we don't know it now task.dest_ = OBSERVER.get_self(); task.result_ = ctx.result_; task.start_time_ = ctx.create_ts_; task.action_ = ctx.action_; task.replica_state_ = OB_UNKNOWN_REPLICA; // we don't know it now task.doing_task_count_ = 0; task.total_task_count_ = 0; task.rebuild_count_ = 0; task.continue_fail_count_ = 0; task.data_statics_ = ctx.data_statics_; // allow comment truncation, no need to set ret (void)ctx.fill_comment(task.comment_, sizeof(task.comment_)); if (OB_SUCCESS != (tmp_ret = ObPartitionMigrationStatusMgr::get_instance().add_status(task))) { STORAGE_LOG(WARN, "failed to add partition migration status", K(tmp_ret), K(task)); } } return ret; } int ObBackupPrepareTask::build_backup_prepare_context() { int ret = OB_SUCCESS; ObIPartitionGroup* partition = NULL; ObPGStorage* pg_storage = NULL; int64_t trans_table_end_log_ts = 0; int64_t trans_table_timestamp = 0; ObPartitionGroupMeta local_pg_meta; ObPartGroupMigrationTask* group_task = NULL; if (!is_inited_) { ret = OB_NOT_INIT; LOG_WARN("not inited", K(ret)); } else if (OB_NOT_NULL(partition = ctx_->get_partition())) { // do nothing pg_storage = &(partition->get_pg_storage()); LOG_INFO("partition already hold, do not hold again"); } else if (OB_FAIL(ObPartitionService::get_instance().get_partition( ctx_->replica_op_arg_.key_, ctx_->partition_guard_))) { LOG_WARN("partition is not exist, cannot backup partition", K(ret), K(*ctx_)); } else if (OB_ISNULL(partition = ctx_->partition_guard_.get_partition_group()) || OB_ISNULL(pg_storage = &(partition->get_pg_storage()))) { ret = OB_ERR_SYS; STORAGE_LOG(ERROR, "partition must not null", K(ret)); } else if (OB_FAIL(pg_storage->get_backup_pg_meta_data( ctx_->replica_op_arg_.backup_arg_.backup_snapshot_version_, ctx_->pg_meta_))) { STORAGE_LOG(WARN, "failed to get backup pg meta data", K(ret), K(ctx_->replica_op_arg_)); } else if (!ctx_->pg_meta_.is_valid()) { ret = OB_ERR_UNEXPECTED; STORAGE_LOG(WARN, "backup ctx pg meta is invalid", K(ret), K(*ctx_)); } else if (OB_FAIL( pg_storage->get_trans_table_end_log_ts_and_timestamp(trans_table_end_log_ts, trans_table_timestamp))) { LOG_WARN("failed to get trans table end_log_ts and timestamp", K(ret), K(ctx_->replica_op_arg_)); } else { ctx_->local_publish_version_ = ctx_->pg_meta_.storage_info_.get_data_info().get_publish_version(); ctx_->local_last_replay_log_id_ = ctx_->pg_meta_.storage_info_.get_clog_info().get_last_replay_log_id(); ctx_->local_last_replay_log_ts_ = std::max(trans_table_end_log_ts, ctx_->pg_meta_.storage_info_.get_data_info().get_last_replay_log_ts()); ctx_->migrate_src_info_.src_addr_ = ctx_->replica_op_arg_.data_src_.get_server(); ctx_->migrate_src_info_.cluster_id_ = ctx_->replica_op_arg_.cluster_id_; } if (OB_FAIL(ret) && NULL != ctx_) { ctx_->can_rebuild_ = false; LOG_WARN("failed during build backup prepare context, set cannot rebuild", K(ret), K(*ctx_)); } return ret; } int ObBackupPrepareTask::build_backup_pg_partition_info() { int ret = OB_SUCCESS; ObIPGPartitionBaseDataMetaObReader* reader = NULL; if (OB_UNLIKELY(!is_inited_)) { ret = OB_NOT_INIT; LOG_WARN("not inited", K(ret)); } else if (OB_FAIL(get_partition_table_info_backup_reader(ctx_->migrate_src_info_, reader))) { LOG_WARN("failed to get partition info reader", K(ret), K(ctx_)); } else if (OB_FAIL(build_table_partition_info(ctx_->replica_op_arg_, reader))) { LOG_WARN("failed to build table partition info", K(ret), K(ctx_->replica_op_arg_)); } if (NULL != reader) { cp_fty_->free(reader); } return ret; } int ObBackupPrepareTask::build_backup_partition_info(const ObPGPartitionMetaInfo& partition_meta_info, const common::ObIArray& table_info_res, const common::ObIArray& table_id_list, ObPartitionMigrateCtx& part_migrate_ctx) { int ret = OB_SUCCESS; ObMigrateTableInfo table_info; int64_t cost_ts = ObTimeUtility::current_time(); const ObPartitionKey& pkey = partition_meta_info.meta_.pkey_; ObMigratePartitionInfo& info = part_migrate_ctx.copy_info_; part_migrate_ctx.ctx_ = ctx_; DEBUG_SYNC(BEFORE_BUILD_MIGRATE_PARTITION_INFO); if (!is_inited_) { ret = OB_NOT_INIT; LOG_WARN("not inited", K(ret)); } else if (!partition_meta_info.is_valid()) { ret = OB_INVALID_ARGUMENT; LOG_WARN("build backup partition info get invalid argument", K(ret), K(partition_meta_info)); } else if (OB_FAIL(info.meta_.deep_copy(partition_meta_info.meta_))) { LOG_WARN("fail to deep copy partition store meta", K(ret), K(partition_meta_info.meta_)); } else { for (int64_t i = 0; OB_SUCC(ret) && i < table_info_res.count(); ++i) { table_info.reuse(); const obrpc::ObFetchTableInfoResult& table_res = table_info_res.at(i); const uint64_t table_id = table_id_list.at(i); LOG_INFO("build_backup_partition_info for table", "table_id", table_id); if (OB_FAIL(build_backup_table_info(table_id, pkey, table_res, table_info))) { LOG_WARN("failed to build backup table info", K(ret)); } else if (OB_FAIL(info.table_id_list_.push_back(table_id))) { LOG_WARN("failed to push table id into array", K(ret)); } else if (OB_FAIL(info.table_infos_.push_back(table_info))) { LOG_WARN("failed to add backup table info", K(ret)); } else { LOG_INFO("add table info", K(table_info)); } } } cost_ts = ObTimeUtility::current_time() - cost_ts; LOG_INFO("build_backup_partition_info", K(cost_ts), "pkey", info.meta_.pkey_, "src", info.src_, "table_count", info.table_id_list_.count()); return ret; } int ObBackupPrepareTask::build_backup_table_info(const uint64_t table_id, const ObPartitionKey& pkey, const obrpc::ObFetchTableInfoResult& result, ObMigrateTableInfo& info) { int ret = OB_SUCCESS; const ObIArray& local_tables_info = result.table_keys_; int64_t need_reserve_major_snapshot; info.reuse(); info.table_id_ = table_id; ObBackupDag* backup_dag = NULL; ObBackupDataType backup_data_type; if (!is_inited_) { ret = OB_NOT_INIT; LOG_ERROR("not inited", K(ret)); } else if (OB_ISNULL(backup_dag = reinterpret_cast(get_dag()))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("failed to get backup dag", K(ret)); } else if (FALSE_IT(backup_data_type = backup_dag->get_backup_data_type())) { } else if (backup_data_type.is_major_backup()) { if (OB_FAIL(build_backup_major_sstable(local_tables_info, info.major_sstables_))) { LOG_WARN("failed to build backup major sstable", K(ret), K(table_id), K(pkey)); } } else if (backup_data_type.is_minor_backup()) { if (OB_FAIL(build_backup_minor_sstable(local_tables_info, info.minor_sstables_))) { LOG_WARN("failed to build backup minor sstable", K(ret), K(table_id), K(pkey)); } } else { ret = OB_ERR_UNEXPECTED; LOG_WARN("backup dag type is unexpected", K(ret), K(*ctx_), K(backup_data_type)); } if (OB_FAIL(ret)) { } else { info.multi_version_start_ = result.multi_version_start_; info.ready_for_read_ = result.is_ready_for_read_; FLOG_INFO("succeed build_backup_table_info", K(result), K(info), K(pkey), K(table_id)); } return ret; } int ObBackupPrepareTask::schedule_backup_tasks() { int ret = OB_SUCCESS; int tmp_ret = OB_SUCCESS; bool need_schedule = false; ObArray last_task_array; if (!is_inited_) { ret = OB_NOT_INIT; LOG_ERROR("not inited", K(ret)); } else if (OB_FAIL(generate_pg_backup_tasks(last_task_array))) { LOG_WARN("failed to generate backup task", K(ret)); } else { if (OB_SUCCESS != (tmp_ret = ctx_->update_partition_migration_status())) { LOG_WARN("failed to update partition migration status", K(tmp_ret)); } } return ret; } int ObBackupPrepareTask::build_backup_major_sstable( const ObIArray& local_tables, ObIArray& copy_sstables) { int ret = OB_SUCCESS; if (!is_inited_) { ret = OB_NOT_INIT; LOG_WARN("backup prepare task do not init", K(ret)); } else { for (int64_t i = 0; OB_SUCC(ret) && i < local_tables.count(); ++i) { const ObITable::TableKey& local_table = local_tables.at(i); if (local_table.is_major_sstable()) { ObMigrateTableInfo::SSTableInfo info; info.src_table_key_ = local_table; info.dest_base_version_ = local_table.get_base_version(); info.dest_log_ts_range_ = local_table.log_ts_range_; if (OB_FAIL(copy_sstables.push_back(info))) { LOG_WARN("failed to push backup table into array", K(ret), K(local_table), K(copy_sstables)); } } } if (OB_SUCC(ret)) { LOG_INFO("build_backup_major_sstable", K(copy_sstables), K(local_tables)); } } return ret; } int ObBackupPrepareTask::build_backup_minor_sstable( const ObIArray& local_tables, ObIArray& copy_sstables) { int ret = OB_SUCCESS; ObArray tmp_copy_sstables; if (!is_inited_) { ret = OB_NOT_INIT; LOG_WARN("migrate prepare task do not init", K(ret)); } else { ObMigrateTableInfo::SSTableInfo info; for (int64_t i = 0; OB_SUCC(ret) && i < local_tables.count(); ++i) { const ObITable::TableKey& local_table = local_tables.at(i); if (local_table.is_minor_sstable()) { info.reset(); info.src_table_key_ = local_table; info.dest_base_version_ = local_table.trans_version_range_.base_version_; info.dest_log_ts_range_ = local_table.log_ts_range_; if (OB_FAIL(copy_sstables.push_back(info))) { LOG_WARN("failed to push backup table into array", K(ret), K(local_table), K(copy_sstables)); } } } if (OB_SUCC(ret)) { LOG_INFO("build_backup_minor_sstable", K(copy_sstables), K(local_tables)); } } return ret; } int ObBackupPrepareTask::generate_pg_backup_tasks(ObIArray& last_task_array) { int ret = OB_SUCCESS; ObITask* last_task = NULL; if (!is_inited_) { ret = OB_NOT_INIT; LOG_ERROR("not inited", K(ret)); } else if (BACKUP_REPLICA_OP != ctx_->replica_op_arg_.type_) { ret = OB_INVALID_ARGUMENT; LOG_WARN("unexcepted op type, ", K(ret), K(ctx_->replica_op_arg_)); } else if (!ObReplicaTypeCheck::is_replica_with_ssstore(ctx_->replica_op_arg_.src_.get_replica_type())) { ret = OB_REPLICA_CANNOT_BACKUP; LOG_WARN("replica has no sstore.", K(ret), K(ctx_->replica_op_arg_)); } else if (OB_FAIL(generate_backup_tasks(last_task))) { LOG_WARN("fail to generate backup tasks", K(ret)); } else if (OB_FAIL(last_task_array.push_back(last_task))) { LOG_WARN("fail to push last task into last task array", K(ret)); } return ret; } int ObBackupPrepareTask::generate_backup_tasks(ObITask*& last_task) { int ret = OB_SUCCESS; ObFakeTask* wait_backup_finish_task = NULL; if (!is_inited_) { ret = OB_NOT_INIT; LOG_ERROR("not inited", K(ret)); } else if (OB_FAIL(generate_wait_backup_finish_task(wait_backup_finish_task))) { LOG_WARN("failed to generate_wait_backup_finish_task", K(ret)); } else if (OB_ISNULL(wait_backup_finish_task)) { ret = OB_ERR_SYS; LOG_ERROR("wait_rebuild_finish_task must not null", K(ret)); } else if (OB_FAIL(generate_backup_tasks(*wait_backup_finish_task))) { LOG_WARN("failed to generate_backup_tasks", K(ret)); } if (OB_SUCC(ret)) { last_task = wait_backup_finish_task; } return ret; } int ObBackupPrepareTask::generate_backup_tasks(ObFakeTask& wait_backup_finish_task) { int ret = OB_SUCCESS; ObITask* parent_task = this; if (!is_inited_) { ret = OB_NOT_INIT; LOG_ERROR("not inited", K(ret)); } else if (OB_FAIL(generate_backup_sstable_tasks(parent_task))) { LOG_WARN("failed to generate backup major tasks", K(ret)); } else if (OB_FAIL(parent_task->add_child(wait_backup_finish_task))) { LOG_WARN("failed to add wait_migrate_finish_task", K(ret)); } return ret; } int ObBackupPrepareTask::generate_backup_sstable_tasks(share::ObITask*& parent_task) { int ret = OB_SUCCESS; ObFakeTask* wait_finish_task = NULL; if (!is_inited_) { ret = OB_NOT_INIT; LOG_WARN("migrate prepare task do not init", K(ret)); } else if (OB_ISNULL(parent_task)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid argument", K(ret), KP(parent_task)); } else if (OB_FAIL(dag_->alloc_task(wait_finish_task))) { LOG_WARN("failed to alloc wait finish task", K(ret)); } else if (OB_FAIL(generate_backup_sstable_copy_task(parent_task, wait_finish_task))) { LOG_WARN("failed to generate major sstable copy task", K(ret)); } else if (OB_FAIL(dag_->add_task(*wait_finish_task))) { LOG_WARN("failed to add wait finish task", K(ret)); } else { parent_task = wait_finish_task; LOG_DEBUG("succeed to generate_backup_sstable_task"); } return ret; } int ObBackupPrepareTask::generate_backup_sstable_copy_task(ObITask* parent_task, ObITask* child_task) { int ret = OB_SUCCESS; ObBackupCopyPhysicalTask* copy_task = NULL; ObBackupFinishTask* finish_task = NULL; const int64_t task_idx = 0; if (OB_UNLIKELY(!is_inited_)) { ret = OB_NOT_INIT; LOG_WARN("not inited", K(ret)); } else if (OB_ISNULL(parent_task) || OB_ISNULL(child_task)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid args", K(ret), KP(parent_task), KP(child_task)); } else if (OB_FAIL(dag_->alloc_task(finish_task))) { LOG_WARN("failed to alloc finish task", K(ret)); } else if (OB_FAIL(build_backup_physical_ctx(ctx_->physical_backup_ctx_))) { LOG_WARN("failed to build physical sstable ctx", K(ret)); } else if (OB_FAIL(finish_task->init(*ctx_))) { LOG_WARN("failed to init finish task", K(ret)); } else if (OB_FAIL(finish_task->add_child(*child_task))) { LOG_WARN("failed to add child", K(ret)); } if (OB_SUCC(ret)) { if (ctx_->physical_backup_ctx_.get_task_count() > 0) { // parent->copy->finish->child if (OB_FAIL(dag_->alloc_task(copy_task))) { LOG_WARN("failed to alloc copy task", K(ret)); } else if (OB_FAIL(copy_task->init(task_idx, *ctx_))) { LOG_WARN("failed to init copy task", K(ret)); } else if (OB_FAIL(parent_task->add_child(*copy_task))) { LOG_WARN("failed to add child copy task", K(ret)); } else if (OB_FAIL(copy_task->add_child(*finish_task))) { LOG_WARN("failed to add child finish task", K(ret)); } else if (OB_FAIL(dag_->add_task(*copy_task))) { LOG_WARN("failed to add copy task to dag", K(ret)); } } else { // parent->finish->child if (OB_FAIL(parent_task->add_child(*finish_task))) { LOG_WARN("failed to add child finish_task for parent", K(ret)); } } } if (OB_SUCC(ret)) { if (OB_FAIL(dag_->add_task(*finish_task))) { LOG_WARN("failed to add finish task to dag", K(ret)); } } return ret; } int ObBackupPrepareTask::build_backup_physical_ctx(ObBackupPhysicalPGCtx& ctx) { int ret = OB_SUCCESS; ObBackupDataType backup_data_type; ObBackupDag* backup_dag = NULL; if (OB_UNLIKELY(!is_inited_)) { ret = OB_NOT_INIT; LOG_WARN("not inited", K(ret)); } else if (OB_ISNULL(backup_dag = reinterpret_cast(get_dag()))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("failed to get backup dag", K(ret)); } else if (FALSE_IT(backup_data_type = backup_dag->get_backup_data_type())) { } else if (OB_FAIL(ctx.open( *bandwidth_throttle_, ctx_->replica_op_arg_.backup_arg_, ctx_->pg_meta_.pg_key_, backup_data_type))) { LOG_WARN("ctx init failed", K(ret)); } else if (OB_FAIL(fetch_backup_sstables(backup_data_type, ctx.table_keys_))) { LOG_WARN("failed to build sub task", K(ret)); } else if (ctx.table_keys_.empty()) { LOG_INFO("pg don't have sstable, ", K(ret), K(ctx_->pg_meta_)); } else if (OB_FAIL(build_backup_sub_task(ctx))) { LOG_WARN("failed to build sub task", K(ret)); } else { ATOMIC_AAF(&ctx_->data_statics_.total_macro_block_, ctx.macro_block_count_); LOG_INFO("succeed to build physical sstable ctx", K(ctx)); } return ret; } int ObBackupPrepareTask::fetch_backup_sstables( const ObBackupDataType& backup_data_type, ObIArray& table_keys) { int ret = OB_SUCCESS; if (OB_UNLIKELY(!is_inited_)) { ret = OB_NOT_INIT; LOG_ERROR("not inited", K(ret)); } else if (!backup_data_type.is_valid()) { ret = OB_INVALID_ARGUMENT; LOG_WARN("fetch backup sstables get invalid argument", K(ret), K(backup_data_type)); } else if (backup_data_type.is_major_backup()) { if (OB_FAIL(fetch_backup_major_sstables(table_keys))) { LOG_WARN("failed to fetch backup major sstables", K(ret)); } } else { // backup minor if (OB_FAIL(fetch_backup_minor_sstables(table_keys))) { LOG_WARN("failed to fetch backup major sstables", K(ret)); } } return ret; } int ObBackupPrepareTask::fetch_backup_major_sstables(ObIArray& table_keys) { int ret = OB_SUCCESS; if (OB_UNLIKELY(!is_inited_)) { ret = OB_NOT_INIT; LOG_ERROR("not inited", K(ret)); } else { // partition for (int64_t i = 0; OB_SUCC(ret) && i < ctx_->part_ctx_array_.count(); ++i) { ObPartitionMigrateCtx& part_migrate_ctx = ctx_->part_ctx_array_.at(i); if (OB_LIKELY(!part_migrate_ctx.is_valid())) { ret = OB_INVALID_ARGUMENT; LOG_WARN("part_migrate_ctx is invalid", K(ret), K(part_migrate_ctx)); } else { // tables const ObArray& table_infos = part_migrate_ctx.copy_info_.table_infos_; for (int64_t i = 0; OB_SUCC(ret) && i < table_infos.count(); ++i) { const ObMigrateTableInfo& table_info = table_infos.at(i); // major sstables for (int64_t sstable_idx = 0; OB_SUCC(ret) && sstable_idx < table_info.major_sstables_.count(); ++sstable_idx) { const ObITable::TableKey& major_table_key = table_info.major_sstables_.at(sstable_idx).src_table_key_; if (OB_UNLIKELY(!major_table_key.is_valid())) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid major table key", K(ret), K(major_table_key)); } else if (OB_UNLIKELY(!ObITable::is_major_sstable(major_table_key.table_type_))) { ret = OB_ERR_SYS; LOG_ERROR("table type is not major sstable", K(ret), K(major_table_key), K(table_info)); } else if (OB_FAIL(table_keys.push_back(major_table_key))) { LOG_WARN("failed to push major table key into array", K(ret), K(major_table_key)); } } } } } } return ret; } int ObBackupPrepareTask::fetch_backup_minor_sstables(ObIArray& table_keys) { int ret = OB_SUCCESS; if (OB_UNLIKELY(!is_inited_)) { ret = OB_NOT_INIT; LOG_ERROR("not inited", K(ret)); } else { // partition for (int64_t i = 0; OB_SUCC(ret) && i < ctx_->part_ctx_array_.count(); ++i) { ObPartitionMigrateCtx& part_migrate_ctx = ctx_->part_ctx_array_.at(i); if (OB_LIKELY(!part_migrate_ctx.is_valid())) { ret = OB_INVALID_ARGUMENT; LOG_WARN("part_migrate_ctx is invalid", K(ret), K(part_migrate_ctx)); } else { // tables const ObArray& table_infos = part_migrate_ctx.copy_info_.table_infos_; for (int64_t i = 0; OB_SUCC(ret) && i < table_infos.count(); ++i) { const ObMigrateTableInfo& table_info = table_infos.at(i); // minor sstables for (int64_t sstable_idx = 0; OB_SUCC(ret) && sstable_idx < table_info.minor_sstables_.count(); ++sstable_idx) { const ObITable::TableKey& minor_table_key = table_info.minor_sstables_.at(sstable_idx).src_table_key_; if (OB_UNLIKELY(!minor_table_key.is_valid())) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid major table key", K(ret), K(minor_table_key)); } else if (OB_UNLIKELY(!ObITable::is_minor_sstable(minor_table_key.table_type_))) { ret = OB_ERR_SYS; LOG_ERROR("table type is not minor sstable", K(ret), K(minor_table_key), K(table_info)); } else if (OB_FAIL(table_keys.push_back(minor_table_key))) { LOG_WARN("failed to push major table key into array", K(ret), K(minor_table_key)); } } } } } } return ret; } int ObBackupPrepareTask::build_backup_sub_task(ObBackupPhysicalPGCtx& ctx) { int ret = OB_SUCCESS; if (OB_UNLIKELY(!is_inited_)) { ret = OB_NOT_INIT; LOG_ERROR("not inited", K(ret)); } else { for (int i = 0; OB_SUCC(ret) && i < ctx.table_keys_.count(); ++i) { ObTableHandle tmp_handle; ObSSTable* sstable = NULL; int64_t sstable_macro_count = 0; ObITable::TableKey& table_key = ctx.table_keys_.at(i); if (OB_FAIL(ObPartitionService::get_instance().acquire_sstable(table_key, tmp_handle))) { STORAGE_LOG(WARN, "failed to get table", K(table_key), K(ret)); } else if (OB_FAIL(tmp_handle.get_sstable(sstable))) { STORAGE_LOG(WARN, "failed to get table", K(table_key), K(ret)); } else if (OB_ISNULL(sstable)) { ret = OB_ERR_UNEXPECTED; STORAGE_LOG(WARN, "sstable should not be null", K(ret)); } else if (0 == (sstable_macro_count = sstable->get_meta().get_total_macro_block_count())) { // empty sstable } else { ObBackupMacroBlockInfo block_info; block_info.table_key_ = table_key; block_info.start_index_ = 0; block_info.cur_block_count_ = sstable_macro_count; block_info.total_block_count_ = sstable_macro_count; if (OB_FAIL(ctx.add_backup_macro_block_info(block_info))) { STORAGE_LOG(WARN, "add backup block info failed", K(ret), K(block_info)); } } } } return ret; } int ObBackupPrepareTask::generate_wait_backup_finish_task(ObFakeTask*& wait_backup_finish_task) { int ret = OB_SUCCESS; wait_backup_finish_task = NULL; if (!is_inited_) { ret = OB_NOT_INIT; LOG_ERROR("not inited", K(ret)); } else if (OB_FAIL(dag_->alloc_task(wait_backup_finish_task))) { LOG_WARN("failed to alloc wait_rebuild_finish_task", K(ret)); } else if (OB_FAIL(add_child(*wait_backup_finish_task))) { LOG_WARN("failed to add child wait_rebuild_finish_task", K(ret)); } else if (OB_FAIL(dag_->add_task(*wait_backup_finish_task))) { LOG_WARN("failed to add wait_rebuild_finish_task", K(ret)); } return ret; } int ObBackupPrepareTask::build_table_partition_info( const ObReplicaOpArg& arg, ObIPGPartitionBaseDataMetaObReader* reader) { int ret = OB_SUCCESS; ObPartitionMigrateCtx part_migrate_ctx; ObArray table_info_res; ObArray table_id_list; ObPGPartitionMetaInfo partition_meta_info; if (OB_UNLIKELY(!is_inited_)) { ret = OB_NOT_INIT; LOG_WARN("migrate prepare task do not init", K(ret)); } else if (!arg.is_valid() || OB_ISNULL(reader)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("build table partition info get invalid argument", K(ret), K(arg), KP(reader)); } else { while (OB_SUCC(ret)) { partition_meta_info.reset(); table_info_res.reuse(); table_id_list.reuse(); part_migrate_ctx.reset(); if (OB_FAIL(reader->fetch_pg_partition_meta_info(partition_meta_info))) { if (OB_ITER_END != ret) { LOG_WARN("fail to fetch pg partition meta info", K(ret), K(ctx_->replica_op_arg_)); } else { ret = OB_SUCCESS; break; } } else if (OB_FAIL(table_id_list.assign(partition_meta_info.table_id_list_))) { LOG_WARN("failed to assign table id list", K(ret)); } else if (OB_FAIL(table_info_res.assign(partition_meta_info.table_info_))) { LOG_WARN("failed to copy needed table info", K(ret), K(partition_meta_info)); } else if (OB_FAIL(build_backup_partition_info( partition_meta_info, table_info_res, table_id_list, part_migrate_ctx))) { LOG_WARN("fail to build migrate partition info", K(ret), K(partition_meta_info)); } else if (OB_FAIL(ctx_->part_ctx_array_.push_back(part_migrate_ctx))) { LOG_WARN("fail to push part migrate ctx into array", K(ret), K(part_migrate_ctx)); } } } return ret; } int ObBackupPrepareTask::get_partition_table_info_backup_reader( const ObMigrateSrcInfo& src_info, ObIPGPartitionBaseDataMetaObReader*& reader) { int ret = OB_SUCCESS; UNUSED(src_info); ObPGPartitionBaseDataMetaBackupReader* tmp_reader = NULL; if (OB_ISNULL(cp_fty_)) { ret = OB_ERR_SYS; LOG_ERROR("cp fty should not be NULL", K(ret), KP(cp_fty_)); } else if (OB_ISNULL(tmp_reader = cp_fty_->get_pg_info_backup_reader())) { ret = OB_ALLOCATE_MEMORY_FAILED; STORAGE_LOG(WARN, "failed to get macro block ob reader", K(ret)); } else if (OB_ISNULL(ctx_->backup_meta_reader_)) { ret = OB_ERR_SYS; LOG_ERROR("ctx_->backup_meta_reader_ must not null", K(ret)); } else if (OB_FAIL(tmp_reader->init(ctx_->pg_meta_.partitions_, ctx_->backup_meta_reader_))) { LOG_WARN("fail to init partition table info restore reader", K(ret)); } else { reader = tmp_reader; tmp_reader = NULL; } if (NULL != cp_fty_) { if (NULL != tmp_reader) { cp_fty_->free(tmp_reader); tmp_reader = NULL; } } return ret; } int ObBackupPrepareTask::check_backup_data_continues() { int ret = OB_SUCCESS; ObIPartitionGroup* partition_group = NULL; clog::ObPGLogArchiveStatus pg_log_archive_status; ObLogArchiveBackupInfo archive_backup_info; const int64_t start_ts = ObTimeUtility::current_time(); static const int64_t OB_MAX_RETRY_TIME = 60 * 1000 * 1000; // 60s static const int64_t OB_SINGLE_SLEEP_US = 1 * 1000 * 1000; // 1s const int64_t last_replay_log_id = ctx_->pg_meta_.storage_info_.get_clog_info().get_last_replay_log_id(); if (!is_inited_) { ret = OB_NOT_INIT; LOG_WARN("migrate prepare task do not init", K(ret)); } else if (BACKUP_REPLICA_OP != ctx_->replica_op_arg_.type_) { // do nothing } else if (OB_ISNULL(partition_group = ctx_->get_partition())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("backup local partition should not be NULL", K(ret), KP(partition_group), K(*ctx_)); } else { while (OB_SUCC(ret)) { if (OB_FAIL(partition_group->get_log_archive_status(pg_log_archive_status))) { LOG_WARN("failed to get log archive status", K(ret), K(*ctx_)); } else if (OB_FAIL(ObBackupInfoMgr::get_instance().get_log_archive_backup_info(archive_backup_info))) { LOG_WARN("failed to get log archive backup info", K(ret)); } else if (ObLogArchiveStatus::INVALID == pg_log_archive_status.status_) { if (ObLogArchiveStatus::DOING == archive_backup_info.status_.status_) { LOG_WARN("partition group log archive status is invalid, need retry", K(pg_log_archive_status), K(archive_backup_info)); ret = OB_EAGAIN; } else { ret = OB_ERR_UNEXPECTED; LOG_WARN( "server do not archive log, can not backup", K(ret), K(pg_log_archive_status), K(archive_backup_info)); } } else if (ObLogArchiveStatus::DOING == pg_log_archive_status.status_) { if (pg_log_archive_status.archive_incarnation_ != archive_backup_info.status_.incarnation_ || pg_log_archive_status.log_archive_round_ != archive_backup_info.status_.round_) { ret = OB_ERR_UNEXPECTED; LOG_WARN("pg archive round or incarnation not equal to server archive info", K(ret), K(pg_log_archive_status), K(archive_backup_info)); } else if (pg_log_archive_status.round_start_log_id_ < 1) { ret = OB_LOG_ARCHIVE_STAT_NOT_MATCH; LOG_WARN("log archive status is not match", K(ret), K(pg_log_archive_status)); } else if (last_replay_log_id + 1 < pg_log_archive_status.round_start_log_id_) { ret = OB_ERR_UNEXPECTED; LOG_WARN("base data and log archive data do not continues", K(ret), K(pg_log_archive_status), K(ctx_->pg_meta_), K(last_replay_log_id)); } else { break; } } else { ret = OB_ERR_UNEXPECTED; LOG_WARN("log archive status is unexpected", K(ret), K(pg_log_archive_status)); } if (OB_EAGAIN == ret) { const int64_t cost_ts = ObTimeUtility::current_time() - start_ts; if (cost_ts < OB_MAX_RETRY_TIME) { usleep(OB_SINGLE_SLEEP_US); ret = OB_SUCCESS; } else { ret = OB_ERR_UNEXPECTED; LOG_WARN("server start do archive log, but partition retry many times status still wrong", K(ret), K(pg_log_archive_status), K(archive_backup_info), K(*ctx_)); } } } } return ret; } } // namespace storage } // namespace oceanbase