2006-07-17 19:44:18 +02: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 Dmitry Yemanov
|
|
|
|
* for the Firebird Open Source RDBMS project.
|
|
|
|
*
|
|
|
|
* Copyright (c) 2006 Dmitry Yemanov <dimitr@users.sf.net>
|
|
|
|
* and all contributors signed below.
|
|
|
|
*
|
|
|
|
* All Rights Reserved.
|
|
|
|
* Contributor(s): ______________________________________.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "firebird.h"
|
|
|
|
#include "ids.h"
|
2006-10-30 13:39:08 +01:00
|
|
|
|
|
|
|
#include "../common/classes/auto.h"
|
|
|
|
#include "../common/classes/locks.h"
|
2012-12-14 18:59:02 +01:00
|
|
|
#include "../common/classes/fb_string.h"
|
2006-10-30 13:39:08 +01:00
|
|
|
|
2010-10-13 12:39:52 +02:00
|
|
|
#include "../common/gdsassert.h"
|
2006-07-17 19:44:18 +02:00
|
|
|
#include "../jrd/jrd.h"
|
|
|
|
#include "../jrd/cch.h"
|
|
|
|
#include "../jrd/ini.h"
|
2007-09-14 17:39:53 +02:00
|
|
|
#include "../jrd/nbak.h"
|
2006-07-17 19:44:18 +02:00
|
|
|
#include "../jrd/req.h"
|
|
|
|
#include "../jrd/tra.h"
|
|
|
|
#include "../jrd/blb_proto.h"
|
2010-10-12 10:02:57 +02:00
|
|
|
#include "../common/isc_proto.h"
|
|
|
|
#include "../common/isc_f_proto.h"
|
|
|
|
#include "../common/isc_s_proto.h"
|
2006-10-30 13:39:08 +01:00
|
|
|
#include "../jrd/lck_proto.h"
|
2006-07-17 19:44:18 +02:00
|
|
|
#include "../jrd/met_proto.h"
|
2009-07-06 11:19:26 +02:00
|
|
|
#include "../jrd/mov_proto.h"
|
2014-06-10 15:32:29 +02:00
|
|
|
#include "../jrd/opt_proto.h"
|
2006-12-04 22:36:29 +01:00
|
|
|
#include "../jrd/pag_proto.h"
|
2012-05-31 18:53:42 +02:00
|
|
|
#include "../jrd/CryptoManager.h"
|
2006-07-17 19:44:18 +02:00
|
|
|
|
|
|
|
#include "../jrd/Relation.h"
|
|
|
|
#include "../jrd/RecordBuffer.h"
|
2014-07-31 10:56:53 +02:00
|
|
|
#include "../jrd/Monitoring.h"
|
2009-12-21 18:43:01 +01:00
|
|
|
#include "../jrd/Function.h"
|
2006-07-17 19:44:18 +02:00
|
|
|
|
2014-07-31 23:15:33 +02:00
|
|
|
#ifdef WIN_NT
|
|
|
|
#include <process.h>
|
|
|
|
#define getpid _getpid
|
|
|
|
#endif
|
|
|
|
|
2014-07-31 10:56:53 +02:00
|
|
|
const char* const SCRATCH = "fb_monitor_";
|
2006-10-30 13:39:08 +01:00
|
|
|
|
|
|
|
using namespace Firebird;
|
2006-07-17 19:44:18 +02:00
|
|
|
using namespace Jrd;
|
|
|
|
|
2006-10-30 13:39:08 +01:00
|
|
|
|
2011-02-15 09:47:51 +01:00
|
|
|
const Format* MonitoringTableScan::getFormat(thread_db* tdbb, jrd_rel* relation) const
|
|
|
|
{
|
2014-07-31 10:56:53 +02:00
|
|
|
MonitoringSnapshot* const snapshot = MonitoringSnapshot::create(tdbb);
|
2011-02-15 09:47:51 +01:00
|
|
|
return snapshot->getData(relation)->getFormat();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-07-13 14:31:35 +02:00
|
|
|
bool MonitoringTableScan::retrieveRecord(thread_db* tdbb, jrd_rel* relation,
|
|
|
|
FB_UINT64 position, Record* record) const
|
|
|
|
{
|
2014-07-31 10:56:53 +02:00
|
|
|
MonitoringSnapshot* const snapshot = MonitoringSnapshot::create(tdbb);
|
2010-07-13 14:31:35 +02:00
|
|
|
return snapshot->getData(relation)->fetch(position, record);
|
|
|
|
}
|
|
|
|
|
2006-10-30 13:39:08 +01:00
|
|
|
|
2010-07-13 14:31:35 +02:00
|
|
|
// MonitoringData class
|
|
|
|
|
|
|
|
MonitoringData::MonitoringData(const Database* dbb)
|
2006-10-30 13:39:08 +01:00
|
|
|
{
|
2009-01-29 18:44:21 +01:00
|
|
|
string name;
|
2009-01-28 13:27:18 +01:00
|
|
|
name.printf(MONITOR_FILE, dbb->getUniqueFileId().c_str());
|
2006-10-30 13:39:08 +01:00
|
|
|
|
2009-12-06 02:34:57 +01:00
|
|
|
Arg::StatusVector statusVector;
|
2012-11-01 12:40:18 +01:00
|
|
|
try
|
2006-10-30 13:39:08 +01:00
|
|
|
{
|
2014-07-31 10:56:53 +02:00
|
|
|
shared_memory.reset(FB_NEW(*dbb->dbb_permanent)
|
|
|
|
SharedMemory<MonitoringHeader>(name.c_str(), DEFAULT_SIZE, this));
|
2012-11-01 12:40:18 +01:00
|
|
|
}
|
|
|
|
catch (const Exception& ex)
|
|
|
|
{
|
|
|
|
iscLogException("MonitoringData: Cannot initialize the shared memory region", ex);
|
|
|
|
throw;
|
2006-10-30 13:39:08 +01:00
|
|
|
}
|
|
|
|
|
2015-01-22 11:35:57 +01:00
|
|
|
fb_assert(shared_memory->getHeader()->mhb_header_version == MemoryHeader::HEADER_VERSION);
|
2012-11-01 12:40:18 +01:00
|
|
|
fb_assert(shared_memory->getHeader()->mhb_version == MONITOR_VERSION);
|
2006-10-30 13:39:08 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-07-13 14:31:35 +02:00
|
|
|
MonitoringData::~MonitoringData()
|
2006-10-30 13:39:08 +01:00
|
|
|
{
|
2012-11-01 12:40:18 +01:00
|
|
|
Guard guard(this);
|
2009-01-28 13:27:18 +01:00
|
|
|
|
2012-11-01 12:40:18 +01:00
|
|
|
if (shared_memory->getHeader()->used == sizeof(Header))
|
|
|
|
shared_memory->removeMapFile();
|
2006-10-30 13:39:08 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-07-13 14:31:35 +02:00
|
|
|
void MonitoringData::acquire()
|
2006-10-30 13:39:08 +01:00
|
|
|
{
|
2012-11-01 12:40:18 +01:00
|
|
|
shared_memory->mutexLock();
|
2010-06-17 09:34:15 +02:00
|
|
|
|
2012-11-01 12:40:18 +01:00
|
|
|
if (shared_memory->getHeader()->allocated > shared_memory->sh_mem_length_mapped)
|
2008-02-06 14:47:08 +01:00
|
|
|
{
|
2010-06-25 13:55:11 +02:00
|
|
|
#ifdef HAVE_OBJECT_MAP
|
2009-12-06 02:34:57 +01:00
|
|
|
Arg::StatusVector statusVector;
|
2012-11-01 12:40:18 +01:00
|
|
|
shared_memory->remapFile(statusVector, shared_memory->getHeader()->allocated, false);
|
|
|
|
if (!shared_memory->remapFile(statusVector, shared_memory->getHeader()->allocated, false))
|
2008-02-06 14:47:08 +01:00
|
|
|
{
|
2008-12-20 09:12:19 +01:00
|
|
|
status_exception::raise(statusVector);
|
2008-02-06 14:47:08 +01:00
|
|
|
}
|
|
|
|
#else
|
2008-12-20 09:12:19 +01:00
|
|
|
status_exception::raise(Arg::Gds(isc_montabexh));
|
2008-02-06 14:47:08 +01:00
|
|
|
#endif
|
|
|
|
}
|
2006-10-30 13:39:08 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-07-13 14:31:35 +02:00
|
|
|
void MonitoringData::release()
|
2006-10-30 13:39:08 +01:00
|
|
|
{
|
2012-11-01 12:40:18 +01:00
|
|
|
shared_memory->mutexUnlock();
|
2006-10-30 13:39:08 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-07-31 10:56:53 +02:00
|
|
|
void MonitoringData::read(SLONG att_id, TempSpace& temp)
|
2006-10-30 13:39:08 +01:00
|
|
|
{
|
2014-07-31 10:56:53 +02:00
|
|
|
offset_t position = 0;
|
2008-12-24 14:34:12 +01:00
|
|
|
|
2014-07-31 10:56:53 +02:00
|
|
|
// First, find and copy data for the given session
|
2006-10-30 13:39:08 +01:00
|
|
|
|
2012-11-01 12:40:18 +01:00
|
|
|
for (ULONG offset = alignOffset(sizeof(Header)); offset < shared_memory->getHeader()->used;)
|
2008-12-11 12:58:50 +01:00
|
|
|
{
|
2012-11-01 12:40:18 +01:00
|
|
|
UCHAR* const ptr = (UCHAR*) shared_memory->getHeader() + offset;
|
2008-12-11 12:58:50 +01:00
|
|
|
const Element* const element = (Element*) ptr;
|
2009-07-20 15:44:02 +02:00
|
|
|
const ULONG length = alignOffset(sizeof(Element) + element->length);
|
2006-10-30 13:39:08 +01:00
|
|
|
|
2014-07-31 10:56:53 +02:00
|
|
|
if (element->attId == att_id)
|
2008-12-11 12:58:50 +01:00
|
|
|
{
|
2012-11-01 12:40:18 +01:00
|
|
|
fb_assert(shared_memory->getHeader()->used >= offset + length);
|
2014-07-31 10:56:53 +02:00
|
|
|
temp.write(position, ptr + sizeof(Element), element->length);
|
|
|
|
position += element->length;
|
2008-12-11 12:58:50 +01:00
|
|
|
}
|
2006-10-30 13:39:08 +01:00
|
|
|
|
2014-07-31 10:56:53 +02:00
|
|
|
offset += length;
|
|
|
|
}
|
2008-12-24 14:34:12 +01:00
|
|
|
|
2014-07-31 10:56:53 +02:00
|
|
|
// Second, copy data of other sessions
|
2008-12-24 14:34:12 +01:00
|
|
|
|
2012-11-01 12:40:18 +01:00
|
|
|
for (ULONG offset = alignOffset(sizeof(Header)); offset < shared_memory->getHeader()->used;)
|
2006-10-30 13:39:08 +01:00
|
|
|
{
|
2012-11-01 12:40:18 +01:00
|
|
|
UCHAR* const ptr = (UCHAR*) shared_memory->getHeader() + offset;
|
2008-12-11 12:58:50 +01:00
|
|
|
const Element* const element = (Element*) ptr;
|
2009-07-20 15:44:02 +02:00
|
|
|
const ULONG length = alignOffset(sizeof(Element) + element->length);
|
2008-12-11 12:58:50 +01:00
|
|
|
|
2014-07-31 10:56:53 +02:00
|
|
|
if (element->attId != att_id)
|
2008-12-24 14:34:12 +01:00
|
|
|
{
|
2014-07-31 10:56:53 +02:00
|
|
|
fb_assert(shared_memory->getHeader()->used >= offset + length);
|
|
|
|
temp.write(position, ptr + sizeof(Element), element->length);
|
|
|
|
position += element->length;
|
2008-12-24 14:34:12 +01:00
|
|
|
}
|
|
|
|
|
2008-12-11 12:58:50 +01:00
|
|
|
offset += length;
|
2006-10-30 13:39:08 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-07-31 10:56:53 +02:00
|
|
|
ULONG MonitoringData::setup(SLONG att_id)
|
2006-10-30 13:39:08 +01:00
|
|
|
{
|
2009-07-06 11:19:26 +02:00
|
|
|
ensureSpace(sizeof(Element));
|
|
|
|
|
2014-07-31 10:56:53 +02:00
|
|
|
// Prepare for writing new data at the tail
|
|
|
|
|
2012-11-01 12:40:18 +01:00
|
|
|
const ULONG offset = shared_memory->getHeader()->used;
|
|
|
|
UCHAR* const ptr = (UCHAR*) shared_memory->getHeader() + offset;
|
2009-07-06 11:19:26 +02:00
|
|
|
Element* const element = (Element*) ptr;
|
2014-07-31 10:56:53 +02:00
|
|
|
element->attId = att_id;
|
2009-07-06 11:19:26 +02:00
|
|
|
element->length = 0;
|
2012-11-01 12:40:18 +01:00
|
|
|
shared_memory->getHeader()->used += alignOffset(sizeof(Element));
|
2009-07-06 11:19:26 +02:00
|
|
|
return offset;
|
|
|
|
}
|
2006-10-31 16:49:31 +01:00
|
|
|
|
2006-10-30 13:39:08 +01:00
|
|
|
|
2010-07-13 14:31:35 +02:00
|
|
|
void MonitoringData::write(ULONG offset, ULONG length, const void* buffer)
|
2009-07-06 11:19:26 +02:00
|
|
|
{
|
|
|
|
ensureSpace(length);
|
2008-12-11 12:58:50 +01:00
|
|
|
|
2014-07-31 10:56:53 +02:00
|
|
|
// Write data item at the tail
|
|
|
|
|
2012-11-01 12:40:18 +01:00
|
|
|
UCHAR* const ptr = (UCHAR*) shared_memory->getHeader() + offset;
|
2008-12-11 12:58:50 +01:00
|
|
|
Element* const element = (Element*) ptr;
|
2009-07-06 11:19:26 +02:00
|
|
|
memcpy(ptr + sizeof(Element) + element->length, buffer, length);
|
2009-07-20 15:44:02 +02:00
|
|
|
ULONG previous = alignOffset(sizeof(Element) + element->length);
|
2009-07-06 11:19:26 +02:00
|
|
|
element->length += length;
|
2009-07-20 15:44:02 +02:00
|
|
|
ULONG current = alignOffset(sizeof(Element) + element->length);
|
2012-11-01 12:40:18 +01:00
|
|
|
shared_memory->getHeader()->used += (current - previous);
|
2006-10-30 13:39:08 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-07-31 10:56:53 +02:00
|
|
|
void MonitoringData::cleanup(SLONG att_id)
|
2008-12-12 17:04:57 +01:00
|
|
|
{
|
2014-07-31 10:56:53 +02:00
|
|
|
// Remove information about the given session
|
|
|
|
|
2012-11-01 12:40:18 +01:00
|
|
|
for (ULONG offset = alignOffset(sizeof(Header)); offset < shared_memory->getHeader()->used;)
|
2008-12-12 17:04:57 +01:00
|
|
|
{
|
2012-11-01 12:40:18 +01:00
|
|
|
UCHAR* const ptr = (UCHAR*) shared_memory->getHeader() + offset;
|
2008-12-12 17:04:57 +01:00
|
|
|
const Element* const element = (Element*) ptr;
|
2009-07-20 15:44:02 +02:00
|
|
|
const ULONG length = alignOffset(sizeof(Element) + element->length);
|
2008-12-12 17:04:57 +01:00
|
|
|
|
2014-07-31 10:56:53 +02:00
|
|
|
if (element->attId == att_id)
|
2008-12-12 17:04:57 +01:00
|
|
|
{
|
2012-11-01 12:40:18 +01:00
|
|
|
fb_assert(shared_memory->getHeader()->used >= offset + length);
|
|
|
|
memmove(ptr, ptr + length, shared_memory->getHeader()->used - offset - length);
|
|
|
|
shared_memory->getHeader()->used -= length;
|
2008-12-12 17:04:57 +01:00
|
|
|
}
|
2008-12-13 10:19:55 +01:00
|
|
|
else
|
2008-12-16 12:02:25 +01:00
|
|
|
{
|
2008-12-13 10:19:55 +01:00
|
|
|
offset += length;
|
2008-12-16 12:02:25 +01:00
|
|
|
}
|
2008-12-12 17:04:57 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-07-31 10:56:53 +02:00
|
|
|
void MonitoringData::enumerate(SessionList& sessions)
|
|
|
|
{
|
|
|
|
// Return IDs for all known sessions
|
|
|
|
|
|
|
|
for (ULONG offset = alignOffset(sizeof(Header)); offset < shared_memory->getHeader()->used;)
|
|
|
|
{
|
|
|
|
UCHAR* const ptr = (UCHAR*) shared_memory->getHeader() + offset;
|
|
|
|
const Element* const element = (Element*) ptr;
|
|
|
|
const ULONG length = alignOffset(sizeof(Element) + element->length);
|
|
|
|
offset += length;
|
|
|
|
|
|
|
|
sessions.add(element->attId);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-07-13 14:31:35 +02:00
|
|
|
void MonitoringData::ensureSpace(ULONG length)
|
2006-10-30 13:39:08 +01:00
|
|
|
{
|
2012-11-01 12:40:18 +01:00
|
|
|
ULONG newSize = shared_memory->getHeader()->used + length;
|
2008-02-06 14:47:08 +01:00
|
|
|
|
2012-11-01 12:40:18 +01:00
|
|
|
if (newSize > shared_memory->getHeader()->allocated)
|
2008-02-06 14:47:08 +01:00
|
|
|
{
|
2014-07-28 15:01:10 +02:00
|
|
|
newSize = FB_ALIGN(newSize, DEFAULT_SIZE);
|
2009-07-06 11:19:26 +02:00
|
|
|
|
2010-06-25 13:55:11 +02:00
|
|
|
#ifdef HAVE_OBJECT_MAP
|
2009-12-06 02:34:57 +01:00
|
|
|
Arg::StatusVector statusVector;
|
2012-11-01 12:40:18 +01:00
|
|
|
if (!shared_memory->remapFile(statusVector, newSize, true))
|
2009-07-06 11:19:26 +02:00
|
|
|
{
|
|
|
|
status_exception::raise(statusVector);
|
|
|
|
}
|
2012-11-01 12:40:18 +01:00
|
|
|
shared_memory->getHeader()->allocated = shared_memory->sh_mem_length_mapped;
|
2008-02-06 14:47:08 +01:00
|
|
|
#else
|
2009-07-06 11:19:26 +02:00
|
|
|
status_exception::raise(Arg::Gds(isc_montabexh));
|
2008-02-06 14:47:08 +01:00
|
|
|
#endif
|
2009-07-06 11:19:26 +02:00
|
|
|
}
|
2006-10-30 13:39:08 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-12-14 18:59:02 +01:00
|
|
|
void MonitoringData::mutexBug(int osErrorCode, const char* s)
|
2006-10-30 13:39:08 +01:00
|
|
|
{
|
2012-12-14 18:59:02 +01:00
|
|
|
string msg;
|
|
|
|
msg.printf("MONITOR: mutex %s error, status = %d", s, osErrorCode);
|
|
|
|
fb_utils::logAndDie(msg.c_str());
|
2006-10-30 13:39:08 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-11-01 12:40:18 +01:00
|
|
|
bool MonitoringData::initialize(SharedMemoryBase* sm, bool initialize)
|
2006-10-30 13:39:08 +01:00
|
|
|
{
|
2010-06-25 13:55:11 +02:00
|
|
|
if (initialize)
|
2010-06-17 09:34:15 +02:00
|
|
|
{
|
2012-11-01 12:40:18 +01:00
|
|
|
MonitoringHeader* header = reinterpret_cast<MonitoringHeader*>(sm->sh_mem_header);
|
|
|
|
|
2010-06-25 13:55:11 +02:00
|
|
|
// Initialize the shared data header
|
2015-01-22 11:35:57 +01:00
|
|
|
header->init(SharedMemoryBase::SRAM_DATABASE_SNAPSHOT, MONITOR_VERSION);
|
2006-10-30 13:39:08 +01:00
|
|
|
|
2012-11-01 12:40:18 +01:00
|
|
|
header->used = alignOffset(sizeof(Header));
|
|
|
|
header->allocated = sm->sh_mem_length_mapped;
|
2010-06-25 13:55:11 +02:00
|
|
|
}
|
2006-10-30 13:39:08 +01:00
|
|
|
|
2010-06-25 13:55:11 +02:00
|
|
|
return true;
|
2006-10-30 13:39:08 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-07-13 14:31:35 +02:00
|
|
|
ULONG MonitoringData::alignOffset(ULONG unaligned)
|
2009-07-20 15:44:02 +02:00
|
|
|
{
|
2010-07-13 14:31:35 +02:00
|
|
|
return (ULONG) Firebird::MEM_ALIGN(unaligned);
|
2009-07-20 15:44:02 +02:00
|
|
|
}
|
|
|
|
|
2010-07-13 14:31:35 +02:00
|
|
|
|
2014-07-31 10:56:53 +02:00
|
|
|
// MonitoringSnapshot class
|
2006-10-30 13:39:08 +01:00
|
|
|
|
2006-07-17 21:26:43 +02:00
|
|
|
|
2014-07-31 10:56:53 +02:00
|
|
|
MonitoringSnapshot* MonitoringSnapshot::create(thread_db* tdbb)
|
2006-07-17 19:44:18 +02:00
|
|
|
{
|
2006-07-18 08:00:52 +02:00
|
|
|
SET_TDBB(tdbb);
|
|
|
|
|
2007-12-03 16:46:39 +01:00
|
|
|
jrd_tra* transaction = tdbb->getTransaction();
|
2006-07-17 19:44:18 +02:00
|
|
|
fb_assert(transaction);
|
|
|
|
|
2014-07-31 10:56:53 +02:00
|
|
|
if (!transaction->tra_mon_snapshot)
|
2006-10-30 13:39:08 +01:00
|
|
|
{
|
|
|
|
// Create a database snapshot and store it
|
|
|
|
// in the transaction block
|
2006-07-17 19:44:18 +02:00
|
|
|
MemoryPool& pool = *transaction->tra_pool;
|
2014-07-31 10:56:53 +02:00
|
|
|
transaction->tra_mon_snapshot = FB_NEW(pool) MonitoringSnapshot(tdbb, pool);
|
2007-07-16 17:26:04 +02:00
|
|
|
}
|
2013-11-17 15:24:17 +01:00
|
|
|
|
2014-07-31 10:56:53 +02:00
|
|
|
return transaction->tra_mon_snapshot;
|
2013-11-17 15:24:17 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-07-31 10:56:53 +02:00
|
|
|
MonitoringSnapshot::MonitoringSnapshot(thread_db* tdbb, MemoryPool& pool)
|
|
|
|
: SnapshotData(pool)
|
2006-10-30 13:39:08 +01:00
|
|
|
{
|
2008-12-11 12:58:50 +01:00
|
|
|
SET_TDBB(tdbb);
|
|
|
|
|
2008-07-09 10:40:31 +02:00
|
|
|
PAG_header(tdbb, true);
|
2008-05-06 11:06:04 +02:00
|
|
|
|
2008-03-26 15:04:04 +01:00
|
|
|
Database* const dbb = tdbb->getDatabase();
|
|
|
|
fb_assert(dbb);
|
|
|
|
|
2013-09-22 18:10:06 +02:00
|
|
|
Attachment* const attachment = tdbb->getAttachment();
|
|
|
|
fb_assert(attachment);
|
|
|
|
|
2014-07-31 10:56:53 +02:00
|
|
|
const SLONG self_att_id = attachment->att_attachment_id;
|
|
|
|
|
2006-10-30 13:39:08 +01:00
|
|
|
// Initialize record buffers
|
2009-11-27 03:33:40 +01:00
|
|
|
RecordBuffer* const dbb_buffer = allocBuffer(tdbb, pool, rel_mon_database);
|
|
|
|
RecordBuffer* const att_buffer = allocBuffer(tdbb, pool, rel_mon_attachments);
|
|
|
|
RecordBuffer* const tra_buffer = allocBuffer(tdbb, pool, rel_mon_transactions);
|
|
|
|
RecordBuffer* const stmt_buffer = allocBuffer(tdbb, pool, rel_mon_statements);
|
|
|
|
RecordBuffer* const call_buffer = allocBuffer(tdbb, pool, rel_mon_calls);
|
|
|
|
RecordBuffer* const io_stat_buffer = allocBuffer(tdbb, pool, rel_mon_io_stats);
|
|
|
|
RecordBuffer* const rec_stat_buffer = allocBuffer(tdbb, pool, rel_mon_rec_stats);
|
|
|
|
RecordBuffer* const ctx_var_buffer = allocBuffer(tdbb, pool, rel_mon_ctx_vars);
|
|
|
|
RecordBuffer* const mem_usage_buffer = allocBuffer(tdbb, pool, rel_mon_mem_usage);
|
2014-09-30 19:35:44 +02:00
|
|
|
RecordBuffer* const tab_stat_buffer = allocBuffer(tdbb, pool, rel_mon_tab_stats);
|
2006-10-30 13:39:08 +01:00
|
|
|
|
2014-08-10 22:11:41 +02:00
|
|
|
// Dump our own data and downgrade the lock, if required
|
2007-07-16 16:41:39 +02:00
|
|
|
|
2014-07-31 10:56:53 +02:00
|
|
|
Monitoring::dumpAttachment(tdbb, attachment, false);
|
2009-07-06 11:19:26 +02:00
|
|
|
|
2014-08-10 22:11:41 +02:00
|
|
|
if (!(attachment->att_flags & ATT_monitor_done))
|
|
|
|
{
|
|
|
|
LCK_convert(tdbb, attachment->att_monitor_lock, LCK_SR, LCK_NO_WAIT);
|
|
|
|
attachment->att_flags |= ATT_monitor_done;
|
|
|
|
}
|
|
|
|
|
2014-07-31 10:56:53 +02:00
|
|
|
// Enumerate active sessions
|
2009-07-06 11:19:26 +02:00
|
|
|
|
2014-07-31 10:56:53 +02:00
|
|
|
MonitoringData::SessionList sessions(pool);
|
|
|
|
|
|
|
|
Lock temp_lock(tdbb, sizeof(SLONG), LCK_monitor), *lock = &temp_lock;
|
|
|
|
|
|
|
|
{ // scope for the guard
|
|
|
|
|
|
|
|
MonitoringData::Guard guard(dbb->dbb_monitoring_data);
|
|
|
|
dbb->dbb_monitoring_data->enumerate(sessions);
|
2014-06-26 11:43:40 +02:00
|
|
|
}
|
2006-10-30 13:39:08 +01:00
|
|
|
|
2014-07-31 10:56:53 +02:00
|
|
|
// Signal other sessions to dump their state
|
|
|
|
|
|
|
|
{ // scope for the temporary status
|
2007-12-10 07:31:04 +01:00
|
|
|
|
2014-07-31 10:56:53 +02:00
|
|
|
ThreadStatusGuard temp_status(tdbb);
|
2007-12-10 07:31:04 +01:00
|
|
|
|
2014-07-31 10:56:53 +02:00
|
|
|
for (SLONG* iter = sessions.begin(); iter != sessions.end(); iter++)
|
|
|
|
{
|
|
|
|
if (*iter != self_att_id)
|
|
|
|
{
|
|
|
|
lock->lck_key.lck_long = *iter;
|
|
|
|
|
2014-08-10 22:11:41 +02:00
|
|
|
if (LCK_lock(tdbb, lock, LCK_SR, LCK_WAIT))
|
2014-07-31 10:56:53 +02:00
|
|
|
LCK_release(tdbb, lock);
|
|
|
|
}
|
|
|
|
}
|
2013-10-19 10:09:51 +02:00
|
|
|
}
|
2007-07-16 16:41:39 +02:00
|
|
|
|
2014-07-31 10:56:53 +02:00
|
|
|
// Read the dump into a temporary space. While being there,
|
|
|
|
// also check for dead sessions and garbage collect them.
|
|
|
|
|
|
|
|
TempSpace temp_space(pool, SCRATCH);
|
|
|
|
|
|
|
|
{ // scope for the guard
|
2009-07-06 11:19:26 +02:00
|
|
|
|
2010-07-13 14:31:35 +02:00
|
|
|
MonitoringData::Guard guard(dbb->dbb_monitoring_data);
|
2014-07-31 10:56:53 +02:00
|
|
|
|
|
|
|
ThreadStatusGuard temp_status(tdbb);
|
|
|
|
lock->lck_type = LCK_attachment;
|
|
|
|
|
|
|
|
for (SLONG* iter = sessions.begin(); iter != sessions.end(); iter++)
|
|
|
|
{
|
|
|
|
if (*iter != self_att_id)
|
|
|
|
{
|
|
|
|
lock->lck_key.lck_long = *iter;
|
|
|
|
|
|
|
|
if (LCK_lock(tdbb, lock, LCK_EX, LCK_NO_WAIT))
|
|
|
|
{
|
|
|
|
LCK_release(tdbb, lock);
|
|
|
|
dbb->dbb_monitoring_data->cleanup(*iter);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
dbb->dbb_monitoring_data->read(self_att_id, temp_space);
|
2009-07-06 11:19:26 +02:00
|
|
|
}
|
2007-12-10 07:31:04 +01:00
|
|
|
|
2009-07-11 21:58:28 +02:00
|
|
|
string databaseName(dbb->dbb_database_name.c_str());
|
|
|
|
ISC_systemToUtf8(databaseName);
|
|
|
|
|
2008-12-11 12:58:50 +01:00
|
|
|
const string& userName = attachment->att_user->usr_user_name;
|
|
|
|
const bool locksmith = attachment->locksmith();
|
2006-07-17 19:44:18 +02:00
|
|
|
|
2007-07-16 17:26:04 +02:00
|
|
|
// Parse the dump
|
2014-07-31 10:56:53 +02:00
|
|
|
|
|
|
|
MonitoringData::Reader reader(pool, temp_space);
|
|
|
|
|
2007-07-16 17:26:04 +02:00
|
|
|
RecordBuffer* buffer = NULL;
|
|
|
|
Record* record = NULL;
|
2006-07-17 19:44:18 +02:00
|
|
|
|
2008-12-11 12:58:50 +01:00
|
|
|
bool dbb_processed = false, fields_processed = false;
|
|
|
|
bool dbb_allowed = false, att_allowed = false;
|
2006-07-17 19:44:18 +02:00
|
|
|
|
2014-07-31 10:56:53 +02:00
|
|
|
SnapshotData::DumpRecord dumpRecord(pool);
|
|
|
|
|
2009-07-06 11:19:26 +02:00
|
|
|
while (reader.getRecord(dumpRecord))
|
2007-07-16 17:26:04 +02:00
|
|
|
{
|
2009-07-06 11:19:26 +02:00
|
|
|
const int rid = dumpRecord.getRelationId();
|
2006-10-30 13:39:08 +01:00
|
|
|
|
2009-07-06 11:19:26 +02:00
|
|
|
switch (rid)
|
|
|
|
{
|
|
|
|
case rel_mon_database:
|
|
|
|
buffer = dbb_buffer;
|
|
|
|
break;
|
|
|
|
case rel_mon_attachments:
|
|
|
|
buffer = att_buffer;
|
|
|
|
break;
|
|
|
|
case rel_mon_transactions:
|
|
|
|
buffer = tra_buffer;
|
|
|
|
break;
|
|
|
|
case rel_mon_statements:
|
|
|
|
buffer = stmt_buffer;
|
|
|
|
break;
|
|
|
|
case rel_mon_calls:
|
|
|
|
buffer = call_buffer;
|
|
|
|
break;
|
|
|
|
case rel_mon_io_stats:
|
|
|
|
buffer = io_stat_buffer;
|
|
|
|
break;
|
|
|
|
case rel_mon_rec_stats:
|
|
|
|
buffer = rec_stat_buffer;
|
|
|
|
break;
|
|
|
|
case rel_mon_ctx_vars:
|
|
|
|
buffer = ctx_var_buffer;
|
|
|
|
break;
|
|
|
|
case rel_mon_mem_usage:
|
|
|
|
buffer = mem_usage_buffer;
|
|
|
|
break;
|
2014-09-30 19:35:44 +02:00
|
|
|
case rel_mon_tab_stats:
|
|
|
|
buffer = tab_stat_buffer;
|
|
|
|
break;
|
2009-07-06 11:19:26 +02:00
|
|
|
default:
|
|
|
|
fb_assert(false);
|
|
|
|
}
|
2007-07-16 17:26:04 +02:00
|
|
|
|
2009-07-06 11:19:26 +02:00
|
|
|
if (buffer)
|
|
|
|
{
|
|
|
|
record = buffer->getTempRecord();
|
2013-03-17 18:35:53 +01:00
|
|
|
record->nullify();
|
2007-07-16 17:26:04 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2009-07-06 11:19:26 +02:00
|
|
|
record = NULL;
|
|
|
|
}
|
2006-10-30 13:39:08 +01:00
|
|
|
|
2014-07-31 10:56:53 +02:00
|
|
|
SnapshotData::DumpField dumpField;
|
2009-07-06 11:19:26 +02:00
|
|
|
while (dumpRecord.getField(dumpField))
|
|
|
|
{
|
|
|
|
const USHORT fid = dumpField.id;
|
2014-07-31 23:15:33 +02:00
|
|
|
const FB_SIZE_T length = dumpField.length;
|
2009-07-06 11:19:26 +02:00
|
|
|
const char* source = (const char*) dumpField.data;
|
|
|
|
|
2011-06-02 16:19:31 +02:00
|
|
|
// All the strings that may require transliteration (i.e. the target charset is not NONE)
|
|
|
|
// are known to be in the metadata charset or ASCII (which is binary compatible).
|
2011-07-22 09:00:09 +02:00
|
|
|
const int charset = ttype_metadata;
|
2006-10-30 13:39:08 +01:00
|
|
|
|
2008-12-29 18:32:37 +01:00
|
|
|
// special case for MON$DATABASE
|
|
|
|
if (rid == rel_mon_database)
|
2007-07-16 17:26:04 +02:00
|
|
|
{
|
|
|
|
if (fid == f_mon_db_name)
|
2008-12-11 12:58:50 +01:00
|
|
|
dbb_allowed = !databaseName.compare(source, length);
|
|
|
|
|
|
|
|
if (record && dbb_allowed && !dbb_processed)
|
|
|
|
{
|
2011-06-02 16:19:31 +02:00
|
|
|
putField(tdbb, record, dumpField, charset);
|
2008-12-11 12:58:50 +01:00
|
|
|
fields_processed = true;
|
|
|
|
}
|
2008-12-29 18:32:37 +01:00
|
|
|
|
|
|
|
att_allowed = (dbb_allowed && !dbb_processed);
|
2008-12-11 12:58:50 +01:00
|
|
|
}
|
2008-12-29 18:32:37 +01:00
|
|
|
// special case for MON$ATTACHMENTS
|
|
|
|
else if (rid == rel_mon_attachments)
|
2008-12-11 12:58:50 +01:00
|
|
|
{
|
|
|
|
if (fid == f_mon_att_user)
|
2008-12-13 10:19:55 +01:00
|
|
|
att_allowed = locksmith || !userName.compare(source, length);
|
2007-07-16 16:41:39 +02:00
|
|
|
|
2008-12-11 12:58:50 +01:00
|
|
|
if (record && dbb_allowed && att_allowed)
|
2006-10-30 13:39:08 +01:00
|
|
|
{
|
2011-06-02 16:19:31 +02:00
|
|
|
putField(tdbb, record, dumpField, charset);
|
2006-10-30 13:39:08 +01:00
|
|
|
fields_processed = true;
|
2008-12-11 12:58:50 +01:00
|
|
|
dbb_processed = true;
|
2006-10-30 13:39:08 +01:00
|
|
|
}
|
2006-07-17 19:44:18 +02:00
|
|
|
}
|
2008-12-29 18:32:37 +01:00
|
|
|
// generic logic that covers all other relations
|
|
|
|
else if (record && dbb_allowed && att_allowed)
|
2007-07-16 17:26:04 +02:00
|
|
|
{
|
2011-06-02 16:19:31 +02:00
|
|
|
putField(tdbb, record, dumpField, charset);
|
2007-07-16 17:26:04 +02:00
|
|
|
fields_processed = true;
|
2008-12-11 12:58:50 +01:00
|
|
|
dbb_processed = true;
|
2007-07-16 17:26:04 +02:00
|
|
|
}
|
2006-10-30 13:39:08 +01:00
|
|
|
}
|
|
|
|
|
2009-07-06 11:19:26 +02:00
|
|
|
if (fields_processed)
|
|
|
|
{
|
|
|
|
buffer->store(record);
|
2009-07-07 07:17:55 +02:00
|
|
|
fields_processed = false;
|
2009-07-06 11:19:26 +02:00
|
|
|
}
|
2007-07-16 17:26:04 +02:00
|
|
|
}
|
2006-07-17 19:44:18 +02:00
|
|
|
}
|
|
|
|
|
2006-07-17 21:26:43 +02:00
|
|
|
|
2014-07-31 10:56:53 +02:00
|
|
|
void SnapshotData::clearSnapshot()
|
2006-07-17 19:44:18 +02:00
|
|
|
{
|
2014-07-31 23:15:33 +02:00
|
|
|
for (FB_SIZE_T i = 0; i < m_snapshot.getCount(); i++)
|
2014-07-31 10:56:53 +02:00
|
|
|
delete m_snapshot[i].data;
|
|
|
|
|
|
|
|
m_snapshot.clear();
|
2006-07-17 19:44:18 +02:00
|
|
|
}
|
|
|
|
|
2006-07-17 21:26:43 +02:00
|
|
|
|
2014-07-31 10:56:53 +02:00
|
|
|
RecordBuffer* SnapshotData::getData(const jrd_rel* relation) const
|
2006-07-17 19:44:18 +02:00
|
|
|
{
|
|
|
|
fb_assert(relation);
|
|
|
|
|
2013-12-17 15:20:25 +01:00
|
|
|
return getData(relation->rel_id);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-07-31 10:56:53 +02:00
|
|
|
RecordBuffer* SnapshotData::getData(int id) const
|
2013-12-17 15:20:25 +01:00
|
|
|
{
|
2014-07-31 23:15:33 +02:00
|
|
|
for (FB_SIZE_T i = 0; i < m_snapshot.getCount(); i++)
|
2006-07-17 19:44:18 +02:00
|
|
|
{
|
2014-07-31 10:56:53 +02:00
|
|
|
if (m_snapshot[i].rel_id == id)
|
|
|
|
return m_snapshot[i].data;
|
2006-07-17 19:44:18 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2006-07-17 21:26:43 +02:00
|
|
|
|
2014-07-31 10:56:53 +02:00
|
|
|
RecordBuffer* SnapshotData::allocBuffer(thread_db* tdbb, MemoryPool& pool, int rel_id)
|
2006-10-30 13:39:08 +01:00
|
|
|
{
|
2011-02-15 09:47:51 +01:00
|
|
|
jrd_rel* const relation = MET_lookup_relation_id(tdbb, rel_id, false);
|
2006-10-30 13:39:08 +01:00
|
|
|
fb_assert(relation);
|
|
|
|
MET_scan_relation(tdbb, relation);
|
2010-07-13 14:31:35 +02:00
|
|
|
fb_assert(relation->isVirtual());
|
2011-02-15 09:47:51 +01:00
|
|
|
|
|
|
|
const Format* const format = MET_current(tdbb, relation);
|
2006-10-30 13:39:08 +01:00
|
|
|
fb_assert(format);
|
|
|
|
|
2011-02-15 09:47:51 +01:00
|
|
|
RecordBuffer* const buffer = FB_NEW(pool) RecordBuffer(pool, format);
|
2014-07-31 10:56:53 +02:00
|
|
|
const RelationData data = {relation->rel_id, buffer};
|
|
|
|
m_snapshot.add(data);
|
2006-10-30 13:39:08 +01:00
|
|
|
|
|
|
|
return buffer;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-07-31 10:56:53 +02:00
|
|
|
void SnapshotData::putField(thread_db* tdbb, Record* record, const DumpField& field, int charset)
|
2006-07-17 19:44:18 +02:00
|
|
|
{
|
|
|
|
fb_assert(record);
|
|
|
|
|
2015-02-19 15:15:00 +01:00
|
|
|
const Format* const format = record->getFormat();
|
2011-02-15 09:47:51 +01:00
|
|
|
fb_assert(format);
|
|
|
|
|
|
|
|
dsc to_desc;
|
|
|
|
|
|
|
|
if (field.id < format->fmt_count)
|
|
|
|
to_desc = format->fmt_desc[field.id];
|
|
|
|
|
|
|
|
if (to_desc.isUnknown())
|
|
|
|
return;
|
2006-07-17 19:44:18 +02:00
|
|
|
|
2015-02-19 15:15:00 +01:00
|
|
|
to_desc.dsc_address += (IPTR) record->getData();
|
2006-07-17 19:44:18 +02:00
|
|
|
|
2009-07-06 11:19:26 +02:00
|
|
|
if (field.type == VALUE_GLOBAL_ID)
|
2007-09-14 17:13:19 +02:00
|
|
|
{
|
|
|
|
// special case: translate 64-bit global ID into 32-bit local ID
|
2009-07-06 11:19:26 +02:00
|
|
|
fb_assert(field.length == sizeof(SINT64));
|
|
|
|
SINT64 global_id;
|
|
|
|
memcpy(&global_id, field.data, field.length);
|
2014-09-30 19:35:44 +02:00
|
|
|
|
2009-07-06 11:19:26 +02:00
|
|
|
SLONG local_id;
|
2014-07-31 10:56:53 +02:00
|
|
|
if (!m_map.get(global_id, local_id))
|
2007-09-14 17:13:19 +02:00
|
|
|
{
|
2014-07-31 10:56:53 +02:00
|
|
|
local_id = ++m_counter;
|
|
|
|
m_map.put(global_id, local_id);
|
2007-09-14 17:13:19 +02:00
|
|
|
}
|
2014-09-30 19:35:44 +02:00
|
|
|
|
2009-07-06 11:19:26 +02:00
|
|
|
dsc from_desc;
|
|
|
|
from_desc.makeLong(0, &local_id);
|
|
|
|
MOV_move(tdbb, &from_desc, &to_desc);
|
2007-09-14 17:13:19 +02:00
|
|
|
}
|
2014-09-30 19:35:44 +02:00
|
|
|
else if (field.type == VALUE_TABLE_ID)
|
|
|
|
{
|
|
|
|
// special case: translate relation ID into name
|
|
|
|
fb_assert(field.length == sizeof(SLONG));
|
|
|
|
SLONG rel_id;
|
|
|
|
memcpy(&rel_id, field.data, field.length);
|
|
|
|
|
|
|
|
const jrd_rel* const relation = MET_lookup_relation_id(tdbb, rel_id, false);
|
|
|
|
if (!relation || relation->rel_name.isEmpty())
|
|
|
|
return;
|
|
|
|
|
|
|
|
const MetaName& name = relation->rel_name;
|
|
|
|
dsc from_desc;
|
|
|
|
from_desc.makeText(name.length(), CS_METADATA, (UCHAR*) name.c_str());
|
|
|
|
MOV_move(tdbb, &from_desc, &to_desc);
|
|
|
|
}
|
2009-07-06 11:19:26 +02:00
|
|
|
else if (field.type == VALUE_INTEGER)
|
2009-01-20 09:33:59 +01:00
|
|
|
{
|
2009-07-06 11:19:26 +02:00
|
|
|
fb_assert(field.length == sizeof(SINT64));
|
|
|
|
SINT64 value;
|
|
|
|
memcpy(&value, field.data, field.length);
|
2014-09-30 19:35:44 +02:00
|
|
|
|
2009-07-06 11:19:26 +02:00
|
|
|
dsc from_desc;
|
|
|
|
from_desc.makeInt64(0, &value);
|
|
|
|
MOV_move(tdbb, &from_desc, &to_desc);
|
2006-07-17 19:44:18 +02:00
|
|
|
}
|
2009-07-06 11:19:26 +02:00
|
|
|
else if (field.type == VALUE_TIMESTAMP)
|
2008-05-06 10:46:39 +02:00
|
|
|
{
|
2009-07-06 11:19:26 +02:00
|
|
|
fb_assert(field.length == sizeof(ISC_TIMESTAMP));
|
|
|
|
ISC_TIMESTAMP value;
|
|
|
|
memcpy(&value, field.data, field.length);
|
2014-09-30 19:35:44 +02:00
|
|
|
|
2009-07-06 11:19:26 +02:00
|
|
|
dsc from_desc;
|
|
|
|
from_desc.makeTimestamp(&value);
|
|
|
|
MOV_move(tdbb, &from_desc, &to_desc);
|
|
|
|
}
|
|
|
|
else if (field.type == VALUE_STRING)
|
|
|
|
{
|
|
|
|
dsc from_desc;
|
2009-08-27 18:17:35 +02:00
|
|
|
MoveBuffer buffer;
|
|
|
|
|
|
|
|
if (charset == CS_NONE && to_desc.getCharSet() == CS_METADATA)
|
|
|
|
{
|
2009-08-28 07:04:43 +02:00
|
|
|
// ASF: If an attachment using NONE charset has a string using non-ASCII characters,
|
|
|
|
// nobody will be able to select them in a system field. So we change these characters to
|
2009-08-27 18:17:35 +02:00
|
|
|
// question marks here - CORE-2602.
|
|
|
|
|
|
|
|
UCHAR* p = buffer.getBuffer(field.length);
|
|
|
|
const UCHAR* s = (const UCHAR*) field.data;
|
|
|
|
|
|
|
|
for (const UCHAR* end = buffer.end(); p < end; ++p, ++s)
|
|
|
|
*p = (*s > 0x7F ? '?' : *s);
|
|
|
|
|
|
|
|
from_desc.makeText(field.length, CS_ASCII, buffer.begin());
|
|
|
|
}
|
|
|
|
else
|
|
|
|
from_desc.makeText(field.length, charset, (UCHAR*) field.data);
|
|
|
|
|
2009-07-06 11:19:26 +02:00
|
|
|
MOV_move(tdbb, &from_desc, &to_desc);
|
|
|
|
}
|
2013-12-17 15:20:25 +01:00
|
|
|
else if (field.type == VALUE_BOOLEAN)
|
|
|
|
{
|
|
|
|
fb_assert(field.length == sizeof(UCHAR));
|
|
|
|
UCHAR value;
|
|
|
|
memcpy(&value, field.data, field.length);
|
|
|
|
dsc from_desc;
|
|
|
|
from_desc.makeBoolean(&value);
|
|
|
|
MOV_move(tdbb, &from_desc, &to_desc);
|
|
|
|
}
|
2009-07-06 11:19:26 +02:00
|
|
|
else
|
|
|
|
{
|
|
|
|
fb_assert(false);
|
2006-10-30 13:39:08 +01:00
|
|
|
}
|
|
|
|
|
2009-09-24 04:11:10 +02:00
|
|
|
// hvlad: detach just created temporary blob from request to bound its
|
2009-09-16 23:27:12 +02:00
|
|
|
// lifetime to transaction. This is necessary as this blob belongs to
|
|
|
|
// the MON$ table and must be accessible until transaction ends.
|
2009-09-17 17:55:18 +02:00
|
|
|
if (to_desc.isBlob())
|
2009-09-16 23:27:12 +02:00
|
|
|
{
|
2009-09-17 13:10:55 +02:00
|
|
|
bid* blob_id = reinterpret_cast<bid*>(to_desc.dsc_address);
|
|
|
|
jrd_tra* tran = tdbb->getTransaction();
|
2009-09-16 23:27:12 +02:00
|
|
|
|
2012-03-20 11:10:31 +01:00
|
|
|
if (!tran->tra_blobs->locate(blob_id->bid_temp_id()))
|
|
|
|
fb_assert(false);
|
2009-09-16 23:27:12 +02:00
|
|
|
|
2009-09-17 13:10:55 +02:00
|
|
|
BlobIndex& blobIdx = tran->tra_blobs->current();
|
2009-09-16 23:27:12 +02:00
|
|
|
fb_assert(!blobIdx.bli_materialized);
|
|
|
|
|
|
|
|
if (blobIdx.bli_request)
|
|
|
|
{
|
2012-03-20 11:10:31 +01:00
|
|
|
if (!blobIdx.bli_request->req_blobs.locate(blobIdx.bli_temp_id))
|
|
|
|
fb_assert(false);
|
2009-09-24 04:11:10 +02:00
|
|
|
|
2009-09-16 23:27:12 +02:00
|
|
|
blobIdx.bli_request->req_blobs.fastRemove();
|
|
|
|
blobIdx.bli_request = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-03-17 18:35:53 +01:00
|
|
|
record->clearNull(field.id);
|
2006-10-30 13:39:08 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-07-31 10:56:53 +02:00
|
|
|
// Monitoring class
|
2011-05-27 09:57:16 +02:00
|
|
|
|
2007-12-10 07:31:04 +01:00
|
|
|
|
2014-07-31 10:56:53 +02:00
|
|
|
SINT64 Monitoring::getGlobalId(int value)
|
2008-12-11 12:58:50 +01:00
|
|
|
{
|
|
|
|
return ((SINT64) getpid() << BITS_PER_LONG) + value;
|
2006-10-30 13:39:08 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-07-31 10:56:53 +02:00
|
|
|
void Monitoring::putDatabase(SnapshotData::DumpRecord& record, const Database* database,
|
|
|
|
MonitoringData::Writer& writer, int stat_id, int backup_state)
|
2006-07-17 19:44:18 +02:00
|
|
|
{
|
2006-10-30 13:39:08 +01:00
|
|
|
fb_assert(database);
|
|
|
|
|
2013-08-21 09:41:39 +02:00
|
|
|
record.reset(rel_mon_database);
|
2006-07-17 19:44:18 +02:00
|
|
|
|
2013-08-21 09:41:39 +02:00
|
|
|
PathName databaseName(database->dbb_database_name);
|
2009-07-11 21:58:28 +02:00
|
|
|
ISC_systemToUtf8(databaseName);
|
|
|
|
|
2008-12-11 12:58:50 +01:00
|
|
|
// database name or alias (MUST BE ALWAYS THE FIRST ITEM PASSED!)
|
2009-07-11 21:58:28 +02:00
|
|
|
record.storeString(f_mon_db_name, databaseName);
|
2006-07-17 19:44:18 +02:00
|
|
|
// page size
|
2009-07-06 11:19:26 +02:00
|
|
|
record.storeInteger(f_mon_db_page_size, database->dbb_page_size);
|
2006-07-17 19:44:18 +02:00
|
|
|
// major ODS version
|
2009-07-06 11:19:26 +02:00
|
|
|
record.storeInteger(f_mon_db_ods_major, database->dbb_ods_version);
|
2006-07-17 19:44:18 +02:00
|
|
|
// minor ODS version
|
2009-07-06 11:19:26 +02:00
|
|
|
record.storeInteger(f_mon_db_ods_minor, database->dbb_minor_version);
|
2006-07-17 19:44:18 +02:00
|
|
|
// oldest interesting transaction
|
2009-07-06 11:19:26 +02:00
|
|
|
record.storeInteger(f_mon_db_oit, database->dbb_oldest_transaction);
|
2006-07-17 19:44:18 +02:00
|
|
|
// oldest active transaction
|
2009-07-06 11:19:26 +02:00
|
|
|
record.storeInteger(f_mon_db_oat, database->dbb_oldest_active);
|
2006-07-17 19:44:18 +02:00
|
|
|
// oldest snapshot transaction
|
2009-07-06 11:19:26 +02:00
|
|
|
record.storeInteger(f_mon_db_ost, database->dbb_oldest_snapshot);
|
2006-07-17 19:44:18 +02:00
|
|
|
// next transaction
|
2009-07-06 11:19:26 +02:00
|
|
|
record.storeInteger(f_mon_db_nt, database->dbb_next_transaction);
|
2006-07-17 19:44:18 +02:00
|
|
|
// number of page buffers
|
2009-07-06 11:19:26 +02:00
|
|
|
record.storeInteger(f_mon_db_page_bufs, database->dbb_bcb->bcb_count);
|
2008-04-19 11:42:01 +02:00
|
|
|
|
|
|
|
int temp;
|
|
|
|
|
2006-07-17 19:44:18 +02:00
|
|
|
// SQL dialect
|
2006-10-30 13:39:08 +01:00
|
|
|
temp = (database->dbb_flags & DBB_DB_SQL_dialect_3) ? 3 : 1;
|
2009-07-06 11:19:26 +02:00
|
|
|
record.storeInteger(f_mon_db_dialect, temp);
|
2008-12-05 02:20:14 +01:00
|
|
|
|
2006-07-17 19:44:18 +02:00
|
|
|
// shutdown mode
|
2006-10-30 13:39:08 +01:00
|
|
|
if (database->dbb_ast_flags & DBB_shutdown_full)
|
|
|
|
temp = shut_mode_full;
|
|
|
|
else if (database->dbb_ast_flags & DBB_shutdown_single)
|
|
|
|
temp = shut_mode_single;
|
|
|
|
else if (database->dbb_ast_flags & DBB_shutdown)
|
|
|
|
temp = shut_mode_multi;
|
2006-07-17 19:44:18 +02:00
|
|
|
else
|
2006-10-30 13:39:08 +01:00
|
|
|
temp = shut_mode_online;
|
2009-07-06 11:19:26 +02:00
|
|
|
record.storeInteger(f_mon_db_shut_mode, temp);
|
2007-09-15 04:37:04 +02:00
|
|
|
|
2006-07-17 19:44:18 +02:00
|
|
|
// sweep interval
|
2009-07-06 11:19:26 +02:00
|
|
|
record.storeInteger(f_mon_db_sweep_int, database->dbb_sweep_interval);
|
2006-07-17 19:44:18 +02:00
|
|
|
// read only flag
|
2012-04-12 11:02:13 +02:00
|
|
|
temp = database->readOnly() ? 1 : 0;
|
2009-07-06 11:19:26 +02:00
|
|
|
record.storeInteger(f_mon_db_read_only, temp);
|
2006-07-17 19:44:18 +02:00
|
|
|
// forced writes flag
|
2006-10-30 13:39:08 +01:00
|
|
|
temp = (database->dbb_flags & DBB_force_write) ? 1 : 0;
|
2009-07-06 11:19:26 +02:00
|
|
|
record.storeInteger(f_mon_db_forced_writes, temp);
|
2006-07-17 19:44:18 +02:00
|
|
|
// reserve space flag
|
2006-10-30 13:39:08 +01:00
|
|
|
temp = (database->dbb_flags & DBB_no_reserve) ? 0 : 1;
|
2009-07-06 11:19:26 +02:00
|
|
|
record.storeInteger(f_mon_db_res_space, temp);
|
2006-07-17 19:44:18 +02:00
|
|
|
// creation date
|
2009-07-06 11:19:26 +02:00
|
|
|
record.storeTimestamp(f_mon_db_created, database->dbb_creation_date);
|
2006-07-17 19:44:18 +02:00
|
|
|
// database size
|
2009-07-06 11:19:26 +02:00
|
|
|
record.storeInteger(f_mon_db_pages, PageSpace::actAlloc(database));
|
2013-09-22 18:10:06 +02:00
|
|
|
// database backup state
|
|
|
|
record.storeInteger(f_mon_db_backup_state, backup_state);
|
2009-07-06 11:19:26 +02:00
|
|
|
|
2012-05-31 18:53:42 +02:00
|
|
|
// crypt thread status
|
|
|
|
if (database->dbb_crypto_manager)
|
|
|
|
record.storeInteger(f_mon_db_crypt_page, database->dbb_crypto_manager->getCurrentPage());
|
|
|
|
|
2013-09-18 11:37:13 +02:00
|
|
|
// database owner
|
|
|
|
record.storeString(f_mon_db_owner, database->dbb_owner);
|
|
|
|
|
2007-09-14 17:59:05 +02:00
|
|
|
// statistics
|
2009-07-06 11:19:26 +02:00
|
|
|
record.storeGlobalId(f_mon_db_stat_id, getGlobalId(stat_id));
|
|
|
|
writer.putRecord(record);
|
2009-08-19 11:35:03 +02:00
|
|
|
|
2014-09-01 15:19:53 +02:00
|
|
|
if (database->dbb_flags & DBB_shared)
|
2009-08-19 11:35:03 +02:00
|
|
|
{
|
2013-08-21 09:41:39 +02:00
|
|
|
putStatistics(record, database->dbb_stats, writer, stat_id, stat_database);
|
|
|
|
putMemoryUsage(record, database->dbb_memory_stats, writer, stat_id, stat_database);
|
2009-08-19 11:35:03 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2012-03-15 10:29:33 +01:00
|
|
|
RuntimeStatistics zero_rt_stats;
|
|
|
|
MemoryStats zero_mem_stats;
|
2013-08-21 09:41:39 +02:00
|
|
|
putStatistics(record, zero_rt_stats, writer, stat_id, stat_database);
|
|
|
|
putMemoryUsage(record, zero_mem_stats, writer, stat_id, stat_database);
|
2009-08-19 11:35:03 +02:00
|
|
|
}
|
2006-07-17 19:44:18 +02:00
|
|
|
}
|
|
|
|
|
2006-07-17 21:26:43 +02:00
|
|
|
|
2014-07-31 10:56:53 +02:00
|
|
|
void Monitoring::putAttachment(SnapshotData::DumpRecord& record, const Jrd::Attachment* attachment,
|
|
|
|
MonitoringData::Writer& writer, int stat_id)
|
2006-07-17 19:44:18 +02:00
|
|
|
{
|
2013-09-22 18:10:06 +02:00
|
|
|
fb_assert(attachment && attachment->att_user);
|
2009-05-29 16:10:18 +02:00
|
|
|
|
2013-08-21 09:41:39 +02:00
|
|
|
record.reset(rel_mon_attachments);
|
2006-07-17 19:44:18 +02:00
|
|
|
|
2007-03-05 08:50:23 +01:00
|
|
|
int temp = mon_state_idle;
|
2006-07-19 07:30:21 +02:00
|
|
|
|
2008-04-19 11:42:01 +02:00
|
|
|
for (const jrd_tra* transaction_itr = attachment->att_transactions;
|
2006-09-01 12:51:57 +02:00
|
|
|
transaction_itr; transaction_itr = transaction_itr->tra_next)
|
2006-07-19 07:30:21 +02:00
|
|
|
{
|
2006-09-01 12:51:57 +02:00
|
|
|
if (transaction_itr->tra_requests)
|
|
|
|
{
|
2007-03-05 08:50:23 +01:00
|
|
|
temp = mon_state_active;
|
2006-09-01 12:51:57 +02:00
|
|
|
break;
|
|
|
|
}
|
2006-07-19 07:30:21 +02:00
|
|
|
}
|
|
|
|
|
2013-08-21 09:41:39 +02:00
|
|
|
PathName attName(attachment->att_filename);
|
2009-07-11 21:58:28 +02:00
|
|
|
ISC_systemToUtf8(attName);
|
|
|
|
|
2008-12-11 12:58:50 +01:00
|
|
|
// user (MUST BE ALWAYS THE FIRST ITEM PASSED!)
|
2009-07-06 11:19:26 +02:00
|
|
|
record.storeString(f_mon_att_user, attachment->att_user->usr_user_name);
|
2006-07-17 19:44:18 +02:00
|
|
|
// attachment id
|
2009-07-06 11:19:26 +02:00
|
|
|
record.storeInteger(f_mon_att_id, attachment->att_attachment_id);
|
2006-07-17 19:44:18 +02:00
|
|
|
// process id
|
2009-07-06 11:19:26 +02:00
|
|
|
record.storeInteger(f_mon_att_server_pid, getpid());
|
2006-07-19 07:30:21 +02:00
|
|
|
// state
|
2009-07-06 11:19:26 +02:00
|
|
|
record.storeInteger(f_mon_att_state, temp);
|
2006-07-17 19:44:18 +02:00
|
|
|
// attachment name
|
2009-07-11 21:58:28 +02:00
|
|
|
record.storeString(f_mon_att_name, attName);
|
2006-07-17 19:44:18 +02:00
|
|
|
// role
|
2009-07-06 11:19:26 +02:00
|
|
|
record.storeString(f_mon_att_role, attachment->att_user->usr_sql_role_name);
|
2006-07-17 19:44:18 +02:00
|
|
|
// remote protocol
|
2009-07-06 11:19:26 +02:00
|
|
|
record.storeString(f_mon_att_remote_proto, attachment->att_network_protocol);
|
2006-07-17 19:44:18 +02:00
|
|
|
// remote address
|
2009-07-06 11:19:26 +02:00
|
|
|
record.storeString(f_mon_att_remote_addr, attachment->att_remote_address);
|
2006-09-14 15:47:31 +02:00
|
|
|
// remote process id
|
2009-07-06 11:19:26 +02:00
|
|
|
if (attachment->att_remote_pid)
|
|
|
|
{
|
|
|
|
record.storeInteger(f_mon_att_remote_pid, attachment->att_remote_pid);
|
|
|
|
}
|
2007-05-16 09:54:33 +02:00
|
|
|
// remote process name
|
2009-07-06 11:19:26 +02:00
|
|
|
record.storeString(f_mon_att_remote_process, attachment->att_remote_process);
|
2006-07-17 19:44:18 +02:00
|
|
|
// charset
|
2010-05-06 19:53:11 +02:00
|
|
|
record.storeInteger(f_mon_att_charset_id, attachment->att_charset);
|
2006-07-17 19:44:18 +02:00
|
|
|
// timestamp
|
2009-07-06 11:19:26 +02:00
|
|
|
record.storeTimestamp(f_mon_att_timestamp, attachment->att_timestamp);
|
2006-07-17 19:44:18 +02:00
|
|
|
// garbage collection flag
|
2006-10-30 13:39:08 +01:00
|
|
|
temp = (attachment->att_flags & ATT_no_cleanup) ? 0 : 1;
|
2009-07-06 11:19:26 +02:00
|
|
|
record.storeInteger(f_mon_att_gc, temp);
|
2012-09-12 09:45:51 +02:00
|
|
|
// client library version
|
|
|
|
record.storeString(f_mon_att_client_version, attachment->att_client_version);
|
|
|
|
// remote protocol version
|
|
|
|
record.storeString(f_mon_att_remote_version, attachment->att_remote_protocol);
|
|
|
|
// remote host name
|
|
|
|
record.storeString(f_mon_att_remote_host, attachment->att_remote_host);
|
|
|
|
// OS user name
|
|
|
|
record.storeString(f_mon_att_remote_os_user, attachment->att_remote_os_user);
|
2013-09-18 11:37:13 +02:00
|
|
|
// authentication method
|
|
|
|
record.storeString(f_mon_att_auth_method, attachment->att_user->usr_auth_method);
|
2007-09-14 17:13:19 +02:00
|
|
|
// statistics
|
2009-07-06 11:19:26 +02:00
|
|
|
record.storeGlobalId(f_mon_att_stat_id, getGlobalId(stat_id));
|
2014-01-11 10:10:44 +01:00
|
|
|
// system flag
|
|
|
|
temp = (attachment->att_flags & ATT_system) ? 1 : 0;
|
|
|
|
record.storeInteger(f_mon_att_sys_flag, temp);
|
|
|
|
|
2009-07-06 11:19:26 +02:00
|
|
|
writer.putRecord(record);
|
2009-08-19 11:35:03 +02:00
|
|
|
|
2014-09-01 15:19:53 +02:00
|
|
|
if (attachment->att_database->dbb_flags & DBB_shared)
|
2009-08-19 11:35:03 +02:00
|
|
|
{
|
2013-08-21 09:41:39 +02:00
|
|
|
putStatistics(record, attachment->att_stats, writer, stat_id, stat_attachment);
|
|
|
|
putMemoryUsage(record, attachment->att_memory_stats, writer, stat_id, stat_attachment);
|
2009-08-19 11:35:03 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2013-08-21 09:41:39 +02:00
|
|
|
putStatistics(record, attachment->att_database->dbb_stats, writer, stat_id, stat_attachment);
|
|
|
|
putMemoryUsage(record, attachment->att_database->dbb_memory_stats, writer, stat_id, stat_attachment);
|
2009-08-19 11:35:03 +02:00
|
|
|
}
|
2009-05-29 16:10:18 +02:00
|
|
|
|
2013-08-21 09:41:39 +02:00
|
|
|
// context vars
|
|
|
|
putContextVars(record, attachment->att_context_vars, writer, attachment->att_attachment_id, true);
|
2006-07-17 19:44:18 +02:00
|
|
|
}
|
|
|
|
|
2006-07-17 21:26:43 +02:00
|
|
|
|
2014-07-31 10:56:53 +02:00
|
|
|
void Monitoring::putTransaction(SnapshotData::DumpRecord& record, const jrd_tra* transaction,
|
|
|
|
MonitoringData::Writer& writer, int stat_id)
|
2006-07-17 19:44:18 +02:00
|
|
|
{
|
2007-09-14 17:13:19 +02:00
|
|
|
fb_assert(transaction);
|
2006-07-17 19:44:18 +02:00
|
|
|
|
2013-08-21 09:41:39 +02:00
|
|
|
record.reset(rel_mon_transactions);
|
2006-07-17 19:44:18 +02:00
|
|
|
|
2006-10-30 13:39:08 +01:00
|
|
|
int temp;
|
2006-07-17 19:44:18 +02:00
|
|
|
|
|
|
|
// transaction id
|
2009-07-06 11:19:26 +02:00
|
|
|
record.storeInteger(f_mon_tra_id, transaction->tra_number);
|
2006-07-17 19:44:18 +02:00
|
|
|
// attachment id
|
2009-07-06 11:19:26 +02:00
|
|
|
record.storeInteger(f_mon_tra_att_id, transaction->tra_attachment->att_attachment_id);
|
2006-07-19 07:30:21 +02:00
|
|
|
// state
|
2007-09-14 17:13:19 +02:00
|
|
|
temp = transaction->tra_requests ? mon_state_active : mon_state_idle;
|
2009-07-06 11:19:26 +02:00
|
|
|
record.storeInteger(f_mon_tra_state, temp);
|
2006-07-17 19:44:18 +02:00
|
|
|
// timestamp
|
2009-07-06 11:19:26 +02:00
|
|
|
record.storeTimestamp(f_mon_tra_timestamp, transaction->tra_timestamp);
|
2006-07-17 19:44:18 +02:00
|
|
|
// top transaction
|
2009-07-06 11:19:26 +02:00
|
|
|
record.storeInteger(f_mon_tra_top, transaction->tra_top);
|
2006-07-17 19:44:18 +02:00
|
|
|
// oldest transaction
|
2009-07-06 11:19:26 +02:00
|
|
|
record.storeInteger(f_mon_tra_oit, transaction->tra_oldest);
|
2006-07-17 19:44:18 +02:00
|
|
|
// oldest active transaction
|
2009-07-06 11:19:26 +02:00
|
|
|
record.storeInteger(f_mon_tra_oat, transaction->tra_oldest_active);
|
2006-07-17 19:44:18 +02:00
|
|
|
// isolation mode
|
2007-09-14 17:13:19 +02:00
|
|
|
if (transaction->tra_flags & TRA_degree3)
|
2009-07-06 11:19:26 +02:00
|
|
|
{
|
2006-10-30 13:39:08 +01:00
|
|
|
temp = iso_mode_consistency;
|
2009-07-06 11:19:26 +02:00
|
|
|
}
|
2007-09-14 17:13:19 +02:00
|
|
|
else if (transaction->tra_flags & TRA_read_committed)
|
2008-04-19 11:42:01 +02:00
|
|
|
{
|
2009-07-08 16:34:17 +02:00
|
|
|
temp = (transaction->tra_flags & TRA_rec_version) ?
|
2006-07-19 09:07:54 +02:00
|
|
|
iso_mode_rc_version : iso_mode_rc_no_version;
|
2008-04-19 11:42:01 +02:00
|
|
|
}
|
2006-07-17 19:44:18 +02:00
|
|
|
else
|
2009-07-06 11:19:26 +02:00
|
|
|
{
|
2006-10-30 13:39:08 +01:00
|
|
|
temp = iso_mode_concurrency;
|
2009-07-06 11:19:26 +02:00
|
|
|
}
|
|
|
|
record.storeInteger(f_mon_tra_iso_mode, temp);
|
2006-07-17 19:44:18 +02:00
|
|
|
// lock timeout
|
2009-07-06 11:19:26 +02:00
|
|
|
record.storeInteger(f_mon_tra_lock_timeout, transaction->tra_lock_timeout);
|
2006-07-17 19:44:18 +02:00
|
|
|
// read only flag
|
2007-09-14 17:13:19 +02:00
|
|
|
temp = (transaction->tra_flags & TRA_readonly) ? 1 : 0;
|
2009-07-06 11:19:26 +02:00
|
|
|
record.storeInteger(f_mon_tra_read_only, temp);
|
2006-07-17 19:44:18 +02:00
|
|
|
// autocommit flag
|
2007-09-14 17:13:19 +02:00
|
|
|
temp = (transaction->tra_flags & TRA_autocommit) ? 1 : 0;
|
2009-07-06 11:19:26 +02:00
|
|
|
record.storeInteger(f_mon_tra_auto_commit, temp);
|
2006-07-17 19:44:18 +02:00
|
|
|
// auto undo flag
|
2007-09-14 17:13:19 +02:00
|
|
|
temp = (transaction->tra_flags & TRA_no_auto_undo) ? 0 : 1;
|
2009-07-06 11:19:26 +02:00
|
|
|
record.storeInteger(f_mon_tra_auto_undo, temp);
|
|
|
|
|
2007-09-14 17:13:19 +02:00
|
|
|
// statistics
|
2009-07-06 11:19:26 +02:00
|
|
|
record.storeGlobalId(f_mon_tra_stat_id, getGlobalId(stat_id));
|
|
|
|
writer.putRecord(record);
|
2013-08-21 09:41:39 +02:00
|
|
|
putStatistics(record, transaction->tra_stats, writer, stat_id, stat_transaction);
|
|
|
|
putMemoryUsage(record, transaction->tra_memory_stats, writer, stat_id, stat_transaction);
|
|
|
|
|
|
|
|
// context vars
|
|
|
|
putContextVars(record, transaction->tra_context_vars, writer, transaction->tra_number, false);
|
2006-07-17 19:44:18 +02:00
|
|
|
}
|
|
|
|
|
2006-07-17 21:26:43 +02:00
|
|
|
|
2014-07-31 10:56:53 +02:00
|
|
|
void Monitoring::putRequest(SnapshotData::DumpRecord& record, const jrd_req* request,
|
|
|
|
MonitoringData::Writer& writer, int stat_id, const string& plan)
|
2006-07-17 19:44:18 +02:00
|
|
|
{
|
2006-10-30 13:39:08 +01:00
|
|
|
fb_assert(request);
|
2006-07-17 21:26:43 +02:00
|
|
|
|
2013-08-21 09:41:39 +02:00
|
|
|
record.reset(rel_mon_statements);
|
2006-07-17 19:44:18 +02:00
|
|
|
|
|
|
|
// request id
|
2011-02-15 08:16:57 +01:00
|
|
|
record.storeInteger(f_mon_stmt_id, request->req_id);
|
2006-07-17 19:44:18 +02:00
|
|
|
// attachment id
|
2009-07-06 11:19:26 +02:00
|
|
|
if (request->req_attachment)
|
|
|
|
{
|
|
|
|
record.storeInteger(f_mon_stmt_att_id, request->req_attachment->att_attachment_id);
|
2006-07-17 19:44:18 +02:00
|
|
|
}
|
2007-03-05 08:50:23 +01:00
|
|
|
// state, transaction ID, timestamp
|
2009-07-06 11:19:26 +02:00
|
|
|
if (request->req_flags & req_active)
|
|
|
|
{
|
2008-08-25 08:58:35 +02:00
|
|
|
const bool is_stalled = (request->req_flags & req_stall);
|
2009-07-06 11:19:26 +02:00
|
|
|
record.storeInteger(f_mon_stmt_state, is_stalled ? mon_state_stalled : mon_state_active);
|
|
|
|
if (request->req_transaction)
|
|
|
|
{
|
|
|
|
record.storeInteger(f_mon_stmt_tra_id, request->req_transaction->tra_number);
|
|
|
|
}
|
|
|
|
record.storeTimestamp(f_mon_stmt_timestamp, request->req_timestamp);
|
2006-07-17 19:44:18 +02:00
|
|
|
}
|
2009-07-06 11:19:26 +02:00
|
|
|
else
|
|
|
|
{
|
|
|
|
record.storeInteger(f_mon_stmt_state, mon_state_idle);
|
2007-03-05 08:50:23 +01:00
|
|
|
}
|
2014-06-10 15:32:29 +02:00
|
|
|
|
|
|
|
const JrdStatement* const statement = request->getStatement();
|
|
|
|
|
2007-03-05 08:50:23 +01:00
|
|
|
// sql text
|
2014-06-10 15:32:29 +02:00
|
|
|
if (statement->sqlText)
|
|
|
|
record.storeString(f_mon_stmt_sql_text, *statement->sqlText);
|
|
|
|
|
|
|
|
// explained plan
|
|
|
|
if (plan.hasData())
|
|
|
|
record.storeString(f_mon_stmt_expl_plan, plan);
|
2009-07-06 11:19:26 +02:00
|
|
|
|
2007-09-14 17:13:19 +02:00
|
|
|
// statistics
|
2009-07-06 11:19:26 +02:00
|
|
|
record.storeGlobalId(f_mon_stmt_stat_id, getGlobalId(stat_id));
|
|
|
|
writer.putRecord(record);
|
2013-08-21 09:41:39 +02:00
|
|
|
putStatistics(record, request->req_stats, writer, stat_id, stat_statement);
|
|
|
|
putMemoryUsage(record, request->req_memory_stats, writer, stat_id, stat_statement);
|
2007-03-05 08:50:23 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-07-31 10:56:53 +02:00
|
|
|
void Monitoring::putCall(SnapshotData::DumpRecord& record, const jrd_req* request,
|
|
|
|
MonitoringData::Writer& writer, int stat_id)
|
2007-03-05 08:50:23 +01:00
|
|
|
{
|
|
|
|
fb_assert(request);
|
|
|
|
|
2010-04-19 00:19:11 +02:00
|
|
|
const jrd_req* initialRequest = request->req_caller;
|
|
|
|
while (initialRequest->req_caller)
|
2009-07-06 11:19:26 +02:00
|
|
|
{
|
2010-04-19 00:19:11 +02:00
|
|
|
initialRequest = initialRequest->req_caller;
|
2009-07-06 11:19:26 +02:00
|
|
|
}
|
2010-04-19 00:19:11 +02:00
|
|
|
fb_assert(initialRequest);
|
2007-03-05 08:50:23 +01:00
|
|
|
|
2013-08-21 09:41:39 +02:00
|
|
|
record.reset(rel_mon_calls);
|
2007-03-05 08:50:23 +01:00
|
|
|
|
|
|
|
// call id
|
2011-02-15 08:16:57 +01:00
|
|
|
record.storeInteger(f_mon_call_id, request->req_id);
|
2007-03-05 08:50:23 +01:00
|
|
|
// statement id
|
2011-02-15 08:16:57 +01:00
|
|
|
record.storeInteger(f_mon_call_stmt_id, initialRequest->req_id);
|
2007-03-05 08:50:23 +01:00
|
|
|
// caller id
|
2010-04-19 00:19:11 +02:00
|
|
|
if (initialRequest != request->req_caller)
|
2009-07-06 11:19:26 +02:00
|
|
|
{
|
2011-02-15 08:16:57 +01:00
|
|
|
record.storeInteger(f_mon_call_caller_id, request->req_caller->req_id);
|
2007-03-05 08:50:23 +01:00
|
|
|
}
|
2009-12-22 01:08:49 +01:00
|
|
|
|
2014-04-02 04:32:42 +02:00
|
|
|
const JrdStatement* statement = request->getStatement();
|
2010-04-19 00:19:11 +02:00
|
|
|
const Routine* routine = statement->getRoutine();
|
2009-10-21 02:42:38 +02:00
|
|
|
|
2009-12-30 02:40:39 +01:00
|
|
|
// object name/type
|
|
|
|
if (routine)
|
2009-12-21 18:43:01 +01:00
|
|
|
{
|
2010-01-27 05:32:27 +01:00
|
|
|
if (routine->getName().package.hasData())
|
|
|
|
record.storeString(f_mon_call_pkg_name, routine->getName().package);
|
2009-12-21 18:43:01 +01:00
|
|
|
|
2009-12-30 02:40:39 +01:00
|
|
|
record.storeString(f_mon_call_name, routine->getName().identifier);
|
|
|
|
record.storeInteger(f_mon_call_type, routine->getObjectType());
|
2009-12-21 18:43:01 +01:00
|
|
|
}
|
2010-04-19 00:19:11 +02:00
|
|
|
else if (!statement->triggerName.isEmpty())
|
2009-07-06 11:19:26 +02:00
|
|
|
{
|
2010-04-19 00:19:11 +02:00
|
|
|
record.storeString(f_mon_call_name, statement->triggerName);
|
2009-07-06 11:19:26 +02:00
|
|
|
record.storeInteger(f_mon_call_type, obj_trigger);
|
2007-03-05 08:50:23 +01:00
|
|
|
}
|
2009-07-06 11:19:26 +02:00
|
|
|
else
|
|
|
|
{
|
2007-03-05 08:50:23 +01:00
|
|
|
// we should never be here...
|
|
|
|
fb_assert(false);
|
2006-07-17 19:44:18 +02:00
|
|
|
}
|
2009-12-22 01:08:49 +01:00
|
|
|
|
2006-10-30 13:39:08 +01:00
|
|
|
// timestamp
|
2009-07-06 11:19:26 +02:00
|
|
|
record.storeTimestamp(f_mon_call_timestamp, request->req_timestamp);
|
2007-03-05 08:50:23 +01:00
|
|
|
// source line/column
|
2009-07-06 11:19:26 +02:00
|
|
|
if (request->req_src_line)
|
|
|
|
{
|
|
|
|
record.storeInteger(f_mon_call_src_line, request->req_src_line);
|
|
|
|
record.storeInteger(f_mon_call_src_column, request->req_src_column);
|
|
|
|
}
|
|
|
|
|
2007-09-14 17:13:19 +02:00
|
|
|
// statistics
|
2009-07-06 11:19:26 +02:00
|
|
|
record.storeGlobalId(f_mon_call_stat_id, getGlobalId(stat_id));
|
|
|
|
writer.putRecord(record);
|
2013-08-21 09:41:39 +02:00
|
|
|
putStatistics(record, request->req_stats, writer, stat_id, stat_call);
|
|
|
|
putMemoryUsage(record, request->req_memory_stats, writer, stat_id, stat_call);
|
2007-09-14 17:13:19 +02:00
|
|
|
}
|
|
|
|
|
2014-07-31 10:56:53 +02:00
|
|
|
void Monitoring::putStatistics(SnapshotData::DumpRecord& record, const RuntimeStatistics& statistics,
|
|
|
|
MonitoringData::Writer& writer, int stat_id, int stat_group)
|
2007-09-14 17:13:19 +02:00
|
|
|
{
|
|
|
|
// statistics id
|
|
|
|
const SINT64 id = getGlobalId(stat_id);
|
|
|
|
|
|
|
|
// physical I/O statistics
|
2013-08-21 09:41:39 +02:00
|
|
|
record.reset(rel_mon_io_stats);
|
2009-07-06 11:19:26 +02:00
|
|
|
record.storeGlobalId(f_mon_io_stat_id, id);
|
|
|
|
record.storeInteger(f_mon_io_stat_group, stat_group);
|
|
|
|
record.storeInteger(f_mon_io_page_reads, statistics.getValue(RuntimeStatistics::PAGE_READS));
|
|
|
|
record.storeInteger(f_mon_io_page_writes, statistics.getValue(RuntimeStatistics::PAGE_WRITES));
|
|
|
|
record.storeInteger(f_mon_io_page_fetches, statistics.getValue(RuntimeStatistics::PAGE_FETCHES));
|
|
|
|
record.storeInteger(f_mon_io_page_marks, statistics.getValue(RuntimeStatistics::PAGE_MARKS));
|
|
|
|
writer.putRecord(record);
|
2007-09-14 17:13:19 +02:00
|
|
|
|
2014-09-30 19:35:44 +02:00
|
|
|
// logical I/O statistics (global)
|
2009-07-06 11:19:26 +02:00
|
|
|
record.reset(rel_mon_rec_stats);
|
|
|
|
record.storeGlobalId(f_mon_rec_stat_id, id);
|
|
|
|
record.storeInteger(f_mon_rec_stat_group, stat_group);
|
|
|
|
record.storeInteger(f_mon_rec_seq_reads, statistics.getValue(RuntimeStatistics::RECORD_SEQ_READS));
|
|
|
|
record.storeInteger(f_mon_rec_idx_reads, statistics.getValue(RuntimeStatistics::RECORD_IDX_READS));
|
|
|
|
record.storeInteger(f_mon_rec_inserts, statistics.getValue(RuntimeStatistics::RECORD_INSERTS));
|
|
|
|
record.storeInteger(f_mon_rec_updates, statistics.getValue(RuntimeStatistics::RECORD_UPDATES));
|
|
|
|
record.storeInteger(f_mon_rec_deletes, statistics.getValue(RuntimeStatistics::RECORD_DELETES));
|
|
|
|
record.storeInteger(f_mon_rec_backouts, statistics.getValue(RuntimeStatistics::RECORD_BACKOUTS));
|
|
|
|
record.storeInteger(f_mon_rec_purges, statistics.getValue(RuntimeStatistics::RECORD_PURGES));
|
|
|
|
record.storeInteger(f_mon_rec_expunges, statistics.getValue(RuntimeStatistics::RECORD_EXPUNGES));
|
2014-08-05 10:46:09 +02:00
|
|
|
record.storeInteger(f_mon_rec_locks, statistics.getValue(RuntimeStatistics::RECORD_LOCKS));
|
|
|
|
record.storeInteger(f_mon_rec_waits, statistics.getValue(RuntimeStatistics::RECORD_WAITS));
|
|
|
|
record.storeInteger(f_mon_rec_conflicts, statistics.getValue(RuntimeStatistics::RECORD_CONFLICTS));
|
2014-08-28 17:16:39 +02:00
|
|
|
record.storeInteger(f_mon_rec_bkver_reads, statistics.getValue(RuntimeStatistics::RECORD_BACKVERSION_READS));
|
2014-08-05 10:46:09 +02:00
|
|
|
record.storeInteger(f_mon_rec_frg_reads, statistics.getValue(RuntimeStatistics::RECORD_FRAGMENT_READS));
|
2014-08-27 16:51:51 +02:00
|
|
|
record.storeInteger(f_mon_rec_rpt_reads, statistics.getValue(RuntimeStatistics::RECORD_RPT_READS));
|
|
|
|
writer.putRecord(record);
|
2014-09-30 19:35:44 +02:00
|
|
|
|
|
|
|
// logical I/O statistics (table wise)
|
|
|
|
|
|
|
|
for (RuntimeStatistics::Iterator iter = statistics.begin(); iter != statistics.end(); ++iter)
|
|
|
|
{
|
|
|
|
const SINT64 rec_stat_id = getGlobalId(fb_utils::genUniqueId());
|
|
|
|
|
|
|
|
record.reset(rel_mon_tab_stats);
|
|
|
|
record.storeGlobalId(f_mon_tab_stat_id, id);
|
|
|
|
record.storeInteger(f_mon_tab_stat_group, stat_group);
|
|
|
|
record.storeTableId(f_mon_tab_name, (*iter).getRelationId());
|
|
|
|
record.storeGlobalId(f_mon_tab_rec_stat_id, rec_stat_id);
|
|
|
|
writer.putRecord(record);
|
|
|
|
|
|
|
|
record.reset(rel_mon_rec_stats);
|
|
|
|
record.storeGlobalId(f_mon_rec_stat_id, rec_stat_id);
|
|
|
|
record.storeInteger(f_mon_rec_stat_group, stat_group);
|
|
|
|
record.storeInteger(f_mon_rec_seq_reads, (*iter).getCounter(RuntimeStatistics::RECORD_SEQ_READS));
|
|
|
|
record.storeInteger(f_mon_rec_idx_reads, (*iter).getCounter(RuntimeStatistics::RECORD_IDX_READS));
|
|
|
|
record.storeInteger(f_mon_rec_inserts, (*iter).getCounter(RuntimeStatistics::RECORD_INSERTS));
|
|
|
|
record.storeInteger(f_mon_rec_updates, (*iter).getCounter(RuntimeStatistics::RECORD_UPDATES));
|
|
|
|
record.storeInteger(f_mon_rec_deletes, (*iter).getCounter(RuntimeStatistics::RECORD_DELETES));
|
|
|
|
record.storeInteger(f_mon_rec_backouts, (*iter).getCounter(RuntimeStatistics::RECORD_BACKOUTS));
|
|
|
|
record.storeInteger(f_mon_rec_purges, (*iter).getCounter(RuntimeStatistics::RECORD_PURGES));
|
|
|
|
record.storeInteger(f_mon_rec_expunges, (*iter).getCounter(RuntimeStatistics::RECORD_EXPUNGES));
|
|
|
|
record.storeInteger(f_mon_rec_locks, (*iter).getCounter(RuntimeStatistics::RECORD_LOCKS));
|
|
|
|
record.storeInteger(f_mon_rec_waits, (*iter).getCounter(RuntimeStatistics::RECORD_WAITS));
|
|
|
|
record.storeInteger(f_mon_rec_conflicts, (*iter).getCounter(RuntimeStatistics::RECORD_CONFLICTS));
|
|
|
|
record.storeInteger(f_mon_rec_bkver_reads, (*iter).getCounter(RuntimeStatistics::RECORD_BACKVERSION_READS));
|
|
|
|
record.storeInteger(f_mon_rec_frg_reads, (*iter).getCounter(RuntimeStatistics::RECORD_FRAGMENT_READS));
|
|
|
|
record.storeInteger(f_mon_rec_rpt_reads, (*iter).getCounter(RuntimeStatistics::RECORD_RPT_READS));
|
|
|
|
writer.putRecord(record);
|
|
|
|
}
|
2008-02-20 14:13:22 +01:00
|
|
|
}
|
|
|
|
|
2014-07-31 10:56:53 +02:00
|
|
|
void Monitoring::putContextVars(SnapshotData::DumpRecord& record, const StringMap& variables,
|
|
|
|
MonitoringData::Writer& writer, int object_id, bool is_attachment)
|
2008-02-20 14:13:22 +01:00
|
|
|
{
|
2009-02-08 13:57:49 +01:00
|
|
|
StringMap::ConstAccessor accessor(&variables);
|
2008-12-19 15:57:01 +01:00
|
|
|
|
|
|
|
for (bool found = accessor.getFirst(); found; found = accessor.getNext())
|
2008-02-20 14:13:22 +01:00
|
|
|
{
|
2013-08-21 09:41:39 +02:00
|
|
|
record.reset(rel_mon_ctx_vars);
|
2008-02-20 14:13:22 +01:00
|
|
|
|
|
|
|
if (is_attachment)
|
2009-07-06 11:19:26 +02:00
|
|
|
record.storeInteger(f_mon_ctx_var_att_id, object_id);
|
2008-02-20 14:13:22 +01:00
|
|
|
else
|
2009-07-06 11:19:26 +02:00
|
|
|
record.storeInteger(f_mon_ctx_var_tra_id, object_id);
|
|
|
|
|
|
|
|
record.storeString(f_mon_ctx_var_name, accessor.current()->first);
|
|
|
|
record.storeString(f_mon_ctx_var_value, accessor.current()->second);
|
2008-02-20 14:13:22 +01:00
|
|
|
|
2009-07-06 11:19:26 +02:00
|
|
|
writer.putRecord(record);
|
2008-02-20 14:13:22 +01:00
|
|
|
}
|
2006-07-17 19:44:18 +02:00
|
|
|
}
|
2008-05-06 10:46:39 +02:00
|
|
|
|
2014-07-31 10:56:53 +02:00
|
|
|
void Monitoring::putMemoryUsage(SnapshotData::DumpRecord& record, const MemoryStats& stats,
|
|
|
|
MonitoringData::Writer& writer, int stat_id, int stat_group)
|
2008-05-06 10:46:39 +02:00
|
|
|
{
|
|
|
|
// statistics id
|
|
|
|
const SINT64 id = getGlobalId(stat_id);
|
|
|
|
|
|
|
|
// memory usage
|
2013-08-21 09:41:39 +02:00
|
|
|
record.reset(rel_mon_mem_usage);
|
2009-07-06 11:19:26 +02:00
|
|
|
record.storeGlobalId(f_mon_mem_stat_id, id);
|
|
|
|
record.storeInteger(f_mon_mem_stat_group, stat_group);
|
|
|
|
record.storeInteger(f_mon_mem_cur_used, stats.getCurrentUsage());
|
|
|
|
record.storeInteger(f_mon_mem_cur_alloc, stats.getCurrentMapping());
|
|
|
|
record.storeInteger(f_mon_mem_max_used, stats.getMaximumUsage());
|
|
|
|
record.storeInteger(f_mon_mem_max_alloc, stats.getMaximumMapping());
|
|
|
|
|
|
|
|
writer.putRecord(record);
|
2008-05-06 10:46:39 +02:00
|
|
|
}
|
2014-07-31 10:56:53 +02:00
|
|
|
|
|
|
|
|
|
|
|
void Monitoring::checkState(thread_db* tdbb)
|
|
|
|
{
|
|
|
|
SET_TDBB(tdbb);
|
|
|
|
|
|
|
|
Jrd::Attachment* const attachment = tdbb->getAttachment();
|
|
|
|
|
2014-08-10 22:11:41 +02:00
|
|
|
if (attachment->att_flags & ATT_monitor_done)
|
2014-07-31 10:56:53 +02:00
|
|
|
{
|
|
|
|
// Enable signal handler for the monitoring stuff
|
2014-08-10 22:11:41 +02:00
|
|
|
attachment->att_flags &= ~ATT_monitor_done;
|
|
|
|
LCK_convert(tdbb, attachment->att_monitor_lock, LCK_EX, LCK_WAIT);
|
2014-07-31 10:56:53 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Monitoring::dumpAttachment(thread_db* tdbb, const Attachment* attachment, bool ast)
|
|
|
|
{
|
|
|
|
if (!attachment->att_user)
|
|
|
|
return;
|
|
|
|
|
|
|
|
Database* const dbb = tdbb->getDatabase();
|
|
|
|
MemoryPool& pool = *dbb->dbb_permanent;
|
|
|
|
|
|
|
|
const SLONG att_id = attachment->att_attachment_id;
|
|
|
|
|
|
|
|
// Determine the backup state
|
|
|
|
int backup_state = backup_state_unknown;
|
|
|
|
|
|
|
|
if (!ast)
|
|
|
|
{
|
|
|
|
BackupManager* const bm = dbb->dbb_backup_manager;
|
|
|
|
|
|
|
|
if (bm && !bm->isShutDown())
|
|
|
|
{
|
|
|
|
BackupManager::StateReadGuard holder(tdbb);
|
|
|
|
|
|
|
|
switch (bm->getState())
|
|
|
|
{
|
2014-09-30 16:21:44 +02:00
|
|
|
case Ods::hdr_nbak_normal:
|
2014-07-31 10:56:53 +02:00
|
|
|
backup_state = backup_state_normal;
|
|
|
|
break;
|
2014-09-30 16:21:44 +02:00
|
|
|
case Ods::hdr_nbak_stalled:
|
2014-07-31 10:56:53 +02:00
|
|
|
backup_state = backup_state_stalled;
|
|
|
|
break;
|
2014-09-30 16:21:44 +02:00
|
|
|
case Ods::hdr_nbak_merge:
|
2014-07-31 10:56:53 +02:00
|
|
|
backup_state = backup_state_merge;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!dbb->dbb_monitoring_data)
|
|
|
|
dbb->dbb_monitoring_data = FB_NEW(pool) MonitoringData(dbb);
|
|
|
|
|
|
|
|
MonitoringData::Guard guard(dbb->dbb_monitoring_data);
|
|
|
|
dbb->dbb_monitoring_data->cleanup(att_id);
|
|
|
|
|
|
|
|
MonitoringData::Writer writer(dbb->dbb_monitoring_data, att_id);
|
|
|
|
SnapshotData::DumpRecord record(pool);
|
|
|
|
|
|
|
|
if (!ast)
|
|
|
|
putDatabase(record, dbb, writer, fb_utils::genUniqueId(), backup_state);
|
|
|
|
|
|
|
|
putAttachment(record, attachment, writer, fb_utils::genUniqueId());
|
|
|
|
|
|
|
|
jrd_tra* transaction = NULL;
|
|
|
|
|
|
|
|
// Transaction information
|
|
|
|
|
|
|
|
for (transaction = attachment->att_transactions; transaction;
|
|
|
|
transaction = transaction->tra_next)
|
|
|
|
{
|
|
|
|
putTransaction(record, transaction, writer, fb_utils::genUniqueId());
|
|
|
|
}
|
|
|
|
|
|
|
|
// Call stack information
|
|
|
|
|
|
|
|
for (transaction = attachment->att_transactions; transaction;
|
|
|
|
transaction = transaction->tra_next)
|
|
|
|
{
|
|
|
|
for (jrd_req* request = transaction->tra_requests;
|
2014-08-12 12:21:58 +02:00
|
|
|
request && (request->req_flags & req_active) && (request->req_transaction == transaction);
|
|
|
|
request = request->req_caller)
|
2014-07-31 10:56:53 +02:00
|
|
|
{
|
|
|
|
request->adjustCallerStats();
|
|
|
|
|
|
|
|
if (!(request->getStatement()->flags &
|
|
|
|
(JrdStatement::FLAG_INTERNAL | JrdStatement::FLAG_SYS_TRIGGER)) &&
|
|
|
|
request->req_caller)
|
|
|
|
{
|
|
|
|
putCall(record, request, writer, fb_utils::genUniqueId());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Request information
|
|
|
|
|
|
|
|
for (const jrd_req* const* i = attachment->att_requests.begin();
|
|
|
|
i != attachment->att_requests.end();
|
|
|
|
++i)
|
|
|
|
{
|
|
|
|
const jrd_req* const request = *i;
|
|
|
|
|
|
|
|
if (!(request->getStatement()->flags &
|
|
|
|
(JrdStatement::FLAG_INTERNAL | JrdStatement::FLAG_SYS_TRIGGER)))
|
|
|
|
{
|
|
|
|
const string plan = OPT_get_plan(tdbb, request, true);
|
|
|
|
putRequest(record, request, writer, fb_utils::genUniqueId(), plan);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Monitoring::publishAttachment(thread_db* tdbb)
|
|
|
|
{
|
|
|
|
Database* const dbb = tdbb->getDatabase();
|
|
|
|
Attachment* const attachment = tdbb->getAttachment();
|
|
|
|
|
|
|
|
if (!dbb->dbb_monitoring_data)
|
|
|
|
dbb->dbb_monitoring_data = FB_NEW(*dbb->dbb_permanent) MonitoringData(dbb);
|
|
|
|
|
|
|
|
MonitoringData::Guard guard(dbb->dbb_monitoring_data);
|
|
|
|
dbb->dbb_monitoring_data->setup(attachment->att_attachment_id);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Monitoring::cleanupAttachment(thread_db* tdbb)
|
|
|
|
{
|
|
|
|
Database* const dbb = tdbb->getDatabase();
|
|
|
|
Attachment* const attachment = tdbb->getAttachment();
|
|
|
|
|
|
|
|
if (dbb->dbb_monitoring_data)
|
|
|
|
{
|
|
|
|
MonitoringData::Guard guard(dbb->dbb_monitoring_data);
|
|
|
|
dbb->dbb_monitoring_data->cleanup(attachment->att_attachment_id);
|
|
|
|
}
|
|
|
|
}
|