[FEAT MERGE] implement SQL level resource management based on pattern match

This commit is contained in:
obdev
2023-01-04 12:39:02 +00:00
committed by ob-robot
parent cca9f7c2d2
commit 7c991b5da5
58 changed files with 2613 additions and 168 deletions

View File

@ -28,6 +28,7 @@
#include "sql/udr/ob_udr_utils.h"
#include "share/ob_duplicate_scope_define.h"
#include "pl/ob_pl_stmt.h"
#include "share/resource_manager/ob_resource_manager.h"
using namespace oceanbase::share::schema;
using namespace oceanbase::common;
using namespace oceanbase::pl;
@ -519,7 +520,63 @@ int ObPlanCacheValue::choose_plan(ObPlanCacheCtx &pc_ctx,
} else {
SQL_PC_LOG(TRACE, "failed to select plan in plan set", K(ret));
}
} else {
} else if (NULL != params) {
// set res map rule
uint64_t rule_id = plan_set->res_map_rule_id_;
int64_t param_idx = plan_set->res_map_rule_param_idx_;
uint64_t tenant_id = OB_INVALID_ID;
ObString param_text;
ObCollationType cs_type = CS_TYPE_INVALID;
if (rule_id != OB_INVALID_ID && param_idx != OB_INVALID_INDEX
&& pc_ctx.sql_ctx_.enable_sql_resource_manage_) {
if (OB_UNLIKELY(param_idx < 0 || param_idx >= params->count())) {
ret = OB_ERR_UNEXPECTED;
LOG_ERROR("unexpected res map rule param idx", K(ret), K(rule_id), K(param_idx), K(params->count()));
} else if (OB_FAIL(session->get_collation_connection(cs_type))) {
LOG_WARN("get collation connection failed", K(ret));
} else if (OB_INVALID_ID == (tenant_id = session->get_effective_tenant_id())) {
ret = OB_ERR_UNEXPECTED;
SQL_PC_LOG(ERROR, "got effective tenant id is invalid", K(ret));
} else if (OB_FAIL(ObObjCaster::get_obj_param_text(
params->at(plan_set->res_map_rule_param_idx_),
pc_ctx.raw_sql_, pc_ctx.allocator_,
cs_type, param_text))) {
LOG_WARN("get obj param text failed", K(ret));
} else {
uint64_t group_id = G_RES_MGR.get_col_mapping_rule_mgr().get_column_mapping_group_id(
tenant_id,
plan_set->res_map_rule_id_,
session->get_user_name(),
param_text);
if (OB_INVALID_ID == group_id) {
// OB_INVALID_ID means current user+param_value is not defined in mapping rule,
// get group_id according to current user.
if (OB_FAIL(G_RES_MGR.get_mapping_rule_mgr().get_group_id_by_user(
tenant_id, session->get_user_id(), group_id))) {
LOG_WARN("get group id by user failed", K(ret));
} else if (OB_INVALID_ID == group_id) {
// if not set consumer_group for current user, use OTHER_GROUP by default.
group_id = 0;
}
}
if (OB_SUCC(ret)) {
session->set_expect_group_id(group_id);
if (group_id == THIS_WORKER.get_group_id()) {
// do nothing if equals to current group id.
} else if (session->get_is_in_retry()
&& OB_NEED_SWITCH_CONSUMER_GROUP
== session->get_retry_info().get_last_query_retry_err()) {
LOG_ERROR("use unexpected group when retry, maybe set packet retry failed before",
K(group_id), K(THIS_WORKER.get_group_id()), K(rule_id), K(param_idx));
} else {
ret = OB_NEED_SWITCH_CONSUMER_GROUP;
}
LOG_TRACE("get expect rule id", K(ret), K(group_id),
K(THIS_WORKER.get_group_id()), K(session->get_expect_group_id()),
K(pc_ctx.raw_sql_));
}
}
}
break; //这个地方建议保留,如果去掉,需要另外加标记在for()中判断,并且不使用上面的for循环的宏;
}
}
@ -1029,8 +1086,28 @@ int ObPlanCacheValue::add_plan(ObPlanCacheObject &plan,
} else if (is_old_version) {
ret = OB_OLD_SCHEMA_VERSION;
SQL_PC_LOG(DEBUG, "view or table is old version", K(ret));
/* Consider this concurrent scene:
1. No mapping is defined on t.c1 at first.
2. Thread1 resolve select * from t where c1 = 1; and generate a plan with rule_id = INVALID
3. User define a mapping rule on t.c1.
4. Thread2 load the new mapping rule on t.c1 into cache and evict all plans related with t
5. Thread1 add the plan into plan cache. The plan is marked without a mapping rule
but there is actually a mapping rule on t.c1 now
Solution:
1. When start to resolve a sql, record the current version of mapping rule.
2. Before adding a plan into plan cache, check whether the recorded version is same as current version,
and not add into plan cache if not same.
THERE IS A FLAW of this solution. If step 4 accurs right in the gap between check version and add plan in plan cache,
a stale plan will be added into plan cache. Since the gap is quite small, we think the flaw is acceptable.
*/
} else if (pc_ctx.sql_ctx_.res_map_rule_version_ != 0) {
int64_t latest_rule_version = G_RES_MGR.get_col_mapping_rule_mgr().get_column_mapping_version(MTL_ID());
if (pc_ctx.sql_ctx_.res_map_rule_version_ != latest_rule_version) {
ret = OB_OLD_SCHEMA_VERSION;
SQL_PC_LOG(TRACE, "resource map rule version is outdated, not add to plan cache.", K(ret),
K(pc_ctx.sql_ctx_.res_map_rule_version_), K(latest_rule_version));
}
}
if (OB_FAIL(ret)) {//do nothing
} else if (OB_FAIL(get_outline_param_index(pc_ctx.exec_ctx_, outline_param_idx))) {
LOG_WARN("fail to judge concurrent limit sql", K(ret));
@ -1980,5 +2057,21 @@ int ObPlanCacheValue::rm_space_for_neg_num(ParseNode *param_node, ObIAllocator &
return ret;
}
int ObPlanCacheValue::check_contains_table(uint64_t db_id, common::ObString tab_name, bool &contains)
{
int ret = OB_SUCCESS;
for (int64_t i = 0; !contains && i < stored_schema_objs_.count(); i++) {
if (OB_ISNULL(stored_schema_objs_.at(i))) {
// do nothing
} else {
if ((stored_schema_objs_.at(i)->database_id_ == db_id) &&
(stored_schema_objs_.at(i)->table_name_ == tab_name)) {
contains = true;
}
}
}
return ret;
}
}//end of namespace sql
}//end of namespace oceanbase