@@ -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+
286307void 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
313336ProfilerManager::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
318352ProfilerManager::~ProfilerManager ()
319353{
354+ flushTimer->stop ();
320355}
321356
322357ProfilerManager* 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)
585626void 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
591644void 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
618684ProfilerManager::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}},
0 commit comments