mirror of
https://github.com/FirebirdSQL/firebird.git
synced 2025-02-02 08:40:39 +01:00
Add procedure SET_FLUSH_INTERVAL.
Add parameter FLUSH_INTERVAL to START_SESSION.
This commit is contained in:
parent
e090ec0f60
commit
35ba33592f
@ -91,7 +91,7 @@ execute procedure rdb$profiler.finish_session(true);
|
||||
|
||||
-- Data analysis
|
||||
|
||||
commit; -- start new transaction
|
||||
set transaction read committed;
|
||||
|
||||
select * from plg$prof_sessions;
|
||||
|
||||
@ -130,12 +130,15 @@ select pstat.*
|
||||
|
||||
`RDB$PROFILER.START_SESSION` starts a new profiler session, turns it the current session (of the given `ATTACHMENT_ID`) and return its identifier.
|
||||
|
||||
If `FLUSH_INTERVAL` is different than `NULL` auto-flush is setup in the same way as manually calling `RDB$PROFILER.SET_FLUSH_INTERVAL`.
|
||||
|
||||
If `PLUGIN_NAME` is `NULL` (the default) it uses the database configuration `DefaultProfilerPlugin`.
|
||||
|
||||
`PLUGIN_OPTIONS` is plugin specific options and currently should be `NULL` for `Default_Profiler` plugin.
|
||||
|
||||
Input parameters:
|
||||
- `DESCRIPTION` type `VARCHAR(255) CHARACTER SET UTF8` default `NULL`
|
||||
- `FLUSH_INTERVAL` type `INTEGER` default `NULL`
|
||||
- `ATTACHMENT_ID` type `BIGINT NOT NULL` default `CURRENT_CONNECTION`
|
||||
- `PLUGIN_NAME` type `VARCHAR(255) CHARACTER SET UTF8` default `NULL`
|
||||
- `PLUGIN_OPTIONS` type `VARCHAR(255) CHARACTER SET UTF8` default `NULL`
|
||||
@ -206,6 +209,16 @@ Once flush happens, finished sessions are removed from memory.
|
||||
Input parameters:
|
||||
- `ATTACHMENT_ID` type `BIGINT NOT NULL` default `CURRENT_CONNECTION`
|
||||
|
||||
## Procedure `SET_FLUSH_INTERVAL`
|
||||
|
||||
`RDB$PROFILER.SET_FLUSH_INTERVAL` turns periodic auto-flush on (when `FLUSH_INTERVAL` is greater than 0) or off (when `FLUSH_INTERVAL` is equal to 0).
|
||||
|
||||
`FLUSH_INTERVAL` is interpreted as number of seconds.
|
||||
|
||||
Input parameters:
|
||||
- `FLUSH_INTERVAL` type `INTEGER NOT NULL`
|
||||
- `ATTACHMENT_ID` type `BIGINT NOT NULL` default `CURRENT_CONNECTION`
|
||||
|
||||
# Snapshot tables
|
||||
|
||||
Snapshot tables (as well views and sequence) are automatically created in the first usage of the profiler. They are owned by the current user with read/write permissions for `PUBLIC`.
|
||||
|
@ -1172,3 +1172,8 @@ bool Attachment::isProfilerActive()
|
||||
{
|
||||
return att_profiler_manager && att_profiler_manager->isActive();
|
||||
}
|
||||
|
||||
void Attachment::releaseProfilerManager()
|
||||
{
|
||||
att_profiler_manager.reset();
|
||||
}
|
||||
|
@ -800,6 +800,7 @@ public:
|
||||
|
||||
ProfilerManager* getProfilerManager(thread_db* tdbb);
|
||||
bool isProfilerActive();
|
||||
void releaseProfilerManager();
|
||||
|
||||
JProvider* getProvider()
|
||||
{
|
||||
|
@ -58,6 +58,7 @@ namespace
|
||||
FLUSH,
|
||||
PAUSE_SESSION,
|
||||
RESUME_SESSION,
|
||||
SET_FLUSH_INTERVAL,
|
||||
START_SESSION
|
||||
};
|
||||
|
||||
@ -283,6 +284,26 @@ IExternalResultSet* ProfilerPackage::resumeSessionProcedure(ThrowStatusException
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
IExternalResultSet* ProfilerPackage::setFlushIntervalProcedure(ThrowStatusExceptionWrapper* /*status*/,
|
||||
IExternalContext* context, const SetFlushIntervalInput::Type* in, void* out)
|
||||
{
|
||||
const auto tdbb = JRD_get_thread_data();
|
||||
const auto attachment = tdbb->getAttachment();
|
||||
|
||||
if (in->attachmentId != attachment->att_attachment_id)
|
||||
{
|
||||
ProfilerIpc ipc(tdbb, *getDefaultMemoryPool(), in->attachmentId);
|
||||
ipc.send(tdbb, ProfilerIpc::Tag::SET_FLUSH_INTERVAL, in);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const auto profilerManager = attachment->getProfilerManager(tdbb);
|
||||
|
||||
profilerManager->setFlushInterval(in->flushInterval);
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void ProfilerPackage::startSessionFunction(ThrowStatusExceptionWrapper* /*status*/,
|
||||
IExternalContext* context, const StartSessionInput::Type* in, StartSessionOutput::Type* out)
|
||||
{
|
||||
@ -297,13 +318,15 @@ void ProfilerPackage::startSessionFunction(ThrowStatusExceptionWrapper* /*status
|
||||
}
|
||||
|
||||
const string description(in->description.str, in->descriptionNull ? 0 : in->description.length);
|
||||
const Nullable<SLONG> flushInterval(in->flushIntervalNull ?
|
||||
Nullable<SLONG>() : Nullable<SLONG>(in->flushInterval));
|
||||
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 profilerManager = attachment->getProfilerManager(tdbb);
|
||||
|
||||
out->sessionIdNull = FB_FALSE;
|
||||
out->sessionId = profilerManager->startSession(tdbb, in->attachmentId, pluginName, description, pluginOptions);
|
||||
out->sessionId = profilerManager->startSession(tdbb, flushInterval, pluginName, description, pluginOptions);
|
||||
}
|
||||
|
||||
|
||||
@ -313,10 +336,22 @@ void ProfilerPackage::startSessionFunction(ThrowStatusExceptionWrapper* /*status
|
||||
ProfilerManager::ProfilerManager(thread_db* tdbb)
|
||||
: activePlugins(*tdbb->getAttachment()->att_pool)
|
||||
{
|
||||
const auto attachment = tdbb->getAttachment();
|
||||
|
||||
flushTimer = FB_NEW TimerImpl();
|
||||
|
||||
flushTimer->setOnTimer([this, attachment](auto) {
|
||||
FbLocalStatus statusVector;
|
||||
EngineContextHolder innerTdbb(&statusVector, attachment->getInterface(), FB_FUNCTION);
|
||||
|
||||
flush(false);
|
||||
updateFlushTimer(false);
|
||||
});
|
||||
}
|
||||
|
||||
ProfilerManager::~ProfilerManager()
|
||||
{
|
||||
flushTimer->stop();
|
||||
}
|
||||
|
||||
ProfilerManager* ProfilerManager::create(thread_db* tdbb)
|
||||
@ -346,9 +381,12 @@ int ProfilerManager::blockingAst(void* astObject)
|
||||
return 0;
|
||||
}
|
||||
|
||||
SINT64 ProfilerManager::startSession(thread_db* tdbb, AttNumber attachmentId, const PathName& pluginName,
|
||||
const string& description, const string& options)
|
||||
SINT64 ProfilerManager::startSession(thread_db* tdbb, Nullable<SLONG> flushInterval,
|
||||
const PathName& pluginName, const string& description, const string& options)
|
||||
{
|
||||
if (flushInterval.isAssigned())
|
||||
checkFlushInterval(flushInterval.value);
|
||||
|
||||
AutoSetRestore<bool> pauseProfiler(&paused, true);
|
||||
|
||||
const auto attachment = tdbb->getAttachment();
|
||||
@ -405,6 +443,9 @@ SINT64 ProfilerManager::startSession(thread_db* tdbb, AttNumber attachmentId, co
|
||||
|
||||
paused = false;
|
||||
|
||||
if (flushInterval.isAssigned())
|
||||
setFlushInterval(flushInterval.value);
|
||||
|
||||
return currentSession->pluginSession->getId();
|
||||
}
|
||||
|
||||
@ -585,7 +626,19 @@ void ProfilerManager::pauseSession(bool flushData)
|
||||
void ProfilerManager::resumeSession()
|
||||
{
|
||||
if (currentSession)
|
||||
{
|
||||
paused = false;
|
||||
updateFlushTimer();
|
||||
}
|
||||
}
|
||||
|
||||
void ProfilerManager::setFlushInterval(SLONG interval)
|
||||
{
|
||||
checkFlushInterval(interval);
|
||||
|
||||
currentFlushInterval = (unsigned) interval;
|
||||
|
||||
updateFlushTimer();
|
||||
}
|
||||
|
||||
void ProfilerManager::discard()
|
||||
@ -594,25 +647,38 @@ void ProfilerManager::discard()
|
||||
activePlugins.clear();
|
||||
}
|
||||
|
||||
void ProfilerManager::flush()
|
||||
void ProfilerManager::flush(bool updateTimer)
|
||||
{
|
||||
AutoSetRestore<bool> pauseProfiler(&paused, true);
|
||||
{ // scope
|
||||
AutoSetRestore<bool> pauseProfiler(&paused, true);
|
||||
|
||||
auto pluginAccessor = activePlugins.accessor();
|
||||
auto pluginAccessor = activePlugins.accessor();
|
||||
|
||||
for (bool hasNext = pluginAccessor.getFirst(); hasNext;)
|
||||
{
|
||||
auto& pluginName = pluginAccessor.current()->first;
|
||||
auto& plugin = pluginAccessor.current()->second;
|
||||
for (bool hasNext = pluginAccessor.getFirst(); hasNext;)
|
||||
{
|
||||
auto& pluginName = pluginAccessor.current()->first;
|
||||
auto& plugin = pluginAccessor.current()->second;
|
||||
|
||||
LogLocalStatus status("Profiler flush");
|
||||
plugin->flush(&status);
|
||||
LogLocalStatus status("Profiler flush");
|
||||
plugin->flush(&status);
|
||||
|
||||
hasNext = pluginAccessor.getNext();
|
||||
hasNext = pluginAccessor.getNext();
|
||||
|
||||
if (!currentSession || plugin.get() != currentSession->plugin.get())
|
||||
activePlugins.remove(pluginName);
|
||||
if (!currentSession || plugin.get() != currentSession->plugin.get())
|
||||
activePlugins.remove(pluginName);
|
||||
}
|
||||
}
|
||||
|
||||
if (updateTimer)
|
||||
updateFlushTimer();
|
||||
}
|
||||
|
||||
void ProfilerManager::updateFlushTimer(bool canStopTimer)
|
||||
{
|
||||
if (currentSession && !paused && currentFlushInterval)
|
||||
flushTimer->reset(currentFlushInterval);
|
||||
else if (canStopTimer)
|
||||
flushTimer->stop();
|
||||
}
|
||||
|
||||
ProfilerManager::Statement* ProfilerManager::getStatement(jrd_req* request)
|
||||
@ -984,6 +1050,16 @@ void ProfilerListener::processCommand(thread_db* tdbb)
|
||||
header->bufferSize = 0;
|
||||
break;
|
||||
|
||||
case Tag::SET_FLUSH_INTERVAL:
|
||||
{
|
||||
const auto in = reinterpret_cast<const ProfilerPackage::SetFlushIntervalInput::Type*>(header->buffer);
|
||||
fb_assert(sizeof(*in) == header->bufferSize);
|
||||
|
||||
profilerManager->setFlushInterval(in->flushInterval);
|
||||
header->bufferSize = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
case Tag::START_SESSION:
|
||||
{
|
||||
const auto in = reinterpret_cast<const ProfilerPackage::StartSessionInput::Type*>(header->buffer);
|
||||
@ -991,6 +1067,8 @@ void ProfilerListener::processCommand(thread_db* tdbb)
|
||||
|
||||
const string description(in->description.str,
|
||||
in->descriptionNull ? 0 : in->description.length);
|
||||
const Nullable<SLONG> flushInterval(in->flushIntervalNull ?
|
||||
Nullable<SLONG>() : Nullable<SLONG>(in->flushInterval));
|
||||
const PathName pluginName(in->pluginName.str,
|
||||
in->pluginNameNull ? 0 : in->pluginName.length);
|
||||
const string pluginOptions(in->pluginOptions.str,
|
||||
@ -1001,8 +1079,8 @@ void ProfilerListener::processCommand(thread_db* tdbb)
|
||||
header->bufferSize = sizeof(*out);
|
||||
|
||||
out->sessionIdNull = FB_FALSE;
|
||||
out->sessionId = profilerManager->startSession(tdbb,
|
||||
in->attachmentId, pluginName, description, pluginOptions);
|
||||
out->sessionId = profilerManager->startSession(tdbb, flushInterval,
|
||||
pluginName, description, pluginOptions);
|
||||
|
||||
break;
|
||||
}
|
||||
@ -1110,6 +1188,21 @@ ProfilerPackage::ProfilerPackage(MemoryPool& pool)
|
||||
// output parameters
|
||||
{
|
||||
}
|
||||
),
|
||||
SystemProcedure(
|
||||
pool,
|
||||
"SET_FLUSH_INTERVAL",
|
||||
SystemProcedureFactory<SetFlushIntervalInput, VoidMessage, setFlushIntervalProcedure>(),
|
||||
prc_executable,
|
||||
// input parameters
|
||||
{
|
||||
{"FLUSH_INTERVAL", fld_seconds_interval, false},
|
||||
{"ATTACHMENT_ID", fld_att_id, false, "current_connection",
|
||||
{blr_internal_info, blr_literal, blr_long, 0, INFO_TYPE_CONNECTION_ID, 0, 0, 0}}
|
||||
},
|
||||
// output parameters
|
||||
{
|
||||
}
|
||||
)
|
||||
},
|
||||
// functions
|
||||
@ -1121,6 +1214,7 @@ ProfilerPackage::ProfilerPackage(MemoryPool& pool)
|
||||
// parameters
|
||||
{
|
||||
{"DESCRIPTION", fld_short_description, true, "null", {blr_null}},
|
||||
{"FLUSH_INTERVAL", fld_seconds_interval, true, "null", {blr_null}},
|
||||
{"ATTACHMENT_ID", fld_att_id, false, "current_connection",
|
||||
{blr_internal_info, blr_literal, blr_long, 0, INFO_TYPE_CONNECTION_ID, 0, 0, 0}},
|
||||
{"PLUGIN_NAME", fld_file_name2, true, "null", {blr_null}},
|
||||
|
@ -28,6 +28,8 @@
|
||||
#include "../common/classes/auto.h"
|
||||
#include "../common/classes/fb_string.h"
|
||||
#include "../common/classes/Nullable.h"
|
||||
#include "../common/classes/RefCounted.h"
|
||||
#include "../common/classes/TimerImpl.h"
|
||||
#include "../jrd/SystemPackages.h"
|
||||
|
||||
namespace Jrd {
|
||||
@ -97,8 +99,8 @@ public:
|
||||
void operator=(const ProfilerManager&) = delete;
|
||||
|
||||
public:
|
||||
SINT64 startSession(thread_db* tdbb, AttNumber attachmentId, const Firebird::PathName& pluginName,
|
||||
const Firebird::string& description, const Firebird::string& options);
|
||||
SINT64 startSession(thread_db* tdbb, Nullable<SLONG> flushInterval,
|
||||
const Firebird::PathName& pluginName, const Firebird::string& description, const Firebird::string& options);
|
||||
|
||||
void prepareRecSource(thread_db* tdbb, jrd_req* request, const RecordSource* rsb);
|
||||
void onRequestFinish(jrd_req* request);
|
||||
@ -114,13 +116,27 @@ public:
|
||||
return currentSession && !paused;
|
||||
}
|
||||
|
||||
static void checkFlushInterval(SLONG interval)
|
||||
{
|
||||
if (interval < 0)
|
||||
{
|
||||
Firebird::status_exception::raise(
|
||||
Firebird::Arg::Gds(isc_not_valid_for_var) <<
|
||||
"FLUSH_INTERVAL" <<
|
||||
Firebird::Arg::Num(interval));
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
void cancelSession();
|
||||
void finishSession(thread_db* tdbb, bool flushData);
|
||||
void pauseSession(bool flushData);
|
||||
void resumeSession();
|
||||
void setFlushInterval(SLONG interval);
|
||||
void discard();
|
||||
void flush();
|
||||
void flush(bool updateTimer = true);
|
||||
|
||||
void updateFlushTimer(bool canStopTimer = true);
|
||||
|
||||
Statement* getStatement(jrd_req* request);
|
||||
SINT64 getRequest(jrd_req* request, unsigned flags);
|
||||
@ -129,6 +145,8 @@ private:
|
||||
Firebird::AutoPtr<ProfilerListener> listener;
|
||||
Firebird::LeftPooledMap<Firebird::PathName, Firebird::AutoPlugin<Firebird::IProfilerPlugin>> activePlugins;
|
||||
Firebird::AutoPtr<Session> currentSession;
|
||||
Firebird::RefPtr<Firebird::TimerImpl> flushTimer;
|
||||
unsigned currentFlushInterval = 0;
|
||||
bool paused = false;
|
||||
};
|
||||
|
||||
@ -199,8 +217,19 @@ private:
|
||||
|
||||
//----------
|
||||
|
||||
FB_MESSAGE(SetFlushIntervalInput, Firebird::ThrowStatusExceptionWrapper,
|
||||
(FB_INTEGER, flushInterval)
|
||||
(FB_BIGINT, attachmentId)
|
||||
);
|
||||
|
||||
static Firebird::IExternalResultSet* setFlushIntervalProcedure(Firebird::ThrowStatusExceptionWrapper* status,
|
||||
Firebird::IExternalContext* context, const SetFlushIntervalInput::Type* in, void* out);
|
||||
|
||||
//----------
|
||||
|
||||
FB_MESSAGE(StartSessionInput, Firebird::ThrowStatusExceptionWrapper,
|
||||
(FB_INTL_VARCHAR(255, CS_METADATA), description)
|
||||
(FB_INTEGER, flushInterval)
|
||||
(FB_BIGINT, attachmentId)
|
||||
(FB_INTL_VARCHAR(255, CS_METADATA), pluginName)
|
||||
(FB_INTL_VARCHAR(255, CS_METADATA), pluginOptions)
|
||||
|
@ -225,4 +225,5 @@
|
||||
FIELD(fld_keyword_reserved, nam_keyword_reserved, dtype_boolean, 1 , 0 , NULL , false)
|
||||
|
||||
FIELD(fld_short_description, nam_short_description, dtype_varying, 255 * METADATA_BYTES_PER_CHAR, dsc_text_type_metadata, NULL , true)
|
||||
FIELD(fld_seconds_interval, nam_seconds_interval, dtype_long, sizeof(SLONG) , 0 , NULL , true)
|
||||
FIELD(fld_prof_ses_id , nam_prof_ses_id , dtype_int64 , sizeof(SINT64) , 0 , NULL , true)
|
||||
|
@ -7518,6 +7518,8 @@ void release_attachment(thread_db* tdbb, Jrd::Attachment* attachment)
|
||||
if (!attachment)
|
||||
return;
|
||||
|
||||
attachment->releaseProfilerManager();
|
||||
|
||||
attachment->att_replicator = nullptr;
|
||||
|
||||
while (attachment->att_repl_appliers.hasData())
|
||||
|
@ -462,4 +462,5 @@ NAME("MON$COMPILED_STATEMENTS", nam_mon_compiled_statements)
|
||||
NAME("MON$COMPILED_STATEMENT_ID", nam_mon_cmp_stmt_id)
|
||||
|
||||
NAME("RDB$SHORT_DESCRIPTION", nam_short_description)
|
||||
NAME("RDB$SECONDS_INTERVAL", nam_seconds_interval)
|
||||
NAME("RDB$PROFILE_SESSION_ID", nam_prof_ses_id)
|
||||
|
Loading…
Reference in New Issue
Block a user