277 lines
8.5 KiB
C++
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();
|
|
}
|