From 3a452630b67f26d100c60234941a40d4468c170e Mon Sep 17 00:00:00 2001 From: Adriano dos Santos Fernandes Date: Wed, 24 Nov 2021 15:18:39 -0300 Subject: [PATCH 1/3] Add table MON$COMPILED_STATEMENTS and columns MON$STATEMENTS.MON$COMPILED_STATEMENT_ID and MON$CALL_STACK.MON$COMPILED_STATEMENT_ID. --- src/dsql/dsql.cpp | 4 +- src/jrd/Attachment.cpp | 1 + src/jrd/Attachment.h | 1 + src/jrd/Database.h | 6 +++ src/jrd/JrdStatement.cpp | 16 ++++--- src/jrd/JrdStatement.h | 8 ++++ src/jrd/Monitoring.cpp | 80 ++++++++++++++++++++++++++++++---- src/jrd/Monitoring.h | 1 + src/jrd/exe.cpp | 9 +++- src/jrd/names.h | 3 ++ src/jrd/opt.cpp | 6 +-- src/jrd/opt_proto.h | 2 +- src/jrd/relations.h | 12 +++++ src/jrd/req.h | 12 ++++- src/jrd/trace/TraceObjects.cpp | 2 +- 15 files changed, 142 insertions(+), 21 deletions(-) diff --git a/src/dsql/dsql.cpp b/src/dsql/dsql.cpp index 07098bd3a3c..fe24f8db7a6 100644 --- a/src/dsql/dsql.cpp +++ b/src/dsql/dsql.cpp @@ -2197,7 +2197,9 @@ static void sql_info(thread_db* tdbb, { const bool detailed = (item == isc_info_sql_explain_plan); string plan = tdbb->getAttachment()->stringToUserCharSet(tdbb, - OPT_get_plan(tdbb, request->req_request, detailed)); + OPT_get_plan(tdbb, + (request->req_request ? request->req_request->getStatement() : nullptr), + detailed)); if (plan.hasData()) { diff --git a/src/jrd/Attachment.cpp b/src/jrd/Attachment.cpp index d3f5530447d..2cfbfb0c62a 100644 --- a/src/jrd/Attachment.cpp +++ b/src/jrd/Attachment.cpp @@ -225,6 +225,7 @@ Jrd::Attachment::Attachment(MemoryPool* pool, Database* dbb, JProvider* provider att_ss_user(NULL), att_user_ids(*pool), att_active_snapshots(*pool), + att_statements(*pool), att_requests(*pool), att_lock_owner_id(Database::getLockOwnerId()), att_backup_state_counter(0), diff --git a/src/jrd/Attachment.h b/src/jrd/Attachment.h index 563940ffd6a..1e42f2a2633 100644 --- a/src/jrd/Attachment.h +++ b/src/jrd/Attachment.h @@ -545,6 +545,7 @@ class Attachment : public pool_alloc StableAttachmentPart* att_stable; public: + Firebird::SortedArray att_statements; // Statements belonging to attachment Firebird::SortedArray att_requests; // Requests belonging to attachment Lock* att_id_lock; // Attachment lock (if any) AttNumber att_attachment_id; // Attachment ID diff --git a/src/jrd/Database.h b/src/jrd/Database.h index 236bd4e64d9..353aedf5815 100644 --- a/src/jrd/Database.h +++ b/src/jrd/Database.h @@ -59,6 +59,7 @@ #include "../jrd/RandomGenerator.h" #include "../common/os/guid.h" #include "../common/os/os_utils.h" +#include "../jrd/ods.h" #include "../jrd/sbm.h" #include "../jrd/flu.h" #include "../jrd/RuntimeStatistics.h" @@ -582,6 +583,11 @@ class Database : public pool_alloc return (dbb_replica_mode == mode); } + USHORT getEncodedOdsVersion() const + { + return ENCODE_ODS(dbb_ods_version, dbb_minor_version); + } + private: Database(MemoryPool* p, Firebird::IPluginConfig* pConf, bool shared) : dbb_permanent(p), diff --git a/src/jrd/JrdStatement.cpp b/src/jrd/JrdStatement.cpp index 2af48dcb895..1ce4864d13e 100644 --- a/src/jrd/JrdStatement.cpp +++ b/src/jrd/JrdStatement.cpp @@ -304,6 +304,8 @@ JrdStatement* JrdStatement::makeStatement(thread_db* tdbb, CompilerScratch* csb, if (internalFlag) statement->flags |= FLAG_INTERNAL; + tdbb->getAttachment()->att_statements.add(statement); + return statement; } @@ -407,7 +409,6 @@ jrd_req* JrdStatement::getRequest(thread_db* tdbb, USHORT level) // Create the request. jrd_req* const request = FB_NEW_POOL(*pool) jrd_req(attachment, this, parentStats); - request->setRequestId(dbb->generateStatementId()); requests[level] = request; @@ -645,14 +646,19 @@ void JrdStatement::release(thread_db* tdbb) for (jrd_req** instance = requests.begin(); instance != requests.end(); ++instance) EXE_release(tdbb, *instance); + const auto attachment = tdbb->getAttachment(); + + FB_SIZE_T pos; + if (attachment->att_statements.find(this, pos)) + attachment->att_statements.remove(pos); + else + fb_assert(false); + sqlText = NULL; // Sub statement pool is the same of the main statement, so don't delete it. if (!parentStatement) - { - Jrd::Attachment* const att = tdbb->getAttachment(); - att->deletePool(pool); - } + attachment->deletePool(pool); } // Check that we have enough rights to access all resources this list of triggers touches. diff --git a/src/jrd/JrdStatement.h b/src/jrd/JrdStatement.h index ed67f30dfaa..1234b11adde 100644 --- a/src/jrd/JrdStatement.h +++ b/src/jrd/JrdStatement.h @@ -48,6 +48,13 @@ class JrdStatement : public pool_alloc static JrdStatement* makeStatement(thread_db* tdbb, CompilerScratch* csb, bool internalFlag); static jrd_req* makeRequest(thread_db* tdbb, CompilerScratch* csb, bool internalFlag); + StmtNumber getStatementId() const + { + if (!id) + id = JRD_get_thread_data()->getDatabase()->generateStatementId(); + return id; + } + const Routine* getRoutine() const; bool isActive() const; @@ -68,6 +75,7 @@ class JrdStatement : public pool_alloc unsigned flags; // statement flags unsigned blrVersion; ULONG impureSize; // Size of impure area + mutable StmtNumber id; // statement identifier Firebird::Array rpbsSetup; Firebird::Array requests; // vector of requests ExternalAccessList externalList; // Access to procedures/triggers to be checked diff --git a/src/jrd/Monitoring.cpp b/src/jrd/Monitoring.cpp index 17b6767982f..be19a879fe7 100644 --- a/src/jrd/Monitoring.cpp +++ b/src/jrd/Monitoring.cpp @@ -446,6 +446,9 @@ MonitoringSnapshot::MonitoringSnapshot(thread_db* tdbb, MemoryPool& pool) RecordBuffer* const dbb_buffer = allocBuffer(tdbb, pool, rel_mon_database); RecordBuffer* const att_buffer = allocBuffer(tdbb, pool, rel_mon_attachments); RecordBuffer* const tra_buffer = allocBuffer(tdbb, pool, rel_mon_transactions); + RecordBuffer* const cmp_stmt_buffer = dbb->getEncodedOdsVersion() >= ODS_13_1 ? + allocBuffer(tdbb, pool, rel_mon_compiled_statements) : + nullptr; RecordBuffer* const stmt_buffer = allocBuffer(tdbb, pool, rel_mon_statements); RecordBuffer* const call_buffer = allocBuffer(tdbb, pool, rel_mon_calls); RecordBuffer* const io_stat_buffer = allocBuffer(tdbb, pool, rel_mon_io_stats); @@ -561,6 +564,9 @@ MonitoringSnapshot::MonitoringSnapshot(thread_db* tdbb, MemoryPool& pool) case rel_mon_transactions: buffer = tra_buffer; break; + case rel_mon_compiled_statements: + buffer = cmp_stmt_buffer; + break; case rel_mon_statements: buffer = stmt_buffer; break; @@ -1039,7 +1045,7 @@ void Monitoring::putAttachment(SnapshotData::DumpRecord& record, const Jrd::Atta // statement timeout, milliseconds record.storeInteger(f_mon_att_stmt_timeout, attachment->getStatementTimeout()); - if (ENCODE_ODS(dbb->dbb_ods_version, dbb->dbb_minor_version) >= ODS_13_1) + if (dbb->getEncodedOdsVersion() >= ODS_13_1) { char timeZoneBuffer[TimeZoneUtil::MAX_SIZE]; TimeZoneUtil::format(timeZoneBuffer, sizeof(timeZoneBuffer), attachment->att_current_timezone); @@ -1134,11 +1140,49 @@ void Monitoring::putTransaction(SnapshotData::DumpRecord& record, const jrd_tra* } +void Monitoring::putStatement(SnapshotData::DumpRecord& record, const JrdStatement* statement, const string& plan) +{ + fb_assert(statement); + + record.reset(rel_mon_compiled_statements); + + // compiled statement id + record.storeInteger(f_mon_cmp_stmt_id, statement->getStatementId()); + + // sql text + if (statement->sqlText) + record.storeString(f_mon_cmp_stmt_sql_text, *statement->sqlText); + + // explained plan + if (plan.hasData()) + record.storeString(f_mon_cmp_stmt_expl_plan, plan); + + // object name/type + if (const auto routine = statement->getRoutine()) + { + if (routine->getName().package.hasData()) + record.storeString(f_mon_cmp_stmt_pkg_name, routine->getName().package); + + record.storeString(f_mon_cmp_stmt_name, routine->getName().identifier); + record.storeInteger(f_mon_cmp_stmt_type, routine->getObjectType()); + } + else if (!statement->triggerName.isEmpty()) + { + record.storeString(f_mon_cmp_stmt_name, statement->triggerName); + record.storeInteger(f_mon_cmp_stmt_type, obj_trigger); + } + + record.write(); +} + + void Monitoring::putRequest(SnapshotData::DumpRecord& record, const jrd_req* request, const string& plan) { fb_assert(request); + const auto dbb = request->req_attachment->att_database; + record.reset(rel_mon_statements); // request id @@ -1181,6 +1225,10 @@ void Monitoring::putRequest(SnapshotData::DumpRecord& record, const jrd_req* req // statement timeout, milliseconds record.storeInteger(f_mon_stmt_timeout, request->req_timeout); + + if (dbb->getEncodedOdsVersion() >= ODS_13_1) + record.storeInteger(f_mon_stmt_cmp_stmt_id, statement->getStatementId()); + record.write(); putStatistics(record, request->req_stats, stat_id, stat_statement); @@ -1192,7 +1240,9 @@ void Monitoring::putCall(SnapshotData::DumpRecord& record, const jrd_req* reques { fb_assert(request); + const auto dbb = request->req_attachment->att_database; const jrd_req* initialRequest = request->req_caller; + while (initialRequest->req_caller) { initialRequest = initialRequest->req_caller; @@ -1241,6 +1291,9 @@ void Monitoring::putCall(SnapshotData::DumpRecord& record, const jrd_req* reques record.storeInteger(f_mon_call_src_column, request->req_src_column); } + if (dbb->getEncodedOdsVersion() >= ODS_13_1) + record.storeInteger(f_mon_call_cmp_stmt_id, statement->getStatementId()); + // statistics const int stat_id = fb_utils::genUniqueId(); record.storeGlobalId(f_mon_call_stat_id, getGlobalId(stat_id)); @@ -1432,18 +1485,29 @@ void Monitoring::dumpAttachment(thread_db* tdbb, Attachment* attachment) } } + if (dbb->getEncodedOdsVersion() >= ODS_13_1) + { + // Statement information + + for (const auto statement : attachment->att_statements) + { + if (!(statement->flags & (JrdStatement::FLAG_INTERNAL | JrdStatement::FLAG_SYS_TRIGGER))) + { + const string plan = OPT_get_plan(tdbb, statement, true); + putStatement(record, statement, plan); + } + } + } + // Request information - for (const jrd_req* const* i = attachment->att_requests.begin(); - i != attachment->att_requests.end(); - ++i) + for (const auto request : attachment->att_requests) { - const jrd_req* const request = *i; + const auto statement = request->getStatement(); - if (!(request->getStatement()->flags & - (JrdStatement::FLAG_INTERNAL | JrdStatement::FLAG_SYS_TRIGGER))) + if (!(statement->flags & (JrdStatement::FLAG_INTERNAL | JrdStatement::FLAG_SYS_TRIGGER))) { - const string plan = OPT_get_plan(tdbb, request, true); + const string plan = OPT_get_plan(tdbb, statement, true); putRequest(record, request, plan); } } diff --git a/src/jrd/Monitoring.h b/src/jrd/Monitoring.h index 7e8d266c614..65d959f0621 100644 --- a/src/jrd/Monitoring.h +++ b/src/jrd/Monitoring.h @@ -389,6 +389,7 @@ class Monitoring static void putAttachment(SnapshotData::DumpRecord&, const Attachment*); static void putTransaction(SnapshotData::DumpRecord&, const jrd_tra*); + static void putStatement(SnapshotData::DumpRecord&, const JrdStatement*, const Firebird::string&); static void putRequest(SnapshotData::DumpRecord&, const jrd_req*, const Firebird::string&); static void putCall(SnapshotData::DumpRecord&, const jrd_req*); static void putStatistics(SnapshotData::DumpRecord&, const RuntimeStatistics&, int, int); diff --git a/src/jrd/exe.cpp b/src/jrd/exe.cpp index 6b46cdcb9f8..36fd215fbe0 100644 --- a/src/jrd/exe.cpp +++ b/src/jrd/exe.cpp @@ -878,7 +878,14 @@ void EXE_start(thread_db* tdbb, jrd_req* request, jrd_tra* transaction) if (transaction->tra_flags & TRA_prepared) ERR_post(Arg::Gds(isc_req_no_trans)); - JrdStatement* statement = request->getStatement(); + const auto dbb = tdbb->getDatabase(); + const auto statement = request->getStatement(); + + // Generate request id. + request->setRequestId( + request->isRequestIdUnassigned() && statement->requests.hasData() && request == statement->requests[0] ? + statement->getStatementId() : + dbb->generateStatementId()); /* Post resources to transaction block. In particular, the interest locks on relations/indices are copied to the transaction, which is very diff --git a/src/jrd/names.h b/src/jrd/names.h index ece88e406d1..1c81cafc3c7 100644 --- a/src/jrd/names.h +++ b/src/jrd/names.h @@ -457,3 +457,6 @@ NAME("MON$SESSION_TIMEZONE", nam_mon_session_tz) NAME("RDB$KEYWORDS", nam_keywords) NAME("RDB$KEYWORD_NAME", nam_keyword_name) NAME("RDB$KEYWORD_RESERVED", nam_keyword_reserved) + +NAME("MON$COMPILED_STATEMENTS", nam_mon_compiled_statements) +NAME("MON$COMPILED_STATEMENT_ID", nam_mon_cmp_stmt_id) diff --git a/src/jrd/opt.cpp b/src/jrd/opt.cpp index d212417ed1c..35e777ab503 100644 --- a/src/jrd/opt.cpp +++ b/src/jrd/opt.cpp @@ -441,7 +441,7 @@ static const UCHAR sort_dtypes[] = }; -string OPT_get_plan(thread_db* tdbb, const jrd_req* request, bool detailed) +string OPT_get_plan(thread_db* tdbb, const JrdStatement* statement, bool detailed) { /************************************** * @@ -455,9 +455,9 @@ string OPT_get_plan(thread_db* tdbb, const jrd_req* request, bool detailed) **************************************/ string plan; - if (request) + if (statement) { - const Array& fors = request->getStatement()->fors; + const Array& fors = statement->fors; for (FB_SIZE_T i = 0; i < fors.getCount(); i++) { diff --git a/src/jrd/opt_proto.h b/src/jrd/opt_proto.h index af6284dbd3a..233d8ee3ee7 100644 --- a/src/jrd/opt_proto.h +++ b/src/jrd/opt_proto.h @@ -41,7 +41,7 @@ namespace Jrd { class MapNode; } -Firebird::string OPT_get_plan(Jrd::thread_db* tdbb, const Jrd::jrd_req* request, bool detailed); +Firebird::string OPT_get_plan(Jrd::thread_db* tdbb, const Jrd::JrdStatement* statement, bool detailed); Jrd::RecordSource* OPT_compile(Jrd::thread_db* tdbb, Jrd::CompilerScratch* csb, Jrd::RseNode* rse, Jrd::BoolExprNodeStack* parent_stack); void OPT_compile_relation(Jrd::thread_db* tdbb, Jrd::jrd_rel* relation, Jrd::CompilerScratch* csb, diff --git a/src/jrd/relations.h b/src/jrd/relations.h index 2e00e9c4885..2fbfe565962 100644 --- a/src/jrd/relations.h +++ b/src/jrd/relations.h @@ -561,6 +561,7 @@ RELATION(nam_mon_statements, rel_mon_statements, ODS_11_1, rel_virtual) FIELD(f_mon_stmt_expl_plan, nam_mon_expl_plan, fld_source, 0, ODS_11_1) FIELD(f_mon_stmt_timeout, nam_stmt_timeout, fld_stmt_timeout, 0, ODS_13_0) FIELD(f_mon_stmt_timer, nam_stmt_timer, fld_stmt_timer, 0, ODS_13_0) + FIELD(f_mon_stmt_cmp_stmt_id, nam_mon_cmp_stmt_id, fld_stmt_id, 0, ODS_13_1) END_RELATION // Relation 37 (MON$CALL_STACK) @@ -575,6 +576,7 @@ RELATION(nam_mon_calls, rel_mon_calls, ODS_11_1, rel_virtual) FIELD(f_mon_call_src_column, nam_mon_src_column, fld_src_info, 0, ODS_11_1) FIELD(f_mon_call_stat_id, nam_mon_stat_id, fld_stat_id, 0, ODS_11_1) FIELD(f_mon_call_pkg_name, nam_mon_pkg_name, fld_pkg_name, 0, ODS_12_0) + FIELD(f_mon_call_cmp_stmt_id, nam_mon_cmp_stmt_id, fld_stmt_id, 0, ODS_13_1) END_RELATION // Relation 38 (MON$IO_STATS) @@ -741,3 +743,13 @@ RELATION(nam_keywords, rel_keywords, ODS_13_1, rel_virtual) FIELD(f_keyword_name, nam_keyword_name, fld_keyword_name, 0, ODS_13_1) FIELD(f_keyword_reserved, nam_keyword_reserved, fld_keyword_reserved, 0, ODS_13_1) END_RELATION + +// Relation 55 (MON$COMPILED_STATEMENTS) +RELATION(nam_mon_compiled_statements, rel_mon_compiled_statements, ODS_13_1, rel_virtual) + FIELD(f_mon_cmp_stmt_id, nam_mon_cmp_stmt_id, fld_stmt_id, 0, ODS_13_1) + FIELD(f_mon_cmp_stmt_sql_text, nam_mon_sql_text, fld_source, 0, ODS_13_1) + FIELD(f_mon_cmp_stmt_expl_plan, nam_mon_expl_plan, fld_source, 0, ODS_13_1) + FIELD(f_mon_cmp_stmt_name, nam_mon_obj_name, fld_gnr_name, 0, ODS_13_1) + FIELD(f_mon_cmp_stmt_type, nam_mon_obj_type, fld_obj_type, 0, ODS_13_1) + FIELD(f_mon_cmp_stmt_pkg_name, nam_mon_pkg_name, fld_pkg_name, 0, ODS_13_1) +END_RELATION diff --git a/src/jrd/req.h b/src/jrd/req.h index 9e82f4f90b8..f6d68a601c1 100644 --- a/src/jrd/req.h +++ b/src/jrd/req.h @@ -219,10 +219,20 @@ class jrd_req : public pool_alloc CS_METADATA : req_attachment->att_charset; } + bool isRequestIdUnassigned() const + { + return req_id == 0; + } + StmtNumber getRequestId() const { if (!req_id) - req_id = JRD_get_thread_data()->getDatabase()->generateStatementId(); + { + req_id = statement->requests.hasData() && this == statement->requests[0] ? + statement->getStatementId() : + JRD_get_thread_data()->getDatabase()->generateStatementId(); + } + return req_id; } diff --git a/src/jrd/trace/TraceObjects.cpp b/src/jrd/trace/TraceObjects.cpp index 64ac68d7785..39848f31595 100644 --- a/src/jrd/trace/TraceObjects.cpp +++ b/src/jrd/trace/TraceObjects.cpp @@ -212,7 +212,7 @@ void TraceSQLStatementImpl::fillPlan(bool explained) { m_planExplained = explained; if (m_stmt->req_request) - m_plan = OPT_get_plan(JRD_get_thread_data(), m_stmt->req_request, m_planExplained); + m_plan = OPT_get_plan(JRD_get_thread_data(), m_stmt->req_request->getStatement(), m_planExplained); } } From e0e1a6debad64f9ec745e1c47c575cf36b5aae97 Mon Sep 17 00:00:00 2001 From: Adriano dos Santos Fernandes Date: Wed, 8 Dec 2021 10:51:42 -0300 Subject: [PATCH 2/3] Fix #7062 - Creation of expression index does not release its statement correctly. --- src/jrd/dfw.epp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/jrd/dfw.epp b/src/jrd/dfw.epp index 98623524711..5d104fc6061 100644 --- a/src/jrd/dfw.epp +++ b/src/jrd/dfw.epp @@ -2810,6 +2810,10 @@ static bool create_expression_index(thread_db* tdbb, SSHORT phase, DeferredWork* { tdbb->setTransaction(current_transaction); tdbb->setRequest(current_request); + + // Get rid of the expression statement. + idx.idx_expression_statement->release(tdbb); + throw; } @@ -2818,9 +2822,8 @@ static bool create_expression_index(thread_db* tdbb, SSHORT phase, DeferredWork* DFW_update_index(work->dfw_name.c_str(), idx.idx_id, selectivity, transaction); - // Get rid of the pool containing the expression tree - - attachment->deletePool(new_pool); + // Get rid of the expression statement. + idx.idx_expression_statement->release(tdbb); } break; From fee5dc74d588070652f40cc9e7b549140727149f Mon Sep 17 00:00:00 2001 From: Adriano dos Santos Fernandes Date: Sun, 6 Feb 2022 21:38:49 -0300 Subject: [PATCH 3/3] Add jrd_req::isRoot() as suggested by Dmitry. --- src/jrd/exe.cpp | 2 +- src/jrd/req.h | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/jrd/exe.cpp b/src/jrd/exe.cpp index 36fd215fbe0..a8c13b5e812 100644 --- a/src/jrd/exe.cpp +++ b/src/jrd/exe.cpp @@ -883,7 +883,7 @@ void EXE_start(thread_db* tdbb, jrd_req* request, jrd_tra* transaction) // Generate request id. request->setRequestId( - request->isRequestIdUnassigned() && statement->requests.hasData() && request == statement->requests[0] ? + request->isRequestIdUnassigned() && request->isRoot() ? statement->getStatementId() : dbb->generateStatementId()); diff --git a/src/jrd/req.h b/src/jrd/req.h index f6d68a601c1..adc4be924af 100644 --- a/src/jrd/req.h +++ b/src/jrd/req.h @@ -219,6 +219,11 @@ class jrd_req : public pool_alloc CS_METADATA : req_attachment->att_charset; } + bool isRoot() const + { + return statement->requests.hasData() && this == statement->requests[0]; + } + bool isRequestIdUnassigned() const { return req_id == 0; @@ -228,7 +233,7 @@ class jrd_req : public pool_alloc { if (!req_id) { - req_id = statement->requests.hasData() && this == statement->requests[0] ? + req_id = isRoot() ? statement->getStatementId() : JRD_get_thread_data()->getDatabase()->generateStatementId(); }