Skip to content

Commit 35ba335

Browse files
committed
Add procedure SET_FLUSH_INTERVAL.
Add parameter FLUSH_INTERVAL to START_SESSION.
1 parent e090ec0 commit 35ba335

File tree

8 files changed

+167
-21
lines changed

8 files changed

+167
-21
lines changed

doc/sql.extensions/README.profiler.md

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ execute procedure rdb$profiler.finish_session(true);
9191
9292
-- Data analysis
9393
94-
commit; -- start new transaction
94+
set transaction read committed;
9595
9696
select * from plg$prof_sessions;
9797
@@ -130,12 +130,15 @@ select pstat.*
130130

131131
`RDB$PROFILER.START_SESSION` starts a new profiler session, turns it the current session (of the given `ATTACHMENT_ID`) and return its identifier.
132132

133+
If `FLUSH_INTERVAL` is different than `NULL` auto-flush is setup in the same way as manually calling `RDB$PROFILER.SET_FLUSH_INTERVAL`.
134+
133135
If `PLUGIN_NAME` is `NULL` (the default) it uses the database configuration `DefaultProfilerPlugin`.
134136

135137
`PLUGIN_OPTIONS` is plugin specific options and currently should be `NULL` for `Default_Profiler` plugin.
136138

137139
Input parameters:
138140
- `DESCRIPTION` type `VARCHAR(255) CHARACTER SET UTF8` default `NULL`
141+
- `FLUSH_INTERVAL` type `INTEGER` default `NULL`
139142
- `ATTACHMENT_ID` type `BIGINT NOT NULL` default `CURRENT_CONNECTION`
140143
- `PLUGIN_NAME` type `VARCHAR(255) CHARACTER SET UTF8` default `NULL`
141144
- `PLUGIN_OPTIONS` type `VARCHAR(255) CHARACTER SET UTF8` default `NULL`
@@ -206,6 +209,16 @@ Once flush happens, finished sessions are removed from memory.
206209
Input parameters:
207210
- `ATTACHMENT_ID` type `BIGINT NOT NULL` default `CURRENT_CONNECTION`
208211

212+
## Procedure `SET_FLUSH_INTERVAL`
213+
214+
`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).
215+
216+
`FLUSH_INTERVAL` is interpreted as number of seconds.
217+
218+
Input parameters:
219+
- `FLUSH_INTERVAL` type `INTEGER NOT NULL`
220+
- `ATTACHMENT_ID` type `BIGINT NOT NULL` default `CURRENT_CONNECTION`
221+
209222
# Snapshot tables
210223

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

src/jrd/Attachment.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1172,3 +1172,8 @@ bool Attachment::isProfilerActive()
11721172
{
11731173
return att_profiler_manager && att_profiler_manager->isActive();
11741174
}
1175+
1176+
void Attachment::releaseProfilerManager()
1177+
{
1178+
att_profiler_manager.reset();
1179+
}

src/jrd/Attachment.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -800,6 +800,7 @@ class Attachment : public pool_alloc<type_att>
800800

801801
ProfilerManager* getProfilerManager(thread_db* tdbb);
802802
bool isProfilerActive();
803+
void releaseProfilerManager();
803804

804805
JProvider* getProvider()
805806
{

src/jrd/ProfilerManager.cpp

Lines changed: 111 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ namespace
5858
FLUSH,
5959
PAUSE_SESSION,
6060
RESUME_SESSION,
61+
SET_FLUSH_INTERVAL,
6162
START_SESSION
6263
};
6364

@@ -283,6 +284,26 @@ IExternalResultSet* ProfilerPackage::resumeSessionProcedure(ThrowStatusException
283284
return nullptr;
284285
}
285286

287+
IExternalResultSet* ProfilerPackage::setFlushIntervalProcedure(ThrowStatusExceptionWrapper* /*status*/,
288+
IExternalContext* context, const SetFlushIntervalInput::Type* in, void* out)
289+
{
290+
const auto tdbb = JRD_get_thread_data();
291+
const auto attachment = tdbb->getAttachment();
292+
293+
if (in->attachmentId != attachment->att_attachment_id)
294+
{
295+
ProfilerIpc ipc(tdbb, *getDefaultMemoryPool(), in->attachmentId);
296+
ipc.send(tdbb, ProfilerIpc::Tag::SET_FLUSH_INTERVAL, in);
297+
return nullptr;
298+
}
299+
300+
const auto profilerManager = attachment->getProfilerManager(tdbb);
301+
302+
profilerManager->setFlushInterval(in->flushInterval);
303+
304+
return nullptr;
305+
}
306+
286307
void ProfilerPackage::startSessionFunction(ThrowStatusExceptionWrapper* /*status*/,
287308
IExternalContext* context, const StartSessionInput::Type* in, StartSessionOutput::Type* out)
288309
{
@@ -297,13 +318,15 @@ void ProfilerPackage::startSessionFunction(ThrowStatusExceptionWrapper* /*status
297318
}
298319

299320
const string description(in->description.str, in->descriptionNull ? 0 : in->description.length);
321+
const Nullable<SLONG> flushInterval(in->flushIntervalNull ?
322+
Nullable<SLONG>() : Nullable<SLONG>(in->flushInterval));
300323
const PathName pluginName(in->pluginName.str, in->pluginNameNull ? 0 : in->pluginName.length);
301324
const string pluginOptions(in->pluginOptions.str, in->pluginOptionsNull ? 0 : in->pluginOptions.length);
302325

303326
const auto profilerManager = attachment->getProfilerManager(tdbb);
304327

305328
out->sessionIdNull = FB_FALSE;
306-
out->sessionId = profilerManager->startSession(tdbb, in->attachmentId, pluginName, description, pluginOptions);
329+
out->sessionId = profilerManager->startSession(tdbb, flushInterval, pluginName, description, pluginOptions);
307330
}
308331

309332

@@ -313,10 +336,22 @@ void ProfilerPackage::startSessionFunction(ThrowStatusExceptionWrapper* /*status
313336
ProfilerManager::ProfilerManager(thread_db* tdbb)
314337
: activePlugins(*tdbb->getAttachment()->att_pool)
315338
{
339+
const auto attachment = tdbb->getAttachment();
340+
341+
flushTimer = FB_NEW TimerImpl();
342+
343+
flushTimer->setOnTimer([this, attachment](auto) {
344+
FbLocalStatus statusVector;
345+
EngineContextHolder innerTdbb(&statusVector, attachment->getInterface(), FB_FUNCTION);
346+
347+
flush(false);
348+
updateFlushTimer(false);
349+
});
316350
}
317351

318352
ProfilerManager::~ProfilerManager()
319353
{
354+
flushTimer->stop();
320355
}
321356

322357
ProfilerManager* ProfilerManager::create(thread_db* tdbb)
@@ -346,9 +381,12 @@ int ProfilerManager::blockingAst(void* astObject)
346381
return 0;
347382
}
348383

349-
SINT64 ProfilerManager::startSession(thread_db* tdbb, AttNumber attachmentId, const PathName& pluginName,
350-
const string& description, const string& options)
384+
SINT64 ProfilerManager::startSession(thread_db* tdbb, Nullable<SLONG> flushInterval,
385+
const PathName& pluginName, const string& description, const string& options)
351386
{
387+
if (flushInterval.isAssigned())
388+
checkFlushInterval(flushInterval.value);
389+
352390
AutoSetRestore<bool> pauseProfiler(&paused, true);
353391

354392
const auto attachment = tdbb->getAttachment();
@@ -405,6 +443,9 @@ SINT64 ProfilerManager::startSession(thread_db* tdbb, AttNumber attachmentId, co
405443

406444
paused = false;
407445

446+
if (flushInterval.isAssigned())
447+
setFlushInterval(flushInterval.value);
448+
408449
return currentSession->pluginSession->getId();
409450
}
410451

@@ -585,7 +626,19 @@ void ProfilerManager::pauseSession(bool flushData)
585626
void ProfilerManager::resumeSession()
586627
{
587628
if (currentSession)
629+
{
588630
paused = false;
631+
updateFlushTimer();
632+
}
633+
}
634+
635+
void ProfilerManager::setFlushInterval(SLONG interval)
636+
{
637+
checkFlushInterval(interval);
638+
639+
currentFlushInterval = (unsigned) interval;
640+
641+
updateFlushTimer();
589642
}
590643

591644
void ProfilerManager::discard()
@@ -594,25 +647,38 @@ void ProfilerManager::discard()
594647
activePlugins.clear();
595648
}
596649

597-
void ProfilerManager::flush()
650+
void ProfilerManager::flush(bool updateTimer)
598651
{
599-
AutoSetRestore<bool> pauseProfiler(&paused, true);
652+
{ // scope
653+
AutoSetRestore<bool> pauseProfiler(&paused, true);
600654

601-
auto pluginAccessor = activePlugins.accessor();
655+
auto pluginAccessor = activePlugins.accessor();
602656

603-
for (bool hasNext = pluginAccessor.getFirst(); hasNext;)
604-
{
605-
auto& pluginName = pluginAccessor.current()->first;
606-
auto& plugin = pluginAccessor.current()->second;
657+
for (bool hasNext = pluginAccessor.getFirst(); hasNext;)
658+
{
659+
auto& pluginName = pluginAccessor.current()->first;
660+
auto& plugin = pluginAccessor.current()->second;
607661

608-
LogLocalStatus status("Profiler flush");
609-
plugin->flush(&status);
662+
LogLocalStatus status("Profiler flush");
663+
plugin->flush(&status);
610664

611-
hasNext = pluginAccessor.getNext();
665+
hasNext = pluginAccessor.getNext();
612666

613-
if (!currentSession || plugin.get() != currentSession->plugin.get())
614-
activePlugins.remove(pluginName);
667+
if (!currentSession || plugin.get() != currentSession->plugin.get())
668+
activePlugins.remove(pluginName);
669+
}
615670
}
671+
672+
if (updateTimer)
673+
updateFlushTimer();
674+
}
675+
676+
void ProfilerManager::updateFlushTimer(bool canStopTimer)
677+
{
678+
if (currentSession && !paused && currentFlushInterval)
679+
flushTimer->reset(currentFlushInterval);
680+
else if (canStopTimer)
681+
flushTimer->stop();
616682
}
617683

618684
ProfilerManager::Statement* ProfilerManager::getStatement(jrd_req* request)
@@ -984,13 +1050,25 @@ void ProfilerListener::processCommand(thread_db* tdbb)
9841050
header->bufferSize = 0;
9851051
break;
9861052

1053+
case Tag::SET_FLUSH_INTERVAL:
1054+
{
1055+
const auto in = reinterpret_cast<const ProfilerPackage::SetFlushIntervalInput::Type*>(header->buffer);
1056+
fb_assert(sizeof(*in) == header->bufferSize);
1057+
1058+
profilerManager->setFlushInterval(in->flushInterval);
1059+
header->bufferSize = 0;
1060+
break;
1061+
}
1062+
9871063
case Tag::START_SESSION:
9881064
{
9891065
const auto in = reinterpret_cast<const ProfilerPackage::StartSessionInput::Type*>(header->buffer);
9901066
fb_assert(sizeof(*in) == header->bufferSize);
9911067

9921068
const string description(in->description.str,
9931069
in->descriptionNull ? 0 : in->description.length);
1070+
const Nullable<SLONG> flushInterval(in->flushIntervalNull ?
1071+
Nullable<SLONG>() : Nullable<SLONG>(in->flushInterval));
9941072
const PathName pluginName(in->pluginName.str,
9951073
in->pluginNameNull ? 0 : in->pluginName.length);
9961074
const string pluginOptions(in->pluginOptions.str,
@@ -1001,8 +1079,8 @@ void ProfilerListener::processCommand(thread_db* tdbb)
10011079
header->bufferSize = sizeof(*out);
10021080

10031081
out->sessionIdNull = FB_FALSE;
1004-
out->sessionId = profilerManager->startSession(tdbb,
1005-
in->attachmentId, pluginName, description, pluginOptions);
1082+
out->sessionId = profilerManager->startSession(tdbb, flushInterval,
1083+
pluginName, description, pluginOptions);
10061084

10071085
break;
10081086
}
@@ -1110,6 +1188,21 @@ ProfilerPackage::ProfilerPackage(MemoryPool& pool)
11101188
// output parameters
11111189
{
11121190
}
1191+
),
1192+
SystemProcedure(
1193+
pool,
1194+
"SET_FLUSH_INTERVAL",
1195+
SystemProcedureFactory<SetFlushIntervalInput, VoidMessage, setFlushIntervalProcedure>(),
1196+
prc_executable,
1197+
// input parameters
1198+
{
1199+
{"FLUSH_INTERVAL", fld_seconds_interval, false},
1200+
{"ATTACHMENT_ID", fld_att_id, false, "current_connection",
1201+
{blr_internal_info, blr_literal, blr_long, 0, INFO_TYPE_CONNECTION_ID, 0, 0, 0}}
1202+
},
1203+
// output parameters
1204+
{
1205+
}
11131206
)
11141207
},
11151208
// functions
@@ -1121,6 +1214,7 @@ ProfilerPackage::ProfilerPackage(MemoryPool& pool)
11211214
// parameters
11221215
{
11231216
{"DESCRIPTION", fld_short_description, true, "null", {blr_null}},
1217+
{"FLUSH_INTERVAL", fld_seconds_interval, true, "null", {blr_null}},
11241218
{"ATTACHMENT_ID", fld_att_id, false, "current_connection",
11251219
{blr_internal_info, blr_literal, blr_long, 0, INFO_TYPE_CONNECTION_ID, 0, 0, 0}},
11261220
{"PLUGIN_NAME", fld_file_name2, true, "null", {blr_null}},

src/jrd/ProfilerManager.h

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@
2828
#include "../common/classes/auto.h"
2929
#include "../common/classes/fb_string.h"
3030
#include "../common/classes/Nullable.h"
31+
#include "../common/classes/RefCounted.h"
32+
#include "../common/classes/TimerImpl.h"
3133
#include "../jrd/SystemPackages.h"
3234

3335
namespace Jrd {
@@ -97,8 +99,8 @@ class ProfilerManager final
9799
void operator=(const ProfilerManager&) = delete;
98100

99101
public:
100-
SINT64 startSession(thread_db* tdbb, AttNumber attachmentId, const Firebird::PathName& pluginName,
101-
const Firebird::string& description, const Firebird::string& options);
102+
SINT64 startSession(thread_db* tdbb, Nullable<SLONG> flushInterval,
103+
const Firebird::PathName& pluginName, const Firebird::string& description, const Firebird::string& options);
102104

103105
void prepareRecSource(thread_db* tdbb, jrd_req* request, const RecordSource* rsb);
104106
void onRequestFinish(jrd_req* request);
@@ -114,13 +116,27 @@ class ProfilerManager final
114116
return currentSession && !paused;
115117
}
116118

119+
static void checkFlushInterval(SLONG interval)
120+
{
121+
if (interval < 0)
122+
{
123+
Firebird::status_exception::raise(
124+
Firebird::Arg::Gds(isc_not_valid_for_var) <<
125+
"FLUSH_INTERVAL" <<
126+
Firebird::Arg::Num(interval));
127+
}
128+
}
129+
117130
private:
118131
void cancelSession();
119132
void finishSession(thread_db* tdbb, bool flushData);
120133
void pauseSession(bool flushData);
121134
void resumeSession();
135+
void setFlushInterval(SLONG interval);
122136
void discard();
123-
void flush();
137+
void flush(bool updateTimer = true);
138+
139+
void updateFlushTimer(bool canStopTimer = true);
124140

125141
Statement* getStatement(jrd_req* request);
126142
SINT64 getRequest(jrd_req* request, unsigned flags);
@@ -129,6 +145,8 @@ class ProfilerManager final
129145
Firebird::AutoPtr<ProfilerListener> listener;
130146
Firebird::LeftPooledMap<Firebird::PathName, Firebird::AutoPlugin<Firebird::IProfilerPlugin>> activePlugins;
131147
Firebird::AutoPtr<Session> currentSession;
148+
Firebird::RefPtr<Firebird::TimerImpl> flushTimer;
149+
unsigned currentFlushInterval = 0;
132150
bool paused = false;
133151
};
134152

@@ -199,8 +217,19 @@ class ProfilerPackage final : public SystemPackage
199217

200218
//----------
201219

220+
FB_MESSAGE(SetFlushIntervalInput, Firebird::ThrowStatusExceptionWrapper,
221+
(FB_INTEGER, flushInterval)
222+
(FB_BIGINT, attachmentId)
223+
);
224+
225+
static Firebird::IExternalResultSet* setFlushIntervalProcedure(Firebird::ThrowStatusExceptionWrapper* status,
226+
Firebird::IExternalContext* context, const SetFlushIntervalInput::Type* in, void* out);
227+
228+
//----------
229+
202230
FB_MESSAGE(StartSessionInput, Firebird::ThrowStatusExceptionWrapper,
203231
(FB_INTL_VARCHAR(255, CS_METADATA), description)
232+
(FB_INTEGER, flushInterval)
204233
(FB_BIGINT, attachmentId)
205234
(FB_INTL_VARCHAR(255, CS_METADATA), pluginName)
206235
(FB_INTL_VARCHAR(255, CS_METADATA), pluginOptions)

src/jrd/fields.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,4 +225,5 @@
225225
FIELD(fld_keyword_reserved, nam_keyword_reserved, dtype_boolean, 1 , 0 , NULL , false)
226226

227227
FIELD(fld_short_description, nam_short_description, dtype_varying, 255 * METADATA_BYTES_PER_CHAR, dsc_text_type_metadata, NULL , true)
228+
FIELD(fld_seconds_interval, nam_seconds_interval, dtype_long, sizeof(SLONG) , 0 , NULL , true)
228229
FIELD(fld_prof_ses_id , nam_prof_ses_id , dtype_int64 , sizeof(SINT64) , 0 , NULL , true)

src/jrd/jrd.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7518,6 +7518,8 @@ void release_attachment(thread_db* tdbb, Jrd::Attachment* attachment)
75187518
if (!attachment)
75197519
return;
75207520

7521+
attachment->releaseProfilerManager();
7522+
75217523
attachment->att_replicator = nullptr;
75227524

75237525
while (attachment->att_repl_appliers.hasData())

src/jrd/names.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -462,4 +462,5 @@ NAME("MON$COMPILED_STATEMENTS", nam_mon_compiled_statements)
462462
NAME("MON$COMPILED_STATEMENT_ID", nam_mon_cmp_stmt_id)
463463

464464
NAME("RDB$SHORT_DESCRIPTION", nam_short_description)
465+
NAME("RDB$SECONDS_INTERVAL", nam_seconds_interval)
465466
NAME("RDB$PROFILE_SESSION_ID", nam_prof_ses_id)

0 commit comments

Comments
 (0)