/** * 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 SQL_EXE #include "sql/session/ob_sql_session_info.h" #include "sql/engine/ob_physical_plan_ctx.h" #include "sql/executor/ob_fifo_receive.h" #include "sql/executor/ob_receive.h" #include "sql/executor/ob_transmit.h" #include "sql/executor/ob_job.h" #include "sql/executor/ob_task_executor_ctx.h" #include "sql/executor/ob_executor_rpc_impl.h" #include "sql/executor/ob_distributed_scheduler.h" #include "share/ob_define.h" #include "sql/engine/ob_exec_context.h" using namespace oceanbase::common; namespace oceanbase { namespace sql { ObTaskResultIter::ObTaskResultIter(IterType iter_type) : iter_type_(iter_type) {} ObTaskResultIter::~ObTaskResultIter() {} ObRootTaskResultIter::ObRootTaskResultIter( ObExecContext& exec_ctx, uint64_t exec_id, uint64_t child_op_id, int64_t ts_timeout) : ObTaskResultIter(IT_ROOT), exec_ctx_(exec_ctx), exec_id_(exec_id), scheduler_holder_(), scheduler_(NULL), child_op_id_(child_op_id), ts_timeout_(ts_timeout) {} ObRootTaskResultIter::~ObRootTaskResultIter() { scheduler_holder_.reset(); } int ObRootTaskResultIter::get_next_task_result(ObTaskResult& task_result) { int ret = OB_SUCCESS; if (OB_ISNULL(scheduler_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("scheduler is NULL", K(ret)); } else if (OB_FAIL(scheduler_->pop_task_result_for_root(exec_ctx_, child_op_id_, task_result, ts_timeout_))) { if (OB_ITER_END != ret) { LOG_WARN("fail to pop task result for root", K(ret)); } } return ret; } int ObRootTaskResultIter::check_status() { int ret = OB_SUCCESS; if (OB_ISNULL(scheduler_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("scheduler is NULL", K(ret)); } else if (OB_FAIL(scheduler_->get_schedule_ret())) { if (OB_ITER_END != ret) { LOG_WARN("schecule error", K(ret)); } else { ret = OB_SUCCESS; } } return ret; } int ObRootTaskResultIter::init() { int ret = OB_SUCCESS; ObDistributedSchedulerManager* scheduler_manager = ObDistributedSchedulerManager::get_instance(); if (OB_ISNULL(scheduler_manager)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("ObDistributedSchedulerManager instance is NULL", K(ret)); } else if (OB_FAIL(scheduler_manager->get_scheduler(exec_id_, scheduler_holder_))) { LOG_WARN("fail to get scheduler holder", K(ret)); } else if (OB_FAIL(scheduler_holder_.get_scheduler(scheduler_))) { LOG_WARN("fail to get scheduler", K(ret)); } else if (OB_ISNULL(scheduler_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("scheduler is NULL", K(ret)); } return ret; } ObDistributedTaskResultIter::ObDistributedTaskResultIter(const ObIArray& task_results) : ObTaskResultIter(IT_DISTRIBUTED), task_results_(task_results), cur_idx_(0) {} ObDistributedTaskResultIter::~ObDistributedTaskResultIter() {} int ObDistributedTaskResultIter::get_next_task_result(ObTaskResult& task_result) { int ret = OB_SUCCESS; if (cur_idx_ < 0) { ret = OB_ERR_UNEXPECTED; LOG_WARN("cur idx is less than 0", K(ret)); } else if (cur_idx_ >= task_results_.count()) { ret = OB_ITER_END; } else if (OB_FAIL(task_result.init( task_results_.at(cur_idx_).get_task_location(), task_results_.at(cur_idx_).get_slice_events()))) { LOG_WARN("fail to init task result", K(ret)); } else { cur_idx_++; } return ret; } int ObDistributedTaskResultIter::check_status() { return OB_SUCCESS; } ObDistributedReceiveInput::ObDistributedReceiveInput() : child_task_results_(), child_job_id_(0) {} ObDistributedReceiveInput::~ObDistributedReceiveInput() {} void ObDistributedReceiveInput::reset() { child_task_results_.reset(); } int ObDistributedReceiveInput::init(ObExecContext& exec_ctx, ObTaskInfo& task_info, const ObPhyOperator& phy_op) { int ret = OB_SUCCESS; ObIArray& child_task_results = task_info.get_child_task_results(); for (int64_t i = 0; OB_SUCC(ret) && i < child_task_results.count(); i++) { ObTaskResultBuf& task_result = child_task_results.at(i); if (task_result.get_task_location().get_job_id() == child_job_id_) { if (OB_FAIL(child_task_results_.push_back(task_result))) { LOG_WARN("fail to push back child task result", K(ret)); } } } UNUSED(exec_ctx); UNUSED(phy_op); return ret; } OB_SERIALIZE_MEMBER(ObDistributedReceiveInput, child_task_results_, child_job_id_); ObIDataSource::ObIDataSource() : cur_scanner_(ObModIds::OB_SQL_EXECUTOR), row_iter_(), exec_ctx_(nullptr), use_small_result_(false), inited_(false) {} ObIDataSource::~ObIDataSource() { // destroy(); } int ObIDataSource::open(ObExecContext& exec_ctx, const ObTaskResult& task_result) { int ret = OB_SUCCESS; exec_ctx_ = &exec_ctx; const common::ObIArray* slice_events = task_result.get_slice_events(); if (OB_UNLIKELY(inited_)) { ret = OB_INIT_TWICE; LOG_WARN("open twice", K(ret)); } else if (OB_ISNULL(slice_events)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("slice event is NULL", K(ret), KP(slice_events)); } else if (1 != slice_events->count()) { ret = OB_NOT_IMPLEMENT; LOG_WARN("receive should read only 1 slice per task now", K(ret)); } else if (!cur_scanner_.is_inited() && OB_FAIL(cur_scanner_.init())) { LOG_WARN("fail to init scanner", K(ret)); } else if (slice_events->at(0).has_small_result()) { int64_t pos = 0; if (OB_FAIL(cur_scanner_.deserialize( slice_events->at(0).get_small_result_buf(), slice_events->at(0).get_small_result_len(), pos))) { LOG_WARN("fail to deserialize current small result", K(ret)); } else { use_small_result_ = true; } } else { slice_id_ = slice_events->at(0).get_ob_slice_id(); peer_ = task_result.get_task_location().get_server(); if (OB_FAIL(fetch_next_scanner())) { LOG_WARN("fetch next scanner failed", K(ret)); } } if (OB_SUCC(ret)) { row_iter_ = cur_scanner_.begin(); inited_ = true; if (!cur_scanner_.is_result_accurate()) { if (OB_ISNULL(exec_ctx.get_physical_plan_ctx())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("phy plan ctx is NULL", K(ret)); } else { exec_ctx.get_physical_plan_ctx()->set_is_result_accurate(false); } } } return ret; } int ObIDataSource::get_next_row(ObNewRow& row) { int ret = OB_SUCCESS; while (OB_SUCC(ret)) { if (OB_SUCC(row_iter_.get_next_row(row))) { break; } else if (OB_UNLIKELY(OB_ITER_END != ret)) { LOG_WARN("fail to get next row", K(ret)); } else if (!use_small_result_) { if (OB_FAIL(fetch_next_scanner())) { if (OB_ITER_END != ret) { LOG_WARN("fetch next scanner failed", K(ret)); } } else { row_iter_ = cur_scanner_.begin(); } } } return ret; } int ObIDataSource::close() { cur_scanner_.reset(); row_iter_.reset(); exec_ctx_ = NULL; slice_id_.reset(); peer_.reset(); use_small_result_ = false; inited_ = false; return OB_SUCCESS; } ObStreamDataSource::ObStreamDataSource() : stream_handler_(ObModIds::OB_SQL_EXECUTOR), stream_opened_(false) {} ObStreamDataSource::~ObStreamDataSource() { if (inited_) { int ret = close(); if (OB_SUCCESS != ret) { LOG_WARN("close data source failed", K(ret)); } } } int ObStreamDataSource::fetch_next_scanner() { int ret = OB_SUCCESS; ObIntermResultItem* handler_result = stream_handler_.get_result(); if (OB_ISNULL(exec_ctx_) || OB_ISNULL(handler_result)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("execute ctx/handler result is NULL"); } else { if (!stream_opened_) { ObExecutorRpcImpl* exec_rpc = NULL; ObSQLSessionInfo* session = exec_ctx_->get_my_session(); ObPhysicalPlanCtx* plan_ctx = exec_ctx_->get_physical_plan_ctx(); if (OB_FAIL(ObTaskExecutorCtxUtil::get_task_executor_rpc(*exec_ctx_, exec_rpc))) { LOG_WARN("fail to get executor rpc", K(ret)); } else if (OB_ISNULL(session) || OB_ISNULL(plan_ctx) || OB_ISNULL(exec_rpc)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("some parameter is NULL", K(ret), K(session), K(plan_ctx), K(exec_rpc)); } else { // should reset first to release previous scanner memory handler_result->reset(); ObExecutorRpcCtx rpc_ctx(session->get_rpc_tenant_id(), plan_ctx->get_timeout_timestamp(), exec_ctx_->get_task_exec_ctx().get_min_cluster_version(), &exec_ctx_->get_scheduler_thread_ctx().get_scheduler_retry_info_for_update(), exec_ctx_->get_my_session(), plan_ctx->is_plain_select_stmt()); if (OB_FAIL(exec_rpc->task_fetch_interm_result(rpc_ctx, slice_id_, peer_, stream_handler_))) { LOG_WARN("fail to fetch task result", K(ret)); } else if (OB_FAIL(handler_result->to_scanner(cur_scanner_))) { LOG_WARN("fail to assign to scanner", K(ret), K(*handler_result)); } } stream_opened_ = true; } else { if (!stream_handler_.get_handle().has_more()) { ret = OB_ITER_END; } else if (OB_FAIL(stream_handler_.reset_result())) { LOG_WARN("reset result failed", K(ret)); } else if (OB_FAIL(stream_handler_.get_handle().get_more(*handler_result))) { LOG_WARN("get more result failed", K(ret)); } else { cur_scanner_.reset(); if (OB_FAIL(handler_result->to_scanner(cur_scanner_))) { LOG_WARN("assign to scanner failed", K(ret)); } } } } return ret; } int ObStreamDataSource::close() { int ret = OB_SUCCESS; if (OB_FAIL(ObIDataSource::close())) { LOG_WARN("close base data source failed", K(ret)); } if (OB_SUCC(ret)) { if (stream_handler_.get_handle().has_more()) { if (OB_FAIL(stream_handler_.get_handle().abort())) { LOG_WARN("fail to abort stream handler", K(ret)); } } } stream_opened_ = false; return ret; } ObSpecifyDataSource::ObSpecifyDataSource() : fetch_index_(OB_INVALID_INDEX) {} ObSpecifyDataSource::~ObSpecifyDataSource() { if (inited_) { int ret = close(); if (OB_SUCCESS != ret) { LOG_WARN("close data source failed", K(ret)); } } } int ObSpecifyDataSource::fetch_next_scanner() { int ret = OB_SUCCESS; if (OB_INVALID_INDEX == fetch_index_) { // first fetch fetch_index_ = 0; } else if (fetch_index_ >= interm_result_item_.total_item_cnt_) { ret = OB_ITER_END; } if (OB_FAIL(ret)) { } else if (OB_ISNULL(exec_ctx_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("execute ctx/task result is NULL", K(ret)); } else { ObExecutorRpcImpl* exec_rpc = NULL; ObSQLSessionInfo* session = exec_ctx_->get_my_session(); ObPhysicalPlanCtx* plan_ctx = exec_ctx_->get_physical_plan_ctx(); if (OB_FAIL(ObTaskExecutorCtxUtil::get_task_executor_rpc(*exec_ctx_, exec_rpc))) { LOG_WARN("fail to get executor rpc", K(ret)); } else if (OB_ISNULL(session) || OB_ISNULL(plan_ctx) || OB_ISNULL(exec_rpc)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("some parameter is NULL", K(ret), K(session), K(plan_ctx), K(exec_rpc)); } else { ObExecutorRpcCtx rpc_ctx(session->get_rpc_tenant_id(), plan_ctx->get_timeout_timestamp(), exec_ctx_->get_task_exec_ctx().get_min_cluster_version(), &exec_ctx_->get_scheduler_thread_ctx().get_scheduler_retry_info_for_update(), exec_ctx_->get_my_session(), plan_ctx->is_plain_select_stmt()); int64_t pre_total_cnt = interm_result_item_.total_item_cnt_; interm_result_item_.result_item_.reset(); if (OB_FAIL(exec_rpc->fetch_interm_result_item(rpc_ctx, peer_, slice_id_, fetch_index_, interm_result_item_))) { LOG_WARN("fetch interm result item failed", K(ret), K(peer_), K(slice_id_), K(fetch_index_)); } else { fetch_index_ += 1; cur_scanner_.reset(); if (interm_result_item_.total_item_cnt_ < 0 || (pre_total_cnt >= 0 && pre_total_cnt != interm_result_item_.total_item_cnt_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN( "invalid interm result item count", K(ret), K(interm_result_item_.total_item_cnt_), K(pre_total_cnt)); } else if (OB_FAIL(interm_result_item_.result_item_.to_scanner(cur_scanner_))) { LOG_WARN("assign to scanner failed", K(ret)); } } } } return ret; } int ObSpecifyDataSource::close() { int ret = OB_SUCCESS; if (OB_FAIL(ObIDataSource::close())) { LOG_WARN("close base data source failed", K(ret)); } else { fetch_index_ = OB_INVALID_INDEX; interm_result_item_.total_item_cnt_ = -1; interm_result_item_.result_item_.reset(); } return ret; } ObAsyncReceive::ObAsyncReceiveCtx::ObAsyncReceiveCtx(ObExecContext& exec_ctx) : ObReceiveCtx(exec_ctx), task_result_iter_(NULL), found_rows_(0), affected_rows_(0), matched_rows_(0), duplicated_rows_(0), iter_end_(false) {} ObAsyncReceive::ObAsyncReceiveCtx::~ObAsyncReceiveCtx() {} void ObAsyncReceive::ObAsyncReceiveCtx::destroy() { if (NULL != task_result_iter_) { task_result_iter_->~ObTaskResultIter(); task_result_iter_ = NULL; } ObReceiveCtx::destroy(); } int ObAsyncReceive::ObAsyncReceiveCtx::init_root_iter(uint64_t child_op_id) { int ret = OB_SUCCESS; uint64_t exec_id = exec_ctx_.get_execution_id(); ObPhysicalPlanCtx* plan_ctx = exec_ctx_.get_physical_plan_ctx(); int64_t ts_timeout = 0; void* iter_buf = NULL; ObRootTaskResultIter* task_result_iter = NULL; if (!OB_ISNULL(task_result_iter_)) { ret = OB_INIT_TWICE; LOG_WARN("task result iter is not null", K(ret)); } else if (OB_ISNULL(plan_ctx)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("plan ctx is NULL", K(ret)); } else if (FALSE_IT(ts_timeout = plan_ctx->get_timeout_timestamp())) { } else if (OB_ISNULL(iter_buf = exec_ctx_.get_allocator().alloc(sizeof(ObRootTaskResultIter)))) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("fail to alloc root iter buf", K(ret)); } else if (OB_ISNULL( task_result_iter = new (iter_buf) ObRootTaskResultIter(exec_ctx_, exec_id, child_op_id, ts_timeout))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("fail to new root task result iter object", K(ret)); } else if (OB_FAIL(task_result_iter->init())) { LOG_WARN("fail to init task result iter", K(ret)); task_result_iter->~ObRootTaskResultIter(); task_result_iter = NULL; } else { task_result_iter_ = task_result_iter; } return ret; } int ObAsyncReceive::ObAsyncReceiveCtx::init_distributed_iter(const ObIArray& task_results) { int ret = OB_SUCCESS; void* iter_buf = NULL; if (!OB_ISNULL(task_result_iter_)) { ret = OB_INIT_TWICE; LOG_WARN("task result iter is not null", K(ret)); } else if (OB_ISNULL(iter_buf = exec_ctx_.get_allocator().alloc(sizeof(ObDistributedTaskResultIter)))) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("fail to alloc root iter buf", K(ret)); } else if (OB_ISNULL(task_result_iter_ = new (iter_buf) ObDistributedTaskResultIter(task_results))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("fail to new distributed task result iter object", K(ret)); } return ret; } int ObAsyncReceive::create_data_source(ObExecContext& exec_ctx, ObIDataSource*& data_source) const { int ret = OB_SUCCESS; const bool use_specify_ds = GET_MIN_CLUSTER_VERSION() > CLUSTER_VERSION_2000; const int64_t buf_size = use_specify_ds ? sizeof(ObSpecifyDataSource) : sizeof(ObStreamDataSource); void* buf = exec_ctx.get_allocator().alloc(buf_size); if (OB_ISNULL(buf)) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("fail to alloc data source buf", K(ret), K(buf_size)); } else { if (use_specify_ds) { data_source = new (buf) ObSpecifyDataSource(); } else { data_source = new (buf) ObStreamDataSource(); } } return ret; } ObAsyncReceive::ObAsyncReceive(common::ObIAllocator& alloc) : ObReceive(alloc), in_root_job_(false) {} ObAsyncReceive::~ObAsyncReceive() {} int ObAsyncReceive::create_operator_input(ObExecContext& exec_ctx) const { int ret = OB_SUCCESS; ObDistributedReceiveInput* op_input = NULL; if (!is_in_root_job()) { if (OB_FAIL( CREATE_PHY_OP_INPUT(ObDistributedReceiveInput, exec_ctx, get_id(), PHY_DISTRIBUTED_RECEIVE, op_input))) { LOG_WARN("fail to create distributed receive input", K(ret)); } else if (OB_ISNULL(op_input)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("receive input is NULL", K(ret)); } } return ret; } int ObAsyncReceive::init_op_ctx(ObExecContext& exec_ctx) const { int ret = OB_SUCCESS; ObAsyncReceiveCtx* op_ctx = NULL; if (OB_FAIL(create_op_ctx(exec_ctx, op_ctx))) { LOG_WARN("fail to create receive ctx", K(ret)); } else if (OB_ISNULL(op_ctx)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("receive ctx is NULL", K(ret), K(op_ctx)); } else if (OB_FAIL(init_cur_row(*op_ctx, true))) { LOG_WARN("create current row failed", K(ret)); } else if (is_in_root_job()) { if (1 != get_child_num()) { ret = OB_ERR_UNEXPECTED; LOG_WARN("receive child num should be 1", K(ret), K(get_child_num())); } else if (OB_FAIL(op_ctx->init_root_iter(get_child(0)->get_id()))) { LOG_WARN("fail to init root iter", K(ret)); } } else { ObDistributedReceiveInput* op_input = GET_PHY_OP_INPUT(ObDistributedReceiveInput, exec_ctx, get_id()); if (OB_ISNULL(op_input)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("receive input is NULL", K(ret), K(op_input)); } else if (OB_FAIL(op_ctx->init_distributed_iter(op_input->get_child_task_results()))) { LOG_WARN("fail to init distributed iter", K(ret)); } } return ret; } int ObAsyncReceive::inner_close(ObExecContext& exec_ctx) const { int ret = OB_SUCCESS; ObAsyncReceiveCtx* op_ctx = GET_PHY_OPERATOR_CTX(ObAsyncReceiveCtx, exec_ctx, get_id()); ObPhysicalPlanCtx* plan_ctx = exec_ctx.get_physical_plan_ctx(); if (OB_ISNULL(op_ctx)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("receive ctx is NULL", K(ret)); } else { if (OB_ISNULL(op_ctx->task_result_iter_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("task result iter is NULL", K(ret)); } else { op_ctx->task_result_iter_->~ObTaskResultIter(); op_ctx->task_result_iter_ = NULL; } if (OB_ISNULL(plan_ctx)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("plan ctx is NULL", K(ret)); } else { plan_ctx->set_found_rows(plan_ctx->get_found_rows() + op_ctx->found_rows_); } } return ret; } int ObAsyncReceive::rescan(ObExecContext& exec_ctx) const { UNUSED(exec_ctx); int ret = OB_NOT_SUPPORTED; LOG_USER_ERROR(OB_NOT_SUPPORTED, "Distributed rescan"); return ret; } int ObAsyncReceive::get_next_task_result(ObAsyncReceiveCtx& op_ctx, ObTaskResult& task_result) const { int ret = OB_SUCCESS; if (OB_ISNULL(op_ctx.task_result_iter_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("task result iter is NULL", K(ret)); } else { while (OB_SUCC(ret)) { if (OB_FAIL(op_ctx.task_result_iter_->get_next_task_result(task_result))) { if (OB_ITER_END != ret) { LOG_WARN("fail to get next task result", K(ret)); } } else if (task_result.has_empty_data()) { op_ctx.affected_rows_ += task_result.get_affected_rows(); op_ctx.duplicated_rows_ += task_result.get_duplicated_rows(); op_ctx.matched_rows_ += task_result.get_matched_rows(); task_result.reset(); } else { op_ctx.found_rows_ += task_result.get_found_rows(); break; } } } return ret; } ObSerialReceive::ObSerialReceiveCtx::ObSerialReceiveCtx(ObExecContext& exec_ctx) : ObAsyncReceiveCtx(exec_ctx), data_source_(NULL) {} ObSerialReceive::ObSerialReceiveCtx::~ObSerialReceiveCtx() {} void ObSerialReceive::ObSerialReceiveCtx::destroy() { if (NULL != data_source_) { data_source_->~ObIDataSource(); data_source_ = NULL; } ObAsyncReceiveCtx::destroy(); } ObSerialReceive::ObSerialReceive(common::ObIAllocator& alloc) : ObAsyncReceive(alloc) {} ObSerialReceive::~ObSerialReceive() {} int ObSerialReceive::inner_open(ObExecContext& exec_ctx) const { int ret = OB_SUCCESS; ObSerialReceiveCtx* op_ctx = NULL; ObTaskResult task_result; ObPhysicalPlanCtx* plan_ctx = exec_ctx.get_physical_plan_ctx(); if (OB_ISNULL(plan_ctx)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("plan_ctx is NULL", K(ret)); } else if (OB_FAIL(init_op_ctx(exec_ctx))) { LOG_WARN("fail to initialize operator context", K(ret)); } else if (OB_ISNULL(op_ctx = GET_PHY_OPERATOR_CTX(ObSerialReceiveCtx, exec_ctx, get_id()))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("receive ctx is NULL", K(ret)); } else if (OB_FAIL(get_next_task_result(*op_ctx, task_result))) { if (OB_ITER_END != ret) { LOG_WARN("fail to get next task result", K(ret)); } else { if (op_ctx->affected_rows_ > 0) { plan_ctx->set_affected_rows(plan_ctx->get_affected_rows() + op_ctx->affected_rows_); } if (op_ctx->duplicated_rows_ > 0) { plan_ctx->set_row_duplicated_count(plan_ctx->get_row_duplicated_count() + op_ctx->duplicated_rows_); } if (op_ctx->matched_rows_ > 0) { plan_ctx->set_row_matched_count(plan_ctx->get_row_matched_count() + op_ctx->matched_rows_); } ret = OB_SUCCESS; op_ctx->iter_end_ = true; } } else if (OB_FAIL(create_data_source(exec_ctx, op_ctx->data_source_))) { LOG_WARN("create data source failed", K(ret)); } else if (OB_ISNULL(op_ctx->data_source_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("data source is NULL", K(ret)); } else if (OB_FAIL(op_ctx->data_source_->open(exec_ctx, task_result))) { LOG_WARN("fail to open data source", K(ret)); } return ret; } int ObSerialReceive::inner_get_next_row(ObExecContext& exec_ctx, const common::ObNewRow*& row) const { int ret = OB_SUCCESS; ObSerialReceiveCtx* op_ctx = GET_PHY_OPERATOR_CTX(ObSerialReceiveCtx, exec_ctx, get_id()); if (OB_ISNULL(op_ctx) || OB_ISNULL(op_ctx->task_result_iter_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("receive ctx or task result iter is NULL", K(ret)); } else if (op_ctx->iter_end_) { ret = OB_ITER_END; } else if (OB_FAIL(check_status(exec_ctx)) || OB_FAIL(op_ctx->task_result_iter_->check_status())) { LOG_WARN("fail to check status", K(ret)); } while (OB_SUCC(ret)) { if (OB_SUCC(op_ctx->data_source_->get_next_row(op_ctx->cur_row_))) { row = &op_ctx->cur_row_; break; } else if (OB_ITER_END == ret) { ObTaskResult task_result; if (OB_FAIL(op_ctx->data_source_->close())) { LOG_WARN("fail to close data source", K(ret)); } else if (OB_FAIL(get_next_task_result(*op_ctx, task_result))) { if (OB_ITER_END != ret) { LOG_WARN("fail to get next task result", K(ret)); } else { op_ctx->iter_end_ = true; } } else if (OB_FAIL(op_ctx->data_source_->open(exec_ctx, task_result))) { LOG_WARN("fail to open data source", K(ret)); } } else { LOG_WARN("fail to get next row", K(ret)); } } return ret; } int ObSerialReceive::inner_close(ObExecContext& exec_ctx) const { int ret = OB_SUCCESS; ObSerialReceiveCtx* op_ctx = GET_PHY_OPERATOR_CTX(ObSerialReceiveCtx, exec_ctx, get_id()); if (OB_ISNULL(op_ctx)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("receive ctx is NULL", K(ret)); } else { if (NULL != op_ctx->data_source_) { if (OB_FAIL(op_ctx->data_source_->close())) { LOG_WARN("fail to close data source", K(ret)); } } } if (OB_FAIL(ObAsyncReceive::inner_close(exec_ctx))) { LOG_WARN("fail to inner close", K(ret)); } return ret; } ObParallelReceive::ObParallelReceiveCtx::ObParallelReceiveCtx(ObExecContext& exec_ctx) : ObAsyncReceiveCtx(exec_ctx), data_sources_(), child_rows_(), row_idxs_() {} ObParallelReceive::ObParallelReceiveCtx::~ObParallelReceiveCtx() {} void ObParallelReceive::ObParallelReceiveCtx::destroy() { data_sources_.~ObSEArray(); child_rows_.~ObSEArray(); row_idxs_.~ObSEArray(); ObAsyncReceiveCtx::destroy(); } ObParallelReceive::ObParallelReceive(common::ObIAllocator& alloc) : ObAsyncReceive(alloc) {} ObParallelReceive::~ObParallelReceive() {} int ObParallelReceive::inner_open(ObExecContext& exec_ctx) const { int ret = OB_SUCCESS; ObParallelReceiveCtx* op_ctx = NULL; if (OB_FAIL(init_op_ctx(exec_ctx))) { LOG_WARN("fail to initialize operator context", K(ret)); } else if (OB_ISNULL(op_ctx = GET_PHY_OPERATOR_CTX(ObParallelReceiveCtx, exec_ctx, get_id()))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("receive ctx is NULL", K(ret)); } else { ObTaskResult task_result; ObIDataSource* data_source = NULL; ObNewRow row; int64_t row_count = 0; while (OB_SUCC(ret)) { if (OB_FAIL(get_next_task_result(*op_ctx, task_result))) { if (OB_ITER_END != ret) { LOG_WARN("fail to get next task result", K(ret)); } else { ret = OB_SUCCESS; break; } } else if (task_result.has_empty_data()) { // skip task result with empty data. } else if (OB_FAIL(create_data_source(exec_ctx, data_source))) { LOG_WARN("fail to create data source", K(ret)); } else if (OB_ISNULL(data_source)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("data source is NULL", K(ret)); } else if (OB_FAIL(create_new_row(exec_ctx, op_ctx->cur_row_, row))) { LOG_WARN("fail to create new row", K(ret)); } else if (OB_FAIL(data_source->open(exec_ctx, task_result))) { LOG_WARN("fail to open data source", K(ret)); } else if (OB_FAIL(data_source->get_next_row(row))) { LOG_WARN("fail to get next row", K(ret)); } else if (OB_FAIL(op_ctx->data_sources_.push_back(data_source))) { LOG_WARN("fail to push back data source", K(ret)); } else if (OB_FAIL(op_ctx->child_rows_.push_back(row))) { LOG_WARN("fail to push back child row", K(ret)); } else if (OB_FAIL(op_ctx->row_idxs_.push_back(row_count))) { LOG_WARN("fail to push back row idx", K(ret)); } else { row_count++; task_result.reset(); data_source = NULL; row.reset(); } } if (0 == row_count) { op_ctx->iter_end_ = true; } } return ret; } int ObParallelReceive::inner_close(ObExecContext& exec_ctx) const { int ret = OB_SUCCESS; ObParallelReceiveCtx* op_ctx = GET_PHY_OPERATOR_CTX(ObParallelReceiveCtx, exec_ctx, get_id()); if (OB_ISNULL(op_ctx)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("receive ctx is NULL", K(ret)); } else { for (int64_t i = 0; /*OB_SUCC(ret)*/ i < op_ctx->data_sources_.count(); i++) { if (OB_ISNULL(op_ctx->data_sources_.at(i))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("data source is NULL", K(ret), K(i)); } else { if (OB_FAIL(op_ctx->data_sources_.at(i)->close())) { LOG_WARN("fail to close data source", K(ret), K(i)); } op_ctx->data_sources_.at(i)->~ObIDataSource(); op_ctx->data_sources_.at(i) = NULL; } } } if (OB_FAIL(ObAsyncReceive::inner_close(exec_ctx))) { LOG_WARN("fail to inner close", K(ret)); } return ret; } int ObParallelReceive::create_new_row(ObExecContext& exec_ctx, const ObNewRow& cur_row, ObNewRow& row) const { int ret = OB_SUCCESS; if (NULL == row.cells_) { void* cells_buf = exec_ctx.get_allocator().alloc(cur_row.count_ * sizeof(ObObj)); if (OB_ISNULL(cells_buf)) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("fail to alloc cells buf", K(ret)); } else { row.cells_ = new (cells_buf) ObObj[cur_row.count_]; row.count_ = cur_row.count_; row.projector_ = cur_row.projector_; row.projector_size_ = cur_row.projector_size_; } } return ret; } ObFifoReceiveV2::ObFifoReceiveV2(common::ObIAllocator& alloc) : ObSerialReceive(alloc) {} ObFifoReceiveV2::~ObFifoReceiveV2() {} int ObFifoReceiveV2::create_op_ctx(ObExecContext& exec_ctx, ObAsyncReceiveCtx*& op_ctx) const { return CREATE_PHY_OPERATOR_CTX(ObFifoReceiveCtx, exec_ctx, get_id(), get_type(), op_ctx); } ObTaskOrderReceive::ObTaskComparer::ObTaskComparer() {} ObTaskOrderReceive::ObTaskComparer::~ObTaskComparer() {} bool ObTaskOrderReceive::ObTaskComparer::operator()(const ObTaskResult& task1, const ObTaskResult& task2) { return task1.get_task_id() > task2.get_task_id(); } ObTaskOrderReceive::ObTaskOrderReceiveCtx::ObTaskOrderReceiveCtx(ObExecContext& exec_ctx) : ObSerialReceiveCtx(exec_ctx), task_results_(), task_comparer_(), cur_task_id_(0) {} ObTaskOrderReceive::ObTaskOrderReceiveCtx::~ObTaskOrderReceiveCtx() {} void ObTaskOrderReceive::ObTaskOrderReceiveCtx::destroy() { task_results_.~ObSEArray(); ObSerialReceiveCtx::destroy(); } ObTaskOrderReceive::ObTaskOrderReceive(common::ObIAllocator& alloc) : ObSerialReceive(alloc) {} ObTaskOrderReceive::~ObTaskOrderReceive() {} int ObTaskOrderReceive::create_op_ctx(ObExecContext& exec_ctx, ObAsyncReceiveCtx*& op_ctx) const { return CREATE_PHY_OPERATOR_CTX(ObTaskOrderReceiveCtx, exec_ctx, get_id(), get_type(), op_ctx); } int ObTaskOrderReceive::get_next_task_result(ObAsyncReceiveCtx& receive_ctx, ObTaskResult& task_result) const { int ret = OB_SUCCESS; ObTaskOrderReceiveCtx& op_ctx = static_cast(receive_ctx); if (OB_ISNULL(op_ctx.task_result_iter_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("task result iter is NULL", K(ret)); } else if (ObTaskResultIter::IT_ROOT == op_ctx.task_result_iter_->get_iter_type()) { if (OB_FAIL(get_next_task_result_root(receive_ctx, task_result))) { LOG_WARN("fail to get next task result for root", K(ret)); } } else if (ObTaskResultIter::IT_DISTRIBUTED == op_ctx.task_result_iter_->get_iter_type()) { if (OB_FAIL(get_next_task_result_distributed(receive_ctx, task_result))) { LOG_WARN("fail to get next task result for distributed", K(ret)); } } else { ret = OB_ERR_UNEXPECTED; LOG_WARN("invalid task result iter type", K(ret), "iter_type", op_ctx.task_result_iter_->get_iter_type()); } return ret; } int ObTaskOrderReceive::get_next_task_result_root(ObAsyncReceiveCtx& receive_ctx, ObTaskResult& task_result) const { int ret = OB_SUCCESS; ObTaskOrderReceiveCtx& op_ctx = static_cast(receive_ctx); if (OB_ISNULL(op_ctx.task_result_iter_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("task result iter is NULL", K(ret)); } else { common::ObIArray& task_results = op_ctx.task_results_; task_result.reset(); while (OB_SUCC(ret)) { if (task_results.count() > 0 && op_ctx.cur_task_id_ == task_results.at(0).get_task_id()) { ObTaskResult* first_task = &task_results.at(0); std::pop_heap(first_task, first_task + task_results.count(), op_ctx.task_comparer_); if (OB_FAIL(task_results.pop_back(task_result))) { LOG_WARN("fail to pop back task result", K(ret)); } } else { while (OB_SUCC(ret) && op_ctx.cur_task_id_ != task_result.get_task_id()) { if (OB_FAIL(op_ctx.task_result_iter_->get_next_task_result(task_result))) { if (OB_ITER_END != ret) { LOG_WARN("fail to get next task result", K(ret)); } } else if (op_ctx.cur_task_id_ == task_result.get_task_id()) { // nothing. } else if (OB_FAIL(task_results.push_back(task_result))) { LOG_WARN("fail to push back task result", K(ret)); } else { ObTaskResult* first_task = &task_results.at(0); std::push_heap(first_task, first_task + task_results.count(), op_ctx.task_comparer_); task_result.reset(); } } } if (OB_SUCC(ret)) { // now we get the task result with cur_task_id. if (op_ctx.cur_task_id_ != task_result.get_task_id()) { ret = OB_ERR_UNEXPECTED; LOG_WARN( "task id is not expected", K(ret), "expect", op_ctx.cur_task_id_, "actual", task_result.get_task_id()); } else { op_ctx.cur_task_id_++; if (task_result.has_empty_data()) { task_result.reset(); } else { break; } } } } } return ret; } int ObTaskOrderReceive::get_next_task_result_distributed( ObAsyncReceiveCtx& receive_ctx, ObTaskResult& task_result) const { int ret = OB_SUCCESS; ObTaskOrderReceiveCtx& op_ctx = static_cast(receive_ctx); common::ObIArray& task_results = op_ctx.task_results_; if (0 == task_results.count()) { if (OB_ISNULL(op_ctx.task_result_iter_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("task result iter is NULL", K(ret)); } else { while (OB_SUCC(ret)) { if (OB_FAIL(op_ctx.task_result_iter_->get_next_task_result(task_result))) { if (OB_ITER_END != ret) { LOG_WARN("fail to get next task result", K(ret)); } } else if (OB_FAIL(task_results.push_back(task_result))) { LOG_WARN("fail to push back task result", K(ret)); } else { ObTaskResult* first_task = &task_results.at(0); std::push_heap(first_task, first_task + task_results.count(), op_ctx.task_comparer_); task_result.reset(); } } if (OB_ITER_END == ret) { ret = OB_SUCCESS; } } } if (OB_SUCC(ret)) { task_result.reset(); while (task_results.count() > 0) { ObTaskResult* first_task = &task_results.at(0); std::pop_heap(first_task, first_task + task_results.count(), op_ctx.task_comparer_); if (OB_FAIL(task_results.pop_back(task_result))) { LOG_WARN("fail to pop back task result", K(ret)); } else if (task_result.has_empty_data()) { task_result.reset(); } else { break; } } if (!task_result.is_valid()) { ret = OB_ITER_END; } } return ret; } ObMergeSortReceive::ObRowComparer::ObRowComparer() : columns_(NULL), rows_(NULL), ret_(OB_SUCCESS) {} ObMergeSortReceive::ObRowComparer::~ObRowComparer() {} void ObMergeSortReceive::ObRowComparer::init( const common::ObIArray& columns, const common::ObIArray& rows) { columns_ = &columns; rows_ = &rows; } bool ObMergeSortReceive::ObRowComparer::operator()(int64_t row_idx1, int64_t row_idx2) { int& ret = ret_; int cmp = 0; bool cmp_ret = false; if (OB_FAIL(ret)) { // do nothing if we already have an error, // so we can finish the sort process ASAP. } else if (OB_ISNULL(columns_) || OB_ISNULL(rows_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("columns or rows is NULL", K(ret), K_(columns), K_(rows)); } else if (OB_UNLIKELY(!(0 <= row_idx1 && row_idx1 < rows_->count() && 0 <= row_idx2 && row_idx2 < rows_->count()))) { ret = OB_INDEX_OUT_OF_RANGE; LOG_WARN("row idx out of range", K(ret), K(row_idx1), K(row_idx2), K(rows_->count())); } else { const ObNewRow& row1 = rows_->at(row_idx1); const ObNewRow& row2 = rows_->at(row_idx2); for (int64_t i = 0; OB_SUCC(ret) && 0 == cmp && i < columns_->count(); i++) { int64_t col_idx = columns_->at(i).index_; if (OB_UNLIKELY(!(0 <= col_idx && col_idx < row1.count_ && col_idx < row2.count_))) { ret = OB_INDEX_OUT_OF_RANGE; LOG_WARN("row idx out of range", K(ret), K(col_idx), K(row1.count_), K(row2.count_)); } else { cmp = row1.cells_[col_idx].compare(row2.cells_[col_idx], columns_->at(i).cs_type_); if (cmp < 0) { cmp_ret = !columns_->at(i).is_ascending(); } else if (cmp > 0) { cmp_ret = columns_->at(i).is_ascending(); } } } } return cmp_ret; } ObMergeSortReceive::ObMergeSortReceiveCtx::ObMergeSortReceiveCtx(ObExecContext& exec_ctx) : ObParallelReceiveCtx(exec_ctx), row_comparer_(), last_row_idx_(-1) {} ObMergeSortReceive::ObMergeSortReceiveCtx::~ObMergeSortReceiveCtx() {} ObMergeSortReceive::ObMergeSortReceive(common::ObIAllocator& alloc) : ObParallelReceive(alloc), ObSortableTrait(alloc) {} ObMergeSortReceive::~ObMergeSortReceive() {} int ObMergeSortReceive::create_op_ctx(ObExecContext& exec_ctx, ObAsyncReceiveCtx*& op_ctx) const { int ret = OB_SUCCESS; ObMergeSortReceiveCtx* receive_ctx = NULL; if (OB_FAIL(CREATE_PHY_OPERATOR_CTX(ObMergeSortReceiveCtx, exec_ctx, get_id(), get_type(), receive_ctx))) { LOG_WARN("fail to create merge sort receive ctx", K(ret)); } else if (OB_ISNULL(receive_ctx)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("fail to create merge sort receive ctx", K(ret)); } else { receive_ctx->row_comparer_.init(sort_columns_, receive_ctx->child_rows_); op_ctx = receive_ctx; } return ret; } int ObMergeSortReceive::inner_get_next_row(ObExecContext& exec_ctx, const common::ObNewRow*& row) const { int ret = OB_SUCCESS; ObMergeSortReceiveCtx* op_ctx = GET_PHY_OPERATOR_CTX(ObMergeSortReceiveCtx, exec_ctx, get_id()); if (OB_ISNULL(op_ctx)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("receive ctx is NULL", K(ret)); } else if (op_ctx->iter_end_) { ret = OB_ITER_END; } else if (0 == sort_columns_.count()) { ret = OB_ERR_UNEXPECTED; LOG_WARN("sort columns count is 0", K(ret)); } else { ObIArray& data_sources = op_ctx->data_sources_; ObIArray& child_rows = op_ctx->child_rows_; ObIArray& row_idxs = op_ctx->row_idxs_; int64_t& last_row_idx = op_ctx->last_row_idx_; if (0 <= last_row_idx && last_row_idx < data_sources.count() && last_row_idx < child_rows.count()) { if (OB_ISNULL(data_sources.at(last_row_idx))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("data source is NULL", K(ret), K(last_row_idx)); } else if (OB_FAIL(data_sources.at(last_row_idx)->get_next_row(child_rows.at(last_row_idx)))) { if (OB_ITER_END != ret) { LOG_WARN("fail to get next row", K(ret)); } else if (last_row_idx != row_idxs.at(row_idxs.count() - 1)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("last pop idx is not equal to the last row idx", K(ret)); } else { row_idxs.pop_back(); if (row_idxs.count() > 0) { ret = OB_SUCCESS; } else { op_ctx->iter_end_ = true; } } } else { int64_t* first_row_idx = &row_idxs.at(0); std::push_heap(first_row_idx, first_row_idx + row_idxs.count(), op_ctx->row_comparer_); if (OB_FAIL(op_ctx->row_comparer_.get_ret())) { LOG_WARN("fail to compare row", K(ret)); } } } else { int64_t* first_row_idx = &row_idxs.at(0); std::make_heap(first_row_idx, first_row_idx + row_idxs.count(), op_ctx->row_comparer_); if (OB_FAIL(op_ctx->row_comparer_.get_ret())) { LOG_WARN("fail to compare row", K(ret)); } } if (OB_SUCC(ret)) { int64_t* first_row_idx = &row_idxs.at(0); std::pop_heap(first_row_idx, first_row_idx + row_idxs.count(), op_ctx->row_comparer_); last_row_idx = row_idxs.at(row_idxs.count() - 1); if (OB_FAIL(op_ctx->row_comparer_.get_ret())) { LOG_WARN("fail to compare", K(ret)); } else if (OB_UNLIKELY(!(0 <= last_row_idx && last_row_idx < child_rows.count()))) { ret = OB_INDEX_OUT_OF_RANGE; LOG_WARN("last row idx is out of range", K(ret), K(last_row_idx), K(child_rows.count())); } else { row = &child_rows.at(last_row_idx); } } } return ret; } OB_SERIALIZE_MEMBER((ObMergeSortReceive, ObParallelReceive), sort_columns_); // // ///////////////////// ObFifoReceiveCtx /////////////////////// // // ObFifoReceive::ObFifoReceiveCtx::ObFifoReceiveCtx(ObExecContext& ctx) : ObReceiveCtx(ctx), found_rows_(0), stream_handler_(ObModIds::OB_SQL_EXECUTOR), old_stream_handler_(ObModIds::OB_SQL_EXECUTOR), cur_scanner_(ObModIds::OB_SQL_EXECUTOR_SMALL_INTERM_RESULT_SCANNER), cur_scanner_iter_(), scheduler_holder_(), iter_has_started_(false), iter_end_(false), allocator_(ObModIds::OB_SQL_EXECUTOR), waiting_finish_tasks_(allocator_), last_pull_task_id_(OB_INVALID_ID), affected_row_(0), row_i_(NULL), cur_merge_handle_(NULL) {} ObFifoReceive::ObFifoReceiveCtx::~ObFifoReceiveCtx() {} // // ///////////////////// ObFifoReceiveInput /////////////////////// // // ObPhyOperatorType ObFifoReceiveInput::get_phy_op_type() const { return PHY_FIFO_RECEIVE; } OB_SERIALIZE_MEMBER((ObFifoReceiveInput, ObReceiveInput)); // // ///////////////////// ObFifoReceive /////////////////////// // // ObFifoReceive::ObFifoReceive(common::ObIAllocator& alloc) : ObReceive(alloc), ObSortableTrait(alloc) {} ObFifoReceive::~ObFifoReceive() {} int ObFifoReceive::inner_open(ObExecContext& ctx) const { // Implementation process: // 1. According to task id, reduce function, child task location you can get the data list to be requested // child_task_list = reduce_function(task_id); // foreach (child_task_list as slice) { // svr = task_locs_.get_loc(slice); // } // 2. Read the result streaming in get_next_row // int ret = OB_SUCCESS; if (OB_FAIL(init_op_ctx(ctx))) { LOG_WARN("initialize operator context failed", K(ret)); } else { if (ctx.get_physical_plan_ctx() != NULL && ctx.get_physical_plan_ctx()->get_phy_plan() != NULL && ctx.get_physical_plan_ctx()->get_phy_plan()->get_stmt_type() == stmt::T_INSERT) { if (OB_FAIL(deal_with_insert(ctx))) { LOG_WARN("deal with insert", K(ret), K(ctx.get_physical_plan_ctx()->get_phy_plan()->get_stmt_type())); } } } return ret; } int ObFifoReceive::inner_get_next_row(ObExecContext& ctx, const common::ObNewRow*& row) const { int ret = OB_SUCCESS; // NG_TRACE(fifo_recv_next_begin); ObFifoReceiveCtx* fifo_receive_ctx = GET_PHY_OPERATOR_CTX(ObFifoReceiveCtx, ctx, get_id()); ObFifoReceiveInput* fifo_receive_input = GET_PHY_OP_INPUT(ObFifoReceiveInput, ctx, get_id()); ObDistributedScheduler* scheduler = NULL; ObTaskExecutorCtx* task_exec_ctx = ctx.get_task_executor_ctx(); if (OB_ISNULL(fifo_receive_ctx) || OB_ISNULL(fifo_receive_input)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("ctx or input is NULL", K(ret), "op_id", get_id(), K(fifo_receive_ctx), K(fifo_receive_input)); } else if (fifo_receive_ctx->iter_end_) { ret = OB_ITER_END; } else if (OB_FAIL(check_status(ctx))) { LOG_WARN("check physical plan status failed", K(ret)); } else if (OB_FAIL(fifo_receive_ctx->scheduler_holder_.get_scheduler(scheduler))) { LOG_WARN("fail to get scheduler from scheduler holder", K(ret)); } else if (OB_FAIL(check_schedule_status(scheduler))) { if (OB_ITER_END != ret) { LOG_WARN("check schecule status failed", K(ret)); } } else if (OB_ISNULL(task_exec_ctx)) { ret = OB_ERR_UNEXPECTED; LOG_ERROR("task exec ctx is NULL", K(ret)); } else if (fifo_receive_ctx && is_merge_sort_ && task_exec_ctx->min_cluster_version_is_valid() && task_exec_ctx->get_min_cluster_version() >= CLUSTER_VERSION_140) { // merge sort if (OB_FAIL(merge_sort_result(ctx, fifo_receive_ctx, fifo_receive_input))) { if (OB_ITER_END == ret) { fifo_receive_ctx->iter_end_ = true; } else { LOG_WARN("merge sort failed", K(ret)); } } else if (OB_ISNULL(fifo_receive_ctx->row_i_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("row_i is null", K(ret)); } else { // if get a row for (int64_t i = 0; i < fifo_receive_ctx->row_i_->count_ && i < fifo_receive_ctx->cur_row_.count_; ++i) { fifo_receive_ctx->cur_row_.cells_[i] = fifo_receive_ctx->row_i_->cells_[i]; } row = &fifo_receive_ctx->cur_row_; // LOG_DEBUG("MERGE SORT GET A ROW SUCC", K(*row), K(*fifo_receive_ctx->row_i_)); } } else { while (true) { if (!fifo_receive_ctx->iter_has_started_) { if (OB_FAIL(fetch_more_result(ctx, fifo_receive_ctx, fifo_receive_input))) { if (OB_UNLIKELY(OB_ITER_END != ret)) { LOG_WARN("fail to fetch more result", K(ret)); } break; } } else if (OB_FAIL(fifo_receive_ctx->cur_scanner_iter_.get_next_row(fifo_receive_ctx->cur_row_))) { if (OB_UNLIKELY(OB_ITER_END != ret)) { LOG_WARN("fail to get next row from receive interm result", K(ret)); break; } else if (fifo_receive_ctx->iter_has_started_) { if (OB_FAIL(fetch_more_result(ctx, fifo_receive_ctx, fifo_receive_input))) { if (OB_UNLIKELY(OB_ITER_END != ret)) { LOG_WARN("fail to fetch more result", K(ret)); } break; } } else { int pre_ret = ret; ret = OB_ERR_UNEXPECTED; LOG_ERROR("unexpected case, BUG!", K(ret), K(pre_ret), K(fifo_receive_ctx->iter_has_started_)); break; } } else { break; } } if (OB_SUCC(ret)) { row = &fifo_receive_ctx->cur_row_; } } if (OB_ITER_END == ret) { if (OB_ISNULL(fifo_receive_ctx)) { LOG_ERROR("ret is OB_ITER_END, but fifo_receive_ctx is NULL", K(ret)); } else { fifo_receive_ctx->iter_end_ = true; } } // NG_TRACE(fifo_recv_next_end); return ret; } struct ObFifoReceive::MergeRowComparer { explicit MergeRowComparer(const ObIArray& sort_columns, int* err) : sort_columns_(sort_columns), err_(err) {} bool operator()(const ObSortRow& sr1, const ObSortRow& sr2) { bool ret = false; int cmp = 0; if (OB_UNLIKELY(OB_SUCCESS != *err_)) { // do nothing if we already have an error, // so we can finish the sort process ASAP. } else if (OB_ISNULL(sr1.row_) || OB_ISNULL(sr2.row_)) { *err_ = OB_BAD_NULL_ERROR; LOG_WARN("row is null", "ret", *err_); } else { ObNewRow* r1 = sr1.row_; ObNewRow* r2 = sr2.row_; for (int64_t i = 0; OB_SUCCESS == *err_ && 0 == cmp && i < sort_columns_.count(); ++i) { int64_t idx = sort_columns_.at(i).index_; if (idx >= r1->get_count() || idx >= r2->get_count()) { *err_ = OB_ERR_UNEXPECTED; LOG_WARN("idx is invalid", K(ret), K(idx), K(r1->get_count()), K(r2->get_count())); } else { cmp = r1->cells_[idx].compare(r2->cells_[idx], sort_columns_.at(i).cs_type_); if (cmp < 0) { ret = !sort_columns_.at(i).is_ascending(); } else if (cmp > 0) { ret = sort_columns_.at(i).is_ascending(); } else { } } } // end for } return ret; } private: const ObIArray& sort_columns_; int* err_; }; int ObFifoReceive::pop_a_row_from_heap(ObFifoReceiveCtx& fifo_receive_ctx, ObSortRow& row) const { int ret = OB_SUCCESS; const ObIArray& sort_column = get_sort_columns(); int err = OB_SUCCESS; int64_t size = fifo_receive_ctx.heap_sort_rows_.count(); if (size > 0) { MergeRowComparer rowcomparer(sort_column, &err); ObSortRow* first_row = &fifo_receive_ctx.heap_sort_rows_.at(0); std::pop_heap(first_row, first_row + size, rowcomparer); if (OB_FAIL(err)) { LOG_WARN("failed to std::pop_heap", K(ret)); } else if (OB_FAIL(fifo_receive_ctx.heap_sort_rows_.pop_back(row))) { LOG_WARN("failed to pop row", K(ret)); } } else { ret = OB_ERR_UNEXPECTED; LOG_WARN("array size is 0", K(ret)); } return ret; } int ObFifoReceive::push_a_row_into_heap(ObFifoReceiveCtx& fifo_receive_ctx, ObSortRow& row) const { int ret = OB_SUCCESS; const ObIArray& sort_column = get_sort_columns(); if (OB_FAIL(fifo_receive_ctx.heap_sort_rows_.push_back(row))) { LOG_WARN("push back row failed", K(ret)); } else { int err = OB_SUCCESS; MergeRowComparer rowcomparer(sort_column, &err); ObSortRow* first_row = &fifo_receive_ctx.heap_sort_rows_.at(0); std::push_heap(first_row, first_row + fifo_receive_ctx.heap_sort_rows_.count(), rowcomparer); if (OB_FAIL(err)) { LOG_WARN("failed to std::push_heap", K(ret)); } } return ret; } int ObFifoReceive::more_get_scanner(ObExecContext& ctx, ObFifoReceiveCtx& fifo_receive_ctx, MergeSortHandle& sort_handler, const ObFifoReceiveInput& fifo_receive_input) const { int ret = OB_SUCCESS; UNUSED(fifo_receive_input); UNUSED(fifo_receive_ctx); ObPhysicalPlanCtx* plan_ctx = NULL; if (OB_ISNULL(plan_ctx = ctx.get_physical_plan_ctx())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("fail to get physical plan ctx", K(ret)); } else { FetchIntermResultStreamHandle& stream_handler = sort_handler.stream_handler_; ObScanner& cur_scanner = sort_handler.curhandler_scanner_; if (stream_handler.get_handle().has_more()) { if (OB_FAIL(stream_handler.reset_result())) { } else if (OB_ISNULL(stream_handler.get_result())) { ret = OB_ERR_UNEXPECTED; LOG_ERROR("succ to alloc result, but result is NULL", K(ret)); } else if (OB_FAIL(stream_handler.get_handle().get_more(*stream_handler.get_result()))) { LOG_WARN("fail get more result", K(ret)); } else if (FALSE_IT(cur_scanner.reset())) { } else if (!cur_scanner.is_inited() && OB_FAIL(cur_scanner.init())) { LOG_WARN("fail to init current scanner", K(ret)); } else if (OB_FAIL(stream_handler.get_result()->to_scanner(cur_scanner))) { LOG_WARN("fail to assign to scanner", K(ret), K(*stream_handler.get_result())); } else { sort_handler.row_iter_ = cur_scanner.begin(); plan_ctx->set_last_insert_id_session(cur_scanner.get_last_insert_id_session()); } } else { // has no more scanners, cur handler is end ret = OB_ITER_END; } } return ret; } int ObFifoReceive::get_row_from_heap(ObFifoReceiveCtx& fifo_receive_ctx) const { int ret = OB_SUCCESS; ObSortRow sort_row; if (OB_FAIL(pop_a_row_from_heap(fifo_receive_ctx, sort_row))) { // get a row from heap LOG_WARN("pop a row from heap failed", K(ret)); } else if (sort_row.pos_ < 0 || sort_row.pos_ >= fifo_receive_ctx.merge_handles_.count()) { ret = OB_ERR_UNEXPECTED; LOG_WARN("sort pos is invalid", K(sort_row.pos_), K(fifo_receive_ctx.merge_handles_.count())); } else { fifo_receive_ctx.cur_merge_handle_ = fifo_receive_ctx.merge_handles_.at(sort_row.pos_); fifo_receive_ctx.row_i_ = sort_row.row_; } return ret; } int ObFifoReceive::get_row_from_scanner(ObExecContext& ctx, ObFifoReceiveCtx& fifo_receive_ctx, MergeSortHandle& sort_handler, const ObFifoReceiveInput& fifo_receive_input) const { int ret = OB_SUCCESS; ObNewRow* row = fifo_receive_ctx.row_i_; ObSortRow sort_row; if (OB_ISNULL(row)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("row is null", K(ret)); } else if (OB_FAIL(sort_handler.row_iter_.get_next_row(*row))) { // get a new row from cur scanner if (OB_UNLIKELY(OB_ITER_END != ret)) { LOG_WARN("fail to get next row from cur stream handle", K(ret)); } else { ret = OB_SUCCESS; // get a new scanner from cur stream handler if (OB_FAIL(more_get_scanner(ctx, fifo_receive_ctx, sort_handler, fifo_receive_input))) { if (OB_UNLIKELY(OB_ITER_END != ret)) { LOG_WARN("get scanner failed", K(ret)); } else if (fifo_receive_ctx.heap_sort_rows_.count() <= 0) { // do nothing, iter_end } else { ret = OB_SUCCESS; // iter_end -> succ, pop a row if (OB_FAIL(get_row_from_heap(fifo_receive_ctx))) { LOG_WARN("get row from heap failed", K(ret)); } } } else { // get a new scanner sort_handler.row_iter_ = sort_handler.curhandler_scanner_.begin(); if (OB_FAIL(get_row_from_scanner(ctx, fifo_receive_ctx, sort_handler, fifo_receive_input))) { LOG_WARN("get row from scanner failed", K(ret)); } } } } else if (0 == fifo_receive_ctx.heap_sort_rows_.count()) { // now,only one partition has data, no need push row into heap, return row fifo_receive_ctx.row_i_ = row; } else { sort_row.row_ = row; sort_row.pos_ = sort_handler.merge_id_; if (OB_FAIL(push_a_row_into_heap(fifo_receive_ctx, sort_row))) { // push cur row LOG_WARN("push a row into heap failed", K(ret)); } else if (OB_FAIL(get_row_from_heap(fifo_receive_ctx))) { // pop heap_top row into -> fifo_ctx.row_i_ LOG_WARN("pop a row from heap failed", K(ret)); } else { // do nothing } } return ret; } int ObFifoReceive::create_new_cur_row(ObExecContext& ctx, const ObNewRow& cur_row, ObNewRow*& row_i) const { int ret = OB_SUCCESS; int64_t obj_size = cur_row.count_ * sizeof(ObObj); void* ptr = NULL; if (OB_ISNULL(row_i = static_cast(ctx.get_allocator().alloc(sizeof(ObNewRow))))) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("allocate memory failed", K(ret)); } else if (OB_ISNULL(ptr = ctx.get_allocator().alloc(obj_size))) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("allocate memory failed", K(ret), K(obj_size)); } else { row_i->cells_ = new (ptr) ObObj[cur_row.count_]; row_i->count_ = cur_row.count_; row_i->projector_ = cur_row.projector_; row_i->projector_size_ = cur_row.projector_size_; } return ret; } int ObFifoReceive::init_row_heap(ObExecContext& ctx, ObFifoReceiveCtx& fifo_receive_ctx) const { int ret = OB_SUCCESS; ObSortRow sort_row; ObNewRow& cur_row = fifo_receive_ctx.child_row_; for (int64_t i = 0; OB_SUCC(ret) && i < fifo_receive_ctx.merge_handles_.count(); ++i) { MergeSortHandle* cur_handler = fifo_receive_ctx.merge_handles_.at(i); ObNewRow* row_i = NULL; if (OB_FAIL(create_new_cur_row(ctx, cur_row, row_i))) { LOG_WARN("alloc cur row failed", K(ret)); } else if (OB_ISNULL(cur_handler) || OB_ISNULL(row_i)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("cur hande or row_i is null", K(ret), K(i), K(row_i)); } else if (OB_FAIL(cur_handler->row_iter_.get_next_row(*row_i))) { // get a row if (OB_ITER_END == ret) { // no row ret = OB_SUCCESS; } else { LOG_WARN("get next row failed", K(ret)); } } else { // set sort_row sort_row.row_ = row_i; sort_row.pos_ = i; if (OB_FAIL(push_a_row_into_heap(fifo_receive_ctx, sort_row))) { // push back sort_row into heap_k LOG_WARN("push a row into heap failed", K(ret)); } } } return ret; } int ObFifoReceive::fetch_a_new_scanner(ObExecContext& ctx, ObFifoReceiveCtx& fifo_receive_ctx, MergeSortHandle& sort_handler, const ObFifoReceiveInput& fifo_receive_input) const { int ret = OB_SUCCESS; ObPhysicalPlanCtx* plan_ctx = NULL; if (OB_ISNULL(plan_ctx = ctx.get_physical_plan_ctx())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("fail to get physical plan ctx", K(ret)); } else { // extract common, get a task_loc ObDistributedScheduler* scheduler = NULL; uint64_t job_id = fifo_receive_input.get_child_job_id(); uint64_t child_op_id = fifo_receive_input.get_child_op_id(); int64_t ts_timeout = plan_ctx->get_timeout_timestamp(); if (OB_FAIL(fifo_receive_ctx.scheduler_holder_.get_scheduler(scheduler))) { LOG_WARN("fail to get scheduler from scheduler holder", K(ret), K(job_id)); } else if (OB_ISNULL(scheduler)) { ret = OB_ERR_UNEXPECTED; LOG_ERROR("scheduler is null", K(ret), K(job_id)); } else { ObTaskResult task_result; bool result_scanner_is_empty = true; while (OB_SUCC(ret) && result_scanner_is_empty) { task_result.reset(); if (OB_FAIL(scheduler->pop_task_result_for_root(ctx, child_op_id, task_result, ts_timeout))) { if (OB_ITER_END != ret) { LOG_WARN("fail to pop task loc for root", K(ret), K(job_id), K(task_result), K(ts_timeout)); } } else if (OB_FAIL(deal_with_task(ctx, fifo_receive_ctx, sort_handler, task_result, result_scanner_is_empty, fifo_receive_input))) { } else { // return scanner iter } } } } return ret; } int ObFifoReceive::merge_sort_result( ObExecContext& ctx, ObFifoReceiveCtx* fifo_receive_ctx, const ObFifoReceiveInput* fifo_receive_input) const { int ret = OB_SUCCESS; if (OB_ISNULL(fifo_receive_ctx) || OB_ISNULL(fifo_receive_input)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("fifo_receive_ctx or fifo_receive_input is null", K(ret), K(fifo_receive_input)); } else if (fifo_receive_ctx->iter_has_started_) { // not first if (OB_ISNULL(fifo_receive_ctx->cur_merge_handle_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("cur merge_handle is null", K(ret)); } else if (OB_FAIL(get_row_from_scanner( ctx, *fifo_receive_ctx, *fifo_receive_ctx->cur_merge_handle_, *fifo_receive_input))) { // from handle get a row if (OB_ITER_END == ret) { // no row, iter end } else { LOG_WARN("get a row from scanner failed", K(ret)); } } } else { // first fetch data from all partitions fifo_receive_ctx->iter_has_started_ = true; while (OB_SUCC(ret)) { MergeSortHandle* sort_handler = NULL; if (OB_ISNULL(sort_handler = static_cast(ctx.get_allocator().alloc(sizeof(MergeSortHandle))))) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("alloca memory for sort handle failed", K(ret), K(sizeof(MergeSortHandle))); } else { new (sort_handler) MergeSortHandle; if (OB_FAIL(fetch_a_new_scanner(ctx, *fifo_receive_ctx, *sort_handler, *fifo_receive_input))) { if (OB_ITER_END == ret) { // =0 -> iter end, no data if (fifo_receive_ctx->merge_handles_.count() > 0) { ret = OB_SUCCESS; } } else { LOG_WARN("first fetch scanners failed", K(ret)); } sort_handler->~MergeSortHandle(); break; // no more handlers,break } else if (OB_FAIL(fifo_receive_ctx->merge_handles_.push_back(sort_handler))) { sort_handler->~MergeSortHandle(); // free LOG_WARN("push back sort handle failed", K(ret)); } else { sort_handler->merge_id_ = fifo_receive_ctx->merge_handles_.count() - 1; sort_handler->row_iter_ = sort_handler->curhandler_scanner_.begin(); } } } if (OB_SUCC(ret) && fifo_receive_ctx->merge_handles_.count() > 0) { if (OB_FAIL(init_row_heap(ctx, *fifo_receive_ctx))) { LOG_WARN("init row heap failed", K(ret)); } else if (OB_FAIL(get_row_from_heap(*fifo_receive_ctx))) { // first get LOG_WARN("get row from heap failed", K(ret)); } else { fifo_receive_ctx->iter_has_started_ = true; } } } return ret; } int ObFifoReceive::deal_with_task(ObExecContext& ctx, ObFifoReceiveCtx& fifo_receive_ctx, MergeSortHandle& sort_handler, ObTaskResult& task_result, bool& result_scanner_is_empty, const ObFifoReceiveInput& fifo_receive_input) const { int ret = OB_SUCCESS; LOG_DEBUG("Got task result", K_(partition_order_specified), K(task_result)); ObSQLSessionInfo* session = ctx.get_my_session(); ObPhysicalPlanCtx* plan_ctx = ctx.get_physical_plan_ctx(); bool has_local_data = false; const ObIArray* slice_events = task_result.get_slice_events(); ObScanner& cur_scanner = sort_handler.curhandler_scanner_; if (OB_ISNULL(session) || OB_ISNULL(plan_ctx)) { ret = OB_ERR_UNEXPECTED; LOG_ERROR("session or plan ctx is NULL", K(ret), K(session), K(plan_ctx)); } else if (OB_ISNULL(slice_events)) { ret = OB_ERR_UNEXPECTED; LOG_ERROR("slice event list is NULL", K(ret)); } else if (OB_UNLIKELY(1 != slice_events->count())) { ret = OB_ERR_UNEXPECTED; LOG_ERROR("slice events count is not 1", K(ret), K(slice_events->count())); } else { const ObSliceEvent& slice_event = slice_events->at(0); // if (OB_ISNULL(slice_event)) { // ret = OB_ERR_UNEXPECTED; // LOG_ERROR("slice event is NULL", K(ret), K(slice_events->count())); // } else { const ObTaskSmallResult& sr = slice_event.get_small_result(); if (sr.has_data()) { // The intermediate results have been brought back in the task event, // so there is no need to go to the remote end to pull the intermediate results // Pull to a scanner and point cur sort_handler.row_iter to it has_local_data = true; if (sr.get_data_len() <= 0) { result_scanner_is_empty = true; } else { int64_t pos = 0; result_scanner_is_empty = false; cur_scanner.reset(); if (!cur_scanner.is_inited() && OB_FAIL(cur_scanner.init())) { LOG_WARN("fail to init current scanner", K(ret), K(sr)); } else if (OB_FAIL(cur_scanner.deserialize(sr.get_data_buf(), sr.get_data_len(), pos))) { LOG_WARN("fail to deserialize small result scanner", K(ret), K(pos), K(sr)); } else { const ObScanner& sr_data = cur_scanner; sort_handler.row_iter_ = sr_data.begin(); fifo_receive_ctx.found_rows_ += sr_data.get_found_rows(); plan_ctx->set_last_insert_id_session(sr_data.get_last_insert_id_session()); if (!(sr_data.is_result_accurate())) { plan_ctx->set_is_result_accurate(sr_data.is_result_accurate()); } } } } // } } if (OB_SUCC(ret) && !has_local_data) { ObExecutorRpcImpl* rpc = NULL; ObSliceID slice_id; slice_id.set_ob_task_id(task_result.get_task_location().get_ob_task_id()); slice_id.set_slice_id(fifo_receive_input.get_pull_slice_id()); if (OB_FAIL(ObTaskExecutorCtxUtil::get_task_executor_rpc(ctx, rpc))) { LOG_WARN("fail to get executor rpc", K(ret)); } else if (OB_ISNULL(rpc)) { ret = OB_ERR_UNEXPECTED; LOG_ERROR("succ to get task executor rpc, but rpc is NULL", K(ret)); } else if (OB_FAIL(sort_handler.stream_handler_.reset_result())) { LOG_WARN("fail to reset and init result", K(ret)); } else if (OB_ISNULL(sort_handler.stream_handler_.get_result())) { ret = OB_ERR_UNEXPECTED; LOG_ERROR("succ to alloc result, but result is NULL", K(ret)); } else { ObExecutorRpcCtx rpc_ctx(session->get_rpc_tenant_id(), plan_ctx->get_timeout_timestamp(), ctx.get_task_exec_ctx().get_min_cluster_version(), &ctx.get_scheduler_thread_ctx().get_scheduler_retry_info_for_update(), ctx.get_my_session(), plan_ctx->is_plain_select_stmt()); if (OB_FAIL(rpc->task_fetch_interm_result( rpc_ctx, slice_id, task_result.get_task_location().get_server(), sort_handler.stream_handler_))) { LOG_WARN("fail fetch result", K(ret), K(slice_id), K(task_result)); } else if (FALSE_IT(cur_scanner.reset())) { } else if (!cur_scanner.is_inited() && OB_FAIL(cur_scanner.init())) { LOG_WARN("fail to init current scanner", K(ret)); } else if (OB_FAIL(sort_handler.stream_handler_.get_result()->to_scanner(cur_scanner))) { LOG_WARN("fail to assign to scanner", K(ret), K(*sort_handler.stream_handler_.get_result())); } else { result_scanner_is_empty = false; sort_handler.row_iter_ = cur_scanner.begin(); fifo_receive_ctx.found_rows_ += cur_scanner.get_found_rows(); plan_ctx->set_last_insert_id_session(cur_scanner.get_last_insert_id_session()); if (!cur_scanner.is_result_accurate()) { plan_ctx->set_is_result_accurate(cur_scanner.is_result_accurate()); } } } } return ret; } int ObFifoReceive::fetch_more_result( ObExecContext& ctx, ObFifoReceiveCtx* fifo_receive_ctx, const ObFifoReceiveInput* fifo_receive_input) const { int ret = OB_SUCCESS; ObTaskExecutorCtx* task_exec_ctx = ctx.get_task_executor_ctx(); if (OB_ISNULL(task_exec_ctx)) { ret = OB_ERR_UNEXPECTED; LOG_ERROR("task exec ctx is NULL", K(ret)); } else { if (task_exec_ctx->min_cluster_version_is_valid() && task_exec_ctx->get_min_cluster_version() >= CLUSTER_VERSION_140) { if (OB_FAIL(new_fetch_more_result(ctx, fifo_receive_ctx, fifo_receive_input))) { if (OB_ITER_END != ret) { LOG_WARN("fail to fetch more result by new function", K(ret)); } } } else { if (OB_FAIL(old_fetch_more_result(ctx, fifo_receive_ctx, fifo_receive_input))) { if (OB_ITER_END != ret) { LOG_WARN("fail to fetch more result by old function", K(ret)); } } } } return ret; } int ObFifoReceive::new_fetch_more_result( ObExecContext& ctx, ObFifoReceiveCtx* fifo_receive_ctx, const ObFifoReceiveInput* fifo_receive_input) const { int ret = OB_SUCCESS; // NG_TRACE(fetch_more_result_begin); ObSQLSessionInfo* session = ctx.get_my_session(); ObPhysicalPlanCtx* plan_ctx = ctx.get_physical_plan_ctx(); if (OB_ISNULL(fifo_receive_ctx) || OB_ISNULL(fifo_receive_input)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("ctx or input is NULL", K(ret), "op_id", get_id(), K(fifo_receive_ctx), K(fifo_receive_input)); } else if (OB_ISNULL(session) || OB_ISNULL(plan_ctx)) { ret = OB_ERR_UNEXPECTED; LOG_ERROR("session or plan ctx is NULL", K(ret), K(session), K(plan_ctx)); } else { FetchIntermResultStreamHandle& stream_handler = fifo_receive_ctx->stream_handler_; if (stream_handler.get_handle().has_more()) { if (OB_FAIL(stream_handler.reset_result())) { LOG_WARN("fail to reset result", K(ret)); } else if (OB_ISNULL(stream_handler.get_result())) { ret = OB_ERR_UNEXPECTED; LOG_ERROR("succ to alloc result, but result is NULL", K(ret)); } else if (OB_FAIL(stream_handler.get_handle().get_more(*stream_handler.get_result()))) { LOG_WARN("fail get more result", K(ret)); } else if (FALSE_IT(fifo_receive_ctx->cur_scanner_.reset())) { } else if (!fifo_receive_ctx->cur_scanner_.is_inited() && OB_FAIL(fifo_receive_ctx->cur_scanner_.init())) { LOG_WARN("fail to init current scanner", K(ret)); } else if (OB_FAIL(stream_handler.get_result()->to_scanner(fifo_receive_ctx->cur_scanner_))) { LOG_WARN("fail to assign to scanner", K(ret), K(*stream_handler.get_result())); } else { fifo_receive_ctx->cur_scanner_iter_ = fifo_receive_ctx->cur_scanner_.begin(); fifo_receive_ctx->iter_has_started_ = true; fifo_receive_ctx->found_rows_ += fifo_receive_ctx->cur_scanner_.get_found_rows(); fifo_receive_ctx->affected_row_ += fifo_receive_ctx->cur_scanner_.get_affected_rows(); plan_ctx->set_last_insert_id_session(fifo_receive_ctx->cur_scanner_.get_last_insert_id_session()); if (!fifo_receive_ctx->cur_scanner_.is_result_accurate()) { plan_ctx->set_is_result_accurate(fifo_receive_ctx->cur_scanner_.is_result_accurate()); } } } else { ObDistributedScheduler* scheduler = NULL; uint64_t job_id = fifo_receive_input->get_child_job_id(); uint64_t child_op_id = fifo_receive_input->get_child_op_id(); int64_t ts_timeout = plan_ctx->get_timeout_timestamp(); if (OB_FAIL(fifo_receive_ctx->scheduler_holder_.get_scheduler(scheduler))) { LOG_WARN("fail to get scheduler from scheduler holder", K(ret), K(job_id)); } else if (OB_ISNULL(scheduler)) { ret = OB_ERR_UNEXPECTED; LOG_ERROR("scheduler is null", K(ret), K(job_id)); } else { ObTaskResult task_result; bool result_scanner_is_empty = true; while (OB_SUCC(ret) && result_scanner_is_empty) { task_result.reset(); // If you want to pull data in the specified partition order, // you only need to ensure the pull order of task_loc here, // That is to ensure that the task_id of task_loc is continuous. if (partition_order_specified_) { // Pull data in the specified partition order bool has_got_task = false; uint64_t expected_pop_task_id = OB_INVALID_ID == fifo_receive_ctx->last_pull_task_id_ ? 0 : fifo_receive_ctx->last_pull_task_id_ + 1; if (fifo_receive_ctx->waiting_finish_tasks_.size() > 0) { ObList::iterator waiting_task_head_iter = fifo_receive_ctx->waiting_finish_tasks_.begin(); if (OB_UNLIKELY(fifo_receive_ctx->waiting_finish_tasks_.end() == waiting_task_head_iter)) { ret = OB_ERR_UNEXPECTED; LOG_ERROR("waiting finish task list size > 0, but begin == end", K(ret)); } else { const ObTaskResult& head_task_result = *waiting_task_head_iter; if (head_task_result.get_task_location().get_task_id() == expected_pop_task_id) { if (OB_FAIL(fifo_receive_ctx->waiting_finish_tasks_.pop_front(task_result))) { LOG_WARN("fail to pop front waiting finish task", K(ret), K(head_task_result)); } else { has_got_task = true; } } else { // The cached task information does not conform to the order, pop in the scheduler has_got_task = false; } } } else { // There is no cache task information, pop in the scheduler has_got_task = false; } if (OB_SUCC(ret) && !has_got_task) { do { task_result.reset(); if (OB_FAIL(scheduler->pop_task_result_for_root(ctx, child_op_id, task_result, ts_timeout))) { if (OB_UNLIKELY(OB_ITER_END != ret)) { LOG_WARN("fail to pop task loc for root", K(ret), K(job_id), K(task_result), K(ts_timeout)); } else if (OB_UNLIKELY(fifo_receive_ctx->waiting_finish_tasks_.size() > 0)) { ret = OB_ERR_UNEXPECTED; LOG_ERROR("waiting task list has still tasks, but pop ret is iter end, bug!", K(ret), K(job_id), K(fifo_receive_ctx->waiting_finish_tasks_.size())); } } else { expected_pop_task_id = OB_INVALID_ID == fifo_receive_ctx->last_pull_task_id_ ? 0 : fifo_receive_ctx->last_pull_task_id_ + 1; if (expected_pop_task_id != task_result.get_task_location().get_task_id()) { // Can't pull it yet, cache it, pay attention to sort by task_id ObList::iterator waiting_task_iter = fifo_receive_ctx->waiting_finish_tasks_.begin(); for (; OB_SUCC(ret) && waiting_task_iter != fifo_receive_ctx->waiting_finish_tasks_.end(); ++waiting_task_iter) { if ((*waiting_task_iter).get_task_location().get_task_id() > task_result.get_task_location().get_task_id()) { // Sort by task_id and insert at this position break; } } if (OB_FAIL(fifo_receive_ctx->waiting_finish_tasks_.insert(waiting_task_iter, task_result))) { LOG_WARN("fail to insert task loc into waiting_finish_tasks_", K(ret), K((*waiting_task_iter)), K(task_result)); } } else { has_got_task = true; } } } while (OB_SUCC(ret) && !has_got_task); } if (OB_SUCC(ret)) { if (OB_UNLIKELY(!has_got_task)) { ret = OB_ERR_UNEXPECTED; LOG_ERROR("ret is OB_SUCCESS, but has not got task", K(ret), K(job_id), K(task_result), K(fifo_receive_ctx->last_pull_task_id_)); } else { fifo_receive_ctx->last_pull_task_id_ = task_result.get_task_location().get_task_id(); } } } else { // Pull data in the specified partition order if (OB_FAIL(scheduler->pop_task_result_for_root(ctx, child_op_id, task_result, ts_timeout))) { if (OB_ITER_END != ret) { LOG_WARN("fail to pop task loc for root", K(ret), K(job_id), K(task_result), K(ts_timeout)); } } } if (OB_FAIL(ret)) { } else { LOG_DEBUG("Get task result", K_(partition_order_specified), K(task_result)); bool has_local_data = false; const ObIArray* slice_events = task_result.get_slice_events(); if (OB_ISNULL(slice_events)) { ret = OB_ERR_UNEXPECTED; LOG_ERROR("slice event list is NULL", K(ret)); } else { if (OB_UNLIKELY(1 != slice_events->count())) { ret = OB_ERR_UNEXPECTED; LOG_ERROR("slice events count is not 1", K(ret), K(slice_events->count())); } else { const ObSliceEvent& slice_event = slice_events->at(0); // if (OB_ISNULL(slice_event)) { // ret = OB_ERR_UNEXPECTED; // LOG_ERROR("slice event is NULL", K(ret), K(slice_events->count())); // } else { const ObTaskSmallResult& sr = slice_event.get_small_result(); if (sr.has_data()) { // The intermediate results have been brought back in the task event, // so there is no need to go to the remote end to pull the intermediate results // Pull to a scanner and point cur sort_handler.row_iter to it has_local_data = true; if (sr.get_data_len() <= 0) { result_scanner_is_empty = true; fifo_receive_ctx->found_rows_ += sr.get_found_rows(); fifo_receive_ctx->affected_row_ += sr.get_affected_rows(); plan_ctx->set_last_insert_id_session(sr.get_last_insert_id()); } else { int64_t pos = 0; result_scanner_is_empty = false; fifo_receive_ctx->cur_scanner_.reset(); if (!fifo_receive_ctx->cur_scanner_.is_inited() && OB_FAIL(fifo_receive_ctx->cur_scanner_.init())) { LOG_WARN("fail to init current scanner", K(ret), K(sr)); } else if (OB_FAIL(fifo_receive_ctx->cur_scanner_.deserialize( sr.get_data_buf(), sr.get_data_len(), pos))) { LOG_WARN("fail to deserialize small result scanner", K(ret), K(pos), K(sr)); } else { const ObScanner& sr_data = fifo_receive_ctx->cur_scanner_; fifo_receive_ctx->cur_scanner_iter_ = sr_data.begin(); fifo_receive_ctx->iter_has_started_ = true; fifo_receive_ctx->found_rows_ += sr_data.get_found_rows(); fifo_receive_ctx->affected_row_ += sr_data.get_affected_rows(); plan_ctx->set_last_insert_id_session(sr_data.get_last_insert_id_session()); if (!(sr_data.is_result_accurate())) { plan_ctx->set_is_result_accurate(sr_data.is_result_accurate()); } } } } // } } } if (OB_SUCC(ret) && !has_local_data) { ObExecutorRpcImpl* rpc = NULL; ObSliceID slice_id; slice_id.set_ob_task_id(task_result.get_task_location().get_ob_task_id()); slice_id.set_slice_id(fifo_receive_input->get_pull_slice_id()); stream_handler.reset(); if (OB_FAIL(ObTaskExecutorCtxUtil::get_task_executor_rpc(ctx, rpc))) { LOG_WARN("fail to get executor rpc", K(ret)); } else if (OB_ISNULL(rpc)) { ret = OB_ERR_UNEXPECTED; LOG_ERROR("succ to get task executor rpc, but rpc is NULL", K(ret)); } else if (OB_FAIL(stream_handler.reset_result())) { LOG_WARN("fail to reset and init result", K(ret)); } else if (OB_ISNULL(stream_handler.get_result())) { ret = OB_ERR_UNEXPECTED; LOG_ERROR("succ to alloc result, but result is NULL", K(ret)); } else { ObExecutorRpcCtx rpc_ctx(session->get_rpc_tenant_id(), plan_ctx->get_timeout_timestamp(), ctx.get_task_exec_ctx().get_min_cluster_version(), &ctx.get_scheduler_thread_ctx().get_scheduler_retry_info_for_update(), ctx.get_my_session(), plan_ctx->is_plain_select_stmt()); if (OB_FAIL(rpc->task_fetch_interm_result( rpc_ctx, slice_id, task_result.get_task_location().get_server(), stream_handler))) { LOG_WARN("fail fetch result", K(ret), K(slice_id), K(task_result)); } else if (FALSE_IT(fifo_receive_ctx->cur_scanner_.reset())) { } else if (!fifo_receive_ctx->cur_scanner_.is_inited() && OB_FAIL(fifo_receive_ctx->cur_scanner_.init())) { LOG_WARN("fail to init current scanner", K(ret)); } else if (OB_FAIL(stream_handler.get_result()->to_scanner(fifo_receive_ctx->cur_scanner_))) { LOG_WARN("fail to assign to scanner", K(ret), K(*stream_handler.get_result())); } else { result_scanner_is_empty = false; fifo_receive_ctx->cur_scanner_iter_ = fifo_receive_ctx->cur_scanner_.begin(); fifo_receive_ctx->iter_has_started_ = true; fifo_receive_ctx->found_rows_ += fifo_receive_ctx->cur_scanner_.get_found_rows(); fifo_receive_ctx->affected_row_ += fifo_receive_ctx->cur_scanner_.get_affected_rows(); plan_ctx->set_last_insert_id_session(fifo_receive_ctx->cur_scanner_.get_last_insert_id_session()); if (!fifo_receive_ctx->cur_scanner_.is_result_accurate()) { plan_ctx->set_is_result_accurate(fifo_receive_ctx->cur_scanner_.is_result_accurate()); } } } } } } } } } return ret; } int ObFifoReceive::old_fetch_more_result( ObExecContext& ctx, ObFifoReceiveCtx* fifo_receive_ctx, const ObFifoReceiveInput* fifo_receive_input) const { int ret = OB_SUCCESS; // NG_TRACE(fetch_more_result_begin); ObSQLSessionInfo* session = ctx.get_my_session(); ObPhysicalPlanCtx* plan_ctx = ctx.get_physical_plan_ctx(); if (OB_ISNULL(fifo_receive_ctx) || OB_ISNULL(fifo_receive_input)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("ctx or input is NULL", K(ret), "op_id", get_id(), K(fifo_receive_ctx), K(fifo_receive_input)); } else if (OB_ISNULL(session) || OB_ISNULL(plan_ctx)) { ret = OB_ERR_UNEXPECTED; LOG_ERROR("session or plan ctx is NULL", K(ret), K(session), K(plan_ctx)); } else { FetchResultStreamHandle& old_stream_handler = fifo_receive_ctx->old_stream_handler_; if (old_stream_handler.get_handle().has_more()) { if (OB_FAIL(old_stream_handler.reset_and_init_result())) { LOG_WARN("fail to reset and init result", K(ret)); } else if (OB_ISNULL(old_stream_handler.get_result())) { ret = OB_ERR_UNEXPECTED; LOG_ERROR("succ to alloc result, but result is NULL", K(ret)); } else if (OB_FAIL(old_stream_handler.get_handle().get_more(*old_stream_handler.get_result()))) { LOG_WARN("fail get more result", K(ret)); } else { fifo_receive_ctx->cur_scanner_iter_ = old_stream_handler.get_result()->begin(); fifo_receive_ctx->iter_has_started_ = true; fifo_receive_ctx->found_rows_ += old_stream_handler.get_result()->get_found_rows(); fifo_receive_ctx->affected_row_ += old_stream_handler.get_result()->get_affected_rows(); plan_ctx->set_last_insert_id_session(old_stream_handler.get_result()->get_last_insert_id_session()); if (!old_stream_handler.get_result()->is_result_accurate()) { plan_ctx->set_is_result_accurate(old_stream_handler.get_result()->is_result_accurate()); } } } else { ObDistributedScheduler* scheduler = NULL; uint64_t job_id = fifo_receive_input->get_child_job_id(); uint64_t child_op_id = fifo_receive_input->get_child_op_id(); int64_t ts_timeout = plan_ctx->get_timeout_timestamp(); if (OB_FAIL(fifo_receive_ctx->scheduler_holder_.get_scheduler(scheduler))) { LOG_WARN("fail to get scheduler from scheduler holder", K(ret), K(job_id)); } else if (OB_ISNULL(scheduler)) { ret = OB_ERR_UNEXPECTED; LOG_ERROR("scheduler is null", K(ret), K(job_id)); } else { ObTaskResult task_result; bool result_scanner_is_empty = true; while (OB_SUCC(ret) && result_scanner_is_empty) { task_result.reset(); // If you want to pull data in the specified partition order, // you only need to ensure the pull order of task_loc here, // That is to ensure that the task_id of task_loc is continuous. if (partition_order_specified_) { // Pull data in the specified partition order bool has_got_task = false; uint64_t expected_pop_task_id = OB_INVALID_ID == fifo_receive_ctx->last_pull_task_id_ ? 0 : fifo_receive_ctx->last_pull_task_id_ + 1; if (fifo_receive_ctx->waiting_finish_tasks_.size() > 0) { ObList::iterator waiting_task_head_iter = fifo_receive_ctx->waiting_finish_tasks_.begin(); if (OB_UNLIKELY(fifo_receive_ctx->waiting_finish_tasks_.end() == waiting_task_head_iter)) { ret = OB_ERR_UNEXPECTED; LOG_ERROR("waiting finish task list size > 0, but begin == end", K(ret)); } else { const ObTaskResult& head_task_result = *waiting_task_head_iter; if (head_task_result.get_task_location().get_task_id() == expected_pop_task_id) { // The cached task information conforms to the order and is directly taken from the cache if (OB_FAIL(fifo_receive_ctx->waiting_finish_tasks_.pop_front(task_result))) { LOG_WARN("fail to pop front waiting finish task", K(ret), K(head_task_result)); } else { has_got_task = true; } } else { // The cached task information does not conform to the order, pop in the scheduler has_got_task = false; } } } else { // There is no cache task information, pop in the scheduler has_got_task = false; } if (OB_SUCC(ret) && !has_got_task) { do { task_result.reset(); if (OB_FAIL(scheduler->pop_task_result_for_root(ctx, child_op_id, task_result, ts_timeout))) { if (OB_UNLIKELY(OB_ITER_END != ret)) { LOG_WARN("fail to pop task loc for root", K(ret), K(job_id), K(task_result), K(ts_timeout)); } else if (OB_UNLIKELY(fifo_receive_ctx->waiting_finish_tasks_.size() > 0)) { ret = OB_ERR_UNEXPECTED; LOG_ERROR("waiting task list has still tasks, but pop ret is iter end, bug!", K(ret), K(job_id), K(fifo_receive_ctx->waiting_finish_tasks_.size())); } } else { expected_pop_task_id = OB_INVALID_ID == fifo_receive_ctx->last_pull_task_id_ ? 0 : fifo_receive_ctx->last_pull_task_id_ + 1; if (expected_pop_task_id != task_result.get_task_location().get_task_id()) { // Can't pull it yet, cache it, pay attention to sort by task_id ObList::iterator waiting_task_iter = fifo_receive_ctx->waiting_finish_tasks_.begin(); for (; OB_SUCC(ret) && waiting_task_iter != fifo_receive_ctx->waiting_finish_tasks_.end(); ++waiting_task_iter) { if ((*waiting_task_iter).get_task_location().get_task_id() > task_result.get_task_location().get_task_id()) { // Sort by task_id and insert at this position break; } } if (OB_FAIL(fifo_receive_ctx->waiting_finish_tasks_.insert(waiting_task_iter, task_result))) { LOG_WARN("fail to insert task loc into waiting_finish_tasks_", K(ret), K((*waiting_task_iter)), K(task_result)); } } else { has_got_task = true; } } } while (OB_SUCC(ret) && !has_got_task); } if (OB_SUCC(ret)) { if (OB_UNLIKELY(!has_got_task)) { ret = OB_ERR_UNEXPECTED; LOG_ERROR("ret is OB_SUCCESS, but has not got task", K(ret), K(job_id), K(task_result), K(fifo_receive_ctx->last_pull_task_id_)); } else { fifo_receive_ctx->last_pull_task_id_ = task_result.get_task_location().get_task_id(); } } } else { // Pull data in the specified partition order if (OB_FAIL(scheduler->pop_task_result_for_root(ctx, child_op_id, task_result, ts_timeout))) { if (OB_ITER_END != ret) { LOG_WARN("fail to pop task loc for root", K(ret), K(job_id), K(task_result), K(ts_timeout)); } } } if (OB_FAIL(ret)) { } else { LOG_DEBUG("Get task result", K_(partition_order_specified), K(task_result)); ObExecutorRpcImpl* rpc = NULL; ObSliceID slice_id; slice_id.set_ob_task_id(task_result.get_task_location().get_ob_task_id()); slice_id.set_slice_id(fifo_receive_input->get_pull_slice_id()); old_stream_handler.reset(); if (OB_FAIL(ObTaskExecutorCtxUtil::get_task_executor_rpc(ctx, rpc))) { LOG_WARN("fail to get executor rpc", K(ret)); } else if (OB_ISNULL(rpc)) { ret = OB_ERR_UNEXPECTED; LOG_ERROR("succ to get task executor rpc, but rpc is NULL", K(ret)); } else if (OB_FAIL(old_stream_handler.reset_and_init_result())) { LOG_WARN("fail to reset and init result", K(ret)); } else if (OB_ISNULL(old_stream_handler.get_result())) { ret = OB_ERR_UNEXPECTED; LOG_ERROR("succ to alloc result, but result is NULL", K(ret)); } else { ObExecutorRpcCtx rpc_ctx(session->get_rpc_tenant_id(), plan_ctx->get_timeout_timestamp(), ctx.get_task_exec_ctx().get_min_cluster_version(), &ctx.get_scheduler_thread_ctx().get_scheduler_retry_info_for_update(), ctx.get_my_session(), plan_ctx->is_plain_select_stmt()); if (OB_FAIL(rpc->task_fetch_result( rpc_ctx, slice_id, task_result.get_task_location().get_server(), old_stream_handler))) { LOG_WARN("fail fetch result", K(ret), K(slice_id), K(task_result)); } else { result_scanner_is_empty = false; fifo_receive_ctx->cur_scanner_iter_ = old_stream_handler.get_result()->begin(); fifo_receive_ctx->iter_has_started_ = true; fifo_receive_ctx->found_rows_ += old_stream_handler.get_result()->get_found_rows(); fifo_receive_ctx->affected_row_ += old_stream_handler.get_result()->get_affected_rows(); plan_ctx->set_last_insert_id_session(old_stream_handler.get_result()->get_last_insert_id_session()); if (!old_stream_handler.get_result()->is_result_accurate()) { plan_ctx->set_is_result_accurate(old_stream_handler.get_result()->is_result_accurate()); } } } } } } } } return ret; } int ObFifoReceive::check_schedule_status(ObDistributedScheduler* scheduler) const { int ret = OB_SUCCESS; if (OB_ISNULL(scheduler)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("scheculer is NULL", K(ret)); } else if (OB_FAIL(scheduler->get_schedule_ret())) { LOG_WARN("schecule error", K(ret)); } return ret; } int ObFifoReceive::inner_close(ObExecContext& ctx) const { int ret = OB_SUCCESS; // ObSQLSessionInfo *my_session = NULL; ObPhysicalPlanCtx* plan_ctx = ctx.get_physical_plan_ctx(); ObFifoReceiveCtx* fifo_receive_ctx = GET_PHY_OPERATOR_CTX(ObFifoReceiveCtx, ctx, get_id()); if (OB_ISNULL(fifo_receive_ctx) || OB_ISNULL(plan_ctx)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("ctx is NULL", K(ret), "op_id", get_id(), K(fifo_receive_ctx), K(plan_ctx)); } else { plan_ctx->set_found_rows(plan_ctx->get_found_rows() + fifo_receive_ctx->found_rows_); FetchIntermResultStreamHandle& stream_handler = fifo_receive_ctx->stream_handler_; if (stream_handler.get_handle().has_more()) { if (OB_FAIL(stream_handler.get_handle().abort())) { LOG_WARN("abort failed", K(ret)); } } FetchResultStreamHandle& old_stream_handler = fifo_receive_ctx->old_stream_handler_; if (old_stream_handler.get_handle().has_more()) { if (OB_FAIL(old_stream_handler.get_handle().abort())) { LOG_WARN("abort failed", K(ret)); } } } // Release the scheduler's lock here if (OB_ISNULL(fifo_receive_ctx)) { // It is possible to call close when the context does not have init, so you cannot print ERROR LOG_WARN("fifo_receive_ctx is NULL", K(ret)); } else { fifo_receive_ctx->scheduler_holder_.reset(); } return ret; } int ObFifoReceive::init_op_ctx(ObExecContext& ctx) const { int ret = OB_SUCCESS; ObPhyOperatorCtx* op_ctx = NULL; ObDistributedSchedulerManager* scheduler_manager = ObDistributedSchedulerManager::get_instance(); if (OB_FAIL(CREATE_PHY_OPERATOR_CTX(ObFifoReceiveCtx, ctx, get_id(), get_type(), op_ctx))) { LOG_WARN("create physical operator context failed", K(ret)); } else if (OB_FAIL(init_cur_row(*op_ctx, true))) { LOG_WARN("create current row failed", K(ret)); } else if (OB_ISNULL(scheduler_manager)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("get ObDistributedSchedulerManager instance failed", K(ret)); } else { ObFifoReceiveCtx* receive_ctx = static_cast(op_ctx); // this scheduler is allocated and freed in root thread, see callers of // alloc_scheduler() and free_scheduler(), so here we can keep this pointer safe. if (OB_FAIL(scheduler_manager->get_scheduler(ctx.get_execution_id(), receive_ctx->scheduler_holder_))) { LOG_WARN("get scheduler failed", K(ret)); } else if (OB_ISNULL(child_op_)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("child op is null", K(ret)); } else if (OB_FAIL(receive_ctx->alloc_row_cells(child_op_->get_column_count(), receive_ctx->child_row_))) { LOG_WARN("failed to create cur left row ", K(ret)); } else { receive_ctx->child_row_.projector_ = const_cast(child_op_->get_projector()); receive_ctx->child_row_.projector_size_ = child_op_->get_projector_size(); } } return ret; } int ObFifoReceive::create_operator_input(ObExecContext& ctx) const { int ret = OB_SUCCESS; ObIPhyOperatorInput* input = NULL; if (OB_FAIL(CREATE_PHY_OP_INPUT(ObFifoReceiveInput, ctx, get_id(), get_type(), input))) { LOG_WARN("fail to create fifo receive input", K(ret), "op_id", get_type()); } UNUSED(input); return ret; } int ObFifoReceive::rescan(ObExecContext& ctx) const { // Do not support distributed rescan operations on remote operators UNUSED(ctx); int ret = OB_NOT_SUPPORTED; LOG_USER_ERROR(OB_NOT_SUPPORTED, "Distributed rescan"); return ret; } int ObFifoReceive::deal_with_insert(ObExecContext& ctx) const { int ret = OB_SUCCESS; ObFifoReceiveCtx* fifo_receive_ctx = GET_PHY_OPERATOR_CTX(ObFifoReceiveCtx, ctx, get_id()); ObFifoReceiveInput* fifo_receive_input = GET_PHY_OP_INPUT(ObFifoReceiveInput, ctx, get_id()); ObDistributedScheduler* scheduler = NULL; ObPhysicalPlanCtx* plan_ctx = NULL; if (OB_ISNULL(fifo_receive_ctx) || OB_ISNULL(fifo_receive_input)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("ctx or input is NULL", K(ret), "op_id", get_id(), K(fifo_receive_ctx), K(fifo_receive_input)); } else if (OB_FAIL(check_status(ctx))) { LOG_WARN("check physical plan status failed", K(ret)); } else if (OB_FAIL(fifo_receive_ctx->scheduler_holder_.get_scheduler(scheduler))) { LOG_WARN("fail to get scheduler from scheduler holder", K(ret)); } else if (OB_FAIL(check_schedule_status(scheduler))) { if (OB_ITER_END != ret) { LOG_WARN("check schecule status failed", K(ret)); } } else if (OB_ISNULL(plan_ctx = ctx.get_physical_plan_ctx())) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected error. plan ctx is null", K(ret)); } else { fifo_receive_ctx->iter_has_started_ = true; while (OB_SUCC(ret)) { if (OB_FAIL(fetch_more_result(ctx, fifo_receive_ctx, fifo_receive_input))) { if (OB_UNLIKELY(OB_ITER_END != ret)) { LOG_WARN("fail to fetch more result", K(ret)); } break; } } } if (OB_ITER_END == ret) { if (OB_ISNULL(fifo_receive_ctx)) { ret = OB_ERR_UNEXPECTED; LOG_ERROR("ret is OB_ITER_END, but fifo_receive_ctx is NULL", K(ret)); } else { if (need_set_affected_row_) { plan_ctx->set_affected_rows(plan_ctx->get_affected_rows() + fifo_receive_ctx->affected_row_); } fifo_receive_ctx->iter_end_ = true; ret = OB_SUCCESS; } } return ret; } } // namespace sql } // namespace oceanbase