forked from huawei/openGauss-server
753 lines
26 KiB
C++
753 lines
26 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.
|
|
* -------------------------------------------------------------------------
|
|
*
|
|
* streamMain.cpp
|
|
* stream main Interface.
|
|
*
|
|
* IDENTIFICATION
|
|
* src/gausskernel/process/stream/streamMain.cpp
|
|
*
|
|
* -------------------------------------------------------------------------
|
|
*/
|
|
#include "postgres.h"
|
|
|
|
#include "access/dfs/dfs_am.h"
|
|
#include "access/gtm.h"
|
|
#include "access/printtup.h"
|
|
#include "distributelayer/streamMain.h"
|
|
#include "distributelayer/streamProducer.h"
|
|
#include "executor/execStream.h"
|
|
#include "executor/executor.h"
|
|
#include "knl/knl_variable.h"
|
|
#include "libpq/libpq.h"
|
|
#include "miscadmin.h"
|
|
#include "pgxc/pgxc.h"
|
|
#include "postmaster/postmaster.h"
|
|
#include "replication/dataqueue.h"
|
|
#include "storage/ipc.h"
|
|
#include "storage/pmsignal.h"
|
|
#include "storage/proc.h"
|
|
#include "tcop/tcopprot.h"
|
|
#include "threadpool/threadpool.h"
|
|
#include "utils/memtrack.h"
|
|
#include "utils/postinit.h"
|
|
#include "utils/ps_status.h"
|
|
#include "utils/snapmgr.h"
|
|
#include "utils/syscache.h"
|
|
#include "utils/timestamp.h"
|
|
#include "instruments/instr_handle_mgr.h"
|
|
|
|
extern void CodeGenThreadInitialize();
|
|
extern void InitRecursiveCTEGlobalVariables(const PlannedStmt* planstmt);
|
|
|
|
static void InitStreamThread();
|
|
static void InitStreamPath();
|
|
static void InitStreamSignal();
|
|
static void InitStreamResource();
|
|
static void HandleStreamSigjmp();
|
|
static void execute_stream_plan(StreamProducer* producer);
|
|
static void execute_stream_end(StreamProducer* producer);
|
|
static void StreamQuitAndClean(int code, Datum arg);
|
|
static void ResetStreamWorkerInfo();
|
|
|
|
/* ----------------------------------------------------------------
|
|
* StreamMain
|
|
* stream thread main entrance
|
|
* ----------------------------------------------------------------
|
|
*/
|
|
int StreamMain()
|
|
{
|
|
sigjmp_buf local_sigjmp_buf;
|
|
|
|
InitStreamThread();
|
|
|
|
SetProcessingMode(NormalProcessing);
|
|
|
|
on_proc_exit(StreamQuitAndClean, 0);
|
|
|
|
/*
|
|
* process any libraries that should be preloaded at backend start (this
|
|
* likewise can't be done until GUC settings are complete)
|
|
*/
|
|
process_local_preload_libraries();
|
|
|
|
int curTryCounter;
|
|
int* oldTryCounter = NULL;
|
|
if (sigsetjmp(local_sigjmp_buf, 1) != 0) {
|
|
t_thrd.int_cxt.ignoreBackendSignal = false;
|
|
/* reset STP thread local valueables */
|
|
stp_reset_opt_values();
|
|
|
|
gstrace_tryblock_exit(true, oldTryCounter);
|
|
HandleStreamSigjmp();
|
|
if (IS_THREAD_POOL_STREAM) {
|
|
t_thrd.threadpool_cxt.stream->CleanUp();
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
oldTryCounter = gstrace_tryblock_entry(&curTryCounter);
|
|
|
|
MemoryContext oldMemory = MemoryContextSwitchTo(
|
|
THREAD_GET_MEM_CXT_GROUP(MEMORY_CONTEXT_EXECUTOR));
|
|
CodeGenThreadInitialize();
|
|
(void)MemoryContextSwitchTo(oldMemory);
|
|
|
|
/* We can now handle ereport(ERROR) */
|
|
t_thrd.log_cxt.PG_exception_stack = &local_sigjmp_buf;
|
|
|
|
if (IS_THREAD_POOL_STREAM) {
|
|
ResetStreamWorkerInfo();
|
|
}
|
|
|
|
while (true) {
|
|
if (IS_THREAD_POOL_STREAM) {
|
|
pgstat_report_activity(STATE_IDLE, NULL);
|
|
pgstat_report_waitstatus(STATE_WAIT_COMM);
|
|
t_thrd.threadpool_cxt.stream->WaitMission();
|
|
pgstat_report_waitstatus(STATE_WAIT_UNDEFINED);
|
|
}
|
|
|
|
pgstat_report_queryid(u_sess->debug_query_id);
|
|
pgstat_report_smpid(u_sess->stream_cxt.smp_id);
|
|
timeInfoRecordStart();
|
|
|
|
/* Wait thread ID ready */
|
|
u_sess->stream_cxt.producer_obj->waitThreadIdReady();
|
|
|
|
execute_stream_plan(u_sess->stream_cxt.producer_obj);
|
|
execute_stream_end(u_sess->stream_cxt.producer_obj);
|
|
WLMReleaseNodeFromHash();
|
|
WLMReleaseIoInfoFromHash();
|
|
/* Reset here so that we can get debug_query_string when Stream thread is in Sync point */
|
|
t_thrd.postgres_cxt.debug_query_string = NULL;
|
|
|
|
/*
|
|
* Note that parent thread will do commit or abort transaction.
|
|
* Stream thread should not change clog file
|
|
*/
|
|
ResetTransactionInfo();
|
|
|
|
if (IS_THREAD_POOL_STREAM) {
|
|
t_thrd.threadpool_cxt.stream->CleanUp();
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
|
|
CloseGTM();
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void InitStreamThread()
|
|
{
|
|
initRandomState(0, GetCurrentTimestamp());
|
|
|
|
t_thrd.proc_cxt.MyProcPid = gs_thread_self();
|
|
u_sess->exec_cxt.under_stream_runtime = true;
|
|
t_thrd.codegen_cxt.g_runningInFmgr = false;
|
|
FrontendProtocol = PG_PROTOCOL_LATEST;
|
|
u_sess->attr.attr_common.remoteConnType = REMOTE_CONN_DATANODE;
|
|
|
|
InitStreamPath();
|
|
|
|
InitStreamSignal();
|
|
|
|
/* Early initialization */
|
|
BaseInit();
|
|
|
|
/* We need to allow SIGINT, etc during the initial transaction */
|
|
gs_signal_setmask(&t_thrd.libpq_cxt.UnBlockSig, NULL);
|
|
|
|
/* Initialize the memory tracking information */
|
|
MemoryTrackingInit();
|
|
|
|
if (!IS_THREAD_POOL_STREAM) {
|
|
ExtractProduerInfo();
|
|
t_thrd.proc_cxt.PostInit->SetDatabaseAndUser(
|
|
u_sess->stream_cxt.producer_obj->getDbName(), InvalidOid, u_sess->stream_cxt.producer_obj->getUserName());
|
|
repair_guc_variables();
|
|
}
|
|
t_thrd.proc_cxt.PostInit->InitStreamWorker();
|
|
|
|
InitVecFuncMap();
|
|
|
|
InitStreamResource();
|
|
}
|
|
|
|
static void InitStreamPath()
|
|
{
|
|
/* Compute paths, if we didn't inherit them from postmaster */
|
|
if (my_exec_path[0] == '\0') {
|
|
if (find_my_exec("postgres", my_exec_path) < 0)
|
|
ereport(FATAL, (errmsg("postgres: could not locate my own executable path")));
|
|
}
|
|
|
|
if (t_thrd.proc_cxt.pkglib_path[0] == '\0')
|
|
get_pkglib_path(my_exec_path, t_thrd.proc_cxt.pkglib_path);
|
|
}
|
|
|
|
static void InitStreamSignal()
|
|
{
|
|
(void)gspqsignal(SIGINT, StatementCancelHandler);
|
|
(void)gspqsignal(SIGTERM, die);
|
|
(void)gspqsignal(SIGALRM, handle_sig_alarm); /* timeout conditions */
|
|
(void)gspqsignal(SIGUSR1, procsignal_sigusr1_handler);
|
|
(void)gs_signal_unblock_sigusr2();
|
|
|
|
if (IsUnderPostmaster) {
|
|
/* We allow SIGQUIT (quickdie) at all times */
|
|
(void)sigdelset(&t_thrd.libpq_cxt.BlockSig, SIGQUIT);
|
|
}
|
|
}
|
|
|
|
static void InitStreamResource()
|
|
{
|
|
/*
|
|
* Create the memory context we will use in the main loop.
|
|
*
|
|
* t_thrd.mem_cxt.msg_mem_cxt is reset once per iteration of the main loop, ie, upon
|
|
* completion of processing of each command message from the client.
|
|
*/
|
|
t_thrd.mem_cxt.msg_mem_cxt = AllocSetContextCreate(t_thrd.top_mem_cxt,
|
|
"MessageContext",
|
|
ALLOCSET_DEFAULT_MINSIZE,
|
|
ALLOCSET_DEFAULT_INITSIZE,
|
|
ALLOCSET_DEFAULT_MAXSIZE);
|
|
|
|
t_thrd.mem_cxt.mask_password_mem_cxt = AllocSetContextCreate(t_thrd.top_mem_cxt,
|
|
"MaskPasswordCtx",
|
|
ALLOCSET_DEFAULT_MINSIZE,
|
|
ALLOCSET_DEFAULT_INITSIZE,
|
|
ALLOCSET_DEFAULT_MAXSIZE);
|
|
|
|
t_thrd.utils_cxt.TopResourceOwner = ResourceOwnerCreate(NULL, "stream thread", MEMORY_CONTEXT_EXECUTOR);
|
|
t_thrd.utils_cxt.CurrentResourceOwner = t_thrd.utils_cxt.TopResourceOwner;
|
|
|
|
if (t_thrd.mem_cxt.postmaster_mem_cxt) {
|
|
MemoryContextDelete(t_thrd.mem_cxt.postmaster_mem_cxt);
|
|
t_thrd.mem_cxt.postmaster_mem_cxt = NULL;
|
|
}
|
|
}
|
|
|
|
void ExtractProduerInfo()
|
|
{
|
|
if (u_sess->stream_cxt.producer_obj == NULL) {
|
|
return;
|
|
}
|
|
u_sess->wlm_cxt->wlm_params = u_sess->stream_cxt.producer_obj->getWlmParams();
|
|
u_sess->instr_cxt.gs_query_id->procId = u_sess->stream_cxt.producer_obj->getExplainThreadid();
|
|
u_sess->exec_cxt.need_track_resource = u_sess->stream_cxt.producer_obj->getExplainTrack();
|
|
u_sess->stream_cxt.producer_obj->getUniqueSQLKey(&u_sess->unique_sql_cxt.unique_sql_id,
|
|
&u_sess->unique_sql_cxt.unique_sql_user_id, &u_sess->unique_sql_cxt.unique_sql_cn_id);
|
|
|
|
WLMGeneralParam *g_wlm_params = &u_sess->wlm_cxt->wlm_params;
|
|
errno_t ret = sprintf_s(u_sess->wlm_cxt->control_group,
|
|
sizeof(u_sess->wlm_cxt->control_group), "%s", g_wlm_params->cgroup);
|
|
securec_check_ss(ret, "\0", "\0");
|
|
|
|
/* Get the node group information */
|
|
t_thrd.wlm_cxt.thread_node_group = WLMGetNodeGroupFromHTAB(g_wlm_params->ngroup);
|
|
t_thrd.wlm_cxt.thread_climgr = &t_thrd.wlm_cxt.thread_node_group->climgr;
|
|
t_thrd.wlm_cxt.thread_srvmgr = &t_thrd.wlm_cxt.thread_node_group->srvmgr;
|
|
|
|
/* Set the right pgxcnodeid */
|
|
u_sess->pgxc_cxt.PGXCNodeId = u_sess->stream_cxt.producer_obj->getPgxcNodeId();
|
|
u_sess->instr_cxt.global_instr = u_sess->stream_cxt.producer_obj->getStreamInstrumentation();
|
|
u_sess->proc_cxt.MyProcPort->database_name = u_sess->stream_cxt.producer_obj->getDbName();
|
|
u_sess->proc_cxt.MyProcPort->user_name = u_sess->stream_cxt.producer_obj->getUserName();
|
|
|
|
/* runtimethreadinstr */
|
|
if (u_sess->instr_cxt.global_instr) {
|
|
Assert(u_sess->instr_cxt.thread_instr == NULL);
|
|
int segmentId = u_sess->stream_cxt.producer_obj->getPlan()->planTree->plan_node_id;
|
|
u_sess->instr_cxt.thread_instr = u_sess->instr_cxt.global_instr->allocThreadInstrumentation(segmentId);
|
|
}
|
|
|
|
u_sess->stream_cxt.producer_obj->netInit();
|
|
u_sess->stream_cxt.producer_obj->setThreadInit(true);
|
|
#ifdef ENABLE_MULTIPLE_NODES
|
|
u_sess->stream_cxt.producer_obj->initSkewState();
|
|
#endif
|
|
|
|
if (u_sess->stream_cxt.producer_obj->isDummy()) {
|
|
u_sess->exec_cxt.executorStopFlag = true;
|
|
u_sess->stream_cxt.dummy_thread = true;
|
|
} else {
|
|
u_sess->exec_cxt.executorStopFlag = false;
|
|
u_sess->stream_cxt.dummy_thread = false;
|
|
}
|
|
|
|
/* stream workers share the same session memory entry as their parents */
|
|
t_thrd.shemem_ptr_cxt.mySessionMemoryEntry = u_sess->stream_cxt.producer_obj->getSessionMemory();
|
|
if (t_thrd.proc != NULL) {
|
|
t_thrd.proc->sessMemorySessionid = u_sess->stream_cxt.producer_obj->getParentSessionid();
|
|
Assert(t_thrd.proc->sessMemorySessionid == t_thrd.shemem_ptr_cxt.mySessionMemoryEntry->sessionid);
|
|
}
|
|
|
|
/* Initialize the global variables for recursive */
|
|
InitRecursiveCTEGlobalVariables(u_sess->stream_cxt.producer_obj->getPlan());
|
|
|
|
STREAM_LOG(DEBUG2, "enter StreamMain, StreamKey(%lu, %u, %u)",
|
|
u_sess->stream_cxt.producer_obj->getKey().queryId,
|
|
u_sess->stream_cxt.producer_obj->getKey().planNodeId,
|
|
u_sess->stream_cxt.producer_obj->getKey().smpIdentifier);
|
|
}
|
|
|
|
static void HandleStreamSigjmp()
|
|
{
|
|
pgstat_report_waitstatus(STATE_WAIT_UNDEFINED);
|
|
t_thrd.pgxc_cxt.GlobalNetInstr = NULL;
|
|
|
|
/* output the memory tracking information when error happened */
|
|
MemoryTrackingOutputFile();
|
|
|
|
/* Since not using PG_TRY, must reset error stack by hand */
|
|
t_thrd.log_cxt.error_context_stack = NULL;
|
|
/* reset buffer strategy flag */
|
|
t_thrd.storage_cxt.is_btree_split = false;
|
|
|
|
/* Prevent interrupts while cleaning up */
|
|
HOLD_INTERRUPTS();
|
|
|
|
/*
|
|
* Turn off these interrupts too. This is only needed here and not in
|
|
* other exception-catching places since these interrupts are only
|
|
* enabled while we wait for client input.
|
|
*/
|
|
t_thrd.postgres_cxt.DoingCommandRead = false;
|
|
|
|
/*
|
|
* Abort the current transaction in order to recover.
|
|
*/
|
|
ereport(DEBUG1,
|
|
(errmsg("stream thread %lu end transaction " XID_FMT " abnormally",
|
|
t_thrd.proc_cxt.MyProcPid,
|
|
GetCurrentTransactionIdIfAny())));
|
|
|
|
/*
|
|
* when clearing the BCM encounter ERROR, we should ResetBCMArray, or it
|
|
* will enter ClearBCMArray infinite loop, then coredump.
|
|
*/
|
|
ResetBCMArray();
|
|
|
|
/* release operator-level hash table in memory */
|
|
releaseExplainTable();
|
|
|
|
/* Mark recursive vfd is invalid before aborting transaction. */
|
|
StreamNodeGroup::MarkRecursiveVfdInvalid();
|
|
|
|
AbortCurrentTransaction();
|
|
|
|
LWLockReleaseAll();
|
|
|
|
if (u_sess->stream_cxt.producer_obj != NULL) {
|
|
u_sess->stream_cxt.producer_obj->reportError();
|
|
}
|
|
|
|
MemoryContextSwitchTo(THREAD_GET_MEM_CXT_GROUP(MEMORY_CONTEXT_DEFAULT));
|
|
FlushErrorState();
|
|
|
|
if (ENABLE_WORKLOAD_CONTROL)
|
|
WLMResetStatInfo4Exception();
|
|
|
|
RESUME_INTERRUPTS();
|
|
|
|
timeInfoRecordEnd();
|
|
StreamNodeGroup::syncQuit(STREAM_ERROR);
|
|
}
|
|
|
|
static void execute_stream_plan(StreamProducer* producer)
|
|
{
|
|
/*
|
|
* Start up a transaction command. All queries generated by the
|
|
* query_string will be in this same command block, *unless* we find a
|
|
* BEGIN/COMMIT/ABORT statement; we have to force a new xact command after
|
|
* one of those, else bad things will happen in xact.c. (Note that this
|
|
* will normally change current memory context.)
|
|
*/
|
|
start_xact_command();
|
|
|
|
producer->setUpStreamTxnEnvironment();
|
|
|
|
PlannedStmt* planstmt = producer->getPlan();
|
|
CommandDest dest = producer->getDest();
|
|
bool save_log_statement_stats = u_sess->attr.attr_common.log_statement_stats;
|
|
bool was_logged = false;
|
|
bool isTopLevel = false;
|
|
const char* commandTag = NULL;
|
|
char completionTag[COMPLETION_TAG_BUFSIZE];
|
|
Portal portal = NULL;
|
|
DestReceiver* receiver = NULL;
|
|
int16 format;
|
|
char msec_str[32];
|
|
|
|
t_thrd.postgres_cxt.debug_query_string = planstmt->query_string;
|
|
pgstat_report_activity(STATE_RUNNING, t_thrd.postgres_cxt.debug_query_string);
|
|
/* Use planNodeId as thread_level, same as the key which SCTP use for send/receive */
|
|
pgstat_report_parent_sessionid(producer->getParentSessionid(), producer->getKey().planNodeId);
|
|
|
|
if (u_sess->instr_cxt.global_instr &&
|
|
u_sess->instr_cxt.perf_monitor_enable) // Don't use perf util you set has_use_perf = true
|
|
CPUMon::Initialize(CMON_GENERAL);
|
|
|
|
/*
|
|
* We use save_log_statement_stats so ShowUsage doesn't report incorrect
|
|
* results because ResetUsage wasn't called.
|
|
*/
|
|
if (save_log_statement_stats)
|
|
ResetUsage();
|
|
|
|
isTopLevel = true;
|
|
|
|
// For now plan shipping is used only for SELECTs, in future
|
|
// we should remove this hard coding and get the tag automatically
|
|
commandTag = "SELECT";
|
|
|
|
set_ps_display(commandTag, false);
|
|
|
|
BeginCommand(commandTag, dest);
|
|
|
|
/*
|
|
* If we are in an aborted transaction, reject all commands except
|
|
* COMMIT/ABORT. It is important that this test occur before we try
|
|
* to do parse analysis, rewrite, or planning, since all those phases
|
|
* try to do database accesses, which may fail in abort state. (It
|
|
* might be safe to allow some additional utility commands in this
|
|
* state, but not many...)
|
|
*/
|
|
if (IsAbortedTransactionBlockState()) // &&
|
|
ereport(ERROR,
|
|
(errcode(ERRCODE_IN_FAILED_SQL_TRANSACTION),
|
|
errmsg("current transaction is aborted, "
|
|
"commands ignored until end of transaction block, firstChar[%c]",
|
|
u_sess->proc_cxt.firstChar),
|
|
errdetail_abort()));
|
|
|
|
/* Make sure we are in a transaction command */
|
|
start_xact_command();
|
|
|
|
/* If we got a cancel signal in parsing or prior command, quit */
|
|
CHECK_FOR_INTERRUPTS();
|
|
|
|
/*
|
|
* Create unnamed portal to run the query or queries in. If there
|
|
* already is one, silently drop it.
|
|
*/
|
|
portal = CreatePortal("", true, true);
|
|
/* Don't display the portal in pg_cursors */
|
|
portal->visible = false;
|
|
|
|
u_sess->instr_cxt.global_instr = producer->getStreamInstrumentation();
|
|
u_sess->instr_cxt.obs_instr = producer->getOBSInstrumentation();
|
|
if (u_sess->instr_cxt.obs_instr)
|
|
u_sess->instr_cxt.p_OBS_instr_valid = u_sess->instr_cxt.obs_instr->m_p_globalOBSInstrument_valid;
|
|
|
|
PortalDefineQuery(portal, NULL, "DUMMY", commandTag, lappend(NULL, planstmt), NULL);
|
|
|
|
/*
|
|
* Start the portal. No parameters here.
|
|
*/
|
|
PortalStart(portal, producer->getParams(), 0, producer->getSnapShot());
|
|
format = 0;
|
|
PortalSetResultFormat(portal, 1, &format);
|
|
|
|
receiver = CreateDestReceiver(dest);
|
|
if (dest >= DestTupleBroadCast)
|
|
SetStreamReceiverParams(receiver, producer, portal);
|
|
|
|
/*
|
|
* Run the portal to completion, and then drop it (and the receiver).
|
|
*/
|
|
(void)PortalRun(portal, FETCH_ALL, isTopLevel, receiver, receiver, completionTag);
|
|
|
|
(*receiver->rDestroy)(receiver);
|
|
|
|
PortalDrop(portal, false);
|
|
|
|
finish_xact_command();
|
|
|
|
/*
|
|
* Emit duration logging if appropriate.
|
|
*/
|
|
switch (check_log_duration(msec_str, was_logged)) {
|
|
case 1:
|
|
ereport(LOG, (errmsg("duration: %s ms", msec_str), errhidestmt(true)));
|
|
break;
|
|
case 2:
|
|
ereport(LOG,
|
|
(errmsg("duration: %s ms statement: %s", msec_str, "TODO: deparse plan"), // vam query_string),
|
|
errhidestmt(true)
|
|
// vam errdetail_execute(parsetree_list)
|
|
));
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (save_log_statement_stats)
|
|
ShowUsage("QUERY STATISTICS");
|
|
}
|
|
|
|
static void execute_stream_end(StreamProducer* producer)
|
|
{
|
|
int consumer_number;
|
|
int i, res;
|
|
|
|
consumer_number = producer->getConnNum();
|
|
StreamTransport** transport = producer->getTransport();
|
|
|
|
// prepare an end message to all the consumer backend thread.
|
|
//
|
|
// if is dummy, do not bother send
|
|
if (producer->isDummy() == false) {
|
|
for (i = 0; i < consumer_number; i++) {
|
|
if (producer->netSwitchDest(i)) {
|
|
if (PG_PROTOCOL_MAJOR(FrontendProtocol) >= 3) {
|
|
StringInfoData buf;
|
|
|
|
pq_beginmessage(&buf, 'Z');
|
|
pq_sendbyte(&buf, TransactionBlockStatusCode());
|
|
pq_endmessage(&buf);
|
|
} else if (PG_PROTOCOL_MAJOR(FrontendProtocol) >= 2)
|
|
pq_putemptymessage('Z');
|
|
/* Flush output at end of cycle in any case. */
|
|
res = pq_flush();
|
|
if (res == EOF) {
|
|
transport[i]->release();
|
|
}
|
|
producer->netStatusSave(i);
|
|
}
|
|
}
|
|
}
|
|
producer->finalizeLocalStream();
|
|
timeInfoRecordEnd();
|
|
StreamNodeGroup::syncQuit(STREAM_COMPLETE);
|
|
ForgetRegisterStreamSnapshots();
|
|
}
|
|
|
|
/*
|
|
* Called when the Stream thread is ending.
|
|
*/
|
|
static void StreamQuitAndClean(int code, Datum arg)
|
|
{
|
|
/* Close connection with GTM, if active */
|
|
CloseGTM();
|
|
|
|
/* Free remote xact state */
|
|
free_RemoteXactState();
|
|
}
|
|
|
|
// reset some flag related to stream
|
|
void ResetStreamEnv()
|
|
{
|
|
t_thrd.subrole = NO_SUBROLE;
|
|
u_sess->stream_cxt.dummy_thread = false;
|
|
u_sess->exec_cxt.executorStopFlag = false;
|
|
u_sess->stream_cxt.global_obj = NULL;
|
|
u_sess->stream_cxt.producer_obj = NULL;
|
|
u_sess->instr_cxt.global_instr = NULL;
|
|
u_sess->instr_cxt.thread_instr = NULL;
|
|
u_sess->exec_cxt.under_stream_runtime = false;
|
|
u_sess->stream_cxt.in_waiting_quit = false;
|
|
u_sess->stream_cxt.enter_sync_point = false;
|
|
t_thrd.pgxc_cxt.GlobalNetInstr = NULL;
|
|
|
|
/*
|
|
* When gaussdb backend running in Query or Operator level, we are going to use global
|
|
* variable notplanshipping to mark current query is not plan shipping, so we do string
|
|
* initialization here
|
|
*/
|
|
u_sess->opt_cxt.not_shipping_info->need_log = true;
|
|
errno_t errorno = memset_s(
|
|
u_sess->opt_cxt.not_shipping_info->not_shipping_reason, NOTPLANSHIPPING_LENGTH, '\0', NOTPLANSHIPPING_LENGTH);
|
|
securec_check_c(errorno, "\0", "\0");
|
|
|
|
t_thrd.postgres_cxt.table_created_in_CTAS = false;
|
|
|
|
if (IS_PGXC_COORDINATOR) {
|
|
u_sess->exec_cxt.need_track_resource = false;
|
|
}
|
|
|
|
u_sess->instr_cxt.gs_query_id->queryId = 0;
|
|
|
|
u_sess->wlm_cxt->local_foreign_respool = NULL;
|
|
t_thrd.postmaster_cxt.forceNoSeparate = false;
|
|
|
|
u_sess->pcache_cxt.gpc_remote_msg = false;
|
|
|
|
t_thrd.postgres_cxt.gpc_fisrt_send_clean = true;
|
|
|
|
if (IS_PGXC_COORDINATOR) {
|
|
WLMStatusTag status = t_thrd.wlm_cxt.collect_info->status;
|
|
if (!(status == WLM_STATUS_FINISHED || status == WLM_STATUS_ABORT))
|
|
return;
|
|
}
|
|
|
|
if (IS_PGXC_DATANODE) {
|
|
WLMStatusTag status = t_thrd.wlm_cxt.dn_cpu_detail->status;
|
|
if (!(status == WLM_STATUS_FINISHED || status == WLM_STATUS_ABORT))
|
|
return;
|
|
}
|
|
|
|
t_thrd.shemem_ptr_cxt.mySessionMemoryEntry->initMemInChunks = t_thrd.utils_cxt.trackedMemChunks;
|
|
t_thrd.shemem_ptr_cxt.mySessionMemoryEntry->queryMemInChunks = t_thrd.utils_cxt.trackedMemChunks;
|
|
t_thrd.shemem_ptr_cxt.mySessionMemoryEntry->peakChunksQuery = t_thrd.utils_cxt.trackedMemChunks;
|
|
t_thrd.shemem_ptr_cxt.mySessionMemoryEntry->spillCount = 0;
|
|
t_thrd.shemem_ptr_cxt.mySessionMemoryEntry->spillSize = 0;
|
|
t_thrd.shemem_ptr_cxt.mySessionMemoryEntry->broadcastSize = 0;
|
|
t_thrd.shemem_ptr_cxt.mySessionMemoryEntry->estimate_time = 0;
|
|
t_thrd.shemem_ptr_cxt.mySessionMemoryEntry->estimate_memory = 0;
|
|
t_thrd.shemem_ptr_cxt.mySessionMemoryEntry->warning = 0;
|
|
t_thrd.shemem_ptr_cxt.mySessionMemoryEntry->iscomplex = 0;
|
|
t_thrd.shemem_ptr_cxt.mySessionMemoryEntry->dnStartTime = GetCurrentTimestamp();
|
|
t_thrd.shemem_ptr_cxt.mySessionMemoryEntry->dnEndTime = 0;
|
|
|
|
pfree_ext(t_thrd.shemem_ptr_cxt.mySessionMemoryEntry->query_plan);
|
|
t_thrd.shemem_ptr_cxt.mySessionMemoryEntry->plan_size = 0;
|
|
pfree_ext(t_thrd.shemem_ptr_cxt.mySessionMemoryEntry->query_plan_issue);
|
|
|
|
t_thrd.wlm_cxt.collect_info->status = WLM_STATUS_RESERVE;
|
|
t_thrd.wlm_cxt.dn_cpu_detail->status = WLM_STATUS_RESERVE;
|
|
|
|
t_thrd.sig_cxt.gs_sigale_check_type = SIGNAL_CHECK_NONE;
|
|
t_thrd.sig_cxt.session_id = 0;
|
|
}
|
|
|
|
void SetStreamWorkerInfo(StreamProducer* proObj)
|
|
{
|
|
if (proObj == NULL) {
|
|
return;
|
|
}
|
|
|
|
u_sess->stream_cxt.producer_obj = proObj;
|
|
u_sess->stream_cxt.smp_id = proObj->getKey().smpIdentifier;
|
|
u_sess->stream_cxt.producer_dop = proObj->getParallelDesc().producerDop;
|
|
u_sess->debug_query_id = proObj->getKey().queryId;
|
|
u_sess->utils_cxt.sync_guc_variables = u_sess->stream_cxt.producer_obj->get_sync_guc_variables();
|
|
// set the stopFlag;
|
|
u_sess->stream_cxt.global_obj = u_sess->stream_cxt.producer_obj->getNodeGroup();
|
|
u_sess->stream_cxt.global_obj->setStopFlagPoint(
|
|
u_sess->stream_cxt.producer_obj->getNodeGroupIdx(), &u_sess->exec_cxt.executorStopFlag);
|
|
}
|
|
|
|
static void ResetStreamWorkerInfo()
|
|
{
|
|
u_sess->stream_cxt.producer_obj = NULL;
|
|
u_sess->stream_cxt.global_obj = NULL;
|
|
}
|
|
|
|
static void StoreStreamSyncParam(StreamSyncParam *syncParam)
|
|
{
|
|
syncParam->TempNamespace = u_sess->catalog_cxt.myTempNamespace;
|
|
syncParam->TempToastNamespace = u_sess->catalog_cxt.myTempToastNamespace;
|
|
syncParam->IsBinaryUpgrade = u_sess->proc_cxt.IsBinaryUpgrade;
|
|
if (module_logging_is_on(MOD_COMM_IPC) && (t_thrd.proc && t_thrd.proc->workingVersionNum >= 92060)) {
|
|
syncParam->CommIpcLog = true;
|
|
} else {
|
|
syncParam->CommIpcLog = false;
|
|
}
|
|
}
|
|
|
|
void RestoreStreamSyncParam(StreamSyncParam *syncParam)
|
|
{
|
|
u_sess->catalog_cxt.myTempNamespace = syncParam->TempNamespace;
|
|
u_sess->catalog_cxt.myTempToastNamespace = syncParam->TempToastNamespace;
|
|
u_sess->proc_cxt.IsBinaryUpgrade = syncParam->IsBinaryUpgrade;
|
|
if (syncParam->CommIpcLog == true) {
|
|
module_logging_enable_comm(MOD_COMM_IPC);
|
|
}
|
|
}
|
|
|
|
ThreadId ApplyStreamThread(StreamProducer *producer)
|
|
{
|
|
ThreadId tid = InvalidTid;
|
|
|
|
producer->setParentSessionid(t_thrd.proc->sessMemorySessionid);
|
|
StoreStreamSyncParam(&producer->m_syncParam);
|
|
|
|
if (t_thrd.threadpool_cxt.group != NULL) {
|
|
tid = t_thrd.threadpool_cxt.group->GetStreamFromPool(producer);
|
|
STREAM_LOG(DEBUG2, "[StreamPool] Apply thread %lu query_id %lu, tlevel %u, smpid %u",
|
|
tid,
|
|
producer->getKey().queryId,
|
|
producer->getKey().planNodeId,
|
|
producer->getKey().smpIdentifier);
|
|
} else {
|
|
producer->setChildSlot(AssignPostmasterChildSlot());
|
|
tid = initialize_util_thread(STREAM_WORKER, producer);
|
|
}
|
|
|
|
return tid;
|
|
}
|
|
|
|
void RestoreStream()
|
|
{
|
|
/*
|
|
* We should restoreStreamEnter after release the memory context.
|
|
* Make sure top consumer thread exit after stream thread.
|
|
*/
|
|
if (StreamThreadAmI() && u_sess->stream_cxt.global_obj) {
|
|
/*
|
|
* Set CurrentResourceOwner to NULL or will core dumped in ResourceOwnerEnlargePthreadMutex
|
|
* case t_thrd.top_mem_cxt has been set NULL.
|
|
*/
|
|
t_thrd.utils_cxt.CurrentResourceOwner = NULL;
|
|
u_sess->stream_cxt.global_obj->restoreStreamEnter();
|
|
u_sess->stream_cxt.global_obj = NULL;
|
|
}
|
|
}
|
|
|
|
void StreamExit()
|
|
{
|
|
if (u_sess == t_thrd.fake_session) {
|
|
return;
|
|
}
|
|
|
|
/* Reset to Local vfd if we have attach it to global vfdcache */
|
|
ResetToLocalVfdCache();
|
|
|
|
CleanupDfsHandlers(true);
|
|
|
|
closeAllVfds();
|
|
|
|
AtProcExit_Buffers(0, 0);
|
|
ShutdownPostgres(0, 0);
|
|
AtProcExit_Files(0, 0);
|
|
StreamQuitAndClean(0, 0);
|
|
|
|
RestoreStream();
|
|
|
|
/* release memory context and reset flags. */
|
|
MemoryContextReset(u_sess->syscache_cxt.SysCacheMemCxt);
|
|
|
|
errno_t rc = EOK;
|
|
rc = memset_s(u_sess->syscache_cxt.SysCache, sizeof(CatCache*) * SysCacheSize,
|
|
0, sizeof(CatCache*) * SysCacheSize);
|
|
securec_check(rc, "\0", "\0");
|
|
rc = memset_s(u_sess->syscache_cxt.SysCacheRelationOid, sizeof(Oid) * SysCacheSize,
|
|
0, sizeof(Oid) * SysCacheSize);
|
|
securec_check(rc, "\0", "\0");
|
|
|
|
/* release statement_cxt */
|
|
if (t_thrd.proc_cxt.MyBackendId != InvalidBackendId) {
|
|
release_statement_context(t_thrd.shemem_ptr_cxt.MyBEEntry, __FUNCTION__, __LINE__);
|
|
}
|
|
|
|
free_session_context(u_sess);
|
|
}
|