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 {
|
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));
|
||||||
|
@ -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;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user