From 114c58d19fd5a23db036e52c6b85f0979f42e5c0 Mon Sep 17 00:00:00 2001 From: TotaJ Date: Wed, 28 Apr 2021 16:44:47 +0800 Subject: [PATCH 1/3] fix GPC bug with memoryleak and make it suitable for SQLBYPASS --- src/bin/gs_guc/cluster_guc.conf | 1 + src/common/backend/utils/cache/plancache.cpp | 54 +- src/common/backend/utils/misc/guc.cpp | 15 + .../backend/utils/resowner/resowner.cpp | 4 +- .../optimizer/commands/prepare.cpp | 23 +- .../globalplancache/globalplancache.cpp | 13 +- .../globalplancache/globalplancache_util.cpp | 5 +- .../globalplancache/globalplancache_view.cpp | 4 + src/gausskernel/process/tcop/postgres.cpp | 157 +- .../threadpool/threadpool_scheduler.cpp | 18 +- src/gausskernel/runtime/executor/opfusion.cpp | 1711 ++++++++++------- .../runtime/executor/opfusion_util.cpp | 13 + .../storage/access/transam/xact.cpp | 9 + .../knl/knl_guc/knl_session_attr_common.h | 1 + src/include/opfusion/opfusion.h | 304 ++- src/include/opfusion/opfusion_util.h | 1 + src/include/threadpool/threadpool_scheduler.h | 1 + src/include/utils/globalplancore.h | 2 +- 18 files changed, 1445 insertions(+), 891 deletions(-) diff --git a/src/bin/gs_guc/cluster_guc.conf b/src/bin/gs_guc/cluster_guc.conf index 4894b312c..af5042c2a 100755 --- a/src/bin/gs_guc/cluster_guc.conf +++ b/src/bin/gs_guc/cluster_guc.conf @@ -186,6 +186,7 @@ enable_compress_hll|bool|0,0|NULL|NULL| enable_fast_numeric|bool|0,0|NULL|Enable numeric optimize.| enable_force_vector_engine|bool|0,0|NULL|NULL| enable_global_plancache|bool|0,0|NULL|NULL| +gpc_clean_timeout|int|300,86400|NULL|NULL| enable_twophase_commit|bool|0,0|NULL|NULL| enable_hashagg|bool|0,0|NULL|NULL| enable_hashjoin|bool|0,0|NULL|NULL| diff --git a/src/common/backend/utils/cache/plancache.cpp b/src/common/backend/utils/cache/plancache.cpp index a2f79df79..a994ab540 100644 --- a/src/common/backend/utils/cache/plancache.cpp +++ b/src/common/backend/utils/cache/plancache.cpp @@ -115,15 +115,6 @@ static bool check_stream_plan(Plan* plan); static bool is_upsert_query_with_update_param(Node* raw_parse_tree); static void GPCFillPlanCache(CachedPlanSource* plansource, bool isBuildingCustomPlan); -bool IsStreamSupport() -{ -#ifdef ENABLE_MULTIPLE_NODES - return u_sess->attr.attr_sql.enable_stream_operator; -#else - return u_sess->opt_cxt.query_dop > 1; -#endif -} - /* * InitPlanCache: initialize module during InitPostgres. * @@ -139,6 +130,25 @@ void InitPlanCache(void) CacheRegisterSyscacheCallback(AMOPOPID, PlanCacheSysCallback, (Datum)0); } +/* ddl no need to global it */ +static bool IsSupportGPCStmt(const Node* node) +{ + bool isSupportGPC = false; + switch (nodeTag(node)) { + case T_InsertStmt: + case T_DeleteStmt: + case T_UpdateStmt: + case T_MergeStmt: + case T_SelectStmt: + isSupportGPC = false; + break; + default: + isSupportGPC = true; + break; + } + return isSupportGPC; +} + /* * CreateCachedPlan: initially create a plan cache entry. * @@ -174,15 +184,8 @@ CachedPlanSource* CreateCachedPlan(Node* raw_parse_tree, const char* query_strin MemoryContext oldcxt; Assert(query_string != NULL); /* required as of 8.4 */ - bool enable_pbe_gpc = false; - if (stmt_name != NULL && stmt_name[0] != '\0') { -#ifdef ENABLE_MULTIPLE_NODES - /* TransactionStmt do not support shared plan */ - enable_pbe_gpc = (ENABLE_CN_GPC && raw_parse_tree && !IsA(raw_parse_tree, TransactionStmt)) || ENABLE_DN_GPC; -#else - enable_pbe_gpc = ENABLE_GPC && raw_parse_tree && !IsA(raw_parse_tree, TransactionStmt); -#endif - } + bool isSupportGPC = raw_parse_tree && IsSupportGPCStmt(raw_parse_tree); + bool enable_pbe_gpc = ENABLE_GPC && stmt_name != NULL && stmt_name[0] != '\0' && !isSupportGPC; if(!enable_pbe_gpc && !(ENABLE_CN_GPC && enable_spi_gpc)) { /* @@ -239,7 +242,7 @@ CachedPlanSource* CreateCachedPlan(Node* raw_parse_tree, const char* query_strin plansource->context = source_context; #ifdef PGXC plansource->stmt_name = (stmt_name ? pstrdup(stmt_name) : NULL); - plansource->stream_enabled = IsStreamSupport(); + plansource->stream_enabled = u_sess->attr.attr_sql.enable_stream_operator; plansource->cplan = NULL; plansource->single_exec_node = NULL; plansource->is_read_only = false; @@ -355,7 +358,7 @@ CachedPlanSource* CreateOneShotCachedPlan(Node* raw_parse_tree, const char* quer #endif #ifdef PGXC - plansource->stream_enabled = IsStreamSupport(); + plansource->stream_enabled = u_sess->attr.attr_sql.enable_stream_operator; plansource->cplan = NULL; plansource->single_exec_node = NULL; plansource->is_read_only = false; @@ -998,7 +1001,7 @@ static bool CheckCachedPlan(CachedPlanSource* plansource) } /* If stream_operator alreadly change, need build plan again.*/ - if ((!plansource->gpc.status.InShareTable()) && plansource->stream_enabled != IsStreamSupport()) { + if ((!plansource->gpc.status.InShareTable()) && plansource->stream_enabled != u_sess->attr.attr_sql.enable_stream_operator) { return false; } @@ -1291,7 +1294,7 @@ static CachedPlan* BuildCachedPlan(CachedPlanSource* plansource, List* qlist, Pa MemoryContextSwitchTo(oldcxt); /* Set plan real u_sess->attr.attr_sql.enable_stream_operator.*/ - plansource->stream_enabled = IsStreamSupport(); + plansource->stream_enabled = u_sess->attr.attr_sql.enable_stream_operator; //in shared hash table, we can not share the plan, we should throw error before this logic. plan->is_share = false; @@ -2660,12 +2663,13 @@ void DropCachedPlanInternal(CachedPlanSource* plansource) } plansource->lightProxyObj = NULL; } else { - if (plansource->opFusionObj != NULL) { + if (!plansource->gpc.status.InShareTable() && plansource->opFusionObj != NULL) { OpFusion *opfusion = (OpFusion *)plansource->opFusionObj; - if (opfusion->m_portalName == NULL || OpFusion::locateFusion(opfusion->m_portalName) == NULL) { + if (opfusion->m_local.m_portalName == NULL || + OpFusion::locateFusion(opfusion->m_local.m_portalName) == NULL) { OpFusion::tearDown(opfusion); } else { - opfusion->m_psrc = NULL; + opfusion->m_global->m_psrc = NULL; } plansource->opFusionObj = NULL; } diff --git a/src/common/backend/utils/misc/guc.cpp b/src/common/backend/utils/misc/guc.cpp index d35a99da5..881b9bcc6 100644 --- a/src/common/backend/utils/misc/guc.cpp +++ b/src/common/backend/utils/misc/guc.cpp @@ -6893,6 +6893,21 @@ static void InitConfigureNamesInt() NULL, NULL}, #endif + /* The I/O upper limit of batch flush dirty page every second */ + {{"gpc_clean_timeout", + PGC_SIGHUP, + CLIENT_CONN, + gettext_noop("Set the maximum allowed duration of any unused global plancache."), + NULL, + GUC_UNIT_S}, + &u_sess->attr.attr_common.gpc_clean_timeout, + 30 * 60, /* 30min */ + 5 * 60, /* 5min */ + 24 * 60 * 60, /* 24h */ + NULL, + NULL, + NULL}, + /* End-of-list marker */ {{NULL, (GucContext)0, (config_group)0, NULL, NULL}, NULL, 0, 0, 0, NULL, NULL, NULL}}; diff --git a/src/common/backend/utils/resowner/resowner.cpp b/src/common/backend/utils/resowner/resowner.cpp index fc8d5609c..6599642e8 100644 --- a/src/common/backend/utils/resowner/resowner.cpp +++ b/src/common/backend/utils/resowner/resowner.cpp @@ -431,6 +431,8 @@ static void ResourceOwnerFreeOwner(ResourceOwner owner) pfree(owner->partmaprefs); if (owner->fakepartrefs) pfree(owner->fakepartrefs); + if (owner->globalMemContexts) + pfree(owner->globalMemContexts); pfree(owner); } @@ -1700,7 +1702,7 @@ void ResourceOwnerEnlargeGMemContext(ResourceOwner owner) if (owner->globalMemContexts == NULL) { newmax = 2; owner->globalMemContexts = (MemoryContext*)MemoryContextAlloc( - THREAD_GET_MEM_CXT_GROUP(MEMORY_CONTEXT_CBB), newmax * sizeof(MemoryContext)); + THREAD_GET_MEM_CXT_GROUP(MEMORY_CONTEXT_EXECUTOR), newmax * sizeof(MemoryContext)); } else { newmax = owner->maxGlobalMemContexts * 2; owner->globalMemContexts = (MemoryContext*)repalloc(owner->globalMemContexts, newmax * sizeof(MemoryContext)); diff --git a/src/gausskernel/optimizer/commands/prepare.cpp b/src/gausskernel/optimizer/commands/prepare.cpp index 62cbdee99..c95b7d386 100644 --- a/src/gausskernel/optimizer/commands/prepare.cpp +++ b/src/gausskernel/optimizer/commands/prepare.cpp @@ -233,12 +233,19 @@ void ExecuteQuery(ExecuteStmt* stmt, IntoClause* intoClause, const char* querySt OpFusion::clearForCplan((OpFusion*)psrc->opFusionObj, psrc); if (psrc->opFusionObj != NULL) { - ((OpFusion*)psrc->opFusionObj)->setPreparedDestReceiver(dest); - ((OpFusion*)psrc->opFusionObj)->useOuterParameter(paramLI); - ((OpFusion*)psrc->opFusionObj)->setCurrentOpFusionObj((OpFusion*)psrc->opFusionObj); + OpFusion *opFusionObj = (OpFusion *)(psrc->opFusionObj); + if (opFusionObj->IsGlobal()) { + opFusionObj = (OpFusion *)OpFusion::FusionFactory(opFusionObj->m_global->m_type, + u_sess->cache_mem_cxt, psrc, NULL, params); + Assert(opFusionObj != NULL); + } + opFusionObj->setPreparedDestReceiver(dest); + opFusionObj->useOuterParameter(paramLI); + opFusionObj->setCurrentOpFusionObj((OpFusion*)psrc->opFusionObj); - CachedPlanSource* cps = ((OpFusion*)psrc->opFusionObj)->m_psrc; - if (cps != NULL && cps->gplan) { + CachedPlanSource* cps = opFusionObj->m_global->m_psrc; + bool needBucketId = cps != NULL && cps->gplan; + if (needBucketId) { setCachedPlanBucketId(cps->gplan, paramLI); } @@ -310,10 +317,12 @@ void ExecuteQuery(ExecuteStmt* stmt, IntoClause* intoClause, const char* querySt eflags = 0; count = FETCH_ALL; } - bool checkSQLBypass = IS_PGXC_DATANODE && (psrc->cplan == NULL) && (psrc->is_checked_opfusion == false); + bool checkSQLBypass = IS_PGXC_DATANODE && !psrc->gpc.status.InShareTable() && + (psrc->cplan == NULL) && (psrc->is_checked_opfusion == false); if (checkSQLBypass) { psrc->opFusionObj = - OpFusion::FusionFactory(OpFusion::getFusionType(cplan, paramLI, NULL), psrc->context, psrc, NULL, paramLI); + OpFusion::FusionFactory(OpFusion::getFusionType(cplan, paramLI, NULL), + u_sess->cache_mem_cxt, psrc, NULL, paramLI); psrc->is_checked_opfusion = true; if (psrc->opFusionObj != NULL) { ((OpFusion*)psrc->opFusionObj)->setPreparedDestReceiver(dest); diff --git a/src/gausskernel/process/globalplancache/globalplancache.cpp b/src/gausskernel/process/globalplancache/globalplancache.cpp index f2a22c503..cb8e07325 100644 --- a/src/gausskernel/process/globalplancache/globalplancache.cpp +++ b/src/gausskernel/process/globalplancache/globalplancache.cpp @@ -33,6 +33,7 @@ #include "executor/lightProxy.h" #include "executor/spi_priv.h" #include "optimizer/nodegroups.h" +#include "opfusion/opfusion.h" #include "pgxc/groupmgr.h" #include "pgxc/pgxcnode.h" #include "utils/dynahash.h" @@ -248,6 +249,10 @@ bool GlobalPlanCache::TryStore(CachedPlanSource *plansource, PreparedStatement INSTR_TIME_SET_CURRENT(entry->val.last_use_time); /* off the link */ plansource->next_saved = NULL; + plansource->is_checked_opfusion = true; + if (plansource->opFusionObj != NULL) { + OpFusion::SaveInGPC((OpFusion*)(plansource->opFusionObj)); + } /* initialize the ref count .*/ #ifdef ENABLE_MULTIPLE_NODES /* dn only count reference on cur_stmt_psrc, no prepare statement. @@ -386,6 +391,9 @@ void GlobalPlanCache::DropInvalid() curr->magic = 0; MemoryContextUnSeal(curr->context); MemoryContextUnSeal(curr->query_context); + if (curr->opFusionObj) { + OpFusion::DropGlobalOpfusion((OpFusion*)(curr->opFusionObj)); + } MemoryContextDelete(curr->context); cell = next; @@ -553,7 +561,7 @@ void GlobalPlanCache::RecreateCachePlan(CachedPlanSource* oldsource, const char* GPC_LOG("recreate plan", oldsource, oldsource->stmt_name); CachedPlanSource *newsource = CopyCachedPlan(oldsource, true); MemoryContext oldcxt = MemoryContextSwitchTo(newsource->context); - newsource->stream_enabled = IsStreamSupport(); + newsource->stream_enabled = u_sess->attr.attr_sql.enable_stream_operator; u_sess->exec_cxt.CurrentOpFusionObj = NULL; Assert (oldsource->gpc.status.IsSharePlan()); newsource->gpc.status.ShareInit(); @@ -949,6 +957,9 @@ void GlobalPlanCache::CleanUpByTime() cur_plansource->magic = 0; MemoryContextUnSeal(cur_plansource->context); MemoryContextUnSeal(cur_plansource->query_context); + if (cur_plansource->opFusionObj) { + OpFusion::DropGlobalOpfusion((OpFusion*)(cur_plansource->opFusionObj)); + } MemoryContextDelete(cur_plansource->context); m_array[bucket_id].count--; } diff --git a/src/gausskernel/process/globalplancache/globalplancache_util.cpp b/src/gausskernel/process/globalplancache/globalplancache_util.cpp index e92d49ddd..900c6e33f 100644 --- a/src/gausskernel/process/globalplancache/globalplancache_util.cpp +++ b/src/gausskernel/process/globalplancache/globalplancache_util.cpp @@ -307,9 +307,8 @@ List* CopyLocalStmt(const List* stmt_list, const MemoryContext parent_cxt, Memor *plan_context = AllocSetContextCreate(parent_cxt, "CopyedStmt", ALLOCSET_DEFAULT_MINSIZE, - 16 * 1024, - ALLOCSET_DEFAULT_MAXSIZE, - STACK_CONTEXT); + ALLOCSET_DEFAULT_INITSIZE, + ALLOCSET_DEFAULT_MAXSIZE); /* * Copy plan into the new context. */ diff --git a/src/gausskernel/process/globalplancache/globalplancache_view.cpp b/src/gausskernel/process/globalplancache/globalplancache_view.cpp index 8c2c3e237..1307d4679 100644 --- a/src/gausskernel/process/globalplancache/globalplancache_view.cpp +++ b/src/gausskernel/process/globalplancache/globalplancache_view.cpp @@ -29,6 +29,7 @@ #include "access/xact.h" #include "catalog/pgxc_node.h" #include "commands/prepare.h" +#include "opfusion/opfusion.h" #include "optimizer/nodegroups.h" #include "pgxc/groupmgr.h" #include "pgxc/pgxcnode.h" @@ -211,6 +212,9 @@ Datum GlobalPlanCache::PlanClean() hash_search(m_array[bucket_id].hash_tbl, (void *) &(entry->key), HASH_REMOVE, &found); MemoryContextUnSeal(cur->context); MemoryContextUnSeal(cur->query_context); + if (cur->opFusionObj) { + OpFusion::DropGlobalOpfusion((OpFusion*)(cur->opFusionObj)); + } MemoryContextDelete(cur->context); m_array[bucket_id].count--; } diff --git a/src/gausskernel/process/tcop/postgres.cpp b/src/gausskernel/process/tcop/postgres.cpp index 47cd3d4b8..596c7143b 100644 --- a/src/gausskernel/process/tcop/postgres.cpp +++ b/src/gausskernel/process/tcop/postgres.cpp @@ -3323,7 +3323,7 @@ static void exec_parse_message(const char* query_string, /* string to execute */ query = parse_analyze_varparams(raw_parse_tree, query_string, ¶mTypes, &numParams); #else query = parse_analyze_varparams(raw_parse_tree, query_string, ¶mTypes, &numParams, paramTypeNames); -#endif +#endif #ifdef ENABLE_MOT /* check cross engine queries */ StorageEngineType storageEngineType = SE_TYPE_UNSPECIFIED; @@ -3341,7 +3341,11 @@ static void exec_parse_message(const char* query_string, /* string to execute */ // MOT LLVM TryMotJitCodegenQuery(query_string, psrc, query); } - + /* gpc does not support MOT engine */ + if (ENABLE_CN_GPC && psrc->gpc.status.IsSharePlan() && + (psrc->storageEngineType == SE_TYPE_MOT || psrc->storageEngineType == SE_TYPE_MIXED)) { + psrc->gpc.status.SetKind(GPC_UNSHARED); + } if (!IsTransactionExitStmt(raw_parse_tree) && CheckMotIndexedColumnUpdate(query)) { ereport(ERROR, (errcode(ERRCODE_FDW_UPDATE_INDEXED_FIELD_NOT_SUPPORTED), errmodule(MOD_MOT), errmsg("Update of indexed column is not supported for memory table"))); @@ -4109,22 +4113,14 @@ static void exec_bind_message(StringInfo input_message) #ifdef ENABLE_MOT /* set transaction storage engine and check for cross transaction violation */ SetCurrentTransactionStorageEngine(psrc->storageEngineType); - if (!IsTransactionExitStmt(psrc->raw_parse_tree) && IsMixedEngineUsed()) { + if (!IsTransactionExitStmt(psrc->raw_parse_tree) && IsMixedEngineUsed()) ereport(ERROR, (errcode(ERRCODE_FDW_CROSS_STORAGE_ENGINE_TRANSACTION_NOT_SUPPORTED), errmodule(MOD_MOT), - errmsg("Cross storage engine transaction is not supported"))); - } + errmsg("Cross storage engine transaction is not supported"))); /* block MOT engine queries in sub-transactions */ - if (!IsTransactionExitStmt(psrc->raw_parse_tree) && IsMOTEngineUsedInParentTransaction() && IsMOTEngineUsed()) { + if (!IsTransactionExitStmt(psrc->raw_parse_tree) && IsMOTEngineUsedInParentTransaction() && IsMOTEngineUsed()) ereport(ERROR, (errcode(ERRCODE_FDW_OPERATION_NOT_SUPPORTED), errmodule(MOD_MOT), - errmsg("SubTransaction is not supported for memory table"))); - } - - if (IsTransactionPrepareStmt(psrc->raw_parse_tree) && (IsMOTEngineUsed() || IsMixedEngineUsed())) { - /* Explicit prepare transaction is not supported for memory table */ - ereport(ERROR, (errcode(ERRCODE_FDW_OPERATION_NOT_SUPPORTED), errmodule(MOD_MOT), - errmsg("Explicit prepare transaction is not supported for memory table"))); - } + errmsg("SubTransaction is not supported for memory table"))); /* * MOT JIT Execution: @@ -4144,21 +4140,26 @@ static void exec_bind_message(StringInfo input_message) OpFusion::clearForCplan((OpFusion*)psrc->opFusionObj, psrc); if (psrc->opFusionObj != NULL) { + Assert(psrc->cplan == NULL); (void)RevalidateCachedQuery(psrc); - if (psrc->opFusionObj != NULL) { - Assert(psrc->cplan == NULL); - ((OpFusion*)psrc->opFusionObj)->clean(); - ((OpFusion*)psrc->opFusionObj)->updatePreAllocParamter(input_message); - ((OpFusion*)psrc->opFusionObj)->setCurrentOpFusionObj((OpFusion*)psrc->opFusionObj); - if (portal_name[0] != '\0') - ((OpFusion *)psrc->opFusionObj)->storeFusion(portal_name); - - CachedPlanSource* cps = ((OpFusion*)psrc->opFusionObj)->m_psrc; - if (cps != NULL && cps->gplan) { - setCachedPlanBucketId(cps->gplan, ((OpFusion*)psrc->opFusionObj)->m_params); + OpFusion *opFusionObj = (OpFusion *)(psrc->opFusionObj); + if (opFusionObj != NULL) { + if (opFusionObj->IsGlobal()) { + opFusionObj = (OpFusion *)OpFusion::FusionFactory(opFusionObj->m_global->m_type, + u_sess->cache_mem_cxt, psrc, NULL, params); + Assert(opFusionObj != NULL); } + opFusionObj->clean(); + opFusionObj->updatePreAllocParamter(input_message); + opFusionObj->setCurrentOpFusionObj(opFusionObj); + if (portal_name[0] != '\0') + opFusionObj->storeFusion(portal_name); + CachedPlanSource* cps = opFusionObj->m_global->m_psrc; + if (cps != NULL && cps->gplan) { + setCachedPlanBucketId(cps->gplan, opFusionObj->m_local.m_params); + } if (t_thrd.postgres_cxt.whereToSendOutput == DestRemote) pq_putemptymessage('2'); gstrace_exit(GS_TRC_ID_exec_bind_message); @@ -4543,13 +4544,10 @@ static void exec_bind_message(StringInfo input_message) */ PortalDefineQuery(portal, saved_stmt_name, query_string, psrc->commandTag, cplan->stmt_list, cplan); - if (ENABLE_GPC && psrc->gplan) { - portal->stmts = CopyLocalStmt(cplan->stmt_list, u_sess->top_portal_cxt, &portal->copyCxt); - } - - if (IS_PGXC_DATANODE && psrc->cplan == NULL && psrc->is_checked_opfusion == false) { + if (IS_PGXC_DATANODE && psrc->cplan == NULL && !psrc->gpc.status.InShareTable() && + psrc->is_checked_opfusion == false) { psrc->opFusionObj = OpFusion::FusionFactory(OpFusion::getFusionType(cplan, params, NULL), - u_sess->cache_mem_cxt, psrc, NULL, params); + u_sess->cache_mem_cxt, psrc, NULL, params); psrc->is_checked_opfusion = true; if (psrc->opFusionObj != NULL) { ((OpFusion*)psrc->opFusionObj)->clean(); @@ -4569,6 +4567,10 @@ static void exec_bind_message(StringInfo input_message) } } + if (ENABLE_GPC && psrc->gplan) { + portal->stmts = CopyLocalStmt(cplan->stmt_list, u_sess->top_portal_cxt, &portal->copyCxt); + } + /* Done with the snapshot used for parameter I/O and parsing/planning */ if (snapshot_set) PopActiveSnapshot(); @@ -8404,8 +8406,12 @@ int PostgresMain(int argc, char* argv[], const char* dbname, const char* usernam if (IS_PGXC_DATANODE && closeTarget[0] != '\0') { OpFusion* curr = OpFusion::locateFusion(closeTarget); if (curr != NULL) { - curr->clean(); - OpFusion::removeFusionFromHtab(closeTarget); + if (curr->IsGlobal()) { + OpFusion::tearDown(curr); + } else { + curr->clean(); + OpFusion::removeFusionFromHtab(closeTarget); + } } } @@ -9773,25 +9779,45 @@ void execute_simple_query(const char* query_string) * If query is not SELECT/INSERT/UPDATE/DELETE, return completionTag, else NULL. */ static void exec_one_in_batch(CachedPlanSource* psrc, ParamListInfo params, int numRFormats, int16* rformats, - bool send_DP_msg, CommandDest dest, char* completionTag, const char* stmt_name, List* gpcCopyStmts) + bool send_DP_msg, CommandDest dest, char* completionTag, + const char* stmt_name, List** gpcCopyStmts, MemoryContext* tmpCxt, PreparedStatement* pstmt) { CachedPlan* cplan = NULL; Portal portal; DestReceiver* receiver = NULL; bool completed = false; + + if (ENABLE_GPC && psrc->stmt_name && psrc->stmt_name[0] != '\0' && + g_instance.plan_cache->CheckRecreateCachePlan(psrc)) { + g_instance.plan_cache->RecreateCachePlan(psrc, stmt_name, pstmt, NULL, NULL); +#ifdef ENABLE_MULTIPLE_NODES + psrc = IS_PGXC_DATANODE ? u_sess->pcache_cxt.cur_stmt_psrc : pstmt->plansource; +#else + psrc = pstmt->plansource; +#endif + t_thrd.postgres_cxt.debug_query_string = psrc->query_string; + } + + int generation = psrc->generation; + OpFusion::clearForCplan((OpFusion*)psrc->opFusionObj, psrc); if (psrc->opFusionObj != NULL) { (void)RevalidateCachedQuery(psrc); - + OpFusion *opFusionObj = (OpFusion *)(psrc->opFusionObj); if (psrc->opFusionObj != NULL) { Assert(psrc->cplan == NULL); - ((OpFusion*)psrc->opFusionObj)->bindClearPosition(); - ((OpFusion*)psrc->opFusionObj)->useOuterParameter(params); - ((OpFusion*)psrc->opFusionObj)->setCurrentOpFusionObj((OpFusion*)psrc->opFusionObj); + if (opFusionObj->IsGlobal()) { + opFusionObj = (OpFusion *)OpFusion::FusionFactory(opFusionObj->m_global->m_type, + u_sess->cache_mem_cxt, psrc, NULL, params); + Assert(opFusionObj != NULL); + } + opFusionObj->bindClearPosition(); + opFusionObj->useOuterParameter(params); + opFusionObj->setCurrentOpFusionObj(opFusionObj); - CachedPlanSource* cps = ((OpFusion*)psrc->opFusionObj)->m_psrc; + CachedPlanSource* cps = opFusionObj->m_global->m_psrc; if (cps != NULL && cps->gplan) { setCachedPlanBucketId(cps->gplan, params); } @@ -9856,8 +9882,20 @@ static void exec_one_in_batch(CachedPlanSource* psrc, ParamListInfo params, int cplan->stmt_list, cplan); - if (ENABLE_GPC && gpcCopyStmts != NULL) { - portal->stmts = gpcCopyStmts; + if (ENABLE_GPC) { + /* generated new gplan, copy it incase someone change it */ + if (generation != psrc->generation && psrc->gplan) { + if (*tmpCxt != NULL) + MemoryContextDelete(*tmpCxt); + *gpcCopyStmts = CopyLocalStmt(psrc->gplan->stmt_list, u_sess->temp_mem_cxt, tmpCxt); + } else if (*gpcCopyStmts == NULL && psrc->gpc.status.InShareTable()) { + /* copy for shared plan */ + if (*tmpCxt != NULL) + MemoryContextDelete(*tmpCxt); + *gpcCopyStmts = CopyLocalStmt(psrc->gplan->stmt_list, u_sess->temp_mem_cxt, tmpCxt); + } + if (*gpcCopyStmts != NULL) + portal->stmts = *gpcCopyStmts; } #ifdef ENABLE_MOT @@ -9873,13 +9911,14 @@ static void exec_one_in_batch(CachedPlanSource* psrc, ParamListInfo params, int } #endif - bool checkSQLBypass = IS_PGXC_DATANODE && (psrc->cplan == NULL) && (psrc->is_checked_opfusion == false); + bool checkSQLBypass = IS_PGXC_DATANODE && !psrc->gpc.status.InShareTable() && + (psrc->cplan == NULL) && (psrc->is_checked_opfusion == false); if (checkSQLBypass) { - psrc->opFusionObj = - OpFusion::FusionFactory(OpFusion::getFusionType(cplan, params, NULL), psrc->context, psrc, NULL, params); + psrc->opFusionObj = OpFusion::FusionFactory(OpFusion::getFusionType(cplan, params, NULL), + u_sess->cache_mem_cxt, psrc, NULL, params); psrc->is_checked_opfusion = true; if (psrc->opFusionObj != NULL) { - ((OpFusion*)psrc->opFusionObj)->bindClearPosition(); + ((OpFusion*)psrc->opFusionObj)->bindClearPosition(); ((OpFusion*)psrc->opFusionObj)->useOuterParameter(params); ((OpFusion*)psrc->opFusionObj)->setCurrentOpFusionObj((OpFusion*)psrc->opFusionObj); ((OpFusion*)psrc->opFusionObj)->CopyFormats(rformats, numRFormats); @@ -10342,6 +10381,7 @@ static void exec_batch_bind_execute(StringInfo input_message) *portal_name ? portal_name : "", *stmt_name ? stmt_name : "", batch_count))); + PreparedStatement *pstmt = NULL; /* Find prepared statement */ if (stmt_name[0] != '\0') { @@ -10351,7 +10391,6 @@ static void exec_batch_bind_execute(StringInfo input_message) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_PSTATEMENT), errmsg("dn gpc's prepared statement %s does not exist", stmt_name))); } else { - PreparedStatement *pstmt = NULL; pstmt = FetchPreparedStatement(stmt_name, true, true); psrc = pstmt->plansource; } @@ -10859,21 +10898,26 @@ static void exec_batch_bind_execute(StringInfo input_message) } else { char* completionTag = (char*)palloc0(COMPLETION_TAG_BUFSIZE * sizeof(char)); List* copyedStmts = NULL; + MemoryContext tmpCxt = NULL; if (u_sess->attr.attr_resource.use_workload_manager && g_instance.wlm_cxt->gscgroup_init_done && !IsAbortedTransactionBlockState()) { u_sess->wlm_cxt->cgroup_last_stmt = u_sess->wlm_cxt->cgroup_stmt; u_sess->wlm_cxt->cgroup_stmt = WLMIsSpecialCommand(psrc->raw_parse_tree, NULL); } - if (ENABLE_GPC && psrc->gplan && psrc->gpc.status.IsSharePlan()) { - MemoryContext tmpCxt = NULL; - copyedStmts = CopyLocalStmt(psrc->gplan->stmt_list, u_sess->temp_mem_cxt, &tmpCxt); - } if (use_original_logic) { for (int i = 0; i < batch_count; i++) { exec_one_in_batch(psrc, params_set[i], numRFormats, rformats, - (i == 0) ? send_DP_msg : false, dest, completionTag, stmt_name, copyedStmts); + (i == 0) ? send_DP_msg : false, dest, completionTag, + stmt_name, ©edStmts, &tmpCxt, pstmt); + if (ENABLE_GPC && stmt_name[0] != '\0') { +#ifdef ENABLE_MULTIPLE_NODES + psrc = IS_PGXC_DATANODE ? u_sess->pcache_cxt.cur_stmt_psrc : pstmt->plansource; +#else + psrc = pstmt->plansource; +#endif + } } /* only send the last commandTag */ @@ -10883,7 +10927,15 @@ static void exec_batch_bind_execute(StringInfo input_message) for (int i = 0; i < batch_count; i++) { exec_one_in_batch(psrc, params_set[i], numRFormats, rformats, - (i == 0) ? send_DP_msg : false, dest, completionTag, stmt_name, copyedStmts); + (i == 0) ? send_DP_msg : false, dest, completionTag, + stmt_name, ©edStmts, &tmpCxt, pstmt); + if (ENABLE_GPC && stmt_name[0] != '\0') { +#ifdef ENABLE_MULTIPLE_NODES + psrc = IS_PGXC_DATANODE ? u_sess->pcache_cxt.cur_stmt_psrc : pstmt->plansource; +#else + psrc = pstmt->plansource; +#endif + } /* Get process_count (X) from completionTag */ if (completionTag[0] == 'I') { @@ -10897,7 +10949,6 @@ static void exec_batch_bind_execute(StringInfo input_message) Assert(completionTag[0] == 'U' || completionTag[0] == 'D' || completionTag[0] == 'S'); tmp_count = pg_atoi(&completionTag[7], sizeof(int32), '\0'); } - process_count += tmp_count; } } diff --git a/src/gausskernel/process/threadpool/threadpool_scheduler.cpp b/src/gausskernel/process/threadpool/threadpool_scheduler.cpp index 66a241f0d..75f3cd02e 100644 --- a/src/gausskernel/process/threadpool/threadpool_scheduler.cpp +++ b/src/gausskernel/process/threadpool/threadpool_scheduler.cpp @@ -46,17 +46,31 @@ #define MAX_HANG_TIME 100 #define REDUCE_THREAD_TIME 100 #define SHUTDOWN_THREAD_TIME 1000 -#define GPC_CLEAN_TIME 600 +#define GPC_CLEAN_TIME 300 static void SchedulerSIGKILLHandler(SIGNAL_ARGS) { proc_exit(0); } +static void SchedulerSIGHUPHandler(SIGNAL_ARGS) +{ + t_thrd.threadpool_cxt.scheduler->m_getSIGHUP = true; +} + +static void reloadConfigFileIfNecessary() +{ + if (t_thrd.threadpool_cxt.scheduler->m_getSIGHUP) { + t_thrd.threadpool_cxt.scheduler->m_getSIGHUP = false; + ProcessConfigFile(PGC_SIGHUP); + } +} + void TpoolSchedulerMain(ThreadPoolScheduler *scheduler) { int gpc_count = 0; + (void)gspqsignal(SIGHUP, SchedulerSIGHUPHandler); (void)gspqsignal(SIGKILL, SchedulerSIGKILLHandler); gs_signal_setmask(&t_thrd.libpq_cxt.UnBlockSig, NULL); (void)gs_signal_unblock_sigusr2(); @@ -70,6 +84,7 @@ void TpoolSchedulerMain(ThreadPoolScheduler *scheduler) while (true) { pg_usleep(SCHEDULER_TIME_UNIT); + reloadConfigFileIfNecessary(); scheduler->DynamicAdjustThreadPool(); scheduler->GPCScheduleCleaner(&gpc_count); g_threadPoolControler->GetSessionCtrl()->CheckSessionTimeout(); @@ -85,6 +100,7 @@ ThreadPoolScheduler::ThreadPoolScheduler(int groupNum, ThreadPoolGroup** groups) m_freeTestCount = (uint *)palloc0(sizeof(uint) * groupNum); m_freeStreamCount = (uint *)palloc0(sizeof(uint) * groupNum); m_gpcContext = NULL; + m_getSIGHUP = false; } ThreadPoolScheduler::~ThreadPoolScheduler() diff --git a/src/gausskernel/runtime/executor/opfusion.cpp b/src/gausskernel/runtime/executor/opfusion.cpp index 585956ce1..28b33dd6a 100644 --- a/src/gausskernel/runtime/executor/opfusion.cpp +++ b/src/gausskernel/runtime/executor/opfusion.cpp @@ -55,51 +55,126 @@ extern void opfusion_executeEnd(PlannedStmt* plannedstmt, const char *queryStrin OpFusion::OpFusion(MemoryContext context, CachedPlanSource* psrc, List* plantree_list) { - m_context = AllocSetContextCreate( - context, "OpfusionContext", ALLOCSET_DEFAULT_MINSIZE, ALLOCSET_DEFAULT_INITSIZE, ALLOCSET_DEFAULT_MAXSIZE); - m_tmpContext = AllocSetContextCreate(context, - "OpfusionTemporaryContext", - ALLOCSET_DEFAULT_MINSIZE, - ALLOCSET_DEFAULT_INITSIZE, - ALLOCSET_DEFAULT_MAXSIZE); + /* for shared plancache, we only need to init local variables */ + if (psrc && psrc->opFusionObj && ((OpFusion*)(psrc->opFusionObj))->m_global->m_is_global) { + Assert (psrc->gpc.status.InShareTable()); + m_global = ((OpFusion*)(psrc->opFusionObj))->m_global; + InitLocals(context); + m_global->m_psrc->gpc.status.AddRefcount(); + } else { + InitGlobals(context, psrc, plantree_list); + InitLocals(context); + } +} + +void OpFusion::InitGlobals(MemoryContext context, CachedPlanSource* psrc, List* plantree_list) +{ + bool is_shared = psrc && psrc->gpc.status.InShareTable(); + bool needShardCxt = !is_shared && psrc && psrc->gpc.status.IsSharePlan(); + MemoryContext cxt = NULL; + if (needShardCxt) { + cxt = AllocSetContextCreate(GLOBAL_PLANCACHE_MEMCONTEXT, + "SharedOpfusionContext", + ALLOCSET_DEFAULT_MINSIZE, + ALLOCSET_DEFAULT_INITSIZE, + ALLOCSET_DEFAULT_MAXSIZE, + SHARED_CONTEXT); + } else { + cxt = AllocSetContextCreate(context, + "OpfusionContext", + ALLOCSET_DEFAULT_MINSIZE, + ALLOCSET_DEFAULT_INITSIZE, + ALLOCSET_DEFAULT_MAXSIZE, + STANDARD_CONTEXT); + } + + MemoryContext old_context = MemoryContextSwitchTo(cxt); + m_global = (OpFusionGlobalVariable*)palloc0(sizeof(OpFusionGlobalVariable)); + m_global->m_context = cxt; if (psrc == NULL && plantree_list != NULL) { - m_is_pbe_query = false; - m_psrc = NULL; - m_cacheplan = NULL; - m_planstmt = (PlannedStmt*)linitial(plantree_list); + m_global->m_is_pbe_query = false; + m_global->m_psrc = NULL; + m_global->m_cacheplan = NULL; + m_global->m_planstmt = (PlannedStmt*)linitial(plantree_list); } else if (plantree_list == NULL && psrc != NULL) { - m_is_pbe_query = true; - m_psrc = psrc; - m_cacheplan = psrc->cplan ? psrc->cplan : psrc->gplan; - m_cacheplan->refcount++; - m_planstmt = (PlannedStmt*)linitial(m_cacheplan->stmt_list); + Assert(psrc->gplan != NULL); + m_global->m_is_pbe_query = true; + m_global->m_psrc = psrc; + m_global->m_cacheplan = psrc->gplan; + m_global->m_cacheplan->refcount++; + (void)pg_atomic_add_fetch_u32((volatile uint32*)&m_global->m_cacheplan->global_refcount, 1); + m_global->m_planstmt = (PlannedStmt*)linitial(m_global->m_cacheplan->stmt_list); } else { Assert(0); ereport(ERROR, (errcode(ERRCODE_UNDEFINED_PSTATEMENT), errmsg("Both cacheplan and planstmt are NULL"))); } + m_global->m_reloid = 0; + m_global->m_attrno = NULL; + m_global->m_tupDesc = NULL; + m_global->m_paramNum = 0; + m_global->m_paramLoc = NULL; + m_global->m_is_global = false; + m_global->m_natts = 0; + m_global->m_table_type = TAM_HEAP; + m_global->m_is_bucket_rel = false; + (void)MemoryContextSwitchTo(old_context); +} - m_outParams = NULL; - m_params = NULL; - m_isFirst = true; - m_rformats = NULL; - m_isCompleted = false; - m_position = 0; - m_isInsideRec = false; - m_tmpvals = NULL; - m_reloid = 0; - m_isnull = NULL; - m_attrno = NULL; - m_reslot = NULL; - m_receiver = NULL; - m_tupDesc = NULL; - m_values = NULL; - m_paramNum = 0; - m_paramLoc = NULL; - m_tmpisnull = NULL; - m_portalName = NULL; - m_snapshot = NULL; - m_scan = NULL; +void OpFusion::InitLocals(MemoryContext context) +{ + m_local.m_tmpContext = AllocSetContextCreate(context, + "OpfusionTemporaryContext", + ALLOCSET_DEFAULT_MINSIZE, + ALLOCSET_DEFAULT_INITSIZE, + ALLOCSET_DEFAULT_MAXSIZE); + m_local.m_localContext = AllocSetContextCreate(context, + "OpfusionLocalContext", + ALLOCSET_DEFAULT_MINSIZE, + ALLOCSET_DEFAULT_INITSIZE, + ALLOCSET_DEFAULT_MAXSIZE); + m_local.m_outParams = NULL; + m_local.m_isFirst = true; + m_local.m_rformats = NULL; + m_local.m_isCompleted = false; + m_local.m_position = 0; + m_local.m_isInsideRec = false; + m_local.m_tmpvals = NULL; + m_local.m_isnull = NULL; + m_local.m_reslot = NULL; + m_local.m_receiver = NULL; + m_local.m_values = NULL; + m_local.m_tmpisnull = NULL; + m_local.m_portalName = NULL; + m_local.m_snapshot = NULL; + m_local.m_scan = NULL; + m_local.m_params = NULL; + m_local.m_resOwner = NULL; +} + +/* clear local variables before global it */ +void OpFusion::SaveInGPC(OpFusion* obj) +{ + Assert(!obj->IsGlobal()); + Assert(obj->m_global->m_context->is_shared); + /* only can change global flag here */ + obj->m_global->m_is_global = true; + removeFusionFromHtab(obj->m_local.m_portalName); + MemoryContextDelete(obj->m_local.m_tmpContext); + MemoryContextDelete(obj->m_local.m_localContext); + int rc = -1; + rc = memset_s((void*)&obj->m_local, sizeof(OpFusionLocaleVariable), 0, sizeof(OpFusionLocaleVariable)); + securec_check(rc, "\0", "\0"); + MemoryContextSeal(obj->m_global->m_context); +} + +void OpFusion::DropGlobalOpfusion(OpFusion* obj) +{ + Assert(obj->IsGlobal()); + MemoryContextUnSeal(obj->m_global->m_context); + ReleaseCachedPlan(obj->m_global->m_cacheplan, false); + MemoryContextDelete(obj->m_global->m_context); + delete obj; } #ifdef ENABLE_MOT @@ -129,10 +204,6 @@ FusionType OpFusion::getFusionType(CachedPlan* plan, ParamListInfo params, List* return NONE_FUSION; } - if (ENABLE_GPC) { - return NONE_FUSION; - } - if (!u_sess->attr.attr_sql.enable_opfusion) { return NONE_FUSION; } @@ -203,7 +274,7 @@ void OpFusion::checkPermission() if (!(IS_PGXC_DATANODE && (IsConnFromCoord() || IsConnFromDatanode()))) { check = true; } - if (m_planstmt->in_compute_pool) { + if (m_global->m_planstmt->in_compute_pool) { check = false; } @@ -212,16 +283,18 @@ void OpFusion::checkPermission() } if (check) { - (void)ExecCheckRTPerms(m_planstmt->rtable, true); + (void)ExecCheckRTPerms(m_global->m_planstmt->rtable, true); } } void OpFusion::executeInit() { - if (m_isFirst == true) { + if (m_local.m_isFirst == true) { checkPermission(); } - + if (m_local.m_resOwner == NULL) { + m_local.m_resOwner = t_thrd.utils_cxt.CurrentResourceOwner; + } if (IS_SINGLE_NODE && ENABLE_WORKLOAD_CONTROL) { u_sess->debug_query_id = generate_unique_id64(>_queryId); WLMCreateDNodeInfoOnDN(NULL); @@ -229,17 +302,17 @@ void OpFusion::executeInit() } if (u_sess->attr.attr_common.XactReadOnly) { - ExecCheckXactReadOnly(m_planstmt); + ExecCheckXactReadOnly(m_global->m_planstmt); } #ifdef ENABLE_MOT - if (!(u_sess->exec_cxt.CurrentOpFusionObj->m_cacheplan && - u_sess->exec_cxt.CurrentOpFusionObj->m_cacheplan->storageEngineType == SE_TYPE_MOT)) { + if (!(u_sess->exec_cxt.CurrentOpFusionObj->m_global->m_cacheplan && + u_sess->exec_cxt.CurrentOpFusionObj->m_global->m_cacheplan->storageEngineType == SE_TYPE_MOT)) { #endif - if (m_snapshot == NULL) { - m_snapshot = RegisterSnapshot(GetTransactionSnapshot()); + if (m_local.m_snapshot == NULL) { + m_local.m_snapshot = RegisterSnapshot(GetTransactionSnapshot()); } - PushActiveSnapshot(m_snapshot); + PushActiveSnapshot(m_local.m_snapshot); #ifdef ENABLE_MOT } #endif @@ -252,19 +325,19 @@ void OpFusion::auditRecord() IsPostmasterEnvironment) { char* object_name = NULL; - switch (m_planstmt->commandType) { + switch (m_global->m_planstmt->commandType) { case CMD_INSERT: case CMD_DELETE: case CMD_UPDATE: if (u_sess->attr.attr_security.Audit_DML != 0) { - object_name = pgaudit_get_relation_name(m_planstmt->rtable); - pgaudit_dml_table(object_name, m_is_pbe_query ? m_psrc->query_string : t_thrd.postgres_cxt.debug_query_string); + object_name = pgaudit_get_relation_name(m_global->m_planstmt->rtable); + pgaudit_dml_table(object_name, m_global->m_is_pbe_query ? m_global->m_psrc->query_string : t_thrd.postgres_cxt.debug_query_string); } break; case CMD_SELECT: if (u_sess->attr.attr_security.Audit_DML_SELECT != 0) { - object_name = pgaudit_get_relation_name(m_planstmt->rtable); - pgaudit_dml_table_select(object_name, m_is_pbe_query ? m_psrc->query_string : t_thrd.postgres_cxt.debug_query_string); + object_name = pgaudit_get_relation_name(m_global->m_planstmt->rtable); + pgaudit_dml_table_select(object_name, m_global->m_is_pbe_query ? m_global->m_psrc->query_string : t_thrd.postgres_cxt.debug_query_string); } break; /* Not support others */ @@ -274,13 +347,15 @@ void OpFusion::auditRecord() } } -void OpFusion::executeEnd(const char* portal_name, bool* isQueryCompleted) +bool OpFusion::executeEnd(const char* portal_name, bool* isQueryCompleted) { #ifdef ENABLE_MOT - if (!(u_sess->exec_cxt.CurrentOpFusionObj->m_cacheplan && - u_sess->exec_cxt.CurrentOpFusionObj->m_cacheplan->storageEngineType == SE_TYPE_MOT)) { + if (!(u_sess->exec_cxt.CurrentOpFusionObj->m_global->m_cacheplan && + u_sess->exec_cxt.CurrentOpFusionObj->m_global->m_cacheplan->storageEngineType == SE_TYPE_MOT)) { #endif - opfusion_executeEnd(m_planstmt, ((m_psrc == NULL)?(NULL):(m_psrc->query_string)), GetActiveSnapshot()); + opfusion_executeEnd(m_global->m_planstmt, + ((m_global->m_psrc == NULL) ? NULL : (m_global->m_psrc->query_string)), + GetActiveSnapshot()); PopActiveSnapshot(); #ifdef ENABLE_MOT @@ -292,36 +367,41 @@ void OpFusion::executeEnd(const char* portal_name, bool* isQueryCompleted) MemoryContextCheck(TopMemoryContext, false); /* Check per-query memory context before Opfusion temp memory */ - MemoryContextCheck(m_tmpContext, true); + MemoryContextCheck(m_local.m_tmpContext, true); #endif + bool has_completed = m_local.m_isCompleted; + m_local.m_isFirst = false; /* reset the context. */ - if (m_isCompleted) { - UnregisterSnapshot(m_snapshot); - m_snapshot = NULL; - MemoryContextDeleteChildren(m_tmpContext); + if (m_local.m_isCompleted) { + UnregisterSnapshot(m_local.m_snapshot); + m_local.m_snapshot = NULL; + MemoryContextDeleteChildren(m_local.m_tmpContext); /* reset the context. */ - MemoryContextReset(m_tmpContext); + MemoryContextReset(m_local.m_tmpContext); /* clear hash table */ removeFusionFromHtab(portal_name); - m_outParams = NULL; - m_isCompleted = false; + m_local.m_outParams = NULL; + m_local.m_isCompleted = false; if (isQueryCompleted) *isQueryCompleted = true; u_sess->xact_cxt.pbe_execute_complete = true; + m_local.m_resOwner = NULL; } else { if (isQueryCompleted) *isQueryCompleted = false; u_sess->xact_cxt.pbe_execute_complete = false; + if (ENABLE_GPC) + Assert(locateFusion(m_local.m_portalName) != NULL); } - u_sess->exec_cxt.CurrentOpFusionObj = NULL; - m_isFirst = false; auditRecord(); if (u_sess->attr.attr_common.pgstat_track_activities && u_sess->attr.attr_common.pgstat_track_sql_count) { - report_qps_type(m_planstmt->commandType); + report_qps_type(m_global->m_planstmt->commandType); report_qps_type(CMD_DML); } + + return has_completed; } bool OpFusion::process(int op, StringInfo msg, char* completionTag, bool isTopLevel, bool* isQueryCompleted) @@ -355,7 +435,13 @@ bool OpFusion::process(int op, StringInfo msg, char* completionTag, bool isTopLe u_sess->exec_cxt.CurrentOpFusionObj->execute(max_rows, completionTag); u_sess->exec_cxt.need_track_resource = old_status; gstrace_exit(GS_TRC_ID_BypassExecutor); - u_sess->exec_cxt.CurrentOpFusionObj->executeEnd(portal_name, isQueryCompleted); + bool completed = false; + completed = u_sess->exec_cxt.CurrentOpFusionObj->executeEnd(portal_name, isQueryCompleted); + if (completed && u_sess->exec_cxt.CurrentOpFusionObj->IsGlobal()) { + Assert(ENABLE_GPC); + tearDown(u_sess->exec_cxt.CurrentOpFusionObj); + } + u_sess->exec_cxt.CurrentOpFusionObj = NULL; UpdateSingleNodeByPassUniqueSQLStat(isTopLevel); break; } @@ -399,9 +485,9 @@ bool OpFusion::process(int op, StringInfo msg, char* completionTag, bool isTopLe void OpFusion::CopyFormats(int16* formats, int numRFormats) { - MemoryContext old_context = MemoryContextSwitchTo(m_tmpContext); + MemoryContext old_context = MemoryContextSwitchTo(m_local.m_tmpContext); int natts; - if (m_tupDesc == NULL) { + if (m_global->m_tupDesc == NULL) { Assert(0); return; } @@ -410,8 +496,8 @@ void OpFusion::CopyFormats(int16* formats, int numRFormats) (errcode(ERRCODE_UNEXPECTED_NULL_VALUE), errmsg("r_formats can not be NULL when num of rformats is not 0"))); } - natts = m_tupDesc->natts; - m_rformats = (int16*)palloc(natts * sizeof(int16)); + natts = m_global->m_tupDesc->natts; + m_local.m_rformats = (int16*)palloc(natts * sizeof(int16)); if (numRFormats > 1) { /* format specified for each column */ if (numRFormats != natts) @@ -419,18 +505,18 @@ void OpFusion::CopyFormats(int16* formats, int numRFormats) (errcode(ERRCODE_PROTOCOL_VIOLATION), errmsg("bind message has %d result formats but query has %d columns", numRFormats, natts))); errno_t errorno = EOK; - errorno = memcpy_s(m_rformats, natts * sizeof(int16), formats, natts * sizeof(int16)); + errorno = memcpy_s(m_local.m_rformats, natts * sizeof(int16), formats, natts * sizeof(int16)); securec_check(errorno, "\0", "\0"); } else if (numRFormats > 0) { /* single format specified, use for all columns */ int16 format1 = formats[0]; for (int i = 0; i < natts; i++) { - m_rformats[i] = format1; + m_local.m_rformats[i] = format1; } } else { /* use default format for all columns */ for (int i = 0; i < natts; i++) { - m_rformats[i] = 0; + m_local.m_rformats[i] = 0; } } MemoryContextSwitchTo(old_context); @@ -438,7 +524,7 @@ void OpFusion::CopyFormats(int16* formats, int numRFormats) void OpFusion::useOuterParameter(ParamListInfo params) { - m_outParams = params; + m_local.m_outParams = params; } @@ -452,45 +538,58 @@ void* OpFusion::FusionFactory( if (ftype > BYPASS_OK) { return NULL; } - + void* opfusionObj = NULL; + MemoryContext objCxt = NULL; + if (psrc && psrc->gpc.status.InShareTable()) { + /* global plansource cannot new bypass on plansource context, must generate on local context */ + objCxt = context; + } else { + /* for opfusion for plansource may global later, generate on global context */ + if (psrc && psrc->gpc.status.IsSharePlan()) + objCxt = GLOBAL_PLANCACHE_MEMCONTEXT; + else + objCxt = context; + } switch (ftype) { case SELECT_FUSION: - return New(context) SelectFusion(context, psrc, plantree_list, params); - + opfusionObj = New(objCxt) SelectFusion(context, psrc, plantree_list, params); + break; case INSERT_FUSION: - return New(context) InsertFusion(context, psrc, plantree_list, params); - + opfusionObj = New(objCxt) InsertFusion(context, psrc, plantree_list, params); + break; case UPDATE_FUSION: - return New(context) UpdateFusion(context, psrc, plantree_list, params); - + opfusionObj = New(objCxt) UpdateFusion(context, psrc, plantree_list, params); + break; case DELETE_FUSION: - return New(context) DeleteFusion(context, psrc, plantree_list, params); - + opfusionObj = New(objCxt) DeleteFusion(context, psrc, plantree_list, params); + break; case SELECT_FOR_UPDATE_FUSION: - return New(context) SelectForUpdateFusion(context, psrc, plantree_list, params); - + opfusionObj = New(objCxt) SelectForUpdateFusion(context, psrc, plantree_list, params); + break; #ifdef ENABLE_MOT case MOT_JIT_SELECT_FUSION: - return New(context) MotJitSelectFusion(context, psrc, plantree_list, params); - + opfusionObj = New(objCxt) MotJitSelectFusion(context, psrc, plantree_list, params); + break; case MOT_JIT_MODIFY_FUSION: - return New(context) MotJitModifyFusion(context, psrc, plantree_list, params); + opfusionObj = New(objCxt) MotJitModifyFusion(context, psrc, plantree_list, params); + break; #endif - case AGG_INDEX_FUSION: - return New(context) AggFusion(context, psrc, plantree_list, params); - + opfusionObj = New(objCxt) AggFusion(context, psrc, plantree_list, params); + break; case SORT_INDEX_FUSION: - return New(context) SortFusion(context, psrc, plantree_list, params); - + opfusionObj = New(objCxt) SortFusion(context, psrc, plantree_list, params); + break; case NONE_FUSION: - return NULL; - + opfusionObj = NULL; + break; default: - return NULL; + opfusionObj = NULL; + break; } - - return NULL; + if (opfusionObj != NULL && !((OpFusion*)opfusionObj)->m_global->m_is_global) + ((OpFusion*)opfusionObj)->m_global->m_type = ftype; + return opfusionObj; } void OpFusion::updatePreAllocParamter(StringInfo input_message) @@ -502,7 +601,7 @@ void OpFusion::updatePreAllocParamter(StringInfo input_message) int num_params; int num_rformats; int paramno; - ParamListInfo params = m_params; + ParamListInfo params = m_local.m_params; /* Get the parameter format codes */ num_pformats = pq_getmsgint(input_message, 2); if (num_pformats > 0) { @@ -516,13 +615,13 @@ void OpFusion::updatePreAllocParamter(StringInfo input_message) /* Get the parameter value count */ num_params = pq_getmsgint(input_message, 2); - if (unlikely(num_params != m_paramNum)) { + if (unlikely(num_params != m_global->m_paramNum)) { ereport(ERROR, (errcode(ERRCODE_UNDEFINED_PSTATEMENT), errmsg("unmatched parameter number"))); } - MemoryContextSwitchTo(m_tmpContext); + (void)MemoryContextSwitchTo(m_local.m_tmpContext); if (num_params > 0) { for (paramno = 0; paramno < num_params; paramno++) { - Oid ptype = m_psrc->param_types[paramno]; + Oid ptype = m_global->m_psrc->param_types[paramno]; int32 plength; Datum pval; bool isNull = false; @@ -671,10 +770,11 @@ void OpFusion::updatePreAllocParamter(StringInfo input_message) void OpFusion::describe(StringInfo msg) { - if (m_psrc->resultDesc != NULL) { + if (m_global->m_psrc->resultDesc != NULL) { StringInfoData buf; initStringInfo(&buf); - SendRowDescriptionMessage(&buf, m_tupDesc, m_planstmt->planTree->targetlist, m_rformats); + SendRowDescriptionMessage(&buf, m_global->m_tupDesc, + m_global->m_planstmt->planTree->targetlist, m_local.m_rformats); pfree_ext(buf.data); } else { pq_putemptymessage('n'); @@ -683,8 +783,8 @@ void OpFusion::describe(StringInfo msg) void OpFusion::setPreparedDestReceiver(DestReceiver* preparedDest) { - m_receiver = preparedDest; - m_isInsideRec = false; + m_local.m_receiver = preparedDest; + m_local.m_isInsideRec = false; } /* evaluate datum from node, simple node types such as Const, Param, Var excludes FuncExpr and OpExpr */ @@ -698,7 +798,7 @@ Datum OpFusion::EvalSimpleArg(Node* arg, bool* is_null, Datum* values, bool* isN *is_null = isNulls[(((Var*)arg)->varattno - 1)]; return values[(((Var*)arg)->varattno - 1)]; case T_Param: { - ParamListInfo param_list = m_outParams != NULL ? m_outParams : m_params; + ParamListInfo param_list = m_local.m_outParams != NULL ? m_local.m_outParams : m_local.m_params; if (param_list->params[(((Param*)arg)->paramid - 1)].isnull) { *is_null = true; @@ -794,19 +894,23 @@ void OpFusion::tearDown(OpFusion* opfusion) return; } - removeFusionFromHtab(opfusion->m_portalName); + removeFusionFromHtab(opfusion->m_local.m_portalName); - if (opfusion->m_cacheplan != NULL) { - ReleaseCachedPlan(opfusion->m_cacheplan, false); + if (!opfusion->IsGlobal()) { + if (opfusion->m_global->m_cacheplan != NULL) { + ReleaseCachedPlan(opfusion->m_global->m_cacheplan, false); + } + if (opfusion->m_global->m_psrc != NULL) { + opfusion->m_global->m_psrc->is_checked_opfusion = false; + opfusion->m_global->m_psrc->opFusionObj = NULL; + } + MemoryContextDelete(opfusion->m_global->m_context); + } else { + opfusion->m_global->m_psrc->gpc.status.SubRefCount(); } - if (opfusion->m_psrc != NULL) { - opfusion->m_psrc->is_checked_opfusion = false; - opfusion->m_psrc->opFusionObj = NULL; - } - - MemoryContextDelete(opfusion->m_tmpContext); - MemoryContextDelete(opfusion->m_context); + MemoryContextDelete(opfusion->m_local.m_tmpContext); + MemoryContextDelete(opfusion->m_local.m_localContext); delete opfusion; @@ -818,6 +922,7 @@ void OpFusion::clearForCplan(OpFusion* opfusion, CachedPlanSource* psrc) if (opfusion == NULL) return; if (psrc->cplan != NULL) { + Assert (!psrc->gpc.status.InShareTable()); tearDown(opfusion); } } @@ -825,36 +930,45 @@ void OpFusion::clearForCplan(OpFusion* opfusion, CachedPlanSource* psrc) /* just for select and select for */ void OpFusion::setReceiver() { - if (m_isInsideRec) { - m_receiver = CreateDestReceiver((CommandDest)t_thrd.postgres_cxt.whereToSendOutput); + if (m_local.m_isInsideRec) { + m_local.m_receiver = CreateDestReceiver((CommandDest)t_thrd.postgres_cxt.whereToSendOutput); } - ((DR_printtup*)m_receiver)->sendDescrip = false; - if (m_receiver->mydest == DestRemote || m_receiver->mydest == DestRemoteExecute) { - ((DR_printtup*)m_receiver)->formats = m_rformats; + ((DR_printtup*)m_local.m_receiver)->sendDescrip = false; + if (m_local.m_receiver->mydest == DestRemote || m_local.m_receiver->mydest == DestRemoteExecute) { + ((DR_printtup*)m_local.m_receiver)->formats = m_local.m_rformats; } - (*m_receiver->rStartup)(m_receiver, CMD_SELECT, m_tupDesc); - if (!m_is_pbe_query) { - StringInfoData buf = ((DR_printtup*)m_receiver)->buf; + (*m_local.m_receiver->rStartup)(m_local.m_receiver, CMD_SELECT, m_global->m_tupDesc); + if (!m_global->m_is_pbe_query) { + StringInfoData buf = ((DR_printtup*)m_local.m_receiver)->buf; initStringInfo(&buf); - SendRowDescriptionMessage(&buf, m_tupDesc, m_planstmt->planTree->targetlist, m_rformats); + SendRowDescriptionMessage(&buf, m_global->m_tupDesc, + m_global->m_planstmt->planTree->targetlist, m_local.m_rformats); } } void OpFusion::initParams(ParamListInfo params) { - m_outParams = params; - + m_local.m_outParams = params; /* init params */ - if (m_is_pbe_query && params != NULL) { - m_paramNum = params->numParams; - m_params = (ParamListInfo)palloc(offsetof(ParamListInfoData, params) + m_paramNum * sizeof(ParamExternData)); - m_params->paramFetch = NULL; - m_params->paramFetchArg = NULL; - m_params->parserSetup = NULL; - m_params->parserSetupArg = NULL; - m_params->params_need_process = false; - m_params->numParams = m_paramNum; + if (m_global->m_is_pbe_query && !IsGlobal() && params != NULL) { + m_global->m_paramNum = params->numParams; + m_local.m_params = (ParamListInfo)palloc(offsetof(ParamListInfoData, params) + + m_global->m_paramNum * sizeof(ParamExternData)); + m_local.m_params->paramFetch = NULL; + m_local.m_params->paramFetchArg = NULL; + m_local.m_params->parserSetup = NULL; + m_local.m_params->parserSetupArg = NULL; + m_local.m_params->params_need_process = false; + m_local.m_params->numParams = m_global->m_paramNum; + } else if (IsGlobal() && m_global->m_paramNum > 0) { + m_local.m_params = (ParamListInfo)palloc(offsetof(ParamListInfoData, params) + m_global->m_paramNum * sizeof(ParamExternData)); + m_local.m_params->paramFetch = NULL; + m_local.m_params->paramFetchArg = NULL; + m_local.m_params->parserSetup = NULL; + m_local.m_params->parserSetupArg = NULL; + m_local.m_params->params_need_process = false; + m_local.m_params->numParams = m_global->m_paramNum; } } @@ -869,14 +983,14 @@ bool OpFusion::isQueryCompleted() void OpFusion::bindClearPosition() { - m_isCompleted = false; - m_position = 0; - m_outParams = NULL; - m_snapshot = NULL; + m_local.m_isCompleted = false; + m_local.m_position = 0; + m_local.m_outParams = NULL; + m_local.m_snapshot = NULL; - MemoryContextDeleteChildren(m_tmpContext); + MemoryContextDeleteChildren(m_local.m_tmpContext); /* reset the context. */ - MemoryContextReset(m_tmpContext); + MemoryContextReset(m_local.m_tmpContext); } void OpFusion::initFusionHtab() @@ -901,34 +1015,89 @@ void OpFusion::ClearInUnexpectSituation() hash_seq_init(&seq, u_sess->pcache_cxt.pn_fusion_htab); while ((entry = (pnFusionObj *)hash_seq_search(&seq)) != NULL) { OpFusion* curr = entry->opfusion; - if (curr->m_portalName == NULL || strcmp(curr->m_portalName, entry->portalname) == 0) { + if (curr->IsGlobal()) { + curr->clean(); + OpFusion::tearDown(curr); + } else if (curr->m_local.m_portalName == NULL || + strcmp(curr->m_local.m_portalName, entry->portalname) == 0) { curr->clean(); /* only opfusion has reference on cachedplan, no need any more */ - if (curr->m_cacheplan && curr->m_cacheplan->refcount == 1) { - ReleaseCachedPlan(curr->m_cacheplan, false); - MemoryContextDelete(curr->m_tmpContext); - MemoryContextDelete(curr->m_context); + if (curr->m_global->m_cacheplan && curr->m_global->m_cacheplan->refcount == 1) { + ReleaseCachedPlan(curr->m_global->m_cacheplan, false); + MemoryContextDelete(curr->m_local.m_tmpContext); + MemoryContextDelete(curr->m_local.m_localContext); + MemoryContextDelete(curr->m_global->m_context); delete curr; } } - hash_search(u_sess->pcache_cxt.pn_fusion_htab, entry->portalname, HASH_REMOVE, NULL); + removeFusionFromHtab(entry->portalname); } } u_sess->exec_cxt.CurrentOpFusionObj = NULL; } +void OpFusion::ClearInSubUnexpectSituation(ResourceOwner owner) +{ + if (u_sess->pcache_cxt.pn_fusion_htab != NULL) { + HASH_SEQ_STATUS seq; + pnFusionObj *entry = NULL; + hash_seq_init(&seq, u_sess->pcache_cxt.pn_fusion_htab); + while ((entry = (pnFusionObj *)hash_seq_search(&seq)) != NULL) { + OpFusion* curr = entry->opfusion; + if (curr->m_local.m_resOwner != owner) + continue; + if (curr->IsGlobal()) { + curr->clean(); + OpFusion::tearDown(curr); + } else if (curr->m_local.m_portalName == NULL || + strcmp(curr->m_local.m_portalName, entry->portalname) == 0) { + curr->clean(); + /* only opfusion has reference on cachedplan, no need any more */ + if (curr->m_global->m_cacheplan && curr->m_global->m_cacheplan->refcount == 1) { + ReleaseCachedPlan(curr->m_global->m_cacheplan, false); + MemoryContextDelete(curr->m_local.m_tmpContext); + MemoryContextDelete(curr->m_local.m_localContext); + MemoryContextDelete(curr->m_global->m_context); + delete curr; + } + } + removeFusionFromHtab(entry->portalname); + } + } +} + + void OpFusion::clean() { - UnregisterSnapshot(m_snapshot); - m_snapshot = NULL; - m_position = 0; - m_outParams = NULL; - if (m_scan) - m_scan->End(true); - m_isCompleted = false; - MemoryContextDeleteChildren(m_tmpContext); - /* reset the context. */ - MemoryContextReset(m_tmpContext); + ResourceOwner oldResourceOwner = t_thrd.utils_cxt.CurrentResourceOwner; + bool hasChangeResOwner = false; + if (m_local.m_resOwner && m_local.m_resOwner != oldResourceOwner) { + t_thrd.utils_cxt.CurrentResourceOwner = m_local.m_resOwner; + hasChangeResOwner = true; + } + PG_TRY(); + { + UnregisterSnapshot(m_local.m_snapshot); + m_local.m_snapshot = NULL; + m_local.m_position = 0; + m_local.m_outParams = NULL; + if (m_local.m_scan) + m_local.m_scan->End(true); + m_local.m_isCompleted = false; + MemoryContextDeleteChildren(m_local.m_tmpContext); + /* reset the context. */ + MemoryContextReset(m_local.m_tmpContext); + } + PG_CATCH(); + { + t_thrd.utils_cxt.CurrentResourceOwner = oldResourceOwner; + PG_RE_THROW(); + } + PG_END_TRY(); + t_thrd.utils_cxt.CurrentResourceOwner = oldResourceOwner; + if (hasChangeResOwner) { + m_local.m_resOwner = NULL; + } } void OpFusion::storeFusion(const char *portalname) @@ -937,13 +1106,13 @@ void OpFusion::storeFusion(const char *portalname) if (!u_sess->pcache_cxt.pn_fusion_htab) initFusionHtab(); - removeFusionFromHtab(m_portalName); + removeFusionFromHtab(m_local.m_portalName); entry = (pnFusionObj *)(hash_search(u_sess->pcache_cxt.pn_fusion_htab, portalname, HASH_ENTER, NULL)); entry->opfusion = this; - MemoryContext old_cxt = MemoryContextSwitchTo(m_context); - pfree_ext(m_portalName); - m_portalName = pstrdup(portalname); + MemoryContext old_cxt = MemoryContextSwitchTo(m_local.m_localContext); + pfree_ext(m_local.m_portalName); + m_local.m_portalName = pstrdup(portalname); MemoryContextSwitchTo(old_cxt); } @@ -980,62 +1149,73 @@ void OpFusion::refreshCurFusion(StringInfo msg) msg->cursor = oldCursor; } -/* judge plan node is partiterator */ -Node* JudgePlanIsPartIterator(Plan* plan) -{ - Node* node = NULL; - if (IsA(plan, PartIterator)) { - node = (Node*)plan->lefttree; - } else { - node = (Node*)plan; - } - return node; -} SelectFusion::SelectFusion(MemoryContext context, CachedPlanSource* psrc, List* plantree_list, ParamListInfo params) : OpFusion(context, psrc, plantree_list) { - m_tmpvals = NULL; - m_values = NULL; - m_isnull = NULL; - m_paramLoc = NULL; - m_tmpisnull = NULL; - m_attrno = NULL; - m_reloid = 0; + MemoryContext old_context = NULL; + if (!IsGlobal()) { + old_context = MemoryContextSwitchTo(m_global->m_context); + InitGlobals(); + MemoryContextSwitchTo(old_context); + } else { + m_c_global = ((SelectFusion*)(psrc->opFusionObj))->m_c_global; + } + old_context = MemoryContextSwitchTo(m_local.m_localContext); + InitLocals(params); + MemoryContextSwitchTo(old_context); +} - MemoryContext old_context = MemoryContextSwitchTo(m_context); - Node* node = NULL; +void SelectFusion::InitGlobals() +{ + m_global->m_reloid = 0; + m_c_global = (SelectFusionGlobalVariable*)palloc0(sizeof(SelectFusionGlobalVariable)); - m_limitCount = -1; - m_limitOffset = -1; + m_c_global->m_limitCount = -1; + m_c_global->m_limitOffset = -1; /* get limit num */ - if (IsA(m_planstmt->planTree, Limit)) { - Limit* limit = (Limit*)m_planstmt->planTree; - node = JudgePlanIsPartIterator(m_planstmt->planTree->lefttree); + if (IsA(m_global->m_planstmt->planTree, Limit)) { + Limit* limit = (Limit*)m_global->m_planstmt->planTree; if (limit->limitCount != NULL && IsA(limit->limitCount, Const) && !((Const*)limit->limitCount)->constisnull) { - m_limitCount = DatumGetInt64(((Const*)limit->limitCount)->constvalue); + m_c_global->m_limitCount = DatumGetInt64(((Const*)limit->limitCount)->constvalue); } if (limit->limitOffset != NULL && IsA(limit->limitOffset, Const) && !((Const*)limit->limitOffset)->constisnull) { - m_limitOffset = DatumGetInt64(((Const*)limit->limitOffset)->constvalue); + m_c_global->m_limitOffset = DatumGetInt64(((Const*)limit->limitOffset)->constvalue); } - } else { - node = JudgePlanIsPartIterator(m_planstmt->planTree); } +} +void SelectFusion::InitLocals(ParamListInfo params) +{ + m_local.m_tmpvals = NULL; + m_local.m_values = NULL; + m_local.m_isnull = NULL; + m_local.m_tmpisnull = NULL; initParams(params); - m_receiver = NULL; - m_isInsideRec = true; - m_scan = ScanFusion::getScanFusion(node, m_planstmt, m_outParams); - m_tupDesc = m_scan->m_tupDesc; - m_reslot = NULL; - MemoryContextSwitchTo(old_context); + m_local.m_receiver = NULL; + m_local.m_isInsideRec = true; + + Node* node = NULL; + if (IsA(m_global->m_planstmt->planTree, Limit)) { + node = JudgePlanIsPartIterator(m_global->m_planstmt->planTree->lefttree); + } else { + node = JudgePlanIsPartIterator(m_global->m_planstmt->planTree); + } + m_local.m_scan = ScanFusion::getScanFusion(node, m_global->m_planstmt, + m_local.m_outParams ? m_local.m_outParams : m_local.m_params); + if (!IsGlobal()) { + MemoryContext old_context = MemoryContextSwitchTo(m_global->m_context); + m_global->m_tupDesc = CreateTupleDescCopy(m_local.m_scan->m_tupDesc); + MemoryContextSwitchTo(old_context); + } + m_local.m_reslot = NULL; } bool SelectFusion::execute(long max_rows, char* completionTag) { - MemoryContext oldContext = MemoryContextSwitchTo(m_tmpContext); + MemoryContext oldContext = MemoryContextSwitchTo(m_local.m_tmpContext); bool success = false; int64 start_row = 0; @@ -1044,50 +1224,50 @@ bool SelectFusion::execute(long max_rows, char* completionTag) /******************* * step 1: prepare * *******************/ - start_row = m_limitOffset >= 0 ? m_limitOffset : start_row; - get_rows = m_limitCount >= 0 ? (m_limitCount + start_row) : max_rows; + start_row = m_c_global->m_limitOffset >= 0 ? m_c_global->m_limitOffset : start_row; + get_rows = m_c_global->m_limitCount >= 0 ? (m_c_global->m_limitCount + start_row) : max_rows; /********************** * step 2: begin scan * **********************/ - if (m_position == 0) { - m_scan->refreshParameter(m_outParams == NULL ? m_params : m_outParams); - m_scan->Init(max_rows); + if (m_local.m_position == 0) { + m_local.m_scan->refreshParameter(m_local.m_outParams == NULL ? m_local.m_params : m_local.m_outParams); + m_local.m_scan->Init(max_rows); } setReceiver(); unsigned long nprocessed = 0; /* put selected tuple into receiver */ TupleTableSlot* offset_reslot = NULL; - while (nprocessed < (unsigned long)start_row && (offset_reslot = m_scan->getTupleSlot()) != NULL) { + while (nprocessed < (unsigned long)start_row && (offset_reslot = m_local.m_scan->getTupleSlot()) != NULL) { tpslot_free_heaptuple(offset_reslot); nprocessed++; } - while (nprocessed < (unsigned long)get_rows && (m_reslot = m_scan->getTupleSlot()) != NULL) { + while (nprocessed < (unsigned long)get_rows && (m_local.m_reslot = m_local.m_scan->getTupleSlot()) != NULL) { CHECK_FOR_INTERRUPTS(); nprocessed++; - (*m_receiver->receiveSlot)(m_reslot, m_receiver); - tpslot_free_heaptuple(m_reslot); + (*m_local.m_receiver->receiveSlot)(m_local.m_reslot, m_local.m_receiver); + tpslot_free_heaptuple(m_local.m_reslot); } - if (!ScanDirectionIsNoMovement(*(m_scan->m_direction))) { + if (!ScanDirectionIsNoMovement(*(m_local.m_scan->m_direction))) { if (max_rows == 0 || nprocessed < (unsigned long)max_rows) { - m_isCompleted = true; + m_local.m_isCompleted = true; } - m_position += nprocessed; + m_local.m_position += nprocessed; } else { - m_isCompleted = true; + m_local.m_isCompleted = true; } success = true; /**************** * step 3: done * ****************/ - if (m_isInsideRec) { - (*m_receiver->rDestroy)(m_receiver); + if (m_local.m_isInsideRec) { + (*m_local.m_receiver->rDestroy)(m_local.m_receiver); } - m_scan->End(m_isCompleted); - if (m_isCompleted) { - m_position = 0; + m_local.m_scan->End(m_local.m_isCompleted); + if (m_local.m_isCompleted) { + m_local.m_position = 0; } errno_t errorno = snprintf_s(completionTag, COMPLETION_TAG_BUFSIZE, COMPLETION_TAG_BUFSIZE - 1, "SELECT %lu", nprocessed); @@ -1099,10 +1279,10 @@ bool SelectFusion::execute(long max_rows, char* completionTag) void SelectFusion::close() { - if (m_isCompleted == false) { - m_scan->End(true); - m_isCompleted = true; - m_position = 0; + if (m_local.m_isCompleted == false) { + m_local.m_scan->End(true); + m_local.m_isCompleted = true; + m_local.m_position = 0; } } @@ -1111,28 +1291,40 @@ MotJitSelectFusion::MotJitSelectFusion( MemoryContext context, CachedPlanSource* psrc, List* plantree_list, ParamListInfo params) : OpFusion(context, psrc, plantree_list) { - MemoryContext oldContext = MemoryContextSwitchTo(m_context); - Node* node = NULL; - node = (Node*)m_planstmt->planTree; - initParams(params); - m_receiver = NULL; - m_isInsideRec = true; - - if (m_planstmt->planTree->targetlist) { - m_tupDesc = ExecCleanTypeFromTL(m_planstmt->planTree->targetlist, false); + MemoryContext old_context = NULL; + if (!IsGlobal()) { + old_context = MemoryContextSwitchTo(m_global->m_context); + InitGlobals(); + MemoryContextSwitchTo(old_context); + } + old_context = MemoryContextSwitchTo(m_local.m_localContext); + InitLocals(params); + MemoryContextSwitchTo(old_context); +} +void MotJitSelectFusion::InitGlobals() +{ + if (m_global->m_planstmt->planTree->targetlist) { + m_global->m_tupDesc = ExecCleanTypeFromTL(m_global->m_planstmt->planTree->targetlist, false); } else { ereport(ERROR, (errmodule(MOD_EXECUTOR), errcode(ERRCODE_UNRECOGNIZED_NODE_TYPE), - errmsg("unrecognized node type: %d when executing executor node.", (int)nodeTag(node)))); + errmsg("unrecognized node type: %d when executing executor node.", + (int)nodeTag(m_global->m_planstmt->planTree)))); } - m_reslot = MakeSingleTupleTableSlot(m_tupDesc); - MemoryContextSwitchTo(oldContext); } +void MotJitSelectFusion::InitLocals(ParamListInfo params) +{ + initParams(params); + m_local.m_receiver = NULL; + m_local.m_isInsideRec = true; + m_local.m_reslot = MakeSingleTupleTableSlot(m_global->m_tupDesc); + +} bool MotJitSelectFusion::execute(long max_rows, char* completionTag) { - ParamListInfo params = (m_outParams != NULL) ? m_outParams : m_params; + ParamListInfo params = (m_local.m_outParams != NULL) ? m_local.m_outParams : m_local.m_params; bool success = false; setReceiver(); unsigned long nprocessed = 0; @@ -1141,7 +1333,8 @@ bool MotJitSelectFusion::execute(long max_rows, char* completionTag) while (!finish) { uint64_t tpProcessed = 0; int scanEnded = 0; - rc = JitExec::JitExecQuery(m_cacheplan->mot_jit_context, params, m_reslot, &tpProcessed, &scanEnded); + rc = JitExec::JitExecQuery(m_global->m_cacheplan->mot_jit_context, params, m_local.m_reslot, + &tpProcessed, &scanEnded); if (scanEnded || (tpProcessed == 0) || (rc != 0)) { // raise flag so that next round we will bail out (current tuple still must be reported to user) finish = true; @@ -1149,8 +1342,8 @@ bool MotJitSelectFusion::execute(long max_rows, char* completionTag) CHECK_FOR_INTERRUPTS(); if (tpProcessed > 0) { nprocessed++; - (*m_receiver->receiveSlot)(m_reslot, m_receiver); - (void)ExecClearTuple(m_reslot); + (*m_local.m_receiver->receiveSlot)(m_local.m_reslot, m_local.m_receiver); + (void)ExecClearTuple(m_local.m_reslot); if ((max_rows != FETCH_ALL) && (nprocessed == (unsigned long)max_rows)) { finish = true; } @@ -1159,12 +1352,12 @@ bool MotJitSelectFusion::execute(long max_rows, char* completionTag) success = true; - if (m_isInsideRec) { - (*m_receiver->rDestroy)(m_receiver); + if (m_local.m_isInsideRec) { + (*m_local.m_receiver->rDestroy)(m_local.m_receiver); } - m_position = 0; - m_isCompleted = true; + m_local.m_position = 0; + m_local.m_isCompleted = true; errno_t errorno = snprintf_s(completionTag, COMPLETION_TAG_BUFSIZE, COMPLETION_TAG_BUFSIZE - 1, "SELECT %lu", nprocessed); @@ -1210,41 +1403,30 @@ void ExecDoneStepInFusion(Relation bucketRel, EState* estate) } } -InsertFusion::InsertFusion(MemoryContext context, CachedPlanSource* psrc, List* plantree_list, ParamListInfo params) - : OpFusion(context, psrc, plantree_list) +void InsertFusion::InitGlobals() { - m_tmpisnull = NULL; - m_tmpvals = NULL; - m_attrno = NULL; - - MemoryContext old_context = MemoryContextSwitchTo(m_context); - ModifyTable* node = (ModifyTable*)m_planstmt->planTree; - - m_reloid = getrelid(linitial_int(m_planstmt->resultRelations), m_planstmt->rtable); - Relation rel = heap_open(m_reloid, AccessShareLock); - - m_estate = CreateExecutorState(); - m_estate->es_range_table = m_planstmt->rtable; + m_c_global = (InsertFusionGlobalVariable*)palloc0(sizeof(InsertFusionGlobalVariable)); + m_global->m_reloid = getrelid(linitial_int(m_global->m_planstmt->resultRelations), m_global->m_planstmt->rtable); + ModifyTable* node = (ModifyTable*)m_global->m_planstmt->planTree; BaseResult* baseresult = (BaseResult*)linitial(node->plans); List* targetList = baseresult->plan.targetlist; - m_tupDesc = ExecTypeFromTL(targetList, false, false, rel->rd_tam_type); - m_reslot = MakeSingleTupleTableSlot(m_tupDesc); - m_values = (Datum*)palloc0(RelationGetDescr(rel)->natts * sizeof(Datum)); - m_isnull = (bool*)palloc0(RelationGetDescr(rel)->natts * sizeof(bool)); - m_curVarValue = (Datum*)palloc0(RelationGetDescr(rel)->natts * sizeof(Datum)); - m_curVarIsnull = (bool*)palloc0(RelationGetDescr(rel)->natts * sizeof(bool)); - m_is_bucket_rel = RELATION_OWN_BUCKET(rel); + Relation rel = heap_open(m_global->m_reloid, AccessShareLock); + m_global->m_natts = RelationGetDescr(rel)->natts; + m_global->m_table_type = rel->rd_tam_type; + m_global->m_is_bucket_rel = RELATION_OWN_BUCKET(rel); + m_global->m_tupDesc = ExecTypeFromTL(targetList, false, false, m_global->m_table_type); heap_close(rel, AccessShareLock); - /* init param */ - m_paramNum = 0; - m_paramLoc = (ParamLoc*)palloc0(RelationGetDescr(rel)->natts * sizeof(ParamLoc)); - m_targetParamNum = 0; - - m_targetFuncNum = 0; - m_targetFuncNodes = (FuncExprInfo*)palloc0(RelationGetDescr(rel)->natts * sizeof(FuncExprInfo)); + /* init param func const */ + m_global->m_paramNum = 0; + m_global->m_paramLoc = (ParamLoc*)palloc0(m_global->m_natts * sizeof(ParamLoc)); + m_c_global->m_targetParamNum = 0; + m_c_global->m_targetFuncNum = 0; + m_c_global->m_targetFuncNodes = (FuncExprInfo*)palloc0(m_global->m_natts * sizeof(FuncExprInfo)); + m_c_global->m_targetConstNum = 0; + m_c_global->m_targetConstLoc = (ConstLoc*)palloc0(m_global->m_natts * sizeof(ConstLoc)); ListCell* lc = NULL; int i = 0; @@ -1255,76 +1437,111 @@ InsertFusion::InsertFusion(MemoryContext context, CachedPlanSource* psrc, List* foreach (lc, targetList) { res = (TargetEntry*)lfirst(lc); expr = res->expr; - Assert( IsA(expr, Const) || IsA(expr, Param) || IsA(expr, FuncExpr) || IsA(expr, RelabelType) || IsA(expr, OpExpr)); while (IsA(expr, RelabelType)) { expr = ((RelabelType*)expr)->arg; } + m_c_global->m_targetConstLoc[i].constLoc = -1; if (IsA(expr, FuncExpr)) { func = (FuncExpr*)expr; - - m_targetFuncNodes[m_targetFuncNum].resno = res->resno; - m_targetFuncNodes[m_targetFuncNum].resname = res->resname; - m_targetFuncNodes[m_targetFuncNum].funcid = func->funcid; - m_targetFuncNodes[m_targetFuncNum].args = func->args; - ++m_targetFuncNum; + m_c_global->m_targetFuncNodes[m_c_global->m_targetFuncNum].resno = res->resno; + m_c_global->m_targetFuncNodes[m_c_global->m_targetFuncNum].resname = res->resname; + m_c_global->m_targetFuncNodes[m_c_global->m_targetFuncNum].funcid = func->funcid; + m_c_global->m_targetFuncNodes[m_c_global->m_targetFuncNum].args = func->args; + ++m_c_global->m_targetFuncNum; } else if (IsA(expr, Param)) { Param* param = (Param*)expr; - m_paramLoc[m_targetParamNum].paramId = param->paramid; - m_paramLoc[m_targetParamNum++].scanKeyIndx = i; + m_global->m_paramLoc[m_c_global->m_targetParamNum].paramId = param->paramid; + m_global->m_paramLoc[m_c_global->m_targetParamNum++].scanKeyIndx = i; } else if (IsA(expr, Const)) { Assert(IsA(expr, Const)); - m_isnull[i] = ((Const*)expr)->constisnull; - m_values[i] = ((Const*)expr)->constvalue; + m_c_global->m_targetConstLoc[i].constValue = ((Const*)expr)->constvalue; + m_c_global->m_targetConstLoc[i].constIsNull = ((Const*)expr)->constisnull; + m_c_global->m_targetConstLoc[i].constLoc = i; } else if (IsA(expr, OpExpr)) { opexpr = (OpExpr*)expr; - - m_targetFuncNodes[m_targetFuncNum].resno = res->resno; - m_targetFuncNodes[m_targetFuncNum].resname = res->resname; - m_targetFuncNodes[m_targetFuncNum].funcid = opexpr->opfuncid; - m_targetFuncNodes[m_targetFuncNum].args = opexpr->args; - ++m_targetFuncNum; + m_c_global->m_targetFuncNodes[m_c_global->m_targetFuncNum].resno = res->resno; + m_c_global->m_targetFuncNodes[m_c_global->m_targetFuncNum].resname = res->resname; + m_c_global->m_targetFuncNodes[m_c_global->m_targetFuncNum].funcid = opexpr->opfuncid; + m_c_global->m_targetFuncNodes[m_c_global->m_targetFuncNum].args = opexpr->args; + ++m_c_global->m_targetFuncNum; } - i++; } + m_c_global->m_targetConstNum = i; + +} +void InsertFusion::InitLocals(ParamListInfo params) +{ + m_c_local.m_estate = CreateExecutorState(); + m_c_local.m_estate->es_range_table = m_global->m_planstmt->rtable; + m_local.m_reslot = MakeSingleTupleTableSlot(m_global->m_tupDesc); + m_local.m_values = (Datum*)palloc0(m_global->m_natts * sizeof(Datum)); + m_local.m_isnull = (bool*)palloc0(m_global->m_natts * sizeof(bool)); + m_c_local.m_curVarValue = (Datum*)palloc0(m_global->m_natts * sizeof(Datum)); + m_c_local.m_curVarIsnull = (bool*)palloc0(m_global->m_natts * sizeof(bool)); initParams(params); + m_local.m_receiver = NULL; + m_local.m_isInsideRec = true; +} - m_receiver = NULL; - m_isInsideRec = true; - +InsertFusion::InsertFusion(MemoryContext context, CachedPlanSource* psrc, List* plantree_list, ParamListInfo params) + : OpFusion(context, psrc, plantree_list) +{ + MemoryContext old_context = NULL; + if (!IsGlobal()) { + old_context = MemoryContextSwitchTo(m_global->m_context); + InitGlobals(); + MemoryContextSwitchTo(old_context); + } else { + m_c_global = ((InsertFusion*)(psrc->opFusionObj))->m_c_global; + } + old_context = MemoryContextSwitchTo(m_local.m_localContext); + InitLocals(params); MemoryContextSwitchTo(old_context); } void InsertFusion::refreshParameterIfNecessary() { - ParamListInfo parms = m_outParams != NULL ? m_outParams : m_params; + ParamListInfo parms = m_local.m_outParams != NULL ? m_local.m_outParams : m_local.m_params; bool func_isnull = false; /* save cur var value */ - for (int i = 0; i < m_tupDesc->natts; i++) { - m_curVarValue[i] = m_values[i]; - m_curVarIsnull[i] = m_isnull[i]; + for (int i = 0; i < m_global->m_tupDesc->natts; i++) { + m_c_local.m_curVarValue[i] = m_local.m_values[i]; + m_c_local.m_curVarIsnull[i] = m_local.m_isnull[i]; + } + /* refresh const value */ + for (int i = 0; i < m_c_global->m_targetConstNum; i++) { + if (m_c_global->m_targetConstLoc[i].constLoc >= 0) { + m_local.m_values[m_c_global->m_targetConstLoc[i].constLoc] = m_c_global->m_targetConstLoc[i].constValue; + m_local.m_isnull[m_c_global->m_targetConstLoc[i].constLoc] = m_c_global->m_targetConstLoc[i].constIsNull; + } } - /* calculate func result */ - for (int i = 0; i < m_targetFuncNum; ++i) { - ELOG_FIELD_NAME_START(m_targetFuncNodes[i].resname); - if (m_targetFuncNodes[i].funcid != InvalidOid) { + for (int i = 0; i < m_c_global->m_targetFuncNum; ++i) { + ELOG_FIELD_NAME_START(m_c_global->m_targetFuncNodes[i].resname); + if (m_c_global->m_targetFuncNodes[i].funcid != InvalidOid) { func_isnull = false; - m_values[m_targetFuncNodes[i].resno - 1] = CalFuncNodeVal( - m_targetFuncNodes[i].funcid, m_targetFuncNodes[i].args, &func_isnull, m_curVarValue, m_curVarIsnull); - m_isnull[m_targetFuncNodes[i].resno - 1] = func_isnull; + m_local.m_values[m_c_global->m_targetFuncNodes[i].resno - 1] = + CalFuncNodeVal(m_c_global->m_targetFuncNodes[i].funcid, + m_c_global->m_targetFuncNodes[i].args, + &func_isnull, + m_c_local.m_curVarValue, + m_c_local.m_curVarIsnull); + m_local.m_isnull[m_c_global->m_targetFuncNodes[i].resno - 1] = func_isnull; } ELOG_FIELD_NAME_END; } /* mapping params */ - if (m_targetParamNum > 0) { - for (int i = 0; i < m_targetParamNum; i++) { - m_values[m_paramLoc[i].scanKeyIndx] = parms->params[m_paramLoc[i].paramId - 1].value; - m_isnull[m_paramLoc[i].scanKeyIndx] = parms->params[m_paramLoc[i].paramId - 1].isnull; + if (m_c_global->m_targetParamNum > 0) { + for (int i = 0; i < m_c_global->m_targetParamNum; i++) { + m_local.m_values[m_global->m_paramLoc[i].scanKeyIndx] = + parms->params[m_global->m_paramLoc[i].paramId - 1].value; + m_local.m_isnull[m_global->m_paramLoc[i].scanKeyIndx] = + parms->params[m_global->m_paramLoc[i].paramId - 1].isnull; } } } @@ -1339,13 +1556,13 @@ bool InsertFusion::execute(long max_rows, char* completionTag) /******************* * step 1: prepare * *******************/ - Relation rel = heap_open(m_reloid, RowExclusiveLock); + Relation rel = heap_open(m_global->m_reloid, RowExclusiveLock); Relation bucket_rel = NULL; int2 bucketid = InvalidBktId; ResultRelInfo* result_rel_info = makeNode(ResultRelInfo); InitResultRelInfo(result_rel_info, rel, 1, 0); - m_estate->es_result_relation_info = result_rel_info; + m_c_local.m_estate->es_result_relation_info = result_rel_info; if (result_rel_info->ri_RelationDesc->rd_rel->relhasindex) { @@ -1359,24 +1576,25 @@ bool InsertFusion::execute(long max_rows, char* completionTag) /************************ * step 2: begin insert * ************************/ - HeapTuple tuple = (HeapTuple)tableam_tops_form_tuple(m_tupDesc, m_values, m_isnull, HEAP_TUPLE); + HeapTuple tuple = (HeapTuple)tableam_tops_form_tuple(m_global->m_tupDesc, m_local.m_values, + m_local.m_isnull, HEAP_TUPLE); Assert(tuple != NULL); if (RELATION_IS_PARTITIONED(rel)) { - m_estate->esfRelations = NULL; + m_c_local.m_estate->esfRelations = NULL; partOid = heapTupleGetPartitionId(rel, tuple); part = partitionOpen(rel, partOid, RowExclusiveLock); partRel = partitionGetRelation(rel, part); } - if (m_is_bucket_rel) { + if (m_global->m_is_bucket_rel) { bucketid = computeTupleBucketId(result_rel_info->ri_RelationDesc, tuple); bucket_rel = InitBucketRelation(bucketid, rel, part); } - (void)ExecStoreTuple(tuple, m_reslot, InvalidBuffer, false); + (void)ExecStoreTuple(tuple, m_local.m_reslot, InvalidBuffer, false); if (rel->rd_att->constr) { - ExecConstraints(result_rel_info, m_reslot, m_estate); + ExecConstraints(result_rel_info, m_local.m_reslot, m_c_local.m_estate); } Relation destRel = RELATION_IS_PARTITIONED(rel) ? partRel : rel; (void)tableam_tuple_insert(bucket_rel == NULL ? destRel : bucket_rel, tuple, mycid, 0, NULL); @@ -1393,9 +1611,9 @@ bool InsertFusion::execute(long max_rows, char* completionTag) /* insert index entries for tuple */ List* recheck_indexes = NIL; if (result_rel_info->ri_NumIndices > 0) { - recheck_indexes = ExecInsertIndexTuples(m_reslot, + recheck_indexes = ExecInsertIndexTuples(m_local.m_reslot, &(tuple->t_self), - m_estate, + m_c_local.m_estate, RELATION_IS_PARTITIONED(rel) ? partRel : NULL, RELATION_IS_PARTITIONED(rel) ? part : NULL, bucketid, NULL); @@ -1404,9 +1622,9 @@ bool InsertFusion::execute(long max_rows, char* completionTag) tableam_tops_free_tuple(tuple); - (void)ExecClearTuple(m_reslot); + (void)ExecClearTuple(m_local.m_reslot); success = true; - m_isCompleted = true; + m_local.m_isCompleted = true; /**************** * step 3: done * ****************/ @@ -1414,7 +1632,7 @@ bool InsertFusion::execute(long max_rows, char* completionTag) heap_close(rel, RowExclusiveLock); - ExecDoneStepInFusion(bucket_rel, m_estate); + ExecDoneStepInFusion(bucket_rel, m_c_local.m_estate); if (RELATION_IS_PARTITIONED(rel)) { partitionClose(rel, part, RowExclusiveLock); @@ -1432,27 +1650,40 @@ MotJitModifyFusion::MotJitModifyFusion( MemoryContext context, CachedPlanSource* psrc, List* plantree_list, ParamListInfo params) : OpFusion(context, psrc, plantree_list) { - MemoryContext oldContext = MemoryContextSwitchTo(m_context); - ModifyTable* node = (ModifyTable*)m_planstmt->planTree; - m_cmdType = node->operation; + MemoryContext old_context = NULL; - m_reloid = getrelid(linitial_int(m_planstmt->resultRelations), m_planstmt->rtable); - - m_estate = CreateExecutorState(); - m_estate->es_range_table = m_planstmt->rtable; + if (!IsGlobal()) { + old_context = MemoryContextSwitchTo(m_global->m_context); + InitGlobals(); + MemoryContextSwitchTo(old_context); + } + old_context = MemoryContextSwitchTo(m_local.m_localContext); + InitLocals(params); + MemoryContextSwitchTo(old_context); +} +void MotJitModifyFusion::InitGlobals() +{ + m_global->m_reloid = getrelid(linitial_int(m_global->m_planstmt->resultRelations), m_global->m_planstmt->rtable); + ModifyTable* node = (ModifyTable*)m_global->m_planstmt->planTree; BaseResult* baseresult = (BaseResult*)linitial(node->plans); List* targetList = baseresult->plan.targetlist; - m_tupDesc = ExecTypeFromTL(targetList, false); - m_reslot = MakeSingleTupleTableSlot(m_tupDesc); + m_global->m_tupDesc = ExecTypeFromTL(targetList, false); + m_global->m_paramNum = 0; +} + +void MotJitModifyFusion::InitLocals(ParamListInfo params) +{ + ModifyTable* node = (ModifyTable*)m_global->m_planstmt->planTree; + m_c_local.m_cmdType = node->operation; + m_c_local.m_estate = CreateExecutorState(); + m_c_local.m_estate->es_range_table = m_global->m_planstmt->rtable; /* init param */ - m_paramNum = 0; + m_local.m_reslot = MakeSingleTupleTableSlot(m_global->m_tupDesc); initParams(params); - m_receiver = NULL; - m_isInsideRec = true; - - MemoryContextSwitchTo(oldContext); + m_local.m_receiver = NULL; + m_local.m_isInsideRec = true; } bool MotJitModifyFusion::execute(long max_rows, char* completionTag) @@ -1460,13 +1691,14 @@ bool MotJitModifyFusion::execute(long max_rows, char* completionTag) bool success = false; uint64_t tpProcessed = 0; int scanEnded = 0; - ParamListInfo params = (m_outParams != NULL) ? m_outParams : m_params; - int rc = JitExec::JitExecQuery(m_cacheplan->mot_jit_context, params, m_reslot, &tpProcessed, &scanEnded); + ParamListInfo params = (m_local.m_outParams != NULL) ? m_local.m_outParams : m_local.m_params; + int rc = JitExec::JitExecQuery(m_global->m_cacheplan->mot_jit_context, params, m_local.m_reslot, + &tpProcessed, &scanEnded); if (rc == 0) { - (void)ExecClearTuple(m_reslot); + (void)ExecClearTuple(m_local.m_reslot); success = true; errno_t ret = EOK; - switch (m_cmdType) + switch (m_c_local.m_cmdType) { case CMD_INSERT: ret = snprintf_s(completionTag, COMPLETION_TAG_BUFSIZE, COMPLETION_TAG_BUFSIZE - 1, @@ -1488,7 +1720,7 @@ bool MotJitModifyFusion::execute(long max_rows, char* completionTag) } } - m_isCompleted = true; + m_local.m_isCompleted = true; return success; } @@ -1498,14 +1730,14 @@ HeapTuple UpdateFusion::heapModifyTuple(HeapTuple tuple) { HeapTuple new_tuple; - tableam_tops_deform_tuple(tuple, m_tupDesc, m_values, m_isnull); + tableam_tops_deform_tuple(tuple, m_global->m_tupDesc, m_local.m_values, m_local.m_isnull); refreshTargetParameterIfNecessary(); /* * create a new tuple from the values and isnull arrays */ - new_tuple = (HeapTuple)tableam_tops_form_tuple(m_tupDesc, m_values, m_isnull, HEAP_TUPLE); + new_tuple = (HeapTuple)tableam_tops_form_tuple(m_global->m_tupDesc, m_local.m_values, m_local.m_isnull, HEAP_TUPLE); /* * copy the identification info of the old tuple: t_ctid, t_self, and OID @@ -1520,7 +1752,7 @@ HeapTuple UpdateFusion::heapModifyTuple(HeapTuple tuple) new_tuple->t_xc_node_id = tuple->t_xc_node_id; #endif - Assert(m_tupDesc->tdhasoid == false); + Assert(m_global->m_tupDesc->tdhasoid == false); return new_tuple; } @@ -1528,65 +1760,66 @@ HeapTuple UpdateFusion::heapModifyTuple(HeapTuple tuple) UpdateFusion::UpdateFusion(MemoryContext context, CachedPlanSource* psrc, List* plantree_list, ParamListInfo params) : OpFusion(context, psrc, plantree_list) { - m_attrno = NULL; - m_paramLoc = NULL; - m_tmpisnull = NULL; - m_tmpvals = NULL; + MemoryContext old_context = NULL; - MemoryContext old_context = MemoryContextSwitchTo(m_context); - ModifyTable* node = (ModifyTable*)m_planstmt->planTree; + if (!IsGlobal()) { + old_context = MemoryContextSwitchTo(m_global->m_context); + InitGlobals(); + MemoryContextSwitchTo(old_context); + } else { + m_c_global = ((UpdateFusion*)(psrc->opFusionObj))->m_c_global; + } + old_context = MemoryContextSwitchTo(m_local.m_localContext); + InitLocals(params); + MemoryContextSwitchTo(old_context); +} + +void UpdateFusion::InitGlobals() +{ + m_c_global = (UpdateFusionGlobalVariable*)palloc0(sizeof(UpdateFusionGlobalVariable)); + + ModifyTable* node = (ModifyTable*)m_global->m_planstmt->planTree; Plan *updatePlan = (Plan *)linitial(node->plans); IndexScan* indexscan = (IndexScan *)JudgePlanIsPartIterator(updatePlan); - - m_reloid = getrelid(linitial_int(m_planstmt->resultRelations), m_planstmt->rtable); - Relation rel = heap_open(m_reloid, AccessShareLock); - - m_estate = CreateExecutorState(); - m_estate->es_range_table = m_planstmt->rtable; - - m_tupDesc = CreateTupleDescCopy(RelationGetDescr(rel)); - m_reslot = MakeSingleTupleTableSlot(m_tupDesc); - m_values = (Datum*)palloc0(RelationGetDescr(rel)->natts * sizeof(Datum)); - m_isnull = (bool*)palloc0(RelationGetDescr(rel)->natts * sizeof(bool)); - m_is_bucket_rel = RELATION_OWN_BUCKET(rel); - + + m_global->m_reloid = getrelid(linitial_int(m_global->m_planstmt->resultRelations), m_global->m_planstmt->rtable); + Relation rel = heap_open(m_global->m_reloid, AccessShareLock); + m_global->m_is_bucket_rel = RELATION_OWN_BUCKET(rel); + m_global->m_natts = RelationGetDescr(rel)->natts; + m_global->m_tupDesc = CreateTupleDescCopy(RelationGetDescr(rel)); heap_close(rel, AccessShareLock); - if (m_is_bucket_rel) { - // ctid + tablebucketid - Assert(RelationGetDescr(rel)->natts + 2 == list_length(indexscan->scan.plan.targetlist)); +#ifdef USE_ASSERT_CHECKING + if (m_global->m_is_bucket_rel) { + /* ctid + tablebucketid */ + Assert(m_global->m_natts + 2 == list_length(indexscan->scan.plan.targetlist)); } else { - // ctid + /* ctid */ if (indexscan->scan.isPartTbl) { - Assert(RelationGetDescr(rel)->natts + 2 == list_length(indexscan->scan.plan.targetlist)); + Assert(m_global->m_natts + 2 == list_length(indexscan->scan.plan.targetlist)); } else { - Assert(RelationGetDescr(rel)->natts + 1 == list_length(indexscan->scan.plan.targetlist)); + Assert(m_global->m_natts + 1 == list_length(indexscan->scan.plan.targetlist)); } } - m_outParams = params; - +#endif /* init target, include param and const */ - m_targetParamNum = 0; - m_targetValues = (Datum*)palloc0(RelationGetDescr(rel)->natts * sizeof(Datum)); - m_targetIsnull = (bool*)palloc0(RelationGetDescr(rel)->natts * sizeof(bool)); - m_targetParamLoc = (ParamLoc*)palloc0(RelationGetDescr(rel)->natts * sizeof(ParamLoc)); - m_targetConstLoc = (int*)palloc0(RelationGetDescr(rel)->natts * sizeof(int)); - m_curVarValue = (Datum*)palloc0(RelationGetDescr(rel)->natts * sizeof(Datum)); - m_curVarIsnull = (bool*)palloc0(RelationGetDescr(rel)->natts * sizeof(bool)); - m_targetVarLoc = (VarLoc*)palloc0(RelationGetDescr(rel)->natts * sizeof(VarLoc)); - - m_targetFuncNum = 0; - m_targetFuncNodes = (FuncExprInfo*)palloc0(RelationGetDescr(rel)->natts * sizeof(FuncExprInfo)); - m_varNum = 0; + m_c_global->m_targetParamNum = 0; + m_c_global->m_targetParamLoc = (ParamLoc*)palloc0(m_global->m_natts * sizeof(ParamLoc)); + m_c_global->m_targetConstLoc = (ConstLoc*)palloc0(m_global->m_natts * sizeof(ConstLoc)); + m_c_global->m_targetVarLoc = (VarLoc*)palloc0(m_global->m_natts * sizeof(VarLoc)); + m_c_global->m_targetFuncNum = 0; + m_c_global->m_targetFuncNodes = (FuncExprInfo*)palloc0(m_global->m_natts * sizeof(FuncExprInfo)); + m_c_global->m_varNum = 0; int i = 0; ListCell* lc = NULL; OpExpr* opexpr = NULL; FuncExpr* func = NULL; Expr* expr = NULL; + foreach (lc, indexscan->scan.plan.targetlist) { - // ignore ctid + tablebucketid or ctid at last - if (i >= RelationGetDescr(rel)->natts) { + /* ignore ctid + tablebucketid or ctid at last */ + if (i >= m_global->m_natts) { break; } @@ -1597,89 +1830,112 @@ UpdateFusion::UpdateFusion(MemoryContext context, CachedPlanSource* psrc, List* expr = ((RelabelType*)expr)->arg; } - m_targetConstLoc[i] = -1; + m_c_global->m_targetConstLoc[i].constLoc = -1; if (IsA(expr, Param)) { Param* param = (Param*)expr; - m_targetParamLoc[m_targetParamNum].paramId = param->paramid; - m_targetParamLoc[m_targetParamNum++].scanKeyIndx = i; + m_c_global->m_targetParamLoc[m_c_global->m_targetParamNum].paramId = param->paramid; + m_c_global->m_targetParamLoc[m_c_global->m_targetParamNum++].scanKeyIndx = i; } else if (IsA(expr, Const)) { - m_targetIsnull[i] = ((Const*)expr)->constisnull; - m_targetValues[i] = ((Const*)expr)->constvalue; - m_targetConstLoc[i] = i; + m_c_global->m_targetConstLoc[i].constValue = ((Const*)expr)->constvalue; + m_c_global->m_targetConstLoc[i].constIsNull = ((Const*)expr)->constisnull; + m_c_global->m_targetConstLoc[i].constLoc = i; } else if (IsA(expr, Var)) { Var* var = (Var*)expr; - m_targetVarLoc[m_varNum].varNo = var->varattno; - m_targetVarLoc[m_varNum++].scanKeyIndx = i; + m_c_global->m_targetVarLoc[m_c_global->m_varNum].varNo = var->varattno; + m_c_global->m_targetVarLoc[m_c_global->m_varNum++].scanKeyIndx = i; } else if (IsA(expr, OpExpr)) { opexpr = (OpExpr*)expr; - - m_targetFuncNodes[m_targetFuncNum].resno = res->resno; - m_targetFuncNodes[m_targetFuncNum].resname = res->resname; - m_targetFuncNodes[m_targetFuncNum].funcid = opexpr->opfuncid; - m_targetFuncNodes[m_targetFuncNum].args = opexpr->args; - ++m_targetFuncNum; + m_c_global->m_targetFuncNodes[m_c_global->m_targetFuncNum].resno = res->resno; + m_c_global->m_targetFuncNodes[m_c_global->m_targetFuncNum].resname = res->resname; + m_c_global->m_targetFuncNodes[m_c_global->m_targetFuncNum].funcid = opexpr->opfuncid; + m_c_global->m_targetFuncNodes[m_c_global->m_targetFuncNum].args = opexpr->args; + ++m_c_global->m_targetFuncNum; } else if (IsA(expr, FuncExpr)) { func = (FuncExpr*)expr; - - m_targetFuncNodes[m_targetFuncNum].resno = res->resno; - m_targetFuncNodes[m_targetFuncNum].resname = res->resname; - m_targetFuncNodes[m_targetFuncNum].funcid = func->funcid; - m_targetFuncNodes[m_targetFuncNum].args = func->args; - ++m_targetFuncNum; + m_c_global->m_targetFuncNodes[m_c_global->m_targetFuncNum].resno = res->resno; + m_c_global->m_targetFuncNodes[m_c_global->m_targetFuncNum].resname = res->resname; + m_c_global->m_targetFuncNodes[m_c_global->m_targetFuncNum].funcid = func->funcid; + m_c_global->m_targetFuncNodes[m_c_global->m_targetFuncNum].args = func->args; + ++m_c_global->m_targetFuncNum; } - i++; } + m_c_global->m_targetConstNum = i; +} - m_targetNum = i; +void UpdateFusion::InitLocals(ParamListInfo params) +{ + m_local.m_tmpisnull = NULL; + m_local.m_tmpvals = NULL; + m_c_local.m_estate = CreateExecutorState(); + m_c_local.m_estate->es_range_table = m_global->m_planstmt->rtable; + m_local.m_reslot = MakeSingleTupleTableSlot(m_global->m_tupDesc); + + m_local.m_values = (Datum*)palloc0(m_global->m_natts * sizeof(Datum)); + m_local.m_isnull = (bool*)palloc0(m_global->m_natts * sizeof(bool)); + + m_c_local.m_curVarValue = (Datum*)palloc0(m_global->m_natts * sizeof(Datum)); + m_c_local.m_curVarIsnull = (bool*)palloc0(m_global->m_natts * sizeof(bool)); + + m_local.m_outParams = params; initParams(params); - m_receiver = NULL; - m_isInsideRec = true; - m_scan = ScanFusion::getScanFusion((Node*)indexscan, m_planstmt, m_outParams); + m_local.m_receiver = NULL; + m_local.m_isInsideRec = true; - MemoryContextSwitchTo(old_context); + ModifyTable* node = (ModifyTable*)m_global->m_planstmt->planTree; + Plan *updatePlan = (Plan *)linitial(node->plans); + IndexScan* indexscan = (IndexScan *)JudgePlanIsPartIterator(updatePlan); + m_local.m_scan = ScanFusion::getScanFusion((Node*)indexscan, m_global->m_planstmt, + m_local.m_outParams ? m_local.m_outParams : m_local.m_params); } void UpdateFusion::refreshTargetParameterIfNecessary() { - ParamListInfo parms = m_outParams != NULL ? m_outParams : m_params; + ParamListInfo parms = m_local.m_outParams != NULL ? m_local.m_outParams : m_local.m_params; /* save cur var value */ - for (int i = 0; i < m_tupDesc->natts; i++) { - m_curVarValue[i] = m_values[i]; - m_curVarIsnull[i] = m_isnull[i]; + for (int i = 0; i < m_global->m_tupDesc->natts; i++) { + m_c_local.m_curVarValue[i] = m_local.m_values[i]; + m_c_local.m_curVarIsnull[i] = m_local.m_isnull[i]; } - if (m_varNum > 0) { - for (int i = 0; i < m_varNum; i++) { - m_values[m_targetVarLoc[i].scanKeyIndx] = m_curVarValue[m_targetVarLoc[i].varNo - 1]; - m_isnull[m_targetVarLoc[i].scanKeyIndx] = m_curVarIsnull[m_targetVarLoc[i].varNo - 1]; + if (m_c_global->m_varNum > 0) { + for (int i = 0; i < m_c_global->m_varNum; i++) { + m_local.m_values[m_c_global->m_targetVarLoc[i].scanKeyIndx] = + m_c_local.m_curVarValue[m_c_global->m_targetVarLoc[i].varNo - 1]; + m_local.m_isnull[m_c_global->m_targetVarLoc[i].scanKeyIndx] = + m_c_local.m_curVarIsnull[m_c_global->m_targetVarLoc[i].varNo - 1]; } } /* mapping value for update from target */ - if (m_targetParamNum > 0) { - Assert(m_targetParamNum > 0); - for (int i = 0; i < m_targetParamNum; i++) { - m_values[m_targetParamLoc[i].scanKeyIndx] = parms->params[m_targetParamLoc[i].paramId - 1].value; - m_isnull[m_targetParamLoc[i].scanKeyIndx] = parms->params[m_targetParamLoc[i].paramId - 1].isnull; + if (m_c_global->m_targetParamNum > 0) { + Assert(m_c_global->m_targetParamNum > 0); + for (int i = 0; i < m_c_global->m_targetParamNum; i++) { + m_local.m_values[m_c_global->m_targetParamLoc[i].scanKeyIndx] = + parms->params[m_c_global->m_targetParamLoc[i].paramId - 1].value; + m_local.m_isnull[m_c_global->m_targetParamLoc[i].scanKeyIndx] = + parms->params[m_c_global->m_targetParamLoc[i].paramId - 1].isnull; } } - for (int i = 0; i < m_targetNum; i++) { - if (m_targetConstLoc[i] >= 0) { - m_values[i] = m_targetValues[m_targetConstLoc[i]]; - m_isnull[i] = m_targetIsnull[m_targetConstLoc[i]]; + for (int i = 0; i < m_c_global->m_targetConstNum; i++) { + if (m_c_global->m_targetConstLoc[i].constLoc >= 0) { + m_local.m_values[m_c_global->m_targetConstLoc[i].constLoc] = m_c_global->m_targetConstLoc[i].constValue; + m_local.m_isnull[m_c_global->m_targetConstLoc[i].constLoc] = m_c_global->m_targetConstLoc[i].constIsNull; } } /* calculate func result */ - for (int i = 0; i < m_targetFuncNum; ++i) { - ELOG_FIELD_NAME_START(m_targetFuncNodes[i].resname); - if (m_targetFuncNodes[i].funcid != InvalidOid) { + for (int i = 0; i < m_c_global->m_targetFuncNum; ++i) { + ELOG_FIELD_NAME_START(m_c_global->m_targetFuncNodes[i].resname); + if (m_c_global->m_targetFuncNodes[i].funcid != InvalidOid) { bool func_isnull = false; - m_values[m_targetFuncNodes[i].resno - 1] = - CalFuncNodeVal(m_targetFuncNodes[i].funcid, m_targetFuncNodes[i].args, &func_isnull, - m_curVarValue, m_curVarIsnull); - m_isnull[m_targetFuncNodes[i].resno - 1] = func_isnull; + m_local.m_values[m_c_global->m_targetFuncNodes[i].resno - 1] = + CalFuncNodeVal(m_c_global->m_targetFuncNodes[i].funcid, + m_c_global->m_targetFuncNodes[i].args, + &func_isnull, + m_c_local.m_curVarValue, + m_c_local.m_curVarIsnull); + m_local.m_isnull[m_c_global->m_targetFuncNodes[i].resno - 1] = func_isnull; } ELOG_FIELD_NAME_END; } @@ -1693,11 +1949,11 @@ bool UpdateFusion::execute(long max_rows, char* completionTag) /******************* * step 1: prepare * *******************/ - m_scan->refreshParameter(m_outParams == NULL ? m_params : m_outParams); + m_local.m_scan->refreshParameter(m_local.m_outParams == NULL ? m_local.m_params : m_local.m_outParams); - m_scan->Init(max_rows); + m_local.m_scan->Init(max_rows); - Relation rel = ((m_scan->m_parentRel) == NULL ? m_scan->m_rel : m_scan->m_parentRel); + Relation rel = ((m_local.m_scan->m_parentRel) == NULL ? m_local.m_scan->m_rel : m_local.m_scan->m_parentRel); Relation partRel = NULL; Partition part = NULL; Relation bucket_rel = NULL; @@ -1705,14 +1961,14 @@ bool UpdateFusion::execute(long max_rows, char* completionTag) ResultRelInfo* result_rel_info = makeNode(ResultRelInfo); InitResultRelInfo(result_rel_info, rel, 1, 0); - m_estate->es_result_relation_info = result_rel_info; - m_estate->es_output_cid = GetCurrentCommandId(true); + m_c_local.m_estate->es_result_relation_info = result_rel_info; + m_c_local.m_estate->es_output_cid = GetCurrentCommandId(true); if (result_rel_info->ri_RelationDesc->rd_rel->relhasindex) { ExecOpenIndices(result_rel_info, false); } - InitPartitionByScanFusion(rel, &partRel, &part, m_estate, m_scan); + InitPartitionByScanFusion(rel, &partRel, &part, m_c_local.m_estate, m_local.m_scan); /********************************* * step 2: begin scan and update * @@ -1721,9 +1977,8 @@ bool UpdateFusion::execute(long max_rows, char* completionTag) HeapTuple tup = NULL; unsigned long nprocessed = 0; List* recheck_indexes = NIL; - m_tupDesc = RelationGetDescr(rel); - while ((oldtup = m_scan->getTuple()) != NULL) { + while ((oldtup = m_local.m_scan->getTuple()) != NULL) { CHECK_FOR_INTERRUPTS(); TM_Result result; TM_FailureData tmfd; @@ -1733,25 +1988,25 @@ bool UpdateFusion::execute(long max_rows, char* completionTag) Relation parentRel = RELATION_IS_PARTITIONED(rel) ? rel : NULL; tup = heapModifyTuple(oldtup); - m_scan->UpdateCurrentRel(&rel); - if (m_is_bucket_rel) { + m_local.m_scan->UpdateCurrentRel(&rel); + if (m_global->m_is_bucket_rel) { Assert(tup->t_bucketId == computeTupleBucketId(result_rel_info->ri_RelationDesc, tup)); bucketid = tup->t_bucketId; bucket_rel = InitBucketRelation(bucketid, rel, part); } - (void)ExecStoreTuple(tup, m_reslot, InvalidBuffer, false); + (void)ExecStoreTuple(tup, m_local.m_reslot, InvalidBuffer, false); if (rel->rd_att->constr) - ExecConstraints(result_rel_info, m_reslot, m_estate); + ExecConstraints(result_rel_info, m_local.m_reslot, m_c_local.m_estate); bool update_indexes = false; result = tableam_tuple_update(bucket_rel == NULL ? destRel : bucket_rel, bucket_rel == NULL ? parentRel : rel, &oldtup->t_self, tup, - m_estate->es_output_cid, + m_c_local.m_estate->es_output_cid, InvalidSnapshot, - m_estate->es_snapshot, + m_c_local.m_estate->es_snapshot, true, &tmfd, &update_indexes, @@ -1759,7 +2014,7 @@ bool UpdateFusion::execute(long max_rows, char* completionTag) switch (result) { case TM_SelfModified: - if (tmfd.cmax != m_estate->es_output_cid) + if (tmfd.cmax != m_c_local.m_estate->es_output_cid) ereport(ERROR, (errcode(ERRCODE_TRIGGERED_DATA_CHANGE_VIOLATION), errmsg("tuple to be updated was already modified by an operation triggered by the current command"), @@ -1784,9 +2039,9 @@ bool UpdateFusion::execute(long max_rows, char* completionTag) } nprocessed++; if (result_rel_info->ri_NumIndices > 0 && update_indexes) { - recheck_indexes = ExecInsertIndexTuples(m_reslot, + recheck_indexes = ExecInsertIndexTuples(m_local.m_reslot, &(tup->t_self), - m_estate, + m_c_local.m_estate, RELATION_IS_PARTITIONED(rel) ? partRel : NULL, RELATION_IS_PARTITIONED(rel) ? part : NULL, bucketid, NULL); @@ -1805,7 +2060,7 @@ bool UpdateFusion::execute(long max_rows, char* completionTag) bool* isnullfornew = NULL; Datum* valuesfornew = NULL; HeapTuple copyTuple; - copyTuple = heap_lock_updated(m_estate->es_output_cid, + copyTuple = heap_lock_updated(m_c_local.m_estate->es_output_cid, bucket_rel == NULL ? destRel : bucket_rel, LockTupleExclusive, &tmfd.ctid, @@ -1816,12 +2071,12 @@ bool UpdateFusion::execute(long max_rows, char* completionTag) break; } - valuesfornew = (Datum*)palloc0(m_tupDesc->natts * sizeof(Datum)); - isnullfornew = (bool*)palloc0(m_tupDesc->natts * sizeof(bool)); + valuesfornew = (Datum*)palloc0(m_global->m_tupDesc->natts * sizeof(Datum)); + isnullfornew = (bool*)palloc0(m_global->m_tupDesc->natts * sizeof(bool)); tableam_tops_deform_tuple(copyTuple, RelationGetDescr(rel), valuesfornew, isnullfornew); - if (m_scan->EpqCheck(valuesfornew, isnullfornew) == false) { + if (m_local.m_scan->EpqCheck(valuesfornew, isnullfornew) == false) { pfree_ext(valuesfornew); pfree_ext(isnullfornew); break; @@ -1852,16 +2107,16 @@ bool UpdateFusion::execute(long max_rows, char* completionTag) tableam_tops_free_tuple(tup); - (void)ExecClearTuple(m_reslot); + (void)ExecClearTuple(m_local.m_reslot); success = true; /**************** * step 3: done * ****************/ ExecCloseIndices(result_rel_info); - m_isCompleted = true; - m_scan->End(true); - ExecDoneStepInFusion(bucket_rel, m_estate); + m_local.m_isCompleted = true; + m_local.m_scan->End(true); + ExecDoneStepInFusion(bucket_rel, m_c_local.m_estate); errno_t errorno = snprintf_s(completionTag, COMPLETION_TAG_BUFSIZE, COMPLETION_TAG_BUFSIZE - 1, "UPDATE %lu", nprocessed); securec_check_ss(errorno, "\0", "\0"); @@ -1872,39 +2127,53 @@ bool UpdateFusion::execute(long max_rows, char* completionTag) DeleteFusion::DeleteFusion(MemoryContext context, CachedPlanSource* psrc, List* plantree_list, ParamListInfo params) : OpFusion(context, psrc, plantree_list) { - m_paramLoc = NULL; - m_tmpvals = NULL; - m_tmpisnull = NULL; - m_attrno = NULL; + MemoryContext old_context = NULL; - MemoryContext old_context = MemoryContextSwitchTo(m_context); - ModifyTable* node = (ModifyTable*)m_planstmt->planTree; - - Plan *deletePlan = (Plan *)linitial(node->plans); - - IndexScan* indexscan = (IndexScan *)JudgePlanIsPartIterator(deletePlan); - - m_reloid = getrelid(linitial_int(m_planstmt->resultRelations), m_planstmt->rtable); - Relation rel = heap_open(m_reloid, AccessShareLock); - - m_estate = CreateExecutorState(); - m_estate->es_range_table = m_planstmt->rtable; - - m_tupDesc = CreateTupleDescCopy(RelationGetDescr(rel)); - m_reslot = MakeSingleTupleTableSlot(m_tupDesc); - m_values = (Datum*)palloc0(RelationGetDescr(rel)->natts * sizeof(Datum)); - m_isnull = (bool*)palloc0(RelationGetDescr(rel)->natts * sizeof(bool)); - m_is_bucket_rel = RELATION_OWN_BUCKET(rel); - - heap_close(rel, AccessShareLock); - initParams(params); - - m_receiver = NULL; - m_isInsideRec = true; - m_scan = ScanFusion::getScanFusion((Node*)indexscan, m_planstmt, m_outParams); + if (!IsGlobal()) { + old_context = MemoryContextSwitchTo(m_global->m_context); + InitGlobals(); + MemoryContextSwitchTo(old_context); + } + old_context = MemoryContextSwitchTo(m_local.m_localContext); + InitLocals(params); MemoryContextSwitchTo(old_context); } +void DeleteFusion::InitLocals(ParamListInfo params) +{ + m_local.m_tmpvals = NULL; + m_local.m_tmpisnull = NULL; + + m_c_local.m_estate = CreateExecutorState(); + m_c_local.m_estate->es_range_table = m_global->m_planstmt->rtable; + + m_local.m_reslot = MakeSingleTupleTableSlot(m_global->m_tupDesc); + m_local.m_values = (Datum*)palloc0(m_global->m_natts * sizeof(Datum)); + m_local.m_isnull = (bool*)palloc0(m_global->m_natts * sizeof(bool)); + initParams(params); + + m_local.m_receiver = NULL; + m_local.m_isInsideRec = true; + + ModifyTable* node = (ModifyTable*)m_global->m_planstmt->planTree; + Plan *deletePlan = (Plan *)linitial(node->plans); + IndexScan* indexscan = (IndexScan *)JudgePlanIsPartIterator(deletePlan); + m_local.m_scan = ScanFusion::getScanFusion((Node*)indexscan, m_global->m_planstmt, + m_local.m_outParams ? m_local.m_outParams : m_local.m_params); +} + +void DeleteFusion::InitGlobals() +{ + m_global->m_reloid = getrelid(linitial_int(m_global->m_planstmt->resultRelations), m_global->m_planstmt->rtable); + Relation rel = heap_open(m_global->m_reloid, AccessShareLock); + + m_global->m_natts = RelationGetDescr(rel)->natts; + m_global->m_tupDesc = CreateTupleDescCopy(RelationGetDescr(rel)); + m_global->m_is_bucket_rel = RELATION_OWN_BUCKET(rel); + + heap_close(rel, AccessShareLock); + +} bool DeleteFusion::execute(long max_rows, char* completionTag) { bool success = false; @@ -1913,11 +2182,11 @@ bool DeleteFusion::execute(long max_rows, char* completionTag) /******************* * step 1: prepare * *******************/ - m_scan->refreshParameter(m_outParams == NULL ? m_params : m_outParams); + m_local.m_scan->refreshParameter(m_local.m_outParams == NULL ? m_local.m_params : m_local.m_outParams); - m_scan->Init(max_rows); + m_local.m_scan->Init(max_rows); - Relation rel = ((m_scan->m_parentRel) == NULL ? m_scan->m_rel : m_scan->m_parentRel); + Relation rel = ((m_local.m_scan->m_parentRel) == NULL ? m_local.m_scan->m_rel : m_local.m_scan->m_parentRel); Relation bucket_rel = NULL; int2 bucketid = InvalidBktId; @@ -1926,27 +2195,26 @@ bool DeleteFusion::execute(long max_rows, char* completionTag) ResultRelInfo* result_rel_info = makeNode(ResultRelInfo); InitResultRelInfo(result_rel_info, rel, 1, 0); - m_estate->es_result_relation_info = result_rel_info; - m_estate->es_output_cid = GetCurrentCommandId(true); + m_c_local.m_estate->es_result_relation_info = result_rel_info; + m_c_local.m_estate->es_output_cid = GetCurrentCommandId(true); if (result_rel_info->ri_RelationDesc->rd_rel->relhasindex) { ExecOpenIndices(result_rel_info, false); } - InitPartitionByScanFusion(rel, &partRel, &part, m_estate, m_scan); + InitPartitionByScanFusion(rel, &partRel, &part, m_c_local.m_estate, m_local.m_scan); /******************************** * step 2: begin scan and delete* ********************************/ HeapTuple oldtup = NULL; unsigned long nprocessed = 0; - m_tupDesc = RelationGetDescr(rel); - while ((oldtup = m_scan->getTuple()) != NULL) { + while ((oldtup = m_local.m_scan->getTuple()) != NULL) { TM_Result result; TM_FailureData tmfd; - m_scan->UpdateCurrentRel(&rel); - if (m_is_bucket_rel) { + m_local.m_scan->UpdateCurrentRel(&rel); + if (m_global->m_is_bucket_rel) { Assert(oldtup->t_bucketId == computeTupleBucketId(result_rel_info->ri_RelationDesc, oldtup)); bucketid = oldtup->t_bucketId; bucket_rel = InitBucketRelation(bucketid, rel, part); @@ -1956,8 +2224,8 @@ bool DeleteFusion::execute(long max_rows, char* completionTag) Relation destRel = RELATION_IS_PARTITIONED(rel) ? partRel : rel; result = tableam_tuple_delete(bucket_rel == NULL ? destRel : bucket_rel, &oldtup->t_self, - m_estate->es_output_cid, - //m_estate->es_snapshot, + m_c_local.m_estate->es_output_cid, + //m_c_local.m_estate->es_snapshot, InvalidSnapshot, NULL, true, @@ -1966,7 +2234,7 @@ bool DeleteFusion::execute(long max_rows, char* completionTag) switch (result) { case TM_SelfModified: - if (tmfd.cmax != m_estate->es_output_cid) + if (tmfd.cmax != m_c_local.m_estate->es_output_cid) ereport(ERROR, (errcode(ERRCODE_TRIGGERED_DATA_CHANGE_VIOLATION), errmsg("tuple to be updated was already modified by an operation triggered by the current command"), @@ -1999,7 +2267,7 @@ bool DeleteFusion::execute(long max_rows, char* completionTag) bool* isnullfornew = NULL; Datum* valuesfornew = NULL; HeapTuple copyTuple; - copyTuple = heap_lock_updated(m_estate->es_output_cid, + copyTuple = heap_lock_updated(m_c_local.m_estate->es_output_cid, bucket_rel == NULL ? destRel : bucket_rel, LockTupleExclusive, &tmfd.ctid, @@ -2007,10 +2275,10 @@ bool DeleteFusion::execute(long max_rows, char* completionTag) if (copyTuple == NULL) { break; } - valuesfornew = (Datum*)palloc0(m_tupDesc->natts * sizeof(Datum)); - isnullfornew = (bool*)palloc0(m_tupDesc->natts * sizeof(bool)); + valuesfornew = (Datum*)palloc0(m_global->m_tupDesc->natts * sizeof(Datum)); + isnullfornew = (bool*)palloc0(m_global->m_tupDesc->natts * sizeof(bool)); tableam_tops_deform_tuple(copyTuple, RelationGetDescr(rel), valuesfornew, isnullfornew); - if (m_scan->EpqCheck(valuesfornew, isnullfornew) == false) { + if (m_local.m_scan->EpqCheck(valuesfornew, isnullfornew) == false) { break; } oldtup->t_self = tmfd.ctid; @@ -2036,16 +2304,16 @@ bool DeleteFusion::execute(long max_rows, char* completionTag) } } - (void)ExecClearTuple(m_reslot); + (void)ExecClearTuple(m_local.m_reslot); success = true; /**************** * step 3: done * ****************/ ExecCloseIndices(result_rel_info); - m_isCompleted = true; - m_scan->End(true); - ExecDoneStepInFusion(bucket_rel, m_estate); + m_local.m_isCompleted = true; + m_local.m_scan->End(true); + ExecDoneStepInFusion(bucket_rel, m_c_local.m_estate); errno_t errorno = snprintf_s(completionTag, COMPLETION_TAG_BUFSIZE, COMPLETION_TAG_BUFSIZE - 1, "DELETE %lu", nprocessed); @@ -2058,46 +2326,79 @@ SelectForUpdateFusion::SelectForUpdateFusion( MemoryContext context, CachedPlanSource* psrc, List* plantree_list, ParamListInfo params) : OpFusion(context, psrc, plantree_list) { - m_paramLoc = NULL; + MemoryContext old_context = NULL; + if (!IsGlobal()) { + old_context = MemoryContextSwitchTo(m_global->m_context); + InitGlobals(); + MemoryContextSwitchTo(old_context); + } else { + m_c_global = ((SelectForUpdateFusion*)(psrc->opFusionObj))->m_c_global; + } + old_context = MemoryContextSwitchTo(m_local.m_localContext); + InitLocals(params); + MemoryContextSwitchTo(old_context); +} + +void SelectForUpdateFusion::InitLocals(ParamListInfo params) +{ + m_local.m_reslot = MakeSingleTupleTableSlot(m_global->m_tupDesc); + m_c_local.m_estate = CreateExecutorState(); + m_c_local.m_estate->es_range_table = m_global->m_planstmt->rtable; + + m_local.m_values = (Datum*)palloc(m_global->m_natts * sizeof(Datum)); + m_local.m_tmpvals = (Datum*)palloc(m_global->m_natts * sizeof(Datum)); + m_local.m_isnull = (bool*)palloc(m_global->m_natts * sizeof(bool)); + m_local.m_tmpisnull = (bool*)palloc(m_global->m_natts * sizeof(bool)); + + initParams(params); + + m_local.m_receiver = NULL; + m_local.m_isInsideRec = true; - MemoryContext old_context = MemoryContextSwitchTo(m_context); IndexScan* node = NULL; - m_limitCount = -1; - m_limitOffset = -1; + if (IsA(m_global->m_planstmt->planTree, Limit)) { + node = (IndexScan *)JudgePlanIsPartIterator(m_global->m_planstmt->planTree->lefttree->lefttree); + } else { + node = (IndexScan *)JudgePlanIsPartIterator(m_global->m_planstmt->planTree->lefttree); + } + m_local.m_scan = ScanFusion::getScanFusion((Node*)node, m_global->m_planstmt, + m_local.m_outParams ? m_local.m_outParams : m_local.m_params); +} + +void SelectForUpdateFusion::InitGlobals() +{ + m_c_global = (SelectForUpdateFusionGlobalVariable*)palloc0(sizeof(SelectForUpdateFusionGlobalVariable)); + + IndexScan* node = NULL; + m_c_global->m_limitCount = -1; + m_c_global->m_limitOffset = -1; /* get limit num */ - if (IsA(m_planstmt->planTree, Limit)) { - Limit* limit = (Limit*)m_planstmt->planTree; - node = (IndexScan *)JudgePlanIsPartIterator(m_planstmt->planTree->lefttree->lefttree); + if (IsA(m_global->m_planstmt->planTree, Limit)) { + Limit* limit = (Limit*)m_global->m_planstmt->planTree; + node = (IndexScan *)JudgePlanIsPartIterator(m_global->m_planstmt->planTree->lefttree->lefttree); if (limit->limitOffset != NULL && IsA(limit->limitOffset, Const) && !((Const*)limit->limitOffset)->constisnull) { - m_limitOffset = DatumGetInt64(((Const*)limit->limitOffset)->constvalue); + m_c_global->m_limitOffset = DatumGetInt64(((Const*)limit->limitOffset)->constvalue); } if (limit->limitCount != NULL && IsA(limit->limitCount, Const) && !((Const*)limit->limitCount)->constisnull) { - m_limitCount = DatumGetInt64(((Const*)limit->limitCount)->constvalue); + m_c_global->m_limitCount = DatumGetInt64(((Const*)limit->limitCount)->constvalue); } } else { - node = (IndexScan *)JudgePlanIsPartIterator(m_planstmt->planTree->lefttree); + node = (IndexScan *)JudgePlanIsPartIterator(m_global->m_planstmt->planTree->lefttree); } List* targetList = node->scan.plan.targetlist; - m_reloid = getrelid(node->scan.scanrelid, m_planstmt->rtable); - Relation rel = heap_open(m_reloid, AccessShareLock); + m_global->m_reloid = getrelid(node->scan.scanrelid, m_global->m_planstmt->rtable); + Relation rel = heap_open(m_global->m_reloid, AccessShareLock); + m_global->m_natts = RelationGetDescr(rel)->natts; Assert(list_length(targetList) >= 2); - m_tupDesc = ExecCleanTypeFromTL(targetList, false, rel->rd_tam_type); - m_reslot = MakeSingleTupleTableSlot(m_tupDesc); - - m_estate = CreateExecutorState(); - m_estate->es_range_table = m_planstmt->rtable; - - m_attrno = (int16*)palloc(m_tupDesc->natts * sizeof(int16)); - m_values = (Datum*)palloc(RelationGetDescr(rel)->natts * sizeof(Datum)); - m_tmpvals = (Datum*)palloc(m_tupDesc->natts * sizeof(Datum)); - m_isnull = (bool*)palloc(RelationGetDescr(rel)->natts * sizeof(bool)); - m_tmpisnull = (bool*)palloc(m_tupDesc->natts * sizeof(bool)); - m_is_bucket_rel = RELATION_OWN_BUCKET(rel); + m_global->m_tupDesc = ExecCleanTypeFromTL(targetList, false, rel->rd_tam_type); + m_global->m_is_bucket_rel = RELATION_OWN_BUCKET(rel); + heap_close(rel, AccessShareLock); + m_global->m_attrno = (int16*)palloc(m_global->m_natts * sizeof(int16)); ListCell* lc = NULL; int cur_resno = 1; TargetEntry* res = NULL; @@ -2106,21 +2407,16 @@ SelectForUpdateFusion::SelectForUpdateFusion( if (res->resjunk) { continue; } - m_attrno[cur_resno - 1] = res->resorigcol; + m_global->m_attrno[cur_resno - 1] = res->resorigcol; cur_resno++; } - Assert(m_tupDesc->natts == cur_resno - 1); - heap_close(rel, AccessShareLock); - initParams(params); - - m_receiver = NULL; - m_isInsideRec = true; - m_scan = ScanFusion::getScanFusion((Node*)node, m_planstmt, m_outParams); - MemoryContextSwitchTo(old_context); + Assert(m_global->m_tupDesc->natts == cur_resno - 1); } + bool SelectForUpdateFusion::execute(long max_rows, char* completionTag) { + MemoryContext oldContext = MemoryContextSwitchTo(m_local.m_tmpContext); bool success = false; int64 start_row = 0; int64 get_rows = 0; @@ -2128,22 +2424,13 @@ bool SelectForUpdateFusion::execute(long max_rows, char* completionTag) /******************* * step 1: prepare * *******************/ - IndexScan* node = NULL; - if (m_limitCount >= 0 || m_limitOffset >= 0) { - node = (IndexScan*)m_planstmt->planTree->lefttree->lefttree; - } else { - node = (IndexScan*)m_planstmt->planTree->lefttree; + start_row = m_c_global->m_limitOffset >= 0 ? m_c_global->m_limitOffset : start_row; + get_rows = m_c_global->m_limitCount >= 0 ? (m_c_global->m_limitCount + start_row) : max_rows; + if (m_local.m_position == 0) { + m_local.m_scan->refreshParameter(m_local.m_outParams == NULL ? m_local.m_params : m_local.m_outParams); + m_local.m_scan->Init(max_rows); } - - start_row = m_limitOffset >= 0 ? m_limitOffset : start_row; - get_rows = m_limitCount >= 0 ? (m_limitCount + start_row) : max_rows; - if (m_position == 0) { - MemoryContext oldContext = MemoryContextSwitchTo(m_tmpContext); - m_scan->refreshParameter(m_outParams == NULL ? m_params : m_outParams); - m_scan->Init(max_rows); - MemoryContextSwitchTo(oldContext); - } - Relation rel = ((m_scan->m_parentRel == NULL) ? m_scan->m_rel : m_scan->m_parentRel); + Relation rel = ((m_local.m_scan->m_parentRel == NULL) ? m_local.m_scan->m_rel : m_local.m_scan->m_parentRel); Relation partRel = NULL; Relation bucket_rel = NULL; Partition part = NULL; @@ -2151,15 +2438,15 @@ bool SelectForUpdateFusion::execute(long max_rows, char* completionTag) ResultRelInfo* result_rel_info = makeNode(ResultRelInfo); InitResultRelInfo(result_rel_info, rel, 1, 0); - m_estate->es_result_relation_info = result_rel_info; - m_estate->es_output_cid = GetCurrentCommandId(true); + m_c_local.m_estate->es_result_relation_info = result_rel_info; + m_c_local.m_estate->es_output_cid = GetCurrentCommandId(true); if (result_rel_info->ri_RelationDesc->rd_rel->relhasindex) { ExecOpenIndices(result_rel_info, false); } - InitPartitionByScanFusion(rel, &partRel, &part, m_estate, m_scan); + InitPartitionByScanFusion(rel, &partRel, &part, m_c_local.m_estate, m_local.m_scan); /************************************** * step 2: begin scan and update xmax * **************************************/ @@ -2172,43 +2459,44 @@ bool SelectForUpdateFusion::execute(long max_rows, char* completionTag) TM_Result result; TM_FailureData tmfd; Buffer buffer; - while (nprocessed < (unsigned long)start_row && (tuple = m_scan->getTuple()) != NULL) { + while (nprocessed < (unsigned long)start_row && (tuple = m_local.m_scan->getTuple()) != NULL) { nprocessed++; } - while (nprocessed < (unsigned long)get_rows && (tuple = m_scan->getTuple()) != NULL) { - m_scan->UpdateCurrentRel(&rel); + while (nprocessed < (unsigned long)get_rows && (tuple = m_local.m_scan->getTuple()) != NULL) { + m_local.m_scan->UpdateCurrentRel(&rel); CHECK_FOR_INTERRUPTS(); - tableam_tops_deform_tuple(tuple, RelationGetDescr(rel), m_values, m_isnull); + tableam_tops_deform_tuple(tuple, RelationGetDescr(rel), m_local.m_values, m_local.m_isnull); - for (int i = 0; i < m_tupDesc->natts; i++) { - Assert(m_attrno[i] > 0); - m_tmpvals[i] = m_values[m_attrno[i] - 1]; - m_tmpisnull[i] = m_isnull[m_attrno[i] - 1]; + for (int i = 0; i < m_global->m_tupDesc->natts; i++) { + Assert(m_global->m_attrno[i] > 0); + m_local.m_tmpvals[i] = m_local.m_values[m_global->m_attrno[i] - 1]; + m_local.m_tmpisnull[i] = m_local.m_isnull[m_global->m_attrno[i] - 1]; } - tmptup = (HeapTuple)tableam_tops_form_tuple(m_tupDesc, m_tmpvals, m_tmpisnull, HEAP_TUPLE); + tmptup = (HeapTuple)tableam_tops_form_tuple(m_global->m_tupDesc, m_local.m_tmpvals, + m_local.m_tmpisnull, HEAP_TUPLE); Assert(tmptup != NULL); { - if (m_is_bucket_rel) { + if (m_global->m_is_bucket_rel) { Assert(tuple->t_bucketId == computeTupleBucketId(result_rel_info->ri_RelationDesc, tuple)); bucketid = tuple->t_bucketId; bucket_rel = InitBucketRelation(bucketid, rel, part); } (void)ExecStoreTuple(tmptup, /* tuple to store */ - m_reslot, /* slot to store in */ + m_local.m_reslot, /* slot to store in */ InvalidBuffer, /* TO DO: survey */ false); /* don't pfree this pointer */ Relation destRel = RELATION_IS_PARTITIONED(rel) ? partRel : rel; - tableam_tslot_getsomeattrs(m_reslot, m_tupDesc->natts); + tableam_tslot_getsomeattrs(m_local.m_reslot, m_global->m_tupDesc->natts); result = tableam_tuple_lock(bucket_rel == NULL ? destRel : bucket_rel, tuple, &buffer, - m_estate->es_output_cid, + m_c_local.m_estate->es_output_cid, LockTupleExclusive, false, &tmfd, false, false, false, InvalidSnapshot, NULL, false); @@ -2246,8 +2534,8 @@ bool SelectForUpdateFusion::execute(long max_rows, char* completionTag) case TM_Ok: /* done successfully */ nprocessed++; - (*m_receiver->receiveSlot)(m_reslot, m_receiver); - tpslot_free_heaptuple(m_reslot); + (*m_local.m_receiver->receiveSlot)(m_local.m_reslot, m_local.m_receiver); + tpslot_free_heaptuple(m_local.m_reslot); break; case TM_Updated: { @@ -2261,7 +2549,7 @@ bool SelectForUpdateFusion::execute(long max_rows, char* completionTag) bool* isnullfornew = NULL; Datum* valuesfornew = NULL; HeapTuple copyTuple; - copyTuple = heap_lock_updated(m_estate->es_output_cid, + copyTuple = heap_lock_updated(m_c_local.m_estate->es_output_cid, bucket_rel == NULL ? destRel : bucket_rel, LockTupleExclusive, &tmfd.ctid, @@ -2274,28 +2562,29 @@ bool SelectForUpdateFusion::execute(long max_rows, char* completionTag) tableam_tops_deform_tuple(copyTuple, RelationGetDescr(rel), valuesfornew, isnullfornew); - if (m_scan->EpqCheck(valuesfornew, isnullfornew) == false) { + if (m_local.m_scan->EpqCheck(valuesfornew, isnullfornew) == false) { pfree_ext(valuesfornew); pfree_ext(isnullfornew); break; } - for (int i = 0; i < m_tupDesc->natts; i++) { - m_tmpvals[i] = valuesfornew[m_attrno[i] - 1]; - m_tmpisnull[i] = isnullfornew[m_attrno[i] - 1]; + for (int i = 0; i < m_global->m_tupDesc->natts; i++) { + m_local.m_tmpvals[i] = valuesfornew[m_global->m_attrno[i] - 1]; + m_local.m_tmpisnull[i] = isnullfornew[m_global->m_attrno[i] - 1]; } - tmptup = (HeapTuple)tableam_tops_form_tuple(m_tupDesc, m_tmpvals, m_tmpisnull, HEAP_TUPLE); + tmptup = (HeapTuple)tableam_tops_form_tuple(m_global->m_tupDesc, m_local.m_tmpvals, + m_local.m_tmpisnull, HEAP_TUPLE); Assert(tmptup != NULL); (void)ExecStoreTuple(tmptup, /* tuple to store */ - m_reslot, /* slot to store in */ + m_local.m_reslot, /* slot to store in */ InvalidBuffer, /* TO DO: survey */ false); /* don't pfree this pointer */ - tableam_tslot_getsomeattrs(m_reslot, m_tupDesc->natts); + tableam_tslot_getsomeattrs(m_local.m_reslot, m_global->m_tupDesc->natts); nprocessed++; - (*m_receiver->receiveSlot)(m_reslot, m_receiver); + (*m_local.m_receiver->receiveSlot)(m_local.m_reslot, m_local.m_receiver); tuple->t_self = tmfd.ctid; tuple = copyTuple; pfree(valuesfornew); @@ -2318,16 +2607,16 @@ bool SelectForUpdateFusion::execute(long max_rows, char* completionTag) } } - if (!ScanDirectionIsNoMovement(*(m_scan->m_direction))) { + if (!ScanDirectionIsNoMovement(*(m_local.m_scan->m_direction))) { if (max_rows == 0 || nprocessed < (unsigned long)max_rows) { - m_isCompleted = true; + m_local.m_isCompleted = true; } - m_position += nprocessed; + m_local.m_position += nprocessed; } else { - m_isCompleted = true; + m_local.m_isCompleted = true; } - (void)ExecClearTuple(m_reslot); + (void)ExecClearTuple(m_local.m_reslot); success = true; /**************** @@ -2335,52 +2624,54 @@ bool SelectForUpdateFusion::execute(long max_rows, char* completionTag) ****************/ ExecCloseIndices(result_rel_info); - m_scan->End(m_isCompleted); - if (m_isCompleted) { - m_position = 0; + m_local.m_scan->End(m_local.m_isCompleted); + if (m_local.m_isCompleted) { + m_local.m_position = 0; } - ExecDoneStepInFusion(bucket_rel, m_estate); + ExecDoneStepInFusion(bucket_rel, m_c_local.m_estate); - if (m_isInsideRec) { - (*m_receiver->rDestroy)(m_receiver); + if (m_local.m_isInsideRec) { + (*m_local.m_receiver->rDestroy)(m_local.m_receiver); } errno_t errorno = snprintf_s(completionTag, COMPLETION_TAG_BUFSIZE, COMPLETION_TAG_BUFSIZE - 1, "SELECT %lu", nprocessed); securec_check_ss(errorno, "\0", "\0"); + (void)MemoryContextSwitchTo(oldContext); return success; } void SelectForUpdateFusion::close() { - if (m_isCompleted == false) { - m_scan->End(true); - m_isCompleted = true; - m_position = 0; + if (m_local.m_isCompleted == false) { + m_local.m_scan->End(true); + m_local.m_isCompleted = true; + m_local.m_position = 0; } } + AggFusion::AggFusion(MemoryContext context, CachedPlanSource* psrc, List* plantree_list, ParamListInfo params) : OpFusion(context, psrc, plantree_list) { - m_tmpvals = NULL; - m_values = NULL; - m_isnull = NULL; - m_tmpisnull = NULL; + MemoryContext old_context = NULL; - m_paramLoc = NULL; - m_attrno = NULL; - m_reloid = 0; + if (!IsGlobal()) { + old_context = MemoryContextSwitchTo(m_global->m_context); + InitGlobals(); + MemoryContextSwitchTo(old_context); + } else { + m_c_global = ((AggFusion*)(psrc->opFusionObj))->m_c_global; + } + old_context = MemoryContextSwitchTo(m_local.m_localContext); + InitLocals(params); + MemoryContextSwitchTo(old_context); +} - MemoryContext oldContext = MemoryContextSwitchTo(m_context); - - Agg *aggnode = (Agg *)m_planstmt->planTree; - Node* scan = JudgePlanIsPartIterator(aggnode->plan.lefttree); - - initParams(params); - m_receiver = NULL; - m_isInsideRec = true; - m_scan = ScanFusion::getScanFusion(scan, m_planstmt, m_outParams); - m_reslot = NULL; +void AggFusion::InitGlobals() +{ + m_c_global = (AggFusionGlobalVariable*)palloc0(sizeof(AggFusionGlobalVariable)); + m_global->m_reloid = 0; + Agg *aggnode = (Agg *)m_global->m_planstmt->planTree; /* agg init */ List *targetList = aggnode->plan.targetlist; @@ -2389,16 +2680,16 @@ AggFusion::AggFusion(MemoryContext context, CachedPlanSource* psrc, List* plantr switch (aggref->aggfnoid) { case INT2SUMFUNCOID: - m_aggSumFunc = &AggFusion::agg_int2_sum; + m_c_global->m_aggSumFunc = &AggFusion::agg_int2_sum; break; case INT4SUMFUNCOID: - m_aggSumFunc = &AggFusion::agg_int4_sum; + m_c_global->m_aggSumFunc = &AggFusion::agg_int4_sum; break; case INT8SUMFUNCOID: - m_aggSumFunc = &AggFusion::agg_int8_sum; + m_c_global->m_aggSumFunc = &AggFusion::agg_int8_sum; break; case NUMERICSUMFUNCOID: - m_aggSumFunc = &AggFusion::agg_numeric_sum; + m_c_global->m_aggSumFunc = &AggFusion::agg_numeric_sum; break; default: elog(ERROR, "unsupported aggfnoid %u for bypass.", aggref->aggfnoid); @@ -2412,22 +2703,30 @@ AggFusion::AggFusion(MemoryContext context, CachedPlanSource* psrc, List* plantr } ReleaseSysCache(aggTuple); - m_tupDesc = ExecTypeFromTL(targetList, false); + m_global->m_tupDesc = ExecTypeFromTL(targetList, false); + m_global->m_attrno = (int16 *) palloc(m_global->m_tupDesc->natts * sizeof(int16)); - m_attrno = (int16 *) palloc(m_tupDesc->natts * sizeof(int16)); - - /* m_tupDesc->natts always be 1 currently. */ + /* m_global->m_tupDesc->natts always be 1 currently. */ TargetEntry *res = NULL; res = (TargetEntry *)linitial(aggref->args); Var *var = (Var *)res->expr; - m_attrno[0] = var->varattno; - m_isCompleted = true; + m_global->m_attrno[0] = var->varattno; +} - m_reslot = MakeSingleTupleTableSlot(m_tupDesc); - m_values = (Datum*)palloc0(m_tupDesc->natts * sizeof(Datum)); - m_isnull = (bool*)palloc0(m_tupDesc->natts * sizeof(bool)); +void AggFusion::InitLocals(ParamListInfo params) +{ + initParams(params); + m_local.m_receiver = NULL; + m_local.m_isInsideRec = true; - MemoryContextSwitchTo(oldContext); + Agg *aggnode = (Agg *)m_global->m_planstmt->planTree; + Node* scan = JudgePlanIsPartIterator(aggnode->plan.lefttree); + m_local.m_scan = ScanFusion::getScanFusion(scan, m_global->m_planstmt, + m_local.m_outParams ? m_local.m_outParams : m_local.m_params); + + m_local.m_reslot = MakeSingleTupleTableSlot(m_global->m_tupDesc); + m_local.m_values = (Datum*)palloc0(m_global->m_tupDesc->natts * sizeof(Datum)); + m_local.m_isnull = (bool*)palloc0(m_global->m_tupDesc->natts * sizeof(bool)); } bool AggFusion::execute(long max_rows, char *completionTag) @@ -2435,32 +2734,32 @@ bool AggFusion::execute(long max_rows, char *completionTag) max_rows = FETCH_ALL; bool success = false; - TupleTableSlot *reslot = m_reslot; - Datum* values = m_values; - bool * isnull = m_isnull; - for (int i = 0; i < m_tupDesc->natts; i++) { + TupleTableSlot *reslot = m_local.m_reslot; + Datum* values = m_local.m_values; + bool * isnull = m_local.m_isnull; + for (int i = 0; i < m_global->m_tupDesc->natts; i++) { isnull[i] = true; } /* step 2: begin scan */ - m_scan->refreshParameter(m_outParams == NULL ? m_params : m_outParams); + m_local.m_scan->refreshParameter(m_local.m_outParams == NULL ? m_local.m_params : m_local.m_outParams); - m_scan->Init(max_rows); + m_local.m_scan->Init(max_rows); setReceiver(); long nprocessed = 0; TupleTableSlot *slot = NULL; - while ((slot = m_scan->getTupleSlot()) != NULL) { + while ((slot = m_local.m_scan->getTupleSlot()) != NULL) { CHECK_FOR_INTERRUPTS(); nprocessed++; { - AutoContextSwitch memSwitch(m_tmpContext); - for (int i = 0; i < m_tupDesc->natts; i++) { - reslot->tts_values[i] = slot->tts_values[m_attrno[i] - 1]; - reslot->tts_isnull[i] = slot->tts_isnull[m_attrno[i] - 1]; - (this->*m_aggSumFunc)(&values[i], isnull[i], + AutoContextSwitch memSwitch(m_local.m_tmpContext); + for (int i = 0; i < m_global->m_tupDesc->natts; i++) { + reslot->tts_values[i] = slot->tts_values[m_global->m_attrno[i] - 1]; + reslot->tts_isnull[i] = slot->tts_isnull[m_global->m_attrno[i] - 1]; + (this->*(m_c_global->m_aggSumFunc))(&values[i], isnull[i], &reslot->tts_values[i], reslot->tts_isnull[i]); isnull[i] = false; } @@ -2471,24 +2770,24 @@ bool AggFusion::execute(long max_rows, char *completionTag) } } - HeapTuple tmptup = (HeapTuple)tableam_tops_form_tuple(m_tupDesc, values, isnull, HEAP_TUPLE); + HeapTuple tmptup = (HeapTuple)tableam_tops_form_tuple(m_global->m_tupDesc, values, isnull, HEAP_TUPLE); (void)ExecStoreTuple(tmptup, reslot, InvalidBuffer, false); - tableam_tslot_getsomeattrs(reslot, m_tupDesc->natts); + tableam_tslot_getsomeattrs(reslot, m_global->m_tupDesc->natts); - (*m_receiver->receiveSlot)(reslot, m_receiver); + (*m_local.m_receiver->receiveSlot)(reslot, m_local.m_receiver); - tpslot_free_heaptuple(m_reslot); + tpslot_free_heaptuple(m_local.m_reslot); success = true; /* step 3: done */ - if (m_isInsideRec == true) { - (*m_receiver->rDestroy)(m_receiver); + if (m_local.m_isInsideRec == true) { + (*m_local.m_receiver->rDestroy)(m_local.m_receiver); } - m_isCompleted = true; - m_scan->End(true); + m_local.m_isCompleted = true; + m_local.m_scan->End(true); errno_t errorno = snprintf_s(completionTag, COMPLETION_TAG_BUFSIZE, COMPLETION_TAG_BUFSIZE - 1, "SELECT %lu", nprocessed); @@ -2640,21 +2939,42 @@ void AggFusion::agg_numeric_sum(Datum *transVal, bool transIsNull, Datum *inVal, SortFusion::SortFusion(MemoryContext context, CachedPlanSource* psrc, List* plantree_list, ParamListInfo params) : OpFusion(context, psrc, plantree_list) { - m_tmpvals = NULL; - m_values = NULL; - m_isnull = NULL; - m_tmpisnull = NULL; + MemoryContext old_context = NULL; + if (!IsGlobal()) { + old_context = MemoryContextSwitchTo(m_global->m_context); + InitGlobals(); + MemoryContextSwitchTo(old_context); + } + old_context = MemoryContextSwitchTo(m_local.m_localContext); + InitLocals(params); + MemoryContextSwitchTo(old_context); +} - m_paramLoc = NULL; - m_attrno = NULL; - m_reloid = 0; +void SortFusion::InitLocals(ParamListInfo params) +{ + Plan *node = (Plan*)m_global->m_planstmt->planTree->lefttree; + Sort *sortnode = (Sort *)m_global->m_planstmt->planTree; + m_c_local.m_scanDesc = ExecTypeFromTL(node->targetlist, false); + initParams(params); + m_local.m_receiver = NULL; + m_local.m_isInsideRec = true; + m_local.m_scan = ScanFusion::getScanFusion((Node*)sortnode->plan.lefttree, m_global->m_planstmt, + m_local.m_outParams ? m_local.m_outParams : m_local.m_params); + m_c_local.m_scanDesc->tdTableAmType = m_local.m_scan->m_tupDesc->tdTableAmType; + if (!IsGlobal()) + m_global->m_tupDesc->tdTableAmType = m_local.m_scan->m_tupDesc->tdTableAmType; - MemoryContext oldContext = MemoryContextSwitchTo(m_context); + m_local.m_reslot = MakeSingleTupleTableSlot(m_global->m_tupDesc, false, m_local.m_scan->m_tupDesc->tdTableAmType); + m_local.m_values = (Datum*)palloc0(m_global->m_tupDesc->natts * sizeof(Datum)); + m_local.m_isnull = (bool*)palloc0(m_global->m_tupDesc->natts * sizeof(bool)); +} - Sort *sortnode = (Sort *)m_planstmt->planTree; - m_tupDesc = ExecCleanTypeFromTL(sortnode->plan.targetlist, false); - - m_attrno = (int16 *) palloc(m_tupDesc->natts * sizeof(int16)); +void SortFusion::InitGlobals() +{ + m_global->m_reloid = 0; + Sort *sortnode = (Sort *)m_global->m_planstmt->planTree; + m_global->m_tupDesc = ExecCleanTypeFromTL(sortnode->plan.targetlist, false); + m_global->m_attrno = (int16 *)palloc(m_global->m_tupDesc->natts * sizeof(int16)); ListCell *lc = NULL; int cur_resno = 1; @@ -2664,27 +2984,9 @@ SortFusion::SortFusion(MemoryContext context, CachedPlanSource* psrc, List* plan continue; Var *var = (Var *)res->expr; - m_attrno[cur_resno - 1] = var->varattno; + m_global->m_attrno[cur_resno - 1] = var->varattno; cur_resno++; } - - Plan *node = (Plan*)m_planstmt->planTree->lefttree; - m_scanDesc = ExecTypeFromTL(node->targetlist, false); - - initParams(params); - m_receiver = NULL; - m_isInsideRec = true; - m_scan = ScanFusion::getScanFusion((Node*)sortnode->plan.lefttree, m_planstmt, m_outParams); - m_tupDesc->tdTableAmType = m_scan->m_tupDesc->tdTableAmType; - m_scanDesc->tdTableAmType = m_scan->m_tupDesc->tdTableAmType; - m_reslot = NULL; - m_isCompleted = true; - - m_reslot = MakeSingleTupleTableSlot(m_tupDesc, false, m_scan->m_tupDesc->tdTableAmType); - m_values = (Datum*)palloc0(m_tupDesc->natts * sizeof(Datum)); - m_isnull = (bool*)palloc0(m_tupDesc->natts * sizeof(bool)); - - MemoryContextSwitchTo(oldContext); } bool SortFusion::execute(long max_rows, char *completionTag) @@ -2692,29 +2994,29 @@ bool SortFusion::execute(long max_rows, char *completionTag) max_rows = FETCH_ALL; bool success = false; - TupleTableSlot *reslot = m_reslot; - Datum *values = m_values; - bool *isnull = m_isnull; - for (int i = 0; i < m_tupDesc->natts; i++) { + TupleTableSlot *reslot = m_local.m_reslot; + Datum *values = m_local.m_values; + bool *isnull = m_local.m_isnull; + for (int i = 0; i < m_global->m_tupDesc->natts; i++) { isnull[i] = true; } /* prepare */ - m_scan->refreshParameter(m_outParams == NULL ? m_params : m_outParams); + m_local.m_scan->refreshParameter(m_local.m_outParams == NULL ? m_local.m_params : m_local.m_outParams); - m_scan->Init(max_rows); + m_local.m_scan->Init(max_rows); setReceiver(); Tuplesortstate *tuplesortstate = NULL; - Sort *sortnode = (Sort *)m_planstmt->planTree; + Sort *sortnode = (Sort *)m_global->m_planstmt->planTree; int64 sortMem = SET_NODEMEM(sortnode->plan.operatorMemKB[0], sortnode->plan.dop); int64 maxMem = (sortnode->plan.operatorMaxMem > 0) ? SET_NODEMEM(sortnode->plan.operatorMaxMem, sortnode->plan.dop) : 0; { - AutoContextSwitch memSwitch(m_context); - tuplesortstate = tuplesort_begin_heap(m_scanDesc, + AutoContextSwitch memSwitch(m_local.m_tmpContext); + tuplesortstate = tuplesort_begin_heap(m_c_local.m_scanDesc, sortnode->numCols, sortnode->sortColIdx, sortnode->sortOperators, @@ -2730,7 +3032,7 @@ bool SortFusion::execute(long max_rows, char *completionTag) /* receive data from indexscan node */ long nprocessed = 0; TupleTableSlot *slot = NULL; - while ((slot = m_scan->getTupleSlot()) != NULL) { + while ((slot = m_local.m_scan->getTupleSlot()) != NULL) { tuplesort_puttupleslot(tuplesortstate, slot); } @@ -2738,17 +3040,18 @@ bool SortFusion::execute(long max_rows, char *completionTag) tuplesort_performsort(tuplesortstate); /* send sorted data to client */ - slot = MakeSingleTupleTableSlot(m_scanDesc); + slot = MakeSingleTupleTableSlot(m_c_local.m_scanDesc); while (tuplesort_gettupleslot(tuplesortstate, true, slot, NULL)) { - tableam_tslot_getsomeattrs(slot, m_scanDesc->natts); - for (int i = 0; i < m_tupDesc->natts; i++) { - values[i] = slot->tts_values[m_attrno[i] - 1]; - isnull[i] = slot->tts_isnull[m_attrno[i] - 1]; + tableam_tslot_getsomeattrs(slot, m_c_local.m_scanDesc->natts); + for (int i = 0; i < m_global->m_tupDesc->natts; i++) { + values[i] = slot->tts_values[m_global->m_attrno[i] - 1]; + isnull[i] = slot->tts_isnull[m_global->m_attrno[i] - 1]; } - HeapTuple tmptup = (HeapTuple) tableam_tops_form_tuple(m_tupDesc, values, isnull, TableAMGetTupleType(m_tupDesc->tdTableAmType)); + HeapTuple tmptup = (HeapTuple)tableam_tops_form_tuple(m_global->m_tupDesc, values, isnull, + TableAMGetTupleType(m_global->m_tupDesc->tdTableAmType)); (void)ExecStoreTuple(tmptup, reslot, InvalidBuffer, false); - (*m_receiver->receiveSlot)(reslot, m_receiver); + (*m_local.m_receiver->receiveSlot)(reslot, m_local.m_receiver); tableam_tops_free_tuple(tmptup); CHECK_FOR_INTERRUPTS(); @@ -2761,12 +3064,12 @@ bool SortFusion::execute(long max_rows, char *completionTag) success = true; /* step 3: done */ - if (m_isInsideRec == true) { - (*m_receiver->rDestroy)(m_receiver); + if (m_local.m_isInsideRec == true) { + (*m_local.m_receiver->rDestroy)(m_local.m_receiver); } - m_isCompleted = true; - m_scan->End(true); + m_local.m_isCompleted = true; + m_local.m_scan->End(true); errno_t errorno = snprintf_s(completionTag, COMPLETION_TAG_BUFSIZE, COMPLETION_TAG_BUFSIZE - 1, "SELECT %lu", nprocessed); diff --git a/src/gausskernel/runtime/executor/opfusion_util.cpp b/src/gausskernel/runtime/executor/opfusion_util.cpp index 431842637..90e3ee49b 100644 --- a/src/gausskernel/runtime/executor/opfusion_util.cpp +++ b/src/gausskernel/runtime/executor/opfusion_util.cpp @@ -1129,3 +1129,16 @@ void tpslot_free_heaptuple(TupleTableSlot* reslot) reslot->tts_tuple = NULL; } } + +/* judge plan node is partiterator */ +Node* JudgePlanIsPartIterator(Plan* plan) +{ + Node* node = NULL; + if (IsA(plan, PartIterator)) { + node = (Node*)plan->lefttree; + } else { + node = (Node*)plan; + } + return node; +} + diff --git a/src/gausskernel/storage/access/transam/xact.cpp b/src/gausskernel/storage/access/transam/xact.cpp index 5a5e71522..62d309122 100644 --- a/src/gausskernel/storage/access/transam/xact.cpp +++ b/src/gausskernel/storage/access/transam/xact.cpp @@ -6284,6 +6284,11 @@ static void CommitSubTransaction(bool STP_commit) ShowTransactionState("CommitSubTransaction"); + /* clean hash table for sub transaction in opfusion */ + if (IS_PGXC_DATANODE) { + OpFusion::ClearInSubUnexpectSituation(s->curTransactionOwner); + } + if (s->state != TRANS_INPROGRESS) { ereport(WARNING, (errmsg("CommitSubTransaction while in %s state", TransStateAsString(s->state)))); } @@ -6415,6 +6420,10 @@ void AbortSubTransaction(bool STP_rollback) { TransactionState s = CurrentTransactionState; t_thrd.xact_cxt.bInAbortTransaction = true; + /* clean hash table for sub transaction in opfusion */ + if (IS_PGXC_DATANODE) { + OpFusion::ClearInSubUnexpectSituation(s->curTransactionOwner); + } /* * @dfs diff --git a/src/include/knl/knl_guc/knl_session_attr_common.h b/src/include/knl/knl_guc/knl_session_attr_common.h index 15edab1f2..60becb840 100644 --- a/src/include/knl/knl_guc/knl_session_attr_common.h +++ b/src/include/knl/knl_guc/knl_session_attr_common.h @@ -203,6 +203,7 @@ typedef struct knl_session_attr_common { char* router_att; bool enable_router; + int gpc_clean_timeout; } knl_session_attr_common; #endif /* SRC_INCLUDE_KNL_KNL_SESSION_ATTR_COMMON_H_ */ diff --git a/src/include/opfusion/opfusion.h b/src/include/opfusion/opfusion.h index 3ed0c7594..4fd2869d8 100644 --- a/src/include/opfusion/opfusion.h +++ b/src/include/opfusion/opfusion.h @@ -45,6 +45,16 @@ typedef struct pnFusionObj { #define HASH_TBL_LEN 64 +/* + * The variables in OpFusion is always in two parts: global's variables and local's variables. + * Global variable means it can be shared in each session. + * Local variable means it will be change in local session, so it cannot be shared. + * + * Global variables be saved into struct OpFusionGlobalVariable, and we access the global variables + * from pointer m_global, and m_global's mem context is under global cachedplansource. + * Local variables be saved into struct OpFusionLocaleVariable, and we access the local variables + * from object m_local, and m_local's context is under session context. + */ class OpFusion : public BaseObject { public: OpFusion(MemoryContext context, CachedPlanSource* psrc, List* plantree_list); @@ -60,6 +70,14 @@ public: static bool process(int op, StringInfo msg, char* completionTag, bool isTopLevel, bool* isQueryCompleted); + static void SaveInGPC(OpFusion* obj); + + static void DropGlobalOpfusion(OpFusion* obj); + + void InitGlobals(MemoryContext context, CachedPlanSource* psrc, List* plantree_list); + + void InitLocals(MemoryContext context); + void CopyFormats(int16* formats, int numRFormats); void updatePreAllocParamter(StringInfo msg); @@ -80,6 +98,7 @@ public: return; } + void copyGlobalOpfusionVar(OpFusion); void setPreparedDestReceiver(DestReceiver* preparedDest); Datum CalFuncNodeVal(Oid functionId, List* args, bool* is_null, Datum* values, bool* isNulls); @@ -98,7 +117,7 @@ public: void executeInit(); - void executeEnd(const char* portal_name, bool* completionTag); + bool executeEnd(const char* portal_name, bool* completionTag); void auditRecord(); @@ -112,6 +131,8 @@ public: static void ClearInUnexpectSituation(); + static void ClearInSubUnexpectSituation(ResourceOwner owner); + void storeFusion(const char *portalname); static OpFusion *locateFusion(const char *portalname); @@ -120,66 +141,104 @@ public: static void refreshCurFusion(StringInfo msg); + inline bool IsGlobal() + { + pg_memory_barrier(); + return (m_global && m_global->m_is_global); + } + public: struct ParamLoc { int paramId; int scanKeyIndx; }; + struct ConstLoc { + Datum constValue; + bool constIsNull; + int constLoc; + }; + /* + * these variables can be shared, mem context on global plancache + */ + struct OpFusionGlobalVariable { + CachedPlanSource* m_psrc; /* to get m_cacheplan in PBE */ + + CachedPlan* m_cacheplan; + + PlannedStmt* m_planstmt; /* m_cacheplan->stmt_list in PBE, plantree in non-PBE */ + + MemoryContext m_context; + + bool m_is_pbe_query; + + ParamLoc* m_paramLoc; /* location of m_params, include paramId and the location in indexqual */ + + Oid m_reloid; /* relation oid of range table */ + + int m_paramNum; - CachedPlanSource* m_psrc; /* to get m_cacheplan in PBE */ + TableAmType m_table_type; + + int16* m_attrno; /* target attribute number, length is m_tupDesc->natts */ + + bool m_is_bucket_rel; - CachedPlan* m_cacheplan; + FusionType m_type; - PlannedStmt* m_planstmt; /* m_cacheplan->stmt_list in PBE, plantree in non-PBE */ + int m_natts; - bool m_isFirst; /* be true if is the fisrt execute in PBE */ + volatile bool m_is_global; - MemoryContext m_context; + TupleDesc m_tupDesc; /* tuple descriptor */ - MemoryContext m_tmpContext; /* use for tmp memory allocation. */ + }; - ParamListInfo m_params; + OpFusionGlobalVariable *m_global; + + /* + * other variables need change each BE, mem context on session cache context + */ + struct OpFusionLocaleVariable { + MemoryContext m_localContext; /* use for local variables */ - ParamListInfo m_outParams; /* use outer side parameter. */ + MemoryContext m_tmpContext; /* use for tmp memory allocation. */ + + bool m_isFirst; /* be true if is the fisrt execute in PBE */ + + ParamListInfo m_outParams; /* use outer side parameter. */ - int m_paramNum; + ParamListInfo m_params; - ParamLoc* m_paramLoc; /* location of m_params, include paramId and the location in indexqual */ + TupleTableSlot* m_reslot; /* result slot */ + + Datum* m_values; + + bool* m_isnull; + + Datum* m_tmpvals; /* for mapping m_values */ + + bool* m_tmpisnull; /* for mapping m_isnull */ + + DestReceiver* m_receiver; + + bool m_isInsideRec; + + int16* m_rformats; + + bool m_isCompleted; + + long m_position; + + const char *m_portalName; + + Snapshot m_snapshot; - Oid m_reloid; /* relation oid of range table */ + class ScanFusion* m_scan; - TupleDesc m_tupDesc; /* tuple descriptor */ - - TupleTableSlot* m_reslot; /* result slot */ - - int16* m_attrno; /* target attribute number, length is m_tupDesc->natts */ - - Datum* m_values; - - bool* m_isnull; - - Datum* m_tmpvals; /* for mapping m_values */ - - bool* m_tmpisnull; /* for mapping m_isnull */ - - DestReceiver* m_receiver; - - bool m_isInsideRec; - - bool m_is_pbe_query; - - int16* m_rformats; - - bool m_isCompleted; - - long m_position; - - const char *m_portalName; - - Snapshot m_snapshot; - - class ScanFusion* m_scan; + ResourceOwner m_resOwner; + }; + OpFusionLocaleVariable m_local; private: #ifdef ENABLE_MOT static FusionType GetMotFusionType(PlannedStmt* plannedStmt); @@ -196,12 +255,18 @@ public: void close(); -private: - int64 m_limitCount; + void InitLocals(ParamListInfo params); - int64 m_limitOffset; + void InitGlobals(); +private: + struct SelectFusionGlobalVariable { + int64 m_limitCount; + int64 m_limitOffset; + }; + SelectFusionGlobalVariable* m_c_global; }; + class InsertFusion : public OpFusion { public: InsertFusion(MemoryContext context, CachedPlanSource* psrc, List* plantree_list, ParamListInfo params); @@ -210,23 +275,33 @@ public: bool execute(long max_rows, char* completionTag); + void InitLocals(ParamListInfo params); + + void InitGlobals(); private: void refreshParameterIfNecessary(); - EState* m_estate; + struct InsertFusionGlobalVariable { + /* for func/op expr calculation */ + FuncExprInfo* m_targetFuncNodes; + + int m_targetFuncNum; + + int m_targetParamNum; - /* for func/op expr calculation */ - FuncExprInfo* m_targetFuncNodes; + int m_targetConstNum; - int m_targetFuncNum; + ConstLoc* m_targetConstLoc; + }; + InsertFusionGlobalVariable* m_c_global; - int m_targetParamNum; + struct InsertFusionLocaleVariable { + EState* m_estate; + Datum* m_curVarValue; + bool* m_curVarIsnull; + }; - Datum* m_curVarValue; - - bool* m_curVarIsnull; - - bool m_is_bucket_rel; + InsertFusionLocaleVariable m_c_local; }; class UpdateFusion : public OpFusion { @@ -237,44 +312,47 @@ public: bool execute(long max_rows, char* completionTag); + void InitLocals(ParamListInfo params); + + void InitGlobals(); private: HeapTuple heapModifyTuple(HeapTuple tuple); void refreshTargetParameterIfNecessary(); - EState* m_estate; - /* targetlist */ - int m_targetNum; - - int m_targetParamNum; - - Datum* m_targetValues; - - bool* m_targetIsnull; - - Datum* m_curVarValue; struct VarLoc { int varNo; int scanKeyIndx; }; + struct UpdateFusionGlobalVariable { + /* targetlist */ + int m_targetConstNum; + + int m_targetParamNum; + + VarLoc* m_targetVarLoc; + + int m_varNum; + + ConstLoc* m_targetConstLoc; + + ParamLoc* m_targetParamLoc; + + /* for func/op expr calculation */ + FuncExprInfo* m_targetFuncNodes; + + int m_targetFuncNum; + }; + UpdateFusionGlobalVariable* m_c_global; - VarLoc* m_targetVarLoc; + struct UpdateFusionLocaleVariable { + EState* m_estate; + Datum* m_curVarValue; + bool* m_curVarIsnull; + }; - int m_varNum; - - bool* m_curVarIsnull; - - int* m_targetConstLoc; - - ParamLoc* m_targetParamLoc; - - /* for func/op expr calculation */ - FuncExprInfo* m_targetFuncNodes; - - int m_targetFuncNum; - - bool m_is_bucket_rel; + UpdateFusionLocaleVariable m_c_local; }; class DeleteFusion : public OpFusion { @@ -285,10 +363,15 @@ public: bool execute(long max_rows, char* completionTag); -private: - EState* m_estate; + void InitLocals(ParamListInfo params); - bool m_is_bucket_rel; + void InitGlobals(); +private: + struct DeleteFusionLocaleVariable { + EState* m_estate; + }; + + DeleteFusionLocaleVariable m_c_local; }; #ifdef ENABLE_MOT @@ -299,6 +382,10 @@ public: ~MotJitSelectFusion() {}; bool execute(long max_rows, char *completionTag); + + void InitLocals(ParamListInfo params); + + void InitGlobals(); }; class MotJitModifyFusion : public OpFusion { @@ -309,9 +396,15 @@ public: bool execute(long max_rows, char *completionTag); + void InitLocals(ParamListInfo params); + + void InitGlobals(); private: - EState* m_estate; - CmdType m_cmdType; + struct MotJitModifyFusionLocaleVariable { + CmdType m_cmdType; + EState* m_estate; + }; + MotJitModifyFusionLocaleVariable m_c_local; }; #endif @@ -325,14 +418,20 @@ public: void close(); + void InitLocals(ParamListInfo params); + + void InitGlobals(); private: - int64 m_limitCount; + struct SelectForUpdateFusionGlobalVariable { + int64 m_limitCount; + int64 m_limitOffset; + }; + SelectForUpdateFusionGlobalVariable* m_c_global; - EState* m_estate; - - int64 m_limitOffset; - - bool m_is_bucket_rel; + struct SelectForUpdateFusionLocaleVariable { + EState* m_estate; + }; + SelectForUpdateFusionLocaleVariable m_c_local; }; class AggFusion : public OpFusion { @@ -344,6 +443,10 @@ public: bool execute(long max_rows, char* completionTag); + void InitLocals(ParamListInfo params); + + void InitGlobals(); + protected: typedef void (AggFusion::*aggSumFun)(Datum *transVal, bool transIsNull, Datum *inVal, bool inIsNull); @@ -368,7 +471,10 @@ protected: dest->buf = NULL; /* digits array is not palloc'd */ } - aggSumFun m_aggSumFunc; + struct AggFusionGlobalVariable { + aggSumFun m_aggSumFunc; + }; + AggFusionGlobalVariable* m_c_global; }; class SortFusion: public OpFusion { @@ -381,8 +487,16 @@ public: bool execute(long max_rows, char *completionTag); + void InitLocals(ParamListInfo params); + + void InitGlobals(); + protected: - TupleDesc m_scanDesc; + struct SortFusionLocaleVariable { + TupleDesc m_scanDesc; + }; + + SortFusionLocaleVariable m_c_local; }; #endif /* SRC_INCLUDE_OPFUSION_OPFUSION_H_ */ diff --git a/src/include/opfusion/opfusion_util.h b/src/include/opfusion/opfusion_util.h index 77e8a4eb6..f7cbbab26 100644 --- a/src/include/opfusion/opfusion_util.h +++ b/src/include/opfusion/opfusion_util.h @@ -38,6 +38,7 @@ const int FUSION_DESCRIB = 1; extern int namestrcmp(Name name, const char* str); extern void report_qps_type(CmdType commandType); void InitOpfusionFunctionId(); +Node* JudgePlanIsPartIterator(Plan* plan); enum FusionType { NONE_FUSION, diff --git a/src/include/threadpool/threadpool_scheduler.h b/src/include/threadpool/threadpool_scheduler.h index d36d9d7be..7dd032bbc 100644 --- a/src/include/threadpool/threadpool_scheduler.h +++ b/src/include/threadpool/threadpool_scheduler.h @@ -46,6 +46,7 @@ public: return m_has_shutdown; } MemoryContext m_gpcContext; + bool m_getSIGHUP; private: void AdjustWorkerPool(int idx); void AdjustStreamPool(int idx); diff --git a/src/include/utils/globalplancore.h b/src/include/utils/globalplancore.h index 7d836f5e2..762a66db4 100644 --- a/src/include/utils/globalplancore.h +++ b/src/include/utils/globalplancore.h @@ -36,7 +36,7 @@ #define GPC_HTAB_SIZE (128) #define GLOBALPLANCACHEKEY_MAGIC (953717831) #define CAS_SLEEP_DURATION (2) -#define GPC_CLEAN_WAIT_TIME (3600) +#define GPC_CLEAN_WAIT_TIME (u_sess->attr.attr_common.gpc_clean_timeout) #define ENABLE_GPC (g_instance.attr.attr_common.enable_global_plancache == true && \ g_instance.attr.attr_common.enable_thread_pool == true) From 6b05f10be41f692ec3650b6cc441231b6924b35a Mon Sep 17 00:00:00 2001 From: TotaJ Date: Thu, 29 Apr 2021 19:48:27 +0800 Subject: [PATCH 2/3] return back IsStreamSupport --- src/common/backend/utils/cache/plancache.cpp | 17 +++++++++++++---- .../process/globalplancache/globalplancache.cpp | 2 +- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/src/common/backend/utils/cache/plancache.cpp b/src/common/backend/utils/cache/plancache.cpp index a994ab540..3a3db73fa 100644 --- a/src/common/backend/utils/cache/plancache.cpp +++ b/src/common/backend/utils/cache/plancache.cpp @@ -115,6 +115,15 @@ static bool check_stream_plan(Plan* plan); static bool is_upsert_query_with_update_param(Node* raw_parse_tree); static void GPCFillPlanCache(CachedPlanSource* plansource, bool isBuildingCustomPlan); +bool IsStreamSupport() +{ +#ifdef ENABLE_MULTIPLE_NODES + return u_sess->attr.attr_sql.enable_stream_operator; +#else + return u_sess->opt_cxt.query_dop > 1; +#endif +} + /* * InitPlanCache: initialize module during InitPostgres. * @@ -242,7 +251,7 @@ CachedPlanSource* CreateCachedPlan(Node* raw_parse_tree, const char* query_strin plansource->context = source_context; #ifdef PGXC plansource->stmt_name = (stmt_name ? pstrdup(stmt_name) : NULL); - plansource->stream_enabled = u_sess->attr.attr_sql.enable_stream_operator; + plansource->stream_enabled = IsStreamSupport(); plansource->cplan = NULL; plansource->single_exec_node = NULL; plansource->is_read_only = false; @@ -358,7 +367,7 @@ CachedPlanSource* CreateOneShotCachedPlan(Node* raw_parse_tree, const char* quer #endif #ifdef PGXC - plansource->stream_enabled = u_sess->attr.attr_sql.enable_stream_operator; + plansource->stream_enabled = IsStreamSupport();; plansource->cplan = NULL; plansource->single_exec_node = NULL; plansource->is_read_only = false; @@ -1001,7 +1010,7 @@ static bool CheckCachedPlan(CachedPlanSource* plansource) } /* If stream_operator alreadly change, need build plan again.*/ - if ((!plansource->gpc.status.InShareTable()) && plansource->stream_enabled != u_sess->attr.attr_sql.enable_stream_operator) { + if ((!plansource->gpc.status.InShareTable()) && plansource->stream_enabled != IsStreamSupport()) { return false; } @@ -1294,7 +1303,7 @@ static CachedPlan* BuildCachedPlan(CachedPlanSource* plansource, List* qlist, Pa MemoryContextSwitchTo(oldcxt); /* Set plan real u_sess->attr.attr_sql.enable_stream_operator.*/ - plansource->stream_enabled = u_sess->attr.attr_sql.enable_stream_operator; + plansource->stream_enabled = IsStreamSupport(); //in shared hash table, we can not share the plan, we should throw error before this logic. plan->is_share = false; diff --git a/src/gausskernel/process/globalplancache/globalplancache.cpp b/src/gausskernel/process/globalplancache/globalplancache.cpp index cb8e07325..af2ee2d07 100644 --- a/src/gausskernel/process/globalplancache/globalplancache.cpp +++ b/src/gausskernel/process/globalplancache/globalplancache.cpp @@ -561,7 +561,7 @@ void GlobalPlanCache::RecreateCachePlan(CachedPlanSource* oldsource, const char* GPC_LOG("recreate plan", oldsource, oldsource->stmt_name); CachedPlanSource *newsource = CopyCachedPlan(oldsource, true); MemoryContext oldcxt = MemoryContextSwitchTo(newsource->context); - newsource->stream_enabled = u_sess->attr.attr_sql.enable_stream_operator; + newsource->stream_enabled = IsStreamSupport(); u_sess->exec_cxt.CurrentOpFusionObj = NULL; Assert (oldsource->gpc.status.IsSharePlan()); newsource->gpc.status.ShareInit(); From 20c720785c995341f08d52f35da3ce6bece28f03 Mon Sep 17 00:00:00 2001 From: TotaJ Date: Thu, 29 Apr 2021 19:52:03 +0800 Subject: [PATCH 3/3] fix symbol --- src/common/backend/utils/cache/plancache.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/common/backend/utils/cache/plancache.cpp b/src/common/backend/utils/cache/plancache.cpp index 3a3db73fa..62b3e1338 100644 --- a/src/common/backend/utils/cache/plancache.cpp +++ b/src/common/backend/utils/cache/plancache.cpp @@ -367,7 +367,7 @@ CachedPlanSource* CreateOneShotCachedPlan(Node* raw_parse_tree, const char* quer #endif #ifdef PGXC - plansource->stream_enabled = IsStreamSupport();; + plansource->stream_enabled = IsStreamSupport(); plansource->cplan = NULL; plansource->single_exec_node = NULL; plansource->is_read_only = false;