From 2b53c44ed1bdaee1c86263009602e1f64861b173 Mon Sep 17 00:00:00 2001 From: Vinoth Date: Tue, 25 Aug 2020 09:40:36 +0800 Subject: [PATCH] Fix JIT range select functionality when client uses batch mode --- src/gausskernel/process/tcop/postgres.cpp | 22 +++++++++ src/gausskernel/runtime/executor/opfusion.cpp | 7 ++- .../storage/mot/jit_exec/src/jit_context.h | 12 ++++- .../storage/mot/jit_exec/src/jit_exec.cpp | 32 +++++++++--- .../mot/jit_exec/src/jit_llvm_exec.cpp | 20 ++++++++ .../storage/mot/jit_exec/src/jit_llvm_exec.h | 8 +-- .../storage/mot/jit_exec/src/jit_tvm.h | 3 ++ .../storage/mot/jit_exec/src/jit_tvm_exec.cpp | 49 ++++++++++++++++++- .../storage/mot/jit_exec/src/jit_tvm_exec.h | 5 +- src/include/storage/mot/jit_exec.h | 16 +++--- 10 files changed, 151 insertions(+), 23 deletions(-) diff --git a/src/gausskernel/process/tcop/postgres.cpp b/src/gausskernel/process/tcop/postgres.cpp index 3a3c8b119f..041efb5657 100755 --- a/src/gausskernel/process/tcop/postgres.cpp +++ b/src/gausskernel/process/tcop/postgres.cpp @@ -3867,6 +3867,17 @@ static void exec_bind_message(StringInfo input_message) ereport(ERROR, (errcode(ERRCODE_FDW_OPERATION_NOT_SUPPORTED), errmodule(MOD_MM), errmsg("SubTransaction is not supported for memory table."))); + /* + * MOT JIT Execution: + * Assist in distinguishing query boundaries in case of range query when client uses batches. This allows us to + * know a new query started, and in case a previous execution did not fetch all records (since user is working in + * batch-mode, and can decide to quit fetching in the middle), using this information we can infer this is a new + * scan, and old scan state should be discarded. + */ + if (psrc->mot_jit_context != NULL) { + JitResetScan(psrc->mot_jit_context); + } + if (psrc->opFusionObj != NULL) { (void)RevalidateCachedQuery(psrc); @@ -9694,6 +9705,17 @@ static void exec_one_in_batch(CachedPlanSource* psrc, ParamListInfo params, int cplan->single_shard_stmt = psrc->single_shard_stmt; } + /* + * MOT JIT Execution: + * Assist in distinguishing query boundaries in case of range query when client uses batches. This allows us to + * know a new query started, and in case a previous execution did not fetch all records (since user is working in + * batch-mode, and can decide to quit fetching in the middle), using this information we can infer this is a new + * scan, and old scan state should be discarded. + */ + if (psrc->mot_jit_context != NULL) { + JitResetScan(psrc->mot_jit_context); + } + if (IS_PGXC_DATANODE && psrc->is_checked_opfusion == false) { psrc->opFusionObj = OpFusion::FusionFactory(OpFusion::getFusionType(cplan, params, NULL), psrc->context, psrc, NULL, params); diff --git a/src/gausskernel/runtime/executor/opfusion.cpp b/src/gausskernel/runtime/executor/opfusion.cpp index cfa5d6cf39..944cf8c3df 100644 --- a/src/gausskernel/runtime/executor/opfusion.cpp +++ b/src/gausskernel/runtime/executor/opfusion.cpp @@ -915,7 +915,6 @@ MotJitSelectFusion::MotJitSelectFusion(MemoryContext context, CachedPlanSource* bool MotJitSelectFusion::execute(long max_rows, char* completionTag) { - max_rows = FETCH_ALL; ParamListInfo params = m_outParams != NULL ? m_outParams : m_params; bool success = false; setReceiver(); @@ -927,13 +926,17 @@ bool MotJitSelectFusion::execute(long max_rows, char* completionTag) int scanEnded = 0; rc = JitExec::JitExecQuery(m_cacheplan->mot_jit_context, params, m_reslot, &tpProcessed, &scanEnded); if (scanEnded || (tpProcessed == 0) || (rc != 0)) { - finish = true; // raise flag so that next round we will bail out (current tuple still must be reported to user) + // raise flag so that next round we will bail out (current tuple still must be reported to user) + finish = true; } CHECK_FOR_INTERRUPTS(); if (tpProcessed > 0) { nprocessed++; (*m_receiver->receiveSlot)(m_reslot, m_receiver); (void)ExecClearTuple(m_reslot); + if ((max_rows != FETCH_ALL) && (nprocessed == (unsigned long)max_rows)) { + finish = true; + } } } diff --git a/src/gausskernel/storage/mot/jit_exec/src/jit_context.h b/src/gausskernel/storage/mot/jit_exec/src/jit_context.h index 67b3f52eb2..1fe59b8027 100644 --- a/src/gausskernel/storage/mot/jit_exec/src/jit_context.h +++ b/src/gausskernel/storage/mot/jit_exec/src/jit_context.h @@ -193,10 +193,20 @@ struct JitContext { /** @var The JIT source from which this context originated. */ JitSource* m_jitSource; // L1 offset 8 + /*---------------------- Batch Execution -------------------*/ + /** + * @var The number of times (iterations) a single stateful query was invoked. Used for distinguishing query + * boundaries in a stateful query execution when client uses batches. + */ + uint64_t m_iterCount; // L1 offset 16 + + /** @var The number of full query executions. */ + uint64_t m_queryCount; // L1 offset 24 + /*---------------------- Debug execution state -------------------*/ /** @var The number of times this context was invoked for execution. */ #ifdef MOT_JIT_DEBUG - uint64_t m_execCount; // L1 offset 16 + uint64_t m_execCount; // L1 offset 32 #endif }; diff --git a/src/gausskernel/storage/mot/jit_exec/src/jit_exec.cpp b/src/gausskernel/storage/mot/jit_exec/src/jit_exec.cpp index aebc89ee94..915a66b450 100644 --- a/src/gausskernel/storage/mot/jit_exec/src/jit_exec.cpp +++ b/src/gausskernel/storage/mot/jit_exec/src/jit_exec.cpp @@ -109,10 +109,6 @@ extern JitPlan* IsJittable(Query* query, const char* queryString) MOT_LOG_TRACE("Disqualifying plan with DISTINCT aggregate"); JitDestroyPlan(jitPlan); jitPlan = nullptr; - } else if (JitPlanHasSort(jitPlan)) { - MOT_LOG_TRACE("Disqualifying plan with ORDER BY specifier"); - JitDestroyPlan(jitPlan); - jitPlan = nullptr; } else { MOT_LOG_TRACE("Query %s jittable by plan", jitPlan ? "is" : "is not"); if (MOT_CHECK_LOG_LEVEL(MOT::LogLevel::LL_TRACE)) { @@ -330,6 +326,12 @@ extern JitContext* JitCodegenQuery(Query* query, const char* queryString, JitPla return jitContext; } +extern void JitResetScan(JitContext* jitContext) +{ + MOT_LOG_DEBUG("JitResetScan(): Resetting iteration count for context %p", jitContext); + jitContext->m_iterCount = 0; +} + extern int JitExecQuery( JitContext* jitContext, ParamListInfo params, TupleTableSlot* slot, uint64_t* tuplesProcessed, int* scanEnded) { @@ -378,15 +380,32 @@ extern int JitExecQuery( // in trace log-level we raise the log level to DEBUG on first few executions only bool firstExec = false; if ((++jitContext->m_execCount <= 2) && MOT_CHECK_LOG_LEVEL(MOT::LogLevel::LL_TRACE)) { - MOT_LOG_TRACE("Executing JIT context %p for the %dth time: %s", + MOT_LOG_TRACE("Executing JIT context %p (exec: %" PRIu64 ", query: %" PRIu64 " iteration: %" PRIu64 "): %s", jitContext, jitContext->m_execCount, + jitContext->m_queryCount, + jitContext->m_iterCount, jitContext->m_queryString); MOT::SetLogComponentLogLevel("JitExec", MOT::LogLevel::LL_DEBUG); firstExec = true; } #endif + // update iteration count and identify a new scan + int newScan = 0; + if (jitContext->m_iterCount == 0) { + ++jitContext->m_queryCount; + newScan = 1; +#ifdef MOT_JIT_DEBUG + MOT_LOG_TRACE("Starting a new scan (exec: %" PRIu64 ", query: %" PRIu64 ",iteration: %" PRIu64 ") for query %s", + jitContext->m_execCount, + jitContext->m_queryCount, + jitContext->m_iterCount, + jitContext->m_queryString); +#endif + } + ++jitContext->m_iterCount; + // invoke the jitted function if (jitContext->m_llvmFunction != nullptr) { #ifdef MOT_JIT_DEBUG @@ -400,6 +419,7 @@ extern int JitExecQuery( slot, tuplesProcessed, scanEnded, + newScan, jitContext->m_endIteratorKey, jitContext->m_innerTable, jitContext->m_innerIndex, @@ -409,7 +429,7 @@ extern int JitExecQuery( #ifdef MOT_JIT_DEBUG MOT_LOG_DEBUG("Executing TVM-jitted function %p: %s", jitContext->m_tvmFunction, jitContext->m_queryString); #endif - result = JitExecTvmQuery(jitContext, params, slot, tuplesProcessed, scanEnded); + result = JitExecTvmQuery(jitContext, params, slot, tuplesProcessed, scanEnded, newScan); } #ifdef MOT_JIT_DEBUG diff --git a/src/gausskernel/storage/mot/jit_exec/src/jit_llvm_exec.cpp b/src/gausskernel/storage/mot/jit_exec/src/jit_llvm_exec.cpp index 52fe6d0dce..72027d7eac 100644 --- a/src/gausskernel/storage/mot/jit_exec/src/jit_llvm_exec.cpp +++ b/src/gausskernel/storage/mot/jit_exec/src/jit_llvm_exec.cpp @@ -237,6 +237,7 @@ struct JitLlvmCodeGenContext { llvm::Value* slot_value; llvm::Value* tp_processed_value; llvm::Value* scan_ended_value; + llvm::Value* isNewScanValue; llvm::Value* bitmap_value; llvm::Value* inner_table_value; llvm::Value* inner_index_value; @@ -2042,6 +2043,7 @@ static void CreateJittedFunction(JitLlvmCodeGenContext* ctx, const char* functio fn_prototype.addArgument(GsCodeGen::NamedVariable("slot", ctx->TupleTableSlotType->getPointerTo())); fn_prototype.addArgument(GsCodeGen::NamedVariable("tp_processed", ctx->INT64_T->getPointerTo())); fn_prototype.addArgument(GsCodeGen::NamedVariable("scan_ended", ctx->INT32_T->getPointerTo())); + fn_prototype.addArgument(GsCodeGen::NamedVariable("isNewScan", ctx->INT32_T)); fn_prototype.addArgument(GsCodeGen::NamedVariable("end_iterator_key", ctx->KeyType->getPointerTo())); fn_prototype.addArgument(GsCodeGen::NamedVariable("inner_table", ctx->TableType->getPointerTo())); fn_prototype.addArgument(GsCodeGen::NamedVariable("inner_index", ctx->IndexType->getPointerTo())); @@ -2060,6 +2062,7 @@ static void CreateJittedFunction(JitLlvmCodeGenContext* ctx, const char* functio ctx->slot_value = llvmargs[arg_index++]; ctx->tp_processed_value = llvmargs[arg_index++]; ctx->scan_ended_value = llvmargs[arg_index++]; + ctx->isNewScanValue = llvmargs[arg_index++]; ctx->end_iterator_key_value = llvmargs[arg_index++]; ctx->inner_table_value = llvmargs[arg_index++]; ctx->inner_index_value = llvmargs[arg_index++]; @@ -4511,6 +4514,17 @@ static JitContext* JitSelectCodegen(const Query* query, const char* query_string return jit_context; } +static void AddCleanupOldScan(JitLlvmCodeGenContext* ctx) +{ + JIT_IF_BEGIN(cleanup_old_scan) + JIT_IF_EVAL(ctx->isNewScanValue) + IssueDebugLog("Destroying state iterators due to new scan"); + AddDestroyStateIterators(ctx, JIT_RANGE_SCAN_MAIN); + AddDestroyStateIterators(ctx, JIT_RANGE_SCAN_INNER); + // sub-query does not have a stateful execution, so no need to cleanup + JIT_IF_END() +} + /** @brief Generates code for range SELECT query with a possible LIMIT clause. */ static JitContext* JitRangeSelectCodegen(const Query* query, const char* query_string, JitRangeSelectPlan* plan) { @@ -4540,6 +4554,9 @@ static JitContext* JitRangeSelectCodegen(const Query* query, const char* query_s // clear tuple even if row is not found later AddExecClearTuple(ctx); + // emit code to cleanup previous scan in case this is a new scan + AddCleanupOldScan(ctx); + // prepare stateful scan if not done so already, if no row exists then emit code to return from function int max_arg = 0; MOT::AccessType access_mode = query->hasForUpdate ? MOT::AccessType::RD_FOR_UPDATE : MOT::AccessType::RD; @@ -5029,6 +5046,9 @@ static JitContext* JitRangeJoinCodegen(const Query* query, const char* query_str // clear tuple even if row is not found later AddExecClearTuple(ctx); + // emit code to cleanup previous scan in case this is a new scan + AddCleanupOldScan(ctx); + // prepare stateful scan if not done so already int max_arg = 0; llvm::BasicBlock* fetch_outer_row_bb = nullptr; diff --git a/src/gausskernel/storage/mot/jit_exec/src/jit_llvm_exec.h b/src/gausskernel/storage/mot/jit_exec/src/jit_llvm_exec.h index 9fe573c9fb..4c9b277b2f 100644 --- a/src/gausskernel/storage/mot/jit_exec/src/jit_llvm_exec.h +++ b/src/gausskernel/storage/mot/jit_exec/src/jit_llvm_exec.h @@ -52,6 +52,7 @@ struct JitPlan; * @param[out] slot The slot used for reporting select result. * @param[out] tuplesProcessed The variable used to report the number of processed rows. * @param[out] scanEnded Signifies in range scans whether scan ended. + * @param newScan Specifies whether this is a new scan or a continued previous scan. * @param endIteratorKey The key used for the end iterator in range scans. * @param innerTable The inner scan table used during JOIN queries. * @param innerKey The search key used for the inner scan table during JOIN queries. @@ -60,11 +61,12 @@ struct JitPlan; * @note This function may cause transaction abort. */ typedef int (*JitFunc)(MOT::Table* table, MOT::Index* index, MOT::Key* key, MOT::BitmapSet* bitmapSet, - ParamListInfo params, TupleTableSlot* slot, uint64_t* tuplesProcessed, int* scanEnded, MOT::Key* endIteratorKey, - MOT::Table* innerTable, MOT::Index* innerIndex, MOT::Key* innerKey, MOT::Key* innerEndIteratorKey); + ParamListInfo params, TupleTableSlot* slot, uint64_t* tuplesProcessed, int* scanEnded, int newScan, + MOT::Key* endIteratorKey, MOT::Table* innerTable, MOT::Index* innerIndex, MOT::Key* innerKey, + MOT::Key* innerEndIteratorKey); // the number of arguments in the jitted function -#define MOT_JIT_FUNC_ARG_COUNT 13 +#define MOT_JIT_FUNC_ARG_COUNT 14 #ifdef __aarch64__ /** diff --git a/src/gausskernel/storage/mot/jit_exec/src/jit_tvm.h b/src/gausskernel/storage/mot/jit_exec/src/jit_tvm.h index fd4d362a2f..de913a48a8 100644 --- a/src/gausskernel/storage/mot/jit_exec/src/jit_tvm.h +++ b/src/gausskernel/storage/mot/jit_exec/src/jit_tvm.h @@ -66,6 +66,9 @@ struct ExecContext { /** @var Specifies whether a range scan ended. */ int* _scan_ended; + /** @var Specifies whether this is a new scan or a continued previous scan. */ + int m_newScan; + // Pseudo-LLVM execution info /** @var The result code of last expression evaluation. */ int64_t _expr_rc; diff --git a/src/gausskernel/storage/mot/jit_exec/src/jit_tvm_exec.cpp b/src/gausskernel/storage/mot/jit_exec/src/jit_tvm_exec.cpp index 60d15bc3d3..adef2466ca 100755 --- a/src/gausskernel/storage/mot/jit_exec/src/jit_tvm_exec.cpp +++ b/src/gausskernel/storage/mot/jit_exec/src/jit_tvm_exec.cpp @@ -1935,6 +1935,26 @@ private: Instruction* _itr_inst; }; +class IsNewScanInstruction : public Instruction { +public: + IsNewScanInstruction() + {} + + ~IsNewScanInstruction() final + {} + +protected: + uint64_t ExecImpl(ExecContext* exec_context) final + { + return (uint64_t)exec_context->m_newScan; + } + + void DumpImpl() final + { + (void)fprintf(stderr, "isNewScan()"); + } +}; + /** @class GetStateIteratorInstruction */ class SetStateIteratorInstruction : public Instruction { public: @@ -3043,6 +3063,12 @@ static void AddDestroyCursor(JitTvmCodeGenContext* ctx, JitTvmRuntimeCursor* cur AddDestroyIterator(ctx, cursor->end_itr); } +/** @brief Adds a call to pseudo-function isNewScan(begin_itr). */ +static Instruction* AddIsNewScan(JitTvmCodeGenContext* ctx) +{ + return ctx->_builder->addInstruction(new (std::nothrow) IsNewScanInstruction()); +} + /** @brief Adds a call to setStateIterator(itr, begin_itr). */ static void AddSetStateIterator( JitTvmCodeGenContext* ctx, Instruction* itr, JitRangeIteratorType range_itr_type, JitRangeScanType range_scan_type) @@ -5699,6 +5725,18 @@ static JitContext* JitSelectCodegen(const Query* query, const char* query_string return jit_context; } +static void AddCleanupOldScan(JitTvmCodeGenContext* ctx) +{ + // emit code to cleanup previous scan in case this is a new scan + JIT_IF_BEGIN(cleanup_old_scan) + Instruction* isNewScan = AddIsNewScan(ctx); + JIT_IF_EVAL(isNewScan) + AddDestroyStateIterators(ctx, JIT_RANGE_SCAN_MAIN); + AddDestroyStateIterators(ctx, JIT_RANGE_SCAN_INNER); + // sub-query does not have a stateful execution, so no need to cleanup + JIT_IF_END() +} + /** @brief Generates code for range SELECT query with a possible LIMIT clause. */ static JitContext* JitRangeSelectCodegen(const Query* query, const char* query_string, JitRangeSelectPlan* plan) { @@ -5724,6 +5762,9 @@ static JitContext* JitRangeSelectCodegen(const Query* query, const char* query_s // clear tuple even if row is not found later AddExecClearTuple(ctx); + // emit code to cleanup previous scan in case this is a new scan + AddCleanupOldScan(ctx); + // prepare stateful scan if not done so already, if no row exists then emit code to return from function int max_arg = 0; MOT::AccessType access_mode = query->hasForUpdate ? MOT::AccessType::RD_FOR_UPDATE : MOT::AccessType::RD; @@ -6192,6 +6233,9 @@ static JitContext* JitRangeJoinCodegen(const Query* query, const char* query_str // clear tuple even if row is not found later AddExecClearTuple(ctx); + // emit code to cleanup previous scan in case this is a new scan + AddCleanupOldScan(ctx); + // prepare stateful scan if not done so already int max_arg = 0; BasicBlock* fetch_outer_row_bb = nullptr; @@ -6795,8 +6839,8 @@ extern JitContext* JitCodegenTvmQuery(Query* query, const char* query_string, Ji return jit_context; } -extern int JitExecTvmQuery( - JitContext* jit_context, ParamListInfo params, TupleTableSlot* slot, uint64_t* tp_processed, int* scan_ended) +extern int JitExecTvmQuery(JitContext* jit_context, ParamListInfo params, TupleTableSlot* slot, uint64_t* tp_processed, + int* scan_ended, int newScan) { int result = 0; ExecContext* exec_context = jit_context->m_execContext; @@ -6819,6 +6863,7 @@ extern int JitExecTvmQuery( exec_context->_slot = slot; exec_context->_tp_processed = tp_processed; exec_context->_scan_ended = scan_ended; + exec_context->m_newScan = newScan; result = (int)jit_context->m_tvmFunction->exec(exec_context); } diff --git a/src/gausskernel/storage/mot/jit_exec/src/jit_tvm_exec.h b/src/gausskernel/storage/mot/jit_exec/src/jit_tvm_exec.h index a2896d9adc..9097300103 100644 --- a/src/gausskernel/storage/mot/jit_exec/src/jit_tvm_exec.h +++ b/src/gausskernel/storage/mot/jit_exec/src/jit_tvm_exec.h @@ -58,11 +58,12 @@ extern JitContext* JitCodegenTvmQuery(Query* query, const char* queryString, Jit * @param[out] slot The slot used for reporting select result. * @param[out] tuplesProcessed The variable used to report the number of processed tuples. * @param[out] scanEnded The variable used to report if a range scan ended. + * @param newScan Specifies whether this is a new scan or a continued previous scan. * @return Zero if succeeded, otherwise an error code. * @note This function may cause transaction abort. */ -extern int JitExecTvmQuery( - JitContext* jitContext, ParamListInfo params, TupleTableSlot* slot, uint64_t* tuplesProcessed, int* scanEnded); +extern int JitExecTvmQuery(JitContext* jitContext, ParamListInfo params, TupleTableSlot* slot, + uint64_t* tuplesProcessed, int* scanEnded, int newScan); } // namespace JitExec #endif // JIT_TVM_EXEC_H diff --git a/src/include/storage/mot/jit_exec.h b/src/include/storage/mot/jit_exec.h index 4acc84b24d..12bc8673b3 100644 --- a/src/include/storage/mot/jit_exec.h +++ b/src/include/storage/mot/jit_exec.h @@ -66,7 +66,7 @@ extern void DisableMotCodegen(); * @param queryString The query text. * @return The JIT plan if the query is jittable, otherwise NULL. */ -extern JitPlan* IsJittable(Query *query, const char* queryString); +extern JitPlan* IsJittable(Query* query, const char* queryString); /** * @brief Generate jitted code for a query. @@ -75,7 +75,10 @@ extern JitPlan* IsJittable(Query *query, const char* queryString); * @param jitPlan The JIT plan produced during the call to @ref IsJittable(). * @return The context of the jitted code required for later execution. */ -extern JitContext* JitCodegenQuery(Query *query, const char* queryString, JitPlan* jitPlan); +extern JitContext* JitCodegenQuery(Query* query, const char* queryString, JitPlan* jitPlan); + +/** @brief Resets the scan iteration counter for the JIT context. */ +extern void JitResetScan(JitContext* jitContext); /** * @brief Executed a previously jitted query. @@ -87,8 +90,8 @@ extern JitContext* JitCodegenQuery(Query *query, const char* queryString, JitPla * @return Zero if succeeded, otherwise an error code. * @note This function may cause transaction abort. */ -extern int JitExecQuery(JitContext* jitContext, ParamListInfo params, TupleTableSlot* slot, uint64_t* tuplesProcessed, - int* scanEnded); +extern int JitExecQuery( + JitContext* jitContext, ParamListInfo params, TupleTableSlot* slot, uint64_t* tuplesProcessed, int* scanEnded); /** * @brief Purges the global cache of JIT source stencils from all entries that refer the given relation id. @@ -106,7 +109,6 @@ extern void FreeSessionJitContextPool(JitContextPool* jitContextPool); /** @brief Releases all resources associated with a plan.*/ extern void JitDestroyPlan(JitPlan* plan); +} // namespace JitExec -} // namespace JitExec - -#endif // JIT_EXEC_H +#endif // JIT_EXEC_H -- Gitee