diff --git a/src/jrd/DatabaseSnapshot.cpp b/src/jrd/DatabaseSnapshot.cpp index e24bcaf4ca..c9b02ab645 100644 --- a/src/jrd/DatabaseSnapshot.cpp +++ b/src/jrd/DatabaseSnapshot.cpp @@ -838,6 +838,24 @@ ClumpletReader* DatabaseSnapshot::dumpData(thread_db* tdbb, bool broadcast) putTransaction(transaction, *writer, dbb->generateId()); } + // Call stack information + + for (transaction = attachment->att_transactions; + transaction; transaction = transaction->tra_next) + { + for (request = transaction->tra_requests; request; + request = request->req_caller) + { + request->adjustCallerStats(); + + if (!(request->req_flags & (req_internal | req_sys_trigger)) && + request->req_caller) + { + putCall(request, *writer, dbb->generateId()); + } + } + } + // Request information for (request = attachment->att_requests; @@ -848,22 +866,6 @@ ClumpletReader* DatabaseSnapshot::dumpData(thread_db* tdbb, bool broadcast) putRequest(request, *writer, dbb->generateId()); } } - - // Call stack information - - for (transaction = attachment->att_transactions; - transaction; transaction = transaction->tra_next) - { - for (request = transaction->tra_requests; - request; request = request->req_tra_next) - { - if (!(request->req_flags & (req_internal | req_sys_trigger)) && - request->req_caller) - { - putCall(request, *writer, dbb->generateId()); - } - } - } } } @@ -1159,8 +1161,7 @@ void DatabaseSnapshot::putCall(const jrd_req* request, writer.insertInt(f_mon_call_caller_id, 0); } else { - writer.insertInt(f_mon_call_caller_id, - request->req_caller->req_id); + writer.insertInt(f_mon_call_caller_id, request->req_caller->req_id); } // object name/type if (request->req_procedure) { diff --git a/src/jrd/RuntimeStatistics.cpp b/src/jrd/RuntimeStatistics.cpp index 53a0623d81..42a4027507 100644 --- a/src/jrd/RuntimeStatistics.cpp +++ b/src/jrd/RuntimeStatistics.cpp @@ -25,6 +25,7 @@ #include "../jrd/RuntimeStatistics.h" using namespace Firebird; + namespace Jrd { RuntimeStatistics RuntimeStatistics::dummy; @@ -34,4 +35,40 @@ void RuntimeStatistics::reset() memset(values, 0, sizeof values); } +bool RuntimeStatistics::operator==(const RuntimeStatistics& other) const +{ + return !memcmp(values, other.values, sizeof(values)); } + +bool RuntimeStatistics::operator!=(const RuntimeStatistics& other) const +{ + return !(*this == other); +} + +RuntimeStatistics& RuntimeStatistics::operator+=(const RuntimeStatistics& other) +{ + for (size_t i = 0; i < TOTAL_ITEMS; ++i) + values[i] += other.values[i]; + + return *this; +} + +RuntimeStatistics& RuntimeStatistics::operator-=(const RuntimeStatistics& other) +{ + for (size_t i = 0; i < TOTAL_ITEMS; ++i) + values[i] -= other.values[i]; + + return *this; +} + +RuntimeStatistics RuntimeStatistics::operator+(const RuntimeStatistics& other) const +{ + return RuntimeStatistics(*this) += other; +} + +RuntimeStatistics RuntimeStatistics::operator-(const RuntimeStatistics& other) const +{ + return RuntimeStatistics(*this) -= other; +} + +} // namespace diff --git a/src/jrd/RuntimeStatistics.h b/src/jrd/RuntimeStatistics.h index ff7bcda75f..9430d4d03e 100644 --- a/src/jrd/RuntimeStatistics.h +++ b/src/jrd/RuntimeStatistics.h @@ -74,17 +74,23 @@ public: ++values[index]; } + bool operator==(const RuntimeStatistics& other) const; + bool operator!=(const RuntimeStatistics& other) const; + + RuntimeStatistics& operator+=(const RuntimeStatistics& other); + RuntimeStatistics& operator-=(const RuntimeStatistics& other); + + RuntimeStatistics operator+(const RuntimeStatistics& other) const; + RuntimeStatistics operator-(const RuntimeStatistics& other) const; + static RuntimeStatistics* getDummy() { return &dummy; } private: - // copying is prohibited - RuntimeStatistics(const RuntimeStatistics&); - RuntimeStatistics& operator= (const RuntimeStatistics&); - SINT64 values[TOTAL_ITEMS]; + // This dummy RuntimeStatistics is used instead of missing elements in tdbb, // helping us avoid conditional checks in time-critical places of code. // Values of it contain actually garbage - don't be surprised when debugging. diff --git a/src/jrd/exe.cpp b/src/jrd/exe.cpp index 0b92b9e493..87841a2566 100644 --- a/src/jrd/exe.cpp +++ b/src/jrd/exe.cpp @@ -681,6 +681,7 @@ jrd_req* EXE_find_request(thread_db* tdbb, jrd_req* request, bool validate) } clone->req_attachment = tdbb->getAttachment(); clone->req_stats.reset(); + clone->req_base_stats.reset(); clone->req_flags |= req_in_use; dbb->dbb_mutexes[DBB_MUTX_clone].leave(); return clone; @@ -2729,11 +2730,15 @@ static jrd_nod* looper(thread_db* tdbb, jrd_req* request, jrd_nod* in_node) BUGCHECK(168); /* msg 168 looper: action not yet implemented */ } + request->adjustCallerStats(); + } // try catch (const Firebird::Exception& ex) { Firebird::stuff_exception(tdbb->tdbb_status_vector, ex); + request->adjustCallerStats(); + // Skip this handling for errors coming from the nested looper calls, // as they're already handled properly. The only need is to undo // our own savepoints. diff --git a/src/jrd/req.h b/src/jrd/req.h index 219044705b..edf8a5a93d 100644 --- a/src/jrd/req.h +++ b/src/jrd/req.h @@ -232,6 +232,7 @@ public: ULONG req_records_updated; /* count of records updated by request */ ULONG req_records_deleted; /* count of records deleted by request */ RuntimeStatistics req_stats; + RuntimeStatistics req_base_stats; AffectedRows req_records_affected; /* records affected by the last statement */ USHORT req_view_flags; /* special flags for virtual ops on views */ @@ -282,6 +283,15 @@ public: StatusXcp req_last_xcp; /* last known exception */ record_param req_rpb[1]; /* record parameter blocks */ + + void adjustCallerStats() + { + if (req_caller) + { + req_caller->req_stats += req_stats - req_base_stats; + } + req_base_stats = req_stats; + } }; // Size of request without rpb items at the tail. Used to calculate impure area size