diff --git a/src/common/utils.cpp b/src/common/utils.cpp index d616921853b..48c2b959026 100644 --- a/src/common/utils.cpp +++ b/src/common/utils.cpp @@ -657,7 +657,7 @@ Firebird::PathName get_process_name() return buffer; } -SLONG genReadOnlyId() +SLONG genUniqueId() { static Firebird::GlobalPtr mutex; Firebird::MutexLockGuard guard(mutex); diff --git a/src/common/utils_proto.h b/src/common/utils_proto.h index 1015dd19497..a531254eabf 100644 --- a/src/common/utils_proto.h +++ b/src/common/utils_proto.h @@ -94,7 +94,7 @@ namespace fb_utils #endif Firebird::PathName get_process_name(); - SLONG genReadOnlyId(); + SLONG genUniqueId(); void getCwd(Firebird::PathName& pn); } // namespace fb_utils diff --git a/src/jrd/Database.h b/src/jrd/Database.h index 6d390daf806..68b272e0466 100644 --- a/src/jrd/Database.h +++ b/src/jrd/Database.h @@ -286,18 +286,22 @@ class Database : public pool_alloc, public Firebird::PublicHandle typedef int (*crypt_routine) (const char*, void*, int, void*); - static Database* newDbb(MemoryPool* p) + static Database* create() { - return FB_NEW(*p) Database(p); + Firebird::MemoryStats temp_stats; + MemoryPool* const pool = MemoryPool::createPool(NULL, temp_stats); + Database* const dbb = FB_NEW(*pool) Database(pool); + pool->setStatsGroup(dbb->dbb_memory_stats); + return dbb; } - // The deleteDbb function MUST be used to delete a Database object. + // The destroy() function MUST be used to delete a Database object. // The function hides some tricky order of operations. Since the // memory for the vectors in the Database is allocated out of the Database's // permanent memory pool, the entire delete() operation needs // to complete _before_ the permanent pool is deleted, or else // risk an aborted engine. - static void deleteDbb(Database* const toDelete) + static void destroy(Database* const toDelete) { if (!toDelete) return; @@ -412,7 +416,6 @@ class Database : public pool_alloc, public Firebird::PublicHandle event_t dbb_gc_event_fini[1]; // Event for finalization garbage collector #endif - ULONG dbb_current_id; // Generator of dbb-local ids Firebird::MemoryStats dbb_memory_stats; SLONG dbb_reads; @@ -440,11 +443,6 @@ class Database : public pool_alloc, public Firebird::PublicHandle Firebird::GenericMap > > dbb_functions; // User defined functions - ULONG generateId() - { - return ++dbb_current_id; - } - // returns true if primary file is located on raw device bool onRawDevice() const; diff --git a/src/jrd/DatabaseSnapshot.cpp b/src/jrd/DatabaseSnapshot.cpp index c18c9a7eb36..1e19e10c977 100644 --- a/src/jrd/DatabaseSnapshot.cpp +++ b/src/jrd/DatabaseSnapshot.cpp @@ -48,6 +48,8 @@ #include "../jrd/RecordBuffer.h" #include "../jrd/DatabaseSnapshot.h" +#include "../common/utils_proto.h" + #ifdef HAVE_UNISTD_H #include #endif @@ -425,6 +427,8 @@ DatabaseSnapshot::DatabaseSnapshot(thread_db* tdbb, MemoryPool& pool) ods_version >= ODS_11_1 ? allocBuffer(tdbb, pool, rel_mon_rec_stats) : NULL; RecordBuffer* const ctx_var_buffer = ods_version >= ODS_11_2 ? allocBuffer(tdbb, pool, rel_mon_ctx_vars) : NULL; + RecordBuffer* const mem_usage_buffer = + ods_version >= ODS_11_2 ? allocBuffer(tdbb, pool, rel_mon_mem_usage) : NULL; const Attachment* const attachment = tdbb->getAttachment(); fb_assert(attachment); @@ -524,6 +528,9 @@ DatabaseSnapshot::DatabaseSnapshot(thread_db* tdbb, MemoryPool& pool) case rel_mon_ctx_vars: buffer = ctx_var_buffer; break; + case rel_mon_mem_usage: + buffer = mem_usage_buffer; + break; default: fb_assert(false); } @@ -774,9 +781,11 @@ const char* DatabaseSnapshot::checkNull(int rid, int fid, const char* source, si // The only goal of this function is to substitute some numeric zeroes // and empty strings with NULLs - switch (rid) { + switch (rid) + { case rel_mon_attachments: - switch (fid) { + switch (fid) + { case f_mon_att_remote_proto: case f_mon_att_remote_addr: case f_mon_att_remote_process: @@ -787,8 +796,10 @@ const char* DatabaseSnapshot::checkNull(int rid, int fid, const char* source, si break; } break; + case rel_mon_statements: - switch (fid) { + switch (fid) + { case f_mon_stmt_att_id: case f_mon_stmt_tra_id: return (*(SLONG*) source) ? source : NULL; @@ -800,8 +811,10 @@ const char* DatabaseSnapshot::checkNull(int rid, int fid, const char* source, si break; } break; + case rel_mon_calls: - switch (fid) { + switch (fid) + { case f_mon_call_caller_id: case f_mon_call_type: case f_mon_call_src_line: @@ -813,6 +826,18 @@ const char* DatabaseSnapshot::checkNull(int rid, int fid, const char* source, si break; } break; + + case rel_mon_mem_usage: + switch (fid) + { + case f_mon_mem_cur_alloc: + case f_mon_mem_max_alloc: + return (*(SLONG*) source) ? source : NULL; + default: + break; + } + break; + default: break; } @@ -838,7 +863,7 @@ ClumpletReader* DatabaseSnapshot::dumpData(thread_db* tdbb, bool broadcast) // Database information - putDatabase(dbb, *writer, dbb->generateId()); + putDatabase(dbb, *writer, fb_utils::genUniqueId()); // Attachment information @@ -847,7 +872,7 @@ ClumpletReader* DatabaseSnapshot::dumpData(thread_db* tdbb, bool broadcast) { if (broadcast || attachment == self_attachment) { - putAttachment(attachment, *writer, dbb->generateId()); + putAttachment(attachment, *writer, fb_utils::genUniqueId()); putContextVars(attachment->att_context_vars, *writer, attachment->att_attachment_id, true); @@ -859,7 +884,7 @@ ClumpletReader* DatabaseSnapshot::dumpData(thread_db* tdbb, bool broadcast) for (transaction = attachment->att_transactions; transaction; transaction = transaction->tra_next) { - putTransaction(transaction, *writer, dbb->generateId()); + putTransaction(transaction, *writer, fb_utils::genUniqueId()); putContextVars(transaction->tra_context_vars, *writer, transaction->tra_number, false); } @@ -871,7 +896,7 @@ ClumpletReader* DatabaseSnapshot::dumpData(thread_db* tdbb, bool broadcast) { if (!(request->req_flags & (req_internal | req_sys_trigger))) { - putRequest(request, *writer, dbb->generateId()); + putRequest(request, *writer, fb_utils::genUniqueId()); } } @@ -886,7 +911,7 @@ ClumpletReader* DatabaseSnapshot::dumpData(thread_db* tdbb, bool broadcast) if (!(request->req_flags & (req_internal | req_sys_trigger)) && request->req_caller) { - putCall(request, *writer, dbb->generateId()); + putCall(request, *writer, fb_utils::genUniqueId()); } } } @@ -926,7 +951,6 @@ void DatabaseSnapshot::putDatabase(const Database* database, // Reload header const PageSpace* const pageSpace = database->dbb_page_manager.findPageSpace(DB_PAGE_SPACE); - const jrd_file* const file = pageSpace->file; PAG_header(true); // database name or alias @@ -1008,6 +1032,7 @@ void DatabaseSnapshot::putDatabase(const Database* database, // statistics writer.insertBigInt(f_mon_db_stat_id, getGlobalId(stat_id)); putStatistics(database->dbb_stats, writer, stat_id, stat_database); + putMemoryUsage(database->dbb_memory_stats, writer, stat_id, stat_database); } @@ -1067,6 +1092,7 @@ void DatabaseSnapshot::putAttachment(const Attachment* attachment, // statistics writer.insertBigInt(f_mon_att_stat_id, getGlobalId(stat_id)); putStatistics(attachment->att_stats, writer, stat_id, stat_attachment); + putMemoryUsage(attachment->att_memory_stats, writer, stat_id, stat_attachment); } @@ -1124,6 +1150,7 @@ void DatabaseSnapshot::putTransaction(const jrd_tra* transaction, // statistics writer.insertBigInt(f_mon_tra_stat_id, getGlobalId(stat_id)); putStatistics(transaction->tra_stats, writer, stat_id, stat_transaction); + putMemoryUsage(transaction->tra_memory_stats, writer, stat_id, stat_transaction); } @@ -1168,6 +1195,7 @@ void DatabaseSnapshot::putRequest(const jrd_req* request, // statistics writer.insertBigInt(f_mon_stmt_stat_id, getGlobalId(stat_id)); putStatistics(request->req_stats, writer, stat_id, stat_statement); + putMemoryUsage(request->req_memory_stats, writer, stat_id, stat_statement); } @@ -1224,6 +1252,7 @@ void DatabaseSnapshot::putCall(const jrd_req* request, // statistics writer.insertBigInt(f_mon_call_stat_id, getGlobalId(stat_id)); putStatistics(request->req_stats, writer, stat_id, stat_call); + putMemoryUsage(request->req_memory_stats, writer, stat_id, stat_call); } void DatabaseSnapshot::putStatistics(const RuntimeStatistics& statistics, @@ -1286,3 +1315,21 @@ void DatabaseSnapshot::putContextVars(Firebird::StringMap& variables, writer.insertString(f_mon_ctx_var_value, variables.current()->second); } } + +void DatabaseSnapshot::putMemoryUsage(const Firebird::MemoryStats& stats, + Firebird::ClumpletWriter& writer, + int stat_id, + int stat_group) +{ + // statistics id + const SINT64 id = getGlobalId(stat_id); + + // memory usage + writer.insertByte(TAG_RECORD, rel_mon_mem_usage); + writer.insertBigInt(f_mon_mem_stat_id, id); + writer.insertInt(f_mon_mem_stat_group, stat_group); + writer.insertBigInt(f_mon_mem_cur_used, stats.getCurrentUsage()); + writer.insertBigInt(f_mon_mem_cur_alloc, stats.getCurrentMapping()); + writer.insertBigInt(f_mon_mem_max_used, stats.getMaximumUsage()); + writer.insertBigInt(f_mon_mem_max_alloc, stats.getMaximumMapping()); +} diff --git a/src/jrd/DatabaseSnapshot.h b/src/jrd/DatabaseSnapshot.h index 9b5b0171fb5..5ed18e4fda2 100644 --- a/src/jrd/DatabaseSnapshot.h +++ b/src/jrd/DatabaseSnapshot.h @@ -132,6 +132,7 @@ class DatabaseSnapshot static void putCall(const jrd_req*, Firebird::ClumpletWriter&, int); static void putStatistics(const RuntimeStatistics&, Firebird::ClumpletWriter&, int, int); static void putContextVars(Firebird::StringMap&, Firebird::ClumpletWriter&, int, bool); + static void putMemoryUsage(const Firebird::MemoryStats&, Firebird::ClumpletWriter&, int, int); static Firebird::GlobalPtr initMutex; static SharedMemory* dump; diff --git a/src/jrd/cch.cpp b/src/jrd/cch.cpp index 89830c94cc4..ab2e77d9535 100644 --- a/src/jrd/cch.cpp +++ b/src/jrd/cch.cpp @@ -3980,8 +3980,10 @@ static THREAD_ENTRY_DECLARE cache_reader(THREAD_ENTRY_PARAM arg) /* Dummy attachment needed for lock owner identification. */ tdbb->setDatabase(dbb); - tdbb->setAttachment(FB_NEW(*dbb->dbb_bufferpool) Attachment(dbb)); - tdbb->getAttachment()->att_filename = dbb->dbb_filename; + Attachment* const attachment = Attachment::create(dbb); + tdbb->setAttachment(attachment); + attachment->att_mutex.enter(); + attachment->att_filename = dbb->dbb_filename; Jrd::ContextPoolHolder context(tdbb, dbb->dbb_bufferpool); /* This try block is specifically to protect the LCK_init call: if @@ -4099,8 +4101,8 @@ static THREAD_ENTRY_DECLARE cache_reader(THREAD_ENTRY_PARAM arg) } LCK_fini(tdbb, LCK_OWNER_attachment); - delete tdbb->getAttachment(); - tdbb->setAttachment(0); + Attachment::destroy(attachment); + tdbb->setAttachment(NULL); bcb->bcb_flags &= ~BCB_cache_reader; ISC_event_post(reader_event); @@ -4142,9 +4144,10 @@ static THREAD_ENTRY_DECLARE cache_writer(THREAD_ENTRY_PARAM arg) /* Dummy attachment needed for lock owner identification. */ tdbb->setDatabase(dbb); - tdbb->setAttachment(FB_NEW(*dbb->dbb_bufferpool) Attachment(dbb)); - tdbb->getAttachment()->att_mutex.enter(); - tdbb->getAttachment()->att_filename = dbb->dbb_filename; + Attachment* const attachment = Attachment::create(dbb); + tdbb->setAttachment(attachment); + attachment->att_mutex.enter(); + attachment->att_filename = dbb->dbb_filename; Jrd::ContextPoolHolder context(tdbb, dbb->dbb_bufferpool); /* This try block is specifically to protect the LCK_init call: if @@ -4259,8 +4262,8 @@ static THREAD_ENTRY_DECLARE cache_writer(THREAD_ENTRY_PARAM arg) } LCK_fini(tdbb, LCK_OWNER_attachment); - delete tdbb->getAttachment(); - tdbb->setAttachment(0); + Attachment::destroy(attachment); + tdbb->setAttachment(NULL); bcb->bcb_flags &= ~BCB_cache_writer; /* Notify the finalization caller that we're finishing. */ ISC_event_post(dbb->dbb_writer_event_fini); diff --git a/src/jrd/cmp.cpp b/src/jrd/cmp.cpp index 66807b9c1b3..f6f6e0b82ca 100644 --- a/src/jrd/cmp.cpp +++ b/src/jrd/cmp.cpp @@ -56,7 +56,6 @@ #include "../jrd/lck.h" #include "../jrd/irq.h" #include "../jrd/drq.h" -//#include "../jrd/license.h" #include "../jrd/intl.h" #include "../jrd/btr.h" #include "../jrd/gdsassert.h" @@ -86,6 +85,8 @@ /* Pick up relation ids */ #include "../jrd/ini.h" +#include "../common/utils_proto.h" + /* Firebird provides transparent conversion from string to date in * contexts where it makes sense. This macro checks a descriptor to * see if it is something that *could* represent a date value @@ -105,8 +106,8 @@ inline bool IS_DATE_AND_TIME(const dsc d1, const dsc d2) { // (((d2).dsc_dtype==dtype_sql_time)&&((d1).dsc_dtype==dtype_sql_date))) // size of req_rpb[0] -const size_t REQ_TAIL = sizeof (Jrd::jrd_req::blk_repeat_type); -const int MAP_LENGTH = 256; +const size_t REQ_TAIL = sizeof(Jrd::jrd_req::blk_repeat_type); +const int MAP_LENGTH = 256; /* RITTER - changed HP10 to HPUX */ #if defined (HPUX) && defined (SUPERSERVER) @@ -447,7 +448,8 @@ jrd_req* CMP_clone_request(thread_db* tdbb, jrd_req* request, USHORT level, bool SET_TDBB(tdbb); - Database* dbb = tdbb->getDatabase(); + Database* const dbb = tdbb->getDatabase(); + Attachment* const attachment = tdbb->getAttachment(); fb_assert(dbb); // find the request if we've got it @@ -455,7 +457,7 @@ jrd_req* CMP_clone_request(thread_db* tdbb, jrd_req* request, USHORT level, bool if (!level) { return request; } - + jrd_req* clone; vec* vector = request->req_sub_requests; if (vector && level < vector->count() && (clone = (*vector)[level])) @@ -478,27 +480,27 @@ jrd_req* CMP_clone_request(thread_db* tdbb, jrd_req* request, USHORT level, bool } + MemoryPool* const pool = request->req_pool; + // we need to clone the request - find someplace to put it vector = request->req_sub_requests = - vec::newVector(*request->req_pool, request->req_sub_requests, level + 1); + vec::newVector(*pool, request->req_sub_requests, level + 1); // clone the request - const USHORT n = - (USHORT) ((request->req_impure_size - REQ_SIZE + REQ_TAIL - 1) / REQ_TAIL); - clone = FB_NEW_RPT(*request->req_pool, n) jrd_req(request->req_pool); + const size_t n = (request->req_impure_size - REQ_SIZE + REQ_TAIL - 1) / REQ_TAIL; + clone = FB_NEW_RPT(*pool, n) jrd_req(pool, &dbb->dbb_memory_stats); (*vector)[level] = clone; - clone->req_attachment = tdbb->getAttachment(); + clone->req_attachment = attachment; clone->req_count = request->req_count; - clone->req_pool = request->req_pool; clone->req_impure_size = request->req_impure_size; clone->req_top_node = request->req_top_node; clone->req_trg_name = request->req_trg_name; clone->req_procedure = request->req_procedure; clone->req_flags = request->req_flags & REQ_FLAGS_CLONE_MASK; clone->req_last_xcp = request->req_last_xcp; - clone->req_id = dbb->generateId(); + clone->req_id = fb_utils::genUniqueId(); // We are cloning full lists here, not assigning pointers clone->req_invariants = request->req_invariants; @@ -521,29 +523,6 @@ jrd_req* CMP_clone_request(thread_db* tdbb, jrd_req* request, USHORT level, bool } -jrd_req* CMP_compile(USHORT blr_length, const UCHAR* blr, USHORT internal_flag) -{ -/************************************** - * - * C M P _ c o m p i l e - * - ************************************** - * - * Functional description - * Compile a BLR request. - * Wrapper for CMP_compile2 - an API change - * was made for CMP_compile, but as calls to this - * are generated by gpre it's necessary to have a - * wrapper function to keep the build from breaking. - * This function can be removed after the next full - * product build is completed. - * 1997-Jan-20 David Schnepper - * - **************************************/ - return CMP_compile2(JRD_get_thread_data(), blr, internal_flag); -} - - jrd_req* CMP_compile2(thread_db* tdbb, const UCHAR* blr, USHORT internal_flag, USHORT dbginfo_length, const UCHAR* dbginfo) { @@ -560,19 +539,19 @@ jrd_req* CMP_compile2(thread_db* tdbb, const UCHAR* blr, USHORT internal_flag, jrd_req* request = NULL; SET_TDBB(tdbb); - Database* dbb = tdbb->getDatabase(); + Database* const dbb = tdbb->getDatabase(); // 26.09.2002 Nickolay Samofatov: default memory pool will become statement pool // and will be freed by CMP_release - MemoryPool* new_pool = NULL; + MemoryPool* const new_pool = dbb->createPool(); try { - new_pool = dbb->createPool(); Jrd::ContextPoolHolder context(tdbb, new_pool); CompilerScratch* csb = PAR_parse(tdbb, blr, internal_flag, dbginfo_length, dbginfo); - request = CMP_make_request(tdbb, csb); + request = CMP_make_request(tdbb, csb, internal_flag); + pool->setStatsGroup(request->req_memory_stats); if (internal_flag) { request->req_flags |= req_internal; @@ -1973,7 +1952,7 @@ SLONG CMP_impure(CompilerScratch* csb, USHORT size) } -jrd_req* CMP_make_request(thread_db* tdbb, CompilerScratch* csb) +jrd_req* CMP_make_request(thread_db* tdbb, CompilerScratch* csb, bool internal_flag) { /************************************** * @@ -1985,16 +1964,17 @@ jrd_req* CMP_make_request(thread_db* tdbb, CompilerScratch* csb) * Turn a parsed request into an executable request. * **************************************/ - jrd_req* request = 0; + jrd_req* request = NULL; DEV_BLKCHK(csb, type_csb); SET_TDBB(tdbb); - Database* dbb = tdbb->getDatabase(); + Database* const dbb = tdbb->getDatabase(); fb_assert(dbb); + Attachment* const attachment = tdbb->getAttachment(); - jrd_req* old_request = tdbb->getRequest(); + jrd_req* const old_request = tdbb->getRequest(); tdbb->setRequest(NULL); try { @@ -2070,16 +2050,18 @@ jrd_req* CMP_make_request(thread_db* tdbb, CompilerScratch* csb) // Build the final request block. First, compute the "effective" repeat // count of hold the impure areas. - const SLONG n = (csb->csb_impure - REQ_SIZE + REQ_TAIL - 1) / REQ_TAIL; - request = FB_NEW_RPT(*tdbb->getDefaultPool(), n) jrd_req(tdbb->getDefaultPool()); + MemoryPool* const pool = tdbb->getDefaultPool(); + const size_t n = (csb->csb_impure - REQ_SIZE + REQ_TAIL - 1) / REQ_TAIL; + Firebird::MemoryStats* const parent_stats = + internal_flag ? &dbb->dbb_memory_stats : &attachment->att_memory_stats; + request = FB_NEW_RPT(*pool, n) jrd_req(pool, parent_stats); request->req_count = csb->csb_n_stream; - request->req_pool = tdbb->getDefaultPool(); request->req_impure_size = csb->csb_impure; request->req_top_node = csb->csb_node; request->req_access = csb->csb_access; request->req_external = csb->csb_external; request->req_map_field_info.takeOwnership(csb->csb_map_field_info); - request->req_id = dbb->generateId(); + request->req_id = fb_utils::genUniqueId(); // CVC: Unused. //request->req_variables = csb->csb_variables; @@ -2096,7 +2078,8 @@ jrd_req* CMP_make_request(thread_db* tdbb, CompilerScratch* csb) // a little complicated since relation locks MUST be taken before // index locks. - for (Resource* resource = request->req_resources.begin(); resource < request->req_resources.end(); resource++) + for (Resource* resource = request->req_resources.begin(); + resource < request->req_resources.end(); resource++) { switch (resource->rsc_type) { @@ -2147,7 +2130,7 @@ jrd_req* CMP_make_request(thread_db* tdbb, CompilerScratch* csb) } CompilerScratch::csb_repeat* tail = csb->csb_rpt.begin(); - const CompilerScratch::csb_repeat* const streams_end = tail + csb->csb_n_stream; + const CompilerScratch::csb_repeat* const streams_end = tail + csb->csb_n_stream; DEBUG; for (record_param* rpb = request->req_rpb; tail < streams_end; rpb++, tail++) @@ -2170,7 +2153,7 @@ jrd_req* CMP_make_request(thread_db* tdbb, CompilerScratch* csb) rpb->rpb_relation = tail->csb_relation; delete tail->csb_fields; - tail->csb_fields = 0; + tail->csb_fields = NULL; } // make a vector of all used RSEs diff --git a/src/jrd/cmp_proto.h b/src/jrd/cmp_proto.h index e8f0e8863ee..fd6828252d9 100644 --- a/src/jrd/cmp_proto.h +++ b/src/jrd/cmp_proto.h @@ -31,7 +31,6 @@ bool CMP_clone_is_active(const Jrd::jrd_req*); Jrd::jrd_nod* CMP_clone_node(Jrd::thread_db*, Jrd::CompilerScratch*, Jrd::jrd_nod*); Jrd::jrd_req* CMP_clone_request(Jrd::thread_db*, Jrd::jrd_req*, USHORT, bool); -Jrd::jrd_req* CMP_compile(USHORT, const UCHAR*, USHORT); Jrd::jrd_req* CMP_compile2(Jrd::thread_db*, const UCHAR*, USHORT, USHORT = 0, const UCHAR* = NULL); Jrd::CompilerScratch::csb_repeat* CMP_csb_element(Jrd::CompilerScratch*, USHORT); void CMP_decrement_prc_use_count(Jrd::thread_db*, Jrd::jrd_prc*); @@ -41,7 +40,7 @@ Jrd::Format* CMP_format(Jrd::thread_db*, Jrd::CompilerScratch*, USHORT); void CMP_get_desc(Jrd::thread_db*, Jrd::CompilerScratch*, Jrd::jrd_nod*, dsc*); Jrd::IndexLock* CMP_get_index_lock(Jrd::thread_db*, Jrd::jrd_rel*, USHORT); SLONG CMP_impure(Jrd::CompilerScratch*, USHORT); -Jrd::jrd_req* CMP_make_request(Jrd::thread_db*, Jrd::CompilerScratch*); +Jrd::jrd_req* CMP_make_request(Jrd::thread_db*, Jrd::CompilerScratch*, bool); void CMP_post_access(Jrd::thread_db*, Jrd::CompilerScratch*, const Firebird::MetaName&, SLONG, Jrd::SecurityClass::flags_t, const TEXT*, const Firebird::MetaName&, const Firebird::MetaName&); diff --git a/src/jrd/inf.cpp b/src/jrd/inf.cpp index cae4f0a1ae3..10e2f0e7108 100644 --- a/src/jrd/inf.cpp +++ b/src/jrd/inf.cpp @@ -305,11 +305,11 @@ int INF_database_info(const SCHAR* items, break; case isc_info_current_memory: - length = INF_convert(dbb->dbb_memory_stats.get_current_usage(), buffer); + length = INF_convert(dbb->dbb_memory_stats.getCurrentUsage(), buffer); break; case isc_info_max_memory: - length = INF_convert(dbb->dbb_memory_stats.get_maximum_usage(), buffer); + length = INF_convert(dbb->dbb_memory_stats.getMaximumUsage(), buffer); break; case isc_info_attachment_id: diff --git a/src/jrd/jrd.cpp b/src/jrd/jrd.cpp index 95c545042a5..f27534d035c 100644 --- a/src/jrd/jrd.cpp +++ b/src/jrd/jrd.cpp @@ -803,7 +803,8 @@ ISC_STATUS GDS_ATTACH_DATABASE(ISC_STATUS* user_status, } } - tdbb->setAttachment((attachment = FB_NEW(*dbb->dbb_permanent) Attachment(dbb))); + attachment = Attachment::create(dbb); + tdbb->setAttachment(attachment); attachment->att_filename = is_alias ? file_name : expanded_name; attachment->att_network_protocol = options.dpb_network_protocol; attachment->att_remote_address = options.dpb_remote_address; @@ -1750,7 +1751,8 @@ ISC_STATUS GDS_CREATE_DATABASE(ISC_STATUS* user_status, dbb->dbb_encrypt_key = options.dpb_key; } - tdbb->setAttachment((attachment = FB_NEW(*dbb->dbb_permanent) Attachment(dbb))); + attachment = Attachment::create(dbb); + tdbb->setAttachment(attachment); attachment->att_filename = is_alias ? file_name : expanded_name; attachment->att_network_protocol = options.dpb_network_protocol; attachment->att_remote_address = options.dpb_remote_address; @@ -2231,7 +2233,7 @@ ISC_STATUS GDS_DROP_DATABASE(ISC_STATUS* user_status, Attachment** handle) } tdbb->setDatabase(NULL); - Database::deleteDbb(dbb); + Database::destroy(dbb); if (err) { user_status[0] = isc_arg_gds; @@ -3311,9 +3313,8 @@ ISC_STATUS GDS_TRANSACT_REQUEST(ISC_STATUS* user_status, { Jrd::ContextPoolHolder context(tdbb, new_pool); - CompilerScratch* csb = - PAR_parse(tdbb, reinterpret_cast(blr), FALSE); - request = CMP_make_request(tdbb, csb); + CompilerScratch* csb = PAR_parse(tdbb, reinterpret_cast(blr), FALSE); + request = CMP_make_request(tdbb, csb, false); CMP_verify_access(tdbb, request); jrd_nod* node; @@ -4662,17 +4663,13 @@ static Database* init(thread_db* tdbb, } #endif - Firebird::MemoryStats temp_stats; - MemoryPool* perm = MemoryPool::createPool(NULL, temp_stats); - dbb = Database::newDbb(perm); - perm->setStatsGroup(dbb->dbb_memory_stats); - + dbb = Database::create(); tdbb->setDatabase(dbb); dbb->dbb_bufferpool = dbb->createPool(); // provide context pool for the rest stuff - Jrd::ContextPoolHolder context(tdbb, perm); + Jrd::ContextPoolHolder context(tdbb, dbb->dbb_permanent); dbb->dbb_next = databases; databases = dbb; @@ -4715,7 +4712,7 @@ static Database* init(thread_db* tdbb, // Initialize a number of subsystems - TRA_init(tdbb); + TRA_init(dbb); // Lookup some external "hooks" @@ -4892,8 +4889,7 @@ static void release_attachment(thread_db* tdbb, Attachment* attachment) attachment->att_flags &= ~ATT_lck_init_done; } - if (attachment->att_compatibility_table) - delete attachment->att_compatibility_table; + delete attachment->att_compatibility_table; if (attachment->att_dsql_instance) { MemoryPool* const pool = &attachment->att_dsql_instance->dbb_pool; @@ -4910,6 +4906,17 @@ static void release_attachment(thread_db* tdbb, Attachment* attachment) } } + // CMP_release() advances the pointer before the deallocation. + jrd_req* request; + while ( (request = attachment->att_requests) ) { + CMP_release(tdbb, request); + } + + SCL_release_all(attachment->att_security_classes); + + delete attachment->att_user; + + Attachment::destroy(attachment); tdbb->setAttachment(NULL); } @@ -4942,18 +4949,20 @@ static void detachLocksFromAttachment(Attachment* attachment) } -Attachment::Attachment(Database* dbb) : - att_database(dbb), - att_lock_owner_id(Database::getLockOwnerId()), - att_lc_messages(*dbb->dbb_permanent), - att_working_directory(*dbb->dbb_permanent), - att_filename(*dbb->dbb_permanent), - att_timestamp(Firebird::TimeStamp::getCurrentTimeStamp()), - att_context_vars(*dbb->dbb_permanent), - att_network_protocol(*dbb->dbb_permanent), - att_remote_address(*dbb->dbb_permanent), - att_remote_process(*dbb->dbb_permanent), - att_dsql_cache(*dbb->dbb_permanent) +Attachment::Attachment(MemoryPool* pool, Database* dbb) +: att_pool(pool), + att_memory_stats(&dbb->dbb_memory_stats), + att_database(dbb), + att_lock_owner_id(Database::getLockOwnerId()), + att_lc_messages(*pool), + att_working_directory(*pool), + att_filename(*pool), + att_timestamp(Firebird::TimeStamp::getCurrentTimeStamp()), + att_context_vars(*pool), + att_network_protocol(*pool), + att_remote_address(*pool), + att_remote_process(*pool), + att_dsql_cache(*pool) { } @@ -5146,7 +5155,7 @@ static void shutdown_database(Database* dbb, const bool release_pools) if (release_pools) { tdbb->setDatabase(NULL); - Database::deleteDbb(dbb); + Database::destroy(dbb); } } @@ -5586,22 +5595,7 @@ static void purge_attachment(thread_db* tdbb, if (dbb->checkHandle()) { - if (dbb->dbb_attachments || (dbb->dbb_flags & DBB_being_opened)) - { - // There are still attachments so do a partial shutdown - - // CMP_release() advances the pointer before the deallocation. - jrd_req* request; - while ( (request = attachment->att_requests) ) { - CMP_release(tdbb, request); - } - - SCL_release_all(attachment->att_security_classes); - - delete attachment->att_user; - delete attachment; - } - else + if (!dbb->dbb_attachments && !(dbb->dbb_flags & DBB_being_opened)) { shutdown_database(dbb, true); } @@ -5837,10 +5831,6 @@ static ISC_STATUS unwindAttach(const Firebird::Exception& ex, { shutdown_database(dbb, true); } - else if (attachment) - { - delete attachment; - } } } catch (const Firebird::Exception&) @@ -6015,7 +6005,6 @@ void JRD_receive(thread_db* tdbb, jrd_req* request, USHORT msg_type, USHORT msg_ } - void JRD_request_info(Jrd::thread_db*, jrd_req* request, SSHORT level, SSHORT item_length, const SCHAR* items, SSHORT buffer_length, SCHAR* buffer) { diff --git a/src/jrd/jrd.h b/src/jrd/jrd.h index da999b26d41..92dc355f3e7 100644 --- a/src/jrd/jrd.h +++ b/src/jrd/jrd.h @@ -223,8 +223,35 @@ struct DSqlCacheItem class Attachment : public pool_alloc { public: - explicit Attachment(Database* dbb); - ~Attachment(); + static Attachment* create(Database* dbb) + { + MemoryPool* const pool = dbb->createPool(); + + try + { + Attachment* const attachment = FB_NEW(*pool) Attachment(pool, dbb); + pool->setStatsGroup(attachment->att_memory_stats); + return attachment; + } + catch (const Firebird::Exception&) + { + dbb->deletePool(pool); + throw; + } + } + + static void destroy(Attachment* const attachment) + { + if (attachment) + { + Database* const dbb = attachment->att_database; + MemoryPool* const pool = attachment->att_pool; + Firebird::MemoryStats temp_stats; + pool->setStatsGroup(temp_stats); + delete attachment; + dbb->deletePool(pool); + } + } /* Attachment() : att_database(0), @@ -252,6 +279,9 @@ class Attachment : public pool_alloc att_counts[0] = 0; }*/ + MemoryPool* att_pool; // Memory pool + Firebird::MemoryStats att_memory_stats; + Database* att_database; // Parent database block Attachment* att_next; // Next attachment to database UserId* att_user; // User identification @@ -298,6 +328,10 @@ class Attachment : public pool_alloc PreparedStatement* prepareStatement(thread_db* tdbb, Firebird::MemoryPool& pool, jrd_tra* transaction, const Firebird::string& text); + +private: + Attachment(MemoryPool* pool, Database* dbb); + ~Attachment(); }; diff --git a/src/jrd/pag.cpp b/src/jrd/pag.cpp index e546ff33c46..28fa3c82206 100644 --- a/src/jrd/pag.cpp +++ b/src/jrd/pag.cpp @@ -943,7 +943,7 @@ SLONG PAG_attachment_id(thread_db* tdbb) /* Get new attachment id */ if (dbb->dbb_flags & DBB_read_only) { - attachment->att_attachment_id = dbb->dbb_attachment_id + fb_utils::genReadOnlyId(); + attachment->att_attachment_id = dbb->dbb_attachment_id + fb_utils::genUniqueId(); } else { window.win_page = HEADER_PAGE_NUMBER; diff --git a/src/jrd/par.cpp b/src/jrd/par.cpp index 8e543212983..c0faca6a7c6 100644 --- a/src/jrd/par.cpp +++ b/src/jrd/par.cpp @@ -225,7 +225,7 @@ jrd_nod* PAR_blr(thread_db* tdbb, syntax_error(csb, "end_of_command"); if (request_ptr) - *request_ptr = CMP_make_request(tdbb, csb); + *request_ptr = CMP_make_request(tdbb, csb, true); if (csb_ptr) *csb_ptr = csb; diff --git a/src/jrd/req.h b/src/jrd/req.h index 31863168256..3afb7ca7861 100644 --- a/src/jrd/req.h +++ b/src/jrd/req.h @@ -193,7 +193,8 @@ class AffectedRows class jrd_req : public pool_alloc_rpt { public: - jrd_req(MemoryPool* pool) : + jrd_req(MemoryPool* pool, Firebird::MemoryStats* parent_stats) + : req_pool(pool), req_memory_stats(parent_stats), req_blobs(pool), req_external(*pool), req_access(*pool), req_resources(*pool), req_trg_name(*pool), req_fors(*pool), req_exec_sta(*pool), req_ext_stmt(NULL), req_invariants(*pool), req_sql_text(*pool), req_domain_validation(NULL), @@ -206,6 +207,7 @@ class jrd_req : public pool_alloc_rpt USHORT req_incarnation; // incarnation number ULONG req_impure_size; // size of impure area MemoryPool* req_pool; + Firebird::MemoryStats req_memory_stats; vec* req_sub_requests; // vector of sub-requests // Transaction pointer and doubly linked list pointers for requests in this @@ -301,7 +303,7 @@ class jrd_req : public pool_alloc_rpt // alignment quirks, but from quick glance on code it looks like it should not be // causing problems. Good fix for this kludgy behavior is to use some C++ means // to manage impure area and array of record parameter blocks -const size_t REQ_SIZE = sizeof (jrd_req) - sizeof (jrd_req::blk_repeat_type); +const size_t REQ_SIZE = sizeof(jrd_req) - sizeof(jrd_req::blk_repeat_type); /* Flags for req_flags */ const ULONG req_active = 0x1L; diff --git a/src/jrd/scl.epp b/src/jrd/scl.epp index 27c529cf543..454b378d95a 100644 --- a/src/jrd/scl.epp +++ b/src/jrd/scl.epp @@ -357,8 +357,8 @@ void SCL_check_index(thread_db* tdbb, const Firebird::MetaName& index_name, UCHA object_column, fullFieldName); } else { - SCL_check_access(default_s_class, 0, NULL, NULL, mask, - object_column, fullFieldName); + SCL_check_access(default_s_class, 0, NULL, NULL, mask, + object_column, fullFieldName); } END_FOR; @@ -496,21 +496,21 @@ SecurityClass* SCL_get_class(thread_db* tdbb, const TEXT* _string) // Look for the class already known - SecurityClass* s_class; SecurityClassList* list = attachment->att_security_classes; if (list && list->locate(string)) return list->current(); // Class isn't known. So make up a new security class block. - s_class = FB_NEW(*dbb->dbb_permanent) SecurityClass(*dbb->dbb_permanent, string); + MemoryPool& pool = *attachment->att_pool; + + SecurityClass* const s_class = FB_NEW(pool) SecurityClass(pool, string); s_class->scl_flags = compute_access(tdbb, s_class, NULL, NULL, NULL); if (s_class->scl_flags & SCL_exists) { if (!list) { - attachment->att_security_classes = list = FB_NEW (*dbb->dbb_permanent) - SecurityClassList(*dbb->dbb_permanent); + attachment->att_security_classes = list = FB_NEW(pool) SecurityClassList(pool); } list->add(s_class); @@ -714,9 +714,11 @@ void SCL_init(bool create, role_name = NULL_ROLE; } - UserId* user = FB_NEW(*dbb->dbb_permanent) UserId(*dbb->dbb_permanent, tempId); + Attachment* const attachment = tdbb->getAttachment(); + MemoryPool& pool = *attachment->att_pool; + UserId* const user = FB_NEW(pool) UserId(pool, tempId); user->usr_sql_role_name = role_name.c_str(); - tdbb->getAttachment()->att_user = user; + attachment->att_user = user; if (!create) { jrd_req* handle = NULL; @@ -726,8 +728,7 @@ void SCL_init(bool create, FOR(REQUEST_HANDLE handle) X IN RDB$DATABASE if (!X.RDB$SECURITY_CLASS.NULL) - tdbb->getAttachment()->att_security_class = - SCL_get_class(tdbb, X.RDB$SECURITY_CLASS); + attachment->att_security_class = SCL_get_class(tdbb, X.RDB$SECURITY_CLASS); END_FOR; CMP_release(tdbb, handle); diff --git a/src/jrd/tra.cpp b/src/jrd/tra.cpp index f278d3424be..f3b2f0b1bb9 100644 --- a/src/jrd/tra.cpp +++ b/src/jrd/tra.cpp @@ -214,9 +214,11 @@ bool TRA_active_transactions(thread_db* tdbb, Database* dbb) #endif /* SUPERSERVER_V2 */ const ULONG base = oldest & ~TRA_MASK; + const size_t length = (number - base + TRA_MASK) / 4; + MemoryPool* const pool = dbb->dbb_permanent; Firebird::AutoPtr trans = - FB_NEW_RPT(*dbb->dbb_permanent, (number - base + TRA_MASK) / 4) jrd_tra(dbb->dbb_permanent); + FB_NEW(*pool) jrd_tra(pool, &dbb->dbb_memory_stats, NULL, NULL, length); /* Build transaction bitmap to scan for active transactions. */ @@ -722,7 +724,7 @@ void TRA_header_write(thread_db* tdbb, Database* dbb, SLONG number) #endif -void TRA_init(thread_db* tdbb) +void TRA_init(Database* dbb) { /************************************** * @@ -734,11 +736,10 @@ void TRA_init(thread_db* tdbb) * "Start" the system transaction. * **************************************/ - SET_TDBB(tdbb); - Database* dbb = tdbb->getDatabase(); CHECK_DBB(dbb); - jrd_tra* trans = FB_NEW_RPT(*dbb->dbb_permanent, 0) jrd_tra(dbb->dbb_permanent, NULL); + MemoryPool* const pool = dbb->dbb_permanent; + jrd_tra* const trans = FB_NEW(*pool) jrd_tra(pool, &dbb->dbb_memory_stats, NULL, NULL); dbb->dbb_sys_trans = trans; trans->tra_flags |= TRA_system | TRA_ignore_limbo; } @@ -1001,15 +1002,17 @@ jrd_tra* TRA_reconnect(thread_db* tdbb, const UCHAR* id, USHORT length) * **************************************/ SET_TDBB(tdbb); - Database* dbb = tdbb->getDatabase(); + Database* const dbb = tdbb->getDatabase(); CHECK_DBB(dbb); + Attachment* const attachment = tdbb->getAttachment(); /* Cannot work on limbo transactions for ReadOnly database */ if (dbb->dbb_flags & DBB_read_only) ERR_post(isc_read_only_database, 0); - Jrd::ContextPoolHolder context(tdbb, dbb->createPool()); - jrd_tra* trans = FB_NEW_RPT(*tdbb->getDefaultPool(), 0) jrd_tra(tdbb->getDefaultPool(), NULL); + MemoryPool* const pool = dbb->createPool(); + Jrd::ContextPoolHolder context(tdbb, pool); + jrd_tra* const trans = jrd_tra::create(pool, attachment, NULL); trans->tra_number = gds__vax_integer(id, length); trans->tra_flags |= TRA_prepared | TRA_reconnected | TRA_write; @@ -1033,9 +1036,7 @@ jrd_tra* TRA_reconnect(thread_db* tdbb, const UCHAR* id, USHORT length) } const SLONG number = trans->tra_number; - MemoryPool* const tra_pool = trans->tra_pool; - delete trans; - dbb->deletePool(tra_pool); + jrd_tra::destroy(dbb, trans); TEXT text[128]; USHORT flags = 0; @@ -1184,11 +1185,9 @@ void TRA_release_transaction(thread_db* tdbb, jrd_tra* transaction) DSQL_free_statement(tdbb, transaction->tra_open_cursors.pop(), DSQL_close); } - // Release the transaction pool + // Release the transaction and its pool - MemoryPool* const tra_pool = transaction->tra_outer ? NULL : transaction->tra_pool; - delete transaction; - dbb->deletePool(tra_pool); + jrd_tra::destroy(dbb, transaction); } @@ -1523,7 +1522,7 @@ int TRA_snapshot_state(thread_db* tdbb, const jrd_tra* trans, SLONG number) if (number > trans->tra_top) return tra_active; - return TRA_state(trans->tra_transactions, trans->tra_oldest, number); + return TRA_state(trans->tra_transactions.begin(), trans->tra_oldest, number); } @@ -1540,8 +1539,8 @@ jrd_tra* TRA_start(thread_db* tdbb, ULONG flags, SSHORT lock_timeout, Jrd::jrd_t * **************************************/ SET_TDBB(tdbb); - Database* dbb = tdbb->getDatabase(); - Attachment* attachment = tdbb->getAttachment(); + Database* const dbb = tdbb->getDatabase(); + Attachment* const attachment = tdbb->getAttachment(); if (dbb->dbb_ast_flags & DBB_shut_tran) { @@ -1553,8 +1552,9 @@ jrd_tra* TRA_start(thread_db* tdbb, ULONG flags, SSHORT lock_timeout, Jrd::jrd_t // To handle the problems of relation locks, allocate a temporary // transaction block first, seize relation locks, then go ahead and // make up the real transaction block. - Jrd::ContextPoolHolder context(tdbb, (outer ? outer->tra_pool : dbb->createPool())); - jrd_tra* temp = FB_NEW_RPT(*tdbb->getDefaultPool(), 0) jrd_tra(tdbb->getDefaultPool(), outer); + MemoryPool* const pool = outer ? outer->tra_pool : dbb->createPool(); + Jrd::ContextPoolHolder context(tdbb, pool); + jrd_tra* const temp = jrd_tra::create(pool, attachment, outer); temp->tra_flags = flags; temp->tra_lock_timeout = lock_timeout; @@ -1589,8 +1589,9 @@ jrd_tra* TRA_start(thread_db* tdbb, int tpb_length, const UCHAR* tpb, Jrd::jrd_t // To handle the problems of relation locks, allocate a temporary // transaction block first, seize relation locks, then go ahead and // make up the real transaction block. - Jrd::ContextPoolHolder context(tdbb, (outer ? outer->tra_pool : dbb->createPool())); - jrd_tra* temp = FB_NEW_RPT(*tdbb->getDefaultPool(), 0) jrd_tra(tdbb->getDefaultPool(), outer); + MemoryPool* const pool = outer ? outer->tra_pool : dbb->createPool(); + Jrd::ContextPoolHolder context(tdbb, pool); + jrd_tra* const temp = jrd_tra::create(pool, attachment, outer); transaction_options(tdbb, temp, tpb, tpb_length); @@ -2412,7 +2413,6 @@ static void link_transaction(thread_db* tdbb, jrd_tra* transaction) SET_TDBB(tdbb); Attachment* attachment = tdbb->getAttachment(); - transaction->tra_attachment = attachment; transaction->tra_next = attachment->att_transactions; attachment->att_transactions = transaction; } @@ -2500,7 +2500,7 @@ static void retain_context(thread_db* tdbb, jrd_tra* transaction, new_number = bump_transaction_id(tdbb, &window); #else if (dbb->dbb_flags & DBB_read_only) - new_number = dbb->dbb_next_transaction + fb_utils::genReadOnlyId(); + new_number = dbb->dbb_next_transaction + fb_utils::genUniqueId(); else { const header_page* header = bump_transaction_id(tdbb, &window); new_number = header->hdr_next_transaction; @@ -3159,8 +3159,8 @@ static jrd_tra* transaction_start(thread_db* tdbb, jrd_tra* temp) * **************************************/ SET_TDBB(tdbb); - Database* dbb = tdbb->getDatabase(); - Attachment* attachment = tdbb->getAttachment(); + Database* const dbb = tdbb->getDatabase(); + Attachment* const attachment = tdbb->getAttachment(); WIN window(DB_PAGE_SPACE, -1); Lock* lock = create_transaction_lock(tdbb, temp); @@ -3180,7 +3180,7 @@ static jrd_tra* transaction_start(thread_db* tdbb, jrd_tra* temp) #else /* SUPERSERVER_V2 */ if (dbb->dbb_flags & DBB_read_only) { - number = dbb->dbb_next_transaction + fb_utils::genReadOnlyId(); + number = dbb->dbb_next_transaction + fb_utils::genUniqueId(); oldest = dbb->dbb_oldest_transaction; oldest_active = dbb->dbb_oldest_active; oldest_snapshot = dbb->dbb_oldest_snapshot; @@ -3207,14 +3207,11 @@ static jrd_tra* transaction_start(thread_db* tdbb, jrd_tra* temp) ULONG base = oldest & ~TRA_MASK; - jrd_tra* trans; - if (temp->tra_flags & TRA_read_committed) - trans = FB_NEW_RPT(*tdbb->getDefaultPool(), 0) jrd_tra(tdbb->getDefaultPool(), temp->tra_outer); - else - { - trans = FB_NEW_RPT(*tdbb->getDefaultPool(), (number - base + TRA_MASK) / 4) - jrd_tra(tdbb->getDefaultPool(), temp->tra_outer); - } + const size_t length = + (temp->tra_flags & TRA_read_committed) ? 0 : (number - base + TRA_MASK) / 4; + + MemoryPool* const pool = tdbb->getDefaultPool(); + jrd_tra* const trans = jrd_tra::create(pool, attachment, temp->tra_outer, length); fb_assert(trans->tra_pool == temp->tra_pool); trans->tra_relation_locks = temp->tra_relation_locks; @@ -3244,7 +3241,7 @@ static jrd_tra* transaction_start(thread_db* tdbb, jrd_tra* temp) if (!(dbb->dbb_flags & DBB_read_only)) CCH_RELEASE(tdbb, &window); #endif - delete trans; + jrd_tra::destroy(dbb, trans); ERR_post(isc_lock_conflict, 0); } @@ -3271,7 +3268,7 @@ static jrd_tra* transaction_start(thread_db* tdbb, jrd_tra* temp) if (trans->tra_flags & TRA_read_committed) TPC_initialize_tpc(tdbb, number); else - TRA_get_inventory(tdbb, trans->tra_transactions, base, number); + TRA_get_inventory(tdbb, trans->tra_transactions.begin(), base, number); /* Next task is to find the oldest active transaction on the system. This is needed for garbage collection. Things are made ever so slightly diff --git a/src/jrd/tra.h b/src/jrd/tra.h index af25902006c..ed7efe7ca32 100644 --- a/src/jrd/tra.h +++ b/src/jrd/tra.h @@ -92,7 +92,7 @@ typedef Firebird::BePlusTree BlobIndexT const int DEFAULT_LOCK_TIMEOUT = -1; // infinite const char* const TRA_TEMP_SPACE = "fb_trans_"; -class jrd_tra : public pool_alloc_rpt +class jrd_tra : public pool_alloc { public: enum wait_t { @@ -101,8 +101,11 @@ class jrd_tra : public pool_alloc_rpt tra_wait }; - explicit jrd_tra(MemoryPool* p, jrd_tra* outer) : - tra_pool(p), + jrd_tra(MemoryPool* p, Firebird::MemoryStats* parent_stats, + Attachment* attachment, jrd_tra* outer, size_t length = 0) + : tra_pool(p), + tra_memory_stats(parent_stats), + tra_attachment(attachment), tra_blobs_tree(p), tra_blobs(&tra_blobs_tree), tra_resources(*p), @@ -110,7 +113,8 @@ class jrd_tra : public pool_alloc_rpt tra_lock_timeout(DEFAULT_LOCK_TIMEOUT), tra_timestamp(Firebird::TimeStamp::getCurrentTimeStamp()), tra_open_cursors(*p), - tra_outer(outer) + tra_outer(outer), + tra_transactions(*p) { if (outer) { @@ -118,12 +122,48 @@ class jrd_tra : public pool_alloc_rpt tra_arrays = outer->tra_arrays; tra_blobs = outer->tra_blobs; } + + tra_transactions.resize(length); } ~jrd_tra() { if (!tra_outer) + { delete tra_temp_space; + } + } + + static jrd_tra* create(MemoryPool* pool, Attachment* attachment, jrd_tra* outer, size_t length = 0) + { + jrd_tra* const transaction = + FB_NEW(*pool) jrd_tra(pool, &attachment->att_memory_stats, attachment, outer, length); + + if (!outer) + { + pool->setStatsGroup(transaction->tra_memory_stats); + } + + return transaction; + } + + static void destroy(Database* const dbb, jrd_tra* const transaction) + { + if (transaction) + { + if (transaction->tra_outer) + { + delete transaction; + } + else + { + MemoryPool* const pool = transaction->tra_pool; + Firebird::MemoryStats temp_stats; + pool->setStatsGroup(temp_stats); + delete transaction; + dbb->deletePool(pool); + } + } } Attachment* tra_attachment; /* database attachment */ @@ -135,6 +175,7 @@ class jrd_tra : public pool_alloc_rpt jrd_tra* tra_next; /* next transaction in database */ jrd_tra* tra_sibling; /* next transaction in group */ MemoryPool* const tra_pool; /* pool for transaction */ + Firebird::MemoryStats tra_memory_stats; BlobIndexTree tra_blobs_tree; // list of active blobs BlobIndexTree* tra_blobs; // pointer to actual list of active blobs ArrayField* tra_arrays; /* Linked list of active arrays */ @@ -160,6 +201,7 @@ class jrd_tra : public pool_alloc_rpt RuntimeStatistics tra_stats; Firebird::Array tra_open_cursors; jrd_tra* const tra_outer; // outer transaction of an autonomous transaction + Firebird::Array tra_transactions; EDS::Transaction *tra_ext_common; //Transaction *tra_ext_two_phase; @@ -167,9 +209,6 @@ class jrd_tra : public pool_alloc_rpt private: TempSpace* tra_temp_space; // temp space storage -public: - UCHAR tra_transactions[1]; - public: SSHORT getLockWait() const { diff --git a/src/jrd/tra_proto.h b/src/jrd/tra_proto.h index 943415f912a..54bf723f482 100644 --- a/src/jrd/tra_proto.h +++ b/src/jrd/tra_proto.h @@ -42,7 +42,7 @@ int TRA_get_state(Jrd::thread_db*, SLONG); #ifdef SUPERSERVER_V2 void TRA_header_write(Jrd::thread_db*, Jrd::Database*, SLONG); #endif -void TRA_init(Jrd::thread_db*); +void TRA_init(Jrd::Database*); void TRA_invalidate(Jrd::Database*, ULONG); void TRA_link_cursor(Jrd::jrd_tra*, Jrd::dsql_req*); void TRA_unlink_cursor(Jrd::jrd_tra*, Jrd::dsql_req*); diff --git a/src/jrd/validation.cpp b/src/jrd/validation.cpp index 1febf410661..b7a0e0ec4cb 100644 --- a/src/jrd/validation.cpp +++ b/src/jrd/validation.cpp @@ -716,7 +716,7 @@ bool VAL_validate(thread_db* tdbb, USHORT switches) /* initialize validate errors */ if (!att->att_val_errors) { - att->att_val_errors = vcl::newVector(*dbb->dbb_permanent, VAL_MAX_ERROR); + att->att_val_errors = vcl::newVector(*att->att_pool, VAL_MAX_ERROR); } else { for (USHORT i = 0; i < VAL_MAX_ERROR; i++) diff --git a/src/jrd/vio.cpp b/src/jrd/vio.cpp index decf517dcd7..3f828010142 100644 --- a/src/jrd/vio.cpp +++ b/src/jrd/vio.cpp @@ -3895,10 +3895,11 @@ static THREAD_ENTRY_DECLARE garbage_collector(THREAD_ENTRY_PARAM arg) /* Pseudo attachment needed for lock owner identification. */ - tdbb->setAttachment(FB_NEW(*dbb->dbb_permanent) Attachment(dbb)); - tdbb->getAttachment()->att_mutex.enter(); - tdbb->getAttachment()->att_filename = dbb->dbb_filename; - tdbb->getAttachment()->att_flags = ATT_garbage_collector; + Attachment* const attachment = Attachment::create(dbb); + tdbb->setAttachment(attachment); + attachment->att_mutex.enter(); + attachment->att_filename = dbb->dbb_filename; + attachment->att_flags = ATT_garbage_collector; rpb.getWindow(tdbb).win_flags = WIN_garbage_collector; @@ -4138,17 +4139,19 @@ static THREAD_ENTRY_DECLARE garbage_collector(THREAD_ENTRY_PARAM arg) try { - if (rpb.rpb_record) { - delete rpb.rpb_record; /* Possibly allocated from permanent pool. */ - } + delete rpb.rpb_record; + if (transaction) { TRA_commit(tdbb, transaction, false); } - if (tdbb->getAttachment()) { + + Attachment* const attachment = tdbb->getAttachment(); + if (attachment) { LCK_fini(tdbb, LCK_OWNER_attachment); - delete tdbb->getAttachment(); - tdbb->setAttachment(0); + Attachment::destroy(attachment); + tdbb->setAttachment(NULL); } + dbb->dbb_flags &= ~(DBB_garbage_collector | DBB_gc_active | DBB_gc_pending); /* Notify the finalization caller that we're finishing. */ ISC_event_post(dbb->dbb_gc_event_fini);