* Copyright (c) 2020 Huawei Technologies Co.,Ltd.
*
* openGauss is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
*
* http://license.coscl.org.cn/MulanPSL2
*
* 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 PSL v2 for more details.
* -------------------------------------------------------------------------
*
* randomplan.cpp
* Generate random plan according to random mode and seed.
*
* IDENTIFICATION
* src/gausskernel/optimizer/util/randomplan.cpp
*
* -------------------------------------------------------------------------
*/
#include "postgres.h"
#include "knl/knl_variable.h"
#include <limits.h>
#include "fmgr.h"
#include "optimizer/randomplan.h"
#define RAND48_SEED_0 0x330e
#define RAND48_SEED_1 0xabcd
#define RAND48_SEED_2 0x1234
static unsigned short path_inital_seed_factor[3] = {RAND48_SEED_0, RAND48_SEED_1, RAND48_SEED_2};
#define path_reset_srandom(xseed) pg_reset_srand48((unsigned short*)(xseed))
#define path_get_srandom() (unsigned short*)pg_get_srand48()
* FUNCTION
*****************************************************************************/
static long get_next_path_random(unsigned int seed)
{
long random = 0;
unsigned short zero[3] = {0};
errno_t ret = 0;
if (0 == memcmp(u_sess->opt_cxt.path_current_seed_factor, zero, sizeof(zero))) {
path_reset_srandom(path_inital_seed_factor);
if (seed > 0) {
gs_srandom(seed);
}
} else {
path_reset_srandom(u_sess->opt_cxt.path_current_seed_factor);
}
random = gs_random();
ret = memcpy_s(u_sess->opt_cxt.path_current_seed_factor,
sizeof(u_sess->opt_cxt.path_current_seed_factor),
path_get_srandom(),
sizeof(u_sess->opt_cxt.path_current_seed_factor));
securec_check(ret, "\0", "\0");
return random;
}
void set_path_seed_factor_zero()
{
errno_t ret = 0;
ret = memset_s(u_sess->opt_cxt.path_current_seed_factor,
sizeof(u_sess->opt_cxt.path_current_seed_factor),
0,
sizeof(u_sess->opt_cxt.path_current_seed_factor));
securec_check(ret, "\0", "\0");
}
int choose_random_option(int optionnum)
{
unsigned int random_pathno = 0;
long random = 0;
if (optionnum == 0) {
ereport(ERROR, (errcode(ERRCODE_DIVISION_BY_ZERO), errmsg("division by zero")));
}
random = get_next_path_random(u_sess->opt_cxt.plan_current_seed);
random_pathno = random % optionnum;
return random_pathno;
}
void set_inital_plan_seed()
{
u_sess->opt_cxt.plan_prev_seed = u_sess->opt_cxt.plan_current_seed;
if (u_sess->attr.attr_sql.plan_mode_seed == OPTIMIZE_PLAN) {
u_sess->opt_cxt.plan_current_seed = 0;
} else {
set_path_seed_factor_zero();
if (u_sess->attr.attr_sql.plan_mode_seed == RANDOM_PLAN_DEFAULT) {
u_sess->opt_cxt.plan_current_seed = gs_random() % INT_MAX + 1;
} else {
u_sess->opt_cxt.plan_current_seed = u_sess->attr.attr_sql.plan_mode_seed;
}
}
}
the plan stable */
uint32 get_inital_plan_seed()
{
return u_sess->opt_cxt.plan_current_seed;
}
Datum get_plan_seed(PG_FUNCTION_ARGS)
{
PG_RETURN_INT64(u_sess->opt_cxt.plan_prev_seed);
}
static List* set_random_cheapest_path_list(const List* pathlist, List* cheapest_path_list, uint32* random_pathno)
{
unsigned int pathnum = 0;
long random = 0;
Path* randompath = NULL;
pathnum = list_length(pathlist);
if (pathnum == 0)
return cheapest_path_list;
random = get_next_path_random(u_sess->opt_cxt.plan_current_seed);
*random_pathno = random % pathnum;
randompath = (Path*)list_nth(pathlist, *random_pathno);
cheapest_path_list = list_append_unique_ptr(cheapest_path_list, randompath);
return cheapest_path_list;
}
List* get_random_path(RelOptInfo* parent_rel, Path** cheapest_startup_path, Path** cheapest_total_path)
{
ListCell* p = NULL;
List* cheapest_path_list = NIL;
List* nonParamPathlist = NIL;
List* ParamPathlist = NIL;
Path* path = NULL;
unsigned int random_pathno = 0;
if (parent_rel->pathlist == NIL && parent_rel->cheapest_gather_path != NULL) {
*cheapest_startup_path = parent_rel->cheapest_gather_path;
*cheapest_total_path = parent_rel->cheapest_gather_path;
cheapest_path_list = lappend(cheapest_path_list, parent_rel->cheapest_gather_path);
return cheapest_path_list;
}
foreach (p, parent_rel->pathlist) {
path = (Path*)lfirst(p);
if (path->param_info) {
ParamPathlist = lappend(ParamPathlist, path);
continue;
}
nonParamPathlist = lappend(nonParamPathlist, path);
}
if (nonParamPathlist == NIL) {
cheapest_path_list = set_random_cheapest_path_list(ParamPathlist, cheapest_path_list, &random_pathno);
*cheapest_startup_path = (Path*)list_nth(ParamPathlist, random_pathno);
cheapest_path_list = set_random_cheapest_path_list(ParamPathlist, cheapest_path_list, &random_pathno);
*cheapest_total_path = (Path*)list_nth(ParamPathlist, random_pathno);
list_free_ext(ParamPathlist);
return cheapest_path_list;
}
cheapest_path_list = set_random_cheapest_path_list(nonParamPathlist, cheapest_path_list, &random_pathno);
*cheapest_startup_path = (Path*)list_nth(nonParamPathlist, random_pathno);
cheapest_path_list = set_random_cheapest_path_list(nonParamPathlist, cheapest_path_list, &random_pathno);
*cheapest_total_path = (Path*)list_nth(nonParamPathlist, random_pathno);
list_free_ext(nonParamPathlist);
if (ParamPathlist) {
cheapest_path_list = set_random_cheapest_path_list(ParamPathlist, cheapest_path_list, &random_pathno);
list_free_ext(ParamPathlist);
}
return cheapest_path_list;
}
char* get_random_plan_string()
{
char* randomPlanInfo = NULL;
if ((u_sess->attr.attr_sql.plan_mode_seed != OPTIMIZE_PLAN) && u_sess->opt_cxt.plan_current_seed) {
randomPlanInfo = (char*)palloc0(NAMEDATALEN);
int rc = snprintf_s(
randomPlanInfo, NAMEDATALEN, NAMEDATALEN - 1, "Query random seed: %u", u_sess->opt_cxt.plan_current_seed);
securec_check_ss(rc, "\0", "\0");
}
return randomPlanInfo;
}