8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-02-02 09:20:39 +01:00

Rework monitoring logic to provide faster response under high CPU-bound load

This commit is contained in:
Dmitry Yemanov 2022-10-08 11:31:12 +03:00
parent 99b5542c4d
commit e9fdb67e63
8 changed files with 209 additions and 153 deletions

View File

@ -969,28 +969,28 @@ int Jrd::Attachment::blockingAstCancel(void* ast_object)
int Jrd::Attachment::blockingAstMonitor(void* ast_object)
{
Jrd::Attachment* const attachment = static_cast<Jrd::Attachment*>(ast_object);
const auto attachment = static_cast<Jrd::Attachment*>(ast_object);
try
{
Database* const dbb = attachment->att_database;
const auto dbb = attachment->att_database;
AsyncContextHolder tdbb(dbb, FB_FUNCTION, attachment->att_monitor_lock);
if (!(attachment->att_flags & ATT_monitor_done))
if (const auto generation = Monitoring::checkGeneration(dbb, attachment))
{
try
{
Monitoring::dumpAttachment(tdbb, attachment);
Monitoring::dumpAttachment(tdbb, attachment, generation);
}
catch (const Exception& ex)
{
iscLogException("Cannot dump the monitoring data", ex);
}
LCK_downgrade(tdbb, attachment->att_monitor_lock);
attachment->att_flags |= ATT_monitor_done;
}
LCK_downgrade(tdbb, attachment->att_monitor_lock);
attachment->att_flags |= ATT_monitor_disabled;
}
catch (const Exception&)
{} // no-op

View File

@ -159,7 +159,7 @@ const ULONG ATT_async_manual_lock = 0x01000L; // Async mutex was locked manually
const ULONG ATT_overwrite_check = 0x02000L; // Attachment checks is it possible to overwrite DB
const ULONG ATT_system = 0x04000L; // Special system attachment
const ULONG ATT_creator = 0x08000L; // This attachment created the DB
const ULONG ATT_monitor_done = 0x10000L; // Monitoring data is refreshed
const ULONG ATT_monitor_disabled = 0x10000L; // Monitoring lock is downgraded
const ULONG ATT_security_db = 0x20000L; // Attachment used for security purposes
const ULONG ATT_mapping = 0x40000L; // Attachment used for mapping auth block
const ULONG ATT_from_thread = 0x80000L; // Attachment from internal special thread (sweep, crypt)
@ -579,6 +579,7 @@ public:
AttNumber att_attachment_id; // Attachment ID
Lock* att_cancel_lock; // Lock to cancel the active request
Lock* att_monitor_lock; // Lock for monitoring purposes
ULONG att_monitor_generation; // Monitoring state generation
Lock* att_profiler_listener_lock; // Lock for remote profiler listener
const ULONG att_lock_owner_id; // ID for the lock manager
SLONG att_lock_owner_handle; // Handle for the lock manager

View File

@ -102,6 +102,19 @@ namespace Jrd
return dbb_tip_cache->getLatestStatementId();
}
ULONG Database::getMonitorGeneration() const
{
if (!dbb_tip_cache)
return 0;
return dbb_tip_cache->getMonitorGeneration();
}
ULONG Database::newMonitorGeneration() const
{
fb_assert(dbb_tip_cache);
return dbb_tip_cache->newMonitorGeneration();
}
const Firebird::string& Database::getUniqueFileId()
{
if (dbb_file_id.isEmpty())

View File

@ -635,6 +635,9 @@ public:
AttNumber getLatestAttachmentId() const;
StmtNumber getLatestStatementId() const;
ULONG getMonitorGeneration() const;
ULONG newMonitorGeneration() const;
USHORT getMaxIndexKeyLength() const
{
return dbb_page_size / 4;

View File

@ -64,8 +64,8 @@ namespace
class DumpWriter : public SnapshotData::DumpRecord::Writer
{
public:
DumpWriter(MonitoringData* data, AttNumber att_id, const char* user_name)
: dump(data), offset(dump->setup(att_id, user_name))
DumpWriter(MonitoringData* data, AttNumber att_id, const char* user_name, ULONG generation)
: dump(data), offset(dump->setup(att_id, user_name, generation))
{
fb_assert(offset);
}
@ -247,7 +247,36 @@ void MonitoringData::release()
}
void MonitoringData::read(const char* user_name, TempSpace& temp)
void MonitoringData::enumerate(const char* userName, ULONG generation, SessionList& sessions)
{
const bool init = sessions.isEmpty();
// When initializing, collect all sessions older than the given generation.
// Otherwise, remove sessions that have updated their generation.
for (ULONG offset = alignOffset(sizeof(Header)); offset < m_sharedMemory->getHeader()->used;)
{
const auto ptr = (UCHAR*) m_sharedMemory->getHeader() + offset;
const auto element = (Element*) ptr;
const ULONG length = alignOffset(sizeof(Element) + element->length);
if (!userName || !strcmp(element->userName, userName)) // permitted
{
if (init)
{
if (element->generation < generation)
sessions.add(element->attId);
}
else if (element->generation >= generation)
sessions.findAndRemove(element->attId);
}
offset += length;
}
}
void MonitoringData::read(const char* userName, TempSpace& temp)
{
offset_t position = temp.getSize();
@ -255,11 +284,11 @@ void MonitoringData::read(const char* user_name, TempSpace& temp)
for (ULONG offset = alignOffset(sizeof(Header)); offset < m_sharedMemory->getHeader()->used;)
{
UCHAR* const ptr = (UCHAR*) m_sharedMemory->getHeader() + offset;
const Element* const element = (Element*) ptr;
const auto ptr = (UCHAR*) m_sharedMemory->getHeader() + offset;
const auto element = (Element*) ptr;
const ULONG length = alignOffset(sizeof(Element) + element->length);
if (!user_name || !strcmp(element->userName, user_name))
if (!userName || !strcmp(element->userName, userName)) // permitted
{
temp.write(position, ptr + sizeof(Element), element->length);
position += element->length;
@ -270,7 +299,7 @@ void MonitoringData::read(const char* user_name, TempSpace& temp)
}
ULONG MonitoringData::setup(AttNumber att_id, const char* user_name)
ULONG MonitoringData::setup(AttNumber att_id, const char* userName, ULONG generation)
{
const ULONG offset = alignOffset(m_sharedMemory->getHeader()->used);
const ULONG delta = offset + sizeof(Element) - m_sharedMemory->getHeader()->used;
@ -279,10 +308,11 @@ ULONG MonitoringData::setup(AttNumber att_id, const char* user_name)
// Prepare for writing new data at the tail
UCHAR* const ptr = (UCHAR*) m_sharedMemory->getHeader() + offset;
Element* const element = (Element*) ptr;
const auto ptr = (UCHAR*) m_sharedMemory->getHeader() + offset;
const auto element = (Element*) ptr;
element->attId = att_id;
snprintf(element->userName, sizeof(element->userName), "%s", user_name);
snprintf(element->userName, sizeof(element->userName), "%s", userName);
element->generation = generation;
element->length = 0;
m_sharedMemory->getHeader()->used += delta;
return offset;
@ -295,8 +325,8 @@ void MonitoringData::write(ULONG offset, ULONG length, const void* buffer)
// Write data item at the tail
UCHAR* const ptr = (UCHAR*) m_sharedMemory->getHeader() + offset;
Element* const element = (Element*) ptr;
const auto ptr = (UCHAR*) m_sharedMemory->getHeader() + offset;
const auto element = (Element*) ptr;
memcpy(ptr + sizeof(Element) + element->length, buffer, length);
element->length += length;
m_sharedMemory->getHeader()->used += length;
@ -309,8 +339,8 @@ void MonitoringData::cleanup(AttNumber att_id)
for (ULONG offset = alignOffset(sizeof(Header)); offset < m_sharedMemory->getHeader()->used;)
{
UCHAR* const ptr = (UCHAR*) m_sharedMemory->getHeader() + offset;
const Element* const element = (Element*) ptr;
const auto ptr = (UCHAR*) m_sharedMemory->getHeader() + offset;
const auto element = (Element*) ptr;
const ULONG length = alignOffset(sizeof(Element) + element->length);
if (element->attId == att_id)
@ -333,24 +363,6 @@ void MonitoringData::cleanup(AttNumber att_id)
}
void MonitoringData::enumerate(SessionList& sessions, const char* user_name)
{
// Return IDs for all known (and permitted) sessions
for (ULONG offset = alignOffset(sizeof(Header)); offset < m_sharedMemory->getHeader()->used;)
{
UCHAR* const ptr = (UCHAR*) m_sharedMemory->getHeader() + offset;
const Element* const element = (Element*) ptr;
const ULONG length = alignOffset(sizeof(Element) + element->length);
if (!user_name || !strcmp(element->userName, user_name))
sessions.add(element->attId);
offset += length;
}
}
void MonitoringData::ensureSpace(ULONG length)
{
ULONG newSize = m_sharedMemory->getHeader()->used + length;
@ -409,9 +421,7 @@ ULONG MonitoringData::alignOffset(ULONG unaligned)
MonitoringSnapshot* MonitoringSnapshot::create(thread_db* tdbb)
{
SET_TDBB(tdbb);
jrd_tra* transaction = tdbb->getTransaction();
const auto transaction = tdbb->getTransaction();
fb_assert(transaction);
if (!transaction->tra_mon_snapshot)
@ -429,76 +439,84 @@ MonitoringSnapshot* MonitoringSnapshot::create(thread_db* tdbb)
MonitoringSnapshot::MonitoringSnapshot(thread_db* tdbb, MemoryPool& pool)
: SnapshotData(pool)
{
SET_TDBB(tdbb);
PAG_header(tdbb, true);
Database* const dbb = tdbb->getDatabase();
fb_assert(dbb);
const auto dbb = tdbb->getDatabase();
const auto attachment = tdbb->getAttachment();
Attachment* const attachment = tdbb->getAttachment();
fb_assert(attachment);
const AttNumber self_att_id = attachment->att_attachment_id;
const auto selfAttId = attachment->att_attachment_id;
// Initialize record buffers
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 cmp_stmt_buffer = dbb->getEncodedOdsVersion() >= ODS_13_1 ?
const auto dbb_buffer = allocBuffer(tdbb, pool, rel_mon_database);
const auto att_buffer = allocBuffer(tdbb, pool, rel_mon_attachments);
const auto tra_buffer = allocBuffer(tdbb, pool, rel_mon_transactions);
const auto cmp_stmt_buffer = dbb->getEncodedOdsVersion() >= ODS_13_1 ?
allocBuffer(tdbb, pool, rel_mon_compiled_statements) :
nullptr;
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);
RecordBuffer* const tab_stat_buffer = allocBuffer(tdbb, pool, rel_mon_tab_stats);
const auto stmt_buffer = allocBuffer(tdbb, pool, rel_mon_statements);
const auto call_buffer = allocBuffer(tdbb, pool, rel_mon_calls);
const auto io_stat_buffer = allocBuffer(tdbb, pool, rel_mon_io_stats);
const auto rec_stat_buffer = allocBuffer(tdbb, pool, rel_mon_rec_stats);
const auto ctx_var_buffer = allocBuffer(tdbb, pool, rel_mon_ctx_vars);
const auto mem_usage_buffer = allocBuffer(tdbb, pool, rel_mon_mem_usage);
const auto tab_stat_buffer = allocBuffer(tdbb, pool, rel_mon_tab_stats);
// Dump our own data and downgrade the lock, if required
// Increment the global monitor generation
Monitoring::dumpAttachment(tdbb, attachment);
const auto generation = dbb->newMonitorGeneration();
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;
}
// Dump state of our own attachment
// Enumerate active sessions
Monitoring::dumpAttachment(tdbb, attachment, generation);
const bool locksmith = attachment->locksmith(tdbb, MONITOR_ANY_ATTACHMENT);
const MetaString& user_name = attachment->getEffectiveUserName();
const char* const user_name_ptr = locksmith ? NULL : user_name.c_str();
// Enumerate active sessions and ensure they have dumped their state.
// Check that by comparing the session generation with the current one.
MonitoringData::SessionList sessions(pool);
const auto locksmith = attachment->locksmith(tdbb, MONITOR_ANY_ATTACHMENT);
const auto userName = attachment->getEffectiveUserName();
const auto userNamePtr = locksmith ? nullptr : userName.c_str();
Lock temp_lock(tdbb, sizeof(AttNumber), LCK_monitor), *lock = &temp_lock;
MonitoringData::SessionList sessions(pool);
{ // scope for the guard
do
{
ThreadStatusGuard tempStatus(tdbb);
MonitoringData::Guard guard(dbb->dbb_monitoring_data);
dbb->dbb_monitoring_data->enumerate(sessions, user_name_ptr);
}
{ // scope for the guard
// Signal other sessions to dump their state
{ // scope for the temporary status
ThreadStatusGuard temp_status(tdbb);
for (AttNumber* iter = sessions.begin(); iter != sessions.end(); iter++)
{
if (*iter != self_att_id)
{
lock->setKey(*iter);
if (LCK_lock(tdbb, lock, LCK_SR, LCK_WAIT))
LCK_release(tdbb, lock);
}
MonitoringData::Guard guard(dbb->dbb_monitoring_data);
dbb->dbb_monitoring_data->enumerate(userNamePtr, generation, sessions);
}
}
if (!sessions.hasData())
break;
const auto attId = sessions.pop();
fb_assert(attId != selfAttId);
lock->setKey(attId);
// Try getting an exclusive lock first.
// Success means session is dead and must be garbage collected.
if (LCK_lock(tdbb, lock, LCK_EX, LCK_NO_WAIT))
{
LCK_release(tdbb, lock);
dbb->dbb_monitoring_data->cleanup(attId);
continue;
}
// Ping the session via AST to dump its state
if (!LCK_lock(tdbb, lock, LCK_SR, LCK_WAIT))
{
fb_assert(false);
ERR_punt();
}
LCK_release(tdbb, lock);
} while (sessions.hasData());
// Collect monitoring data. Start by gathering database-level info,
// it goes directly to the temporary space (as it's not stored in the shared dump).
@ -513,31 +531,13 @@ MonitoringSnapshot::MonitoringSnapshot(thread_db* tdbb, MemoryPool& pool)
Monitoring::putDatabase(tdbb, tempRecord);
}
// Read the dump into a temporary space. While being there,
// also check for dead sessions and garbage collect them.
// Read the dump into a temporary space
{ // scope for the guard
MonitoringData::Guard guard(dbb->dbb_monitoring_data);
ThreadStatusGuard temp_status(tdbb);
lock->lck_type = LCK_attachment;
for (AttNumber* iter = sessions.begin(); iter != sessions.end(); iter++)
{
if (*iter != self_att_id)
{
lock->setKey(*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(user_name_ptr, temp_space);
dbb->dbb_monitoring_data->read(userNamePtr, temp_space);
}
// Parse the dump
@ -549,8 +549,8 @@ MonitoringSnapshot::MonitoringSnapshot(thread_db* tdbb, MemoryPool& pool)
{
const int rid = dumpRecord.getRelationId();
RecordBuffer* buffer = NULL;
Record* record = NULL;
RecordBuffer* buffer = nullptr;
Record* record = nullptr;
switch (rid)
{
@ -640,7 +640,7 @@ RecordBuffer* SnapshotData::getData(int id) const
return m_snapshot[i].data;
}
return NULL;
return nullptr;
}
@ -800,7 +800,7 @@ void SnapshotData::putField(thread_db* tdbb, Record* record, const DumpField& fi
fb_assert(false);
blobIdx.bli_request->req_blobs.fastRemove();
blobIdx.bli_request = NULL;
blobIdx.bli_request = nullptr;
}
}
@ -916,13 +916,13 @@ void Monitoring::putDatabase(thread_db* tdbb, SnapshotData::DumpRecord& record)
// security database type
PathName secDbName;
string secDbType = "Other";
expandDatabaseName(dbb->dbb_config->getSecurityDatabase(), secDbName, NULL);
expandDatabaseName(dbb->dbb_config->getSecurityDatabase(), secDbName, nullptr);
if (secDbName == dbb->dbb_filename)
secDbType = "Self";
else
{
PathName defDbName;
expandDatabaseName(Config::getDefaultConfig()->getSecurityDatabase(), defDbName, NULL);
expandDatabaseName(Config::getDefaultConfig()->getSecurityDatabase(), defDbName, nullptr);
if (secDbName == defDbName)
secDbType = "Default";
}
@ -1246,12 +1246,11 @@ void Monitoring::putCall(SnapshotData::DumpRecord& record, const Request* reques
fb_assert(request);
const auto dbb = request->req_attachment->att_database;
const Request* initialRequest = request->req_caller;
auto initialRequest = request->req_caller;
while (initialRequest->req_caller)
{
initialRequest = initialRequest->req_caller;
}
fb_assert(initialRequest);
record.reset(rel_mon_calls);
@ -1264,8 +1263,8 @@ void Monitoring::putCall(SnapshotData::DumpRecord& record, const Request* reques
if (initialRequest != request->req_caller)
record.storeInteger(f_mon_call_caller_id, request->req_caller->getRequestId());
const Statement* statement = request->getStatement();
const Routine* routine = statement->getRoutine();
const auto statement = request->getStatement();
const auto routine = statement->getRoutine();
// object name/type
if (routine)
@ -1300,7 +1299,7 @@ void Monitoring::putCall(SnapshotData::DumpRecord& record, const Request* reques
record.storeInteger(f_mon_call_cmp_stmt_id, statement->getStatementId());
// statistics
const int stat_id = fb_utils::genUniqueId();
const auto stat_id = fb_utils::genUniqueId();
record.storeGlobalId(f_mon_call_stat_id, getGlobalId(stat_id));
record.write();
@ -1314,7 +1313,7 @@ void Monitoring::putStatistics(SnapshotData::DumpRecord& record, const RuntimeSt
int stat_id, int stat_group)
{
// statistics id
const SINT64 id = getGlobalId(stat_id);
const auto id = getGlobalId(stat_id);
// physical I/O statistics
record.reset(rel_mon_io_stats);
@ -1351,7 +1350,7 @@ void Monitoring::putStatistics(SnapshotData::DumpRecord& record, const RuntimeSt
for (RuntimeStatistics::Iterator iter = statistics.begin(); iter != statistics.end(); ++iter)
{
const SINT64 rec_stat_id = getGlobalId(fb_utils::genUniqueId());
const auto rec_stat_id = getGlobalId(fb_utils::genUniqueId());
record.reset(rel_mon_tab_stats);
record.storeGlobalId(f_mon_tab_stat_id, id);
@ -1407,7 +1406,7 @@ void Monitoring::putMemoryUsage(SnapshotData::DumpRecord& record, const MemorySt
int stat_id, int stat_group)
{
// statistics id
const SINT64 id = getGlobalId(stat_id);
const auto id = getGlobalId(stat_id);
// memory usage
record.reset(rel_mon_mem_usage);
@ -1424,43 +1423,53 @@ void Monitoring::putMemoryUsage(SnapshotData::DumpRecord& record, const MemorySt
void Monitoring::checkState(thread_db* tdbb)
{
SET_TDBB(tdbb);
const auto dbb = tdbb->getDatabase();
const auto attachment = tdbb->getAttachment();
Jrd::Attachment* const attachment = tdbb->getAttachment();
if (!(attachment && (attachment->att_flags & ATT_monitor_init)))
return;
if (attachment->att_flags & ATT_monitor_done)
if (const auto generation = checkGeneration(dbb, attachment))
{
// Dump attachment state
dumpAttachment(tdbb, attachment, generation);
}
if (attachment->att_flags & ATT_monitor_disabled)
{
// Enable signal handler for the monitoring stuff
attachment->att_flags &= ~ATT_monitor_done;
attachment->att_flags &= ~ATT_monitor_disabled;
LCK_convert(tdbb, attachment->att_monitor_lock, LCK_EX, LCK_WAIT);
}
}
void Monitoring::dumpAttachment(thread_db* tdbb, Attachment* attachment)
void Monitoring::dumpAttachment(thread_db* tdbb, Attachment* attachment, ULONG generation)
{
if (!attachment->att_user)
return;
Database* const dbb = tdbb->getDatabase();
MemoryPool& pool = *dbb->dbb_permanent;
const auto dbb = tdbb->getDatabase();
auto& pool = *dbb->dbb_permanent;
attachment->mergeStats();
const AttNumber att_id = attachment->att_attachment_id;
const MetaString& user_name = attachment->getUserName();
const auto attId = attachment->att_attachment_id;
const auto userName = attachment->getUserName();
fb_assert(dbb->dbb_monitoring_data);
MonitoringData::Guard guard(dbb->dbb_monitoring_data);
dbb->dbb_monitoring_data->cleanup(att_id);
attachment->att_monitor_generation = generation;
DumpWriter writer(dbb->dbb_monitoring_data, att_id, user_name.c_str());
MonitoringData::Guard guard(dbb->dbb_monitoring_data);
dbb->dbb_monitoring_data->cleanup(attId);
DumpWriter writer(dbb->dbb_monitoring_data, attId, userName.c_str(), generation);
SnapshotData::DumpRecord record(pool, writer);
putAttachment(record, attachment);
jrd_tra* transaction = NULL;
jrd_tra* transaction = nullptr;
// Transaction information
@ -1521,15 +1530,18 @@ void Monitoring::dumpAttachment(thread_db* tdbb, Attachment* attachment)
void Monitoring::publishAttachment(thread_db* tdbb)
{
Database* const dbb = tdbb->getDatabase();
Attachment* const attachment = tdbb->getAttachment();
const auto dbb = tdbb->getDatabase();
const auto attachment = tdbb->getAttachment();
const char* user_name = attachment->getUserName().c_str();
const auto userName = attachment->getUserName().c_str();
fb_assert(dbb->dbb_monitoring_data);
const auto generation = attachment->att_monitor_generation =
dbb->getMonitorGeneration();
MonitoringData::Guard guard(dbb->dbb_monitoring_data);
dbb->dbb_monitoring_data->setup(attachment->att_attachment_id, user_name);
dbb->dbb_monitoring_data->setup(attachment->att_attachment_id, userName, generation);
attachment->att_flags |= ATT_monitor_init;
}
@ -1537,8 +1549,8 @@ void Monitoring::publishAttachment(thread_db* tdbb)
void Monitoring::cleanupAttachment(thread_db* tdbb)
{
Database* const dbb = tdbb->getDatabase();
Attachment* const attachment = tdbb->getAttachment();
const auto dbb = tdbb->getDatabase();
const auto attachment = tdbb->getAttachment();
if (attachment->att_flags & ATT_monitor_init)
{

View File

@ -246,7 +246,7 @@ struct MonitoringHeader : public Firebird::MemoryHeader
class MonitoringData final : public Firebird::PermanentStorage, public Firebird::IpcObject
{
static const USHORT MONITOR_VERSION = 5;
static const USHORT MONITOR_VERSION = 6;
static const ULONG DEFAULT_SIZE = 1048576;
typedef MonitoringHeader Header;
@ -255,6 +255,7 @@ class MonitoringData final : public Firebird::PermanentStorage, public Firebird:
{
AttNumber attId;
TEXT userName[USERNAME_LENGTH + 1];
ULONG generation;
ULONG length;
};
@ -331,12 +332,12 @@ public:
void acquire();
void release();
void enumerate(const char*, ULONG, SessionList&);
void read(const char*, TempSpace&);
ULONG setup(AttNumber, const char*);
ULONG setup(AttNumber, const char*, ULONG);
void write(ULONG, ULONG, const void*);
void cleanup(AttNumber);
void enumerate(SessionList&, const char*);
private:
// copying is prohibited
@ -379,10 +380,22 @@ protected:
class Monitoring
{
public:
static int blockingAst(void* ast_object);
static ULONG checkGeneration(const Database* dbb, const Attachment* attachment)
{
const auto generation = dbb->getMonitorGeneration();
if (generation != attachment->att_monitor_generation)
return generation;
return 0;
}
static void checkState(thread_db* tdbb);
static SnapshotData* getSnapshot(thread_db* tdbb);
static void dumpAttachment(thread_db* tdbb, Attachment* attachment);
static void dumpAttachment(thread_db* tdbb, Attachment* attachment, ULONG generation);
static void publishAttachment(thread_db* tdbb);
static void cleanupAttachment(thread_db* tdbb);

View File

@ -69,6 +69,7 @@ bool TipCache::GlobalTpcInitializer::initialize(SharedMemoryBase* sm, bool initF
header->latest_commit_number.store(CN_PREHISTORIC, std::memory_order_relaxed);
header->latest_statement_id.store(0, std::memory_order_relaxed);
header->monitor_generation.store(0, std::memory_order_relaxed);
header->tpc_block_size = dbb->dbb_config->getTipCacheBlockSize();
m_cache->initTransactionsPerBlock(header->tpc_block_size);

View File

@ -148,6 +148,16 @@ public:
return m_tpcHeader->getHeader()->latest_commit_number.load(std::memory_order_acquire);
}
ULONG getMonitorGeneration() const
{
return m_tpcHeader->getHeader()->monitor_generation.load(std::memory_order_acquire);
}
ULONG newMonitorGeneration() const
{
return m_tpcHeader->getHeader()->monitor_generation++ + 1;
}
private:
class GlobalTpcHeader : public Firebird::MemoryHeader
{
@ -170,6 +180,9 @@ private:
std::atomic<AttNumber> latest_attachment_id;
std::atomic<StmtNumber> latest_statement_id;
// Monitor state generation
std::atomic<ULONG> monitor_generation;
// Size of memory chunk with TransactionStatusBlock
ULONG tpc_block_size; // final
};
@ -266,7 +279,7 @@ private:
typedef Firebird::BePlusTree<StatusBlockData*, TpcBlockNumber, Firebird::MemoryPool, StatusBlockData> BlocksMemoryMap;
static const ULONG TPC_VERSION = 1;
static const ULONG TPC_VERSION = 2;
static const int SAFETY_GAP_BLOCKS = 1;
Firebird::SharedMemory<GlobalTpcHeader>* m_tpcHeader; // final