2194 lines
		
	
	
		
			85 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			2194 lines
		
	
	
		
			85 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /**
 | |
|  * Copyright (c) 2021 OceanBase
 | |
|  * OceanBase CE is licensed under Mulan PubL v2.
 | |
|  * You can use this software according to the terms and conditions of the Mulan PubL v2.
 | |
|  * You may obtain a copy of Mulan PubL v2 at:
 | |
|  *          http://license.coscl.org.cn/MulanPubL-2.0
 | |
|  * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 | |
|  * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 | |
|  * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 | |
|  * See the Mulan PubL v2 for more details.
 | |
|  */
 | |
| 
 | |
| #define USING_LOG_PREFIX 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<const ObBuildIndexDag&>(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<ObPartitionStorage*>(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<ObBuildIndexDag*>(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<ObBuildIndexDag*>(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<ObBuildIndexDag*>(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<ObBuildIndexDag*>(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<ObExternalSort<ObStoreRow, ObStoreRowComparer>*>& local_sorters,
 | |
|     ObExternalSort<ObStoreRow, ObStoreRowComparer>& merge_sorter, ObBuildIndexContext* context,
 | |
|     ObTableHandle& new_sstable)
 | |
| {
 | |
|   int ret = OB_SUCCESS;
 | |
|   int tmp_ret = OB_SUCCESS;
 | |
|   int comp_ret = OB_SUCCESS;
 | |
|   ObArray<int64_t> 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<ObBuildIndexDag*>(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<ObStoreRow, ObStoreRowComparer>* 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<ObStoreRow, ObStoreRowComparer>& 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<ObBuildIndexDag*>(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<int>(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<ObBuildIndexDag*>(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<ObBuildIndexDag*>(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<int64_t>& 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<int64_t>& 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<ObPartitionStorage*>(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<ObColumnParam*> col_params;
 | |
|     ObArray<uint64_t> 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<ObScanTableParam&>(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<int64_t>& column_checksum, int64_t& row_count)
 | |
| {
 | |
|   int ret = OB_SUCCESS;
 | |
|   ObArray<share::schema::ObColDesc> col_ids;
 | |
|   ObArray<share::schema::ObColDesc> org_col_ids;
 | |
|   ObArray<int32_t> 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<int64_t>& column_checksum, int64_t& row_count)
 | |
| {
 | |
|   int ret = OB_SUCCESS;
 | |
|   ObArray<ObColDesc> 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<int32_t> output_projector;
 | |
|     for (int64_t i = 0; OB_SUCC(ret) && i < column_ids.count(); ++i) {
 | |
|       if (OB_FAIL(output_projector.push_back(static_cast<int32_t>(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<int64_t> 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<ObColDesc> 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<ObIndexChecksumItem> 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<ObPartitionStorage*>(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<int64_t> data_table_column_checksum;
 | |
|     ObTablesHandle index_table_handle;
 | |
|     ObArray<int64_t> 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<ObColDesc> 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<ObPartitionStorage*>(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<ObBuildIndexDag*>(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<ObBuildIndexDag*>(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<ObBuildIndexDag*>(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<const ObUniqueCheckingDag&>(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<ObUniqueCheckingDag*>(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<ObUniqueCheckingDag*>(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<ObUniqueCheckingDag*>(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<ObUniqueCheckingDag*>(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;
 | |
| }
 | 
