From a8b1dba646c4ced38a5aafdee65a9a75ab19f611 Mon Sep 17 00:00:00 2001 From: dimitr Date: Tue, 5 Aug 2014 08:46:09 +0000 Subject: [PATCH] Refactored RuntimeStatistics internals. Added more record-level performance counters. --- src/include/gen/ids.h | 5 + src/jrd/Monitoring.cpp | 7 +- src/jrd/RuntimeStatistics.cpp | 207 +++------------ src/jrd/RuntimeStatistics.h | 174 +++++++----- src/jrd/inf.cpp | 20 +- src/jrd/jrd.h | 20 +- src/jrd/names.h | 5 + src/jrd/relations.h | 5 + src/jrd/vio.cpp | 481 ++++++++++++++++------------------ 9 files changed, 418 insertions(+), 506 deletions(-) diff --git a/src/include/gen/ids.h b/src/include/gen/ids.h index 00594c70ee..721298d8c8 100644 --- a/src/include/gen/ids.h +++ b/src/include/gen/ids.h @@ -577,6 +577,11 @@ const USHORT f_mon_rec_backouts = 7; const USHORT f_mon_rec_purges = 8; const USHORT f_mon_rec_expunges = 9; + const USHORT f_mon_rec_locks = 10; + const USHORT f_mon_rec_waits = 11; + const USHORT f_mon_rec_conflicts = 12; + const USHORT f_mon_rec_ver_reads = 13; + const USHORT f_mon_rec_frg_reads = 14; // Relation 40 (MON$CONTEXT_VARIABLES) diff --git a/src/jrd/Monitoring.cpp b/src/jrd/Monitoring.cpp index ea5116f501..380f641653 100644 --- a/src/jrd/Monitoring.cpp +++ b/src/jrd/Monitoring.cpp @@ -1094,7 +1094,12 @@ void Monitoring::putStatistics(SnapshotData::DumpRecord& record, const RuntimeSt 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)); - writer.putRecord(record); + 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)); + record.storeInteger(f_mon_rec_ver_reads, statistics.getValue(RuntimeStatistics::RECORD_VERSION_READS)); + record.storeInteger(f_mon_rec_frg_reads, statistics.getValue(RuntimeStatistics::RECORD_FRAGMENT_READS)); + writer.putRecord(record); } void Monitoring::putContextVars(SnapshotData::DumpRecord& record, const StringMap& variables, diff --git a/src/jrd/RuntimeStatistics.cpp b/src/jrd/RuntimeStatistics.cpp index c8cfdfa231..378aadfb93 100644 --- a/src/jrd/RuntimeStatistics.cpp +++ b/src/jrd/RuntimeStatistics.cpp @@ -33,153 +33,18 @@ namespace Jrd { GlobalPtr RuntimeStatistics::dummy; -#ifdef REL_COUNTS_TREE - -void RuntimeStatistics::bumpRelValue(const RelStatType index, SLONG relation_id) -{ - fb_assert(index >= 0); - ++relChgNumber; - - RelCounters::Accessor accessor(&rel_counts); - if (accessor.locate(relation_id)) - accessor.current().rlc_counter[index]++; - else - { - RelationCounts counts; - memset(&counts, 0, sizeof(counts)); - counts.rlc_relation_id = relation_id; - counts.rlc_counter[index]++; - rel_counts.add(counts); - } -} - - -void RuntimeStatistics::addRelCounts(const RelCounters& other, bool add) -{ - RelCounters::Accessor first(&rel_counts); - RelCounters::ConstAccessor second(&other); - - if (second.getFirst()) - { - do - { - const RelationCounts& src = second.current(); - - if (!first.locate(src.rlc_relation_id)) - { - RelationCounts counts; - memset(&counts, 0, sizeof(counts)); - counts.rlc_relation_id = src.rlc_relation_id; - first.add(counts); - - first.locate(src.rlc_relation_id); - } - - RelationCounts& dst = first.current(); - fb_assert(src.rlc_relation_id == dst.rlc_relation_id); - - if (add) - { - for (int index = 0; index < FB_NELEM(src.rlc_counter); index++) - dst.rlc_counter[index] += src.rlc_counter[index]; - } - else - { - for (int index = 0; index < FB_NELEM(src.rlc_counter); index++) - dst.rlc_counter[index] -= src.rlc_counter[index]; - } - } while (second.getNext()); - } -} - - -PerformanceInfo* RuntimeStatistics::computeDifference( - Database* dbb, const RuntimeStatistics& new_stat, PerformanceInfo& dest, TraceCountsArray& temp) -{ - // NOTE: we do not initialize dest.pin_time. This must be done by the caller - - // Calculate database-level statistics - for (int i = 0; i < TOTAL_ITEMS; i++) - values[i] = new_stat.values[i] - values[i]; - - dest.pin_counters = values; - - // Calculate relation-level statistics - temp.clear(); - - RelCounters::ConstAccessor new_acc(&new_stat.rel_counts); - - if (new_acc.getFirst()) - { - // This loop assumes that base array is smaller than new one - RelCounters::Accessor base_acc(&rel_counts); - bool base_found = base_acc.getFirst(); - - do - { - const RelationCounts* counts = &new_acc.current(); - if (base_found && base_acc.current().rlc_relation_id == counts->rlc_relation_id) - { - RelationCounts* base_counts = &base_acc.current(); - bool all_zeros = true; - for (int i = 0; i < DBB_max_rel_count; i++) - { - if ((base_counts->rlc_counter[i] = counts->rlc_counter[i] - base_counts->rlc_counter[i])) - all_zeros = false; - } - - // Point TraceCounts to counts array from baseline object - if (!all_zeros) - { - jrd_rel* relation = counts->rlc_relation_id < dbb->dbb_relations->count() ? - (*dbb->dbb_relations)[counts->rlc_relation_id] : NULL; - TraceCounts traceCounts; - traceCounts.trc_relation_id = counts->rlc_relation_id; - traceCounts.trc_counters = base_counts->rlc_counter; - traceCounts.trc_relation_name = relation ? relation->rel_name.c_str() : NULL; - temp.add(traceCounts); - } - - base_found = base_acc.getNext(); - } - else - { - jrd_rel* relation = counts->rlc_relation_id < dbb->dbb_relations->count() ? - (*dbb->dbb_relations)[counts->rlc_relation_id] : NULL; - - // Point TraceCounts to counts array from object with updated counters - TraceCounts traceCounts; - traceCounts.trc_relation_id = counts->rlc_relation_id; - traceCounts.trc_counters = counts->rlc_counter; - traceCounts.trc_relation_name = relation ? relation->rel_name.c_str() : NULL; - temp.add(traceCounts); - } - } while (new_acc.getNext()); - } - - dest.pin_count = temp.getCount(); - dest.pin_tables = temp.begin(); - - return &dest; -} - -#else // REL_COUNTS_TREE - - -void RuntimeStatistics::bumpRelValue(const RelStatType index, SLONG relation_id) +void RuntimeStatistics::bumpRelValue(const StatType index, SLONG relation_id, SINT64 delta) { fb_assert(index >= 0); ++relChgNumber; FB_SIZE_T pos; if (rel_counts.find(relation_id, pos)) - rel_counts[pos].rlc_counter[index]++; + rel_counts[pos].bumpCounter(index, delta); else { - RelationCounts counts; - memset(&counts, 0, sizeof(counts)); - counts.rlc_relation_id = relation_id; - counts.rlc_counter[index]++; + RelationCounts counts(relation_id); + counts.bumpCounter(index, delta); rel_counts.add(counts); } } @@ -193,37 +58,26 @@ void RuntimeStatistics::addRelCounts(const RelCounters& other, bool add) const RelCounters::const_iterator end(other.end()); FB_SIZE_T pos; - rel_counts.find(src->rlc_relation_id, pos); + rel_counts.find(src->getRelationId(), pos); for (; src != end; ++src) { const FB_SIZE_T cnt = rel_counts.getCount(); - while (pos < cnt && rel_counts[pos].rlc_relation_id < src->rlc_relation_id) + while (pos < cnt && rel_counts[pos].getRelationId() < src->getRelationId()) pos++; - if (pos >= cnt || rel_counts[pos].rlc_relation_id > src->rlc_relation_id) + if (pos >= cnt || rel_counts[pos].getRelationId() > src->getRelationId()) { - RelationCounts counts; - memset(&counts, 0, sizeof(counts)); - counts.rlc_relation_id = src->rlc_relation_id; + RelationCounts counts(src->getRelationId()); rel_counts.insert(pos, counts); } fb_assert(pos >= 0 && pos < rel_counts.getCount()); - RelationCounts* dst = &(rel_counts[pos]); - fb_assert(dst->rlc_relation_id == src->rlc_relation_id); - if (add) - { - for (int index = 0; index < FB_NELEM(src->rlc_counter); index++) - dst->rlc_counter[index] += src->rlc_counter[index]; - } + rel_counts[pos] += *src; else - { - for (int index = 0; index < FB_NELEM(src->rlc_counter); index++) - dst->rlc_counter[index] -= src->rlc_counter[index]; - } + rel_counts[pos] -= *src; } } @@ -251,23 +105,18 @@ PerformanceInfo* RuntimeStatistics::computeDifference(Attachment* att, const RelCounters::const_iterator end = new_stat.rel_counts.end(); for (; new_cnts != end; ++new_cnts) { - if (base_found && base_cnts->rlc_relation_id == new_cnts->rlc_relation_id) + if (base_found && base_cnts->getRelationId() == new_cnts->getRelationId()) { - bool all_zeros = true; - for (int i = 0; i < DBB_max_rel_count; i++) - { - if ((base_cnts->rlc_counter[i] = new_cnts->rlc_counter[i] - base_cnts->rlc_counter[i])) - all_zeros = false; - } - // Point TraceCounts to counts array from baseline object - if (!all_zeros) + if (base_cnts->setToDiff(*new_cnts)) { - jrd_rel* relation = new_cnts->rlc_relation_id < static_cast(att->att_relations->count()) ? - (*att->att_relations)[new_cnts->rlc_relation_id] : NULL; + jrd_rel* const relation = + new_cnts->getRelationId() < static_cast(att->att_relations->count()) ? + (*att->att_relations)[new_cnts->getRelationId()] : NULL; + TraceCounts traceCounts; - traceCounts.trc_relation_id = new_cnts->rlc_relation_id; - traceCounts.trc_counters = base_cnts->rlc_counter; + traceCounts.trc_relation_id = new_cnts->getRelationId(); + traceCounts.trc_counters = base_cnts->getCounterVector(); traceCounts.trc_relation_name = relation ? relation->rel_name.c_str() : NULL; temp.add(traceCounts); } @@ -277,13 +126,14 @@ PerformanceInfo* RuntimeStatistics::computeDifference(Attachment* att, } else { - jrd_rel* relation = new_cnts->rlc_relation_id < static_cast(att->att_relations->count()) ? - (*att->att_relations)[new_cnts->rlc_relation_id] : NULL; + jrd_rel* const relation = + new_cnts->getRelationId() < static_cast(att->att_relations->count()) ? + (*att->att_relations)[new_cnts->getRelationId()] : NULL; // Point TraceCounts to counts array from object with updated counters TraceCounts traceCounts; - traceCounts.trc_relation_id = new_cnts->rlc_relation_id; - traceCounts.trc_counters = new_cnts->rlc_counter; + traceCounts.trc_relation_id = new_cnts->getRelationId(); + traceCounts.trc_counters = new_cnts->getCounterVector(); traceCounts.trc_relation_name = relation ? relation->rel_name.c_str() : NULL; temp.add(traceCounts); } @@ -294,6 +144,15 @@ PerformanceInfo* RuntimeStatistics::computeDifference(Attachment* att, return &dest; } -#endif // REL_COUNTS_TREE + +RuntimeStatistics::Accumulator::Accumulator(thread_db* tdbb, const jrd_rel* relation, StatType type) + : m_tdbb(tdbb), m_type(type), m_id(relation->rel_id), m_counter(0) +{} + +RuntimeStatistics::Accumulator::~Accumulator() +{ + if (m_counter) + m_tdbb->bumpRelStats(m_type, m_id, m_counter); +} } // namespace diff --git a/src/jrd/RuntimeStatistics.h b/src/jrd/RuntimeStatistics.h index 9fc64a858b..7c3e5207c8 100644 --- a/src/jrd/RuntimeStatistics.h +++ b/src/jrd/RuntimeStatistics.h @@ -33,58 +33,10 @@ struct PerformanceInfo; // declared in ntrace.h namespace Jrd { -// hvlad: what to use for relation's counters - tree or sorted array ? -// #define REL_COUNTS_TREE -// #define REL_COUNTS_PTR - class Attachment; class Database; - -// -// Database record counters. -// -enum RelStatType -{ - DBB_read_seq_count = 0, - DBB_read_idx_count, - DBB_update_count, - DBB_insert_count, - DBB_delete_count, - DBB_backout_count, - DBB_purge_count, - DBB_expunge_count, - DBB_lock_count, - DBB_max_count -}; - -// Performance counters for individual table -struct RelationCounts -{ - SLONG rlc_relation_id; // Relation ID - SINT64 rlc_counter[DBB_max_count]; - -#ifdef REL_COUNTS_PTR - inline static const SLONG* generate(const RelationCounts* item) - { - return &item->rlc_relation_id; - } -#else - inline static const SLONG& generate(const RelationCounts& item) - { - return item.rlc_relation_id; - } -#endif -}; - -#if defined(REL_COUNTS_TREE) -typedef Firebird::BePlusTree RelCounters; -#elif defined(REL_COUNTS_PTR) -typedef Firebird::PointersArray, - SLONG, RelationCounts> RelCounters; -#else -typedef Firebird::SortedArray, - SLONG, RelationCounts> RelCounters; -#endif +class thread_db; +class jrd_rel; typedef Firebird::HalfStaticArray TraceCountsArray; @@ -108,6 +60,10 @@ public: RECORD_PURGES, RECORD_EXPUNGES, RECORD_LOCKS, + RECORD_WAITS, + RECORD_CONFLICTS, + RECORD_VERSION_READS, + RECORD_FRAGMENT_READS, SORTS, SORT_GETS, SORT_PUTS, @@ -116,6 +72,91 @@ public: TOTAL_ITEMS // last }; + // Performance counters for individual table + + class RelationCounts + { + static const size_t REL_BASE_OFFSET = RECORD_SEQ_READS; + + public: + static const size_t REL_TOTAL_ITEMS = RECORD_FRAGMENT_READS - REL_BASE_OFFSET + 1; + + explicit RelationCounts(SLONG relation_id) + : rlc_relation_id(relation_id) + { + memset(rlc_counter, 0, sizeof(rlc_counter)); + } + + SLONG getRelationId() const + { + return rlc_relation_id; + } + + const SINT64* getCounterVector() const + { + return rlc_counter; + } + + SINT64 getCounter(size_t index) const + { + fb_assert(index >= REL_BASE_OFFSET && index < REL_BASE_OFFSET + REL_TOTAL_ITEMS); + return rlc_counter[index - REL_BASE_OFFSET]; + } + + void bumpCounter(size_t index, SINT64 delta = 1) + { + fb_assert(index >= REL_BASE_OFFSET && index < REL_BASE_OFFSET + REL_TOTAL_ITEMS); + rlc_counter[index - REL_BASE_OFFSET] += delta; + } + + bool setToDiff(const RelationCounts& other) + { + fb_assert(rlc_relation_id == other.rlc_relation_id); + + bool ret = false; + + for (size_t i = 0; i < REL_TOTAL_ITEMS; i++) + { + if ( (rlc_counter[i] = other.rlc_counter[i] - rlc_counter[i]) ) + ret = true; + } + + return ret; + } + + RelationCounts& operator+=(const RelationCounts& other) + { + fb_assert(rlc_relation_id == other.rlc_relation_id); + + for (size_t i = 0; i < REL_TOTAL_ITEMS; i++) + rlc_counter[i] += other.rlc_counter[i]; + + return *this; + } + + RelationCounts& operator-=(const RelationCounts& other) + { + fb_assert(rlc_relation_id == other.rlc_relation_id); + + for (size_t i = 0; i < REL_TOTAL_ITEMS; i++) + rlc_counter[i] -= other.rlc_counter[i]; + + return *this; + } + + inline static const SLONG& generate(const RelationCounts& item) + { + return item.rlc_relation_id; + } + + private: + SLONG rlc_relation_id; + SINT64 rlc_counter[REL_TOTAL_ITEMS]; + }; + + typedef Firebird::SortedArray, + SLONG, RelationCounts> RelCounters; + RuntimeStatistics() : Firebird::AutoStorage(), rel_counts(getPool()) { @@ -163,28 +204,25 @@ public: return values[index]; } - void bumpValue(const StatType index) + void bumpValue(const StatType index, SINT64 delta = 1) { - ++values[index]; + values[index] += delta; ++allChgNumber; } - SINT64 getRelValue(const RelStatType index, SLONG relation_id) const + SINT64 getRelValue(const StatType index, SLONG relation_id) const { FB_SIZE_T pos; - return rel_counts.find(relation_id, pos) ? rel_counts[pos].rlc_counter[index] : 0; + return rel_counts.find(relation_id, pos) ? rel_counts[pos].getCounter(index) : 0; } - void bumpRelValue(const RelStatType index, SLONG relation_id); + void bumpRelValue(const StatType index, SLONG relation_id, SINT64 delta = 1); // Calculate difference between counts stored in this object and current // counts of given request. Counts stored in object are destroyed. PerformanceInfo* computeDifference(Attachment* att, const RuntimeStatistics& new_stat, PerformanceInfo& dest, TraceCountsArray& temp); - // bool operator==(const RuntimeStatistics& other) const; - // bool operator!=(const RuntimeStatistics& other) const; - // add difference between newStats and baseStats to our counters // newStats and baseStats must be "in-sync" void adjust(const RuntimeStatistics& baseStats, const RuntimeStatistics& newStats) @@ -193,9 +231,7 @@ public: { allChgNumber++; for (size_t i = 0; i < TOTAL_ITEMS; ++i) - { values[i] += newStats.values[i] - baseStats.values[i]; - } if (baseStats.relChgNumber != newStats.relChgNumber) { @@ -276,6 +312,24 @@ public: return Iterator(rel_counts.end()); } + class Accumulator + { + public: + Accumulator(thread_db* tdbb, const jrd_rel* relation, StatType type); + ~Accumulator(); + + void operator++() + { + m_counter++; + } + + private: + thread_db* m_tdbb; + StatType m_type; + SLONG m_id; + SINT64 m_counter; + }; + private: void addRelCounts(const RelCounters& other, bool add); diff --git a/src/jrd/inf.cpp b/src/jrd/inf.cpp index 07ae33a008..04e7a457a8 100644 --- a/src/jrd/inf.cpp +++ b/src/jrd/inf.cpp @@ -344,42 +344,42 @@ void INF_database_info(thread_db* tdbb, break; case isc_info_read_seq_count: - length = get_counts(tdbb, DBB_read_seq_count, counts_buffer); + length = get_counts(tdbb, RuntimeStatistics::RECORD_SEQ_READS, counts_buffer); buffer = counts_buffer.begin(); break; case isc_info_read_idx_count: - length = get_counts(tdbb, DBB_read_idx_count, counts_buffer); + length = get_counts(tdbb, RuntimeStatistics::RECORD_IDX_READS, counts_buffer); buffer = counts_buffer.begin(); break; case isc_info_update_count: - length = get_counts(tdbb, DBB_update_count, counts_buffer); + length = get_counts(tdbb, RuntimeStatistics::RECORD_UPDATES, counts_buffer); buffer = counts_buffer.begin(); break; case isc_info_insert_count: - length = get_counts(tdbb, DBB_insert_count, counts_buffer); + length = get_counts(tdbb, RuntimeStatistics::RECORD_INSERTS, counts_buffer); buffer = counts_buffer.begin(); break; case isc_info_delete_count: - length = get_counts(tdbb, DBB_delete_count, counts_buffer); + length = get_counts(tdbb, RuntimeStatistics::RECORD_DELETES, counts_buffer); buffer = counts_buffer.begin(); break; case isc_info_backout_count: - length = get_counts(tdbb, DBB_backout_count, counts_buffer); + length = get_counts(tdbb, RuntimeStatistics::RECORD_BACKOUTS, counts_buffer); buffer = counts_buffer.begin(); break; case isc_info_purge_count: - length = get_counts(tdbb, DBB_purge_count, counts_buffer); + length = get_counts(tdbb, RuntimeStatistics::RECORD_PURGES, counts_buffer); buffer = counts_buffer.begin(); break; case isc_info_expunge_count: - length = get_counts(tdbb, DBB_expunge_count, counts_buffer); + length = get_counts(tdbb, RuntimeStatistics::RECORD_EXPUNGES, counts_buffer); buffer = counts_buffer.begin(); break; @@ -1202,8 +1202,8 @@ static USHORT get_counts(thread_db* tdbb, USHORT count_id, CountsBuffer& buffer) for (RuntimeStatistics::Iterator iter = stats.begin(); iter != stats.end(); ++iter) { - const USHORT relation_id = (*iter).rlc_relation_id; - const SINT64 n = (*iter).rlc_counter[count_id]; + const USHORT relation_id = (*iter).getRelationId(); + const SINT64 n = (*iter).getCounter(count_id); if (n) { diff --git a/src/jrd/jrd.h b/src/jrd/jrd.h index fc86d35fa0..5cc213ddf6 100644 --- a/src/jrd/jrd.h +++ b/src/jrd/jrd.h @@ -483,19 +483,21 @@ public: SSHORT getCharSet() const; - void bumpStats(const RuntimeStatistics::StatType index) + void bumpStats(const RuntimeStatistics::StatType index, SINT64 delta = 1) { - reqStat->bumpValue(index); - traStat->bumpValue(index); - attStat->bumpValue(index); - dbbStat->bumpValue(index); + reqStat->bumpValue(index, delta); + traStat->bumpValue(index, delta); + attStat->bumpValue(index, delta); + dbbStat->bumpValue(index, delta); } - void bumpRelStats(const RelStatType index, SLONG relation_id) + void bumpRelStats(const RuntimeStatistics::StatType index, SLONG relation_id, SINT64 delta = 1) { - reqStat->bumpRelValue(index, relation_id); - traStat->bumpRelValue(index, relation_id); - attStat->bumpRelValue(index, relation_id); + bumpStats(index, delta); + + reqStat->bumpRelValue(index, relation_id, delta); + traStat->bumpRelValue(index, relation_id, delta); + attStat->bumpRelValue(index, relation_id, delta); //dbbStat->bumpRelValue(index, relation_id); } diff --git a/src/jrd/names.h b/src/jrd/names.h index d98c7807da..77c3736817 100644 --- a/src/jrd/names.h +++ b/src/jrd/names.h @@ -296,6 +296,7 @@ NAME("MON$DATABASE", nam_mon_database) NAME("MON$DATABASE_NAME", nam_mon_db_name) NAME("MON$EXPLAINED_PLAN", nam_mon_expl_plan) NAME("MON$FORCED_WRITES", nam_mon_forced_writes) +NAME("MON$FRAGMENT_READS", nam_mon_fragment_reads) NAME("MON$GARBAGE_COLLECTION", nam_mon_gc) NAME("MON$IO_STATS", nam_mon_io_stats) NAME("MON$ISOLATION_MODE", nam_mon_iso_mode) @@ -325,14 +326,17 @@ NAME("MON$PAGE_READS", nam_mon_page_reads) NAME("MON$PAGE_WRITES", nam_mon_page_writes) NAME("MON$PAGES", nam_mon_pages) NAME("MON$RECORD_BACKOUTS", nam_mon_rec_backouts) +NAME("MON$RECORD_CONFLICTS", nam_mon_rec_conflicts) NAME("MON$RECORD_DELETES", nam_mon_rec_deletes) NAME("MON$RECORD_EXPUNGES", nam_mon_rec_expunges) NAME("MON$RECORD_IDX_READS", nam_mon_rec_idx_reads) NAME("MON$RECORD_INSERTS", nam_mon_rec_inserts) +NAME("MON$RECORD_LOCKS", nam_mon_rec_locks) NAME("MON$RECORD_PURGES", nam_mon_rec_purges) NAME("MON$RECORD_SEQ_READS", nam_mon_rec_seq_reads) NAME("MON$RECORD_STATS", nam_mon_rec_stats) NAME("MON$RECORD_UPDATES", nam_mon_rec_updates) +NAME("MON$RECORD_WAITS", nam_mon_rec_waits) NAME("MON$REMOTE_ADDRESS", nam_mon_remote_addr) NAME("MON$REMOTE_HOST", nam_mon_remote_host) NAME("MON$REMOTE_OS_USER", nam_mon_remote_os_user) @@ -361,6 +365,7 @@ NAME("MON$TRANSACTION_ID", nam_mon_tra_id) NAME("MON$USER", nam_mon_user) NAME("MON$VARIABLE_NAME", nam_mon_var_name) NAME("MON$VARIABLE_VALUE", nam_mon_var_value) +NAME("MON$VERSION_READS", nam_mon_version_reads) NAME("SEC$USERS", nam_sec_users) NAME("SEC$USER_ATTRIBUTES", nam_sec_user_attributes) diff --git a/src/jrd/relations.h b/src/jrd/relations.h index e8d8e3d218..039852d1c8 100644 --- a/src/jrd/relations.h +++ b/src/jrd/relations.h @@ -576,6 +576,11 @@ RELATION(nam_mon_rec_stats, rel_mon_rec_stats, ODS_11_1, rel_virtual) FIELD(f_mon_rec_backouts, nam_mon_rec_backouts, fld_counter, 0, ODS_11_1) FIELD(f_mon_rec_purges, nam_mon_rec_purges, fld_counter, 0, ODS_11_1) FIELD(f_mon_rec_expunges, nam_mon_rec_expunges, fld_counter, 0, ODS_11_1) + FIELD(f_mon_rec_locks, nam_mon_rec_locks, fld_counter, 0, ODS_12_0) + FIELD(f_mon_rec_waits, nam_mon_rec_waits, fld_counter, 0, ODS_12_0) + FIELD(f_mon_rec_conflicts, nam_mon_rec_conflicts, fld_counter, 0, ODS_12_0) + FIELD(f_mon_rec_ver_reads, nam_mon_version_reads, fld_counter, 0, ODS_12_0) + FIELD(f_mon_rec_frg_reads, nam_mon_fragment_reads, fld_counter, 0, ODS_12_0) END_RELATION // Relation 40 (MON$CONTEXT_VARIABLES) diff --git a/src/jrd/vio.cpp b/src/jrd/vio.cpp index 1a65fa6c99..40a42b83d8 100644 --- a/src/jrd/vio.cpp +++ b/src/jrd/vio.cpp @@ -204,6 +204,16 @@ inline void check_gbak_cheating_delete(thread_db* tdbb, const jrd_rel* relation) } } +inline int wait(thread_db* tdbb, jrd_tra* transaction, + const record_param* rpb, jrd_tra::wait_t wait) +{ + const SSHORT timeout = (wait == jrd_tra::tra_wait) ? transaction->getLockWait() : 0; + + if (timeout) + tdbb->bumpRelStats(RuntimeStatistics::RECORD_WAITS, rpb->rpb_relation->rel_id); + + return TRA_wait(tdbb, transaction, rpb->rpb_transaction_nr, wait); +} static const UCHAR gc_tpb[] = { @@ -280,13 +290,12 @@ IPTR VIO_savepoint_large(const Savepoint* savepoint, IPTR size) { // Estimate size used for record backout bitmaps for this table - if (verb_actions->vct_records) { + if (verb_actions->vct_records) size -= verb_actions->vct_records->approxSize(); - } - if (size < 0) { + if (size < 0) break; - } + verb_actions = verb_actions->vct_next; } @@ -326,9 +335,7 @@ void VIO_backout(thread_db* tdbb, record_param* rpb, const jrd_tra* transaction) rpb->rpb_number.getValue(), transaction ? transaction->tra_number : 0); #endif - jrd_rel* relation = rpb->rpb_relation; - tdbb->bumpRelStats(DBB_backout_count, relation->rel_id); - tdbb->bumpStats(RuntimeStatistics::RECORD_BACKOUTS); + jrd_rel* const relation = rpb->rpb_relation; // If there is data in the record, fetch it now. If the old version // is a differences record, we will need it sooner. In any case, we @@ -336,9 +343,8 @@ void VIO_backout(thread_db* tdbb, record_param* rpb, const jrd_tra* transaction) // has changed in between, stop now before things get worse. record_param temp = *rpb; - if (!DPM_get(tdbb, &temp, LCK_read)) { + if (!DPM_get(tdbb, &temp, LCK_read)) return; - } #ifdef VIO_DEBUG VIO_trace(DEBUG_WRITES_INFO, @@ -400,19 +406,23 @@ void VIO_backout(thread_db* tdbb, record_param* rpb, const jrd_tra* transaction) { if (!DPM_get(tdbb, &temp, LCK_read)) goto gc_cleanup; + if (temp.rpb_b_page != rpb->rpb_b_page || temp.rpb_b_line != rpb->rpb_b_line || temp.rpb_transaction_nr != rpb->rpb_transaction_nr) { CCH_RELEASE(tdbb, &temp.getWindow(tdbb)); goto gc_cleanup; } + if (temp.rpb_flags & rpb_delta) temp.rpb_prior = data; + if (!DPM_fetch_back(tdbb, &temp, LCK_read, -1)) { fb_utils::init_status(tdbb->tdbb_status_vector); continue; } + if (temp.rpb_flags & rpb_deleted) CCH_RELEASE(tdbb, &temp.getWindow(tdbb)); else @@ -572,6 +582,8 @@ void VIO_backout(thread_db* tdbb, record_param* rpb, const jrd_tra* transaction) gc_rec1->rec_flags &= ~REC_gc_active; if (gc_rec2) gc_rec2->rec_flags &= ~REC_gc_active; + + tdbb->bumpRelStats(RuntimeStatistics::RECORD_BACKOUTS, relation->rel_id); } @@ -594,11 +606,13 @@ bool VIO_chase_record_version(thread_db* tdbb, record_param* rpb, * **************************************/ SET_TDBB(tdbb); - Jrd::Attachment* attachment = transaction->tra_attachment; + Database* const dbb = tdbb->getDatabase(); + Jrd::Attachment* const attachment = transaction->tra_attachment; + jrd_rel* const relation = rpb->rpb_relation; - const bool gcPolicyCooperative = tdbb->getDatabase()->dbb_flags & DBB_gc_cooperative; - const bool gcPolicyBackground = tdbb->getDatabase()->dbb_flags & DBB_gc_background; - const TraNumber oldest_snapshot = rpb->rpb_relation->isTemporary() ? + const bool gcPolicyCooperative = dbb->dbb_flags & DBB_gc_cooperative; + const bool gcPolicyBackground = dbb->dbb_flags & DBB_gc_background; + const TraNumber oldest_snapshot = relation->isTemporary() ? attachment->att_oldest_snapshot : transaction->tra_oldest_active; #ifdef VIO_DEBUG @@ -630,19 +644,18 @@ bool VIO_chase_record_version(thread_db* tdbb, record_param* rpb, if (rpb->rpb_flags & rpb_gc_active) { - if (!rpb->rpb_transaction_nr) { + if (!rpb->rpb_transaction_nr) state = tra_active; - } - if (state == tra_committed) { + if (state == tra_committed) state = TRA_pc_active(tdbb, rpb->rpb_transaction_nr) ? tra_precommitted : tra_dead; - } - if (state == tra_dead) { + if (state == tra_dead) rpb->rpb_flags &= ~rpb_gc_active; - } } + RuntimeStatistics::Accumulator versions(tdbb, relation, RuntimeStatistics::RECORD_VERSION_READS); + rpb->rpb_stream_flags &= ~RPB_s_undo_data; int forceBack = 0; @@ -670,6 +683,7 @@ bool VIO_chase_record_version(thread_db* tdbb, record_param* rpb, if (gcPolicyBackground && rpb->rpb_b_page) notify_garbage_collector(tdbb, rpb); + ++versions; return true; } @@ -689,17 +703,21 @@ bool VIO_chase_record_version(thread_db* tdbb, record_param* rpb, rpb->rpb_flags, rpb->rpb_b_page, rpb->rpb_b_line, rpb->rpb_f_page, rpb->rpb_f_line); #endif + ++versions; + if (rpb->rpb_flags & rpb_damaged) { CCH_RELEASE(tdbb, &rpb->getWindow(tdbb)); return false; } + if (state == tra_limbo && !(transaction->tra_flags & TRA_ignore_limbo)) { - state = TRA_wait(tdbb, transaction, rpb->rpb_transaction_nr, jrd_tra::tra_wait); + state = wait(tdbb, transaction, rpb, jrd_tra::tra_wait); if (state == tra_active) state = tra_limbo; } + if (state == tra_precommitted) state = check_precommitted(transaction, rpb); @@ -712,7 +730,7 @@ bool VIO_chase_record_version(thread_db* tdbb, record_param* rpb, if (state == tra_limbo) { CCH_RELEASE(tdbb, &rpb->getWindow(tdbb)); - state = TRA_wait(tdbb, transaction, rpb->rpb_transaction_nr, jrd_tra::tra_wait); + state = wait(tdbb, transaction, rpb, jrd_tra::tra_wait); if (!DPM_get(tdbb, rpb, LCK_read)) return false; @@ -744,7 +762,7 @@ bool VIO_chase_record_version(thread_db* tdbb, record_param* rpb, // of a dead record version. CCH_RELEASE(tdbb, &rpb->getWindow(tdbb)); - state = TRA_wait(tdbb, transaction, rpb->rpb_transaction_nr, jrd_tra::tra_wait); + state = wait(tdbb, transaction, rpb, jrd_tra::tra_wait); if (state == tra_precommitted) state = check_precommitted(transaction, rpb); @@ -759,10 +777,8 @@ bool VIO_chase_record_version(thread_db* tdbb, record_param* rpb, // could have updated the record a second time. // go back to outer loop - - if (!DPM_get(tdbb, rpb, LCK_read)) { + if (!DPM_get(tdbb, rpb, LCK_read)) return false; - } state = TRA_snapshot_state(tdbb, transaction, rpb->rpb_transaction_nr); continue; @@ -802,6 +818,7 @@ bool VIO_chase_record_version(thread_db* tdbb, record_param* rpb, CCH_RELEASE(tdbb, &rpb->getWindow(tdbb)); return false; } + record_param temp = *rpb; if ((!(rpb->rpb_flags & rpb_deleted)) || (rpb->rpb_flags & rpb_delta)) { @@ -811,9 +828,9 @@ bool VIO_chase_record_version(thread_db* tdbb, record_param* rpb, if (!(DPM_fetch(tdbb, rpb, LCK_read))) { - if (!DPM_get(tdbb, rpb, LCK_read)) { + if (!DPM_get(tdbb, rpb, LCK_read)) return false; - } + break; } @@ -822,40 +839,42 @@ bool VIO_chase_record_version(thread_db* tdbb, record_param* rpb, rpb->rpb_flags != temp.rpb_flags) { CCH_RELEASE(tdbb, &rpb->getWindow(tdbb)); - if (!DPM_get(tdbb, rpb, LCK_read)) { + + if (!DPM_get(tdbb, rpb, LCK_read)) return false; - } + break; } - if (temp.rpb_transaction_nr != rpb->rpb_transaction_nr) { + + if (temp.rpb_transaction_nr != rpb->rpb_transaction_nr) break; - } + if (rpb->rpb_b_page == 0) { CCH_RELEASE(tdbb, &rpb->getWindow(tdbb)); return false; } - if (rpb->rpb_flags & rpb_delta) { + + if (rpb->rpb_flags & rpb_delta) rpb->rpb_prior = rpb->rpb_record; - } } // Fetch a back version. If a latch timeout occurs, refetch the // primary version and start again. If the primary version is // gone, then return 'record not found'. if (!DPM_fetch_back(tdbb, rpb, LCK_read, -1)) { - if (!DPM_get(tdbb, rpb, LCK_read)) { + if (!DPM_get(tdbb, rpb, LCK_read)) return false; - } } break; } CCH_RELEASE(tdbb, &rpb->getWindow(tdbb)); VIO_backout(tdbb, rpb, transaction); - if (!DPM_get(tdbb, rpb, LCK_read)) { + + if (!DPM_get(tdbb, rpb, LCK_read)) return false; - } + break; // If it's active, prepare to fetch the old version. @@ -882,7 +901,6 @@ bool VIO_chase_record_version(thread_db* tdbb, record_param* rpb, rpb->rpb_transaction_nr, transaction->tra_number); } #endif - // we can't use this one so if there aren't any more just stop now. if (rpb->rpb_b_page == 0) @@ -903,15 +921,16 @@ bool VIO_chase_record_version(thread_db* tdbb, record_param* rpb, if (!(rpb->rpb_flags & rpb_delta)) { rpb->rpb_prior = NULL; + // Fetch a back version. If a latch timeout occurs, refetch the // primary version and start again. If the primary version is // gone, then return 'record not found'. if (!DPM_fetch_back(tdbb, rpb, LCK_read, -1)) { - if (!DPM_get(tdbb, rpb, LCK_read)) { + if (!DPM_get(tdbb, rpb, LCK_read)) return false; - } } + break; } else @@ -931,9 +950,9 @@ bool VIO_chase_record_version(thread_db* tdbb, record_param* rpb, if (!DPM_fetch(tdbb, rpb, LCK_read)) { // Things have changed, start all over again. - if (!DPM_get(tdbb, rpb, LCK_read)) { + if (!DPM_get(tdbb, rpb, LCK_read)) return false; // entire record disappeared - } + break; // start from the primary version again } } @@ -944,34 +963,37 @@ bool VIO_chase_record_version(thread_db* tdbb, record_param* rpb, if (!DPM_fetch(tdbb, rpb, LCK_read)) { // Things have changed, start all over again. - if (!DPM_get(tdbb, rpb, LCK_read)) { + if (!DPM_get(tdbb, rpb, LCK_read)) return false; // entire record disappeared - } + break; // start from the primary version again } + if (rpb->rpb_transaction_nr != temp.rpb_transaction_nr) { CCH_RELEASE(tdbb, &rpb->getWindow(tdbb)); - if (!DPM_get(tdbb, rpb, LCK_read)) { + if (!DPM_get(tdbb, rpb, LCK_read)) return false; - } + break; } + if (rpb->rpb_b_page == 0) { CCH_RELEASE(tdbb, &rpb->getWindow(tdbb)); return false; } + if (!(rpb->rpb_flags & rpb_delta)) rpb->rpb_prior = NULL; + // Fetch a back version. If a latch timeout occurs, refetch the // primary version and start again. If the primary version is // gone, then return 'record not found'. if (!DPM_fetch_back(tdbb, rpb, LCK_read, -1)) { - if (!DPM_get(tdbb, rpb, LCK_read)) { + if (!DPM_get(tdbb, rpb, LCK_read)) return false; - } } } } @@ -1037,8 +1059,10 @@ bool VIO_chase_record_version(thread_db* tdbb, record_param* rpb, CCH_RELEASE(tdbb, &rpb->getWindow(tdbb)); expunge(tdbb, rpb, transaction, 0); } + return false; } + CCH_RELEASE(tdbb, &rpb->getWindow(tdbb)); return false; } @@ -1062,6 +1086,7 @@ bool VIO_chase_record_version(thread_db* tdbb, record_param* rpb, // VIO_chase_record_version notify_garbage_collector(tdbb, rpb); } + return true; } @@ -1077,9 +1102,8 @@ bool VIO_chase_record_version(thread_db* tdbb, record_param* rpb, purge(tdbb, rpb); // Go back to be primary record version and chase versions all over again. - if (!DPM_get(tdbb, rpb, LCK_read)) { + if (!DPM_get(tdbb, rpb, LCK_read)) return false; - } } // switch (state) state = TRA_snapshot_state(tdbb, transaction, rpb->rpb_transaction_nr); @@ -1092,17 +1116,14 @@ bool VIO_chase_record_version(thread_db* tdbb, record_param* rpb, if (!(rpb->rpb_flags & rpb_chained) && (rpb->rpb_flags & rpb_gc_active)) { - if (!rpb->rpb_transaction_nr) { + if (!rpb->rpb_transaction_nr) state = tra_active; - } - if (state == tra_committed) { + if (state == tra_committed) state = TRA_pc_active(tdbb, rpb->rpb_transaction_nr) ? tra_precommitted : tra_dead; - } - if (state == tra_dead) { + if (state == tra_dead) rpb->rpb_flags &= ~rpb_gc_active; - } } } } @@ -1130,9 +1151,7 @@ void VIO_copy_record(thread_db* tdbb, record_param* org_rpb, record_param* new_r // fetched and moved separately, remembering to set the missing flag. if (new_rpb->rpb_format_number == org_rpb->rpb_format_number) - { memcpy(new_rpb->rpb_address, org_record->rec_data, new_rpb->rpb_length); - } else { DSC org_desc, new_desc; @@ -1144,17 +1163,13 @@ void VIO_copy_record(thread_db* tdbb, record_param* org_rpb, record_param* new_r if (EVL_field(new_rpb->rpb_relation, new_record, i, &new_desc)) { if (EVL_field(org_rpb->rpb_relation, org_record, i, &org_desc)) - { MOV_move(tdbb, &org_desc, &new_desc); - } else { new_record->setNull(i); if (new_desc.dsc_dtype) - { memset(new_desc.dsc_address, 0, new_desc.dsc_length); - } } } } @@ -1199,6 +1214,7 @@ void VIO_data(thread_db* tdbb, record_param* rpb, MemoryPool* pool) // the format block and set up the record block. This is a performance // optimization. + jrd_rel* const relation = rpb->rpb_relation; Record* record = VIO_record(tdbb, rpb, 0, pool); const Format* format = record->rec_format; @@ -1237,6 +1253,8 @@ void VIO_data(thread_db* tdbb, record_param* rpb, MemoryPool* pool) tail = Compressor::unpack(rpb->rpb_length, rpb->rpb_address, tail_end - tail, tail); + RuntimeStatistics::Accumulator fragments(tdbb, relation, RuntimeStatistics::RECORD_FRAGMENT_READS); + if (rpb->rpb_flags & rpb_incomplete) { const ULONG back_page = rpb->rpb_b_page; @@ -1245,8 +1263,8 @@ void VIO_data(thread_db* tdbb, record_param* rpb, MemoryPool* pool) while (rpb->rpb_flags & rpb_incomplete) { DPM_fetch_fragment(tdbb, rpb, LCK_read); - tail = Compressor::unpack(rpb->rpb_length, rpb->rpb_address, tail_end - tail, tail); + ++fragments; } rpb->rpb_b_page = back_page; rpb->rpb_b_line = back_line; @@ -1772,15 +1790,12 @@ void VIO_erase(thread_db* tdbb, record_param* rpb, jrd_tra* transaction) verb_post(tdbb, transaction, rpb, 0, same_tx, false); } - tdbb->bumpRelStats(DBB_delete_count, relation->rel_id); - tdbb->bumpStats(RuntimeStatistics::RECORD_DELETES); + tdbb->bumpRelStats(RuntimeStatistics::RECORD_DELETES, relation->rel_id); // for an autocommit transaction, mark a commit as necessary if (transaction->tra_flags & TRA_autocommit) - { transaction->tra_flags |= TRA_perform_autocommit; - } // VIO_erase if ((tdbb->getDatabase()->dbb_flags & DBB_gc_background) && !rpb->rpb_relation->isTemporary()) @@ -1846,9 +1861,8 @@ bool VIO_garbage_collect(thread_db* tdbb, record_param* rpb, const jrd_tra* tran rpb->rpb_f_page, rpb->rpb_f_line); #endif - if (attachment->att_flags & ATT_no_cleanup) { + if (attachment->att_flags & ATT_no_cleanup) return true; - } const TraNumber oldest_snapshot = rpb->rpb_relation->isTemporary() ? attachment->att_oldest_snapshot : transaction->tra_oldest_active; @@ -1891,9 +1905,7 @@ bool VIO_garbage_collect(thread_db* tdbb, record_param* rpb, const jrd_tra* tran if (rpb->rpb_flags & rpb_deleted) { if (rpb->rpb_transaction_nr >= oldest_snapshot) - { return true; - } CCH_RELEASE(tdbb, &rpb->getWindow(tdbb)); expunge(tdbb, rpb, transaction, 0); @@ -1901,16 +1913,13 @@ bool VIO_garbage_collect(thread_db* tdbb, record_param* rpb, const jrd_tra* tran } if (rpb->rpb_transaction_nr >= oldest_snapshot || rpb->rpb_b_page == 0) - { return true; - } purge(tdbb, rpb); } - if (!DPM_get(tdbb, rpb, LCK_read)) { + if (!DPM_get(tdbb, rpb, LCK_read)) return false; - } } } @@ -1960,9 +1969,9 @@ Record* VIO_gc_record(thread_db* tdbb, jrd_rel* relation) // Insert the new record block into the last slot of the vector. FB_SIZE_T slot = vector->count() - 1; - if ((*vector)[slot]) { + if ((*vector)[slot]) vector->resize((++slot) + 1); - } + (*vector)[slot] = record; return record; @@ -2012,13 +2021,9 @@ bool VIO_get(thread_db* tdbb, record_param* rpb, jrd_tra* transaction, MemoryPoo #endif if (rpb->rpb_stream_flags & RPB_s_undo_data) - { fb_assert(rpb->getWindow(tdbb).win_bdb == NULL); - } else - { fb_assert(rpb->getWindow(tdbb).win_bdb != NULL); - } if (pool && !(rpb->rpb_stream_flags & RPB_s_undo_data)) { @@ -2032,9 +2037,7 @@ bool VIO_get(thread_db* tdbb, record_param* rpb, jrd_tra* transaction, MemoryPoo VIO_data(tdbb, rpb, pool); } - tdbb->bumpRelStats(DBB_read_idx_count, rpb->rpb_relation->rel_id); - tdbb->bumpStats(RuntimeStatistics::RECORD_IDX_READS); - + tdbb->bumpRelStats(RuntimeStatistics::RECORD_IDX_READS, rpb->rpb_relation->rel_id); return true; } @@ -2079,9 +2082,8 @@ bool VIO_get_current(thread_db* tdbb, { // If the record doesn't exist, no problem. - if (!DPM_get(tdbb, rpb, LCK_read)) { + if (!DPM_get(tdbb, rpb, LCK_read)) return false; - } #ifdef VIO_DEBUG VIO_trace(DEBUG_TRACE_INFO, @@ -2094,32 +2096,25 @@ bool VIO_get_current(thread_db* tdbb, // Get data if there is data. - if (rpb->rpb_flags & rpb_deleted) { + if (rpb->rpb_flags & rpb_deleted) CCH_RELEASE(tdbb, &rpb->getWindow(tdbb)); - } - else { + else VIO_data(tdbb, rpb, pool); - } // If we deleted the record, everything's fine, otherwise // the record must be considered real. - if (rpb->rpb_transaction_nr == transaction->tra_number) { + if (rpb->rpb_transaction_nr == transaction->tra_number) break; - } // check the state of transaction - tra_us is taken care of above // For now check the state in the tip_cache or tip bitmap. If // record is committed (most cases), this will be faster. - int state; - if (transaction->tra_flags & TRA_read_committed) { - state = TPC_cache_state(tdbb, rpb->rpb_transaction_nr); - } - else { - state = TRA_snapshot_state(tdbb, transaction, rpb->rpb_transaction_nr); - } + int state = (transaction->tra_flags & TRA_read_committed) ? + TPC_cache_state(tdbb, rpb->rpb_transaction_nr) : + TRA_snapshot_state(tdbb, transaction, rpb->rpb_transaction_nr); // Reset the garbage collect active flag if the transaction state is // in a terminal state. If committed it must have been a precommitted @@ -2164,14 +2159,14 @@ bool VIO_get_current(thread_db* tdbb, if (!(rpb->rpb_flags & rpb_gc_active)) { - state = TRA_wait(tdbb, transaction, rpb->rpb_transaction_nr, jrd_tra::tra_wait); + state = wait(tdbb, transaction, rpb, jrd_tra::tra_wait); if (state == tra_precommitted) state = check_precommitted(transaction, rpb); } else { - state = TRA_wait(tdbb, transaction, rpb->rpb_transaction_nr, jrd_tra::tra_probe); + state = wait(tdbb, transaction, rpb, jrd_tra::tra_probe); if (state == tra_active) { @@ -2189,9 +2184,8 @@ bool VIO_get_current(thread_db* tdbb, // removed the records it modified and marked itself // committed - if (!DPM_get(tdbb, rpb, LCK_read)) { + if (!DPM_get(tdbb, rpb, LCK_read)) return false; - } // if the transaction actually rolled back and what // we are reading is another record (newly inserted), @@ -2245,9 +2239,8 @@ bool VIO_get_current(thread_db* tdbb, return true; case tra_dead: - if (transaction->tra_attachment->att_flags & ATT_no_cleanup) { + if (transaction->tra_attachment->att_flags & ATT_no_cleanup) return !foreign_key; - } VIO_backout(tdbb, rpb, transaction); break; @@ -2281,9 +2274,7 @@ void VIO_init(thread_db* tdbb) Jrd::Attachment* attachment = tdbb->getAttachment(); if (dbb->readOnly() || !(dbb->dbb_flags & DBB_gc_background)) - { return; - } // If there's no presence of a garbage collector running then start one up. @@ -2331,12 +2322,11 @@ void VIO_merge_proc_sav_points(thread_db* tdbb, jrd_tra* transaction, Savepoint* **************************************/ SET_TDBB(tdbb); - if (transaction->tra_flags & TRA_system) { + if (transaction->tra_flags & TRA_system) return; - } - if (!transaction->tra_save_point) { + + if (!transaction->tra_save_point) return; - } // Merge all savepoints in the sav_point_list at the top // of transaction save points and call VIO_verb_cleanup() @@ -2350,18 +2340,15 @@ void VIO_merge_proc_sav_points(thread_db* tdbb, jrd_tra* transaction, Savepoint* const SLONG sav_number = sav_point->sav_number; if (!sav_point->sav_next) - { sav_point->sav_next = org_save_point; - } VIO_verb_cleanup(tdbb, transaction); - if ( (sav_point = transaction->tra_save_free) ) { + if ( (sav_point = transaction->tra_save_free) ) transaction->tra_save_free = sav_point->sav_next; - } - else { + else sav_point = FB_NEW(*transaction->tra_pool) Savepoint(); - } + sav_point->sav_next = sav_next; sav_point->sav_number = sav_number; *sav_point_list = sav_point; @@ -2423,12 +2410,10 @@ void VIO_modify(thread_db* tdbb, record_param* org_rpb, record_param* new_rpb, j // If we're the system transaction, modify stuff in place. This saves // endless grief on cleanup - tdbb->bumpRelStats(DBB_update_count, relation->rel_id); - tdbb->bumpStats(RuntimeStatistics::RECORD_UPDATES); - if (transaction->tra_flags & TRA_system) { update_in_place(tdbb, transaction, org_rpb, new_rpb); + tdbb->bumpRelStats(RuntimeStatistics::RECORD_UPDATES, relation->rel_id); return; } @@ -2761,6 +2746,7 @@ void VIO_modify(thread_db* tdbb, record_param* org_rpb, record_param* new_rpb, j { verb_post(tdbb, transaction, org_rpb, org_rpb->rpb_undo, false, false); } + tdbb->bumpRelStats(RuntimeStatistics::RECORD_UPDATES, relation->rel_id); return; } @@ -2795,11 +2781,12 @@ void VIO_modify(thread_db* tdbb, record_param* org_rpb, record_param* new_rpb, j verb_post(tdbb, transaction, org_rpb, 0, false, false); } + tdbb->bumpRelStats(RuntimeStatistics::RECORD_UPDATES, relation->rel_id); + // for an autocommit transaction, mark a commit as necessary - if (transaction->tra_flags & TRA_autocommit) { + if (transaction->tra_flags & TRA_autocommit) transaction->tra_flags |= TRA_perform_autocommit; - } // VIO_modify if ((tdbb->getDatabase()->dbb_flags & DBB_gc_background) && @@ -2856,13 +2843,9 @@ bool VIO_next_record(thread_db* tdbb, } while (!VIO_chase_record_version(tdbb, rpb, transaction, pool, false)); if (rpb->rpb_stream_flags & RPB_s_undo_data) - { fb_assert(rpb->getWindow(tdbb).win_bdb == NULL); - } else - { fb_assert(rpb->getWindow(tdbb).win_bdb != NULL); - } if (pool && !(rpb->rpb_stream_flags & RPB_s_undo_data)) { @@ -2886,9 +2869,7 @@ bool VIO_next_record(thread_db* tdbb, rpb->rpb_f_page, rpb->rpb_f_line); #endif - tdbb->bumpRelStats(DBB_read_seq_count, rpb->rpb_relation->rel_id); - tdbb->bumpStats(RuntimeStatistics::RECORD_SEQ_READS); - + tdbb->bumpRelStats(RuntimeStatistics::RECORD_SEQ_READS, rpb->rpb_relation->rel_id); return true; } @@ -3009,12 +2990,10 @@ void VIO_start_save_point(thread_db* tdbb, jrd_tra* transaction) SET_TDBB(tdbb); Savepoint* sav_point = transaction->tra_save_free; - if (sav_point) { + if (sav_point) transaction->tra_save_free = sav_point->sav_next; - } - else { + else sav_point = FB_NEW(*transaction->tra_pool) Savepoint(); - } sav_point->sav_number = ++transaction->tra_save_point_number; sav_point->sav_next = transaction->tra_save_point; @@ -3376,20 +3355,18 @@ void VIO_store(thread_db* tdbb, record_param* rpb, jrd_tra* transaction) rpb->rpb_f_page, rpb->rpb_f_line); #endif - tdbb->bumpRelStats(DBB_insert_count, relation->rel_id); - tdbb->bumpStats(RuntimeStatistics::RECORD_INSERTS); - if (!(transaction->tra_flags & TRA_system) && transaction->tra_save_point && transaction->tra_save_point->sav_verb_count) { verb_post(tdbb, transaction, rpb, 0, false, false); } + tdbb->bumpRelStats(RuntimeStatistics::RECORD_INSERTS, relation->rel_id); + // for an autocommit transaction, mark a commit as necessary - if (transaction->tra_flags & TRA_autocommit) { + if (transaction->tra_flags & TRA_autocommit) transaction->tra_flags |= TRA_perform_autocommit; - } } @@ -3459,12 +3436,13 @@ bool VIO_sweep(thread_db* tdbb, jrd_tra* transaction, TraceSweepEvent* traceSwee while (VIO_next_record(tdbb, &rpb, transaction, 0, false)) { CCH_RELEASE(tdbb, &rpb.getWindow(tdbb)); - if (relation->rel_flags & REL_deleting) { + + if (relation->rel_flags & REL_deleting) break; - } - if (--tdbb->tdbb_quantum < 0) { + + if (--tdbb->tdbb_quantum < 0) JRD_reschedule(tdbb, SWEEP_QUANTUM, true); - } + transaction->tra_oldest_active = dbb->dbb_oldest_snapshot; } @@ -3481,15 +3459,16 @@ bool VIO_sweep(thread_db* tdbb, jrd_tra* transaction, TraceSweepEvent* traceSwee catch (const Firebird::Exception&) { delete rpb.rpb_record; + if (relation) { - if (relation->rel_sweep_count) { + if (relation->rel_sweep_count) --relation->rel_sweep_count; - } - if (relation->rel_scan_count) { + + if (relation->rel_scan_count) --relation->rel_scan_count; - } } + ERR_punt(); } @@ -3570,15 +3549,12 @@ void VIO_verb_cleanup(thread_db* tdbb, jrd_tra* transaction) "VIO_verb_cleanup (transaction %"ULONGFORMAT")\n", transaction ? transaction->tra_number : 0); #endif - if (transaction->tra_flags & TRA_system) { + if (transaction->tra_flags & TRA_system) return; - } Savepoint* sav_point = transaction->tra_save_point; if (!sav_point) - { return; - } Jrd::ContextPoolHolder context(tdbb, transaction->tra_pool); @@ -3651,18 +3627,18 @@ void VIO_verb_cleanup(thread_db* tdbb, jrd_tra* transaction) if (accessor.getFirst()) do { rpb.rpb_number.setValue(accessor.current()); - if (!DPM_get(tdbb, &rpb, LCK_write)) { + + if (!DPM_get(tdbb, &rpb, LCK_write)) BUGCHECK(186); // msg 186 record disappeared - } - if (rpb.rpb_flags & rpb_delta) { + + if (rpb.rpb_flags & rpb_delta) VIO_data(tdbb, &rpb, tdbb->getDefaultPool()); - } - else { + else CCH_RELEASE(tdbb, &rpb.getWindow(tdbb)); - } - if (rpb.rpb_transaction_nr != transaction->tra_number) { + + if (rpb.rpb_transaction_nr != transaction->tra_number) BUGCHECK(185); // msg 185 wrong record version - } + if (!action->vct_undo || !action->vct_undo->locate(Firebird::locEqual, rpb.rpb_number.getValue())) { @@ -3679,6 +3655,7 @@ void VIO_verb_cleanup(thread_db* tdbb, jrd_tra* transaction) if (same_tx) { VIO_backout(tdbb, &rpb, transaction); + /* Nickolay Samofatov, 01 Mar 2003: If we don't have data for the record and it was modified and deleted under our savepoint @@ -3686,19 +3663,18 @@ void VIO_verb_cleanup(thread_db* tdbb, jrd_tra* transaction) before our transaction started */ if (record->rec_length == 0 && (record->rec_flags & REC_new_version)) { - if (!DPM_get(tdbb, &rpb, LCK_write)) { + if (!DPM_get(tdbb, &rpb, LCK_write)) BUGCHECK(186); // msg 186 record disappeared - } - if (rpb.rpb_flags & rpb_delta) { + + if (rpb.rpb_flags & rpb_delta) VIO_data(tdbb, &rpb, tdbb->getDefaultPool()); - } - else { + else CCH_RELEASE(tdbb, &rpb.getWindow(tdbb)); - } VIO_backout(tdbb, &rpb, transaction); } } + if (record->rec_length != 0) { Record* dead_record = rpb.rpb_record; @@ -3708,15 +3684,17 @@ void VIO_verb_cleanup(thread_db* tdbb, jrd_tra* transaction) new_rpb.rpb_length = record->rec_length; if (!(rpb.rpb_flags & rpb_delta)) { - if (!DPM_get(tdbb, &rpb, LCK_write)) { + if (!DPM_get(tdbb, &rpb, LCK_write)) BUGCHECK(186); // msg 186 record disappeared - } + VIO_data(tdbb, &rpb, tdbb->getDefaultPool()); } + update_in_place(tdbb, transaction, &rpb, &new_rpb); - if (!(transaction->tra_flags & TRA_system)) { + + if (!(transaction->tra_flags & TRA_system)) garbage_collect_idx(tdbb, &rpb, NULL, NULL); - } + rpb.rpb_record = dead_record; } } @@ -3742,20 +3720,18 @@ void VIO_verb_cleanup(thread_db* tdbb, jrd_tra* transaction) // because old_data will be used. (this guarantees that the // rpb points to the first fragment of the record) - if (!DPM_get(tdbb, &rpb, LCK_read)) { + if (!DPM_get(tdbb, &rpb, LCK_read)) BUGCHECK(186); // msg 186 record disappeared - } + CCH_RELEASE(tdbb, &rpb.getWindow(tdbb)); + Record* const record = action->vct_undo->current().setupRecord(transaction); const bool same_tx = (record->rec_flags & REC_same_tx) != 0; const bool new_ver = (record->rec_flags & REC_new_version) != 0; if (record->rec_length != 0) - { verb_post(tdbb, transaction, &rpb, record, same_tx, new_ver); - } - else if (same_tx) { + else if (same_tx) verb_post(tdbb, transaction, &rpb, 0, true, new_ver); - } } } while (accessor.getNext()); } @@ -3912,13 +3888,10 @@ bool VIO_writelock(thread_db* tdbb, record_param* org_rpb, jrd_tra* transaction) // for an autocommit transaction, mark a commit as necessary - if (transaction->tra_flags & TRA_autocommit) { + if (transaction->tra_flags & TRA_autocommit) transaction->tra_flags |= TRA_perform_autocommit; - } - - tdbb->bumpRelStats(DBB_lock_count, relation->rel_id); - tdbb->bumpStats(RuntimeStatistics::RECORD_LOCKS); + tdbb->bumpRelStats(RuntimeStatistics::RECORD_LOCKS, relation->rel_id); return true; } @@ -3947,9 +3920,7 @@ static int check_precommitted(const jrd_tra* transaction, const record_param* rp for (; tx; tx = tx->tra_next) { if (tx->tra_number == rpb->rpb_transaction_nr) - { return tra_active; - } } } @@ -4000,10 +3971,10 @@ static void check_rel_field_class(thread_db* tdbb, } EVL_field(0, rpb->rpb_record, f_rfr_rname, &desc); - if (! okField) - { + + if (!okField) SCL_check_relation(tdbb, &desc, flags); - } + DFW_post_work(transaction, dfw_update_format, &desc, 0); } @@ -4092,9 +4063,8 @@ static bool check_user(thread_db* tdbb, const dsc* desc) for (; p < end && *p != ' '; p++, q++) { - if (UPPER7(*p) != UPPER7(*q)) { + if (UPPER7(*p) != UPPER7(*q)) return false; - } } return *q ? false : true; @@ -4144,6 +4114,7 @@ static void delete_record(thread_db* tdbb, record_param* rpb, ULONG prior_page, { record = VIO_record(tdbb, rpb, 0, pool); prior = rpb->rpb_prior; + if (prior) { tail = differences; @@ -4169,6 +4140,7 @@ static void delete_record(thread_db* tdbb, record_param* rpb, ULONG prior_page, tail = record->rec_data; tail_end = tail + record->rec_length; } + tail = Compressor::unpack(rpb->rpb_length, rpb->rpb_address, tail_end - tail, tail); rpb->rpb_prior = (rpb->rpb_flags & rpb_delta) ? record : 0; } @@ -4222,12 +4194,12 @@ static UCHAR* delete_tail(thread_db* tdbb, // Since the callers are modifying this record, it should not be garbage collected. - if (!DPM_fetch(tdbb, rpb, LCK_write)) { + if (!DPM_fetch(tdbb, rpb, LCK_write)) BUGCHECK(248); // msg 248 cannot find record fragment - } - if (tail) { + + if (tail) tail = Compressor::unpack(rpb->rpb_length, rpb->rpb_address, tail_end - tail, tail); - } + DPM_delete(tdbb, rpb, prior_page); prior_page = rpb->rpb_page; } @@ -4334,9 +4306,8 @@ static void expunge(thread_db* tdbb, record_param* rpb, const jrd_tra* transacti // If there aren't any old versions, don't worry about garbage collection. - if (!rpb->rpb_b_page) { + if (!rpb->rpb_b_page) return; - } // Delete old versions fetching data for garbage collection. @@ -4344,8 +4315,7 @@ static void expunge(thread_db* tdbb, record_param* rpb, const jrd_tra* transacti RecordStack empty_staying; garbage_collect(tdbb, &temp, rpb->rpb_page, empty_staying); - tdbb->bumpRelStats(DBB_expunge_count, rpb->rpb_relation->rel_id); - tdbb->bumpStats(RuntimeStatistics::RECORD_EXPUNGES); + tdbb->bumpRelStats(RuntimeStatistics::RECORD_EXPUNGES, rpb->rpb_relation->rel_id); } @@ -4393,13 +4363,15 @@ static void garbage_collect(thread_db* tdbb, record_param* rpb, ULONG prior_page prior_page = rpb->rpb_page; rpb->rpb_page = rpb->rpb_b_page; rpb->rpb_line = rpb->rpb_b_line; - if (!DPM_fetch(tdbb, rpb, LCK_write)) { + + if (!DPM_fetch(tdbb, rpb, LCK_write)) BUGCHECK(291); // msg 291 cannot find record back version - } + delete_record(tdbb, rpb, prior_page, tdbb->getDefaultPool()); - if (rpb->rpb_record) { + + if (rpb->rpb_record) going.push(rpb->rpb_record); - } + // Don't monopolize the server while chasing long back version chains. if (--tdbb->tdbb_quantum < 0) JRD_reschedule(tdbb, 0, true); @@ -4935,13 +4907,14 @@ static void list_staying(thread_db* tdbb, record_param* rpb, RecordStack& stayin break; } depth++; + // Don't monopolize the server while chasing long back version chains. if (--tdbb->tdbb_quantum < 0) JRD_reschedule(tdbb, 0, true); } - if (timed_out) { + + if (timed_out) continue; - } // If there is a next older version, then process it: remember that // version's data in 'staying'. @@ -4951,9 +4924,9 @@ static void list_staying(thread_db* tdbb, record_param* rpb, RecordStack& stayin next_page = temp.rpb_b_page; next_line = temp.rpb_b_line; temp.rpb_record = NULL; - if (temp.rpb_flags & rpb_deleted) { + + if (temp.rpb_flags & rpb_deleted) CCH_RELEASE(tdbb, &temp.getWindow(tdbb)); - } else { // VIO_data below could change the flags @@ -4990,9 +4963,7 @@ static void list_staying(thread_db* tdbb, record_param* rpb, RecordStack& stayin while (depth < max_depth--) { if (staying.hasData()) - { delete staying.pop(); - } } delete backout_rec; @@ -5039,9 +5010,8 @@ static void notify_garbage_collector(thread_db* tdbb, record_param* rpb, TraNumb // of the data page to the LRU tail until the garbage collector // can garbage collect the page. - if (rpb->getWindow(tdbb).win_flags & WIN_large_scan) { + if (rpb->getWindow(tdbb).win_flags & WIN_large_scan) rpb->getWindow(tdbb).win_flags |= WIN_garbage_collect; - } const ULONG dp_sequence = rpb->rpb_number.getValue() / dbb->dbb_max_records; @@ -5150,6 +5120,8 @@ static int prepare_update( thread_db* tdbb, the record and committed, then an update error will be returned. */ + jrd_rel* const relation = rpb->rpb_relation; + *temp = *rpb; Record* record = rpb->rpb_record; @@ -5160,9 +5132,8 @@ static int prepare_update( thread_db* tdbb, temp->rpb_format_number = record->rec_format->fmt_version; temp->rpb_flags = rpb_chained; - if (temp->rpb_prior) { + if (temp->rpb_prior) temp->rpb_flags |= rpb_delta; - } // If it makes sense, store a differences record UCHAR differences[MAX_DIFFERENCES]; @@ -5220,18 +5191,18 @@ static int prepare_update( thread_db* tdbb, // There is no reason why this record would disappear for a // snapshot transaction. if (!(transaction->tra_flags & TRA_read_committed)) - { BUGCHECK(186); // msg 186 record disappeared - } else { // A read-committed transaction, on the other hand, doesn't // insist on the presence of any version, so versions of records // and entire records it has already read might be garbage-collected. - if (!DPM_fetch(tdbb, temp, LCK_write)) { + if (!DPM_fetch(tdbb, temp, LCK_write)) BUGCHECK(291); // msg 291 cannot find record back version - } + delete_record(tdbb, temp, 0, 0); + + tdbb->bumpRelStats(RuntimeStatistics::RECORD_CONFLICTS, relation->rel_id); return PREPARE_DELETE; } } @@ -5268,17 +5239,22 @@ static int prepare_update( thread_db* tdbb, if (rpb->rpb_flags & rpb_deleted) { CCH_RELEASE(tdbb, &rpb->getWindow(tdbb)); + // get rid of the back records we just created if (!(transaction->tra_attachment->att_flags & ATT_no_cleanup)) { - if (!DPM_fetch(tdbb, temp, LCK_write)) { + if (!DPM_fetch(tdbb, temp, LCK_write)) BUGCHECK(291); // msg 291 cannot find record back version - } + delete_record(tdbb, temp, 0, 0); } - if (writelock) { + + if (writelock) + { + tdbb->bumpRelStats(RuntimeStatistics::RECORD_CONFLICTS, relation->rel_id); return PREPARE_DELETE; } + IBERROR(188); // msg 188 cannot update erased record } @@ -5292,10 +5268,12 @@ static int prepare_update( thread_db* tdbb, (commit_tid_read != rpb->rpb_transaction_nr)) { CCH_RELEASE(tdbb, &rpb->getWindow(tdbb)); - if (!DPM_fetch(tdbb, temp, LCK_write)) { + if (!DPM_fetch(tdbb, temp, LCK_write)) BUGCHECK(291); // msg 291 cannot find record back version - } + delete_record(tdbb, temp, 0, 0); + + tdbb->bumpRelStats(RuntimeStatistics::RECORD_CONFLICTS, relation->rel_id); return PREPARE_CONFLICT; } @@ -5336,9 +5314,10 @@ static int prepare_update( thread_db* tdbb, if (!(transaction->tra_attachment->att_flags & ATT_no_cleanup)) { record_param temp2 = *temp; - if (!DPM_fetch(tdbb, &temp2, LCK_write)) { + + if (!DPM_fetch(tdbb, &temp2, LCK_write)) BUGCHECK(291); // msg 291 cannot find record back version - } + delete_record(tdbb, &temp2, 0, 0); } temp->rpb_b_page = rpb->rpb_b_page; @@ -5346,9 +5325,11 @@ static int prepare_update( thread_db* tdbb, temp->rpb_flags &= ~rpb_delta; temp->rpb_flags |= rpb->rpb_flags & rpb_delta; temp->rpb_transaction_nr = rpb->rpb_transaction_nr; + DPM_store(tdbb, temp, stack, DPM_secondary); continue; } + stack.push(PageNumber(DB_PAGE_SPACE, temp->rpb_page)); return PREPARE_OK; @@ -5369,14 +5350,14 @@ static int prepare_update( thread_db* tdbb, if (!(rpb->rpb_flags & rpb_gc_active)) { - state = TRA_wait(tdbb, transaction, rpb->rpb_transaction_nr, jrd_tra::tra_wait); + state = wait(tdbb, transaction, rpb, jrd_tra::tra_wait); if (state == tra_precommitted) state = check_precommitted(transaction, rpb); } else { - state = TRA_wait(tdbb, transaction, rpb->rpb_transaction_nr, jrd_tra::tra_probe); + state = wait(tdbb, transaction, rpb, jrd_tra::tra_probe); if (state == tra_active) { @@ -5398,9 +5379,9 @@ static int prepare_update( thread_db* tdbb, if (state != tra_dead && !(temp->rpb_flags & rpb_deleted)) { - if (!DPM_fetch(tdbb, temp, LCK_write)) { + if (!DPM_fetch(tdbb, temp, LCK_write)) BUGCHECK(291); // msg 291 cannot find record back version - } + delete_record(tdbb, temp, 0, 0); } @@ -5550,7 +5531,7 @@ static void purge(thread_db* tdbb, record_param* rpb) // the record. record_param temp = *rpb; - jrd_rel* relation = rpb->rpb_relation; + jrd_rel* const relation = rpb->rpb_relation; rpb->rpb_record = VIO_gc_record(tdbb, relation); VIO_data(tdbb, rpb, dbb->dbb_permanent); @@ -5593,9 +5574,7 @@ static void purge(thread_db* tdbb, record_param* rpb) garbage_collect(tdbb, &temp, rpb->rpb_page, staying); gc_rec->rec_flags &= ~REC_gc_active; - tdbb->bumpRelStats(DBB_purge_count, relation->rel_id); - tdbb->bumpStats(RuntimeStatistics::RECORD_PURGES); - + tdbb->bumpRelStats(RuntimeStatistics::RECORD_PURGES, relation->rel_id); return; // true; } @@ -5669,9 +5648,8 @@ static void replace_record(thread_db* tdbb, DPM_update(tdbb, rpb, stack, transaction); delete_tail(tdbb, &temp, rpb->rpb_page, 0, 0); - if ((rpb->rpb_flags & rpb_delta) && !rpb->rpb_prior) { + if ((rpb->rpb_flags & rpb_delta) && !rpb->rpb_prior) rpb->rpb_prior = rpb->rpb_record; - } } @@ -5819,7 +5797,7 @@ static void update_in_place(thread_db* tdbb, #endif PageStack& stack = new_rpb->rpb_record->rec_precedence; - jrd_rel* relation = org_rpb->rpb_relation; + jrd_rel* const relation = org_rpb->rpb_relation; Record* const old_data = org_rpb->rpb_record; // If the old version has been stored as a delta, things get complicated. Clearly, @@ -5836,16 +5814,18 @@ static void update_in_place(thread_db* tdbb, temp2.rpb_record = VIO_gc_record(tdbb, relation); temp2.rpb_page = org_rpb->rpb_b_page; temp2.rpb_line = org_rpb->rpb_b_line; - if (! DPM_fetch(tdbb, &temp2, LCK_read)) { + + if (!DPM_fetch(tdbb, &temp2, LCK_read)) BUGCHECK(291); // msg 291 cannot find record back version - } VIO_data(tdbb, &temp2, dbb->dbb_permanent); + gc_rec = temp2.rpb_record; temp2.rpb_flags = rpb_chained; - if (temp2.rpb_prior) { + + if (temp2.rpb_prior) temp2.rpb_flags |= rpb_delta; - } + temp2.rpb_number = org_rpb->rpb_number; DPM_store(tdbb, &temp2, stack, DPM_secondary); @@ -5906,15 +5886,14 @@ static void update_in_place(thread_db* tdbb, if (prior) { - if (!DPM_fetch(tdbb, &temp2, LCK_write)) { + if (!DPM_fetch(tdbb, &temp2, LCK_write)) BUGCHECK(291); // msg 291 cannot find record back version - } + delete_record(tdbb, &temp2, org_rpb->rpb_page, 0); } - if (gc_rec) { + if (gc_rec) gc_rec->rec_flags &= ~REC_gc_active; - } } @@ -5952,19 +5931,17 @@ static void verb_post(thread_db* tdbb, VerbAction* action; for (action = transaction->tra_save_point->sav_verb_actions; action; action = action->vct_next) { - if (action->vct_relation == rpb->rpb_relation) { + if (action->vct_relation == rpb->rpb_relation) break; - } } if (!action) { - if ( (action = transaction->tra_save_point->sav_verb_free) ) { + if ( (action = transaction->tra_save_point->sav_verb_free) ) transaction->tra_save_point->sav_verb_free = action->vct_next; - } - else { + else action = FB_NEW(*tdbb->getDefaultPool()) VerbAction(); - } + action->vct_next = transaction->tra_save_point->sav_verb_actions; transaction->tra_save_point->sav_verb_actions = action; action->vct_relation = rpb->rpb_relation; @@ -5973,14 +5950,15 @@ static void verb_post(thread_db* tdbb, if (!RecordBitmap::test(action->vct_records, rpb->rpb_number.getValue())) { RBM_SET(tdbb->getDefaultPool(), &action->vct_records, rpb->rpb_number.getValue()); + if (old_data) { // An update-in-place is being posted to this savepoint, and this // savepoint hasn't seen this record before. - if (!action->vct_undo) { + if (!action->vct_undo) action->vct_undo = new UndoItemTree(tdbb->getDefaultPool()); - } + const UCHAR flags = same_tx ? REC_same_tx : 0; action->vct_undo->add(UndoItem(transaction, rpb->rpb_number, old_data, flags)); } @@ -5989,9 +5967,9 @@ static void verb_post(thread_db* tdbb, // An insert/update followed by a delete is posted to this savepoint, // and this savepoint hasn't seen this record before. - if (!action->vct_undo) { + if (!action->vct_undo) action->vct_undo = new UndoItemTree(tdbb->getDefaultPool()); - } + const UCHAR flags = REC_same_tx | (new_ver ? REC_new_version : 0); action->vct_undo->add(UndoItem(rpb->rpb_number, flags)); } @@ -6010,9 +5988,9 @@ static void verb_post(thread_db* tdbb, // An insert/update followed by a delete is posted to this savepoint, // and this savepoint has seen this record before but it doesn't have undo data. - if (!action->vct_undo) { + if (!action->vct_undo) action->vct_undo = new UndoItemTree(tdbb->getDefaultPool()); - } + const UCHAR flags = REC_same_tx | REC_new_version; action->vct_undo->add(UndoItem(rpb->rpb_number, flags)); } @@ -6031,9 +6009,8 @@ static void verb_post(thread_db* tdbb, // in-place-updated record. Record* undo = NULL; - if (action->vct_undo && action->vct_undo->locate(rpb->rpb_number.getValue())) { + if (action->vct_undo && action->vct_undo->locate(rpb->rpb_number.getValue())) undo = action->vct_undo->current().setupRecord(transaction); - } garbage_collect_idx(tdbb, rpb, old_data, undo); }