Files
openGauss-server/src/gausskernel/optimizer/util/autoanalyzer.cpp
2021-09-23 15:19:37 +08:00

277 lines
8.5 KiB
C++

/*
* 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.
* -------------------------------------------------------------------------
*
* autoanalyzer.cpp
* routines for processing auto-analyze in optimizer
* IDENTIFICATION
* src/gausskernel/optimizer/util/autoanalyzer.cpp
*
* -------------------------------------------------------------------------
*/
#include "postgres.h"
#include "knl/knl_variable.h"
#include "commands/dbcommands.h"
#include "executor/node/nodeModifyTable.h"
#include "miscadmin.h"
#include "optimizer/autoanalyzer.h"
#include "postmaster/postmaster.h"
#include "storage/buf/bufmgr.h"
#include "utils/acl.h"
#include "utils/builtins.h"
#include "utils/guc.h"
#include "utils/lsyscache.h"
#include "utils/resowner.h"
/* AutoAnalyze */
#define CHAR_BUF_SIZE 512
#define AUTOANALYZE_LOCKWAIT_TIMEOUT 10000 /* 10s */
static int autoAnalyzeFreeProcess = 10;
/* Constructor */
AutoAnaProcess::AutoAnaProcess(Relation rel) : m_pgconn(NULL), m_res(NULL)
{
m_query = NIL;
StringInfoData str_lockwait_timeout;
initStringInfo(&str_lockwait_timeout);
appendStringInfo(&str_lockwait_timeout, "set lockwait_timeout=%d ;", AUTOANALYZE_LOCKWAIT_TIMEOUT);
m_query = lappend(m_query, str_lockwait_timeout.data);
StringInfoData str_allow_concurrent_tuple_update;
initStringInfo(&str_allow_concurrent_tuple_update);
appendStringInfo(&str_allow_concurrent_tuple_update, "set allow_concurrent_tuple_update='off';");
m_query = lappend(m_query, str_allow_concurrent_tuple_update.data);
StringInfoData str_max_query_retry_times;
initStringInfo(&str_max_query_retry_times);
appendStringInfo(&str_max_query_retry_times, "set max_query_retry_times=0;");
m_query = lappend(m_query, str_max_query_retry_times.data);
StringInfoData str_analyze_command;
initStringInfo(&str_analyze_command);
appendStringInfo(&str_analyze_command,
"analyze %s.%s ;",
quote_identifier(get_namespace_name(rel->rd_rel->relnamespace)),
quote_identifier(NameStr(rel->rd_rel->relname)));
m_query = lappend(m_query, str_analyze_command.data);
}
AutoAnaProcess::~AutoAnaProcess()
{
if (t_thrd.utils_cxt.CurrentResourceOwner == NULL) {
m_res = NULL;
}
PQclear(m_res);
PQfinish(m_pgconn);
if (m_query != NIL) {
list_free_deep(m_query);
}
m_pgconn = NULL;
m_res = NULL;
m_query = NIL;
}
bool AutoAnaProcess::executeSQLCommand(char* queryString)
{
bool result = false;
bool ImmediateInterruptOK_Old = t_thrd.int_cxt.ImmediateInterruptOK;
/* Allow cancel/die interrupts to be processed while waiting */
t_thrd.int_cxt.ImmediateInterruptOK = true;
CHECK_FOR_INTERRUPTS();
m_res = PQexec(m_pgconn, queryString);
t_thrd.int_cxt.ImmediateInterruptOK = ImmediateInterruptOK_Old;
if (PQresultStatus(m_res) != PGRES_COMMAND_OK) {
elog(DEBUG2, "[AUTO-ANALYZE] autoanalyze failed: %s, error: %s", queryString, PQerrorMessage(m_pgconn));
} else {
result = true;
elog(DEBUG2, "[AUTO-ANALYZE] autoanalyze sucess: %s", queryString);
}
PQclear(m_res);
m_res = NULL;
return result;
}
bool AutoAnaProcess::run()
{
char conninfo[CHAR_BUF_SIZE];
int ret;
bool result = false;
ListCell* lc = NULL;
foreach (lc, m_query) {
char* cmd = (char*)lfirst(lc);
elog(DEBUG2, "[AUTO-ANALYZE] autoanalyze start: %s", cmd);
}
ret = snprintf_s(conninfo,
sizeof(conninfo),
sizeof(conninfo) - 1,
"dbname=%s port=%d application_name='auto_analyze' enable_ce=1 ",
get_and_check_db_name(u_sess->proc_cxt.MyDatabaseId, true),
g_instance.attr.attr_network.PostPortNumber);
securec_check_ss_c(ret, "\0", "\0");
m_pgconn = PQconnectdb(conninfo);
/* check to see that the backend connection was successfully made */
if (PQstatus(m_pgconn) == CONNECTION_OK) {
foreach (lc, m_query) {
char* cmd = (char*)lfirst(lc);
result = executeSQLCommand(cmd);
if (!result) {
break;
}
}
} else {
elog(DEBUG2, "[AUTO-ANALYZE] connection to database failed: %s", PQerrorMessage(m_pgconn));
}
PQclear(m_res);
PQfinish(m_pgconn);
m_res = NULL;
m_pgconn = NULL;
return result;
}
void AutoAnaProcess::tear_down()
{
delete u_sess->analyze_cxt.autoanalyze_process;
u_sess->analyze_cxt.autoanalyze_process = NULL;
}
/*
* check_conditions
* check the user privilege for autoanalyze, or if temp table
*/
bool AutoAnaProcess::check_conditions(Relation rel)
{
/* if the rel is invalid, just return false */
if (!rel)
return false;
/* if the rel is temp, just return false */
if (RelationIsLocalTemp(rel))
return false;
/*
* If rel is in read only mode(none redistribution scenario), we skip analyze
* the relation.
*/
if (!u_sess->attr.attr_sql.enable_cluster_resize && RelationInClusterResizingReadOnly(rel))
return false;
AclResult aclresult = pg_class_aclcheck(RelationGetRelid(rel), GetUserId(), ACL_VACUUM);
if (aclresult != ACLCHECK_OK && !(pg_class_ownercheck(RelationGetRelid(rel), GetUserId()) ||
(pg_database_ownercheck(u_sess->proc_cxt.MyDatabaseId, GetUserId()) && !rel->rd_rel->relisshared))) {
return false;
}
return true;
}
bool AutoAnaProcess::runAutoAnalyze(Relation rel)
{
bool getProcess = false;
bool result = false;
TimestampTz start_time = 0;
/* need to show auto-analyze time in explain analyze */
if (u_sess->analyze_cxt.autoanalyze_timeinfo) {
start_time = GetCurrentTimestamp();
}
/* 1 check conditions */
if (!check_conditions(rel)) {
elog(DEBUG2, "[AUTO-ANALYZE] check analyze conditions failed: table \"%s\"", NameStr(rel->rd_rel->relname));
return result;
}
/* 2 get free aa process */
(void)LWLockAcquire(AutoanalyzeLock, LW_EXCLUSIVE);
if (autoAnalyzeFreeProcess > 0) {
getProcess = true;
autoAnalyzeFreeProcess--;
}
(void)LWLockRelease(AutoanalyzeLock);
if (!getProcess) {
/* no free process */
elog(DEBUG2, "[AUTO-ANALYZE] no free autoanalyze process");
return result;
}
/* 3 run analyze */
Assert(u_sess->analyze_cxt.autoanalyze_process == NULL);
u_sess->analyze_cxt.autoanalyze_process = New(CurrentMemoryContext) AutoAnaProcess(rel);
result = u_sess->analyze_cxt.autoanalyze_process->run();
tear_down();
/* 4 release free aa process */
LWLockAcquire(AutoanalyzeLock, LW_EXCLUSIVE);
autoAnalyzeFreeProcess++;
LWLockRelease(AutoanalyzeLock);
/* 5 show auto-analyze time in explain analyze when success */
if (u_sess->analyze_cxt.autoanalyze_timeinfo && result) {
long secs;
long msecs;
int usecs;
TimestampDifference(start_time, GetCurrentTimestamp(), &secs, &usecs);
msecs = usecs / 1000L;
msecs = secs * 1000 + msecs;
usecs = usecs % 1000;
MemoryContext oldcontext = MemoryContextSwitchTo(u_sess->temp_mem_cxt);
appendStringInfo(u_sess->analyze_cxt.autoanalyze_timeinfo,
"\"%s.%s\" %ld.%03dms ",
get_namespace_name(rel->rd_rel->relnamespace),
NameStr(rel->rd_rel->relname),
msecs,
usecs);
(void)MemoryContextSwitchTo(oldcontext);
}
return result;
}
void AutoAnaProcess::cancelAutoAnalyze()
{
/* auto-analyzing now */
if (u_sess->analyze_cxt.autoanalyze_process != NULL) {
tear_down();
/* release free aa process */
(void)LWLockAcquire(AutoanalyzeLock, LW_EXCLUSIVE);
autoAnalyzeFreeProcess++;
LWLockRelease(AutoanalyzeLock);
}
/* clean explain info if exists */
if (u_sess->analyze_cxt.autoanalyze_timeinfo != NULL) {
pfree_ext(u_sess->analyze_cxt.autoanalyze_timeinfo->data);
pfree_ext(u_sess->analyze_cxt.autoanalyze_timeinfo);
u_sess->analyze_cxt.autoanalyze_timeinfo = NULL;
}
}
/* Just for query cancel */
void CancelAutoAnalyze()
{
AutoAnaProcess::cancelAutoAnalyze();
}