mirror of
https://github.com/FirebirdSQL/firebird.git
synced 2025-01-23 14:03:07 +01:00
Suspend trace session when log is full despite of log reader [in]activity.
This commit is contained in:
parent
2c3d4018da
commit
22107f0ba3
@ -47,12 +47,10 @@ using namespace Firebird;
|
||||
|
||||
namespace Jrd {
|
||||
|
||||
/// TraceLogImpl
|
||||
|
||||
const size_t MAX_LOG_FILE_SIZE = 1024 * 1024;
|
||||
const unsigned int MAX_FILE_NUM = (unsigned int) -1;
|
||||
|
||||
TraceLogImpl::TraceLogImpl(MemoryPool& pool, const PathName& fileName, bool reader) :
|
||||
TraceLog::TraceLog(MemoryPool& pool, const PathName& fileName, bool reader) :
|
||||
m_baseFileName(pool)
|
||||
{
|
||||
m_base = 0;
|
||||
@ -64,7 +62,7 @@ TraceLogImpl::TraceLogImpl(MemoryPool& pool, const PathName& fileName, bool read
|
||||
ISC_map_file(status, fileName.c_str(), initShMem, this, sizeof(ShMemHeader), &m_handle);
|
||||
if (!m_base)
|
||||
{
|
||||
iscLogStatus("Cannot initialize the shared memory region", status);
|
||||
iscLogStatus("TraceLog: cannot initialize the shared memory region", status);
|
||||
status_exception::raise(status);
|
||||
}
|
||||
|
||||
@ -79,7 +77,7 @@ TraceLogImpl::TraceLogImpl(MemoryPool& pool, const PathName& fileName, bool read
|
||||
m_fileHandle = openFile(m_fileNum);
|
||||
}
|
||||
|
||||
TraceLogImpl::~TraceLogImpl()
|
||||
TraceLog::~TraceLog()
|
||||
{
|
||||
::close(m_fileHandle);
|
||||
|
||||
@ -105,7 +103,7 @@ TraceLogImpl::~TraceLogImpl()
|
||||
}
|
||||
}
|
||||
|
||||
int TraceLogImpl::openFile(int fileNum)
|
||||
int TraceLog::openFile(int fileNum)
|
||||
{
|
||||
PathName fileName;
|
||||
fileName.printf("%s.%07ld", m_baseFileName.c_str(), fileNum);
|
||||
@ -122,14 +120,14 @@ int TraceLogImpl::openFile(int fileNum)
|
||||
return file;
|
||||
}
|
||||
|
||||
int TraceLogImpl::removeFile(int fileNum)
|
||||
int TraceLog::removeFile(int fileNum)
|
||||
{
|
||||
PathName fileName;
|
||||
fileName.printf("%s.%07ld", m_baseFileName.c_str(), fileNum);
|
||||
return unlink(fileName.c_str());
|
||||
}
|
||||
|
||||
size_t TraceLogImpl::read(void* buf, size_t size)
|
||||
size_t TraceLog::read(void* buf, size_t size)
|
||||
{
|
||||
fb_assert(m_reader);
|
||||
|
||||
@ -141,6 +139,7 @@ size_t TraceLogImpl::read(void* buf, size_t size)
|
||||
|
||||
if (reads == 0)
|
||||
{
|
||||
// EOF reached, check the reason
|
||||
const off_t len = lseek(m_fileHandle, 0, SEEK_CUR);
|
||||
if (len >= MAX_LOG_FILE_SIZE)
|
||||
{
|
||||
@ -174,7 +173,7 @@ size_t TraceLogImpl::read(void* buf, size_t size)
|
||||
return (size - readLeft);
|
||||
}
|
||||
|
||||
size_t TraceLogImpl::write(const void* buf, size_t size)
|
||||
size_t TraceLog::write(const void* buf, size_t size)
|
||||
{
|
||||
fb_assert(!m_reader);
|
||||
|
||||
@ -220,19 +219,19 @@ size_t TraceLogImpl::write(const void* buf, size_t size)
|
||||
return size - writeLeft;
|
||||
}
|
||||
|
||||
size_t TraceLogImpl::getApproxLogSize() const
|
||||
size_t TraceLog::getApproxLogSize() const
|
||||
{
|
||||
return (m_base->writeFileNum - m_base->readFileNum + 1) *
|
||||
(MAX_LOG_FILE_SIZE / (1024 * 1024));
|
||||
}
|
||||
|
||||
void TraceLogImpl::checkMutex(const TEXT* string, int state)
|
||||
void TraceLog::checkMutex(const TEXT* string, int state)
|
||||
{
|
||||
if (state)
|
||||
{
|
||||
TEXT msg[BUFFER_TINY];
|
||||
|
||||
sprintf(msg, "TRACE: mutex %s error, status = %d", string, state);
|
||||
sprintf(msg, "TraceLog: mutex %s error, status = %d", string, state);
|
||||
gds__log(msg);
|
||||
|
||||
fprintf(stderr, "%s\n", msg);
|
||||
@ -240,9 +239,9 @@ void TraceLogImpl::checkMutex(const TEXT* string, int state)
|
||||
}
|
||||
}
|
||||
|
||||
void TraceLogImpl::initShMem(void* arg, SH_MEM_T* shmemData, bool initialize)
|
||||
void TraceLog::initShMem(void* arg, SH_MEM_T* shmemData, bool initialize)
|
||||
{
|
||||
TraceLogImpl* log = (TraceLogImpl*) arg;
|
||||
TraceLog* log = (TraceLog*) arg;
|
||||
|
||||
#ifdef WIN_NT
|
||||
checkMutex("init", ISC_mutex_init(&log->m_mutex, shmemData->sh_mem_name));
|
||||
@ -261,7 +260,7 @@ void TraceLogImpl::initShMem(void* arg, SH_MEM_T* shmemData, bool initialize)
|
||||
}
|
||||
}
|
||||
|
||||
void TraceLogImpl::lock()
|
||||
void TraceLog::lock()
|
||||
{
|
||||
#ifdef WIN_NT
|
||||
checkMutex("lock", ISC_mutex_lock(&m_mutex));
|
||||
@ -270,7 +269,7 @@ void TraceLogImpl::lock()
|
||||
#endif
|
||||
}
|
||||
|
||||
void TraceLogImpl::unlock()
|
||||
void TraceLog::unlock()
|
||||
{
|
||||
#ifdef WIN_NT
|
||||
checkMutex("unlock", ISC_mutex_unlock(&m_mutex));
|
||||
|
@ -29,21 +29,18 @@
|
||||
#define TRACE_LOG
|
||||
|
||||
#include "../../common/classes/fb_string.h"
|
||||
#include "../../jrd/ntrace.h"
|
||||
#include "../../jrd/isc.h"
|
||||
|
||||
namespace Jrd {
|
||||
|
||||
class TraceLogImpl : public TraceLogWriter
|
||||
class TraceLog
|
||||
{
|
||||
public:
|
||||
TraceLogImpl(Firebird::MemoryPool& pool, const Firebird::PathName& fileName, bool reader);
|
||||
virtual ~TraceLogImpl();
|
||||
TraceLog(Firebird::MemoryPool& pool, const Firebird::PathName& fileName, bool reader);
|
||||
virtual ~TraceLog();
|
||||
|
||||
size_t read(void* buf, size_t size);
|
||||
virtual size_t write(const void* buf, size_t size);
|
||||
virtual void release()
|
||||
{ delete this; }
|
||||
size_t write(const void* buf, size_t size);
|
||||
|
||||
// returns approximate log size in MB
|
||||
size_t getApproxLogSize() const;
|
||||
@ -78,25 +75,22 @@ private:
|
||||
int m_fileHandle;
|
||||
bool m_reader;
|
||||
|
||||
friend class TraceLogGuard;
|
||||
};
|
||||
|
||||
|
||||
class TraceLogGuard
|
||||
{
|
||||
public:
|
||||
explicit TraceLogGuard(TraceLogImpl* log) : m_log(*log)
|
||||
class TraceLogGuard
|
||||
{
|
||||
m_log.lock();
|
||||
}
|
||||
public:
|
||||
explicit TraceLogGuard(TraceLog* log) : m_log(*log)
|
||||
{
|
||||
m_log.lock();
|
||||
}
|
||||
|
||||
~TraceLogGuard()
|
||||
{
|
||||
m_log.unlock();
|
||||
}
|
||||
~TraceLogGuard()
|
||||
{
|
||||
m_log.unlock();
|
||||
}
|
||||
|
||||
private:
|
||||
TraceLogImpl& m_log;
|
||||
private:
|
||||
TraceLog& m_log;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
|
@ -392,6 +392,64 @@ const char* TraceTriggerImpl::getRelationName()
|
||||
}
|
||||
|
||||
|
||||
/// TraceLogWriterImpl
|
||||
|
||||
class TraceLogWriterImpl : public TraceLogWriter
|
||||
{
|
||||
public:
|
||||
TraceLogWriterImpl(MemoryPool& pool, const TraceSession& session) :
|
||||
m_log(pool, session.ses_logfile, false),
|
||||
m_sesId(session.ses_id)
|
||||
{
|
||||
m_maxSize = Config::getMaxUserTraceLogSize();
|
||||
}
|
||||
|
||||
virtual size_t write(const void* buf, size_t size);
|
||||
virtual void release()
|
||||
{
|
||||
delete this;
|
||||
}
|
||||
|
||||
private:
|
||||
TraceLog m_log;
|
||||
ULONG m_sesId;
|
||||
size_t m_maxSize;
|
||||
};
|
||||
|
||||
size_t TraceLogWriterImpl::write(const void* buf, size_t size)
|
||||
{
|
||||
// comparison is in MB
|
||||
if (m_log.getApproxLogSize() <= m_maxSize)
|
||||
return m_log.write(buf, size);
|
||||
|
||||
ConfigStorage* storage = TraceManager::getStorage();
|
||||
StorageGuard guard(storage);
|
||||
|
||||
TraceSession session(*getDefaultMemoryPool());
|
||||
storage->restart();
|
||||
while (storage->getNextSession(session))
|
||||
{
|
||||
if (session.ses_id == m_sesId)
|
||||
{
|
||||
if (!(session.ses_flags & trs_log_full))
|
||||
{
|
||||
// suspend session
|
||||
session.ses_flags |= trs_log_full;
|
||||
storage->updateSession(session);
|
||||
|
||||
string s;
|
||||
s.printf("\n--- Session %d is suspended as its log is full ---\n", m_sesId);
|
||||
m_log.write(s.c_str(), s.length());
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// report successful write
|
||||
return size;
|
||||
}
|
||||
|
||||
|
||||
/// TraceInitInfoImpl
|
||||
|
||||
const char* TraceInitInfoImpl::getFirebirdRootDirectory()
|
||||
@ -404,7 +462,7 @@ TraceLogWriter* TraceInitInfoImpl::getLogWriter()
|
||||
if (!m_logWriter && !m_session.ses_logfile.empty())
|
||||
{
|
||||
MemoryPool &pool = *getDefaultMemoryPool();
|
||||
m_logWriter = FB_NEW(pool) TraceLogImpl(pool, m_session.ses_logfile, false);
|
||||
m_logWriter = FB_NEW(pool) TraceLogWriterImpl(pool, m_session);
|
||||
}
|
||||
return m_logWriter;
|
||||
}
|
||||
|
@ -67,7 +67,7 @@ public:
|
||||
|
||||
private:
|
||||
bool changeFlags(ULONG id, int setFlags, int clearFlags);
|
||||
bool checkAlive(ULONG sesId);
|
||||
bool checkAliveAndFlags(ULONG sesId, int& flags);
|
||||
|
||||
Service& m_svc;
|
||||
string m_user;
|
||||
@ -84,8 +84,7 @@ void TraceSvcJrd::setAttachInfo(const string& /*service_name*/, const string& us
|
||||
|
||||
void TraceSvcJrd::startSession(TraceSession& session, bool interactive)
|
||||
{
|
||||
TraceManager* mgr = m_svc.getTraceManager();
|
||||
ConfigStorage* storage = mgr->getStorage();
|
||||
ConfigStorage* storage = TraceManager::getStorage();
|
||||
|
||||
{ // scope
|
||||
StorageGuard guard(storage);
|
||||
@ -106,7 +105,6 @@ void TraceSvcJrd::startSession(TraceSession& session, bool interactive)
|
||||
GuidToString(buff, &guid);
|
||||
|
||||
session.ses_logfile.insert(0, "fb_trace.");
|
||||
// session.ses_logfile = TempFile::create("fb_trace_");
|
||||
}
|
||||
|
||||
storage->addSession(session);
|
||||
@ -122,7 +120,6 @@ void TraceSvcJrd::startSession(TraceSession& session, bool interactive)
|
||||
StorageGuard guard(storage);
|
||||
storage->removeSession(session.ses_id);
|
||||
}
|
||||
// unlink(session.ses_logfile.c_str());
|
||||
}
|
||||
else {
|
||||
m_svc.printf("Trace session ID %ld started\n", session.ses_id);
|
||||
@ -132,9 +129,8 @@ void TraceSvcJrd::startSession(TraceSession& session, bool interactive)
|
||||
void TraceSvcJrd::stopSession(ULONG id)
|
||||
{
|
||||
m_svc.started();
|
||||
TraceManager* mgr = m_svc.getTraceManager();
|
||||
|
||||
ConfigStorage* storage = mgr->getStorage();
|
||||
ConfigStorage* storage = TraceManager::getStorage();
|
||||
StorageGuard guard(storage);
|
||||
|
||||
storage->restart();
|
||||
@ -177,10 +173,7 @@ void TraceSvcJrd::setActive(ULONG id, bool active)
|
||||
|
||||
bool TraceSvcJrd::changeFlags(ULONG id, int setFlags, int clearFlags)
|
||||
{
|
||||
m_svc.started();
|
||||
TraceManager* mgr = m_svc.getTraceManager();
|
||||
|
||||
ConfigStorage* storage = mgr->getStorage();
|
||||
ConfigStorage* storage = TraceManager::getStorage();
|
||||
StorageGuard guard(storage);
|
||||
|
||||
storage->restart();
|
||||
@ -193,10 +186,14 @@ bool TraceSvcJrd::changeFlags(ULONG id, int setFlags, int clearFlags)
|
||||
|
||||
if (m_admin || m_user == session.ses_user)
|
||||
{
|
||||
const int saveFlags = session.ses_flags;
|
||||
|
||||
session.ses_flags |= setFlags;
|
||||
session.ses_flags &= ~clearFlags;
|
||||
|
||||
storage->updateSession(session);
|
||||
if (saveFlags != session.ses_flags) {
|
||||
storage->updateSession(session);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else
|
||||
@ -214,9 +211,7 @@ void TraceSvcJrd::listSessions()
|
||||
{
|
||||
m_svc.started();
|
||||
|
||||
TraceManager* mgr = m_svc.getTraceManager();
|
||||
|
||||
ConfigStorage* storage = mgr->getStorage();
|
||||
ConfigStorage* storage = TraceManager::getStorage();
|
||||
StorageGuard guard(storage);
|
||||
|
||||
storage->restart();
|
||||
@ -266,9 +261,6 @@ void TraceSvcJrd::listSessions()
|
||||
|
||||
void TraceSvcJrd::readSession(TraceSession& session)
|
||||
{
|
||||
// Unused, let's assume StorageGuard not needed.
|
||||
//TraceManager* mgr = m_svc.getTraceManager();
|
||||
//ConfigStorage* storage = mgr->getStorage();
|
||||
const size_t maxLogSize = Config::getMaxUserTraceLogSize(); // in MB
|
||||
|
||||
if (session.ses_logfile.empty())
|
||||
@ -278,16 +270,16 @@ void TraceSvcJrd::readSession(TraceSession& session)
|
||||
}
|
||||
|
||||
MemoryPool& pool = *getDefaultMemoryPool();
|
||||
AutoPtr<TraceLogImpl> log(FB_NEW(pool) TraceLogImpl(pool, session.ses_logfile, true));
|
||||
AutoPtr<TraceLog> log(FB_NEW(pool) TraceLog(pool, session.ses_logfile, true));
|
||||
|
||||
bool logFull = false;
|
||||
UCHAR buff[1024];
|
||||
while (!m_svc.finished() && checkAlive(session.ses_id))
|
||||
int flags = session.ses_flags;
|
||||
while (!m_svc.finished() && checkAliveAndFlags(session.ses_id, flags))
|
||||
{
|
||||
size_t len = log->read(buff, sizeof(buff));
|
||||
if (!len)
|
||||
{
|
||||
if (!checkAlive(session.ses_id))
|
||||
if (!checkAliveAndFlags(session.ses_id, flags))
|
||||
break;
|
||||
|
||||
THD_sleep(250);
|
||||
@ -296,24 +288,19 @@ void TraceSvcJrd::readSession(TraceSession& session)
|
||||
{
|
||||
m_svc.putBytes(buff, len);
|
||||
|
||||
if (logFull && log->getApproxLogSize() <= maxLogSize)
|
||||
const bool logFull = (flags & trs_log_full);
|
||||
if (logFull && log->getApproxLogSize() <= maxLogSize)
|
||||
{
|
||||
// resume session
|
||||
changeFlags(session.ses_id, 0, trs_log_full);
|
||||
logFull = false;
|
||||
}
|
||||
else if (!logFull && log->getApproxLogSize() > maxLogSize)
|
||||
{
|
||||
changeFlags(session.ses_id, trs_log_full, 0);
|
||||
logFull = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool TraceSvcJrd::checkAlive(ULONG sesId)
|
||||
bool TraceSvcJrd::checkAliveAndFlags(ULONG sesId, int& flags)
|
||||
{
|
||||
TraceManager* mgr = m_svc.getTraceManager();
|
||||
ConfigStorage* storage = mgr->getStorage();
|
||||
ConfigStorage* storage = TraceManager::getStorage();
|
||||
|
||||
bool alive = (m_chg_number == storage->getChangeNumber());
|
||||
if (!alive)
|
||||
@ -328,6 +315,7 @@ bool TraceSvcJrd::checkAlive(ULONG sesId)
|
||||
if (readSession.ses_id == sesId)
|
||||
{
|
||||
alive = true;
|
||||
flags = readSession.ses_flags;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user