File px_query_checker.cpp¶
File List > cubrid > src > query > parallel > px_query_execute > px_query_checker.cpp
Go to the documentation of this file
/*
*
* Copyright 2016 CUBRID Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
/*
* px_heap_scan_checker.cpp - module that checks whether parallel heap scan is possible.
*/
#include "px_query_checker.hpp"
#include "xasl_analytic.hpp"
#include "xasl_predicate.hpp"
#include <set>
// XXX: SHOULD BE THE LAST INCLUDE HEADER
#include "memory_wrapper.hpp"
namespace parallel_query_execute
{
class xasl_checker
{
public:
xasl_checker()=default;
~xasl_checker()=default;
bool is_parallel_executable (XASL_NODE *xasl);
private:
void add_xasl_recursive (XASL_NODE *xasl);
void check_xasl_recursive (XASL_NODE *xasl);
void check_regu_var (REGU_VARIABLE *regu_var);
void check_pred_expr (PRED_EXPR *pred_expr);
void check_pred (PRED *pred);
void check_eval_term (EVAL_TERM *eval_term);
void check_comp_eval_term (COMP_EVAL_TERM *comp_eval_term);
void check_alsm_eval_term (ALSM_EVAL_TERM *alsm_eval_term);
void check_like_eval_term (LIKE_EVAL_TERM *like_eval_term);
void check_rlike_eval_term (RLIKE_EVAL_TERM *rlike_eval_term);
void check_regu_var_list (REGU_VARIABLE_LIST regu_var_list);
void check_analytic_eval_list (ANALYTIC_EVAL_TYPE *a_eval_list);
void check_xasl_node (XASL_NODE *xasl);
void check_access_spec_type (ACCESS_SPEC_TYPE *access_spec_type);
std::set<XASL_NODE *> get_child_xasl_set_recursive (XASL_NODE *xasl);
std::multimap<XASL_NODE *, XASL_NODE *> m_xasl_map;
std::multimap<XASL_NODE *, XASL_NODE *> m_list_scan_map;
std::set<XASL_NODE *> m_aptr_head_set;
std::set<XASL_NODE *> m_aptr_set;
bool m_is_parallel_executable=true;
};
std::set<XASL_NODE *> xasl_checker::get_child_xasl_set_recursive (XASL_NODE *xasl)
{
std::set<XASL_NODE *> child_xasl_set;
auto child_set = m_xasl_map.equal_range (xasl);
for (auto it = child_set.first; it != child_set.second; it++)
{
child_xasl_set.insert (it->second);
auto child_child_set = get_child_xasl_set_recursive (it->second);
child_xasl_set.insert (child_child_set.begin(), child_child_set.end());
}
return child_xasl_set;
}
void xasl_checker::check_xasl_recursive (XASL_NODE *xasl)
{
std::size_t i,j;
for (XASL_NODE *aptr_head_xasl: m_aptr_head_set)
{
std::vector<std::set<XASL_NODE *>> aptr_set_vector;
#if WITH_PARALLEL_DETAIL_INFO
_er_log_debug (ARG_FILE_LINE, "parallel_detail_info : check_xasl_recursive : aptr head : %p", aptr_head_xasl);
#endif
for (XASL_NODE *scan_ptr = aptr_head_xasl; scan_ptr != nullptr; scan_ptr= scan_ptr->scan_ptr)
{
for (XASL_NODE *aptr = scan_ptr->aptr_list; aptr != nullptr; aptr = aptr->next)
{
auto child_set = get_child_xasl_set_recursive (aptr);
child_set.insert (aptr);
aptr_set_vector.push_back (child_set);
}
}
if (aptr_set_vector.size() > 1)
{
for (i=0; i<aptr_set_vector.size(); i++)
{
auto src_set = aptr_set_vector[i];
for (j=0; j<aptr_set_vector.size(); j++)
{
if (i==j)
{
continue;
}
else
{
auto dst_set = aptr_set_vector[j];
for (auto aptr: src_set)
{
#if WITH_PARALLEL_DETAIL_INFO
_er_log_debug (ARG_FILE_LINE, "parallel_detail_info : check_xasl_recursive : src_child_set[%d] : %p", i, aptr);
#endif
auto list_scan_dst = m_list_scan_map.equal_range (aptr);
for (auto it = list_scan_dst.first; it != list_scan_dst.second; it++)
{
#if WITH_PARALLEL_DETAIL_INFO
_er_log_debug (ARG_FILE_LINE, "parallel_detail_info : check_xasl_recursive : list_scan : %p -> %p", aptr, it->second);
#endif
if (dst_set.find (it->second) != dst_set.end())
{
#if WITH_PARALLEL_DETAIL_INFO
_er_log_debug (ARG_FILE_LINE, "parallel_detail_info : check_xasl_recursive : non-parallelable ref : %p -> %p", aptr,
it->second);
#endif
m_is_parallel_executable = false;
return;
}
}
}
}
}
}
}
}
}
void xasl_checker::check_regu_var (REGU_VARIABLE *regu_var)
{
if (!regu_var)
{
return;
}
switch (regu_var->type)
{
case TYPE_DBVAL:
case TYPE_CONSTANT:
case TYPE_ORDERBY_NUM:
case TYPE_ATTR_ID:
case TYPE_CLASS_ATTR_ID:
case TYPE_SHARED_ATTR_ID:
case TYPE_POSITION:
case TYPE_LIST_ID:
case TYPE_POS_VALUE:
case TYPE_OID:
case TYPE_CLASSOID:
case TYPE_REGUVAL_LIST:
/* can execute parallel */
break;
case TYPE_REGU_VAR_LIST:
check_regu_var_list (regu_var->value.regu_var_list);
break;
case TYPE_FUNC:
check_regu_var_list (regu_var->value.funcp->operand);
break;
case TYPE_INARITH:
case TYPE_OUTARITH:
if (regu_var->value.arithptr->opcode == T_EVALUATE_VARIABLE || regu_var->value.arithptr->opcode == T_DEFINE_VARIABLE)
{
m_is_parallel_executable = false;
}
check_regu_var (regu_var->value.arithptr->leftptr);
check_regu_var (regu_var->value.arithptr->rightptr);
check_regu_var (regu_var->value.arithptr->thirdptr);
break;
case TYPE_SP:
m_is_parallel_executable = false;
break;
default:
assert (0);
m_is_parallel_executable = false;
break;
}
}
void xasl_checker::check_pred_expr (PRED_EXPR *pred_expr)
{
if (!pred_expr)
{
return;
}
switch (pred_expr->type)
{
case T_PRED:
check_pred (&pred_expr->pe.m_pred);
break;
case T_EVAL_TERM:
check_eval_term (&pred_expr->pe.m_eval_term);
break;
case T_NOT_TERM:
check_pred_expr (pred_expr->pe.m_not_term);
break;
default:
assert (0);
break;
}
}
void xasl_checker::check_pred (PRED *pred)
{
if (!pred)
{
return;
}
check_pred_expr (pred->lhs);
check_pred_expr (pred->rhs);
}
void xasl_checker::check_eval_term (EVAL_TERM *eval_term)
{
if (!eval_term)
{
return;
}
switch (eval_term->et_type)
{
case T_COMP_EVAL_TERM:
check_comp_eval_term (&eval_term->et.et_comp);
break;
case T_ALSM_EVAL_TERM:
check_alsm_eval_term (&eval_term->et.et_alsm);
break;
case T_LIKE_EVAL_TERM:
check_like_eval_term (&eval_term->et.et_like);
break;
case T_RLIKE_EVAL_TERM:
check_rlike_eval_term (&eval_term->et.et_rlike);
break;
default:
assert (0);
break;
}
}
void xasl_checker::check_comp_eval_term (COMP_EVAL_TERM *comp_eval_term)
{
if (!comp_eval_term)
{
return;
}
check_regu_var (comp_eval_term->lhs);
check_regu_var (comp_eval_term->rhs);
}
void xasl_checker::check_alsm_eval_term (ALSM_EVAL_TERM *alsm_eval_term)
{
if (!alsm_eval_term)
{
return;
}
check_regu_var (alsm_eval_term->elem);
check_regu_var (alsm_eval_term->elemset);
}
void xasl_checker::check_like_eval_term (LIKE_EVAL_TERM *like_eval_term)
{
if (!like_eval_term)
{
return;
}
check_regu_var (like_eval_term->src);
check_regu_var (like_eval_term->pattern);
check_regu_var (like_eval_term->esc_char);
}
void xasl_checker::check_rlike_eval_term (RLIKE_EVAL_TERM *rlike_eval_term)
{
if (!rlike_eval_term)
{
return;
}
check_regu_var (rlike_eval_term->src);
check_regu_var (rlike_eval_term->pattern);
check_regu_var (rlike_eval_term->case_sensitive);
}
void xasl_checker::check_regu_var_list (REGU_VARIABLE_LIST regu_var_list)
{
REGU_VARIABLE_LIST regu_var_list_p;
for (regu_var_list_p = regu_var_list; regu_var_list_p != nullptr; regu_var_list_p = regu_var_list_p->next)
{
check_regu_var (®u_var_list_p->value);
}
}
void xasl_checker::check_analytic_eval_list (ANALYTIC_EVAL_TYPE *a_eval_list)
{
for (ANALYTIC_EVAL_TYPE *eval = a_eval_list; eval != nullptr; eval = eval->next)
{
for (ANALYTIC_TYPE *node = eval->head; node != nullptr; node = node->next)
{
check_regu_var (&node->operand);
if (node->function == PT_PERCENTILE_CONT || node->function == PT_PERCENTILE_DISC)
{
check_regu_var (node->info.percentile.percentile_reguvar);
}
}
}
}
void xasl_checker::check_xasl_node (XASL_NODE *xasl)
{
if (!xasl)
{
return;
}
ACCESS_SPEC_TYPE *spec_list;
check_pred_expr (xasl->ordbynum_pred);
check_regu_var (xasl->orderby_limit);
if (xasl->outptr_list)
{
check_regu_var_list (xasl->outptr_list->valptrp);
}
for (spec_list = xasl->spec_list; spec_list != nullptr; spec_list = spec_list->next)
{
check_access_spec_type (spec_list);
}
for (spec_list = xasl->merge_spec; spec_list != nullptr; spec_list = spec_list->next)
{
check_access_spec_type (spec_list);
}
check_pred_expr (xasl->during_join_pred);
check_pred_expr (xasl->after_join_pred);
check_pred_expr (xasl->if_pred);
check_pred_expr (xasl->instnum_pred);
check_regu_var (xasl->limit_offset);
check_regu_var (xasl->limit_row_count);
if (xasl->type == BUILDLIST_PROC)
{
if (xasl->proc.buildlist.a_outptr_list)
{
check_regu_var_list (xasl->proc.buildlist.a_outptr_list->valptrp);
}
if (xasl->proc.buildlist.a_outptr_list_ex)
{
check_regu_var_list (xasl->proc.buildlist.a_outptr_list_ex->valptrp);
}
if (xasl->proc.buildlist.a_outptr_list_interm)
{
check_regu_var_list (xasl->proc.buildlist.a_outptr_list_interm->valptrp);
}
if (xasl->proc.buildlist.g_outptr_list)
{
check_regu_var_list (xasl->proc.buildlist.g_outptr_list->valptrp);
}
check_regu_var_list (xasl->proc.buildlist.a_regu_list);
check_regu_var_list (xasl->proc.buildlist.a_scan_regu_list);
check_regu_var_list (xasl->proc.buildlist.g_regu_list);
check_regu_var_list (xasl->proc.buildlist.g_hk_scan_regu_list);
check_regu_var_list (xasl->proc.buildlist.g_hk_sort_regu_list);
check_regu_var_list (xasl->proc.buildlist.g_scan_regu_list);
check_pred_expr (xasl->proc.buildlist.g_having_pred);
check_pred_expr (xasl->proc.buildlist.g_grbynum_pred);
check_analytic_eval_list (xasl->proc.buildlist.a_eval_list);
}
}
void xasl_checker::check_access_spec_type (ACCESS_SPEC_TYPE *access_spec_type)
{
if (!access_spec_type)
{
return;
}
check_pred_expr (access_spec_type->where_key);
check_pred_expr (access_spec_type->where_pred);
check_pred_expr (access_spec_type->where_range);
switch (access_spec_type->type)
{
case TARGET_LIST:
{
check_regu_var_list (access_spec_type->s.list_node.list_regu_list_pred);
check_regu_var_list (access_spec_type->s.list_node.list_regu_list_rest);
check_regu_var_list (access_spec_type->s.list_node.list_regu_list_build);
check_regu_var_list (access_spec_type->s.list_node.list_regu_list_probe);
}
break;
case TARGET_CLASS:
{
check_regu_var_list (access_spec_type->s.cls_node.cls_regu_list_key);
check_regu_var_list (access_spec_type->s.cls_node.cls_regu_list_pred);
check_regu_var_list (access_spec_type->s.cls_node.cls_regu_list_range);
check_regu_var_list (access_spec_type->s.cls_node.cls_regu_list_rest);
}
break;
case TARGET_CLASS_ATTR:
case TARGET_DBLINK:
case TARGET_METHOD:
case TARGET_REGUVAL_LIST:
case TARGET_SET:
case TARGET_SHOWSTMT:
default:
m_is_parallel_executable = false;
break;
}
switch (access_spec_type->access)
{
case ACCESS_METHOD_SEQUENTIAL:
case ACCESS_METHOD_INDEX:
break;
case ACCESS_METHOD_JSON_TABLE:
case ACCESS_METHOD_SCHEMA:
case ACCESS_METHOD_SEQUENTIAL_RECORD_INFO:
case ACCESS_METHOD_SEQUENTIAL_PAGE_SCAN:
case ACCESS_METHOD_INDEX_KEY_INFO:
case ACCESS_METHOD_INDEX_NODE_INFO:
case ACCESS_METHOD_SEQUENTIAL_SAMPLING_SCAN:
default:
m_is_parallel_executable = false;
break;
}
}
void xasl_checker::add_xasl_recursive (XASL_NODE *xasl)
{
if (!xasl)
{
return;
}
if (xasl->scan_op_type != S_SELECT)
{
m_is_parallel_executable = false;
return;
}
if (xasl->upd_del_class_cnt > 0)
{
m_is_parallel_executable = false;
return;
}
if (xasl->type == HASHJOIN_PROC || xasl->type == MERGELIST_PROC)
{
for (XASL_NODE *aptr = xasl->aptr_list; aptr != nullptr; aptr = aptr->next)
{
XASL_SET_FLAG (aptr, XASL_ZERO_CORR_LEVEL);
}
}
else
{
if (!XASL_IS_FLAGED (xasl, XASL_ZERO_CORR_LEVEL))
{
m_is_parallel_executable = false;
return;
}
}
for (XASL_NODE *aptr = xasl->aptr_list; aptr != nullptr; aptr = aptr->next)
{
add_xasl_recursive (aptr);
m_xasl_map.insert (std::make_pair (xasl, aptr));
m_aptr_head_set.insert (xasl);
m_aptr_set.insert (aptr);
if (aptr->type == HASHJOIN_PROC || aptr->type == MERGELIST_PROC)
{
for (XASL_NODE *aptr2 = aptr->aptr_list; aptr2 != nullptr; aptr2 = aptr2->next)
{
XASL_SET_FLAG (aptr2, XASL_ZERO_CORR_LEVEL);
}
}
else
{
if (!XASL_IS_FLAGED (aptr, XASL_ZERO_CORR_LEVEL))
{
m_is_parallel_executable = false;
return;
}
}
check_xasl_node (aptr);
if (aptr->spec_list && aptr->spec_list->type == TARGET_LIST)
{
m_list_scan_map.insert (std::make_pair (aptr, aptr->spec_list->s.list_node.xasl_node));
}
for (XASL_NODE *aptr_scan_ptr = aptr->scan_ptr; aptr_scan_ptr != nullptr; aptr_scan_ptr = aptr_scan_ptr->scan_ptr)
{
check_xasl_node (aptr_scan_ptr);
if (aptr_scan_ptr->spec_list && aptr_scan_ptr->spec_list->type == TARGET_LIST)
{
m_list_scan_map.insert (std::make_pair (aptr, aptr_scan_ptr->spec_list->s.list_node.xasl_node));
}
}
}
for (XASL_NODE *scan_ptr = xasl->scan_ptr; scan_ptr != nullptr; scan_ptr = scan_ptr->scan_ptr)
{
check_xasl_node (scan_ptr);
if (scan_ptr ->spec_list && scan_ptr ->spec_list->type == TARGET_LIST)
{
m_list_scan_map.insert (std::make_pair (xasl, scan_ptr->spec_list->s.list_node.xasl_node));
}
for (XASL_NODE *aptr = scan_ptr->aptr_list; aptr != nullptr; aptr = aptr->next)
{
m_xasl_map.insert (std::make_pair (xasl, aptr));
m_aptr_head_set.insert (xasl);
m_aptr_set.insert (aptr);
if (aptr->type == HASHJOIN_PROC || aptr->type == MERGELIST_PROC)
{
for (XASL_NODE *aptr2 = aptr->aptr_list; aptr2 != nullptr; aptr2 = aptr2->next)
{
XASL_SET_FLAG (aptr2, XASL_ZERO_CORR_LEVEL);
}
}
else
{
if (!XASL_IS_FLAGED (aptr, XASL_ZERO_CORR_LEVEL))
{
m_is_parallel_executable = false;
return;
}
}
check_xasl_node (aptr);
if (aptr->spec_list && aptr->spec_list->type == TARGET_LIST)
{
m_list_scan_map.insert (std::make_pair (aptr, aptr->spec_list->s.list_node.xasl_node));
}
for (XASL_NODE *aptr_scan_ptr = aptr->scan_ptr; aptr_scan_ptr != nullptr; aptr_scan_ptr = aptr_scan_ptr->scan_ptr)
{
check_xasl_node (aptr_scan_ptr);
if (aptr_scan_ptr->spec_list && aptr_scan_ptr->spec_list->type == TARGET_LIST)
{
m_list_scan_map.insert (std::make_pair (aptr, aptr_scan_ptr->spec_list->s.list_node.xasl_node));
}
}
}
}
for (XASL_NODE *dptr = xasl->dptr_list; dptr != nullptr; dptr = dptr->next)
{
add_xasl_recursive (dptr );
m_xasl_map.insert (std::make_pair (xasl, dptr));
}
for (XASL_NODE *fptr = xasl->fptr_list; fptr != nullptr; fptr = fptr->next)
{
add_xasl_recursive (fptr );
m_xasl_map.insert (std::make_pair (xasl, fptr));
}
for (XASL_NODE *connect_by_ptr = xasl->connect_by_ptr; connect_by_ptr != nullptr; connect_by_ptr = connect_by_ptr->next)
{
add_xasl_recursive (connect_by_ptr );
m_xasl_map.insert (std::make_pair (xasl, connect_by_ptr));
}
if (xasl->type == CTE_PROC)
{
if (xasl->proc.cte.non_recursive_part)
{
add_xasl_recursive (xasl->proc.cte.non_recursive_part );
m_xasl_map.insert (std::make_pair (xasl, xasl->proc.cte.non_recursive_part));
}
if (xasl->proc.cte.recursive_part)
{
m_is_parallel_executable = false;
}
}
else if (xasl->type == BUILDLIST_PROC)
{
for (XASL_NODE *eptr = xasl->proc.buildlist.eptr_list; eptr != nullptr; eptr = eptr->next)
{
add_xasl_recursive (eptr );
m_xasl_map.insert (std::make_pair (xasl, eptr));
}
}
check_xasl_node (xasl);
if (xasl->spec_list)
{
if (xasl->spec_list->type == TARGET_LIST)
{
m_list_scan_map.insert (std::make_pair (xasl, xasl->spec_list->s.list_node.xasl_node));
}
}
if (xasl->merge_spec)
{
if (xasl->merge_spec->type == TARGET_LIST)
{
m_list_scan_map.insert (std::make_pair (xasl, xasl->merge_spec->s.list_node.xasl_node));
}
}
}
bool xasl_checker::is_parallel_executable (XASL_NODE *xasl)
{
try
{
add_xasl_recursive (xasl);
if (!m_is_parallel_executable)
{
return false;
}
check_xasl_recursive (xasl);
#if WITH_PARALLEL_DETAIL_INFO
_er_log_debug (ARG_FILE_LINE,
"parallel_detail_info : is_executable : %p, n_aptr: %zu", xasl, m_aptr_head_set.size());
#endif
if (m_aptr_set.size() < 2)
{
return false;
}
return m_is_parallel_executable;
}
catch (std::exception &e)
{
assert_release (false);
return false;
}
}
}
extern int
check_parallel_subquery_possible (XASL_NODE *xasl)
{
parallel_query_execute::xasl_checker checker;
if (xasl)
{
if (!checker.is_parallel_executable (xasl))
{
XASL_SET_FLAG (xasl, XASL_NO_PARALLEL_SUBQUERY);
}
}
return NO_ERROR;
}