/** * 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 "ob_build_index_task.h" #include "lib/utility/ob_tracepoint.h" #include "share/ob_dml_sql_splicer.h" #include "share/ob_index_status_table_operator.h" #include "share/ob_index_checksum.h" #include "storage/ob_partition_scheduler.h" #include "storage/ob_partition_merge_task.h" #include "storage/ob_long_ops_monitor.h" #include "storage/ob_partition_storage.h" #include "storage/ob_partition_group.h" #include "storage/ob_pg_storage.h" #include "ob_i_table.h" #include "observer/ob_server_struct.h" using namespace oceanbase::common; using namespace oceanbase::storage; using namespace oceanbase::blocksstable; using namespace oceanbase::compaction; using namespace oceanbase::share; using namespace oceanbase::share::schema; using namespace oceanbase::observer; using namespace oceanbase::omt; ObBuildIndexDag::ObBuildIndexDag() : ObIDag(DAG_TYPE_CREATE_INDEX, DAG_PRIO_CREATE_INDEX), is_inited_(false), pkey_(), param_(), context_(), partition_service_(NULL), guard_(), partition_storage_(NULL), compat_mode_(ObWorker::CompatMode::INVALID) {} ObBuildIndexDag::~ObBuildIndexDag() { clean_up(); } int ObBuildIndexDag::init(const ObPartitionKey& pkey, ObPartitionService* partition_service) { int ret = OB_SUCCESS; if (OB_UNLIKELY(is_inited_)) { ret = OB_INIT_TWICE; STORAGE_LOG(WARN, "ObBuildIndexDag has already been inited", K(ret)); } else if (!pkey.is_valid() || NULL == partition_service) { ret = OB_INVALID_ARGUMENT; STORAGE_LOG(WARN, "invalid argument", K(ret), K(pkey), KP(partition_service)); } else { pkey_ = pkey; partition_service_ = partition_service; is_inited_ = true; if (OB_FAIL(get_compat_mode_with_table_id(pkey.table_id_, compat_mode_))) { STORAGE_LOG(WARN, "failed to get compat mode", K(ret), K(pkey)); } else if (OB_FAIL(prepare())) { STORAGE_LOG(WARN, "fail to prepare building index", K(ret)); } } return ret; } int64_t ObBuildIndexDag::hash() const { int tmp_ret = OB_SUCCESS; int64_t hash_val = 0; if (NULL == param_.index_schema_) { tmp_ret = OB_ERR_SYS; STORAGE_LOG(ERROR, "index schema must not be NULL", K(tmp_ret)); } else { hash_val = pkey_.hash() + param_.index_schema_->get_table_id(); } return hash_val; } bool ObBuildIndexDag::operator==(const ObIDag& other) const { int tmp_ret = OB_SUCCESS; bool is_equal = false; if (OB_UNLIKELY(this == &other)) { is_equal = true; } else if (get_type() == other.get_type()) { const ObBuildIndexDag& dag = static_cast(other); if (NULL == param_.index_schema_ || NULL == dag.param_.index_schema_) { tmp_ret = OB_ERR_SYS; STORAGE_LOG( ERROR, "index schema must not be NULL", K(tmp_ret), KP(param_.index_schema_), KP(dag.param_.index_schema_)); } else { is_equal = pkey_ == dag.pkey_ && param_.index_schema_->get_table_id() == dag.param_.index_schema_->get_table_id(); } } return is_equal; } int ObBuildIndexDag::get_partition(ObPGPartition*& partition) { int ret = OB_SUCCESS; partition = NULL; if (OB_UNLIKELY(!is_inited_)) { ret = OB_NOT_INIT; STORAGE_LOG(WARN, "ObBuildIndexDag has not been inited", K(ret)); } else if (OB_ISNULL(partition = guard_.get_pg_partition())) { ret = OB_ERR_UNEXPECTED; STORAGE_LOG(WARN, "error unexpected, partition must not be NULL", K(ret)); } return ret; } int ObBuildIndexDag::get_partition_group(ObIPartitionGroup*& pg) { int ret = OB_SUCCESS; pg = nullptr; if (OB_UNLIKELY(!is_inited_)) { ret = OB_NOT_INIT; STORAGE_LOG(WARN, "ObBuildIndexDag has not been inited", K(ret)); } else if (OB_ISNULL(pg = pg_guard_.get_partition_group())) { ret = OB_ERR_SYS; STORAGE_LOG(WARN, "error sys, partition must not be null", K(ret)); } return ret; } int ObBuildIndexDag::fill_comment(char* buf, const int64_t buf_len) const { int ret = OB_SUCCESS; int64_t index_id = 0; if (NULL != param_.index_schema_) { index_id = param_.index_schema_->get_table_id(); } if (OB_UNLIKELY(!is_inited_)) { ret = OB_NOT_INIT; STORAGE_LOG(WARN, "ObBuildIndexDag has not been inited", K(ret)); } else if (OB_FAIL(databuff_printf(buf, buf_len, "build index task: pkey=%s index_id=%ld snapshot_version=%ld parallelism=%ld", to_cstring(pkey_), index_id, param_.snapshot_version_, param_.concurrent_cnt_))) { STORAGE_LOG(WARN, "failed to fill comment", K(ret), K(pkey_)); } return ret; } int ObBuildIndexDag::get_partition_storage(ObPartitionStorage*& storage) { int ret = OB_SUCCESS; if (OB_UNLIKELY(!is_inited_)) { ret = OB_NOT_INIT; STORAGE_LOG(WARN, "ObBuildIndexDag has not been inited", K(ret)); } else { storage = partition_storage_; } return ret; } int ObBuildIndexDag::check_index_need_build(bool& need_build) { int ret = OB_SUCCESS; need_build = false; ObPartitionStorage* storage = NULL; ObSpinLockGuard guard(context_.lock_); if (OB_UNLIKELY(!is_inited_)) { ret = OB_NOT_INIT; STORAGE_LOG(WARN, "ObBuildIndexDag is not inited", K(ret)); } else if (!context_.need_build_) { need_build = false; } else if (OB_FAIL(get_partition_storage(storage))) { STORAGE_LOG(WARN, "fail to get partition storage", K(ret)); } else if (OB_ISNULL(storage)) { ret = OB_ERR_UNEXPECTED; STORAGE_LOG(WARN, "error unexpected, storage must not be NULL", K(ret)); } else if (OB_FAIL(storage->check_index_need_build(*param_.index_schema_, context_.need_build_))) { STORAGE_LOG(WARN, "fail to check index need build", K(ret)); } else { need_build = context_.need_build_; } return ret; } int ObBuildIndexDag::get_partition_service(ObPartitionService*& part_service) { int ret = OB_SUCCESS; if (OB_UNLIKELY(!is_inited_)) { ret = OB_NOT_INIT; STORAGE_LOG(WARN, "ObBuildIndexDag has not been inited", K(ret)); } else { part_service = partition_service_; } return ret; } int ObBuildIndexDag::get_pg(ObIPartitionGroup*& pg) { int ret = OB_SUCCESS; if (IS_NOT_INIT) { ret = OB_NOT_INIT; STORAGE_LOG(WARN, "build index dag is not inited", K(ret)); } else { pg = pg_guard_.get_partition_group(); } return ret; } int ObBuildIndexDag::prepare() { int ret = OB_SUCCESS; if (!is_inited_) { ret = OB_NOT_INIT; STORAGE_LOG(WARN, "dag is not init", K(ret)); } else if (OB_ISNULL(partition_service_) || OB_UNLIKELY(!pkey_.is_valid())) { ret = OB_ERR_SYS; STORAGE_LOG(WARN, "invalid inner status", K(ret), KP(partition_service_), K(pkey_)); } else if (OB_FAIL(partition_service_->get_partition(pkey_, pg_guard_)) || OB_ISNULL(pg_guard_.get_partition_group())) { STORAGE_LOG(WARN, "fail to get partition", K_(pkey), K(ret)); } else if (OB_FAIL(pg_guard_.get_partition_group()->get_pg_partition(pkey_, guard_)) || OB_ISNULL(guard_.get_pg_partition())) { STORAGE_LOG(WARN, "fail to get pg partition", K_(pkey), K(ret)); } else { partition_storage_ = static_cast(guard_.get_pg_partition()->get_storage()); } return ret; } int ObBuildIndexDag::clean_up() { int ret = OB_SUCCESS; if (OB_UNLIKELY(!is_inited_)) { ret = OB_NOT_INIT; STORAGE_LOG(WARN, "ObBuildIndexDag has not been inited", K(ret)); } else { bool need_retry = true; if (context_.need_build_ && !context_.is_report_succ_ && OB_FAIL(context_.build_index_ret_)) { if (OB_FAIL(ObReportIndexStatusTask::report_index_status(pkey_, param_, &context_, need_retry))) { STORAGE_LOG(ERROR, "fail to report index status", K(ret), K(pkey_), K(param_), K(context_)); } } if (NULL != context_.output_sstable_) { context_.output_sstable_ = NULL; context_.output_sstable_handle_.reset(); } } STORAGE_LOG(INFO, "build index finish", K(context_.build_index_ret_), K(pkey_), K(param_), K(context_)); return ret; } ObIndexPrepareTask::ObIndexPrepareTask() : ObITask(TASK_TYPE_INDEX_PERPARE), is_inited_(false), param_(), context_(NULL) {} ObIndexPrepareTask::~ObIndexPrepareTask() {} int ObIndexPrepareTask::init(ObBuildIndexParam& param, ObBuildIndexContext* context) { int ret = OB_SUCCESS; if (OB_UNLIKELY(is_inited_)) { ret = OB_INIT_TWICE; STORAGE_LOG(WARN, "ObIndexPrepareTask has already been inited", K(ret)); } else if (!param.is_valid() || OB_ISNULL(context)) { ret = OB_INVALID_ARGUMENT; STORAGE_LOG(WARN, "invalid arguments", K(ret), K(param), KP(context)); } else { param_ = ¶m; context_ = context; is_inited_ = true; } return ret; } int ObIndexPrepareTask::process() { int ret = OB_SUCCESS; ObIDag* tmp_dag = get_dag(); ObBuildIndexDag* dag = NULL; ObIndexLocalSortTask* local_sort_task = NULL; ObIndexMergeTask* merge_task = NULL; ObCompactToLatestTask* compact_task = NULL; ObUniqueCheckingTask* checking_task = NULL; if (OB_UNLIKELY(!is_inited_)) { ret = OB_NOT_INIT; STORAGE_LOG(WARN, "ObIndexPrepareTask has not been inited", K(ret)); } else if (NULL == tmp_dag || ObIDag::DAG_TYPE_CREATE_INDEX != tmp_dag->get_type()) { ret = OB_ERR_UNEXPECTED; STORAGE_LOG(WARN, "dag is invalid", K(ret), KP(tmp_dag)); } else if (FALSE_IT(dag = static_cast(tmp_dag))) { } else if (OB_FAIL(generate_local_sort_tasks(dag, local_sort_task))) { STORAGE_LOG(WARN, "fail to generate local sort tasks", K(ret)); } else if (OB_FAIL(generate_index_merge_task(dag, local_sort_task, merge_task))) { STORAGE_LOG(WARN, "fail to generate index merge task", K(ret)); } else if (OB_FAIL(generate_compact_task(dag, merge_task, compact_task))) { STORAGE_LOG(WARN, "fail to generate compact task", K(ret)); } else if (OB_FAIL(generate_unique_checking_task(dag, compact_task, checking_task))) { STORAGE_LOG(WARN, "fail to generate unique checking task", K(ret)); } else if (OB_FAIL(generate_report_index_status_task(dag, checking_task))) { STORAGE_LOG(WARN, "fail to generate report index status task", K(ret)); } if (OB_SUCC(ret)) { int tmp_ret = OB_SUCCESS; if (OB_SUCCESS != (tmp_ret = add_monitor_info(dag))) { STORAGE_LOG(WARN, "fail to add monitor info", K(tmp_ret)); } } if (OB_FAIL(ret)) { context_->build_index_ret_ = ret; ret = OB_SUCCESS; } return ret; } int ObIndexPrepareTask::generate_report_index_status_task(ObBuildIndexDag* dag, ObUniqueCheckingTask* checking_task) { int ret = OB_SUCCESS; ObReportIndexStatusTask* report_task = NULL; if (OB_UNLIKELY(!is_inited_)) { ret = OB_NOT_INIT; STORAGE_LOG(WARN, "ObIndexPrepareTask has not been inited", K(ret)); } else if (OB_ISNULL(dag)) { ret = OB_INVALID_ARGUMENT; STORAGE_LOG(WARN, "invalid argument", K(ret), KP(dag)); } else if (OB_FAIL(dag->alloc_task(report_task))) { STORAGE_LOG(WARN, "fail to alloc report index status task", K(ret)); } else if (OB_FAIL(report_task->init(dag->get_partition_key(), *param_, context_))) { STORAGE_LOG(WARN, "fail to init report index status task", K(ret)); } else if (OB_FAIL(checking_task->add_child(*report_task))) { STORAGE_LOG(WARN, "fail to add child for report index status task", K(ret)); } else if (OB_FAIL(dag->add_task(*report_task))) { STORAGE_LOG(WARN, "fail to add report index status task", K(ret)); } return ret; } int ObIndexPrepareTask::generate_compact_task( ObBuildIndexDag* dag, ObIndexMergeTask* merge_task, ObCompactToLatestTask*& compact_task) { int ret = OB_SUCCESS; compact_task = NULL; if (OB_UNLIKELY(!is_inited_)) { ret = OB_NOT_INIT; STORAGE_LOG(WARN, "ObIndexPrepareTask has not been inited", K(ret)); } else if (OB_ISNULL(dag) || OB_ISNULL(merge_task)) { ret = OB_INVALID_ARGUMENT; STORAGE_LOG(WARN, "invalid arguments", K(ret), KP(dag), KP(merge_task)); } else if (OB_FAIL(dag->alloc_task(compact_task))) { STORAGE_LOG(WARN, "fail to alloc compact task", K(ret)); } else if (OB_FAIL(compact_task->init(dag->get_partition_key(), *param_, context_))) { STORAGE_LOG(WARN, "fail to init compact task", K(ret)); } else if (OB_FAIL(merge_task->add_child(*compact_task))) { STORAGE_LOG(WARN, "fail to add child for index merge task", K(ret)); } else if (OB_FAIL(dag->add_task(*compact_task))) { STORAGE_LOG(WARN, "fail to add compact task", K(ret)); } return ret; } int ObIndexPrepareTask::generate_unique_checking_task( ObBuildIndexDag* dag, ObCompactToLatestTask* compact_task, ObUniqueCheckingTask*& checking_task) { int ret = OB_SUCCESS; checking_task = NULL; if (OB_UNLIKELY(!is_inited_)) { ret = OB_NOT_INIT; STORAGE_LOG(WARN, "ObIndexPrepareTask has not been inited", K(ret)); } else if (OB_ISNULL(dag) || OB_ISNULL(compact_task)) { ret = OB_INVALID_ARGUMENT; STORAGE_LOG(WARN, "invalid arguments", K(ret), KP(dag), KP(compact_task)); } else if (OB_FAIL(dag->alloc_task(checking_task))) { STORAGE_LOG(WARN, "fail to alloc checking task", K(ret)); } else if (OB_FAIL(checking_task->init(*param_, context_))) { STORAGE_LOG(WARN, "fail to init unique checking task", K(ret)); } else if (OB_FAIL(compact_task->add_child(*checking_task))) { STORAGE_LOG(WARN, "fail to add child for compact task", K(ret)); } else if (OB_FAIL(dag->add_task(*checking_task))) { STORAGE_LOG(WARN, "fail to add unique checking task", K(ret)); } return ret; } int ObIndexPrepareTask::generate_index_merge_task( ObBuildIndexDag* dag, ObIndexLocalSortTask* local_sort_task, ObIndexMergeTask*& merge_task) { int ret = OB_SUCCESS; merge_task = NULL; if (OB_UNLIKELY(!is_inited_)) { ret = OB_NOT_INIT; STORAGE_LOG(WARN, "ObIndexPrepareTask has not been inited", K(ret)); } else if (OB_ISNULL(dag) || OB_ISNULL(local_sort_task)) { ret = OB_INVALID_ARGUMENT; STORAGE_LOG(WARN, "invalid arguments", K(ret), KP(dag), KP(local_sort_task)); } else if (OB_FAIL(dag->alloc_task(merge_task))) { STORAGE_LOG(WARN, "fail to alloc index merge task", K(ret)); } else if (OB_FAIL(merge_task->init(*param_, context_))) { STORAGE_LOG(WARN, "fail to init index merge task", K(ret)); } else if (OB_FAIL(local_sort_task->add_child(*merge_task))) { STORAGE_LOG(WARN, "fail to add child for index local sort task", K(ret)); } else if (OB_FAIL(dag->add_task(*merge_task))) { STORAGE_LOG(WARN, "fail to add index merge task", K(ret)); } return ret; } int ObIndexPrepareTask::generate_local_sort_tasks(ObBuildIndexDag* dag, ObIndexLocalSortTask*& local_sort_task) { int ret = OB_SUCCESS; if (OB_UNLIKELY(!is_inited_)) { ret = OB_NOT_INIT; STORAGE_LOG(WARN, "ObIndexPrepareTask has not been inited", K(ret)); } else if (OB_ISNULL(dag)) { ret = OB_INVALID_ARGUMENT; STORAGE_LOG(WARN, "invalid arguments", K(ret), KP(dag)); } else { if (OB_FAIL(dag->alloc_task(local_sort_task))) { STORAGE_LOG(WARN, "fail to alloc local sort task", K(ret)); } else if (OB_FAIL(local_sort_task->init(0, *param_, context_))) { STORAGE_LOG(WARN, "fail to init local sort task", K(ret)); } else if (OB_FAIL(add_child(*local_sort_task))) { STORAGE_LOG(WARN, "fail to add child for index prepare task", K(ret)); } else if (OB_FAIL(dag->add_task(*local_sort_task))) { STORAGE_LOG(WARN, "fail to add local sort task to dag", K(ret)); } } return ret; } int ObIndexPrepareTask::add_monitor_info(ObBuildIndexDag* dag) { int ret = OB_SUCCESS; if (OB_UNLIKELY(!is_inited_)) { ret = OB_NOT_INIT; STORAGE_LOG(WARN, "ObIndexPrepareTask has not been inited", K(ret)); } else if (OB_ISNULL(dag)) { ret = OB_INVALID_ARGUMENT; STORAGE_LOG(WARN, "invalid argument", K(ret), KP(dag)); } else { const int64_t concurrent_cnt = param_->concurrent_cnt_; const int64_t total_task_cnt = 2 * concurrent_cnt + 1; // scan(concurrent_cnt), local_sort(concurrent_cnt), merge(1) ObPGPartition* partition = NULL; if (OB_FAIL(dag->get_partition(partition))) { STORAGE_LOG(WARN, "fail to get partition", K(ret)); } else { ObCreateIndexKey key; ObCreateIndexPartitionStat part_stat; key.index_table_id_ = param_->index_schema_->get_table_id(); key.tenant_id_ = extract_tenant_id(key.index_table_id_); key.partition_id_ = dag->get_partition_key().get_partition_id(); if (OB_FAIL(key.to_key_string())) { STORAGE_LOG(WARN, "fail to key string", K(ret)); } else { part_stat.key_ = key; part_stat.common_value_.start_time_ = ObTimeUtility::current_time(); } if (OB_FAIL(ret)) { } else if (OB_FAIL(LONG_OPS_MONITOR_INSTANCE.add_long_ops_stat(key, part_stat))) { STORAGE_LOG(WARN, "fail to add partition stat", K(ret)); } else { // scan task for (int64_t i = 0; OB_SUCC(ret) && i < concurrent_cnt; ++i) { ObCreateIndexScanTaskStat task_stat; task_stat.task_id_ = i; task_stat.type_ = ObILongOpsTaskStat::TaskType::SCAN; if (OB_FAIL(LONG_OPS_MONITOR_INSTANCE.update_task_stat(key, task_stat))) { STORAGE_LOG(WARN, "fail to update task stat", K(ret), K(key)); } } // local sort task and merge task for (int64_t i = concurrent_cnt; OB_SUCC(ret) && i < total_task_cnt; ++i) { ObCreateIndexSortTaskStat task_stat; task_stat.task_id_ = i; task_stat.type_ = ObILongOpsTaskStat::TaskType::SORT; if (OB_FAIL(LONG_OPS_MONITOR_INSTANCE.update_task_stat(key, task_stat))) { STORAGE_LOG(WARN, "fail to update task stat", K(ret), K(key)); } } } } } return ret; } ObIndexLocalSortTask::ObIndexLocalSortTask() : ObITask(TASK_TYPE_INDEX_LOCAL_SORT), is_inited_(false), task_id_(0), param_(NULL), context_(NULL), local_sorter_(NULL) {} ObIndexLocalSortTask::~ObIndexLocalSortTask() {} int ObIndexLocalSortTask::init(const int64_t task_id, ObBuildIndexParam& param, ObBuildIndexContext* context) { int ret = OB_SUCCESS; if (OB_UNLIKELY(is_inited_)) { ret = OB_INIT_TWICE; STORAGE_LOG(WARN, "ObIndexLocalSortTask has already been inited", K(ret)); } else if (task_id < 0 || !param.is_valid() || OB_ISNULL(context)) { ret = OB_INVALID_ARGUMENT; STORAGE_LOG(WARN, "invalid arguments", K(ret), K(task_id), K(param), KP(context)); } else { task_id_ = task_id; param_ = ¶m; context_ = context; is_inited_ = true; if (task_id_ >= 0 && task_id < context_->sorters_.count()) { local_sorter_ = context_->sorters_.at(task_id); } if (OB_ISNULL(local_sorter_)) { ret = OB_ERR_UNEXPECTED; STORAGE_LOG(WARN, "error unexpected, local_sort must not be NULL", K(ret)); } } return ret; } int ObIndexLocalSortTask::process() { int ret = OB_SUCCESS; ObIDag* tmp_dag = get_dag(); ObBuildIndexDag* dag = NULL; ObPartitionStorage* storage = NULL; bool need_build = false; if (OB_UNLIKELY(!is_inited_)) { ret = OB_NOT_INIT; STORAGE_LOG(WARN, "ObIndexLocalSortTask has not been inited", K(ret)); } else if (NULL == tmp_dag || ObIDag::DAG_TYPE_CREATE_INDEX != tmp_dag->get_type()) { ret = OB_ERR_UNEXPECTED; STORAGE_LOG(WARN, "dag is invalid", K(ret), KP(tmp_dag)); } else if (FALSE_IT(dag = static_cast(tmp_dag))) { } else if (OB_FAIL(dag->get_partition_storage(storage))) { STORAGE_LOG(WARN, "fail to get partition storage", K(ret)); } else if (OB_ISNULL(storage)) { ret = OB_ERR_UNEXPECTED; STORAGE_LOG(WARN, "error unexpected, storage must not be NULL", K(ret)); } else if (OB_SUCCESS != (context_->build_index_ret_)) { STORAGE_LOG(WARN, "build index has already failed", "ret", context_->build_index_ret_); } else if (OB_FAIL(dag->check_index_need_build(need_build))) { STORAGE_LOG(WARN, "fail to check index need build", K(ret), K(*param_)); } else if (!need_build) { STORAGE_LOG(INFO, "index do not need build", "index_id", param_->index_schema_->get_table_id()); } else if (OB_FAIL(storage->local_sort_index_by_range(task_id_, *param_, *context_))) { STORAGE_LOG(WARN, "fail to do local sort index by range", K(ret)); } else { STORAGE_LOG(INFO, "finish local sort", "index_id", param_->index_schema_->get_table_id()); } #ifdef ERRSIM if (OB_SUCC(ret)) { ret = E(EventTable::EN_INDEX_LOCAL_SORT_TASK) OB_SUCCESS; } #endif if (OB_FAIL(ret) && NULL != context_) { context_->build_index_ret_ = ret; ret = OB_SUCCESS; } return ret; } int ObIndexLocalSortTask::generate_next_task(ObITask*& next_task) { int ret = OB_SUCCESS; ObIDag* dag = get_dag(); ObBuildIndexDag* build_index_dag = NULL; ObIndexLocalSortTask* index_local_sort_task = NULL; const int64_t next_task_id = task_id_ + 1; next_task = NULL; if (OB_UNLIKELY(!is_inited_)) { ret = OB_NOT_INIT; STORAGE_LOG(WARN, "ObIndexLocalSortTask has not been inited", K(ret)); } else if (next_task_id == param_->concurrent_cnt_) { ret = OB_ITER_END; } else if (OB_ISNULL(dag)) { ret = OB_ERR_UNEXPECTED; STORAGE_LOG(WARN, "error unexpected, dag must not be NULL", K(ret)); } else if (OB_UNLIKELY(ObIDag::DAG_TYPE_CREATE_INDEX != dag->get_type())) { ret = OB_ERR_UNEXPECTED; STORAGE_LOG(WARN, "error unexpected, dag type is invalid", K(ret), "dag type", dag->get_type()); } else if (FALSE_IT(build_index_dag = static_cast(dag))) { } else if (OB_FAIL(build_index_dag->alloc_task(index_local_sort_task))) { STORAGE_LOG(WARN, "fail to alloc task", K(ret)); } else if (OB_FAIL(index_local_sort_task->init(next_task_id, *param_, context_))) { STORAGE_LOG(WARN, "fail to init index local task", K(ret)); } else { next_task = index_local_sort_task; STORAGE_LOG(INFO, "generate next local sort task", K(ret), "index_id", param_->index_schema_->get_table_id()); } if (OB_FAIL(ret) && NULL != context_) { if (OB_ITER_END != ret) { context_->build_index_ret_ = ret; } } return ret; } ObIndexMergeTask::ObIndexMergeTask() : ObITask(TASK_TYPE_INDEX_MERGE), is_inited_(false), param_(), context_(NULL), sorters_(NULL) {} ObIndexMergeTask::~ObIndexMergeTask() {} int ObIndexMergeTask::init(ObBuildIndexParam& param, ObBuildIndexContext* context) { int ret = OB_SUCCESS; if (OB_UNLIKELY(is_inited_)) { ret = OB_INIT_TWICE; STORAGE_LOG(WARN, "ObIndexMergeTask has already been inited", K(ret)); } else if (!param.is_valid() || OB_ISNULL(context)) { ret = OB_INVALID_ARGUMENT; STORAGE_LOG(WARN, "invalid arguments", K(ret), K(param), KP(context)); } else { param_ = ¶m; context_ = context; sorters_ = &context_->sorters_; is_inited_ = true; } return ret; } int ObIndexMergeTask::process() { int ret = OB_SUCCESS; ObIDag* tmp_dag = get_dag(); ObBuildIndexDag* dag = NULL; ObPartitionStorage* storage = NULL; ObIPartitionGroup* pg = nullptr; bool need_build = false; ObTableHandle new_sstable; ObSSTable* sstable = nullptr; const int64_t max_kept_major_version_number = 1; const bool in_slog_trans = false; if (OB_ISNULL(sorters_) || 0 == sorters_->count() || OB_ISNULL(tmp_dag) || OB_ISNULL(context_)) { ret = OB_ERR_SYS; STORAGE_LOG(WARN, "invalid inner state", K(ret), KP(sorters_), KP(tmp_dag), KP(context_)); } else if (OB_SUCCESS != (context_->build_index_ret_)) { STORAGE_LOG(WARN, "Build Index has already failed", "ret", context_->build_index_ret_); } else if (ObIDag::DAG_TYPE_CREATE_INDEX != tmp_dag->get_type()) { ret = OB_ERR_UNEXPECTED; STORAGE_LOG(WARN, "dag is invalid", K(ret), K(tmp_dag->get_type())); } else if (FALSE_IT(dag = static_cast(tmp_dag))) { } else if (OB_FAIL(dag->get_partition_storage(storage))) { STORAGE_LOG(WARN, "fail to get partition storage", K(ret)); } else if (OB_ISNULL(storage)) { ret = OB_ERR_UNEXPECTED; STORAGE_LOG(WARN, "error unexpected, storage must not be NULL", K(ret)); } else if (OB_FAIL(dag->get_pg(pg))) { STORAGE_LOG(WARN, "failed to get pg", K(ret)); } else if (OB_ISNULL(pg)) { ret = OB_ERR_UNEXPECTED; STORAGE_LOG(WARN, "pg is null", K(ret)); } else if (OB_FAIL(dag->check_index_need_build(need_build))) { STORAGE_LOG(WARN, "fail to check index need build", K(ret), K(*param_)); } else if (!need_build) { STORAGE_LOG(INFO, "index do not need build", "index_id", param_->index_schema_->get_table_id()); } else if (OB_FAIL(merge_local_sort_index(*param_, *sorters_, merge_sorter_, context_, new_sstable))) { STORAGE_LOG(WARN, "fail to merge local sort index", K(ret)); } else if (OB_FAIL(new_sstable.get_sstable(sstable))) { STORAGE_LOG(WARN, "failed to get sstable", K(ret)); } else if (OB_FAIL(pg->get_pg_storage().add_sstable( dag->get_partition_key(), sstable, max_kept_major_version_number, in_slog_trans))) { STORAGE_LOG(WARN, "failed to add sstable", K(ret), K(*param_)); } else if (OB_FAIL(param_->report_->submit_checksum_update_task(dag->get_partition_key(), param_->index_schema_->get_table_id(), ObITable::MAJOR_SSTABLE, ObSSTableChecksumUpdateType::UPDATE_ALL, false /*do not batch report immedidately*/))) { STORAGE_LOG(WARN, "fail to submit checksum update task", K(ret)); } STORAGE_LOG(INFO, "do clean up merge sorter"); merge_sorter_.clean_up(); #ifdef ERRSIM if (OB_SUCC(ret)) { ret = E(EventTable::EN_INDEX_MERGE_TASK) OB_SUCCESS; } #endif if (OB_FAIL(ret) && NULL != context_) { context_->build_index_ret_ = ret; ret = OB_SUCCESS; } return ret; } int ObIndexMergeTask::merge_local_sort_index(const ObBuildIndexParam& param, const ObIArray*>& local_sorters, ObExternalSort& merge_sorter, ObBuildIndexContext* context, ObTableHandle& new_sstable) { int ret = OB_SUCCESS; int tmp_ret = OB_SUCCESS; int comp_ret = OB_SUCCESS; ObArray sort_column_indexes; ObStoreRowComparer comparer(comp_ret, sort_column_indexes); ObCreateIndexKey key; ObCreateIndexSortTaskStat sort_task_stat; const int64_t file_buf_size = ObExternalSortConstant::DEFAULT_FILE_READ_WRITE_BUFFER; const int64_t expire_timestamp = 0; // no time limited const int64_t buf_limit = param.DEFAULT_INDEX_SORT_MEMORY_LIMIT; ObPGPartition* partition = NULL; ObIDag* tmp_dag = get_dag(); ObBuildIndexDag* dag = nullptr; if (OB_UNLIKELY(!is_inited_)) { ret = OB_NOT_INIT; STORAGE_LOG(WARN, "ObPartitionStorage has not been inited", K(ret)); } else if (!param.is_valid() || 0 == local_sorters.count() || OB_ISNULL(context)) { ret = OB_INVALID_ARGUMENT; STORAGE_LOG(WARN, "invalid argument", K(ret), K(param), K(local_sorters.count()), KP(context)); } else if (ObIDag::DAG_TYPE_CREATE_INDEX != tmp_dag->get_type()) { ret = OB_ERR_UNEXPECTED; STORAGE_LOG(WARN, "dag is invalid", K(ret), K(tmp_dag->get_type())); } else if (FALSE_IT(dag = static_cast(tmp_dag))) { } else if (OB_FAIL(dag->get_partition(partition))) { STORAGE_LOG(WARN, "fail to get partition", K(ret)); } else { key.index_table_id_ = param.index_schema_->get_table_id(); key.tenant_id_ = extract_tenant_id(key.index_table_id_); key.partition_id_ = partition->get_partition_key().get_partition_id(); sort_task_stat.task_id_ = 2 * param.concurrent_cnt_; sort_task_stat.type_ = ObILongOpsTaskStat::TaskType::SORT; sort_task_stat.state_ = ObILongOpsTaskStat::TaskState::RUNNING; sort_task_stat.macro_count_ = context->index_macro_cnt_; sort_task_stat.run_count_ = 1; if (OB_SUCCESS != (tmp_ret = LONG_OPS_MONITOR_INSTANCE.update_task_stat(key, sort_task_stat))) { STORAGE_LOG(WARN, "fail to update task stat", K(ret), K(sort_task_stat)); } } for (int64_t i = 0; OB_SUCC(ret) && i < param.index_schema_->get_rowkey_column_num(); ++i) { if (OB_FAIL(sort_column_indexes.push_back(i))) { STORAGE_LOG(WARN, "Fail to push sort column indexes, ", K(ret), K(i)); } } STORAGE_LOG(INFO, "begin merging index local sort result", K(ret), K(param)); if (OB_SUCC(ret)) { const uint64_t tenant_id = extract_tenant_id(param.index_schema_->get_table_id()); if (OB_FAIL(merge_sorter.init(buf_limit, file_buf_size, expire_timestamp, tenant_id, &comparer))) { STORAGE_LOG(WARN, "fail to init merge sorter", K(ret)); } else { const bool is_final_merge = true; for (int64_t i = 0; OB_SUCC(ret) && i < local_sorters.count(); ++i) { ObExternalSort* local_sort = local_sorters.at(i); if (OB_ISNULL(local_sort)) { ret = OB_ERR_SYS; STORAGE_LOG(WARN, "local_sort must not be NULL", K(ret)); } else if (OB_FAIL(local_sort->transfer_final_sorted_fragment_iter(merge_sorter))) { STORAGE_LOG(WARN, "fail to get final sorted fragment iterator", K(ret)); } } if (OB_SUCC(ret)) { if (OB_FAIL(merge_sorter.do_sort(is_final_merge))) { STORAGE_LOG(WARN, "fail to do final merge", K(ret)); } else if (OB_FAIL(add_build_index_sstable(param, merge_sorter, context, new_sstable))) { STORAGE_LOG(WARN, "fail to add build index sstable", K(ret)); } else { STORAGE_LOG(INFO, "finish merging index local sort result", K(ret)); } } } } sort_task_stat.state_ = (OB_SUCCESS == ret) ? ObILongOpsTaskStat::TaskState::SUCCESS : ObILongOpsTaskStat::TaskState::FAIL; if (OB_SUCCESS != (tmp_ret = key.to_key_string())) { STORAGE_LOG(WARN, "fail to key string", K(ret)); } else if (OB_SUCCESS != (tmp_ret = LONG_OPS_MONITOR_INSTANCE.update_task_stat(key, sort_task_stat))) { STORAGE_LOG(WARN, "fail to update task stat", K(ret)); } return ret; } int ObIndexMergeTask::add_build_index_sstable(const ObBuildIndexParam& param, ObExternalSort& external_sort, ObBuildIndexContext* context, ObTableHandle& new_sstable) { int ret = OB_SUCCESS; ObColumnChecksumCalculator checksum; const bool is_major_merge = true; ObMacroDataSeq macro_start_seq(0); ObIDag* tmp_dag = get_dag(); ObBuildIndexDag* dag = nullptr; ObPGPartition* partition = nullptr; ObIPartitionGroup* pg = nullptr; if (OB_UNLIKELY(!is_inited_)) { ret = OB_NOT_INIT; STORAGE_LOG(WARN, "ObPartitionStorage has not been inited", K(ret)); } else if (!param.is_valid() || OB_ISNULL(context)) { ret = OB_INVALID_ARGUMENT; STORAGE_LOG(WARN, "invalid argument", K(ret), K(param), KP(context)); } else if (ObIDag::DAG_TYPE_CREATE_INDEX != tmp_dag->get_type()) { ret = OB_ERR_UNEXPECTED; STORAGE_LOG(WARN, "dag is invalid", K(ret), K(tmp_dag->get_type())); } else if (FALSE_IT(dag = static_cast(tmp_dag))) { } else if (OB_FAIL(dag->get_partition(partition))) { STORAGE_LOG(WARN, "fail to get partition", K(ret)); } else if (OB_FAIL(checksum.init(param.index_schema_->get_column_count()))) { STORAGE_LOG(WARN, "fail to init checksum", K(ret)); } else if (OB_FAIL(dag->get_pg(pg))) { STORAGE_LOG(WARN, "fail to get pg", K(ret)); } else if (OB_FAIL(data_desc_.init(*param.index_schema_, param.version_, nullptr, partition->get_partition_key().get_partition_id(), MAJOR_MERGE, blocksstable::CCM_VALUE_ONLY == param.checksum_method_ /*need calc column checksum*/, true /*store column checksum in micro block*/, pg->get_partition_key(), pg->get_storage_file_handle()))) { STORAGE_LOG(WARN, "Fail to init data store desc, ", K(ret)); } else if (FALSE_IT(data_desc_.is_unique_index_ = param.index_schema_->is_unique_index())) { } else if (OB_FAIL(writer_.open(data_desc_, macro_start_seq))) { STORAGE_LOG(WARN, "Fail to open macro block writer, ", K(ret)); } else { common::ObArenaAllocator allocator(ObModIds::OB_SSTABLE_CREATE_INDEX); const ObStoreRow* row = NULL; int64_t row_count = 0; while (OB_SUCC(ret)) { if (OB_FAIL(external_sort.get_next_item(row))) { if (OB_ITER_END != ret) { STORAGE_LOG(WARN, "Fail to get next row from external sort, ", K(ret)); } else { ret = OB_SUCCESS; break; } } else if (OB_FAIL(writer_.append_row(*row))) { if (OB_ERR_PRIMARY_KEY_DUPLICATE == ret && param.index_schema_->is_unique_index()) { LOG_USER_ERROR(OB_ERR_PRIMARY_KEY_DUPLICATE, "", static_cast(sizeof("UNIQUE IDX") - 1), "UNIQUE IDX"); } else { STORAGE_LOG(WARN, "Fail to append row to sstable, ", K(ret)); } } else if (OB_FAIL(checksum.calc_column_checksum(param.checksum_method_, row, NULL, NULL))) { STORAGE_LOG(WARN, "fail to calc column checksum", K(ret)); } else { #ifdef ERRSIM if (OB_SUCC(ret)) { ret = E(EventTable::EN_INDEX_WRITE_BLOCK) OB_SUCCESS; } #endif ++row_count; } } STORAGE_LOG(INFO, "index table row count", K(row_count), "index_id", param.index_schema_->get_table_id()); if (OB_SUCC(ret)) { if (OB_FAIL(writer_.close())) { STORAGE_LOG(WARN, "fail to close writer", K(ret)); } else if (!param.index_schema_->is_domain_index() && OB_FAIL( context->check_column_checksum(checksum.get_column_checksum(), row_count, context->column_cnt_))) { STORAGE_LOG(WARN, "fail to check column checksum", K(ret)); } else if (OB_FAIL(add_new_index_sstable(param, &writer_, checksum.get_column_checksum(), new_sstable))) { STORAGE_LOG(WARN, "fail to update sstore", K(ret)); } } } if (OB_FAIL(ret)) { writer_.reset(); } return ret; } int ObIndexMergeTask::add_new_index_sstable(const ObBuildIndexParam& param, ObMacroBlockWriter* writer, const int64_t* column_checksum, ObTableHandle& new_sstable) { int ret = OB_SUCCESS; ObIDag* tmp_dag = get_dag(); ObBuildIndexDag* dag = nullptr; ObIPartitionGroup* pg = nullptr; ObPGPartition* pg_partition = nullptr; if (OB_UNLIKELY(!is_inited_)) { ret = OB_NOT_INIT; STORAGE_LOG(WARN, "ObPartitionStorage has not been inited", K(ret)); } else if (!param.is_valid() || OB_ISNULL(writer) || OB_ISNULL(column_checksum)) { ret = OB_INVALID_ARGUMENT; STORAGE_LOG(WARN, "invalid arguments", K(ret), K(param), KP(writer), KP(column_checksum)); } else if (ObIDag::DAG_TYPE_CREATE_INDEX != tmp_dag->get_type()) { ret = OB_ERR_UNEXPECTED; STORAGE_LOG(WARN, "dag is invalid", K(ret), K(tmp_dag->get_type())); } else if (FALSE_IT(dag = static_cast(tmp_dag))) { } else if (OB_FAIL(dag->get_partition_group(pg))) { STORAGE_LOG(WARN, "fail to get partition group", K(ret)); } else if (OB_ISNULL(pg)) { ret = OB_ERR_SYS; STORAGE_LOG(WARN, "error sys, invalid partition group", K(ret)); } else if (OB_FAIL(dag->get_partition(pg_partition))) { STORAGE_LOG(WARN, "fail to get partition", K(ret)); } else { const ObTableSchema& index_schema = *param.index_schema_; ObITable::TableKey table_key; ObPGCreateSSTableParam pg_create_sstable_param; ObCreateSSTableParamWithTable sstable_param; table_key.table_type_ = ObITable::MAJOR_SSTABLE; table_key.pkey_ = pg_partition->get_partition_key(); table_key.table_id_ = index_schema.get_table_id(); table_key.trans_version_range_.multi_version_start_ = param.snapshot_version_; table_key.trans_version_range_.base_version_ = ObVersionRange::MIN_VERSION; table_key.trans_version_range_.snapshot_version_ = param.snapshot_version_; table_key.version_ = param.version_; sstable_param.table_key_ = table_key; sstable_param.schema_ = &index_schema; sstable_param.schema_version_ = param.schema_version_; sstable_param.create_snapshot_version_ = param.snapshot_version_; sstable_param.checksum_method_ = param.checksum_method_; sstable_param.progressive_merge_round_ = index_schema.get_progressive_merge_round(); sstable_param.progressive_merge_step_ = 0; sstable_param.logical_data_version_ = table_key.version_; pg_create_sstable_param.with_table_param_ = &sstable_param; if (OB_FAIL(pg_create_sstable_param.data_blocks_.push_back(&writer->get_macro_block_write_ctx()))) { LOG_WARN("fail to push back writer macro block ctx", K(ret)); } else if (OB_FAIL(pg->create_sstable(pg_create_sstable_param, new_sstable))) { LOG_WARN("fail to create sstable", K(ret)); } } return ret; } ObCompactToLatestTask::ObCompactToLatestTask() : ObITask(ObITaskType::TASK_TYPE_COMPACT_TO_LASTEST), is_inited_(false), pkey_(), param_(NULL), context_(NULL) {} ObCompactToLatestTask::~ObCompactToLatestTask() {} int ObCompactToLatestTask::init( const ObPartitionKey& pkey, const compaction::ObBuildIndexParam& param, compaction::ObBuildIndexContext* context) { int ret = OB_SUCCESS; if (OB_UNLIKELY(is_inited_)) { ret = OB_INIT_TWICE; LOG_WARN("ObCompactToLatestTask has already been inited", K(ret)); } else if (OB_UNLIKELY(!pkey.is_valid() || !param.is_valid() || OB_ISNULL(context))) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid arguments", K(ret), K(pkey), K(param), KP(context)); } else { pkey_ = pkey; param_ = ¶m; context_ = context; is_inited_ = true; } return ret; } int ObCompactToLatestTask::process() { int ret = OB_SUCCESS; ObIDag* tmp_dag = get_dag(); ObBuildIndexDag* dag = NULL; bool need_build = false; if (OB_UNLIKELY(!is_inited_)) { ret = OB_NOT_INIT; LOG_WARN("ObCompactToLatestTask has not been inited", K(ret)); } else if (!context_->need_build_) { STORAGE_LOG(INFO, "index does not need build", K(*param_)); } else if (FALSE_IT(dag = static_cast(tmp_dag))) { } else if (OB_FAIL(dag->check_index_need_build(need_build))) { STORAGE_LOG(WARN, "fail to check index need build", K(ret), K(*param_)); } else if (!need_build) { STORAGE_LOG(INFO, "index do not need build", "index_id", param_->index_schema_->get_table_id()); } else if (OB_SUCCESS != (context_->build_index_ret_)) { STORAGE_LOG(WARN, "Build Index has already failed", "ret", context_->build_index_ret_); } else if (OB_FAIL(wait_compact_to_latest(pkey_, param_->index_schema_->get_table_id()))) { STORAGE_LOG(WARN, "fail to wait compact to latest", K(ret)); } if (OB_FAIL(ret) && NULL != context_) { context_->build_index_ret_ = ret; ret = OB_SUCCESS; } LOG_INFO("compact task ret", "ret", context_->build_index_ret_); return ret; } int ObCompactToLatestTask::wait_compact_to_latest(const ObPartitionKey& pkey, const uint64_t index_id) { int ret = OB_SUCCESS; if (OB_UNLIKELY(!pkey.is_valid() || OB_INVALID_ID == index_id)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid arguments", K(ret), K(pkey), K(index_id)); } else { int tmp_ret = OB_SUCCESS; bool is_merged = false; while (OB_SUCC(ret)) { bool is_finished = false; if (OB_SUCCESS != (tmp_ret = ObPartitionScheduler::get_instance().schedule_merge(pkey, is_merged))) { LOG_WARN("fail to schedule merge", K(tmp_ret)); } if (OB_FAIL(ObPartitionScheduler::get_instance().check_index_compact_to_latest(pkey, index_id, is_finished))) { LOG_WARN("fail to check index compact to latest", K(ret)); } else if (is_finished) { break; } if (OB_SUCC(ret)) { usleep(RETRY_INTERVAL); dag_yield(); } } } LOG_INFO("compact index to latest finish", K(ret), K(index_id)); return ret; } ObUniqueIndexChecker::ObUniqueIndexChecker() : is_inited_(false), part_service_(NULL), pkey_(), index_schema_(NULL), data_table_schema_(NULL), execution_id_(0), snapshot_version_(0), part_guard_() {} int ObUniqueIndexChecker::init(ObPartitionService* part_service, const common::ObPartitionKey& pkey, const ObTableSchema* data_table_schema, const ObTableSchema* index_schema, const uint64_t execution_id, const int64_t snapshot_version) { int ret = OB_SUCCESS; if (OB_UNLIKELY(is_inited_)) { ret = OB_NOT_INIT; LOG_WARN("ObUniqueIndexChecker has already been inited", K(ret)); } else if (OB_UNLIKELY( NULL == part_service || !pkey.is_valid() || NULL == data_table_schema || NULL == index_schema)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid arguments", K(ret), KP(part_service), K(pkey), KP(data_table_schema), KP(index_schema)); } else { is_inited_ = true; part_service_ = part_service; pkey_ = pkey; data_table_schema_ = data_table_schema; index_schema_ = index_schema; execution_id_ = execution_id; snapshot_version_ = snapshot_version; } return ret; } int ObUniqueIndexChecker::calc_column_checksum(const int64_t column_cnt, ObIStoreRowIterator& iterator, common::ObIArray& column_checksum, int64_t& row_count) { int ret = OB_SUCCESS; row_count = 0; column_checksum.reuse(); if (OB_UNLIKELY(column_cnt <= 0)) { ret = OB_INVALID_ARGUMENT; STORAGE_LOG(WARN, "invalid arguments", K(ret), K(column_cnt)); } else if (OB_FAIL(column_checksum.reserve(column_cnt))) { STORAGE_LOG(WARN, "fail to reserve column", K(ret), K(column_cnt)); } else { const ObStoreRow* row = NULL; for (int64_t i = 0; OB_SUCC(ret) && i < column_cnt; ++i) { if (OB_FAIL(column_checksum.push_back(0))) { STORAGE_LOG(WARN, "fail to push back column checksum", K(ret)); } } while (OB_SUCC(ret)) { if (OB_FAIL(iterator.get_next_row(row))) { if (OB_ITER_END == ret) { ret = OB_SUCCESS; break; } else { STORAGE_LOG(WARN, "fail to get next row", K(ret)); } } else if (OB_ISNULL(row)) { ret = OB_ERR_UNEXPECTED; STORAGE_LOG(WARN, "store row must not be NULL", K(ret), KP(row)); } else if (column_cnt != row->row_val_.count_) { ret = OB_INVALID_ARGUMENT; STORAGE_LOG( WARN, "column cnt not as expected", K(ret), K(column_cnt), "row_val_column_cnt", row->row_val_.count_); } else { ++row_count; for (int64_t i = 0; OB_SUCC(ret) && i < column_cnt; ++i) { column_checksum.at(i) += row->row_val_.cells_[i].checksum(0); } dag_yield(); } } } return ret; } int ObUniqueIndexChecker::scan_table_with_column_checksum( const ObScanTableParam& param, ObIArray& column_checksum, int64_t& row_count) { int ret = OB_SUCCESS; ObPartitionStorage* storage = NULL; if (OB_UNLIKELY(!param.is_valid())) { ret = OB_INVALID_ARGUMENT; STORAGE_LOG(WARN, "invalid arguments", K(ret), K(param)); } else if (OB_ISNULL(part_guard_.get_pg_partition())) { ret = OB_ERR_UNEXPECTED; STORAGE_LOG(WARN, "error unexpected, partition must not be NULL", K(ret)); } else if (OB_ISNULL(storage = static_cast(part_guard_.get_pg_partition()->get_storage()))) { ret = OB_ERR_UNEXPECTED; STORAGE_LOG(WARN, "error unexpected, storage must not be NULL", K(ret)); } else { ObQueryFlag query_flag(ObQueryFlag::Forward, true, /*is daily merge scan*/ true, /*is read multiple macro block*/ true, /*sys task scan, read one macro block in single io*/ false, /*is full row scan?*/ false, false); ObArray col_params; ObArray output_column_ids; ObTableAccessParam access_param; ObTableAccessContext access_ctx; ObBlockCacheWorkingSet block_cache_ws; ObStoreCtx ctx; ObArenaAllocator allocator(ObModIds::OB_CS_BUILD_INDEX); ObMultipleScanMerge* scan_merge = NULL; for (int64_t i = 0; OB_SUCC(ret) && i < param.col_ids_->count(); i++) { const ObColumnSchemaV2* col = param.index_schema_->get_column_schema(param.col_ids_->at(i).col_id_); if (NULL == col) { // generated column's depend column, get column schema from data table col = param.data_table_schema_->get_column_schema(param.col_ids_->at(i).col_id_); } if (NULL == col) { ret = OB_ERR_UNEXPECTED; STORAGE_LOG(WARN, "fail to get column schema", K(ret)); } else { void* buf = allocator.alloc(sizeof(ObColumnParam)); if (NULL == buf) { ret = OB_ALLOCATE_MEMORY_FAILED; STORAGE_LOG(WARN, "fail to allocate memory", K(ret)); } else { ObColumnParam* col_param = new (buf) ObColumnParam(allocator); if (OB_FAIL(ObTableParam::convert_column_schema_to_param(*col, *col_param))) { STORAGE_LOG(WARN, "fail to convert schema column to column parameter", K(ret)); } else if (OB_FAIL(col_params.push_back(col_param))) { STORAGE_LOG(WARN, "fail to push array", K(ret)); } else if (OB_FAIL(output_column_ids.push_back(param.col_ids_->at(i).col_id_))) { LOG_WARN("push back output column id fail", K(ret), K(param.col_ids_->at(i))); } } } } if (OB_SUCC(ret)) { transaction::ObTransService* txs = ObPartitionService::get_instance().get_trans_service(); const ObTableSchema& query_schema = param.is_scan_index_ ? *param.index_schema_ : *param.data_table_schema_; if (OB_ISNULL(ctx.mem_ctx_ = txs->get_mem_ctx_factory()->alloc())) { ret = OB_ALLOCATE_MEMORY_FAILED; STORAGE_LOG(ERROR, "fail to allocate transaction memory context", K(ret)); } else if (OB_FAIL(ctx.mem_ctx_->trans_begin())) { STORAGE_LOG(WARN, "fail to begin transaction", K(ret)); } else if (OB_FAIL(ctx.mem_ctx_->sub_trans_begin(param.snapshot_version_, BUILD_INDEX_READ_SNAPSHOT_VERSION))) { STORAGE_LOG(WARN, "fail to begin sub transaction", K(ret), K(param.snapshot_version_)); } else if (OB_FAIL(block_cache_ws.init(extract_tenant_id(param.index_schema_->get_table_id())))) { LOG_WARN("fail to init block cache working set", K(ret)); } else if (OB_FAIL(access_param.out_col_desc_param_.init())) { LOG_WARN("fail to init out cols", K(ret)); } else if (OB_FAIL(access_param.out_col_desc_param_.assign(*param.col_ids_))) { LOG_WARN("fail to assign out cols", K(ret)); } else { void* buf = NULL; ObExtStoreRange range; ObGetTableParam get_table_param; range.get_range().set_whole_range(); access_param.iter_param_.table_id_ = query_schema.get_table_id(); access_param.iter_param_.rowkey_cnt_ = query_schema.get_rowkey_column_num(); access_param.iter_param_.schema_version_ = query_schema.get_schema_version(); access_param.iter_param_.out_cols_project_ = param.output_projector_; access_param.iter_param_.out_cols_ = &access_param.out_col_desc_param_.get_col_descs(); access_param.out_cols_param_ = &col_params; access_param.reserve_cell_cnt_ = param.output_projector_->count(); common::ObVersionRange trans_version_range; trans_version_range.snapshot_version_ = param.snapshot_version_; trans_version_range.multi_version_start_ = param.snapshot_version_; trans_version_range.base_version_ = 0; get_table_param.partition_store_ = &storage->get_partition_store(); ObPartitionKey pg_key; if (OB_FAIL(ObPartitionService::get_instance().get_pg_key(pkey_, pg_key))) { STORAGE_LOG(WARN, "failed to get_pg_key", K(ret), K_(pkey)); } else if (OB_FAIL(ctx.init_trans_ctx_mgr(pg_key))) { STORAGE_LOG(WARN, "failed to init_ctx_mgr", K(ret), K(pg_key)); } else if (OB_FAIL( access_ctx.init(query_flag, ctx, allocator, allocator, block_cache_ws, trans_version_range))) { LOG_WARN("Failed to init trans_version range", K(ret)); } else if (OB_ISNULL(buf = allocator.alloc(sizeof(ObMultipleScanMerge)))) { ret = OB_ALLOCATE_MEMORY_FAILED; STORAGE_LOG(WARN, "fail to allocate memory", K(ret)); } else if (OB_ISNULL(scan_merge = new (buf) ObMultipleScanMerge())) { ret = OB_ERR_UNEXPECTED; STORAGE_LOG(WARN, "error unexpected, placement new failed", K(ret)); } else if (OB_FAIL(scan_merge->init(access_param, access_ctx, get_table_param))) { STORAGE_LOG(WARN, "fail to init multiple scan merge", K(ret)); } else if (OB_FAIL(scan_merge->open(range))) { STORAGE_LOG(WARN, "fail to open scan merge", K(ret)); } else { const_cast(param).tables_handle_->reset(); } if (OB_FAIL(ret)) { } else if (OB_FAIL(calc_column_checksum( access_param.iter_param_.out_cols_project_->count(), *scan_merge, column_checksum, row_count))) { STORAGE_LOG(WARN, "fail to calc column checksum", K(ret)); } } if (NULL != scan_merge) { scan_merge->~ObMultipleScanMerge(); scan_merge = NULL; } if (NULL != ctx.mem_ctx_) { ctx.mem_ctx_->trans_end(true, 0); ctx.mem_ctx_->trans_clear(); txs->get_mem_ctx_factory()->free(ctx.mem_ctx_); ctx.mem_ctx_ = NULL; } } } return ret; } int ObUniqueIndexChecker::scan_main_table_with_column_checksum(const ObTableSchema& data_table_schema, const ObTableSchema& index_schema, const int64_t snapshot_version, ObTablesHandle& tables_handle, ObIArray& column_checksum, int64_t& row_count) { int ret = OB_SUCCESS; ObArray col_ids; ObArray org_col_ids; ObArray output_projector; int64_t unique_key_cnt = 0; if (OB_UNLIKELY(!data_table_schema.is_valid() || !index_schema.is_valid() || snapshot_version <= 0 || 0 == tables_handle.get_count())) { ret = OB_INVALID_ARGUMENT; STORAGE_LOG(WARN, "invalid arguments", K(ret), K(data_table_schema), K(index_schema), K(snapshot_version), K(tables_handle)); } else if (OB_FAIL(ObPartitionStorage::generate_index_output_param( data_table_schema, index_schema, col_ids, org_col_ids, output_projector, unique_key_cnt))) { STORAGE_LOG(WARN, "fail to generate index output param", K(ret)); } else { ObScanTableParam param; param.data_table_schema_ = &data_table_schema; param.index_schema_ = &index_schema; param.snapshot_version_ = snapshot_version; param.col_ids_ = &col_ids; param.output_projector_ = &output_projector; param.is_scan_index_ = false; param.tables_handle_ = &tables_handle; if (OB_FAIL(scan_table_with_column_checksum(param, column_checksum, row_count))) { STORAGE_LOG(WARN, "fail to scan table with column checksum", K(ret)); } } return ret; } int ObUniqueIndexChecker::scan_index_table_with_column_checksum(const ObTableSchema& data_table_schema, const ObTableSchema& index_schema, const int64_t snapshot_version, ObTablesHandle& tables_handle, ObIArray& column_checksum, int64_t& row_count) { int ret = OB_SUCCESS; ObArray column_ids; if (OB_UNLIKELY(!index_schema.is_valid() || snapshot_version <= 0 || 0 == tables_handle.get_count())) { ret = OB_INVALID_ARGUMENT; STORAGE_LOG(WARN, "invalid arguments", K(ret), K(index_schema), K(snapshot_version), K(tables_handle)); } else if (OB_FAIL(index_schema.get_column_ids(column_ids))) { STORAGE_LOG(WARN, "fail to get column ids", K(ret), "index_id", index_schema.get_table_id()); } else { ObArray output_projector; for (int64_t i = 0; OB_SUCC(ret) && i < column_ids.count(); ++i) { if (OB_FAIL(output_projector.push_back(static_cast(i)))) { STORAGE_LOG(WARN, "fail to push back output projector", K(ret)); } } if (OB_SUCC(ret)) { ObScanTableParam param; param.data_table_schema_ = &data_table_schema; param.index_schema_ = &index_schema; param.snapshot_version_ = snapshot_version; param.col_ids_ = &column_ids; param.output_projector_ = &output_projector; param.is_scan_index_ = true; param.tables_handle_ = &tables_handle; if (OB_FAIL(scan_table_with_column_checksum(param, column_checksum, row_count))) { STORAGE_LOG(WARN, "fail to scan table with column checksum", K(ret)); } } } return ret; } int ObUniqueIndexChecker::check_global_index(ObIDag* dag, ObPartitionStorage* storage) { int ret = OB_SUCCESS; if (OB_ISNULL(dag) || OB_ISNULL(storage)) { ret = OB_INVALID_ARGUMENT; STORAGE_LOG(WARN, "invalid arguments", K(ret), KP(dag), KP(storage)); } else { ObTablesHandle tables_handle; ObArray column_checksum; int64_t row_count = 0; if (OB_FAIL(try_get_read_tables(pkey_.get_table_id(), snapshot_version_, dag, tables_handle))) { LOG_WARN("fail to try get read tables", K(ret)); } if (OB_SUCC(ret) && !dag->has_set_stop()) { if (pkey_.get_table_id() == data_table_schema_->get_table_id()) { if (OB_FAIL(scan_main_table_with_column_checksum( *data_table_schema_, *index_schema_, snapshot_version_, tables_handle, column_checksum, row_count))) { STORAGE_LOG(WARN, "fail to scan main table with column checksum", K(ret)); } } else if (pkey_.get_table_id() == index_schema_->get_table_id()) { if (OB_FAIL(scan_index_table_with_column_checksum( *data_table_schema_, *index_schema_, snapshot_version_, tables_handle, column_checksum, row_count))) { STORAGE_LOG(WARN, "fail to scan index table with column checksum", K(ret)); } } } if (OB_SUCC(ret) && !dag->has_set_stop()) { ObArray column_ids; if (OB_FAIL(index_schema_->get_column_ids(column_ids))) { STORAGE_LOG(WARN, "fail to get columns ids", K(ret)); } else if (column_ids.count() != column_checksum.count()) { ret = OB_ERR_UNEXPECTED; STORAGE_LOG( WARN, "error unexpected, column count mismatch", K(ret), K(column_ids.count()), K(column_checksum.count())); } else { ObArray checksum_items; for (int64_t i = 0; OB_SUCC(ret) && i < column_ids.count(); ++i) { // generated column in index schema is not marked as generated, so we should retreive the column schema from // data table const ObColumnSchemaV2* column_schema = data_table_schema_->get_column_schema(column_ids.at(i).col_id_); if (NULL == column_schema) { column_schema = index_schema_->get_column_schema(column_ids.at(i).col_id_); } if (OB_ISNULL(column_schema)) { ret = OB_ERR_UNEXPECTED; STORAGE_LOG(WARN, "error unexpected, column schema must not be NULL", K(ret), K(column_ids.at(i).col_id_)); } else if (column_schema->is_shadow_column() || column_schema->is_generated_column() || !column_schema->is_column_stored_in_sstable()) { STORAGE_LOG(INFO, "column do not need to compare checksum", K(column_ids.at(i).col_id_)); } else { ObIndexChecksumItem item; item.execution_id_ = execution_id_; item.tenant_id_ = extract_tenant_id(pkey_.get_table_id()); item.table_id_ = pkey_.get_table_id(); item.partition_id_ = pkey_.get_partition_id(); item.column_id_ = column_ids.at(i).col_id_; item.task_id_ = -1; item.checksum_ = column_checksum.at(i); item.checksum_method_ = blocksstable::CCM_TYPE_AND_VALUE; if (OB_FAIL(checksum_items.push_back(item))) { LOG_WARN("fail to push back item", K(ret)); } } } if (OB_SUCC(ret)) { if (OB_FAIL(ObIndexChecksumOperator::update_checksum(checksum_items, *GCTX.sql_proxy_))) { LOG_WARN("fail to update checksum", K(ret)); } } } } } return ret; } int ObUniqueIndexChecker::try_get_read_tables( const uint64_t table_id, const int64_t snapshot_version, ObIDag* dag, ObTablesHandle& tables_handle) { int ret = OB_SUCCESS; tables_handle.reset(); if (OB_INVALID_ID == table_id || snapshot_version <= 0 || NULL == dag) { ret = OB_INVALID_ARGUMENT; STORAGE_LOG(WARN, "invalid arguments", K(ret), K(table_id), K(snapshot_version), KP(dag)); } else { ObIPartitionGroupGuard part_guard; ObPartitionStorage* storage = NULL; const bool allow_not_ready = false; const bool need_safety_check = true; const bool reset_handle = true; const bool print_dropped_alert = false; while (OB_SUCC(ret) && !dag->has_set_stop()) { if (OB_FAIL(part_service_->get_partition(pkey_, part_guard))) { if (OB_PARTITION_NOT_EXIST == ret) { STORAGE_LOG(INFO, "partition not exist, may be deleted", K(pkey_)); ret = OB_SUCCESS; break; } else { STORAGE_LOG(WARN, "fail to get partition", K(ret), K_(pkey)); } } else if (OB_ISNULL(part_guard_.get_pg_partition())) { ret = OB_ERR_UNEXPECTED; STORAGE_LOG(WARN, "The partition is NULL", K(ret), K_(pkey)); } else if (OB_ISNULL(storage = static_cast(part_guard_.get_pg_partition()->get_storage()))) { ret = OB_ERR_UNEXPECTED; STORAGE_LOG(WARN, "error unexpected, storage must not be NULL", K(ret), K(pkey_)); } else if (OB_FAIL(storage->get_partition_store().get_read_tables(table_id, snapshot_version, tables_handle, allow_not_ready, need_safety_check, reset_handle, print_dropped_alert))) { if (OB_REPLICA_NOT_READABLE == ret) { usleep(RETRY_INTERVAL); dag_yield(); ret = OB_SUCCESS; } else { LOG_WARN("fail to get read tables", K(ret)); } } else { break; } } } return ret; } int ObUniqueIndexChecker::check_local_index(ObIDag* dag, ObPartitionStorage* storage, const int64_t snapshot_version) { int ret = OB_SUCCESS; if (OB_ISNULL(storage) || snapshot_version <= 0) { ret = OB_INVALID_ARGUMENT; STORAGE_LOG(WARN, "invalid arguments", K(ret), KP(storage), K(snapshot_version)); } else { // scan data table ObTablesHandle data_table_handle; ObArray data_table_column_checksum; ObTablesHandle index_table_handle; ObArray index_table_column_checksum; int64_t index_table_row_count = 0; int64_t main_table_row_count = 0; if (OB_FAIL(try_get_read_tables(data_table_schema_->get_table_id(), snapshot_version, dag, data_table_handle))) { LOG_WARN("fail to try get read tables", K(ret)); } // read data table data and calc column checksum if (OB_SUCC(ret) && !dag->has_set_stop() && data_table_handle.get_count() > 0) { if (OB_FAIL(scan_main_table_with_column_checksum(*data_table_schema_, *index_schema_, snapshot_version, data_table_handle, data_table_column_checksum, main_table_row_count))) { STORAGE_LOG(WARN, "fail to scan main table with column checksum", K(ret)); } else { data_table_handle.reset(); } } // scan index table if (OB_SUCC(ret)) { if (OB_FAIL(try_get_read_tables(index_schema_->get_table_id(), snapshot_version, dag, index_table_handle))) { LOG_WARN("fail to try get read tables", K(ret)); } // read index table data and calc column checksum if (OB_SUCC(ret) && !dag->has_set_stop() && index_table_handle.get_count() > 0) { if (OB_FAIL(scan_index_table_with_column_checksum(*data_table_schema_, *index_schema_, snapshot_version, index_table_handle, index_table_column_checksum, index_table_row_count))) { STORAGE_LOG(WARN, "fail to scan index table with column checksum", K(ret)); } else { index_table_handle.reset(); } } } // validate column checksum if (OB_SUCC(ret) && !dag->has_set_stop() && data_table_column_checksum.count() > 0 && index_table_column_checksum.count() > 0) { ObArray column_ids; if (OB_FAIL(index_schema_->get_column_ids(column_ids))) { STORAGE_LOG(WARN, "fail to get columns ids", K(ret)); } else if (main_table_row_count != index_table_row_count) { ret = OB_ERR_PRIMARY_KEY_DUPLICATE; STORAGE_LOG(WARN, "check unique index failed", K(ret), K(main_table_row_count), K(index_table_row_count), "index_id", index_schema_->get_table_id()); } else { for (int64_t i = 0; OB_SUCC(ret) && i < column_ids.count(); ++i) { // generated column in index schema is not marked as generated, so we should retreive the column schema from // data table const ObColumnSchemaV2* column_schema = data_table_schema_->get_column_schema(column_ids.at(i).col_id_); if (NULL == column_schema) { column_schema = index_schema_->get_column_schema(column_ids.at(i).col_id_); } if (OB_ISNULL(column_schema)) { ret = OB_ERR_UNEXPECTED; STORAGE_LOG(WARN, "error unexpected, column schema must not be NULL", K(ret)); } else if (column_schema->is_shadow_column() || column_schema->is_generated_column() || !column_schema->is_column_stored_in_sstable()) { STORAGE_LOG(INFO, "column do not need to compare checksum", K(column_ids.at(i).col_id_)); continue; } else if (data_table_column_checksum.at(i) != index_table_column_checksum.at(i)) { ret = OB_ERR_PRIMARY_KEY_DUPLICATE; STORAGE_LOG(WARN, "check unique index failed", K(ret), K(data_table_column_checksum), K(index_table_column_checksum), K(column_ids), K(i), "index_id", index_schema_->get_table_id()); } } if (OB_SUCC(ret)) { STORAGE_LOG(INFO, "build index checksum", K(data_table_column_checksum), K(index_table_column_checksum), K(column_ids), "index_id", index_schema_->get_table_id()); } } } } return ret; } int ObUniqueIndexChecker::check_unique_index(ObIDag* dag) { int ret = OB_SUCCESS; ObPartitionStorage* storage = NULL; ObTablesHandle table_handle; ObIPartitionGroupGuard pg_guard; if (OB_UNLIKELY(!is_inited_)) { ret = OB_NOT_INIT; LOG_WARN("ObUniqueIndexChecker has not been inited", K(ret)); } else if (OB_ISNULL(dag)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid arguments", K(ret), KP(dag)); } else if (OB_FAIL(part_service_->get_partition(pkey_, pg_guard)) || OB_ISNULL(pg_guard.get_partition_group())) { STORAGE_LOG(WARN, "fail to get partition", K(ret), K_(pkey)); } else if (OB_FAIL(pg_guard.get_partition_group()->get_pg_partition(pkey_, part_guard_)) || OB_ISNULL(part_guard_.get_pg_partition())) { STORAGE_LOG(WARN, "fail to get pg partition", K(ret), K_(pkey)); } else if (OB_ISNULL(storage = static_cast(part_guard_.get_pg_partition()->get_storage()))) { ret = OB_ERR_UNEXPECTED; STORAGE_LOG(WARN, "error unexpected, partition storage must not be NULL", K(ret)); } else if (index_schema_->is_domain_index()) { STORAGE_LOG(INFO, "do not need to check unique for domain index", "index_id", index_schema_->get_table_id()); } else { int64_t check_end_snapshot_version = 0; if (OB_FAIL(ret)) { } else if (OB_FAIL(wait_trans_end(dag, check_end_snapshot_version))) { LOG_WARN("fail to wait trans end", K(ret)); } else { if (index_schema_->is_global_index_table()) { if (OB_FAIL(check_global_index(dag, storage))) { LOG_WARN("fail to check global index", K(ret)); } } else { if (OB_FAIL(check_local_index(dag, storage, check_end_snapshot_version))) { STORAGE_LOG(WARN, "fail to check local index", K(ret), K(check_end_snapshot_version)); } } } } if (is_inited_) { int tmp_ret = OB_SUCCESS; ObIndexStatusTableOperator::ObBuildIndexStatus status; const ObAddr& self_addr = GCTX.self_addr_; const uint64_t index_table_id = index_schema_->get_table_id(); status.index_status_ = index_schema_->get_index_status(); status.ret_code_ = ret; status.role_ = common::FOLLOWER; STORAGE_LOG(INFO, "begin report build index status", K(index_table_id), K(pkey_), K(status)); while (!dag->has_set_stop()) { if (OB_SUCCESS != (tmp_ret = ObIndexStatusTableOperator::report_build_index_status( index_table_id, pkey_.get_partition_id(), self_addr, status, *GCTX.sql_proxy_))) { STORAGE_LOG(WARN, "fail to report build index status", K(ret), K(pkey_)); usleep(RETRY_INTERVAL); dag_yield(); } else { break; } } } return ret; } int ObUniqueIndexChecker::wait_trans_end(ObIDag* dag, int64_t& snapshot_version) { int ret = OB_SUCCESS; snapshot_version = 0; if (OB_UNLIKELY(!is_inited_)) { ret = OB_NOT_INIT; LOG_WARN("ObUniqueIndexChecker has not been inited", K(ret)); } else { const int64_t now = ObTimeUtility::current_time(); while (OB_SUCC(ret) && !dag->has_set_stop() && 0 == snapshot_version) { if (OB_FAIL(part_service_->check_ctx_create_timestamp_elapsed(pkey_, now))) { if (OB_EAGAIN == ret) { ret = OB_SUCCESS; usleep(RETRY_INTERVAL); dag_yield(); } else { LOG_WARN("fail to check ctx create timestamp elapsed", K(ret)); break; } } else if (OB_FAIL(OB_TS_MGR.get_publish_version(pkey_.get_tenant_id(), snapshot_version))) { LOG_WARN("fail to get publish version", K(ret), K(pkey_)); } } } return ret; } ObUniqueCheckingTask::ObUniqueCheckingTask() : ObITask(TASK_TYPE_UNIQUE_INDEX_CHECKING), is_inited_(false), param_(), context_(NULL) {} ObUniqueCheckingTask::~ObUniqueCheckingTask() {} int ObUniqueCheckingTask::init(const ObBuildIndexParam& param, ObBuildIndexContext* context) { int ret = OB_SUCCESS; ObIDag* tmp_dag = get_dag(); ObBuildIndexDag* dag = NULL; ObPartitionService* part_service = NULL; if (OB_UNLIKELY(is_inited_)) { ret = OB_INIT_TWICE; STORAGE_LOG(WARN, "ObUniqueCheckingTask has already been inited", K(ret)); } else if (!param.is_valid() || OB_ISNULL(context)) { ret = OB_INVALID_ARGUMENT; STORAGE_LOG(WARN, "invalid argument", K(ret), K(param), KP(context)); } else if (OB_ISNULL(dag = static_cast(tmp_dag))) { ret = OB_ERR_UNEXPECTED; STORAGE_LOG(WARN, "fail to cast pointer", K(ret)); } else if (OB_FAIL(dag->get_partition_service(part_service))) { STORAGE_LOG(WARN, "fail to get partition service", K(ret)); } else { const ObPartitionKey pkey = dag->get_partition_key(); if (OB_FAIL(unique_checker_.init(part_service, pkey, param.table_schema_, param.index_schema_))) { STORAGE_LOG(WARN, "fail to init unique index checker", K(ret)); } else { param_ = ¶m; context_ = context; is_inited_ = true; } } return ret; } int ObUniqueCheckingTask::process() { int ret = OB_SUCCESS; ObIDag* tmp_dag = get_dag(); ObBuildIndexDag* dag = NULL; bool need_build = false; if (OB_UNLIKELY(!is_inited_)) { ret = OB_NOT_INIT; STORAGE_LOG(WARN, "ObUniqueCheckingTask has not been inited", K(ret)); } else if (!context_->need_build_) { STORAGE_LOG(INFO, "index does not need build", K(*param_)); } else if (OB_ISNULL(dag = static_cast(tmp_dag))) { ret = OB_ERR_UNEXPECTED; STORAGE_LOG(WARN, "fail to cast pointer", K(ret)); } else if (OB_FAIL(dag->check_index_need_build(need_build))) { STORAGE_LOG(WARN, "fail to check index need build", K(ret), K(*param_)); } else if (!need_build) { STORAGE_LOG(INFO, "index do not need build", "index_id", param_->index_schema_->get_table_id()); } else if (OB_SUCCESS != (context_->build_index_ret_)) { STORAGE_LOG(WARN, "Build Index has already failed", "ret", context_->build_index_ret_); } else if (context_->is_unique_checking_complete_) { // do nothing } else if (!param_->index_schema_->is_unique_index()) { context_->is_unique_checking_complete_ = true; } else if (OB_FAIL(unique_checker_.check_unique_index(dag))) { STORAGE_LOG(WARN, "fail to check unique index", K(ret)); } context_->is_unique_checking_complete_ = true; if (OB_FAIL(ret) && NULL != context_) { context_->build_index_ret_ = ret; ret = OB_SUCCESS; } return ret; } ObReportIndexStatusTask::ObReportIndexStatusTask() : ObITask(TASK_TYPE_REPORT_INDEX_STATUS), is_inited_(false), pkey_(), param_(), context_(NULL) {} ObReportIndexStatusTask::~ObReportIndexStatusTask() {} int ObReportIndexStatusTask::init( const ObPartitionKey& pkey, const ObBuildIndexParam& param, ObBuildIndexContext* context) { int ret = OB_SUCCESS; if (OB_UNLIKELY(is_inited_)) { ret = OB_INIT_TWICE; STORAGE_LOG(WARN, "ObReportIndexStatusTask has already been inited", K(ret)); } else if (!pkey.is_valid() || !param.is_valid() || OB_ISNULL(context)) { ret = OB_INVALID_ARGUMENT; STORAGE_LOG(WARN, "invalid argument", K(ret), K(pkey), K(param), KP(context)); } else { pkey_ = pkey; param_ = ¶m; context_ = context; is_inited_ = true; } return ret; } int ObReportIndexStatusTask::process() { int ret = OB_SUCCESS; ObIDag* tmp_dag = get_dag(); ObBuildIndexDag* dag = NULL; if (OB_UNLIKELY(!is_inited_)) { ret = OB_NOT_INIT; STORAGE_LOG(WARN, "ObReportIndexStatusTask has not been inited", K(ret)); } else if (OB_ISNULL(dag = static_cast(tmp_dag))) { ret = OB_ERR_UNEXPECTED; STORAGE_LOG(WARN, "fail to cast pointer", K(ret)); } else { bool need_retry = true; bool need_build = false; const int64_t RETRY_INTERVAL = 5000 * 1000; // 5s while (need_retry) { if (OB_FAIL(dag->check_index_need_build(need_build))) { STORAGE_LOG(WARN, "fail to check index need rebuild", K(ret)); } else if (!need_build) { STORAGE_LOG(INFO, "index does not need build", K(*param_)); need_retry = false; } else if (OB_FAIL(report_index_status(pkey_, *param_, context_, need_retry))) { STORAGE_LOG( WARN, "fail to report index status", K(ret), K(pkey_), "index_id", param_->index_schema_->get_table_id()); } if (need_retry) { if (dag_->has_set_stop()) { STORAGE_LOG(INFO, "dag is stopped, cannot retry now", K(ret), K(pkey_), "index_id", param_->index_schema_->get_table_id()); break; } usleep(RETRY_INTERVAL); dag_yield(); } } } if (OB_FAIL(ret) && NULL != context_) { context_->build_index_ret_ = OB_SUCCESS; ret = OB_SUCCESS; } return ret; } int ObReportIndexStatusTask::report_index_status( const ObPartitionKey& pkey, const ObBuildIndexParam& param, ObBuildIndexContext* context, bool& need_retry) { int ret = OB_SUCCESS; need_retry = true; if (!pkey.is_valid() || !param.is_valid() || OB_ISNULL(context)) { ret = OB_INVALID_ARGUMENT; STORAGE_LOG(WARN, "invalid arguments", K(ret), K(pkey), K(param), KP(context)); } else if (context->is_report_succ_ || !context->need_build_) { // do nothing need_retry = false; } else { ObIndexStatusTableOperator::ObBuildIndexStatus status; const ObAddr& self_addr = GCTX.self_addr_; const uint64_t index_table_id = param.index_schema_->get_table_id(); status.index_status_ = param.index_schema_->get_index_status(); status.ret_code_ = context->build_index_ret_; status.role_ = common::FOLLOWER; if (OB_FAIL(ObIndexStatusTableOperator::report_build_index_status( index_table_id, pkey.get_partition_id(), self_addr, status, *GCTX.sql_proxy_))) { STORAGE_LOG(WARN, "fail to report build index status", K(ret), K(pkey)); } else { context->is_report_succ_ = true; need_retry = false; } STORAGE_LOG(INFO, "process index status report task", K(ret), K(pkey), "build_index_ret_code", status.ret_code_, "index_id", param.index_schema_->get_table_id()); } return ret; } ObUniqueCheckingDag::ObUniqueCheckingDag() : ObIDag(ObIDag::DAG_TYPE_UNIQUE_CHECKING, ObIDag::DAG_PRIO_CREATE_INDEX), is_inited_(false), part_service_(NULL), pkey_(), schema_service_(NULL), schema_guard_(share::schema::ObSchemaMgrItem::MOD_UNIQ_CHECK), index_schema_(NULL), data_table_schema_(NULL), callback_(NULL), execution_id_(0), snapshot_version_(0), compat_mode_(ObWorker::CompatMode::INVALID) {} ObUniqueCheckingDag::~ObUniqueCheckingDag() { if (NULL != callback_) { ob_free(callback_); callback_ = NULL; } } int ObUniqueCheckingDag::init(const ObPartitionKey& pkey, ObPartitionService* part_service, ObMultiVersionSchemaService* schema_service, const uint64_t index_id, const int64_t schema_version, const uint64_t execution_id, const int64_t snapshot_version) { int ret = OB_SUCCESS; ObIPartitionGroupGuard pg_guard; if (OB_UNLIKELY(is_inited_)) { ret = OB_INIT_TWICE; STORAGE_LOG(WARN, "ObUniqueCheckingDag has already been inited", K(ret)); } else if (OB_UNLIKELY(!pkey.is_valid() || NULL == part_service || NULL == schema_service || OB_INVALID_ID == index_id || schema_version <= 0)) { ret = OB_INVALID_ARGUMENT; STORAGE_LOG(WARN, "invalid arguments", K(ret), K(pkey), KP(part_service), KP(schema_service), K(index_id), K(schema_version)); } else if (OB_FAIL(part_service->get_partition(pkey, pg_guard)) || OB_ISNULL(pg_guard.get_partition_group())) { STORAGE_LOG(WARN, "fail to get partition", K(ret), K(pkey)); } else if (OB_FAIL(pg_guard.get_partition_group()->get_pg_partition(pkey, part_guard_)) || OB_ISNULL(part_guard_.get_pg_partition())) { STORAGE_LOG(WARN, "fail to get pg partition", K(ret), K(pkey)); } else if (OB_FAIL(schema_service->get_tenant_schema_guard( extract_tenant_id(pkey.get_table_id()), schema_guard_, schema_version))) { STORAGE_LOG(WARN, "fail to get schema guard", K(ret), K(schema_version)); } else if (OB_FAIL(schema_guard_.check_formal_guard())) { LOG_WARN("schema_guard is not formal", K(ret), K(pkey)); } else if (OB_FAIL(schema_guard_.get_table_schema(index_id, index_schema_))) { STORAGE_LOG(WARN, "fail to get table schema", K(ret)); } else if (OB_ISNULL(index_schema_)) { ret = OB_TABLE_NOT_EXIST; STORAGE_LOG(WARN, "fail to get table schema", K(ret), K(index_id)); } else if (OB_FAIL(schema_guard_.get_table_schema(index_schema_->get_data_table_id(), data_table_schema_))) { STORAGE_LOG(WARN, "fail to get table schema", K(ret)); } else if (OB_ISNULL(data_table_schema_)) { ret = OB_TABLE_NOT_EXIST; STORAGE_LOG(WARN, "data table not exist", K(ret)); } else if (OB_FAIL(get_compat_mode_with_table_id(pkey.table_id_, compat_mode_))) { STORAGE_LOG(WARN, "failed to get compat mode", K(ret), K(pkey)); } else { is_inited_ = true; pkey_ = pkey; part_service_ = part_service; schema_service_ = schema_service; execution_id_ = execution_id; snapshot_version_ = snapshot_version; } return ret; } int ObUniqueCheckingDag::alloc_unique_checking_prepare_task(ObIUniqueCheckingCompleteCallback* callback) { int ret = OB_SUCCESS; ObUniqueCheckingPrepareTask* prepare_task = NULL; if (OB_UNLIKELY(!is_inited_)) { ret = OB_NOT_INIT; STORAGE_LOG(WARN, "ObUniqueCheckingDag has not been inited", K(ret)); } else if (OB_FAIL(alloc_task(prepare_task))) { STORAGE_LOG(WARN, "fail to alloc task", K(ret)); } else if (OB_FAIL(prepare_task->init(callback))) { STORAGE_LOG(WARN, "fail to init prepare task", K(ret)); } else if (OB_FAIL(add_task(*prepare_task))) { STORAGE_LOG(WARN, "fail to add task", K(ret)); } return ret; } int ObUniqueCheckingDag::alloc_local_index_task_callback(ObLocalUniqueIndexCallback*& callback) { int ret = OB_SUCCESS; void* buf = NULL; callback = NULL; if (OB_UNLIKELY(!is_inited_)) { ret = OB_NOT_INIT; STORAGE_LOG(WARN, "ObUniqueCheckingDag has not been inited", K(ret)); } else if (OB_ISNULL(buf = ob_malloc(sizeof(ObLocalUniqueIndexCallback), ObModIds::OB_CS_BUILD_INDEX))) { ret = OB_ALLOCATE_MEMORY_FAILED; STORAGE_LOG(WARN, "fail to allocate memory", K(ret)); } else if (OB_ISNULL(callback = new (buf) ObLocalUniqueIndexCallback())) { ret = OB_ERR_UNEXPECTED; STORAGE_LOG(WARN, "fail to placement new local index callback", K(ret)); } else { callback_ = callback; } return ret; } int ObUniqueCheckingDag::alloc_global_index_task_callback( const ObPartitionKey& pkey, const uint64_t index_id, ObGlobalUniqueIndexCallback*& callback) { int ret = OB_SUCCESS; void* buf = NULL; callback = NULL; if (OB_UNLIKELY(!is_inited_)) { ret = OB_NOT_INIT; STORAGE_LOG(WARN, "ObUniqueCheckingDag has not been inited", K(ret)); } else if (OB_UNLIKELY(!pkey.is_valid() || OB_INVALID_ID == index_id)) { ret = OB_INVALID_ARGUMENT; STORAGE_LOG(WARN, "invalid arguments", K(ret), K(pkey), K(index_id)); } else if (OB_ISNULL(buf = ob_malloc(sizeof(ObGlobalUniqueIndexCallback), ObModIds::OB_CS_BUILD_INDEX))) { ret = OB_ALLOCATE_MEMORY_FAILED; STORAGE_LOG(WARN, "fail to allocate memory", K(ret)); } else if (OB_ISNULL(callback = new (buf) ObGlobalUniqueIndexCallback(pkey, index_id))) { ret = OB_ERR_UNEXPECTED; STORAGE_LOG(WARN, "fail to placement new local index callback", K(ret)); } else { callback_ = callback; } return ret; } int64_t ObUniqueCheckingDag::hash() const { int tmp_ret = OB_SUCCESS; int64_t hash_val = 0; if (NULL == index_schema_) { tmp_ret = OB_ERR_SYS; STORAGE_LOG(ERROR, "index schema must not be NULL", K(tmp_ret)); } else { hash_val = pkey_.hash() + index_schema_->get_table_id(); } return hash_val; } int ObUniqueCheckingDag::fill_comment(char* buf, const int64_t buf_len) const { int ret = OB_SUCCESS; int64_t index_id = 0; if (NULL != index_schema_) { index_id = index_schema_->get_table_id(); } if (!is_inited_) { ret = OB_NOT_INIT; STORAGE_LOG(WARN, "not inited", K(ret)); } else if (OB_FAIL(databuff_printf( buf, buf_len, "unique check task: key=%s index_id=%ld", to_cstring(pkey_), index_id))) { STORAGE_LOG(WARN, "failed to fill comment", K(ret), K(pkey_), K(index_id)); } return ret; } bool ObUniqueCheckingDag::operator==(const ObIDag& other) const { int tmp_ret = OB_SUCCESS; bool is_equal = false; if (OB_UNLIKELY(this == &other)) { is_equal = true; } else if (get_type() == other.get_type()) { const ObUniqueCheckingDag& dag = static_cast(other); if (NULL == index_schema_ || NULL == dag.index_schema_) { tmp_ret = OB_ERR_SYS; STORAGE_LOG(ERROR, "index schema must not be NULL", K(tmp_ret), KP(index_schema_), KP(dag.index_schema_)); } else { is_equal = pkey_ == dag.pkey_ && index_schema_->get_table_id() == dag.index_schema_->get_table_id(); } } return is_equal; } ObUniqueCheckingPrepareTask::ObUniqueCheckingPrepareTask() : ObITask(TASK_TYPE_UNIQUE_CHECKING_PREPARE), is_inited_(false), index_schema_(NULL), data_table_schema_(NULL), callback_(NULL) {} int ObUniqueCheckingPrepareTask::init(ObIUniqueCheckingCompleteCallback* callback) { int ret = OB_SUCCESS; ObUniqueCheckingDag* dag = NULL; if (OB_UNLIKELY(is_inited_)) { ret = OB_INIT_TWICE; STORAGE_LOG(WARN, "ObUniqueCheckingPrepareTask has already been inited", K(ret)); } else if (OB_ISNULL(dag = static_cast(get_dag()))) { ret = OB_ERR_UNEXPECTED; STORAGE_LOG(WARN, "error unexpected, dag must not be NULL", K(ret)); } else if (OB_ISNULL(index_schema_ = dag->get_index_schema())) { ret = OB_INVALID_ARGUMENT; STORAGE_LOG(WARN, "invalid arguments", K(ret), KP(index_schema_)); } else if (OB_ISNULL(data_table_schema_ = dag->get_data_table_schema())) { ret = OB_INVALID_ARGUMENT; STORAGE_LOG(WARN, "invalid data table schema", K(ret)); } else { callback_ = callback; is_inited_ = true; } return ret; } int ObUniqueCheckingPrepareTask::process() { int ret = OB_SUCCESS; ObUniqueCheckingDag* dag = NULL; if (OB_UNLIKELY(!is_inited_)) { ret = OB_NOT_INIT; STORAGE_LOG(WARN, "ObUniqueCheckingPrepareTask has not been inited", K(ret)); } else if (OB_ISNULL(dag = static_cast(get_dag()))) { ret = OB_ERR_UNEXPECTED; STORAGE_LOG(WARN, "error unexpected, dag must not be NULL", K(ret)); } else if (OB_FAIL(generate_unique_checking_task(dag))) { STORAGE_LOG(WARN, "fail to generate unique checking task", K(ret)); } return ret; } int ObUniqueCheckingPrepareTask::generate_unique_checking_task(ObUniqueCheckingDag* dag) { int ret = OB_SUCCESS; ObSimpleUniqueCheckingTask* checking_task = NULL; if (OB_UNLIKELY(!is_inited_)) { ret = OB_NOT_INIT; STORAGE_LOG(WARN, "ObIndexPrepareTask has not been inited", K(ret)); } else if (OB_ISNULL(dag)) { ret = OB_INVALID_ARGUMENT; STORAGE_LOG(WARN, "invalid arguments", K(ret), KP(dag)); } else if (OB_FAIL(dag->alloc_task(checking_task))) { STORAGE_LOG(WARN, "fail to alloc checking task", K(ret)); } else if (OB_FAIL(checking_task->init(data_table_schema_, index_schema_, callback_))) { STORAGE_LOG(WARN, "fail to init unique checking task", K(ret)); } else if (OB_FAIL(add_child(*checking_task))) { STORAGE_LOG(WARN, "fail to add child for prepare task", K(ret)); } else if (OB_FAIL(dag->add_task(*checking_task))) { STORAGE_LOG(WARN, "fail to add unique checking task", K(ret)); } return ret; } ObSimpleUniqueCheckingTask::ObSimpleUniqueCheckingTask() : ObITask(TASK_TYPE_SIMPLE_UNIQUE_CHECKING), is_inited_(false), unique_checker_(), index_schema_(NULL), data_table_schema_(NULL), pkey_(), callback_(NULL) {} int ObSimpleUniqueCheckingTask::init(const ObTableSchema* data_table_schema, const ObTableSchema* index_schema, ObIUniqueCheckingCompleteCallback* callback) { int ret = OB_SUCCESS; ObUniqueCheckingDag* dag = NULL; if (OB_UNLIKELY(is_inited_)) { ret = OB_INIT_TWICE; STORAGE_LOG(WARN, "ObSimpleUniqueCheckingTask has already been inited", K(ret)); } else if (OB_ISNULL(data_table_schema) || OB_ISNULL(index_schema) || OB_ISNULL(callback)) { ret = OB_INVALID_ARGUMENT; STORAGE_LOG(WARN, "invalid arguments", K(ret), KP(data_table_schema), KP(index_schema), KP(callback)); } else if (OB_ISNULL(dag = static_cast(get_dag()))) { ret = OB_ERR_UNEXPECTED; STORAGE_LOG(WARN, "error unexpected, dag must not be NULL", K(ret)); } else { ObPartitionService* part_service = dag->get_partition_service(); pkey_ = dag->get_partition_key(); if (OB_UNLIKELY(NULL == part_service || !pkey_.is_valid())) { ret = OB_INVALID_ARGUMENT; STORAGE_LOG(WARN, "invalid arguments", K(ret), KP(part_service), K(pkey_)); } else if (OB_FAIL(unique_checker_.init(part_service, pkey_, data_table_schema, index_schema, dag->get_execution_id(), dag->get_snapshot_version()))) { STORAGE_LOG(WARN, "fail to init unique index checker", K(ret)); } else { index_schema_ = index_schema; data_table_schema_ = data_table_schema; callback_ = callback; is_inited_ = true; } } return ret; } int ObSimpleUniqueCheckingTask::process() { int ret = OB_SUCCESS; int ret_code = OB_SUCCESS; ObUniqueCheckingDag* dag = NULL; if (OB_UNLIKELY(!is_inited_)) { ret = OB_NOT_INIT; STORAGE_LOG(WARN, "ObSimpleUniqueCheckingTask has not been inited", K(ret)); } else if (OB_ISNULL(dag = static_cast(get_dag()))) { ret = OB_ERR_UNEXPECTED; STORAGE_LOG(WARN, "error unexpected, dag must not be NULL", K(ret)); } else if (OB_FAIL(unique_checker_.check_unique_index(dag))) { STORAGE_LOG(WARN, "fail to check unique index", K(ret)); } ret_code = ret; // overwrite ret if (NULL != callback_) { if (NULL != index_schema_) { STORAGE_LOG(INFO, "unique checking callback", K(pkey_), "index_id", index_schema_->get_table_id()); } if (OB_FAIL(callback_->operator()(ret_code))) { STORAGE_LOG(WARN, "fail to check unique index response", K(ret)); } } return ret; } ObGlobalUniqueIndexCallback::ObGlobalUniqueIndexCallback(const common::ObPartitionKey& pkey, const uint64_t index_id) : pkey_(pkey), index_id_(index_id) {} int ObGlobalUniqueIndexCallback::operator()(const int ret_code) { int ret = OB_SUCCESS; obrpc::ObCalcColumnChecksumResponseArg arg; ObAddr rs_addr; arg.pkey_ = pkey_; arg.index_id_ = index_id_; arg.ret_code_ = ret_code; if (OB_ISNULL(GCTX.rs_rpc_proxy_) || OB_ISNULL(GCTX.rs_mgr_)) { ret = OB_ERR_SYS; STORAGE_LOG(WARN, "innner system error, rootserver rpc proxy or rs mgr must not be NULL", K(ret), K(GCTX)); } else if (OB_FAIL(GCTX.rs_mgr_->get_master_root_server(rs_addr))) { STORAGE_LOG(WARN, "fail to get rootservice address", K(ret)); } else if (OB_FAIL(GCTX.rs_rpc_proxy_->to(rs_addr).calc_column_checksum_response(arg))) { STORAGE_LOG(WARN, "fail to check unique index response", K(ret), K(arg)); } return ret; } ObLocalUniqueIndexCallback::ObLocalUniqueIndexCallback() {} int ObLocalUniqueIndexCallback::operator()(const int ret_code) { int ret = OB_SUCCESS; UNUSED(ret_code); return ret; }