8
0
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:
Adriano dos Santos Fernandes 2022-06-06 21:52:00 -03:00
parent e090ec0f60
commit 35ba33592f
8 changed files with 167 additions and 21 deletions

View File

@ -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`.

View File

@ -1172,3 +1172,8 @@ bool Attachment::isProfilerActive()
{
return att_profiler_manager && att_profiler_manager->isActive();
}
void Attachment::releaseProfilerManager()
{
att_profiler_manager.reset();
}

View File

@ -800,6 +800,7 @@ public:
ProfilerManager* getProfilerManager(thread_db* tdbb);
bool isProfilerActive();
void releaseProfilerManager();
JProvider* getProvider()
{

View File

@ -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}},

View File

@ -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)

View File

@ -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)

View File

@ -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())

View File

@ -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)