Co-authored-by: Charles0429 <xiezhenjiang@gmail.com> Co-authored-by: tino247 <tino247@126.com> Co-authored-by: chaser-ch <chaser.ch@antgroup.com>
283 lines
9.9 KiB
C++
283 lines
9.9 KiB
C++
/**
|
|
* Copyright (c) 2021 OceanBase
|
|
* OceanBase CE is licensed under Mulan PubL v2.
|
|
* You can use this software according to the terms and conditions of the Mulan PubL v2.
|
|
* You may obtain a copy of Mulan PubL v2 at:
|
|
* http://license.coscl.org.cn/MulanPubL-2.0
|
|
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
|
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
|
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
|
* See the Mulan PubL v2 for more details.
|
|
*/
|
|
|
|
#define USING_LOG_PREFIX SQL_PC
|
|
#include "sql/plan_cache/ob_dist_plans.h"
|
|
#include "sql/engine/ob_physical_plan.h"
|
|
#include "sql/plan_cache/ob_cache_object_factory.h"
|
|
#include "sql/plan_cache/ob_plan_cache.h"
|
|
#include "sql/plan_cache/ob_plan_set.h"
|
|
#include "sql/engine/ob_exec_context.h"
|
|
#include "sql/plan_cache/ob_plan_cache_value.h"
|
|
#include "sql/plan_cache/ob_plan_match_helper.h"
|
|
using namespace oceanbase::share;
|
|
|
|
namespace oceanbase {
|
|
namespace sql {
|
|
int ObDistPlans::init(ObSqlPlanSet *ps)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
if (OB_ISNULL(ps)) {
|
|
ret = OB_INVALID_ARGUMENT;
|
|
LOG_WARN("invalid argument", K(ret));
|
|
} else {
|
|
plan_set_ = ps;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
//对于复制表会在检查是否匹配的过程中修改副本index
|
|
int ObDistPlans::get_plan(ObPlanCacheCtx &pc_ctx,
|
|
ObPhysicalPlan *&plan)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
plan = NULL;
|
|
bool is_matched = false;
|
|
|
|
LOG_DEBUG("Get Plan", K(dist_plans_.count()));
|
|
//need to clear all location info before calculate candi tablet locations
|
|
//because get_phy_locations will build the related_tablet_map in ObDASCtx
|
|
//and add candi table location into DASCtx
|
|
DAS_CTX(pc_ctx.exec_ctx_).clear_all_location_info();
|
|
if (OB_ISNULL(plan_set_)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("invalid null plan_set_", K(ret));
|
|
} else if ((plan_set_->is_multi_stmt_plan())) {
|
|
// 如果是multi stmt计划,一定是单表分布式计划,可以直接根据table location算出物理分区地址
|
|
// single table should just return plan, do not match
|
|
if (0 == dist_plans_.count()) {
|
|
ret = OB_SQL_PC_NOT_EXIST;
|
|
LOG_DEBUG("dist plan list is empty", K(ret), K(dist_plans_.count()));
|
|
} else if (OB_ISNULL(dist_plans_.at(0))) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("get an unexpected null plan", K(ret), K(dist_plans_.at(0)));
|
|
} else {
|
|
dist_plans_.at(0)->set_dynamic_ref_handle(pc_ctx.handle_id_);
|
|
plan = dist_plans_.at(0);
|
|
is_matched = true;
|
|
|
|
// fill table location for single plan using px
|
|
// for single dist plan without px, we already fill the phy locations while calculating plan type
|
|
// for multi table px plan, physical location is calculated in match step
|
|
ObArray<ObCandiTableLoc> candi_table_locs;
|
|
bool need_check_on_same_server = false;
|
|
if (OB_ISNULL(plan_set_)) {
|
|
ret = OB_INVALID_ARGUMENT;
|
|
LOG_WARN("invalid null plan set", K(ret), K(plan_set_));
|
|
} else if (!plan_set_->enable_inner_part_parallel()) {
|
|
// do nothing
|
|
} else if (OB_FAIL(ObPhyLocationGetter::get_phy_locations(plan->get_table_locations(),
|
|
pc_ctx,
|
|
candi_table_locs,
|
|
need_check_on_same_server))) {
|
|
LOG_WARN("failed to get physical table locations", K(ret));
|
|
} else if (OB_FAIL(ObPhyLocationGetter::build_table_locs(pc_ctx.exec_ctx_.get_das_ctx(),
|
|
plan->get_table_locations(),
|
|
candi_table_locs))) {
|
|
LOG_WARN("fail to init table locs", K(ret));
|
|
}
|
|
}
|
|
}
|
|
|
|
ObPlanMatchHelper helper(plan_set_);
|
|
ObArray<ObCandiTableLoc> phy_tbl_infos;
|
|
ObArray<ObTableLocation> out_tbl_locations;
|
|
for (int64_t i = 0; OB_SUCC(ret) && !is_matched && i < dist_plans_.count();
|
|
i++) {
|
|
ObPhysicalPlan *tmp_plan = dist_plans_.at(i);
|
|
phy_tbl_infos.reuse();
|
|
out_tbl_locations.reuse();
|
|
if (OB_ISNULL(tmp_plan)) {
|
|
ret = OB_INVALID_ARGUMENT;
|
|
LOG_WARN("invalid argument", K(tmp_plan));
|
|
} else if (OB_FAIL(helper.match_plan(pc_ctx, tmp_plan, is_matched, phy_tbl_infos, out_tbl_locations))) {
|
|
LOG_WARN("fail to match dist plan", K(ret));
|
|
} else if (is_matched) {
|
|
tmp_plan->set_dynamic_ref_handle(pc_ctx.handle_id_);
|
|
plan = tmp_plan;
|
|
if (OB_FAIL(ObPhyLocationGetter::build_table_locs(DAS_CTX(pc_ctx.exec_ctx_),
|
|
out_tbl_locations,
|
|
phy_tbl_infos))) {
|
|
LOG_WARN("fail to init table locs", K(ret));
|
|
}
|
|
}
|
|
}
|
|
|
|
if (OB_SUCC(ret) && plan == NULL) {
|
|
ret = OB_SQL_PC_NOT_EXIST;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int ObDistPlans::add_evolution_plan(ObPhysicalPlan &plan, ObPlanCacheCtx &pc_ctx)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
bool is_matched = false;
|
|
ObPlanMatchHelper helper(plan_set_);
|
|
ObArray<ObCandiTableLoc> phy_tbl_infos;
|
|
ObArray<ObTableLocation> out_tbl_locations;
|
|
for (int64_t i = 0; OB_SUCC(ret) && !is_matched && i < dist_plans_.count(); i++) {
|
|
const ObPhysicalPlan *tmp_plan = dist_plans_.at(i);
|
|
phy_tbl_infos.reuse();
|
|
out_tbl_locations.reuse();
|
|
if (OB_ISNULL(tmp_plan)) {
|
|
ret = OB_INVALID_ARGUMENT;
|
|
LOG_WARN("invalid argument", K(tmp_plan));
|
|
} else if (OB_FAIL(helper.match_plan(pc_ctx, tmp_plan, is_matched, phy_tbl_infos, out_tbl_locations))) {
|
|
LOG_WARN("fail to match dist plan", K(ret));
|
|
} else if (false == is_matched) {
|
|
// do nothing
|
|
} else {
|
|
ret = OB_SQL_PC_PLAN_DUPLICATE;
|
|
}
|
|
}
|
|
if (OB_SUCC(ret) && !is_matched) {
|
|
if (OB_FAIL(dist_plans_.push_back(&plan))) {
|
|
LOG_WARN("fail to add plan", K(ret));
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObDistPlans::add_plan(ObPhysicalPlan &plan,
|
|
ObPlanCacheCtx &pc_ctx)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
bool is_matched = false;
|
|
ObPlanMatchHelper helper(plan_set_);
|
|
ObArray<ObCandiTableLoc> phy_tbl_infos;
|
|
ObArray<ObTableLocation> out_tbl_locations;
|
|
for (int64_t i = 0; OB_SUCC(ret) && !is_matched && i < dist_plans_.count(); i++) {
|
|
//检查是否已有其他线程add该plan成功
|
|
phy_tbl_infos.reuse();
|
|
out_tbl_locations.reuse();
|
|
const ObPhysicalPlan *tmp_plan = dist_plans_.at(i);
|
|
if (OB_ISNULL(tmp_plan)) {
|
|
ret = OB_INVALID_ARGUMENT;
|
|
LOG_WARN("invalid argument", K(tmp_plan));
|
|
} else if (OB_FAIL(helper.match_plan(pc_ctx, tmp_plan, is_matched, phy_tbl_infos, out_tbl_locations))) {
|
|
LOG_WARN("fail to match dist plan", K(ret));
|
|
} else if (false == is_matched) {
|
|
// do nothing
|
|
} else {
|
|
ret = OB_SQL_PC_PLAN_DUPLICATE;
|
|
}
|
|
}
|
|
|
|
if (OB_SUCC(ret) && !is_matched) {
|
|
if (OB_FAIL(plan.set_location_constraints(pc_ctx.sql_ctx_.base_constraints_,
|
|
pc_ctx.sql_ctx_.strict_constraints_,
|
|
pc_ctx.sql_ctx_.non_strict_constraints_))) {
|
|
LOG_WARN("failed to set location constraints", K(ret), K(plan),
|
|
K(pc_ctx.sql_ctx_.base_constraints_),
|
|
K(pc_ctx.sql_ctx_.strict_constraints_),
|
|
K(pc_ctx.sql_ctx_.non_strict_constraints_));
|
|
} else if (OB_FAIL(dist_plans_.push_back(&plan))) {
|
|
LOG_WARN("fail to add plan", K(ret));
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
//使用plan的hash value判断是否为同一个plan
|
|
int ObDistPlans::is_same_plan(const ObPhysicalPlan *l_plan,
|
|
const ObPhysicalPlan *r_plan,
|
|
bool &is_same) const
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
|
|
if (OB_ISNULL(l_plan) || OB_ISNULL(r_plan)) {
|
|
ret = OB_INVALID_ARGUMENT;
|
|
LOG_WARN("invalid argument", K(ret), K(l_plan), K(r_plan));
|
|
} else {
|
|
is_same = (l_plan->get_signature() == r_plan->get_signature());
|
|
LOG_DEBUG("compare plan", K(l_plan->get_signature()), K(r_plan->get_signature()), K(is_same));
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
//删除所有plan及对应plan stat
|
|
int ObDistPlans::remove_all_plan()
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
int tmp_ret = OB_SUCCESS;
|
|
|
|
for (int64_t i = 0; i < dist_plans_.count(); i++) {
|
|
if (OB_ISNULL(dist_plans_.at(i))) {
|
|
tmp_ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("get un expected null in dist_plans",
|
|
K(tmp_ret), K(dist_plans_.at(i)));
|
|
} else {
|
|
dist_plans_.at(i) = NULL;
|
|
}
|
|
}
|
|
|
|
dist_plans_.reset();
|
|
ret = tmp_ret;
|
|
|
|
return ret;
|
|
}
|
|
|
|
//获取所有plan使用内存
|
|
int64_t ObDistPlans::get_mem_size() const
|
|
{
|
|
int64_t plan_set_mem = 0;
|
|
for (int64_t i = 0; i < dist_plans_.count(); i++) {
|
|
if (OB_ISNULL(dist_plans_.at(i))) {
|
|
BACKTRACE_RET(ERROR, OB_ERR_UNEXPECTED, true, "null physical plan");
|
|
} else {
|
|
plan_set_mem += dist_plans_.at(i)->get_mem_size();
|
|
}
|
|
}
|
|
return plan_set_mem;
|
|
}
|
|
|
|
int ObDistPlans::remove_plan_stat()
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
int tmp_ret = OB_SUCCESS;
|
|
ObPlanCache *pc = NULL;
|
|
if (OB_ISNULL(plan_set_)) {
|
|
ret = OB_INVALID_ARGUMENT;
|
|
LOG_WARN("invalid argument", K(plan_set_));
|
|
} else if (OB_ISNULL(pc = plan_set_->get_plan_cache())) {
|
|
ret = OB_INVALID_ARGUMENT;
|
|
LOG_WARN("invalid argument", K(pc));
|
|
} else {
|
|
uint64_t plan_id = OB_INVALID_ID;
|
|
for (int64_t i = 0; i < dist_plans_.count(); i++) {
|
|
if (OB_ISNULL(dist_plans_.at(i))) {
|
|
tmp_ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN_RET(tmp_ret, "get an unexpected null", K(tmp_ret), K(dist_plans_.at(i)));
|
|
} else if (FALSE_IT(plan_id = dist_plans_.at(i)->get_plan_id())) {
|
|
} else if (OB_SUCCESS !=
|
|
(tmp_ret = plan_set_->remove_cache_obj_entry(plan_id))) {
|
|
LOG_WARN_RET(tmp_ret, "failed to remove plan stat",
|
|
K(tmp_ret), K(plan_id), K(i));
|
|
} else {
|
|
/* do nothing */
|
|
}
|
|
}
|
|
if (OB_SUCCESS == tmp_ret) {
|
|
dist_plans_.reuse();
|
|
}
|
|
}
|
|
ret = tmp_ret;
|
|
return ret;
|
|
}
|
|
|
|
} // namespace sql
|
|
} // namespace oceanbase
|