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

This should fix the races while accessing the relation statistics inside dbb_stats. Reads/writes/fetches/marks are incremented (CCH) and read (INF) unprotected, as it's crash safe and read skews are acceptable. Other counters (both global and relation wise) are protected with a mutex. They're incremented on demand based on the attachment counters (via diffs). While being there, cleaned up the currently unused performance counters.

This commit is contained in:
dimitr 2016-01-24 21:14:18 +00:00
parent dd738c7f80
commit 99ad42ab82
12 changed files with 54 additions and 37 deletions

View File

@ -179,6 +179,7 @@ Jrd::Attachment::Attachment(MemoryPool* pool, Database* dbb)
att_lock_owner_id(Database::getLockOwnerId()), att_lock_owner_id(Database::getLockOwnerId()),
att_backup_state_counter(0), att_backup_state_counter(0),
att_stats(*pool), att_stats(*pool),
att_base_stats(*pool),
att_working_directory(*pool), att_working_directory(*pool),
att_filename(*pool), att_filename(*pool),
att_timestamp(Firebird::TimeStamp::getCurrentTimeStamp()), att_timestamp(Firebird::TimeStamp::getCurrentTimeStamp()),
@ -381,6 +382,14 @@ void Jrd::Attachment::signalShutdown()
} }
void Jrd::Attachment::mergeStats()
{
MutexLockGuard guard(att_database->dbb_stats_mutex, FB_FUNCTION);
att_database->dbb_stats.adjust(att_base_stats, att_stats, true);
att_base_stats.assign(att_stats);
}
// Find an inactive incarnation of a system request. If necessary, clone it. // Find an inactive incarnation of a system request. If necessary, clone it.
jrd_req* Jrd::Attachment::findSystemRequest(thread_db* tdbb, USHORT id, USHORT which) jrd_req* Jrd::Attachment::findSystemRequest(thread_db* tdbb, USHORT id, USHORT which)
{ {

View File

@ -250,6 +250,7 @@ public:
SecurityClass* att_security_class; // security class for database SecurityClass* att_security_class; // security class for database
SecurityClassList* att_security_classes; // security classes SecurityClassList* att_security_classes; // security classes
RuntimeStatistics att_stats; RuntimeStatistics att_stats;
RuntimeStatistics att_base_stats;
ULONG att_flags; // Flags describing the state of the attachment ULONG att_flags; // Flags describing the state of the attachment
SSHORT att_client_charset; // user's charset specified in dpb SSHORT att_client_charset; // user's charset specified in dpb
SSHORT att_charset; // current (client or external) attachment charset SSHORT att_charset; // current (client or external) attachment charset
@ -355,6 +356,8 @@ public:
void signalCancel(); void signalCancel();
void signalShutdown(); void signalShutdown();
void mergeStats();
bool backupStateWriteLock(thread_db* tdbb, SSHORT wait); bool backupStateWriteLock(thread_db* tdbb, SSHORT wait);
void backupStateWriteUnLock(thread_db* tdbb); void backupStateWriteUnLock(thread_db* tdbb);
bool backupStateReadLock(thread_db* tdbb, SSHORT wait); bool backupStateReadLock(thread_db* tdbb, SSHORT wait);

View File

@ -447,8 +447,9 @@ public:
Firebird::Semaphore dbb_gc_fini; // Event for finalization garbage collector Firebird::Semaphore dbb_gc_fini; // Event for finalization garbage collector
Firebird::MemoryStats dbb_memory_stats; Firebird::MemoryStats dbb_memory_stats;
RuntimeStatistics dbb_stats; RuntimeStatistics dbb_stats;
mutable Firebird::Mutex dbb_stats_mutex;
TraNumber dbb_last_header_write; // Transaction id of last header page physical write TraNumber dbb_last_header_write; // Transaction id of last header page physical write
SLONG dbb_flush_cycle; // Current flush cycle SLONG dbb_flush_cycle; // Current flush cycle
ULONG dbb_sweep_interval; // Transactions between sweep ULONG dbb_sweep_interval; // Transactions between sweep

View File

@ -281,8 +281,6 @@ JrdStatement* JrdStatement::makeStatement(thread_db* tdbb, CompilerScratch* csb,
if (internalFlag) if (internalFlag)
statement->flags |= FLAG_INTERNAL; statement->flags |= FLAG_INTERNAL;
else
tdbb->bumpStats(RuntimeStatistics::STMT_PREPARES);
return statement; return statement;
} }

View File

@ -786,6 +786,7 @@ void Monitoring::putDatabase(SnapshotData::DumpRecord& record, const Database* d
if (database->dbb_flags & DBB_shared) if (database->dbb_flags & DBB_shared)
{ {
MutexLockGuard guard(database->dbb_stats_mutex, FB_FUNCTION);
putStatistics(record, database->dbb_stats, writer, stat_id, stat_database); putStatistics(record, database->dbb_stats, writer, stat_id, stat_database);
putMemoryUsage(record, database->dbb_memory_stats, writer, stat_id, stat_database); putMemoryUsage(record, database->dbb_memory_stats, writer, stat_id, stat_database);
} }
@ -876,6 +877,7 @@ void Monitoring::putAttachment(SnapshotData::DumpRecord& record, const Jrd::Atta
} }
else else
{ {
MutexLockGuard guard(attachment->att_database->dbb_stats_mutex, FB_FUNCTION);
putStatistics(record, attachment->att_database->dbb_stats, writer, stat_id, stat_attachment); 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); putMemoryUsage(record, attachment->att_database->dbb_memory_stats, writer, stat_id, stat_attachment);
} }
@ -1182,7 +1184,7 @@ void Monitoring::checkState(thread_db* tdbb)
} }
void Monitoring::dumpAttachment(thread_db* tdbb, const Attachment* attachment, bool ast) void Monitoring::dumpAttachment(thread_db* tdbb, Attachment* attachment, bool ast)
{ {
if (!attachment->att_user) if (!attachment->att_user)
return; return;
@ -1190,6 +1192,8 @@ void Monitoring::dumpAttachment(thread_db* tdbb, const Attachment* attachment, b
Database* const dbb = tdbb->getDatabase(); Database* const dbb = tdbb->getDatabase();
MemoryPool& pool = *dbb->dbb_permanent; MemoryPool& pool = *dbb->dbb_permanent;
attachment->mergeStats();
const AttNumber att_id = attachment->att_attachment_id; const AttNumber att_id = attachment->att_attachment_id;
const string& user_name = attachment->att_user->usr_user_name; const string& user_name = attachment->att_user->usr_user_name;

View File

@ -385,7 +385,7 @@ public:
static void checkState(thread_db* tdbb); static void checkState(thread_db* tdbb);
static SnapshotData* getSnapshot(thread_db* tdbb); static SnapshotData* getSnapshot(thread_db* tdbb);
static void dumpAttachment(thread_db* tdbb, const Attachment* attachment, bool ast); static void dumpAttachment(thread_db* tdbb, Attachment* attachment, bool ast);
static void publishAttachment(thread_db* tdbb); static void publishAttachment(thread_db* tdbb);
static void cleanupAttachment(thread_db* tdbb); static void cleanupAttachment(thread_db* tdbb);

View File

@ -50,7 +50,6 @@ public:
PAGE_READS, PAGE_READS,
PAGE_MARKS, PAGE_MARKS,
PAGE_WRITES, PAGE_WRITES,
FLUSHES,
RECORD_SEQ_READS, RECORD_SEQ_READS,
RECORD_IDX_READS, RECORD_IDX_READS,
RECORD_UPDATES, RECORD_UPDATES,
@ -65,23 +64,18 @@ public:
RECORD_BACKVERSION_READS, RECORD_BACKVERSION_READS,
RECORD_FRAGMENT_READS, RECORD_FRAGMENT_READS,
RECORD_RPT_READS, RECORD_RPT_READS,
SORTS,
SORT_GETS,
SORT_PUTS,
STMT_PREPARES,
STMT_EXECUTES,
TOTAL_ITEMS // last TOTAL_ITEMS // last
}; };
private:
static const size_t REL_BASE_OFFSET = RECORD_SEQ_READS;
static const size_t REL_TOTAL_ITEMS = RECORD_RPT_READS - REL_BASE_OFFSET + 1;
// Performance counters for individual table // Performance counters for individual table
class RelationCounts class RelationCounts
{ {
static const size_t REL_BASE_OFFSET = RECORD_SEQ_READS;
public: public:
static const size_t REL_TOTAL_ITEMS = RECORD_RPT_READS - REL_BASE_OFFSET + 1;
explicit RelationCounts(SLONG relation_id) explicit RelationCounts(SLONG relation_id)
: rlc_relation_id(relation_id) : rlc_relation_id(relation_id)
{ {
@ -158,6 +152,7 @@ public:
typedef Firebird::SortedArray<RelationCounts, Firebird::EmptyStorage<RelationCounts>, typedef Firebird::SortedArray<RelationCounts, Firebird::EmptyStorage<RelationCounts>,
SLONG, RelationCounts> RelCounters; SLONG, RelationCounts> RelCounters;
public:
RuntimeStatistics() RuntimeStatistics()
: Firebird::AutoStorage(), rel_counts(getPool()) : Firebird::AutoStorage(), rel_counts(getPool())
{ {
@ -226,12 +221,14 @@ public:
// add difference between newStats and baseStats to our counters // add difference between newStats and baseStats to our counters
// newStats and baseStats must be "in-sync" // newStats and baseStats must be "in-sync"
void adjust(const RuntimeStatistics& baseStats, const RuntimeStatistics& newStats) void adjust(const RuntimeStatistics& baseStats, const RuntimeStatistics& newStats, bool relStatsOnly = false)
{ {
if (baseStats.allChgNumber != newStats.allChgNumber) if (baseStats.allChgNumber != newStats.allChgNumber)
{ {
const size_t FIRST_ITEM = relStatsOnly ? REL_BASE_OFFSET : 0;
allChgNumber++; allChgNumber++;
for (size_t i = 0; i < TOTAL_ITEMS; ++i) for (size_t i = FIRST_ITEM; i < TOTAL_ITEMS; ++i)
values[i] += newStats.values[i] - baseStats.values[i]; values[i] += newStats.values[i] - baseStats.values[i];
if (baseStats.relChgNumber != newStats.relChgNumber) if (baseStats.relChgNumber != newStats.relChgNumber)

View File

@ -1037,8 +1037,6 @@ void CCH_flush(thread_db* tdbb, USHORT flush_flag, TraNumber tra_number)
if (backup_state == Ods::hdr_nbak_stalled || backup_state == Ods::hdr_nbak_merge) if (backup_state == Ods::hdr_nbak_stalled || backup_state == Ods::hdr_nbak_merge)
bm->flushDifference(tdbb); bm->flushDifference(tdbb);
} }
tdbb->bumpStats(RuntimeStatistics::FLUSHES);
} }
// take the opportunity when we know there are no pages // take the opportunity when we know there are no pages

View File

@ -902,9 +902,6 @@ void EXE_start(thread_db* tdbb, jrd_req* request, jrd_tra* transaction)
impure->vlu_flags = 0; impure->vlu_flags = 0;
} }
if (statement->sqlText)
tdbb->bumpStats(RuntimeStatistics::STMT_EXECUTES);
request->req_src_line = 0; request->req_src_line = 0;
request->req_src_column = 0; request->req_src_column = 0;

View File

@ -6358,6 +6358,8 @@ static void release_attachment(thread_db* tdbb, Jrd::Attachment* attachment)
attachment->deletePool(pool); attachment->deletePool(pool);
} }
attachment->mergeStats();
// remove the attachment block from the dbb linked list // remove the attachment block from the dbb linked list
Sync sync(&dbb->dbb_sync, "jrd.cpp: release_attachment"); Sync sync(&dbb->dbb_sync, "jrd.cpp: release_attachment");
sync.lock(SYNC_EXCLUSIVE); sync.lock(SYNC_EXCLUSIVE);
@ -7399,17 +7401,13 @@ void thread_db::setDatabase(Database* val)
const bool wasActive = database && (priorThread || nextThread || database->dbb_active_threads == this); const bool wasActive = database && (priorThread || nextThread || database->dbb_active_threads == this);
if (wasActive) if (wasActive)
{
deactivate(); deactivate();
}
database = val; database = val;
dbbStat = val ? &val->dbb_stats : RuntimeStatistics::getDummy(); dbbStat = val ? &val->dbb_stats : RuntimeStatistics::getDummy();
if (wasActive) if (wasActive)
{
activate(); activate();
}
} }
} }

View File

@ -459,12 +459,30 @@ public:
void bumpRelStats(const RuntimeStatistics::StatType index, SLONG relation_id, SINT64 delta = 1) void bumpRelStats(const RuntimeStatistics::StatType index, SLONG relation_id, SINT64 delta = 1)
{ {
bumpStats(index, delta); // We don't bump counters for dbbStat here, they're merged from attStats on demand
reqStat->bumpRelValue(index, relation_id, delta); reqStat->bumpValue(index, delta);
traStat->bumpRelValue(index, relation_id, delta); traStat->bumpValue(index, delta);
attStat->bumpRelValue(index, relation_id, delta); attStat->bumpValue(index, delta);
dbbStat->bumpRelValue(index, relation_id, delta);
const RuntimeStatistics* const dummyStat = RuntimeStatistics::getDummy();
// We expect that at least attStat is present (not a dummy object)
fb_assert(attStat != dummyStat);
// Relation statistics is a quite complex beast, so a conditional check
// does not hurt. It also allows to avoid races while accessing the static
// dummy object concurrently.
if (reqStat != dummyStat)
reqStat->bumpRelValue(index, relation_id, delta);
if (traStat != dummyStat)
traStat->bumpRelValue(index, relation_id, delta);
if (attStat != dummyStat)
attStat->bumpRelValue(index, relation_id, delta);
} }
ISC_STATUS checkCancelState(); ISC_STATUS checkCancelState();

View File

@ -342,8 +342,6 @@ void Sort::get(thread_db* tdbb, ULONG** record_address)
{ {
diddleKey((UCHAR*) record->sort_record_key, false); diddleKey((UCHAR*) record->sort_record_key, false);
} }
tdbb->bumpStats(RuntimeStatistics::SORT_GETS);
} }
catch (const BadAlloc&) catch (const BadAlloc&)
{ {
@ -419,8 +417,6 @@ void Sort::put(thread_db* tdbb, ULONG** record_address)
*m_next_pointer++ = reinterpret_cast<sort_record*>(record->sr_sort_record.sort_record_key); *m_next_pointer++ = reinterpret_cast<sort_record*>(record->sr_sort_record.sort_record_key);
m_records++; m_records++;
*record_address = (ULONG*) record->sr_sort_record.sort_record_key; *record_address = (ULONG*) record->sr_sort_record.sort_record_key;
tdbb->bumpStats(RuntimeStatistics::SORT_PUTS);
} }
catch (const BadAlloc&) catch (const BadAlloc&)
{ {
@ -463,7 +459,6 @@ void Sort::sort(thread_db* tdbb)
sort(); sort();
m_next_pointer = m_first_pointer + 1; m_next_pointer = m_first_pointer + 1;
m_flags |= scb_sorted; m_flags |= scb_sorted;
tdbb->bumpStats(RuntimeStatistics::SORTS);
return; return;
} }
@ -619,7 +614,6 @@ void Sort::sort(thread_db* tdbb)
sortRunsBySeek(run_count); sortRunsBySeek(run_count);
m_flags |= scb_sorted; m_flags |= scb_sorted;
tdbb->bumpStats(RuntimeStatistics::SORTS);
} }
catch (const BadAlloc&) catch (const BadAlloc&)
{ {