/** * 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/engine/px/ob_px_util.h" #include "sql/executor/ob_slice_calc.h" #include "sql/executor/ob_range_hash_key_getter.h" #include "sql/engine/ob_exec_context.h" #include "sql/engine/expr/ob_expr_calc_partition_id.h" #include "share/schema/ob_table_schema.h" #include "common/row/ob_row.h" #include "lib/ob_define.h" #include "share/schema/ob_part_mgr_util.h" using namespace oceanbase::sql; using namespace oceanbase::common; using namespace oceanbase::share; using namespace oceanbase::share::schema; int ObSliceIdxCalc::get_slice_indexes(const common::ObNewRow& row, SliceIdxArray& slice_idx_array) { int ret = OB_SUCCESS; if (OB_UNLIKELY(slice_idx_array.count() != 1)) { slice_idx_array.reuse(); if (OB_FAIL(slice_idx_array.push_back(0))) { LOG_WARN("array push back failed", K(ret)); } } if (OB_SUCC(ret)) { ret = get_slice_idx(row, slice_idx_array.at(0)); } return ret; } int ObSliceIdxCalc::get_slice_indexes( const ObIArray& exprs, ObEvalCtx& eval_ctx, SliceIdxArray& slice_idx_array) { int ret = OB_SUCCESS; if (OB_UNLIKELY(slice_idx_array.count() != 1)) { slice_idx_array.reuse(); if (OB_FAIL(slice_idx_array.push_back(0))) { LOG_WARN("array push back failed", K(ret)); } } if (OB_SUCC(ret)) { ret = get_slice_idx(exprs, eval_ctx, slice_idx_array.at(0)); } return ret; } int ObSliceIdxCalc::get_previous_row_partition_id(ObObj& partition_id) { int ret = OB_NOT_SUPPORTED; UNUSED(partition_id); return ret; } int ObRepartSliceIdxCalc::get_slice_idx(const common::ObNewRow& row, int64_t& slice_idx) { int ret = OB_SUCCESS; int64_t part_id = common::OB_INVALID_INDEX; int64_t subpart_id = common::OB_INVALID_INDEX; bool skip_row = false; if (OB_REPARTITION_ONE_SIDE_ONE_LEVEL == repart_type_ || OB_REPARTITION_ONE_SIDE_TWO_LEVEL == repart_type_) { if (OB_FAIL(shuffle_service_.get_partition_ids(exec_ctx_, table_schema_, row, *repart_func_, *repart_sub_func_, *repart_columns_, *repart_sub_columns_, part_id, subpart_id, skip_row))) { LOG_WARN("fail get part idx", K(ret), K(part_id), K(subpart_id)); } else if (ObShuffleService::NO_MATCH_PARTITION == part_id || ObShuffleService::NO_MATCH_PARTITION == subpart_id) { slice_idx = ObSliceIdxCalc::DEFAULT_CHANNEL_IDX_TO_DROP_ROW; } else if (OB_FAIL(ObTransmit::get_slice_idx_by_partition_ids(part_id, subpart_id, table_schema_, slice_idx))) { LOG_WARN("fail get slice idx", K(ret), K(part_id), K(subpart_id)); } } else { ret = OB_ERR_UNEXPECTED; LOG_WARN("get unexpected repartition type", K(ret), K(repart_type_)); } return ret; } int ObRepartSliceIdxCalc::get_partition_id(const common::ObNewRow& row, int64_t& partition_id) { int ret = OB_SUCCESS; int64_t part_idx = common::OB_INVALID_INDEX; int64_t subpart_idx = common::OB_INVALID_INDEX; bool skip_row = false; if (OB_ISNULL(repart_func_) || OB_ISNULL(repart_sub_func_) || OB_ISNULL(repart_columns_) || OB_ISNULL(repart_sub_columns_)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid argument", K(ret)); } else if (OB_FAIL(shuffle_service_.get_partition_ids(exec_ctx_, table_schema_, row, *repart_func_, *repart_sub_func_, *repart_columns_, *repart_sub_columns_, px_repart_ch_map_, part_idx, subpart_idx, skip_row, repart_type_))) { LOG_WARN("fail get part idx", K(ret), K(part_idx), K(subpart_idx)); } else if (ObShuffleService::NO_MATCH_PARTITION == part_idx || ObShuffleService::NO_MATCH_PARTITION == subpart_idx) { partition_id = ObSliceIdxCalc::DEFAULT_CHANNEL_IDX_TO_DROP_ROW; } else { partition_id = generate_phy_part_id(part_idx, subpart_idx, table_schema_.get_part_level()); partition_id_ = partition_id; } return ret; } int ObRepartSliceIdxCalc::get_slice_idx(const ObIArray& exprs, ObEvalCtx& eval_ctx, int64_t& slice_idx) { int ret = OB_SUCCESS; UNUSED(exprs); int64_t partition_id = 0; int64_t part_idx = common::OB_INVALID_INDEX; int64_t subpart_idx = common::OB_INVALID_INDEX; partition_id_ = -1; if (OB_FAIL(get_partition_id(eval_ctx, partition_id))) { LOG_WARN("fail to get partition id", K(ret)); } else if (ObSliceIdxCalc::DEFAULT_CHANNEL_IDX_TO_DROP_ROW == partition_id) { // do nothing } else if (PARTITION_LEVEL_TWO == table_schema_.get_part_level()) { part_idx = extract_part_idx(partition_id); subpart_idx = extract_subpart_idx(partition_id); } else { part_idx = partition_id; } if (OB_SUCC(ret)) { partition_id_ = partition_id; if (OB_FAIL(ObTransmit::get_slice_idx_by_partition_ids(part_idx, subpart_idx, table_schema_, slice_idx))) { LOG_WARN("fail to get slice idx by ids", K(part_idx), K(subpart_idx), K(table_schema_)); } } return ret; } int ObRepartSliceIdxCalc::get_part_id_by_one_level_sub_ch_map(int64_t& part_id) { int ret = OB_SUCCESS; if (OB_FAIL(ObShuffleService::get_part_id_by_ch_map(px_repart_ch_map_, part_id))) { LOG_WARN("fail get sub part id", K(ret)); } return ret; } int ObRepartSliceIdxCalc::get_sub_part_id_by_one_level_first_ch_map(const int64_t part_id, int64_t& sub_part_id) { int ret = OB_SUCCESS; if (OB_FAIL(ObShuffleService::get_sub_part_id_by_ch_map(px_repart_ch_map_, part_id, sub_part_id))) { LOG_WARN("fail get sub part id", K(part_id), K(ret)); } return ret; } int ObRepartSliceIdxCalc::get_partition_id(ObEvalCtx& eval_ctx, int64_t& partition_id) { int ret = OB_SUCCESS; ObDatum* partition_id_datum = NULL; CalcTypeGuard calc_type_guard(eval_ctx.exec_ctx_); if (OB_REPARTITION_ONE_SIDE_ONE_LEVEL_FIRST == repart_type_) { eval_ctx.exec_ctx_.set_partition_id_calc_type(CALC_IGNORE_SUB_PART); } else if (OB_REPARTITION_ONE_SIDE_ONE_LEVEL_SUB == repart_type_) { int64_t part_id = OB_INVALID_ID; if (OB_FAIL(get_part_id_by_one_level_sub_ch_map(part_id))) { LOG_WARN("fail to get part id by ch map", K(ret)); } else { eval_ctx.exec_ctx_.set_partition_id_calc_type(CALC_IGNORE_FIRST_PART); eval_ctx.exec_ctx_.set_fixed_id(part_id); } } if (OB_FAIL(ret)) { } else if (OB_ISNULL(calc_part_id_expr_)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid argument", K(calc_part_id_expr_), K(ret)); } else if (OB_FAIL(calc_part_id_expr_->eval(eval_ctx, partition_id_datum))) { LOG_WARN("fail to calc part id", K(ret), K(*calc_part_id_expr_)); } else if (ObExprCalcPartitionId::NONE_PARTITION_ID == (partition_id = partition_id_datum->get_int())) { partition_id = ObSliceIdxCalc::DEFAULT_CHANNEL_IDX_TO_DROP_ROW; } else if (OB_REPARTITION_ONE_SIDE_ONE_LEVEL_FIRST == repart_type_) { int64_t part_id = partition_id; int64_t sub_part_id = common::OB_INVALID_ID; if (OB_FAIL(get_sub_part_id_by_one_level_first_ch_map(part_id, sub_part_id))) { LOG_WARN("fail to get part id by ch map", K(ret)); } else { partition_id = generate_phy_part_id(part_id, sub_part_id, PARTITION_LEVEL_TWO); } } else if (OB_REPARTITION_ONE_SIDE_ONE_LEVEL_SUB == repart_type_) { int64_t part_id = eval_ctx.exec_ctx_.get_fixed_id(); int64_t sub_part_id = partition_id; partition_id = generate_phy_part_id(part_id, sub_part_id, PARTITION_LEVEL_TWO); } if (OB_SUCC(ret)) { partition_id_ = partition_id; } LOG_DEBUG("repart partition id", K(partition_id)); return ret; } int ObRepartSliceIdxCalc::get_previous_row_partition_id(ObObj& partition_id) { int ret = OB_SUCCESS; partition_id.set_int(partition_id_); return ret; } int ObSlaveMapRepartIdxCalcBase::init() { int ret = OB_SUCCESS; if (OB_FAIL(ObRepartSliceIdxCalc::init())) { LOG_WARN("fail init base", K(ret)); } // In the case of pkey random, a partition can be processed by all workers on the SQC where it is located, // So one partition_id may correspond to multiple task idx, // Form the mapping relationship between partition_id -> task_idx_list // For example: SQC1 has 3 workers(task1,task2,task3), 2 partitions(p0,p1); // SQC2 has 2 workers (task4, task5), 1 partition (p2); // will form: // p0 : [task1,task2,task3] // p1 : [task1,task2,task3] // p2 : [task4,task5] const ObPxPartChMapArray& part_ch_array = part_ch_info_.part_ch_array_; if (OB_SUCC(ret)) { if (OB_FAIL(part_to_task_array_map_.create(max(1, part_ch_array.count()), ObModIds::OB_SQL_PX))) { LOG_WARN("fail create part to task array map", "count", part_ch_array.count(), K(ret)); } } ARRAY_FOREACH_X(part_ch_array, idx, cnt, OB_SUCC(ret)) { int64_t partition_id = part_ch_array.at(idx).first_; int64_t task_idx = part_ch_array.at(idx).second_; LOG_DEBUG("get one channel relationship", K(idx), K(cnt), "key", partition_id, "val", task_idx); if (OB_ISNULL(part_to_task_array_map_.get(partition_id))) { TaskIdxArray task_idx_array; if (OB_FAIL(part_to_task_array_map_.set_refactored(partition_id, task_idx_array))) { LOG_WARN("push partition id and task idx array to map failed", K(ret), K(partition_id)); } else { LOG_TRACE("add task idx array successfully", K(ret), K(partition_id)); } } const TaskIdxArray* task_idx_array = part_to_task_array_map_.get(partition_id); if (OB_ISNULL(task_idx_array)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("task idx list is null", K(ret), K(partition_id)); } else if (OB_FAIL(const_cast(task_idx_array)->push_back(task_idx))) { LOG_WARN("failed push back task idx to task idx array", K(ret), K(task_idx), K(partition_id)); } else { LOG_TRACE("push task idx to task idx array", K(partition_id), K(task_idx), K(*task_idx_array), K(task_idx_array->count())); } } return ret; } int ObSlaveMapRepartIdxCalcBase::destroy() { int ret = OB_SUCCESS; if (part_to_task_array_map_.created()) { ret = part_to_task_array_map_.destroy(); } int tmp_ret = ObRepartSliceIdxCalc::destroy(); ret = (OB_SUCCESS == ret) ? tmp_ret : ret; return ret; } int ObRepartRandomSliceIdxCalc::init() { return ObSlaveMapRepartIdxCalcBase::init(); } int ObRepartRandomSliceIdxCalc::destroy() { return ObSlaveMapRepartIdxCalcBase::destroy(); } int ObRepartRandomSliceIdxCalc::get_slice_idx(const common::ObNewRow& row, int64_t& slice_idx) { int ret = OB_SUCCESS; int64_t partition_id = OB_INVALID_INDEX; if (part_ch_info_.part_ch_array_.size() <= 0) { ret = OB_NOT_INIT; LOG_WARN("the size of part task channel map is zero", K(ret)); } else if (OB_FAIL(ObRepartSliceIdxCalc::get_partition_id(row, partition_id))) { LOG_WARN("failed to get partition id", K(ret)); } else if (OB_FAIL(get_task_idx_by_partition_id(partition_id, slice_idx))) { if (OB_HASH_NOT_EXIST == ret) { ret = OB_NO_PARTITION_FOR_GIVEN_VALUE; LOG_WARN("can't get the right partition", K(ret), K(partition_id), K(slice_idx)); } } return ret; } int ObRepartRandomSliceIdxCalc::get_slice_idx(const ObIArray& exprs, ObEvalCtx& eval_ctx, int64_t& slice_idx) { int ret = OB_SUCCESS; UNUSED(exprs); int64_t partition_id = OB_INVALID_INDEX; if (part_ch_info_.part_ch_array_.size() <= 0) { ret = OB_NOT_INIT; LOG_WARN("the size of part task channel map is zero", K(ret)); } else if (OB_FAIL(ObRepartSliceIdxCalc::get_partition_id(eval_ctx, partition_id))) { LOG_WARN("failed to get partition id", K(ret)); } else if (OB_FAIL(get_task_idx_by_partition_id(partition_id, slice_idx))) { if (OB_HASH_NOT_EXIST == ret) { ret = OB_NO_PARTITION_FOR_GIVEN_VALUE; LOG_WARN("can't get the right partition", K(ret), K(partition_id), K(slice_idx)); } } return ret; } int ObRepartRandomSliceIdxCalc::get_task_idx_by_partition_id(int64_t partition_id, int64_t& task_idx) { int ret = OB_SUCCESS; if (part_to_task_array_map_.size() <= 0) { ret = OB_NOT_INIT; LOG_WARN("part to task array is not inited", K(ret)); } else { const TaskIdxArray* task_idx_array = part_to_task_array_map_.get(partition_id); if (OB_ISNULL(task_idx_array)) { ret = OB_HASH_NOT_EXIST; // convert to hash error LOG_WARN("the task idx array is null", K(ret), K(partition_id)); } else if (task_idx_array->count() <= 0) { ret = OB_ERR_UNEXPECTED; LOG_WARN("the size of task idx array is zero", K(ret)); } else { static const int64_t min = 0; static const int64_t max = INT64_MAX; int64_t rand_idx = common::ObRandom::rand(min, max) % task_idx_array->count(); task_idx = task_idx_array->at(rand_idx); LOG_TRACE("get task_idx/slice_idx by random way", K(partition_id), K(task_idx)); } } return ret; } int ObAffinitizedRepartSliceIdxCalc::get_slice_idx(const common::ObNewRow& row, int64_t& slice_idx) { int ret = OB_SUCCESS; int64_t partition_id = OB_INVALID_INDEX; if (task_count_ <= 0) { ret = OB_NOT_INIT; LOG_WARN("task_count not inited", K_(task_count), K(ret)); } else if (px_repart_ch_map_.size() <= 0) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid map size, affinity map should not be empty!", K_(task_count), K(ret)); } else if (OB_FAIL(get_partition_id(row, partition_id))) { LOG_WARN("fail to get partition id", K(ret)); } else if (OB_FAIL(px_repart_ch_map_.get_refactored(partition_id, slice_idx))) { if (OB_HASH_NOT_EXIST == ret && unmatch_row_dist_method_ == ObPQDistributeMethod::DROP) { slice_idx = ObSliceIdxCalc::DEFAULT_CHANNEL_IDX_TO_DROP_ROW; ret = OB_SUCCESS; } else if (OB_HASH_NOT_EXIST == ret && unmatch_row_dist_method_ == ObPQDistributeMethod::RANDOM) { slice_idx = round_robin_idx_; round_robin_idx_++; round_robin_idx_ = round_robin_idx_ % task_count_; ret = OB_SUCCESS; } else if (OB_HASH_NOT_EXIST == ret) { ret = OB_NO_PARTITION_FOR_GIVEN_VALUE; LOG_WARN("failed get partition", K(ret), K(partition_id), K(slice_idx)); } else { LOG_WARN("fail get affinitized taskid", K(ret), K(partition_id), K_(task_count), K_(unmatch_row_dist_method)); } } return ret; } int ObAffinitizedRepartSliceIdxCalc::get_slice_idx( const ObIArray& exprs, ObEvalCtx& eval_ctx, int64_t& slice_idx) { int ret = OB_SUCCESS; UNUSED(exprs); int64_t partition_id = OB_INVALID_INDEX; if (task_count_ <= 0) { ret = OB_NOT_INIT; LOG_WARN("task_count not inited", K_(task_count), K(ret)); } else if (px_repart_ch_map_.size() <= 0) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid map size, affinity map should not be empty!", K_(task_count), K(ret)); } else if (OB_FAIL(ObRepartSliceIdxCalc::get_partition_id(eval_ctx, partition_id))) { LOG_WARN("fail to get partition id", K(ret)); } else if (OB_FAIL(px_repart_ch_map_.get_refactored(partition_id, slice_idx))) { if (OB_HASH_NOT_EXIST == ret && unmatch_row_dist_method_ == ObPQDistributeMethod::DROP) { slice_idx = ObSliceIdxCalc::DEFAULT_CHANNEL_IDX_TO_DROP_ROW; ret = OB_SUCCESS; } else if (OB_HASH_NOT_EXIST == ret && unmatch_row_dist_method_ == ObPQDistributeMethod::RANDOM) { slice_idx = round_robin_idx_; round_robin_idx_++; round_robin_idx_ = round_robin_idx_ % task_count_; ret = OB_SUCCESS; } else { LOG_WARN("fail get affinitized taskid", K(ret), K(partition_id), K_(task_count), K_(unmatch_row_dist_method)); } } return ret; } int ObRepartSliceIdxCalc::init() { int ret = OB_SUCCESS; if (px_repart_ch_map_.created()) { ret = OB_INIT_TWICE; LOG_WARN("this map has been init twice", K(ret)); } else if (OB_FAIL(build_repart_ch_map(px_repart_ch_map_))) { LOG_WARN("failed to build affi hash map", K(ret)); } return ret; } int ObRepartSliceIdxCalc::build_repart_ch_map(ObPxPartChMap& affinity_map) { int ret = OB_SUCCESS; const ObPxPartChMapArray& part_ch_array = part_ch_info_.part_ch_array_; if (OB_FAIL(affinity_map.create(max(1, part_ch_array.count()), ObModIds::OB_SQL_PX))) { LOG_WARN("fail create hashmap", "count", part_ch_array.count(), K(ret)); } int64_t partition_id = common::OB_INVALID_INDEX_INT64; ARRAY_FOREACH_X(part_ch_array, idx, cnt, OB_SUCC(ret)) { LOG_DEBUG("map build", K(idx), K(cnt), "key", part_ch_array.at(idx).first_, "val", part_ch_array.at(idx).second_); if (partition_id != part_ch_array.at(idx).first_) { partition_id = part_ch_array.at(idx).first_; if (OB_FAIL(affinity_map.set_refactored(part_ch_array.at(idx).first_, part_ch_array.at(idx).second_))) { LOG_WARN("fail add item to hash map", K(idx), K(cnt), "key", part_ch_array.at(idx).first_, "val", part_ch_array.at(idx).second_, K(ret)); } } else { // skip, same partition id may take more than one entry in part_ch_array. // (e.g slave mapping pkey hash) } } return ret; } int ObSlaveMapBcastIdxCalc::get_slice_indexes(const common::ObNewRow& row, SliceIdxArray& slice_idx_array) { int ret = OB_SUCCESS; int64_t partition_id = common::OB_INVALID_INDEX; slice_idx_array.reuse(); if (OB_FAIL(get_partition_id(row, partition_id))) { LOG_WARN("failed to get_partition_id", K(ret)); } else if (OB_INVALID_INDEX == partition_id) { int64_t drop_idx = ObSliceIdxCalc::DEFAULT_CHANNEL_IDX_TO_DROP_ROW; if (OB_FAIL(slice_idx_array.push_back(drop_idx))) { LOG_WARN("failed to push back slice idx", K(ret)); } } else { const ObPxPartChMapArray& part_ch_array = part_ch_info_.part_ch_array_; ARRAY_FOREACH(part_ch_array, idx) { if (partition_id == part_ch_array.at(idx).first_) { if (OB_FAIL(slice_idx_array.push_back(part_ch_array.at(idx).second_))) { LOG_WARN("failed to push back slice idx", K(ret)); } LOG_DEBUG("find slice id to trans", K(partition_id), K(part_ch_array.at(idx).second_)); } } } return ret; } int ObAllToOneSliceIdxCalc::get_slice_idx(const ObNewRow& row, int64_t& slice_idx) { UNUSED(row); slice_idx = 0; return OB_SUCCESS; } int ObAllToOneSliceIdxCalc::get_slice_idx(const ObIArray& exprs, ObEvalCtx& eval_ctx, int64_t& slice_idx) { UNUSED(exprs); UNUSED(eval_ctx); slice_idx = 0; return OB_SUCCESS; } int ObBc2HostSliceIdCalc::get_slice_indexes(const common::ObNewRow& row, SliceIdxArray& slice_idx_array) { UNUSED(row); int ret = OB_SUCCESS; if (OB_UNLIKELY(slice_idx_array.count() != host_idx_.count())) { slice_idx_array.reuse(); FOREACH_CNT_X(it, host_idx_, OB_SUCC(ret)) { UNUSED(it); if (OB_FAIL(slice_idx_array.push_back(0))) { LOG_WARN("array push back failed", K(ret)); } } } if (OB_SUCC(ret)) { for (int64_t i = 0; i < host_idx_.count(); i++) { auto& hi = host_idx_.at(i); int64_t idx = hi.begin_ + hi.idx_ % (hi.end_ - hi.begin_); slice_idx_array.at(i) = channel_idx_.at(idx); hi.idx_++; } } return ret; } int ObBc2HostSliceIdCalc::get_slice_indexes( const ObIArray& exprs, ObEvalCtx& eval_ctx, SliceIdxArray& slice_idx_array) { UNUSED(exprs); UNUSED(eval_ctx); int ret = OB_SUCCESS; if (OB_UNLIKELY(slice_idx_array.count() != host_idx_.count())) { slice_idx_array.reuse(); FOREACH_CNT_X(it, host_idx_, OB_SUCC(ret)) { UNUSED(it); if (OB_FAIL(slice_idx_array.push_back(0))) { LOG_WARN("array push back failed", K(ret)); } } } if (OB_SUCC(ret)) { for (int64_t i = 0; i < host_idx_.count(); i++) { auto& hi = host_idx_.at(i); int64_t idx = hi.begin_ + hi.idx_ % (hi.end_ - hi.begin_); slice_idx_array.at(i) = channel_idx_.at(idx); hi.idx_++; } } return ret; } int ObRandomSliceIdCalc::get_slice_idx(const common::ObNewRow& row, int64_t& slice_idx) { UNUSED(row); int ret = OB_SUCCESS; if (slice_cnt_ <= 0) { ret = OB_ERR_UNEXPECTED; LOG_WARN("invalid slice count", K(ret), K(slice_cnt_)); } else { slice_idx = idx_ % slice_cnt_; idx_++; } return ret; } int ObRandomSliceIdCalc::get_slice_idx(const ObIArray& exprs, ObEvalCtx& eval_ctx, int64_t& slice_idx) { UNUSED(exprs); UNUSED(eval_ctx); int ret = OB_SUCCESS; if (slice_cnt_ <= 0) { ret = OB_ERR_UNEXPECTED; LOG_WARN("invalid slice count", K(ret), K(slice_cnt_)); } else { slice_idx = idx_ % slice_cnt_; idx_++; } return ret; } int ObBroadcastSliceIdCalc::get_slice_indexes(const common::ObNewRow& row, SliceIdxArray& slice_idx_array) { int ret = OB_SUCCESS; UNUSED(row); slice_idx_array.reuse(); for (int64_t i = 0; OB_SUCC(ret) && i < slice_cnt_; ++i) { if (OB_FAIL(slice_idx_array.push_back(i))) { LOG_WARN("failed to push back i", K(ret)); } } return ret; } int ObBroadcastSliceIdCalc::get_slice_indexes( const ObIArray& exprs, ObEvalCtx& eval_ctx, SliceIdxArray& slice_idx_array) { UNUSED(exprs); UNUSED(eval_ctx); int ret = OB_SUCCESS; slice_idx_array.reuse(); for (int64_t i = 0; OB_SUCC(ret) && i < slice_cnt_; ++i) { if (OB_FAIL(slice_idx_array.push_back(i))) { LOG_WARN("failed to push back i", K(ret)); } } return ret; } uint64_t ObHashSliceIdCalc::obj_hash_value(const ObObj& obj, const ObCollationType cs_type, uint64_t hash_val) { if (ob_is_string_type(obj.get_type())) { hash_val = obj.varchar_hash(cs_type, hash_val); } else { hash_val = obj.hash(hash_val); } return hash_val; } int ObHashSliceIdCalc::calc_hash_value( const ObObj& obj, const ObObjType type, const ObCollationType cs_type, uint64_t& hash_val) { int ret = OB_SUCCESS; if (obj.is_null()) { hash_val = obj.hash(hash_val); } else if (obj.get_type() == type) { hash_val = obj_hash_value(obj, cs_type, hash_val); } else { if (!obj_casted_) { obj_casted_ = true; } EXPR_DEFINE_CAST_CTX(*expr_ctx_, CM_NONE); ObObj buf_obj; const ObObj* res_obj = NULL; if (OB_FAIL(ObObjCaster::to_type(type, cast_ctx, obj, buf_obj, res_obj))) { LOG_WARN("cast object failed", K(ret), K(obj), K(type)); } else if (OB_ISNULL(res_obj)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("cast obj is NULL", K(ret)); } else { hash_val = obj_hash_value(*res_obj, cs_type, hash_val); } } return ret; } int ObHashSliceIdCalc::get_multi_hash_value(const ObNewRow& row, uint64_t& hash_val) { int ret = OB_SUCCESS; if (hash_dist_columns_->empty()) { ret = OB_ERR_UNEXPECTED; LOG_WARN("invalid task count or hash column count", K(ret), K(hash_dist_columns_->count())); } else { if (!dist_exprs_->empty() || obj_casted_) { expr_ctx_->calc_buf_->reset(); expr_ctx_->row_ctx_.reset(); } FOREACH_CNT_X(col, *hash_dist_columns_, OB_SUCC(ret)) { if (OB_INVALID_INDEX == col->expr_idx_) { auto& c = row.get_cell(col->index_); if (OB_FAIL(calc_hash_value(c, col->cmp_type_, col->cs_type_, hash_val))) { LOG_WARN("calc hash value failed", K(ret), K(*col)); } } else { auto expr = dist_exprs_->at(col->expr_idx_); if (NULL == expr) { ret = OB_ERR_UNEXPECTED; LOG_WARN("null sql expression found", K(ret)); } else { ObObj obj; if (OB_FAIL(expr->calc(*expr_ctx_, row, obj))) { LOG_WARN("expression evaluate failed", K(ret), K(row)); } else { if (OB_FAIL(calc_hash_value(obj, col->cmp_type_, col->cs_type_, hash_val))) { LOG_WARN("calc hash value failed", K(ret), K(*col)); } } } } } } return ret; } int ObHashSliceIdCalc::calc_hash_value(ObEvalCtx& eval_ctx, uint64_t& hash_val) { int ret = OB_SUCCESS; ObDatum* datum = nullptr; if (OB_ISNULL(hash_dist_exprs_) || OB_ISNULL(hash_funcs_)) { ret = OB_NOT_INIT; LOG_WARN("hash func and expr not init", K(ret)); } for (int64_t i = 0; i < hash_dist_exprs_->count() && OB_SUCC(ret); ++i) { const ObExpr* dist_expr = hash_dist_exprs_->at(i); if (OB_FAIL(dist_expr->eval(eval_ctx, datum))) { LOG_WARN("failed to eval datum", K(ret)); } else { hash_val = hash_funcs_->at(i).hash_func_(*datum, hash_val); } } return ret; } int ObHashSliceIdCalc::get_slice_idx(const ObNewRow& row, int64_t& slice_idx) { int ret = OB_SUCCESS; uint64_t hash_val = 0; if (OB_FAIL(get_multi_hash_value(row, hash_val))) { LOG_WARN("failed to get hash values", K(ret)); } else { slice_idx = hash_val % task_cnt_; } return ret; } int ObHashSliceIdCalc::get_slice_idx(const ObIArray&, ObEvalCtx& eval_ctx, int64_t& slice_idx) { int ret = OB_SUCCESS; uint64_t hash_val = 0; if (OB_FAIL(calc_hash_value(eval_ctx, hash_val))) { LOG_WARN("fail calc hash value", K(ret)); } else { slice_idx = hash_val % task_cnt_; } return ret; } int ObSlaveMapPkeyHashIdxCalc::init() { int ret = OB_SUCCESS; if (OB_FAIL(ObSlaveMapRepartIdxCalcBase::init())) { LOG_WARN("fail init base repart class", K(ret)); } else if (affi_hash_map_.created()) { ret = OB_INIT_TWICE; LOG_WARN("this map has been init twice", K(ret)); } else if (OB_FAIL(build_affi_hash_map(affi_hash_map_))) { LOG_WARN("failed to build affi hash map", K(ret)); } return ret; } int ObSlaveMapPkeyHashIdxCalc::destroy() { int ret = OB_SUCCESS; if (affi_hash_map_.created()) { ret = affi_hash_map_.destroy(); } int tmp_ret = ObSlaveMapRepartIdxCalcBase::destroy(); ret = (OB_SUCCESS == ret) ? tmp_ret : ret; return ret; } int ObSlaveMapPkeyHashIdxCalc::get_slice_idx(const ObIArray&, ObEvalCtx& eval_ctx, int64_t& slice_idx) { int ret = OB_SUCCESS; int64_t partition_id = OB_INVALID_INDEX; if (part_ch_info_.part_ch_array_.size() <= 0) { ret = OB_NOT_INIT; LOG_WARN("the size of part task channel map is zero", K(ret)); } else if (OB_FAIL(ObRepartSliceIdxCalc::get_partition_id(eval_ctx, partition_id))) { LOG_WARN("failed to get partition id", K(ret)); } else if (OB_FAIL(get_task_idx_by_partition_id(eval_ctx, partition_id, slice_idx))) { if (OB_HASH_NOT_EXIST == ret) { ret = OB_NO_PARTITION_FOR_GIVEN_VALUE; LOG_WARN("can't get the right partition", K(ret), K(partition_id), K(slice_idx)); } } return ret; } int ObSlaveMapPkeyHashIdxCalc::get_task_idx_by_partition_id( ObEvalCtx& eval_ctx, int64_t partition_id, int64_t& task_idx) { int ret = OB_SUCCESS; uint64_t hash_val = 0; if (part_to_task_array_map_.size() <= 0) { ret = OB_NOT_INIT; LOG_WARN("part to task array is not inited", K(ret)); } else { const TaskIdxArray* task_idx_array = part_to_task_array_map_.get(partition_id); if (OB_ISNULL(task_idx_array)) { ret = OB_HASH_NOT_EXIST; // convert to hash error LOG_WARN("the task idx array is null", K(ret), K(partition_id)); } else if (task_idx_array->count() <= 0) { ret = OB_ERR_UNEXPECTED; LOG_WARN("the size of task idx array is zero", K(ret)); } else if (OB_FAIL(calc_hash_value(eval_ctx, hash_val))) { LOG_WARN("fail calc hash value", K(ret)); } else { int64_t hash_idx = hash_val % task_idx_array->count(); task_idx = task_idx_array->at(hash_idx); LOG_TRACE("get task_idx/slice_idx by hash way", K(partition_id), K(hash_val), K(task_idx)); } } return ret; } int ObSlaveMapPkeyHashIdxCalc::get_slice_idx(const common::ObNewRow& row, int64_t& slice_idx) { int ret = OB_SUCCESS; int64_t partition_id = common::OB_INVALID_INDEX; uint64_t hash_val = 0; if (OB_FAIL(ret)) { // do nothing } else if (affi_hash_map_.size() < 1) { ret = OB_NOT_INIT; LOG_WARN("the size of slave map part task channel map is zero", K(ret)); } else if (OB_FAIL(get_multi_hash_value(row, hash_val))) { LOG_WARN("failed to get hash values", K(ret)); } else if (OB_FAIL(ObRepartSliceIdxCalc::get_partition_id(row, partition_id))) { LOG_WARN("failed to get_partition_id", K(ret)); } else if (OB_INVALID_INDEX == partition_id) { slice_idx = ObSliceIdxCalc::DEFAULT_CHANNEL_IDX_TO_DROP_ROW; } else { ObPxPartChMapItem item; const ObPxPartChMapArray& part_ch_array = part_ch_info_.part_ch_array_; if (OB_FAIL(affi_hash_map_.get_refactored(partition_id, item))) { if (OB_HASH_NOT_EXIST == ret) { LOG_WARN("can't get the right partition", K(ret), K(partition_id), K(slice_idx)); ret = OB_NO_PARTITION_FOR_GIVEN_VALUE; } else { LOG_WARN("failed to get item", K(ret)); } } else { int64_t offset = hash_val % (item.second_ - item.first_); slice_idx = part_ch_array.at(item.first_ + offset).second_; LOG_DEBUG("get slice indexs", K(offset), K(item.first_ + offset), K(part_ch_array), K(item), K(slice_idx), K(hash_val), K(partition_id), K(row)); } } return ret; } int ObSlaveMapPkeyHashIdxCalc::build_affi_hash_map(hash::ObHashMap& affi_hash_map) { int ret = OB_SUCCESS; int64_t partition_id = common::OB_INVALID_INDEX_INT64; ObPxPartChMapItem item; const ObPxPartChMapArray& part_ch_array = part_ch_info_.part_ch_array_; if (OB_FAIL(affi_hash_map.create(part_ch_array.count(), common::ObModIds::OB_SQL_PX))) { LOG_WARN("failed to create part ch map", K(ret)); } ARRAY_FOREACH(part_ch_array, idx) { if (common::OB_INVALID_INDEX_INT64 == partition_id) { partition_id = part_ch_array.at(idx).first_; item.first_ = idx; } else if (partition_id != part_ch_array.at(idx).first_) { item.second_ = idx; if (OB_FAIL(affi_hash_map.set_refactored(partition_id, item))) { LOG_WARN("failed to set refactored", K(ret)); } LOG_DEBUG("build affi hash map", K(partition_id), K(item)); partition_id = part_ch_array.at(idx).first_; item.first_ = idx; } } if (OB_SUCC(ret)) { item.second_ = part_ch_array.count(); if (OB_FAIL(affi_hash_map.set_refactored(partition_id, item))) { LOG_WARN("failed to set refactored", K(ret)); } LOG_DEBUG("build affi hash map", K(partition_id), K(item)); } return ret; } int ObSlaveMapPkeyHashIdxCalc::get_part_id_by_one_level_sub_ch_map(int64_t& part_id) { int ret = OB_SUCCESS; if (OB_FAIL(ObShuffleService::get_part_id_by_ch_map(affi_hash_map_, part_id))) { LOG_WARN("fail get sub part id", K(ret)); } return ret; } int ObSlaveMapPkeyHashIdxCalc::get_sub_part_id_by_one_level_first_ch_map(const int64_t part_id, int64_t& sub_part_id) { int ret = OB_SUCCESS; if (OB_FAIL(ObShuffleService::get_sub_part_id_by_ch_map(affi_hash_map_, part_id, sub_part_id))) { LOG_WARN("fail get sub part id", K(part_id), K(ret)); } return ret; }