8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-02-02 10:00:38 +01:00

Do not pass user's transaction to plugin.

Use autonomous transaction in flush.
This commit is contained in:
Adriano dos Santos Fernandes 2022-06-03 21:52:15 -03:00
parent bb139df3c7
commit 3fe37a6a60
7 changed files with 148 additions and 196 deletions

View File

@ -22,7 +22,7 @@ A session may be paused to temporary disable statistics collecting. It may be re
A new session may be started when a session is already active. In this case it has the same semantics of finishing the current session with `RDB$PROFILER.FINISH_SESSION(FALSE)` so snapshots tables are not updated in the same moment. A new session may be started when a session is already active. In this case it has the same semantics of finishing the current session with `RDB$PROFILER.FINISH_SESSION(FALSE)` so snapshots tables are not updated in the same moment.
To analyze the collected data, the user must flush the data to the snapshot tables, which may be done finishing or pausing a session (with `FLUSH` parameter set to `TRUE`) or calling `RDB$PROFILER.FLUSH`. To analyze the collected data, the user must flush the data to the snapshot tables, which may be done finishing or pausing a session (with `FLUSH` parameter set to `TRUE`) or calling `RDB$PROFILER.FLUSH`. Data is flushed using an autonomous transaction (a transaction started and finished for the specific purpose of profiler data update).
Following is a sample profile session and queries for data analysis. Following is a sample profile session and queries for data analysis.
@ -89,6 +89,8 @@ execute procedure rdb$profiler.finish_session(true);
-- Data analysis -- Data analysis
commit; -- start new transaction
select * from plg$prof_sessions; select * from plg$prof_sessions;
select * from plg$prof_psql_stats_view; select * from plg$prof_psql_stats_view;
@ -195,9 +197,9 @@ Input parameters:
After update data is stored in tables `PLG$PROF_SESSIONS`, `PLG$PROF_STATEMENTS`, `PLG$PROF_RECORD_SOURCES`, `PLG$PROF_REQUESTS`, `PLG$PROF_PSQL_STATS` and `PLG$PROF_RECORD_SOURCE_STATS` and may be read and analyzed by the user. After update data is stored in tables `PLG$PROF_SESSIONS`, `PLG$PROF_STATEMENTS`, `PLG$PROF_RECORD_SOURCES`, `PLG$PROF_REQUESTS`, `PLG$PROF_PSQL_STATS` and `PLG$PROF_RECORD_SOURCE_STATS` and may be read and analyzed by the user.
It also removes finished sessions from memory. Data is updated using an autonomous transaction, so if the procedure is called in a snapshot transaction, data will not be directly readable in the same transaction.
If a remote `ATTACHMENT_ID` is used the data is updated in an autonomous transaction. Once flush happens, finished sessions are removed from memory.
Input parameters: Input parameters:
- `ATTACHMENT_ID` type `BIGINT NOT NULL` default `CURRENT_CONNECTION` - `ATTACHMENT_ID` type `BIGINT NOT NULL` default `CURRENT_CONNECTION`

View File

@ -1700,15 +1700,12 @@ interface ReplicatedSession : PluginBase
interface ProfilerPlugin : PluginBase interface ProfilerPlugin : PluginBase
{ {
// The transaction should not be stored for later usage after the method returns. void init(Status status, Attachment attachment);
void init(Status status, Attachment attachment, Transaction transaction);
// The transaction should not be stored for later usage after the method returns. ProfilerSession startSession(Status status, const string description,
ProfilerSession startSession(Status status, Transaction transaction, const string description,
const string options, ISC_TIMESTAMP_TZ timestamp); const string options, ISC_TIMESTAMP_TZ timestamp);
// The transaction should not be stored for later usage after the method returns. void flush(Status status);
void flush(Status status, Transaction transaction);
} }
interface ProfilerSession : Disposable interface ProfilerSession : Disposable

View File

@ -6648,9 +6648,9 @@ namespace Firebird
public: public:
struct VTable : public IPluginBase::VTable struct VTable : public IPluginBase::VTable
{ {
void (CLOOP_CARG *init)(IProfilerPlugin* self, IStatus* status, IAttachment* attachment, ITransaction* transaction) throw(); void (CLOOP_CARG *init)(IProfilerPlugin* self, IStatus* status, IAttachment* attachment) throw();
IProfilerSession* (CLOOP_CARG *startSession)(IProfilerPlugin* self, IStatus* status, ITransaction* transaction, const char* description, const char* options, ISC_TIMESTAMP_TZ timestamp) throw(); IProfilerSession* (CLOOP_CARG *startSession)(IProfilerPlugin* self, IStatus* status, const char* description, const char* options, ISC_TIMESTAMP_TZ timestamp) throw();
void (CLOOP_CARG *flush)(IProfilerPlugin* self, IStatus* status, ITransaction* transaction) throw(); void (CLOOP_CARG *flush)(IProfilerPlugin* self, IStatus* status) throw();
}; };
protected: protected:
@ -6666,25 +6666,25 @@ namespace Firebird
public: public:
static const unsigned VERSION = 4; static const unsigned VERSION = 4;
template <typename StatusType> void init(StatusType* status, IAttachment* attachment, ITransaction* transaction) template <typename StatusType> void init(StatusType* status, IAttachment* attachment)
{ {
StatusType::clearException(status); StatusType::clearException(status);
static_cast<VTable*>(this->cloopVTable)->init(this, status, attachment, transaction); static_cast<VTable*>(this->cloopVTable)->init(this, status, attachment);
StatusType::checkException(status); StatusType::checkException(status);
} }
template <typename StatusType> IProfilerSession* startSession(StatusType* status, ITransaction* transaction, const char* description, const char* options, ISC_TIMESTAMP_TZ timestamp) template <typename StatusType> IProfilerSession* startSession(StatusType* status, const char* description, const char* options, ISC_TIMESTAMP_TZ timestamp)
{ {
StatusType::clearException(status); StatusType::clearException(status);
IProfilerSession* ret = static_cast<VTable*>(this->cloopVTable)->startSession(this, status, transaction, description, options, timestamp); IProfilerSession* ret = static_cast<VTable*>(this->cloopVTable)->startSession(this, status, description, options, timestamp);
StatusType::checkException(status); StatusType::checkException(status);
return ret; return ret;
} }
template <typename StatusType> void flush(StatusType* status, ITransaction* transaction) template <typename StatusType> void flush(StatusType* status)
{ {
StatusType::clearException(status); StatusType::clearException(status);
static_cast<VTable*>(this->cloopVTable)->flush(this, status, transaction); static_cast<VTable*>(this->cloopVTable)->flush(this, status);
StatusType::checkException(status); StatusType::checkException(status);
} }
}; };
@ -19964,13 +19964,13 @@ namespace Firebird
this->cloopVTable = &vTable; this->cloopVTable = &vTable;
} }
static void CLOOP_CARG cloopinitDispatcher(IProfilerPlugin* self, IStatus* status, IAttachment* attachment, ITransaction* transaction) throw() static void CLOOP_CARG cloopinitDispatcher(IProfilerPlugin* self, IStatus* status, IAttachment* attachment) throw()
{ {
StatusType status2(status); StatusType status2(status);
try try
{ {
static_cast<Name*>(self)->Name::init(&status2, attachment, transaction); static_cast<Name*>(self)->Name::init(&status2, attachment);
} }
catch (...) catch (...)
{ {
@ -19978,13 +19978,13 @@ namespace Firebird
} }
} }
static IProfilerSession* CLOOP_CARG cloopstartSessionDispatcher(IProfilerPlugin* self, IStatus* status, ITransaction* transaction, const char* description, const char* options, ISC_TIMESTAMP_TZ timestamp) throw() static IProfilerSession* CLOOP_CARG cloopstartSessionDispatcher(IProfilerPlugin* self, IStatus* status, const char* description, const char* options, ISC_TIMESTAMP_TZ timestamp) throw()
{ {
StatusType status2(status); StatusType status2(status);
try try
{ {
return static_cast<Name*>(self)->Name::startSession(&status2, transaction, description, options, timestamp); return static_cast<Name*>(self)->Name::startSession(&status2, description, options, timestamp);
} }
catch (...) catch (...)
{ {
@ -19993,13 +19993,13 @@ namespace Firebird
} }
} }
static void CLOOP_CARG cloopflushDispatcher(IProfilerPlugin* self, IStatus* status, ITransaction* transaction) throw() static void CLOOP_CARG cloopflushDispatcher(IProfilerPlugin* self, IStatus* status) throw()
{ {
StatusType status2(status); StatusType status2(status);
try try
{ {
static_cast<Name*>(self)->Name::flush(&status2, transaction); static_cast<Name*>(self)->Name::flush(&status2);
} }
catch (...) catch (...)
{ {
@ -20071,9 +20071,9 @@ namespace Firebird
{ {
} }
virtual void init(StatusType* status, IAttachment* attachment, ITransaction* transaction) = 0; virtual void init(StatusType* status, IAttachment* attachment) = 0;
virtual IProfilerSession* startSession(StatusType* status, ITransaction* transaction, const char* description, const char* options, ISC_TIMESTAMP_TZ timestamp) = 0; virtual IProfilerSession* startSession(StatusType* status, const char* description, const char* options, ISC_TIMESTAMP_TZ timestamp) = 0;
virtual void flush(StatusType* status, ITransaction* transaction) = 0; virtual void flush(StatusType* status) = 0;
}; };
template <typename Name, typename StatusType, typename Base> template <typename Name, typename StatusType, typename Base>

View File

@ -714,9 +714,9 @@ type
IReplicatedSession_startTransactionPtr = function(this: IReplicatedSession; status: IStatus; transaction: ITransaction; number: Int64): IReplicatedTransaction; cdecl; IReplicatedSession_startTransactionPtr = function(this: IReplicatedSession; status: IStatus; transaction: ITransaction; number: Int64): IReplicatedTransaction; cdecl;
IReplicatedSession_cleanupTransactionPtr = procedure(this: IReplicatedSession; status: IStatus; number: Int64); cdecl; IReplicatedSession_cleanupTransactionPtr = procedure(this: IReplicatedSession; status: IStatus; number: Int64); cdecl;
IReplicatedSession_setSequencePtr = procedure(this: IReplicatedSession; status: IStatus; name: PAnsiChar; value: Int64); cdecl; IReplicatedSession_setSequencePtr = procedure(this: IReplicatedSession; status: IStatus; name: PAnsiChar; value: Int64); cdecl;
IProfilerPlugin_initPtr = procedure(this: IProfilerPlugin; status: IStatus; attachment: IAttachment; transaction: ITransaction); cdecl; IProfilerPlugin_initPtr = procedure(this: IProfilerPlugin; status: IStatus; attachment: IAttachment); cdecl;
IProfilerPlugin_startSessionPtr = function(this: IProfilerPlugin; status: IStatus; transaction: ITransaction; description: PAnsiChar; options: PAnsiChar; timestamp: ISC_TIMESTAMP_TZ): IProfilerSession; cdecl; IProfilerPlugin_startSessionPtr = function(this: IProfilerPlugin; status: IStatus; description: PAnsiChar; options: PAnsiChar; timestamp: ISC_TIMESTAMP_TZ): IProfilerSession; cdecl;
IProfilerPlugin_flushPtr = procedure(this: IProfilerPlugin; status: IStatus; transaction: ITransaction); cdecl; IProfilerPlugin_flushPtr = procedure(this: IProfilerPlugin; status: IStatus); cdecl;
IProfilerSession_getIdPtr = function(this: IProfilerSession): Int64; cdecl; IProfilerSession_getIdPtr = function(this: IProfilerSession): Int64; cdecl;
IProfilerSession_getFlagsPtr = function(this: IProfilerSession): Cardinal; cdecl; IProfilerSession_getFlagsPtr = function(this: IProfilerSession): Cardinal; cdecl;
IProfilerSession_cancelPtr = procedure(this: IProfilerSession; status: IStatus); cdecl; IProfilerSession_cancelPtr = procedure(this: IProfilerSession; status: IStatus); cdecl;
@ -3775,9 +3775,9 @@ type
IProfilerPlugin = class(IPluginBase) IProfilerPlugin = class(IPluginBase)
const VERSION = 4; const VERSION = 4;
procedure init(status: IStatus; attachment: IAttachment; transaction: ITransaction); procedure init(status: IStatus; attachment: IAttachment);
function startSession(status: IStatus; transaction: ITransaction; description: PAnsiChar; options: PAnsiChar; timestamp: ISC_TIMESTAMP_TZ): IProfilerSession; function startSession(status: IStatus; description: PAnsiChar; options: PAnsiChar; timestamp: ISC_TIMESTAMP_TZ): IProfilerSession;
procedure flush(status: IStatus; transaction: ITransaction); procedure flush(status: IStatus);
end; end;
IProfilerPluginImpl = class(IProfilerPlugin) IProfilerPluginImpl = class(IProfilerPlugin)
@ -3787,9 +3787,9 @@ type
function release(): Integer; virtual; abstract; function release(): Integer; virtual; abstract;
procedure setOwner(r: IReferenceCounted); virtual; abstract; procedure setOwner(r: IReferenceCounted); virtual; abstract;
function getOwner(): IReferenceCounted; virtual; abstract; function getOwner(): IReferenceCounted; virtual; abstract;
procedure init(status: IStatus; attachment: IAttachment; transaction: ITransaction); virtual; abstract; procedure init(status: IStatus; attachment: IAttachment); virtual; abstract;
function startSession(status: IStatus; transaction: ITransaction; description: PAnsiChar; options: PAnsiChar; timestamp: ISC_TIMESTAMP_TZ): IProfilerSession; virtual; abstract; function startSession(status: IStatus; description: PAnsiChar; options: PAnsiChar; timestamp: ISC_TIMESTAMP_TZ): IProfilerSession; virtual; abstract;
procedure flush(status: IStatus; transaction: ITransaction); virtual; abstract; procedure flush(status: IStatus); virtual; abstract;
end; end;
ProfilerSessionVTable = class(DisposableVTable) ProfilerSessionVTable = class(DisposableVTable)
@ -8945,21 +8945,21 @@ begin
FbException.checkException(status); FbException.checkException(status);
end; end;
procedure IProfilerPlugin.init(status: IStatus; attachment: IAttachment; transaction: ITransaction); procedure IProfilerPlugin.init(status: IStatus; attachment: IAttachment);
begin begin
ProfilerPluginVTable(vTable).init(Self, status, attachment, transaction); ProfilerPluginVTable(vTable).init(Self, status, attachment);
FbException.checkException(status); FbException.checkException(status);
end; end;
function IProfilerPlugin.startSession(status: IStatus; transaction: ITransaction; description: PAnsiChar; options: PAnsiChar; timestamp: ISC_TIMESTAMP_TZ): IProfilerSession; function IProfilerPlugin.startSession(status: IStatus; description: PAnsiChar; options: PAnsiChar; timestamp: ISC_TIMESTAMP_TZ): IProfilerSession;
begin begin
Result := ProfilerPluginVTable(vTable).startSession(Self, status, transaction, description, options, timestamp); Result := ProfilerPluginVTable(vTable).startSession(Self, status, description, options, timestamp);
FbException.checkException(status); FbException.checkException(status);
end; end;
procedure IProfilerPlugin.flush(status: IStatus; transaction: ITransaction); procedure IProfilerPlugin.flush(status: IStatus);
begin begin
ProfilerPluginVTable(vTable).flush(Self, status, transaction); ProfilerPluginVTable(vTable).flush(Self, status);
FbException.checkException(status); FbException.checkException(status);
end; end;
@ -15576,28 +15576,28 @@ begin
end end
end; end;
procedure IProfilerPluginImpl_initDispatcher(this: IProfilerPlugin; status: IStatus; attachment: IAttachment; transaction: ITransaction); cdecl; procedure IProfilerPluginImpl_initDispatcher(this: IProfilerPlugin; status: IStatus; attachment: IAttachment); cdecl;
begin begin
try try
IProfilerPluginImpl(this).init(status, attachment, transaction); IProfilerPluginImpl(this).init(status, attachment);
except except
on e: Exception do FbException.catchException(status, e); on e: Exception do FbException.catchException(status, e);
end end
end; end;
function IProfilerPluginImpl_startSessionDispatcher(this: IProfilerPlugin; status: IStatus; transaction: ITransaction; description: PAnsiChar; options: PAnsiChar; timestamp: ISC_TIMESTAMP_TZ): IProfilerSession; cdecl; function IProfilerPluginImpl_startSessionDispatcher(this: IProfilerPlugin; status: IStatus; description: PAnsiChar; options: PAnsiChar; timestamp: ISC_TIMESTAMP_TZ): IProfilerSession; cdecl;
begin begin
try try
Result := IProfilerPluginImpl(this).startSession(status, transaction, description, options, timestamp); Result := IProfilerPluginImpl(this).startSession(status, description, options, timestamp);
except except
on e: Exception do FbException.catchException(status, e); on e: Exception do FbException.catchException(status, e);
end end
end; end;
procedure IProfilerPluginImpl_flushDispatcher(this: IProfilerPlugin; status: IStatus; transaction: ITransaction); cdecl; procedure IProfilerPluginImpl_flushDispatcher(this: IProfilerPlugin; status: IStatus); cdecl;
begin begin
try try
IProfilerPluginImpl(this).flush(status, transaction); IProfilerPluginImpl(this).flush(status);
except except
on e: Exception do FbException.catchException(status, e); on e: Exception do FbException.catchException(status, e);
end end

View File

@ -192,10 +192,9 @@ IExternalResultSet* ProfilerPackage::flushProcedure(ThrowStatusExceptionWrapper*
return nullptr; return nullptr;
} }
const auto transaction = tdbb->getTransaction();
const auto profilerManager = attachment->getProfilerManager(tdbb); const auto profilerManager = attachment->getProfilerManager(tdbb);
profilerManager->flush(transaction->getInterface(true)); profilerManager->flush();
return nullptr; return nullptr;
} }
@ -234,13 +233,9 @@ IExternalResultSet* ProfilerPackage::finishSessionProcedure(ThrowStatusException
return nullptr; return nullptr;
} }
const auto transaction = tdbb->getTransaction();
const auto profilerManager = attachment->getProfilerManager(tdbb); const auto profilerManager = attachment->getProfilerManager(tdbb);
profilerManager->finishSession(tdbb); profilerManager->finishSession(tdbb, in->flush);
if (in->flush)
profilerManager->flush(transaction->getInterface(true));
return nullptr; return nullptr;
} }
@ -258,14 +253,9 @@ IExternalResultSet* ProfilerPackage::pauseSessionProcedure(ThrowStatusExceptionW
return nullptr; return nullptr;
} }
const auto transaction = tdbb->getTransaction();
const auto profilerManager = attachment->getProfilerManager(tdbb); const auto profilerManager = attachment->getProfilerManager(tdbb);
if (profilerManager->pauseSession()) profilerManager->pauseSession(in->flush);
{
if (in->flush)
profilerManager->flush(transaction->getInterface(true));
}
return nullptr; return nullptr;
} }
@ -359,7 +349,6 @@ SINT64 ProfilerManager::startSession(thread_db* tdbb, AttNumber attachmentId, co
AutoSetRestore<bool> pauseProfiler(&paused, true); AutoSetRestore<bool> pauseProfiler(&paused, true);
const auto attachment = tdbb->getAttachment(); const auto attachment = tdbb->getAttachment();
const auto transaction = tdbb->getTransaction();
ThrowLocalStatus status; ThrowLocalStatus status;
const auto timestamp = TimeZoneUtil::getCurrentTimeStamp(attachment->att_current_timezone); const auto timestamp = TimeZoneUtil::getCurrentTimeStamp(attachment->att_current_timezone);
@ -393,14 +382,13 @@ SINT64 ProfilerManager::startSession(thread_db* tdbb, AttNumber attachmentId, co
plugin.reset(plugins.plugin()); plugin.reset(plugins.plugin());
plugin->addRef(); plugin->addRef();
plugin->init(&status, attachment->getInterface(), transaction->getInterface(true)); plugin->init(&status, attachment->getInterface());
plugin->addRef(); plugin->addRef();
activePlugins.put(pluginName)->reset(plugin.get()); activePlugins.put(pluginName)->reset(plugin.get());
} }
AutoDispose<IProfilerSession> pluginSession = plugin->startSession(&status, AutoDispose<IProfilerSession> pluginSession = plugin->startSession(&status,
transaction->getInterface(true),
description.c_str(), description.c_str(),
options.c_str(), options.c_str(),
timestamp); timestamp);
@ -566,7 +554,7 @@ void ProfilerManager::cancelSession()
} }
} }
void ProfilerManager::finishSession(thread_db* tdbb) void ProfilerManager::finishSession(thread_db* tdbb, bool flushData)
{ {
if (currentSession) if (currentSession)
{ {
@ -577,15 +565,18 @@ void ProfilerManager::finishSession(thread_db* tdbb)
currentSession->pluginSession->finish(&status, timestamp); currentSession->pluginSession->finish(&status, timestamp);
currentSession = nullptr; currentSession = nullptr;
} }
if (flushData)
flush();
} }
bool ProfilerManager::pauseSession() void ProfilerManager::pauseSession(bool flushData)
{ {
if (!currentSession) if (currentSession)
return false; paused = true;
paused = true; if (flushData)
return true; flush();
} }
void ProfilerManager::resumeSession() void ProfilerManager::resumeSession()
@ -600,7 +591,7 @@ void ProfilerManager::discard()
activePlugins.clear(); activePlugins.clear();
} }
void ProfilerManager::flush(ITransaction* transaction) void ProfilerManager::flush()
{ {
AutoSetRestore<bool> pauseProfiler(&paused, true); AutoSetRestore<bool> pauseProfiler(&paused, true);
@ -612,7 +603,7 @@ void ProfilerManager::flush(ITransaction* transaction)
auto& plugin = pluginAccessor.current()->second; auto& plugin = pluginAccessor.current()->second;
LogLocalStatus status("Profiler flush"); LogLocalStatus status("Profiler flush");
plugin->flush(&status, transaction); plugin->flush(&status);
hasNext = pluginAccessor.getNext(); hasNext = pluginAccessor.getNext();
@ -937,122 +928,74 @@ void ProfilerListener::processCommand(thread_db* tdbb)
const auto header = ipc->sharedMemory->getHeader(); const auto header = ipc->sharedMemory->getHeader();
const auto profilerManager = attachment->getProfilerManager(tdbb); const auto profilerManager = attachment->getProfilerManager(tdbb);
jrd_tra* transaction = nullptr; using Tag = ProfilerIpc::Tag;
try
switch (header->tag)
{ {
const auto startTransaction = [&]() { case Tag::CANCEL_SESSION:
transaction = TRA_start(tdbb, 0, 0); profilerManager->cancelSession();
tdbb->setTransaction(transaction); header->bufferSize = 0;
}; break;
using Tag = ProfilerIpc::Tag; case Tag::DISCARD:
profilerManager->discard();
header->bufferSize = 0;
break;
switch (header->tag) case Tag::FINISH_SESSION:
{ {
case Tag::CANCEL_SESSION: const auto in = reinterpret_cast<const ProfilerPackage::FinishSessionInput::Type*>(header->buffer);
profilerManager->cancelSession(); fb_assert(sizeof(*in) == header->bufferSize);
header->bufferSize = 0; profilerManager->finishSession(tdbb, in->flush);
break; header->bufferSize = 0;
break;
case Tag::DISCARD:
profilerManager->discard();
header->bufferSize = 0;
break;
case Tag::FINISH_SESSION:
{
const auto in = reinterpret_cast<const ProfilerPackage::FinishSessionInput::Type*>(header->buffer);
fb_assert(sizeof(*in) == header->bufferSize);
profilerManager->finishSession(tdbb);
if (in->flush)
{
startTransaction();
profilerManager->flush(transaction->getInterface(true));
}
header->bufferSize = 0;
break;
}
case Tag::FLUSH:
startTransaction();
profilerManager->flush(transaction->getInterface(true));
header->bufferSize = 0;
break;
case Tag::PAUSE_SESSION:
if (profilerManager->currentSession)
{
const auto in = reinterpret_cast<const ProfilerPackage::PauseSessionInput::Type*>(header->buffer);
fb_assert(sizeof(*in) == header->bufferSize);
if (profilerManager->pauseSession())
{
if (in->flush)
{
startTransaction();
profilerManager->flush(transaction->getInterface(true));
}
}
}
header->bufferSize = 0;
break;
case Tag::RESUME_SESSION:
profilerManager->resumeSession();
header->bufferSize = 0;
break;
case Tag::START_SESSION:
{
startTransaction();
const auto in = reinterpret_cast<const ProfilerPackage::StartSessionInput::Type*>(header->buffer);
fb_assert(sizeof(*in) == header->bufferSize);
const string description(in->description.str,
in->descriptionNull ? 0 : in->description.length);
const PathName pluginName(in->pluginName.str,
in->pluginNameNull ? 0 : in->pluginName.length);
const string pluginOptions(in->pluginOptions.str,
in->pluginOptionsNull ? 0 : in->pluginOptions.length);
const auto out = reinterpret_cast<ProfilerPackage::StartSessionOutput::Type*>(header->buffer);
header->bufferSize = sizeof(*out);
out->sessionIdNull = FB_FALSE;
out->sessionId = profilerManager->startSession(tdbb,
in->attachmentId, pluginName, description, pluginOptions);
break;
}
default:
fb_assert(false);
(Arg::Gds(isc_random) << "Invalid profiler's remote command").raise();
break;
} }
if (transaction) case Tag::FLUSH:
profilerManager->flush();
header->bufferSize = 0;
break;
case Tag::PAUSE_SESSION:
{ {
TRA_commit(tdbb, transaction, false); const auto in = reinterpret_cast<const ProfilerPackage::PauseSessionInput::Type*>(header->buffer);
tdbb->setTransaction(nullptr); fb_assert(sizeof(*in) == header->bufferSize);
transaction = nullptr; profilerManager->pauseSession(in->flush);
} header->bufferSize = 0;
} break;
catch (...)
{
if (transaction)
{
TRA_rollback(tdbb, transaction, false, true);
tdbb->setTransaction(nullptr);
transaction = nullptr;
} }
throw; case Tag::RESUME_SESSION:
profilerManager->resumeSession();
header->bufferSize = 0;
break;
case Tag::START_SESSION:
{
const auto in = reinterpret_cast<const ProfilerPackage::StartSessionInput::Type*>(header->buffer);
fb_assert(sizeof(*in) == header->bufferSize);
const string description(in->description.str,
in->descriptionNull ? 0 : in->description.length);
const PathName pluginName(in->pluginName.str,
in->pluginNameNull ? 0 : in->pluginName.length);
const string pluginOptions(in->pluginOptions.str,
in->pluginOptionsNull ? 0 : in->pluginOptions.length);
const auto out = reinterpret_cast<ProfilerPackage::StartSessionOutput::Type*>(header->buffer);
header->bufferSize = sizeof(*out);
out->sessionIdNull = FB_FALSE;
out->sessionId = profilerManager->startSession(tdbb,
in->attachmentId, pluginName, description, pluginOptions);
break;
}
default:
fb_assert(false);
(Arg::Gds(isc_random) << "Invalid profiler's remote command").raise();
break;
} }
} }

View File

@ -116,11 +116,11 @@ public:
private: private:
void cancelSession(); void cancelSession();
void finishSession(thread_db* tdbb); void finishSession(thread_db* tdbb, bool flushData);
bool pauseSession(); void pauseSession(bool flushData);
void resumeSession(); void resumeSession();
void discard(); void discard();
void flush(Firebird::ITransaction* transaction); void flush();
Statement* getStatement(jrd_req* request); Statement* getStatement(jrd_req* request);
SINT64 getRequest(jrd_req* request, unsigned flags); SINT64 getRequest(jrd_req* request, unsigned flags);

View File

@ -130,7 +130,7 @@ class Session final :
public RefCounted public RefCounted
{ {
public: public:
Session(ThrowStatusExceptionWrapper* status, ProfilerPlugin* aPlugin, ITransaction* transaction, Session(ThrowStatusExceptionWrapper* status, ProfilerPlugin* aPlugin,
const char* aDescription, ISC_TIMESTAMP_TZ aStartTimestamp); const char* aDescription, ISC_TIMESTAMP_TZ aStartTimestamp);
public: public:
@ -204,12 +204,12 @@ public:
{ {
} }
void init(ThrowStatusExceptionWrapper* status, IAttachment* attachment, ITransaction* transaction) override; void init(ThrowStatusExceptionWrapper* status, IAttachment* attachment) override;
IProfilerSession* startSession(ThrowStatusExceptionWrapper* status, ITransaction* transaction, IProfilerSession* startSession(ThrowStatusExceptionWrapper* status,
const char* description, const char* options, ISC_TIMESTAMP_TZ timestamp) override; const char* description, const char* options, ISC_TIMESTAMP_TZ timestamp) override;
void flush(ThrowStatusExceptionWrapper* status, ITransaction* transaction) override; void flush(ThrowStatusExceptionWrapper* status) override;
private: private:
void createMetadata(ThrowStatusExceptionWrapper* status, RefPtr<IAttachment> attachment, void createMetadata(ThrowStatusExceptionWrapper* status, RefPtr<IAttachment> attachment,
@ -224,7 +224,7 @@ public:
//-------------------------------------- //--------------------------------------
void ProfilerPlugin::init(ThrowStatusExceptionWrapper* status, IAttachment* attachment, ITransaction* transaction) void ProfilerPlugin::init(ThrowStatusExceptionWrapper* status, IAttachment* attachment)
{ {
userAttachment = attachment; userAttachment = attachment;
@ -254,12 +254,14 @@ void ProfilerPlugin::init(ThrowStatusExceptionWrapper* status, IAttachment* atta
message.clear(); message.clear();
RefPtr<IAttachment> refAttachment(attachment); RefPtr<IAttachment> refAttachment(attachment);
RefPtr<ITransaction> refTransaction(transaction); RefPtr<ITransaction> refTransaction;
string currentRole; string currentRole;
bool roleInUse; bool roleInUse;
for (unsigned i = 0; i < 2; ++i) for (unsigned i = 0; i < 2; ++i)
{ {
refTransaction = makeNoIncRef(refAttachment->startTransaction(status, 0, nullptr));
auto resultSet = makeNoIncRef(refAttachment->openCursor(status, refTransaction, 0, sql, SQL_DIALECT_CURRENT, auto resultSet = makeNoIncRef(refAttachment->openCursor(status, refTransaction, 0, sql, SQL_DIALECT_CURRENT,
nullptr, nullptr, message.getMetadata(), nullptr, 0)); nullptr, nullptr, message.getMetadata(), nullptr, 0));
@ -294,8 +296,6 @@ void ProfilerPlugin::init(ThrowStatusExceptionWrapper* status, IAttachment* atta
refAttachment = makeNoIncRef(dispatcher->attachDatabase(status, dbName.c_str(), refAttachment = makeNoIncRef(dispatcher->attachDatabase(status, dbName.c_str(),
dpb->getBufferLength(status), dpb->getBuffer(status))); dpb->getBufferLength(status), dpb->getBuffer(status)));
refTransaction = makeNoIncRef(refAttachment->startTransaction(status, 0, nullptr));
} }
} }
@ -306,17 +306,17 @@ void ProfilerPlugin::init(ThrowStatusExceptionWrapper* status, IAttachment* atta
{ {
// Refresh roles. // Refresh roles.
attachment->execute(status, transaction, 0, "set role plg$profiler", attachment->execute(status, nullptr, 0, "set role plg$profiler",
SQL_DIALECT_CURRENT, nullptr, nullptr, nullptr, nullptr); SQL_DIALECT_CURRENT, nullptr, nullptr, nullptr, nullptr);
attachment->execute(status, transaction, 0, ("set role " + currentRole).c_str(), attachment->execute(status, nullptr, 0, ("set role " + currentRole).c_str(),
SQL_DIALECT_CURRENT, nullptr, nullptr, nullptr, nullptr); SQL_DIALECT_CURRENT, nullptr, nullptr, nullptr, nullptr);
} }
loadMetadata(status); loadMetadata(status);
} }
IProfilerSession* ProfilerPlugin::startSession(ThrowStatusExceptionWrapper* status, ITransaction* transaction, IProfilerSession* ProfilerPlugin::startSession(ThrowStatusExceptionWrapper* status,
const char* description, const char* options, ISC_TIMESTAMP_TZ timestamp) const char* description, const char* options, ISC_TIMESTAMP_TZ timestamp)
{ {
if (options && options[0]) if (options && options[0])
@ -333,10 +333,10 @@ IProfilerSession* ProfilerPlugin::startSession(ThrowStatusExceptionWrapper* stat
return nullptr; return nullptr;
} }
return FB_NEW Session(status, this, transaction, description, timestamp); return FB_NEW Session(status, this, description, timestamp);
} }
void ProfilerPlugin::flush(ThrowStatusExceptionWrapper* status, ITransaction* transaction) void ProfilerPlugin::flush(ThrowStatusExceptionWrapper* status)
{ {
constexpr auto sessionSql = R"""( constexpr auto sessionSql = R"""(
update or insert into plg$prof_sessions update or insert into plg$prof_sessions
@ -514,6 +514,8 @@ void ProfilerPlugin::flush(ThrowStatusExceptionWrapper* status, ITransaction* tr
) psqlStatsMessage(status, MasterInterfacePtr()); ) psqlStatsMessage(status, MasterInterfacePtr());
psqlStatsMessage.clear(); psqlStatsMessage.clear();
auto transaction = makeNoIncRef(userAttachment->startTransaction(status, 0, nullptr));
auto sessionStmt = makeNoIncRef(userAttachment->prepare(status, transaction, 0, sessionSql, SQL_DIALECT_CURRENT, 0)); auto sessionStmt = makeNoIncRef(userAttachment->prepare(status, transaction, 0, sessionSql, SQL_DIALECT_CURRENT, 0));
auto statementStmt = makeNoIncRef(userAttachment->prepare( auto statementStmt = makeNoIncRef(userAttachment->prepare(
status, transaction, 0, statementSql, SQL_DIALECT_CURRENT, 0)); status, transaction, 0, statementSql, SQL_DIALECT_CURRENT, 0));
@ -840,6 +842,9 @@ void ProfilerPlugin::flush(ThrowStatusExceptionWrapper* status, ITransaction* tr
} }
executeBatches(); executeBatches();
transaction->commit(status);
transaction.clear();
} }
void ProfilerPlugin::createMetadata(ThrowStatusExceptionWrapper* status, RefPtr<IAttachment> attachment, void ProfilerPlugin::createMetadata(ThrowStatusExceptionWrapper* status, RefPtr<IAttachment> attachment,
@ -1157,7 +1162,7 @@ void ProfilerPlugin::loadMetadata(ThrowStatusExceptionWrapper* status)
//-------------------------------------- //--------------------------------------
Session::Session(ThrowStatusExceptionWrapper* status, ProfilerPlugin* aPlugin, ITransaction* transaction, Session::Session(ThrowStatusExceptionWrapper* status, ProfilerPlugin* aPlugin,
const char* aDescription, ISC_TIMESTAMP_TZ aStartTimestamp) const char* aDescription, ISC_TIMESTAMP_TZ aStartTimestamp)
: plugin(aPlugin), : plugin(aPlugin),
startTimestamp(aStartTimestamp), startTimestamp(aStartTimestamp),
@ -1170,6 +1175,8 @@ Session::Session(ThrowStatusExceptionWrapper* status, ProfilerPlugin* aPlugin, I
constexpr auto sequenceSql = "select next value for plg$prof_profile_id from rdb$database"; constexpr auto sequenceSql = "select next value for plg$prof_profile_id from rdb$database";
auto transaction = makeNoIncRef(plugin->userAttachment->startTransaction(status, 0, nullptr));
auto resultSet = makeNoIncRef(plugin->userAttachment->openCursor(status, transaction, 0, sequenceSql, auto resultSet = makeNoIncRef(plugin->userAttachment->openCursor(status, transaction, 0, sequenceSql,
SQL_DIALECT_CURRENT, SQL_DIALECT_CURRENT,
nullptr, nullptr, sequenceMessage.getMetadata(), nullptr, 0)); nullptr, nullptr, sequenceMessage.getMetadata(), nullptr, 0));
@ -1177,6 +1184,9 @@ Session::Session(ThrowStatusExceptionWrapper* status, ProfilerPlugin* aPlugin, I
resultSet->fetchNext(status, sequenceMessage.getData()); resultSet->fetchNext(status, sequenceMessage.getData());
id = sequenceMessage->value; id = sequenceMessage->value;
transaction->commit(status);
transaction.clear();
plugin->sessions.add(makeRef(this)); plugin->sessions.add(makeRef(this));
addRef(); addRef();