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

Detach idle worker attachments after 60 seconds of inactivity to free system resources and metadata locks.

Also, publish worker attachments for monitoring.
This commit is contained in:
Vlad Khorsun 2022-06-15 17:05:18 +03:00
parent 25ddf6750d
commit 889ff29299
6 changed files with 91 additions and 19 deletions

View File

@ -27,7 +27,6 @@
#include "../../common/classes/TimerImpl.h"
#include "../../common/StatusHolder.h"
#include "../../common/ThreadStart.h"
#include "../../common/utils_proto.h"
namespace Firebird {
@ -36,7 +35,7 @@ void TimerImpl::handler()
{
{
MutexLockGuard guard(m_mutex, FB_FUNCTION);
fb_assert(!m_inHandler);
fb_assert(!m_handlerTid);
m_fireTime = 0;
if (!m_expTime) // Timer was reset to zero or stopped, do nothing
@ -54,7 +53,7 @@ void TimerImpl::handler()
m_expTime = 0;
if (m_onTimer)
m_inHandler = true;
m_handlerTid = Thread::getId();
}
if (!m_onTimer)
@ -63,7 +62,7 @@ void TimerImpl::handler()
m_onTimer(this);
MutexLockGuard guard(m_mutex, FB_FUNCTION);
m_inHandler = false;
m_handlerTid = 0;
}
void TimerImpl::reset(unsigned int timeout)
@ -108,8 +107,12 @@ void TimerImpl::stop()
{
MutexLockGuard guard(m_mutex, FB_FUNCTION);
// Allow handler() to call stop()
if (m_handlerTid == Thread::getId())
return;
// hvlad: it could be replaced by condition variable when we have good one for Windows
while (m_inHandler)
while (m_handlerTid)
{
MutexUnlockGuard unlock(m_mutex, FB_FUNCTION);
Thread::sleep(10);

View File

@ -32,6 +32,7 @@
#include "../../common/classes/ImplementHelper.h"
#include "../../common/classes/locks.h"
#include "../../common/ThreadStart.h"
namespace Firebird {
@ -51,7 +52,7 @@ public:
TimerImpl() :
m_fireTime(0),
m_expTime(0),
m_inHandler(false)
m_handlerTid(0)
{ }
// ITimer implementation
@ -82,9 +83,9 @@ public:
private:
Mutex m_mutex;
SINT64 m_fireTime; // when ITimer will fire, could be less than m_expTime
SINT64 m_expTime; // when actual idle timeout will expire
SINT64 m_expTime; // when actual timeout will expire
std::function<OnTimerFunc> m_onTimer;
bool m_inHandler;
ThreadId m_handlerTid; // ID of handler thread, if handler is running
};

View File

@ -1036,7 +1036,7 @@ void StableAttachmentPart::manualAsyncUnlock(ULONG& flags)
}
}
void StableAttachmentPart::onIdleTimer(TimerImpl*)
void StableAttachmentPart::doOnIdleTimer(TimerImpl*)
{
// Ensure attachment is still alive and still idle
@ -1075,8 +1075,11 @@ void Attachment::setupIdleTimer(bool clear)
{
if (!att_idle_timer)
{
att_idle_timer = FB_NEW IdleTimer(getStable());
att_idle_timer->setOnTimer(&StableAttachmentPart::onIdleTimer);
using IdleTimer = TimerWithRef<StableAttachmentPart>;
auto idleTimer = FB_NEW IdleTimer(getStable());
idleTimer->setOnTimer(&StableAttachmentPart::onIdleTimer);
att_idle_timer = idleTimer;
}
att_idle_timer->reset(timeout);

View File

@ -374,7 +374,13 @@ public:
return shutError;
}
void onIdleTimer(Firebird::TimerImpl*);
void onIdleTimer(Firebird::TimerImpl* timer)
{
doOnIdleTimer(timer);
}
protected:
virtual void doOnIdleTimer(Firebird::TimerImpl* timer);
private:
Attachment* att;
@ -809,9 +815,7 @@ private:
unsigned int att_idle_timeout; // seconds
unsigned int att_stmt_timeout; // milliseconds
typedef Firebird::TimerWithRef<StableAttachmentPart> IdleTimer;
Firebird::RefPtr<IdleTimer> att_idle_timer;
Firebird::RefPtr<Firebird::TimerImpl> att_idle_timer;
Firebird::Array<JBatch*> att_batches;
InitialOptions att_initial_options; // Initial session options

View File

@ -45,6 +45,8 @@ using namespace Firebird;
namespace Jrd {
const unsigned WORKER_IDLE_TIMEOUT = 60; // 1 minute
/// class WorkerStableAttachment
WorkerStableAttachment::WorkerStableAttachment(FbStatusVector* status, Jrd::Attachment* attachment) :
@ -65,6 +67,7 @@ WorkerStableAttachment::WorkerStableAttachment(FbStatusVector* status, Jrd::Atta
PAG_header(tdbb, true);
PAG_attachment_id(tdbb);
TRA_init(attachment);
Monitoring::publishAttachment(tdbb);
initDone();
}
@ -97,6 +100,11 @@ WorkerStableAttachment* WorkerStableAttachment::create(FbStatusVector* status, J
return NULL;
}
void WorkerStableAttachment::doOnIdleTimer(Firebird::TimerImpl* timer)
{
WorkerAttachment::detachIdle(this);
}
void WorkerStableAttachment::fini()
{
Attachment* attachment = NULL;
@ -232,7 +240,19 @@ void WorkerAttachment::shutdownDbb(Database* dbb)
StableAttachmentPart* WorkerAttachment::getAttachment(FbStatusVector* status, Database* dbb)
{
//?? Database::Checkout cout(dbb);
// There should be no locked attachment.
#ifdef _DEBUG
thread_db* tdbb = JRD_get_thread_data();
if (tdbb)
{
Attachment* att = tdbb->getAttachment();
if (att)
{
const StableAttachmentPart::Sync* sync = att->getStable()->getSync();
fb_assert(!sync || !sync->locked());
}
}
#endif
Arg::Gds(isc_shutdown).copyTo(status);
@ -245,7 +265,6 @@ StableAttachmentPart* WorkerAttachment::getAttachment(FbStatusVector* status, Da
if (m_shutdown)
return NULL;
FB_SIZE_T maxWorkers = Config::getMaxParallelWorkers();
if (maxWorkers <= 0)
maxWorkers = MAX_ULONG;
@ -298,7 +317,10 @@ StableAttachmentPart* WorkerAttachment::getAttachment(FbStatusVector* status, Da
fb_assert(!att || (att->att_flags & ATT_worker));
if (att)
{
att->att_use_count++;
att->setupIdleTimer(true);
}
}
if (att)
@ -319,10 +341,12 @@ void WorkerAttachment::releaseAttachment(FbStatusVector* status, StableAttachmen
return;
att->att_use_count--;
att->setupIdleTimer(false);
item = getByName(att->att_database->dbb_filename);
}
bool detach = (m_shutdown || (item == NULL));
const bool detach = (m_shutdown || (item == NULL));
bool tryClear = false;
if (item)
@ -372,6 +396,36 @@ void WorkerAttachment::clear(bool checkRefs)
}
}
bool WorkerAttachment::detachIdle(StableAttachmentPart* sAtt)
{
WorkerAttachment* item = NULL;
{ // scope
AttSyncLockGuard attGuard(sAtt->getSync(), FB_FUNCTION);
Attachment* att = sAtt->getHandle();
if (!att || att->att_use_count > 0)
return false;
item = getByName(att->att_database->dbb_filename);
}
if (item)
{
MutexLockGuard guard(item->m_mutex, FB_FUNCTION);
FB_SIZE_T pos;
if (item->m_idleAtts.find(sAtt, pos))
item->m_idleAtts.remove(pos);
else
return false;
}
FbLocalStatus status;
doDetach(&status, sAtt);
return true;
}
StableAttachmentPart* WorkerAttachment::doAttach(FbStatusVector* status, Database* dbb)
{
StableAttachmentPart* sAtt = NULL;
@ -396,7 +450,10 @@ StableAttachmentPart* WorkerAttachment::doAttach(FbStatusVector* status, Databas
}
if (sAtt)
{
sAtt->addRef(); // !!
sAtt->getHandle()->setIdleTimeout(WORKER_IDLE_TIMEOUT);
}
return sAtt;
}
@ -415,7 +472,6 @@ void WorkerAttachment::doDetach(FbStatusVector* status, StableAttachmentPart* sA
{
JAttachment* jAtt = sAtt->getInterface();
jAtt->detach(status);
jAtt->release();
}
sAtt->release(); // !!
}

View File

@ -50,6 +50,9 @@ public:
void fini();
protected:
virtual void doOnIdleTimer(Firebird::TimerImpl* timer);
private:
explicit WorkerStableAttachment(FbStatusVector* status, Jrd::Attachment* att);
virtual ~WorkerStableAttachment();
@ -80,6 +83,8 @@ public:
static Jrd::StableAttachmentPart* getAttachment(FbStatusVector* status, Jrd::Database* dbb);
static void releaseAttachment(FbStatusVector* status, Jrd::StableAttachmentPart* sAtt);
static bool detachIdle(Jrd::StableAttachmentPart* sAtt);
static void incUserAtts(const Firebird::PathName& dbname);
static void decUserAtts(const Firebird::PathName& dbname);