8
0
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:
hvlad 2009-02-11 15:24:12 +00:00
parent 2c3d4018da
commit 22107f0ba3
4 changed files with 111 additions and 72 deletions

View File

@ -47,12 +47,10 @@ using namespace Firebird;
namespace Jrd { namespace Jrd {
/// TraceLogImpl
const size_t MAX_LOG_FILE_SIZE = 1024 * 1024; const size_t MAX_LOG_FILE_SIZE = 1024 * 1024;
const unsigned int MAX_FILE_NUM = (unsigned int) -1; 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_baseFileName(pool)
{ {
m_base = 0; 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); ISC_map_file(status, fileName.c_str(), initShMem, this, sizeof(ShMemHeader), &m_handle);
if (!m_base) if (!m_base)
{ {
iscLogStatus("Cannot initialize the shared memory region", status); iscLogStatus("TraceLog: cannot initialize the shared memory region", status);
status_exception::raise(status); status_exception::raise(status);
} }
@ -79,7 +77,7 @@ TraceLogImpl::TraceLogImpl(MemoryPool& pool, const PathName& fileName, bool read
m_fileHandle = openFile(m_fileNum); m_fileHandle = openFile(m_fileNum);
} }
TraceLogImpl::~TraceLogImpl() TraceLog::~TraceLog()
{ {
::close(m_fileHandle); ::close(m_fileHandle);
@ -105,7 +103,7 @@ TraceLogImpl::~TraceLogImpl()
} }
} }
int TraceLogImpl::openFile(int fileNum) int TraceLog::openFile(int fileNum)
{ {
PathName fileName; PathName fileName;
fileName.printf("%s.%07ld", m_baseFileName.c_str(), fileNum); fileName.printf("%s.%07ld", m_baseFileName.c_str(), fileNum);
@ -122,14 +120,14 @@ int TraceLogImpl::openFile(int fileNum)
return file; return file;
} }
int TraceLogImpl::removeFile(int fileNum) int TraceLog::removeFile(int fileNum)
{ {
PathName fileName; PathName fileName;
fileName.printf("%s.%07ld", m_baseFileName.c_str(), fileNum); fileName.printf("%s.%07ld", m_baseFileName.c_str(), fileNum);
return unlink(fileName.c_str()); 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); fb_assert(m_reader);
@ -141,6 +139,7 @@ size_t TraceLogImpl::read(void* buf, size_t size)
if (reads == 0) if (reads == 0)
{ {
// EOF reached, check the reason
const off_t len = lseek(m_fileHandle, 0, SEEK_CUR); const off_t len = lseek(m_fileHandle, 0, SEEK_CUR);
if (len >= MAX_LOG_FILE_SIZE) if (len >= MAX_LOG_FILE_SIZE)
{ {
@ -174,7 +173,7 @@ size_t TraceLogImpl::read(void* buf, size_t size)
return (size - readLeft); 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); fb_assert(!m_reader);
@ -220,19 +219,19 @@ size_t TraceLogImpl::write(const void* buf, size_t size)
return size - writeLeft; return size - writeLeft;
} }
size_t TraceLogImpl::getApproxLogSize() const size_t TraceLog::getApproxLogSize() const
{ {
return (m_base->writeFileNum - m_base->readFileNum + 1) * return (m_base->writeFileNum - m_base->readFileNum + 1) *
(MAX_LOG_FILE_SIZE / (1024 * 1024)); (MAX_LOG_FILE_SIZE / (1024 * 1024));
} }
void TraceLogImpl::checkMutex(const TEXT* string, int state) void TraceLog::checkMutex(const TEXT* string, int state)
{ {
if (state) if (state)
{ {
TEXT msg[BUFFER_TINY]; 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); gds__log(msg);
fprintf(stderr, "%s\n", 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 #ifdef WIN_NT
checkMutex("init", ISC_mutex_init(&log->m_mutex, shmemData->sh_mem_name)); 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 #ifdef WIN_NT
checkMutex("lock", ISC_mutex_lock(&m_mutex)); checkMutex("lock", ISC_mutex_lock(&m_mutex));
@ -270,7 +269,7 @@ void TraceLogImpl::lock()
#endif #endif
} }
void TraceLogImpl::unlock() void TraceLog::unlock()
{ {
#ifdef WIN_NT #ifdef WIN_NT
checkMutex("unlock", ISC_mutex_unlock(&m_mutex)); checkMutex("unlock", ISC_mutex_unlock(&m_mutex));

View File

@ -29,21 +29,18 @@
#define TRACE_LOG #define TRACE_LOG
#include "../../common/classes/fb_string.h" #include "../../common/classes/fb_string.h"
#include "../../jrd/ntrace.h"
#include "../../jrd/isc.h" #include "../../jrd/isc.h"
namespace Jrd { namespace Jrd {
class TraceLogImpl : public TraceLogWriter class TraceLog
{ {
public: public:
TraceLogImpl(Firebird::MemoryPool& pool, const Firebird::PathName& fileName, bool reader); TraceLog(Firebird::MemoryPool& pool, const Firebird::PathName& fileName, bool reader);
virtual ~TraceLogImpl(); virtual ~TraceLog();
size_t read(void* buf, size_t size); size_t read(void* buf, size_t size);
virtual size_t write(const void* buf, size_t size); size_t write(const void* buf, size_t size);
virtual void release()
{ delete this; }
// returns approximate log size in MB // returns approximate log size in MB
size_t getApproxLogSize() const; size_t getApproxLogSize() const;
@ -78,25 +75,22 @@ private:
int m_fileHandle; int m_fileHandle;
bool m_reader; bool m_reader;
friend class TraceLogGuard; class TraceLogGuard
};
class TraceLogGuard
{
public:
explicit TraceLogGuard(TraceLogImpl* log) : m_log(*log)
{ {
m_log.lock(); public:
} explicit TraceLogGuard(TraceLog* log) : m_log(*log)
{
m_log.lock();
}
~TraceLogGuard() ~TraceLogGuard()
{ {
m_log.unlock(); m_log.unlock();
} }
private: private:
TraceLogImpl& m_log; TraceLog& m_log;
};
}; };

View File

@ -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 /// TraceInitInfoImpl
const char* TraceInitInfoImpl::getFirebirdRootDirectory() const char* TraceInitInfoImpl::getFirebirdRootDirectory()
@ -404,7 +462,7 @@ TraceLogWriter* TraceInitInfoImpl::getLogWriter()
if (!m_logWriter && !m_session.ses_logfile.empty()) if (!m_logWriter && !m_session.ses_logfile.empty())
{ {
MemoryPool &pool = *getDefaultMemoryPool(); 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; return m_logWriter;
} }

View File

@ -67,7 +67,7 @@ public:
private: private:
bool changeFlags(ULONG id, int setFlags, int clearFlags); bool changeFlags(ULONG id, int setFlags, int clearFlags);
bool checkAlive(ULONG sesId); bool checkAliveAndFlags(ULONG sesId, int& flags);
Service& m_svc; Service& m_svc;
string m_user; string m_user;
@ -84,8 +84,7 @@ void TraceSvcJrd::setAttachInfo(const string& /*service_name*/, const string& us
void TraceSvcJrd::startSession(TraceSession& session, bool interactive) void TraceSvcJrd::startSession(TraceSession& session, bool interactive)
{ {
TraceManager* mgr = m_svc.getTraceManager(); ConfigStorage* storage = TraceManager::getStorage();
ConfigStorage* storage = mgr->getStorage();
{ // scope { // scope
StorageGuard guard(storage); StorageGuard guard(storage);
@ -106,7 +105,6 @@ void TraceSvcJrd::startSession(TraceSession& session, bool interactive)
GuidToString(buff, &guid); GuidToString(buff, &guid);
session.ses_logfile.insert(0, "fb_trace."); session.ses_logfile.insert(0, "fb_trace.");
// session.ses_logfile = TempFile::create("fb_trace_");
} }
storage->addSession(session); storage->addSession(session);
@ -122,7 +120,6 @@ void TraceSvcJrd::startSession(TraceSession& session, bool interactive)
StorageGuard guard(storage); StorageGuard guard(storage);
storage->removeSession(session.ses_id); storage->removeSession(session.ses_id);
} }
// unlink(session.ses_logfile.c_str());
} }
else { else {
m_svc.printf("Trace session ID %ld started\n", session.ses_id); 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) void TraceSvcJrd::stopSession(ULONG id)
{ {
m_svc.started(); m_svc.started();
TraceManager* mgr = m_svc.getTraceManager();
ConfigStorage* storage = mgr->getStorage(); ConfigStorage* storage = TraceManager::getStorage();
StorageGuard guard(storage); StorageGuard guard(storage);
storage->restart(); storage->restart();
@ -177,10 +173,7 @@ void TraceSvcJrd::setActive(ULONG id, bool active)
bool TraceSvcJrd::changeFlags(ULONG id, int setFlags, int clearFlags) bool TraceSvcJrd::changeFlags(ULONG id, int setFlags, int clearFlags)
{ {
m_svc.started(); ConfigStorage* storage = TraceManager::getStorage();
TraceManager* mgr = m_svc.getTraceManager();
ConfigStorage* storage = mgr->getStorage();
StorageGuard guard(storage); StorageGuard guard(storage);
storage->restart(); storage->restart();
@ -193,10 +186,14 @@ bool TraceSvcJrd::changeFlags(ULONG id, int setFlags, int clearFlags)
if (m_admin || m_user == session.ses_user) if (m_admin || m_user == session.ses_user)
{ {
const int saveFlags = session.ses_flags;
session.ses_flags |= setFlags; session.ses_flags |= setFlags;
session.ses_flags &= ~clearFlags; session.ses_flags &= ~clearFlags;
storage->updateSession(session); if (saveFlags != session.ses_flags) {
storage->updateSession(session);
}
return true; return true;
} }
else else
@ -214,9 +211,7 @@ void TraceSvcJrd::listSessions()
{ {
m_svc.started(); m_svc.started();
TraceManager* mgr = m_svc.getTraceManager(); ConfigStorage* storage = TraceManager::getStorage();
ConfigStorage* storage = mgr->getStorage();
StorageGuard guard(storage); StorageGuard guard(storage);
storage->restart(); storage->restart();
@ -266,9 +261,6 @@ void TraceSvcJrd::listSessions()
void TraceSvcJrd::readSession(TraceSession& session) 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 const size_t maxLogSize = Config::getMaxUserTraceLogSize(); // in MB
if (session.ses_logfile.empty()) if (session.ses_logfile.empty())
@ -278,16 +270,16 @@ void TraceSvcJrd::readSession(TraceSession& session)
} }
MemoryPool& pool = *getDefaultMemoryPool(); 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]; 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)); size_t len = log->read(buff, sizeof(buff));
if (!len) if (!len)
{ {
if (!checkAlive(session.ses_id)) if (!checkAliveAndFlags(session.ses_id, flags))
break; break;
THD_sleep(250); THD_sleep(250);
@ -296,24 +288,19 @@ void TraceSvcJrd::readSession(TraceSession& session)
{ {
m_svc.putBytes(buff, len); 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); 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 = TraceManager::getStorage();
ConfigStorage* storage = mgr->getStorage();
bool alive = (m_chg_number == storage->getChangeNumber()); bool alive = (m_chg_number == storage->getChangeNumber());
if (!alive) if (!alive)
@ -328,6 +315,7 @@ bool TraceSvcJrd::checkAlive(ULONG sesId)
if (readSession.ses_id == sesId) if (readSession.ses_id == sesId)
{ {
alive = true; alive = true;
flags = readSession.ses_flags;
break; break;
} }
} }