8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-01-31 14:03:04 +01:00
firebird-mirror/src/jrd/trace/TraceService.cpp

351 lines
7.7 KiB
C++
Raw Normal View History

2009-02-01 23:07:35 +01:00
/*
* MODULE: TraceService.cpp
2009-04-04 18:39:31 +02:00
* DESCRIPTION:
2009-02-01 23:07:35 +01:00
*
* The contents of this file are subject to the Initial
* Developer's Public License Version 1.0 (the "License");
* you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
* http://www.ibphoenix.com/main.nfs?a=ibphoenix&page=ibp_idpl.
*
* Software distributed under the License is distributed AS IS,
* WITHOUT WARRANTY OF ANY KIND, either express or implied.
* See the License for the specific language governing rights
* and limitations under the License.
*
* The Original Code was created by Khorsun Vladyslav
* for the Firebird Open Source RDBMS project.
*
* Copyright (c) 2008 Khorsun Vladyslav <hvlad@users.sourceforge.net>
* and all contributors signed below.
*
* All Rights Reserved.
* Contributor(s): ______________________________________.
*
*/
#include "firebird.h"
#include "consts_pub.h"
#include "fb_exception.h"
#include "iberror.h"
#include "../../jrd/ibase.h"
#include "../../common/classes/fb_string.h"
2009-02-02 16:23:50 +01:00
#include "../../common/classes/timestamp.h"
2009-02-01 23:07:35 +01:00
#include "../../common/config/config.h"
#include "../../common/StatusArg.h"
#include "../../common/thd.h"
2009-02-02 16:23:50 +01:00
#include "../../jrd/ThreadData.h"
2009-02-01 23:07:35 +01:00
#include "../../jrd/svc.h"
#include "../../jrd/os/guid.h"
#include "../../jrd/trace/TraceLog.h"
#include "../../jrd/trace/TraceManager.h"
#include "../../jrd/trace/TraceService.h"
using namespace Firebird;
using namespace Jrd;
class TraceSvcJrd : public TraceSvcIntf
{
public:
2009-04-04 18:39:31 +02:00
explicit TraceSvcJrd(Service& svc) :
2009-02-02 15:46:24 +01:00
m_svc(svc),
m_admin(false),
m_chg_number(0)
2009-02-01 23:07:35 +01:00
{};
virtual ~TraceSvcJrd() {};
2009-04-04 18:39:31 +02:00
virtual void setAttachInfo(const string& service_name, const string& user,
2009-02-02 15:46:24 +01:00
const string& pwd, bool isAdmin);
2009-02-01 23:07:35 +01:00
2009-02-02 15:46:24 +01:00
virtual void startSession(TraceSession& session, bool interactive);
2009-02-01 23:07:35 +01:00
virtual void stopSession(ULONG id);
virtual void setActive(ULONG id, bool active);
virtual void listSessions();
2009-02-02 15:46:24 +01:00
virtual void readSession(TraceSession& session);
2009-02-01 23:07:35 +01:00
private:
bool changeFlags(ULONG id, int setFlags, int clearFlags);
bool checkAliveAndFlags(ULONG sesId, int& flags);
2009-02-01 23:07:35 +01:00
2009-02-02 15:46:24 +01:00
Service& m_svc;
2009-02-01 23:07:35 +01:00
string m_user;
bool m_admin;
ULONG m_chg_number;
};
2009-04-04 18:39:31 +02:00
void TraceSvcJrd::setAttachInfo(const string& /*service_name*/, const string& user,
2009-02-02 15:46:24 +01:00
const string& /*pwd*/, bool isAdmin)
2009-02-01 23:07:35 +01:00
{
m_user = user;
m_admin = isAdmin || (m_user == SYSDBA_USER_NAME);
}
2009-02-02 15:46:24 +01:00
void TraceSvcJrd::startSession(TraceSession& session, bool interactive)
2009-02-01 23:07:35 +01:00
{
ConfigStorage* storage = TraceManager::getStorage();
2009-02-01 23:07:35 +01:00
2009-02-02 15:46:24 +01:00
{ // scope
2009-02-01 23:07:35 +01:00
StorageGuard guard(storage);
session.ses_user = m_user;
session.ses_flags = trs_active;
if (m_admin) {
session.ses_flags |= trs_admin;
}
2009-02-02 15:46:24 +01:00
2009-04-04 18:39:31 +02:00
if (interactive)
2009-02-01 23:07:35 +01:00
{
FB_GUID guid;
GenerateGuid(&guid);
2009-02-02 15:46:24 +01:00
char* buff = session.ses_logfile.getBuffer(GUID_BUFF_SIZE);
2009-02-01 23:07:35 +01:00
GuidToString(buff, &guid);
2009-04-04 18:39:31 +02:00
2009-02-01 23:07:35 +01:00
session.ses_logfile.insert(0, "fb_trace.");
}
storage->addSession(session);
m_chg_number = storage->getChangeNumber();
}
m_svc.started();
2009-04-04 18:39:31 +02:00
if (interactive)
2009-02-01 23:07:35 +01:00
{
readSession(session);
{
StorageGuard guard(storage);
storage->removeSession(session.ses_id);
}
}
else {
m_svc.printf("Trace session ID %ld started\n", session.ses_id);
}
}
void TraceSvcJrd::stopSession(ULONG id)
{
m_svc.started();
ConfigStorage* storage = TraceManager::getStorage();
2009-02-01 23:07:35 +01:00
StorageGuard guard(storage);
storage->restart();
2009-04-04 18:39:31 +02:00
2009-02-01 23:07:35 +01:00
TraceSession session(*getDefaultMemoryPool());
while (storage->getNextSession(session))
{
if (id != session.ses_id)
continue;
if (m_admin || m_user == session.ses_user)
{
storage->removeSession(id);
m_svc.printf("Trace session ID %ld stopped\n", id);
}
else
2009-02-05 15:50:57 +01:00
m_svc.printf("No permissions to stop other user trace session\n");
2009-02-01 23:07:35 +01:00
return;
}
m_svc.printf("Trace session ID %d not found\n", id);
}
void TraceSvcJrd::setActive(ULONG id, bool active)
{
if (active)
{
if (changeFlags(id, trs_active, 0)) {
m_svc.printf("Trace session ID %ld resumed\n", id);
}
}
else
{
if (changeFlags(id, 0, trs_active)) {
m_svc.printf("Trace session ID %ld paused\n", id);
}
}
}
bool TraceSvcJrd::changeFlags(ULONG id, int setFlags, int clearFlags)
{
ConfigStorage* storage = TraceManager::getStorage();
2009-02-01 23:07:35 +01:00
StorageGuard guard(storage);
storage->restart();
2009-04-04 18:39:31 +02:00
2009-02-01 23:07:35 +01:00
TraceSession session(*getDefaultMemoryPool());
while (storage->getNextSession(session))
{
if (id != session.ses_id)
continue;
if (m_admin || m_user == session.ses_user)
{
const int saveFlags = session.ses_flags;
2009-02-01 23:07:35 +01:00
session.ses_flags |= setFlags;
session.ses_flags &= ~clearFlags;
if (saveFlags != session.ses_flags) {
storage->updateSession(session);
}
2009-02-13 22:08:56 +01:00
2009-02-01 23:07:35 +01:00
return true;
}
2009-02-13 08:48:28 +01:00
m_svc.printf("No permissions to change other user trace session\n");
return false;
2009-02-01 23:07:35 +01:00
}
m_svc.printf("Trace session ID %d not found\n", id);
return false;
}
void TraceSvcJrd::listSessions()
{
m_svc.started();
2009-04-04 18:39:31 +02:00
ConfigStorage* storage = TraceManager::getStorage();
2009-02-01 23:07:35 +01:00
StorageGuard guard(storage);
storage->restart();
TraceSession session(*getDefaultMemoryPool());
while (storage->getNextSession(session))
{
if (m_admin || m_user == session.ses_user)
{
m_svc.printf("\nSession ID: %d\n", session.ses_id);
if (!session.ses_name.empty()) {
m_svc.printf(" name: %s\n", session.ses_name.c_str());
}
m_svc.printf(" user: %s\n", session.ses_user.c_str());
2009-04-04 18:39:31 +02:00
2009-02-02 15:46:24 +01:00
struct tm* t = localtime(&session.ses_start);
2009-02-01 23:07:35 +01:00
m_svc.printf(" date: %04d-%02d-%02d %02d:%02d:%02d\n",
t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,
t->tm_hour, t->tm_min, t->tm_sec);
string flags;
if (session.ses_flags & trs_active) {
flags = "active";
}
else {
flags = "suspend";
}
if (session.ses_flags & trs_admin) {
flags += ", admin";
}
if (session.ses_flags & trs_system) {
flags += ", system";
}
if (session.ses_logfile.empty()) {
flags += ", audit";
}
else {
flags += ", trace";
}
if (session.ses_flags & trs_log_full) {
flags += ", log full";
}
m_svc.printf(" flags: %s\n", flags.c_str());
}
}
}
2009-02-02 15:46:24 +01:00
void TraceSvcJrd::readSession(TraceSession& session)
2009-02-01 23:07:35 +01:00
{
const size_t maxLogSize = Config::getMaxUserTraceLogSize(); // in MB
if (session.ses_logfile.empty())
{
m_svc.printf("Can't open trace data log file");
return;
}
2009-02-02 15:46:24 +01:00
MemoryPool& pool = *getDefaultMemoryPool();
AutoPtr<TraceLog> log(FB_NEW(pool) TraceLog(pool, session.ses_logfile, true));
2009-02-01 23:07:35 +01:00
UCHAR buff[1024];
int flags = session.ses_flags;
while (!m_svc.finished() && checkAliveAndFlags(session.ses_id, flags))
2009-02-01 23:07:35 +01:00
{
2009-04-04 18:39:31 +02:00
size_t len = log->read(buff, sizeof(buff));
2009-02-01 23:07:35 +01:00
if (!len)
{
if (!checkAliveAndFlags(session.ses_id, flags))
2009-02-01 23:07:35 +01:00
break;
THD_sleep(250);
2009-02-01 23:07:35 +01:00
}
else
{
m_svc.putBytes(buff, len);
const bool logFull = (flags & trs_log_full);
2009-04-04 18:39:31 +02:00
if (logFull && log->getApproxLogSize() <= maxLogSize)
2009-02-01 23:07:35 +01:00
{
// resume session
2009-02-01 23:07:35 +01:00
changeFlags(session.ses_id, 0, trs_log_full);
}
}
}
}
bool TraceSvcJrd::checkAliveAndFlags(ULONG sesId, int& flags)
2009-02-01 23:07:35 +01:00
{
ConfigStorage* storage = TraceManager::getStorage();
2009-02-01 23:07:35 +01:00
bool alive = (m_chg_number == storage->getChangeNumber());
if (!alive)
{
// look if our session still alive
StorageGuard guard(storage);
TraceSession readSession(*getDefaultMemoryPool());
storage->restart();
while (storage->getNextSession(readSession))
2009-02-02 15:46:24 +01:00
{
2009-02-01 23:07:35 +01:00
if (readSession.ses_id == sesId)
{
alive = true;
flags = readSession.ses_flags;
2009-02-01 23:07:35 +01:00
break;
}
2009-02-02 15:46:24 +01:00
}
2009-02-01 23:07:35 +01:00
m_chg_number = storage->getChangeNumber();
}
return alive;
}
// service entrypoint
THREAD_ENTRY_DECLARE TRACE_main(THREAD_ENTRY_PARAM arg)
{
2009-02-05 02:08:13 +01:00
Service* svc = (Service*) arg;
2009-02-01 23:07:35 +01:00
int exit_code = FB_SUCCESS;
TraceSvcJrd traceSvc(*svc);
2009-02-02 15:46:24 +01:00
try
{
2009-02-05 15:44:11 +01:00
fbtrace(svc, &traceSvc);
2009-02-01 23:07:35 +01:00
}
catch (const Exception& e)
{
e.stuff_exception(svc->getStatus());
exit_code = FB_FAILURE;
}
svc->started();
svc->finish();
return (THREAD_ENTRY_RETURN)(IPTR) exit_code;
}