From: <hv...@us...> - 2011-05-27 07:57:25
|
Revision: 53021 http://firebird.svn.sourceforge.net/firebird/?rev=53021&view=rev Author: hvlad Date: 2011-05-27 07:57:16 +0000 (Fri, 27 May 2011) Log Message: ----------- Enabled background threads (garbage collector and cache writer). Introduced special kind of system attachments used in this threads and show its activity in monitoring. Modified Paths: -------------- firebird/trunk/builds/win32/msvc10/engine.vcxproj firebird/trunk/builds/win32/msvc10/engine.vcxproj.filters firebird/trunk/builds/win32/msvc8/engine.vcproj firebird/trunk/builds/win32/msvc9/engine.vcproj firebird/trunk/src/common/common.h firebird/trunk/src/jrd/Attachment.h firebird/trunk/src/jrd/Database.h firebird/trunk/src/jrd/DatabaseSnapshot.cpp firebird/trunk/src/jrd/DatabaseSnapshot.h firebird/trunk/src/jrd/EngineInterface.h firebird/trunk/src/jrd/Relation.cpp firebird/trunk/src/jrd/Relation.h firebird/trunk/src/jrd/cch.cpp firebird/trunk/src/jrd/cch.h firebird/trunk/src/jrd/cch_proto.h firebird/trunk/src/jrd/dfw.epp firebird/trunk/src/jrd/dpm.epp firebird/trunk/src/jrd/jrd.cpp firebird/trunk/src/jrd/req.h firebird/trunk/src/jrd/tra.cpp firebird/trunk/src/jrd/vio.cpp firebird/trunk/src/jrd/vio_proto.h Added Paths: ----------- firebird/trunk/src/jrd/GarbageCollector.cpp firebird/trunk/src/jrd/GarbageCollector.h Modified: firebird/trunk/builds/win32/msvc10/engine.vcxproj =================================================================== --- firebird/trunk/builds/win32/msvc10/engine.vcxproj 2011-05-27 03:27:46 UTC (rev 53020) +++ firebird/trunk/builds/win32/msvc10/engine.vcxproj 2011-05-27 07:57:16 UTC (rev 53021) @@ -82,6 +82,7 @@ <ClCompile Include="..\..\..\src\jrd\ExtEngineManager.cpp" /> <ClCompile Include="..\..\..\src\jrd\filters.cpp" /> <ClCompile Include="..\..\..\src\jrd\flu.cpp" /> + <ClCompile Include="..\..\..\src\jrd\GarbageCollector.cpp" /> <ClCompile Include="..\..\..\src\jrd\GlobalRWLock.cpp" /> <ClCompile Include="..\..\..\src\jrd\idx.cpp" /> <ClCompile Include="..\..\..\src\jrd\inf.cpp" /> @@ -247,6 +248,7 @@ <ClInclude Include="..\..\..\src\jrd\flu_proto.h" /> <ClInclude Include="..\..\..\src\jrd\Function.h" /> <ClInclude Include="..\..\..\src\jrd\fun_proto.h" /> + <ClInclude Include="..\..\..\src\jrd\GarbageCollector.h" /> <ClInclude Include="..\..\..\src\jrd\GlobalRWLock.h" /> <ClInclude Include="..\..\..\src\jrd\grant_proto.h" /> <ClInclude Include="..\..\..\src\jrd\ibase.h" /> Modified: firebird/trunk/builds/win32/msvc10/engine.vcxproj.filters =================================================================== --- firebird/trunk/builds/win32/msvc10/engine.vcxproj.filters 2011-05-27 03:27:46 UTC (rev 53020) +++ firebird/trunk/builds/win32/msvc10/engine.vcxproj.filters 2011-05-27 07:57:16 UTC (rev 53021) @@ -465,6 +465,9 @@ <ClCompile Include="..\..\..\src\jrd\recsrc\ConditionalStream.cpp"> <Filter>JRD files\Data Access</Filter> </ClCompile> + <ClCompile Include="..\..\..\src\jrd\GarbageCollector.cpp"> + <Filter>JRD files</Filter> + </ClCompile> </ItemGroup> <ItemGroup> <ClInclude Include="..\..\..\src\jrd\recsrc\RecordSource.h"> @@ -1010,6 +1013,9 @@ <ClInclude Include="..\..\..\src\jrd\vio_proto.h"> <Filter>Header files</Filter> </ClInclude> + <ClInclude Include="..\..\..\src\jrd\GarbageCollector.h"> + <Filter>Header files</Filter> + </ClInclude> </ItemGroup> <ItemGroup> <None Include="..\..\..\src\dsql\DdlNodes.epp"> Modified: firebird/trunk/builds/win32/msvc8/engine.vcproj =================================================================== --- firebird/trunk/builds/win32/msvc8/engine.vcproj 2011-05-27 03:27:46 UTC (rev 53020) +++ firebird/trunk/builds/win32/msvc8/engine.vcproj 2011-05-27 07:57:16 UTC (rev 53021) @@ -420,6 +420,10 @@ > </File> <File + RelativePath="..\..\..\src\jrd\GarbageCollector.cpp" + > + </File> + <File RelativePath="..\..\..\src\jrd\GlobalRWLock.cpp" > </File> @@ -1168,6 +1172,10 @@ > </File> <File + RelativePath="..\..\..\src\jrd\GarbageCollector.h" + > + </File> + <File RelativePath="..\..\..\src\jrd\GlobalRWLock.h" > </File> Modified: firebird/trunk/builds/win32/msvc9/engine.vcproj =================================================================== --- firebird/trunk/builds/win32/msvc9/engine.vcproj 2011-05-27 03:27:46 UTC (rev 53020) +++ firebird/trunk/builds/win32/msvc9/engine.vcproj 2011-05-27 07:57:16 UTC (rev 53021) @@ -420,6 +420,10 @@ > </File> <File + RelativePath="..\..\..\src\jrd\GarbageCollector.cpp" + > + </File> + <File RelativePath="..\..\..\src\jrd\GlobalRWLock.cpp" > </File> @@ -1168,6 +1172,10 @@ > </File> <File + RelativePath="..\..\..\src\jrd\GarbageCollector.h" + > + </File> + <File RelativePath="..\..\..\src\jrd\GlobalRWLock.h" > </File> Modified: firebird/trunk/src/common/common.h =================================================================== --- firebird/trunk/src/common/common.h 2011-05-27 03:27:46 UTC (rev 53020) +++ firebird/trunk/src/common/common.h 2011-05-27 07:57:16 UTC (rev 53021) @@ -78,11 +78,7 @@ do not use links in source code to maintain platform neutrality */ -#ifdef SUPERSERVER -#define GARBAGE_THREAD -#endif - /***************************************************** * Linux platforms *****************************************************/ Modified: firebird/trunk/src/jrd/Attachment.h =================================================================== --- firebird/trunk/src/jrd/Attachment.h 2011-05-27 03:27:46 UTC (rev 53020) +++ firebird/trunk/src/jrd/Attachment.h 2011-05-27 07:57:16 UTC (rev 53021) @@ -351,33 +351,27 @@ // Attachment flags -const ULONG ATT_no_cleanup = 1; // Don't expunge, purge, or garbage collect -const ULONG ATT_shutdown = 2; // attachment has been shutdown -const ULONG ATT_purge_error = 4; // trouble happened in purge attachment, att_mutex remains locked -const ULONG ATT_shutdown_manager = 8; // attachment requesting shutdown -const ULONG ATT_lck_init_done = 16; // LCK_init() called for the attachment -const ULONG ATT_exclusive = 32; // attachment wants exclusive database access -const ULONG ATT_attach_pending = 64; // Indicate attachment is only pending -const ULONG ATT_exclusive_pending = 128; // Indicate exclusive attachment pending -const ULONG ATT_gbak_attachment = 256; // Indicate GBAK attachment +const ULONG ATT_no_cleanup = 0x0001L; // Don't expunge, purge, or garbage collect +const ULONG ATT_shutdown = 0x0002L; // attachment has been shutdown +const ULONG ATT_purge_error = 0x0004L; // trouble happened in purge attachment, att_mutex remains locked +const ULONG ATT_shutdown_manager = 0x0008L; // attachment requesting shutdown +const ULONG ATT_lck_init_done = 0x0010L; // LCK_init() called for the attachment +const ULONG ATT_exclusive = 0x0020L; // attachment wants exclusive database access +const ULONG ATT_attach_pending = 0x0040L; // Indicate attachment is only pending +const ULONG ATT_exclusive_pending = 0x0080L; // Indicate exclusive attachment pending +const ULONG ATT_gbak_attachment = 0x0100L; // Indicate GBAK attachment +const ULONG ATT_notify_gc = 0x0200L; // Notify garbage collector to expunge, purge .. +const ULONG ATT_disable_notify_gc = 0x0400L; // Temporarily perform own garbage collection +const ULONG ATT_garbage_collector = 0x0800L; // I'm a garbage collector +const ULONG ATT_cancel_raise = 0x1000L; // Cancel currently running operation +const ULONG ATT_cancel_disable = 0x2000L; // Disable cancel operations +const ULONG ATT_gfix_attachment = 0x4000L; // Indicate a GFIX attachment +const ULONG ATT_gstat_attachment = 0x8000L; // Indicate a GSTAT attachment +const ULONG ATT_no_db_triggers = 0x10000L; // Don't execute database triggers -#ifdef GARBAGE_THREAD -const ULONG ATT_notify_gc = 1024; // Notify garbage collector to expunge, purge .. -const ULONG ATT_disable_notify_gc = 2048; // Temporarily perform own garbage collection -const ULONG ATT_garbage_collector = 4096; // I'm a garbage collector - const ULONG ATT_NO_CLEANUP = (ATT_no_cleanup | ATT_notify_gc); -#else -const ULONG ATT_NO_CLEANUP = ATT_no_cleanup; -#endif -const ULONG ATT_cancel_raise = 8192; // Cancel currently running operation -const ULONG ATT_cancel_disable = 16384; // Disable cancel operations -const ULONG ATT_gfix_attachment = 32768; // Indicate a GFIX attachment -const ULONG ATT_gstat_attachment = 65536; // Indicate a GSTAT attachment -const ULONG ATT_no_db_triggers = 131072; // Don't execute database triggers - inline bool Attachment::locksmith() const { return att_user && att_user->locksmith(); Modified: firebird/trunk/src/jrd/Database.h =================================================================== --- firebird/trunk/src/jrd/Database.h 2011-05-27 03:27:46 UTC (rev 53020) +++ firebird/trunk/src/jrd/Database.h 2011-05-27 07:57:16 UTC (rev 53021) @@ -75,6 +75,7 @@ class BackupManager; class ExternalFileDirectoryList; class MonitoringData; +class GarbageCollector; // general purpose vector @@ -196,11 +197,9 @@ const ULONG DBB_damaged = 0x1L; const ULONG DBB_exclusive = 0x2L; // Database is accessed in exclusive mode const ULONG DBB_bugcheck = 0x4L; // Bugcheck has occurred -#ifdef GARBAGE_THREAD const ULONG DBB_garbage_collector = 0x8L; // garbage collector thread exists const ULONG DBB_gc_active = 0x10L; // ... and is actively working. const ULONG DBB_gc_pending = 0x20L; // garbage collection requested -#endif const ULONG DBB_force_write = 0x40L; // Database is forced write const ULONG DBB_no_reserve = 0x80L; // No reserve space for versions const ULONG DBB_DB_SQL_dialect_3 = 0x100L; // database SQL dialect 3 @@ -314,6 +313,7 @@ Database* dbb_next; // Next database block in system Attachment* dbb_attachments; // Active attachments + Attachment* dbb_sys_attachments; // System attachments BufferControl* dbb_bcb; // Buffer control block int dbb_monitoring_id; // dbb monitoring identifier Lock* dbb_lock; // granddaddy lock @@ -370,12 +370,10 @@ SLONG dbb_attachment_id; // Next attachment id for ReadOnly DB's ULONG dbb_page_buffers; // Page buffers from header page - -#ifdef GARBAGE_THREAD + GarbageCollector* dbb_garbage_collector; // GarbageCollector class Firebird::Semaphore dbb_gc_sem; // Event to wake up garbage collector Firebird::Semaphore dbb_gc_init; // Event for initialization garbage collector Firebird::Semaphore dbb_gc_fini; // Event for finalization garbage collector -#endif Firebird::MemoryStats dbb_memory_stats; Modified: firebird/trunk/src/jrd/DatabaseSnapshot.cpp =================================================================== --- firebird/trunk/src/jrd/DatabaseSnapshot.cpp 2011-05-27 03:27:46 UTC (rev 53020) +++ firebird/trunk/src/jrd/DatabaseSnapshot.cpp 2011-05-27 07:57:16 UTC (rev 53021) @@ -784,59 +784,70 @@ { Attachment::SyncGuard attGuard(attachment); tdbb->setAttachment(attachment); + dumpAttachment(tdbb, attachment, writer); + } - if (!putAttachment(tdbb, attachment, writer, fb_utils::genUniqueId())) - continue; + for (Attachment* attachment = dbb->dbb_sys_attachments; attachment; attachment = attachment->att_next) + { + Attachment::SyncGuard attGuard(attachment); + tdbb->setAttachment(attachment); + dumpAttachment(tdbb, attachment, writer); + } - putContextVars(attachment->att_context_vars, writer, attachment->att_attachment_id, true); + tdbb->setAttachment(old_attachment); +} - jrd_tra* transaction = NULL; - jrd_req* request = NULL; +void DatabaseSnapshot::dumpAttachment(thread_db* tdbb, const Attachment* attachment, Writer& writer) +{ + if (!putAttachment(tdbb, attachment, writer, fb_utils::genUniqueId())) + return; - // Transaction information + putContextVars(attachment->att_context_vars, writer, attachment->att_attachment_id, true); - for (transaction = attachment->att_transactions; - transaction; transaction = transaction->tra_next) - { - putTransaction(transaction, writer, fb_utils::genUniqueId()); - putContextVars(transaction->tra_context_vars, writer, transaction->tra_number, false); - } + jrd_tra* transaction = NULL; + jrd_req* request = NULL; - // Call stack information + // Transaction information - for (transaction = attachment->att_transactions; - transaction; transaction = transaction->tra_next) - { - for (request = transaction->tra_requests; request; request = request->req_caller) - { - request->adjustCallerStats(); + for (transaction = attachment->att_transactions; + transaction; transaction = transaction->tra_next) + { + putTransaction(transaction, writer, fb_utils::genUniqueId()); + putContextVars(transaction->tra_context_vars, writer, transaction->tra_number, false); + } - if (!(request->getStatement()->flags & - (JrdStatement::FLAG_INTERNAL | JrdStatement::FLAG_SYS_TRIGGER)) && - request->req_caller) - { - putCall(request, writer, fb_utils::genUniqueId()); - } - } - } + // Call stack information - // Request information - - for (const jrd_req* const* i = attachment->att_requests.begin(); - i != attachment->att_requests.end(); - ++i) + for (transaction = attachment->att_transactions; + transaction; transaction = transaction->tra_next) + { + for (request = transaction->tra_requests; request; request = request->req_caller) { - const jrd_req* request = *i; + request->adjustCallerStats(); if (!(request->getStatement()->flags & - (JrdStatement::FLAG_INTERNAL | JrdStatement::FLAG_SYS_TRIGGER))) + (JrdStatement::FLAG_INTERNAL | JrdStatement::FLAG_SYS_TRIGGER)) && + request->req_caller) { - putRequest(request, writer, fb_utils::genUniqueId()); + putCall(request, writer, fb_utils::genUniqueId()); } } } - tdbb->setAttachment(old_attachment); + // Request information + + for (const jrd_req* const* i = attachment->att_requests.begin(); + i != attachment->att_requests.end(); + ++i) + { + const jrd_req* request = *i; + + if (!(request->getStatement()->flags & + (JrdStatement::FLAG_INTERNAL | JrdStatement::FLAG_SYS_TRIGGER))) + { + putRequest(request, writer, fb_utils::genUniqueId()); + } + } } Modified: firebird/trunk/src/jrd/DatabaseSnapshot.h =================================================================== --- firebird/trunk/src/jrd/DatabaseSnapshot.h 2011-05-27 03:27:46 UTC (rev 53020) +++ firebird/trunk/src/jrd/DatabaseSnapshot.h 2011-05-27 07:57:16 UTC (rev 53021) @@ -360,6 +360,7 @@ RecordBuffer* allocBuffer(thread_db*, MemoryPool&, int); static void dumpData(thread_db*); + static void dumpAttachment(thread_db*, const Attachment*, Writer&); static SINT64 getGlobalId(int); Modified: firebird/trunk/src/jrd/EngineInterface.h =================================================================== --- firebird/trunk/src/jrd/EngineInterface.h 2011-05-27 03:27:46 UTC (rev 53020) +++ firebird/trunk/src/jrd/EngineInterface.h 2011-05-27 07:57:16 UTC (rev 53021) @@ -334,6 +334,36 @@ void freeEngineData(Firebird::IStatus* status); }; +// internal class used in system background threads +class SysAttachment : public JAttachment +{ +public: + SysAttachment(Attachment* handle) : + JAttachment(handle) + { + } + + virtual int FB_CARG release() + { + if (--refCounter != 0) + return 1; + + Attachment* attachment = getHandle(); + if (attachment) + { + destroy(attachment); + } + if (!attachment) + { + delete this; + } + return 0; + } + +private: + void destroy(Attachment* attachment); +}; + class JService : public Firebird::RefCntIface<Firebird::IService, FB_SERVICE_VERSION> { public: Added: firebird/trunk/src/jrd/GarbageCollector.cpp =================================================================== --- firebird/trunk/src/jrd/GarbageCollector.cpp (rev 0) +++ firebird/trunk/src/jrd/GarbageCollector.cpp 2011-05-27 07:57:16 UTC (rev 53021) @@ -0,0 +1,275 @@ +/* + * The contents of this file are subject to the Initial + * Developer's Public License Version 1.0 (the "License"); + * you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * http://www.ibphoenix.com/main.nfs?a=ibphoenix&page=ibp_idpl. + * + * Software distributed under the License is distributed AS IS, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. + * See the License for the specific language governing rights + * and limitations under the License. + * + * The Original Code was created by Vlad Khorsun + * for the Firebird Open Source RDBMS project. + * + * Copyright (c) 2011 Vlad Khorsun <hv...@us...> + * and all contributors signed below. + * + * All Rights Reserved. + * Contributor(s): ______________________________________. + */ + +#include "../common/classes/alloc.h" +#include "../jrd/GarbageCollector.h" +#include "../jrd/tra.h" + +using namespace Jrd; +using namespace Firebird; + + +namespace Jrd { + +void GarbageCollector::RelationData::clear() +{ + TranData::ConstAccessor accessor(&m_tranData); + if (accessor.getFirst()) + do + { + delete accessor.current()->second; + } while(accessor.getNext()); + + m_tranData.clear(); +} + + +void GarbageCollector::RelationData::addPage(const ULONG pageno, const SLONG tranid) +{ + // look if given page number is already set at given tx bitmap + PageBitmap** bmPtr = m_tranData.get(tranid); + PageBitmap* bm = bmPtr ? *bmPtr : NULL; + if (bm && bm->test(pageno)) + return; + + // search for given page at other transactions bitmaps + // if found at older tx - we are done, just return + // if found at yanger tx - clear it as page should be set at oldest tx (our) + TranData::ConstAccessor accessor(&m_tranData); + if (accessor.getFirst()) + do + { + const TranBitMap* item = accessor.current(); + if (item->first <= tranid) + { + if (item->second->test(pageno)) + return; + } + else + { + if (item->second->clear(pageno)) + break; + } + } while(accessor.getNext()); + + // add page to the our tx bitmap + if (bm) + { + PBM_SET(&m_pool, &bm, pageno); + } + else + { + PBM_SET(&m_pool, &bm, pageno); + m_tranData.put(tranid, bm); + } +} + + +void GarbageCollector::RelationData::getPageBitmap(const SLONG oldest_snapshot, PageBitmap **sbm) +{ + TranData::Accessor accessor(&m_tranData); + while (accessor.getFirst()) + { + TranBitMap* item = accessor.current(); + + if (item->first >= oldest_snapshot) + break; + + PageBitmap* bm_tran = item->second; + PageBitmap** bm_or = PageBitmap::bit_or(sbm, &bm_tran); + if (*bm_or == item->second) + { + bm_tran = *sbm; + *sbm = item->second; + item->second = bm_tran; + } + delete item->second; + + m_tranData.remove(item->first); + } +} + + +void GarbageCollector::RelationData::swept(const SLONG oldest_snapshot) +{ + TranData::Accessor accessor(&m_tranData); + while (accessor.getFirst()) + { + TranBitMap* item = accessor.current(); + + if (item->first >= oldest_snapshot) + break; + + delete item->second; + m_tranData.remove(item->first); + } +} + + +SLONG GarbageCollector::RelationData::minTranID() const +{ + TranData::ConstAccessor accessor(&m_tranData); + if (accessor.getFirst()) + return accessor.current()->first; + else + return MAX_TRA_NUMBER; +} + + +GarbageCollector::~GarbageCollector() +{ + SyncLockGuard exGuard(&m_sync, SYNC_EXCLUSIVE, "GarbageCollector::~GarbageCollector"); + for (size_t pos = 0; pos < m_relations.getCount(); pos++) + { + Sync sync(&m_relations[pos]->m_sync, "GarbageCollector::~GarbageCollector"); + sync.lock(SYNC_EXCLUSIVE); + sync.unlock(); + delete m_relations[pos]; + } + + m_relations.clear(); +} + + +void GarbageCollector::addPage(const USHORT relID, const ULONG pageno, const SLONG tranid) +{ + Sync syncGC(&m_sync, "GarbageCollector::addPage"); + RelationData* relData = getRelData(syncGC, relID, true); + + SyncLockGuard syncData(&relData->m_sync, SYNC_EXCLUSIVE, "GarbageCollector::addPage"); + syncGC.unlock(); + + relData->addPage(pageno, tranid); +} + + +bool GarbageCollector::getPageBitmap(const SLONG oldest_snapshot, USHORT &relID, PageBitmap **sbm) +{ + *sbm = NULL; + SyncLockGuard shGuard(&m_sync, SYNC_EXCLUSIVE, "GarbageCollector::getPageBitmap"); + + if (m_relations.isEmpty()) + { + m_nextRelID = 0; + return false; + } + + size_t pos; + if (!m_relations.find(m_nextRelID, pos) && (pos == m_relations.getCount()) ) + pos = 0; + + for (; pos < m_relations.getCount(); pos++) + { + RelationData* relData = m_relations[pos]; + SyncLockGuard syncData(&relData->m_sync, SYNC_EXCLUSIVE, "GarbageCollector::getPageBitmap"); + relData->getPageBitmap(oldest_snapshot, sbm); + if (*sbm) + { + relID = relData->getRelID(); + m_nextRelID = relID + 1; + return true; + } + } + + m_nextRelID = 0; + return false; +} + + +void GarbageCollector::removeRelation(const USHORT relID) +{ + Sync syncGC(&m_sync, "GarbageCollector::removeRelation"); + syncGC.lock(SYNC_EXCLUSIVE); + + size_t pos; + if (!m_relations.find(relID, pos)) + return; + + RelationData* relData = m_relations[pos]; + Sync syncData(&relData->m_sync, "GarbageCollector::removeRelation"); + syncData.lock(SYNC_EXCLUSIVE); + + m_relations.remove(pos); + syncGC.unlock(); + + syncData.unlock(); + delete relData; +} + + +void GarbageCollector::sweptRelation(const SLONG oldest_snapshot, const USHORT relID) +{ + Sync syncGC(&m_sync, "GarbageCollector::sweptRelation"); + + RelationData* relData = getRelData(syncGC, relID, false); + if (relData) + { + SyncLockGuard syncData(&relData->m_sync, SYNC_EXCLUSIVE, "GarbageCollector::sweptRelation"); + + syncGC.unlock(); + relData->swept(oldest_snapshot); + } + return; +} + + +SLONG GarbageCollector::minTranID(const USHORT relID) +{ + Sync syncGC(&m_sync, "GarbageCollector::minTranID"); + + RelationData* relData = getRelData(syncGC, relID, false); + if (relData) + { + SyncLockGuard syncData(&relData->m_sync, SYNC_SHARED, "GarbageCollector::minTranID"); + + syncGC.unlock(); + return relData->minTranID(); + } + + return MAX_TRA_NUMBER; +} + + +GarbageCollector::RelationData* GarbageCollector::getRelData(Sync &sync, const USHORT relID, bool allowCreate) +{ + size_t pos; + + sync.lock(SYNC_SHARED); + if (!m_relations.find(relID, pos)) + { + if (!allowCreate) + return NULL; + + sync.unlock(); + sync.lock(SYNC_EXCLUSIVE); + if (!m_relations.find(relID, pos)) + { + m_relations.insert(pos, FB_NEW(m_pool) RelationData(m_pool, relID)); + sync.downgrade(SYNC_SHARED); + } + } + + return m_relations[pos]; +} + + +} // namespace Jrd Property changes on: firebird/trunk/src/jrd/GarbageCollector.cpp ___________________________________________________________________ Added: svn:mime-type + text/plain Added: svn:eol-style + native Added: firebird/trunk/src/jrd/GarbageCollector.h =================================================================== --- firebird/trunk/src/jrd/GarbageCollector.h (rev 0) +++ firebird/trunk/src/jrd/GarbageCollector.h 2011-05-27 07:57:16 UTC (rev 53021) @@ -0,0 +1,108 @@ +/* + * The contents of this file are subject to the Initial + * Developer's Public License Version 1.0 (the "License"); + * you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * http://www.ibphoenix.com/main.nfs?a=ibphoenix&page=ibp_idpl. + * + * Software distributed under the License is distributed AS IS, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. + * See the License for the specific language governing rights + * and limitations under the License. + * + * The Original Code was created by Vlad Khorsun + * for the Firebird Open Source RDBMS project. + * + * Copyright (c) 2011 Vlad Khorsun <hv...@us...> + * and all contributors signed below. + * + * All Rights Reserved. + * Contributor(s): ______________________________________. + */ + +#ifndef JRD_GARBAGE_COLLECTOR_H +#define JRD_GARBAGE_COLLECTOR_H + +#include "firebird.h" +#include "../common/classes/array.h" +#include "../common/classes/GenericMap.h" +#include "../common/classes/SyncObject.h" +#include "../jrd/sbm.h" + + +namespace Jrd { + +class Database; +class Savepoint; + +class GarbageCollector +{ +public: + GarbageCollector(MemoryPool& p, Database* dbb) + : m_pool(p), m_database(dbb), m_relations(m_pool), m_nextRelID(0) + {} + + ~GarbageCollector(); + + void addPage(const USHORT relID, const ULONG pageno, const SLONG tranid); + bool getPageBitmap(const SLONG oldest_snapshot, USHORT &relID, PageBitmap **sbm); + void removeRelation(const USHORT relID); + void sweptRelation(const SLONG oldest_snapshot, const USHORT relID); + + SLONG minTranID(const USHORT relID); + +private: + typedef Firebird::Pair<Firebird::NonPooled<SLONG, PageBitmap*> > TranBitMap; + typedef Firebird::GenericMap<TranBitMap> TranData; + + + class RelationData + { + public: + explicit RelationData(MemoryPool& p, USHORT relID) + : m_pool(p), m_tranData(p), m_relID(relID) + {} + + ~RelationData() { clear(); } + + void addPage(const ULONG pageno, const SLONG tranid); + void getPageBitmap(const SLONG oldest_snapshot, PageBitmap **sbm); + void swept(const SLONG oldest_snapshot); + SLONG minTranID() const; + + USHORT getRelID() const + { + return m_relID; + } + + static inline const USHORT generate(void const*, const RelationData* Item) + { + return Item->m_relID; + } + + void clear(); + + Firebird::MemoryPool& m_pool; + Firebird::SyncObject m_sync; + TranData m_tranData; + USHORT m_relID; + }; + + typedef Firebird::SortedArray< + RelationData*, + Firebird::EmptyStorage<RelationData*>, + LONG, + RelationData> RelGarbageArray; + + RelationData* getRelData(Firebird::Sync &sync, const USHORT relID, bool allowCreate); + + Firebird::MemoryPool& m_pool; + Firebird::SyncObject m_sync; + Database* m_database; + RelGarbageArray m_relations; + USHORT m_nextRelID; +}; + +} // namespace Jrd + +#endif JRD_GARBAGE_COLLECTOR_H Property changes on: firebird/trunk/src/jrd/GarbageCollector.h ___________________________________________________________________ Added: svn:mime-type + text/plain Added: svn:eol-style + native Modified: firebird/trunk/src/jrd/Relation.cpp =================================================================== --- firebird/trunk/src/jrd/Relation.cpp 2011-05-27 03:27:46 UTC (rev 53020) +++ firebird/trunk/src/jrd/Relation.cpp 2011-05-27 07:57:16 UTC (rev 53021) @@ -10,10 +10,10 @@ * See the License for the specific language governing rights * and limitations under the License. * - * The Original Code was created by Vlad Horsun + * The Original Code was created by Vlad Khorsun * for the Firebird Open Source RDBMS project. * - * Copyright (c) 2005 Vlad Horsun <hv...@us...> + * Copyright (c) 2005 Vlad Khorsun <hv...@us...> * and all contributors signed below. * * All Rights Reserved. @@ -32,88 +32,8 @@ using namespace Jrd; -#ifdef GARBAGE_THREAD +/// jrd_rel -void RelationGarbage::clear() -{ - TranGarbage *item = array.begin(), *const last = array.end(); - - for (; item < last; item++) - { - delete item->bm; - item->bm = NULL; - } - - array.clear(); -} - -void RelationGarbage::addPage(MemoryPool* pool, const SLONG pageno, const SLONG tranid) -{ - bool found = false; - TranGarbage const *item = array.begin(), *const last = array.end(); - - for (; item < last; item++) - { - if (item->tran <= tranid) - { - if (PageBitmap::test(item->bm, pageno)) - { - found = true; - break; - } - } - else - { - if (item->bm->clear(pageno)) - break; - } - } - - if (!found) - { - PageBitmap *bm = NULL; - size_t pos = 0; - - if (array.find(tranid, pos) ) - { - bm = array[pos].bm; - PBM_SET(pool, &bm, pageno); - } - else - { - bm = NULL; - PBM_SET(pool, &bm, pageno); - array.add(TranGarbage(bm, tranid)); - } - } -} - -void RelationGarbage::getGarbage(const SLONG oldest_snapshot, PageBitmap **sbm) -{ - while (array.getCount() > 0) - { - TranGarbage& garbage = array[0]; - - if (garbage.tran >= oldest_snapshot) - break; - - PageBitmap* bm_tran = garbage.bm; - PageBitmap** bm_or = PageBitmap::bit_or(sbm, &bm_tran); - if (*bm_or == garbage.bm) - { - bm_tran = *sbm; - *sbm = garbage.bm; - garbage.bm = bm_tran; - } - delete garbage.bm; - - // Need to cast zero to exact type because literal zero means null pointer - array.remove(static_cast<size_t>(0)); - } -} - -#endif //GARBAGE_THREAD - RelationPages* jrd_rel::getPagesInternal(thread_db* tdbb, SLONG tran, bool allocPages) { if (tdbb->tdbb_flags & TDBB_use_db_page_space) Modified: firebird/trunk/src/jrd/Relation.h =================================================================== --- firebird/trunk/src/jrd/Relation.h 2011-05-27 03:27:46 UTC (rev 53020) +++ firebird/trunk/src/jrd/Relation.h 2011-05-27 07:57:16 UTC (rev 53021) @@ -63,54 +63,7 @@ typedef Firebird::SortedArray<ViewContext*, Firebird::EmptyStorage<ViewContext*>, USHORT, ViewContext> ViewContexts; -#ifdef GARBAGE_THREAD -class RelationGarbage -{ -private: - class TranGarbage - { - public: - SLONG tran; - PageBitmap *bm; - - TranGarbage(PageBitmap* aBm, SLONG aTran) - : tran(aTran), bm(aBm) - {} - - static inline const SLONG generate(void const*, const TranGarbage& Item) - { - return Item.tran; - } - }; - - typedef Firebird::SortedArray< - TranGarbage, - Firebird::EmptyStorage<TranGarbage>, - SLONG, - TranGarbage> TranGarbageArray; - - TranGarbageArray array; - -public: - explicit RelationGarbage(MemoryPool& p) - : array(p) - {} - ~RelationGarbage() { clear(); } - - void addPage(MemoryPool* pool, const SLONG pageno, const SLONG tranid); - void clear(); - - void getGarbage(const SLONG oldest_snapshot, PageBitmap **sbm); - - SLONG minTranID() const - { - return (array.getCount() > 0) ? array[0].tran : MAX_SLONG; - } -}; - -#endif //GARBAGE_THREAD - class RelationPages { public: @@ -197,10 +150,6 @@ ExternalFile* rel_file; // external file name vec<Record*>* rel_gc_rec; // vector of records for garbage collection -#ifdef GARBAGE_THREAD - PageBitmap* rel_gc_bitmap; // garbage collect bitmap of data page sequences - RelationGarbage* rel_garbage; // deferred gc bitmap's by tran numbers -#endif USHORT rel_use_count; // requests compiled with relation USHORT rel_sweep_count; // sweep and/or garbage collector threads active Modified: firebird/trunk/src/jrd/cch.cpp =================================================================== --- firebird/trunk/src/jrd/cch.cpp 2011-05-27 03:27:46 UTC (rev 53020) +++ firebird/trunk/src/jrd/cch.cpp 2011-05-27 07:57:16 UTC (rev 53021) @@ -76,7 +76,7 @@ IMPLEMENT_TRACE_ROUTINE(cch_trace, "CCH") #endif -// #define CACHE_WRITER +#define CACHE_WRITER #ifdef SUPERSERVER_V2 #define CACHE_READER @@ -1038,7 +1038,6 @@ // Wait for cache writer startup to complete. while (bcb->bcb_flags & BCB_writer_start) { - Database::Checkout dcoHolder(dbb); THREAD_YIELD(); } @@ -1048,10 +1047,7 @@ { bcb->bcb_flags &= ~BCB_cache_writer; bcb->bcb_writer_sem.release(); // Wake up running thread - { // scope - Database::Checkout dcoHolder(dbb); - bcb->bcb_writer_fini.enter(); - } + bcb->bcb_writer_fini.enter(); } #endif @@ -1268,7 +1264,7 @@ BufferDesc* bdb; if ((bcb->bcb_flags & BCB_free_pending) && - (bdb = get_buffer(tdbb, FREE_PAGE, SYNC_SHARED /*LATCH_none*/, 1))) + (bdb = get_buffer(tdbb, FREE_PAGE, SYNC_NONE, 1))) { if (!write_buffer(tdbb, bdb, bdb->bdb_page, true, tdbb->tdbb_status_vector, true)) CCH_unwind(tdbb, false); @@ -1565,7 +1561,17 @@ if (dbb->dbb_lock->lck_logical != LCK_EX) { dbb->dbb_ast_flags |= DBB_assert_locks; } +} + +void CCH_init2(thread_db* tdbb) +{ + Database* dbb = tdbb->getDatabase(); + BufferControl* bcb = dbb->dbb_bcb; + + if (!(bcb->bcb_flags & BCB_exclusive) || (bcb->bcb_flags & (BCB_cache_writer | BCB_writer_start))) + return; + #ifdef CACHE_READER if (gds__thread_start(cache_reader, dbb, THREAD_high, 0, 0)) { @@ -1586,7 +1592,7 @@ try { - ThreadSync::start(cache_writer, dbb, THREAD_high); + Thread::start(cache_writer, dbb, THREAD_medium); } catch (const Exception&) { @@ -1594,10 +1600,7 @@ ERR_bugcheck_msg("cannot start cache writer thread"); } - { // scope - Database::Checkout dcoHolder(dbb); - bcb->bcb_writer_init.enter(); - } + bcb->bcb_writer_init.enter(); } #endif } @@ -2942,6 +2945,7 @@ #ifdef CACHE_WRITER + static THREAD_ENTRY_DECLARE cache_writer(THREAD_ENTRY_PARAM arg) { /************************************** @@ -2958,11 +2962,10 @@ * **************************************/ - /*** Database* dbb = (Database*)arg; - Database::SyncGuard dsGuard(dbb); ISC_STATUS_ARRAY status_vector; + MOVE_CLEAR(status_vector, sizeof(status_vector)); // Establish a thread context. ThreadContextHolder tdbb(status_vector); @@ -2970,10 +2973,20 @@ // Dummy attachment needed for lock owner identification. tdbb->setDatabase(dbb); - Jrd::Attachment* const attachment = Jrd::Attachment::create(dbb, 0); + + RefPtr<JAttachment> jAtt(NULL); + + Jrd::Attachment* attachment = Jrd::Attachment::create(dbb); + jAtt = attachment->att_interface = new SysAttachment(attachment); + jAtt->getMutex()->enter(); + tdbb->setAttachment(attachment); attachment->att_filename = dbb->dbb_filename; + UserId user; + user.usr_user_name = "Cache Writer"; + attachment->att_user = &user; + BufferControl* bcb = dbb->dbb_bcb; Jrd::ContextPoolHolder context(tdbb, bcb->bcb_bufferpool); @@ -2982,9 +2995,13 @@ // return, unlike the other try blocks further down the page. Semaphore& writer_sem = bcb->bcb_writer_sem; - try { + try + { LCK_init(tdbb, LCK_OWNER_attachment); + PAG_header(tdbb, true); + PAG_attachment_id(tdbb); TRA_init(attachment); + bcb->bcb_flags |= BCB_cache_writer; bcb->bcb_flags &= ~BCB_writer_start; @@ -2999,49 +3016,10 @@ bcb->bcb_flags &= ~(BCB_cache_writer | BCB_writer_start); return (THREAD_ENTRY_RETURN)(-1); } - ***/ - ISC_STATUS_ARRAY status_vector = {0}; - Jrd::Attachment* attachment= NULL; + attachment->att_next = dbb->dbb_sys_attachments; + dbb->dbb_sys_attachments = attachment; - { - bcb->bcb_flags |= BCB_cache_writer; - bcb->bcb_flags &= ~BCB_writer_start; - bcb->bcb_writer_init.release(); - - Database* dbb = (Database*)arg; - Database::SyncGuard dsGuard(dbb); - RefPtr<BufferControl> bcb = dbb->dbb_bcb; - - ClumpletWriter dpb(ClumpletReader::Tagged, MAX_DPB_SIZE); - dpb.reset(isc_dpb_version1); - dpb.insertString(isc_dpb_trusted_auth, "Cache Writer"); - - if (jrd8_attach_database(status_vector, NULL, dbb->dbb_filename.c_str(), &attachment, - dpb.getBufferLength(), dpb.getBuffer())) - { - gds__log_status(dbb->dbb_filename.c_str(), status_vector); - - bcb->bcb_flags &= ~BCB_writer_start; - - bcb->bcb_writer_init.release(); // ? - - return (THREAD_ENTRY_RETURN)(-1); - } - } - - Database* dbb = attachment->att_database; - - // Establish a thread context. - ThreadContextHolder tdbb(status_vector); - tdbb->setDatabase(dbb); - tdbb->setAttachment(attachment); - - BufferControl* bcb = dbb->dbb_bcb; - Jrd::ContextPoolHolder context(tdbb, bcb->bcb_bufferpool); - - Semaphore& writer_sem = bcb->bcb_writer_sem; - try { while (bcb->bcb_flags & BCB_cache_writer) @@ -3053,10 +3031,8 @@ if (dbb->dbb_flags & DBB_suspend_bgio) { - { //scope - Database::Checkout dcoHolder(dbb); - writer_sem.tryEnter(10); - } + Attachment::Checkout cout(attachment); + writer_sem.tryEnter(10); continue; } @@ -3070,14 +3046,9 @@ } #endif - { // scope - Database::Checkout dcoHolder(dbb); - THREAD_YIELD(); - } - if (bcb->bcb_flags & BCB_free_pending) { - BufferDesc* bdb = get_buffer(tdbb, FREE_PAGE, None, 1); + BufferDesc* bdb = get_buffer(tdbb, FREE_PAGE, SYNC_NONE, 1); if (bdb) { write_buffer(tdbb, bdb, bdb->bdb_page, true, status_vector, true); } @@ -3090,12 +3061,11 @@ dbb->dbb_reader_sem.post(); } #endif -#ifdef GARBAGE_THREAD + if ((dbb->dbb_flags & DBB_garbage_collector) && !(dbb->dbb_flags & DBB_gc_active)) { dbb->dbb_gc_sem.release(); } -#endif } // If there's more work to do voluntarily ask to be rescheduled. @@ -3121,16 +3091,14 @@ else { bcb->bcb_flags &= ~BCB_writer_active; - Database::Checkout dcoHolder(dbb); + Attachment::Checkout cout(attachment); writer_sem.tryEnter(10); } } - /*** LCK_fini(tdbb, LCK_OWNER_attachment); - Jrd::Attachment::destroy(attachment); // no need saving warning error strings here - ***/ - jrd8_detach_database(status_vector, &attachment); + jAtt = NULL; + tdbb->setAttachment(NULL); bcb->bcb_flags &= ~BCB_cache_writer; @@ -3964,6 +3932,7 @@ } if (walk) { + oldest->release(tdbb); if (!--walk) break; @@ -5047,7 +5016,7 @@ if (!isTempPage && (backup_state == nbak_state_stalled || - (backup_state == nbak_state_merge && bdb->bdb_difference_page))) + (backup_state == nbak_state_merge && bdb->bdb_difference_page))) { const bool res = dbb->dbb_backup_manager->writeDifference(status, Modified: firebird/trunk/src/jrd/cch.h =================================================================== --- firebird/trunk/src/jrd/cch.h 2011-05-27 03:27:46 UTC (rev 53020) +++ firebird/trunk/src/jrd/cch.h 2011-05-27 07:57:16 UTC (rev 53021) @@ -111,13 +111,11 @@ static BufferControl* create(); static void destroy(BufferControl*); + Database* bcb_database; + Firebird::MemoryPool* bcb_bufferpool; Firebird::MemoryStats bcb_memory_stats; - // To be deleted when PAG will be not coupled with Database. - // Used only in CS mode when each BufferControl have one Database. - Database* bcb_database; - UCharStack bcb_memory; // Large block partitioned into buffers que bcb_in_use; // Que of buffers in use, main LRU que que bcb_pending; // Que of buffers which are going to be freed and reassigned Modified: firebird/trunk/src/jrd/cch_proto.h =================================================================== --- firebird/trunk/src/jrd/cch_proto.h 2011-05-27 03:27:46 UTC (rev 53020) +++ firebird/trunk/src/jrd/cch_proto.h 2011-05-27 07:57:16 UTC (rev 53021) @@ -54,6 +54,7 @@ void CCH_get_related(Jrd::thread_db*, Jrd::PageNumber, Jrd::PagesArray&); Ods::pag* CCH_handoff(Jrd::thread_db*, Jrd::win*, ULONG, int, SCHAR, int, const bool); void CCH_init(Jrd::thread_db*, ULONG, bool); +void CCH_init2(Jrd::thread_db*); void CCH_mark(Jrd::thread_db*, Jrd::win*, bool, bool); void CCH_must_write(Jrd::thread_db*, Jrd::win*); void CCH_precedence(Jrd::thread_db*, Jrd::win*, ULONG); Modified: firebird/trunk/src/jrd/dfw.epp =================================================================== --- firebird/trunk/src/jrd/dfw.epp 2011-05-27 03:27:46 UTC (rev 53020) +++ firebird/trunk/src/jrd/dfw.epp 2011-05-27 07:57:16 UTC (rev 53021) @@ -118,6 +118,7 @@ #include "../jrd/event_proto.h" #include "../jrd/nbak.h" #include "../jrd/trig.h" +#include "../jrd/GarbageCollector.h" #include "../jrd/IntlManager.h" #include "../jrd/UserManagement.h" #include "../jrd/Function.h" @@ -4166,15 +4167,11 @@ Arg::Gds(isc_obj_in_use) << Arg::Str(work->dfw_name)); } -#ifdef GARBAGE_THREAD // Free any memory associated with the relation's garbage collection bitmap + if (dbb->dbb_garbage_collector) { + dbb->dbb_garbage_collector->removeRelation(relation->rel_id); + } - delete relation->rel_gc_bitmap; - relation->rel_gc_bitmap = NULL; - - delete relation->rel_garbage; - relation->rel_garbage = NULL; -#endif if (relation->rel_file) { EXT_fini (relation, false); } Modified: firebird/trunk/src/jrd/dpm.epp =================================================================== --- firebird/trunk/src/jrd/dpm.epp 2011-05-27 03:27:46 UTC (rev 53020) +++ firebird/trunk/src/jrd/dpm.epp 2011-05-27 07:57:16 UTC (rev 53021) @@ -1549,7 +1549,7 @@ // If I'm a sweeper I don't need to look at swept pages. Also I should // check processed pages if they were swept. - const bool sweeper = (tdbb->tdbb_flags & TDBB_sweeper); + const bool sweeper = (rpb->rpb_stream_flags & RPB_s_sweeper); if (sweeper && (pp_sequence || slot) && !line) { Modified: firebird/trunk/src/jrd/jrd.cpp =================================================================== --- firebird/trunk/src/jrd/jrd.cpp 2011-05-27 03:27:46 UTC (rev 53020) +++ firebird/trunk/src/jrd/jrd.cpp 2011-05-27 07:57:16 UTC (rev 53021) @@ -1379,6 +1379,7 @@ // initialize shadowing as soon as the database is ready for it // but before any real work is done SDW_init(tdbb, options.dpb_activate_shadow, options.dpb_delete_shadow); + CCH_init2(tdbb); } else { @@ -1604,11 +1605,10 @@ ERR_post(Arg::Gds(isc_bad_dpb_content) << Arg::Gds(isc_cant_validate)); } -#ifdef GARBAGE_THREAD // Can't allow garbage collection during database validation. VIO_fini(tdbb); -#endif + if (!VAL_validate(tdbb, options.dpb_verify)) { ERR_punt(); } @@ -1685,11 +1685,7 @@ } PAG_attachment_id(tdbb); - -#ifdef GARBAGE_THREAD VIO_init(tdbb); -#endif - CCH_release_exclusive(tdbb); // if there was an error, the status vector is all set @@ -2573,10 +2569,8 @@ // but before any real work is done SDW_init(tdbb, options.dpb_activate_shadow, options.dpb_delete_shadow); - -#ifdef GARBAGE_THREAD + CCH_init2(tdbb); VIO_init(tdbb); -#endif if (options.dpb_set_db_readonly) { @@ -4282,6 +4276,22 @@ } +void SysAttachment::destroy(Attachment* attachment) +{ + Database* dbb = attachment->att_database; + + for (Jrd::Attachment** ptr = &dbb->dbb_sys_attachments; *ptr; ptr = &(*ptr)->att_next) + { + if (*ptr == attachment) + { + *ptr = attachment->att_next; + break; + } + } + Jrd::Attachment::destroy(attachment); +} + + JTransaction* JStatement::execute(IStatus* user_status, Firebird::ITransaction* apiTra, unsigned int in_msg_type, const FbMessage* inMsgBuffer, const FbMessage* outMsgBuffer) { @@ -5666,21 +5676,27 @@ if ((dbb->dbb_flags & (DBB_gc_cooperative | DBB_gc_background)) == 0) { - string gc_policy = dbb->dbb_config->getGCPolicy(); - gc_policy.lower(); - if (gc_policy == GCPolicyCooperative) { + if (!dbb->dbb_config->getSharedCache()) { dbb->dbb_flags |= DBB_gc_cooperative; } - else if (gc_policy == GCPolicyBackground) { - dbb->dbb_flags |= DBB_gc_background; - } - else if (gc_policy == GCPolicyCombined) { - dbb->dbb_flags |= DBB_gc_cooperative | DBB_gc_background; - } - else // config value is invalid + else { - // this should not happen - means bug in config - fb_assert(false); + string gc_policy = dbb->dbb_config->getGCPolicy(); + gc_policy.lower(); + if (gc_policy == GCPolicyCooperative) { + dbb->dbb_flags |= DBB_gc_cooperative; + } + else if (gc_policy == GCPolicyBackground) { + dbb->dbb_flags |= DBB_gc_background; + } + else if (gc_policy == GCPolicyCombined) { + dbb->dbb_flags |= DBB_gc_cooperative | DBB_gc_background; + } + else // config value is invalid + { + // this should not happen - means bug in config + fb_assert(false); + } } } @@ -6054,9 +6070,7 @@ TRA_header_write(tdbb, dbb, 0L); // Update transaction info on header page. #endif -#ifdef GARBAGE_THREAD VIO_fini(tdbb); -#endif CMP_fini(tdbb); CCH_fini(tdbb); @@ -6853,6 +6867,10 @@ { shutdown_database(dbb, true); } + else + { + dbb->dbb_sync.unlock(); + } } } } Modified: firebird/trunk/src/jrd/req.h =================================================================== --- firebird/trunk/src/jrd/req.h 2011-05-27 03:27:46 UTC (rev 53020) +++ firebird/trunk/src/jrd/req.h 2011-05-27 07:57:16 UTC (rev 53021) @@ -123,6 +123,7 @@ const USHORT RPB_s_update = 0x2; // input stream fetched for update const USHORT RPB_s_no_data = 0x4; // nobody is going to access the data const USHORT RPB_s_undo_data = 0x8; // data got from undo log +const USHORT RPB_s_sweeper = 0x10; // garbage collector - skip swept pages #define SET_NULL(record, id) record->rec_data [id >> 3] |= (1 << (id & 7)) #define CLEAR_NULL(record, id) record->rec_data [id >> 3] &= ~(1 << (id & 7)) Modified: firebird/trunk/src/jrd/tra.cpp =================================================================== --- firebird/trunk/src/jrd/tra.cpp 2011-05-27 03:27:46 UTC (rev 53020) +++ firebird/trunk/src/jrd/tra.cpp 2011-05-27 07:57:16 UTC (rev 53021) @@ -82,10 +82,6 @@ using namespace Ods; using namespace Firebird; -#ifdef GARBAGE_THREAD -#include "../common/isc_s_proto.h" -#endif - typedef Firebird::GenericMap<Firebird::Pair<Firebird::NonPooled<USHORT, UCHAR> > > RelationLockTypeMap; @@ -446,13 +442,10 @@ if (transaction->tra_flags & (TRA_prepare2 | TRA_reconnected)) MET_update_transaction(tdbb, transaction, true); -#ifdef GARBAGE_THREAD // Flush pages if transaction logically modified data if (transaction->tra_flags & TRA_write) -#endif CCH_flush(tdbb, FLUSH_TRAN, transaction->tra_number); -#ifdef GARBAGE_THREAD else if (transaction->tra_flags & (TRA_prepare2 | TRA_reconnected)) { // If the transaction only read data but is a member of a @@ -461,7 +454,6 @@ CCH_flush(tdbb, FLUSH_SYSTEM, 0); } -#endif if (retaining_flag) { @@ -993,13 +985,10 @@ DFW_perform_work(tdbb, transaction); -#ifdef GARBAGE_THREAD // Flush pages if transaction logically modified data if (transaction->tra_flags & TRA_write) -#endif CCH_flush(tdbb, FLUSH_TRAN, transaction->tra_number); -#ifdef GARBAGE_THREAD else if (transaction->tra_flags & TRA_prepare2) { // If the transaction only read data but is a member of a @@ -1008,7 +997,6 @@ CCH_flush(tdbb, FLUSH_SYSTEM, 0); } -#endif // Set the state on the inventory page to be limbo @@ -1779,7 +1767,6 @@ tdbb->setTransaction(transaction); -#ifdef GARBAGE_THREAD // The garbage collector runs asynchronously with respect to // our database sweep. This isn't good enough since we must // be absolutely certain that all dead transactions have been @@ -1788,7 +1775,6 @@ // synchronously perform the garbage collection ourselves. transaction->tra_attachment->att_flags &= ~ATT_notify_gc; -#endif if (VIO_sweep(tdbb, transaction)) { @@ -3490,13 +3476,11 @@ { dbb->dbb_oldest_snapshot = trans->tra_oldest_active; -#if defined(GARBAGE_THREAD) if (!(dbb->dbb_flags & DBB_gc_active) && (dbb->dbb_flags & DBB_gc_background)) { dbb->dbb_flags |= DBB_gc_pending; dbb->dbb_gc_sem.release(); } -#endif } // If the transaction block is getting out of hand, force a sweep Modified: firebird/trunk/src/jrd/vio.cpp =================================================================== --- firebird/trunk/src/jrd/vio.cpp 2011-05-27 03:27:46 UTC (rev 53020) +++ firebird/trunk/src/jrd/vio.cpp 2011-05-27 07:57:16 UTC (rev 53021) @@ -61,6 +61,8 @@ #include "../jrd/btr.h" #include "../jrd/exe.h" #include "../jrd/rse.h" +#include "../jrd/scl.h" +#include "../common/classes/alloc.h" #include "../common/ThreadStart.h" #include "../jrd/thread_proto.h" #ifdef VIO_DEBUG @@ -77,6 +79,7 @@ #include "../jrd/idx_proto.h" #include "../common/isc_s_proto.h" #include "../jrd/jrd_proto.h" +#include "../jrd/ini_proto.h" #include "../jrd/lck_proto.h" #include "../jrd/met_proto.h" #include "../jrd/mov_proto.h" @@ -88,6 +91,7 @@ #include "../jrd/dyn_ut_proto.h" #include "../jrd/Function.h" #include "../common/StatusArg.h" +#include "../jrd/GarbageCollector.h" using namespace Jrd; using namespace Firebird; @@ -104,9 +108,7 @@ USHORT irrelevant_field, bool void_update_is_relevant = false); static void garbage_collect(thread_db*, record_param*, ULONG, RecordStack&); static void garbage_collect_idx(thread_db*, record_param*, Record*, Record*); -#ifdef GARBAGE_THREAD static THREAD_ENTRY_DECLARE garbage_collector(THREAD_ENTRY_PARAM); -#endif enum UndoDataRet { udExists, @@ -118,9 +120,7 @@ static UndoDataRet get_undo_data(thread_db* tdbb, jrd_tra* transaction, record_param* rpb); static void list_staying(thread_db*, record_param*, RecordStack&); -#ifdef GARBAGE_THREAD static void notify_garbage_collector(thread_db*, record_param *, SLONG = -1); -#endif static Record* realloc_record(Record*& record, USHORT fmt_length); const int PREPARE_OK = 0; @@ -143,15 +143,14 @@ // Pick up relation ids #include "../jrd/ini.h" -#ifdef GARBAGE_THREAD static const UCHAR gc_tpb[] = { isc_tpb_version1, isc_tpb_read, isc_tpb_read_committed, isc_tpb_rec_version, isc_tpb_ignore_limbo }; -#endif + inline void clearRecordStack(RecordStack& stack) { /************************************** @@ -506,16 +505,6 @@ } #endif -#ifndef DEV_BUILD - // The sweeper threads run in the background without - // any way to inspect these counters. For debugging - // purposes, they are maintained in the DEV_BUILD. - - if (tdbb->tdbb_flags & TDBB_sweeper) { - return; - } -#endif - const USHORT relation_id = relation->rel_id; vcl** ptr = attachment->att_counts + count_id; @@ -546,10 +535,8 @@ **************************************/ SET_TDBB(tdbb); -#ifdef GARBAGE_THREAD const bool gcPolicyCooperative = tdbb->getDatabase()->dbb_flags & DBB_gc_cooperative; const bool gcPolicyBackground = tdbb->getDatabase()->dbb_flags & DBB_gc_background; -#endif #ifdef VIO_DEBUG if (debug_flag > DEBUG_TRACE_ALL) @@ -620,10 +607,8 @@ !(rpb->rpb_flags & (rpb_deleted | rpb_damaged)) && (rpb->rpb_b_page == 0 || rpb->rpb_transaction_nr >= transaction->tra_oldest_active)) { -#ifdef GARBAGE_THREAD if (gcPolicyBackground && rpb->rpb_b_page) notify_garbage_collector(tdbb, rpb); -#endif // GARBAGE_THREAD return true; } @@ -747,13 +732,11 @@ rpb->rpb_transaction_nr, transaction->tra_number); } #endif -#ifdef GARBAGE_THREAD - if (!(rpb->rpb_flags & rpb_chained) && attachment->att_flags & ATT_notify_gc) + if (gcPolicyBackground && !(rpb->rpb_flags & rpb_chained) && attachment->att_flags & ATT_notify_gc) { notify_garbage_collector(tdbb, rpb); } -#endif case tra_precommitted: if (attachment->att_flags & ATT_NO_CLEANUP || @@ -852,7 +835,6 @@ return false; } -#ifdef GARBAGE_THREAD // hvlad: if I'm garbage collector I don't need to read backversion // of active record. Just do notify self about it if (attachment->att_flags & ATT_garbage_collector) @@ -861,7 +843,6 @@ CCH_RELEASE(tdbb, &rpb->getWindow(tdbb)); return false; } -#endif if (!(rpb->rpb_flags & rpb_delta)) { @@ -986,7 +967,6 @@ if (rpb->rpb_transaction_nr < transaction->tra_oldest_active && !(attachment->att_flags & ATT_no_cleanup)) { -#ifdef GARBAGE_THREAD if (!gcPolicyCooperative && (attachment->att_flags & ATT_notify_gc) && !rpb->rpb_relation->isTemporary()) { @@ -994,7 +974,6 @@ CCH_RELEASE(tdbb, &rpb->getWindow(tdbb)); } else -#endif { CCH_RELEASE(tdbb, &rpb->getWindow(tdbb)); expunge(tdbb, rpb, transaction, 0); @@ -1017,7 +996,6 @@ if (cannotGC) { -#ifdef GARBAGE_THREAD if (gcPolicyBackground && attachment->att_flags & (ATT_notify_gc | ATT_garbage_collector) && (rpb->rpb_b_page != 0 && !(rpb->rpb_flags & rpb_chained)) ) @@ -1025,20 +1003,18 @@ // VIO_chase_record_version notify_garbage_collector(tdbb, rpb); } -#endif return true; } // Garbage collect. -#ifdef GARBAGE_THREAD if (!gcPolicyCooperative && (attachment->att_flags & ATT_notify_gc) && !rpb->rpb_relation->isTemporary()) { notify_garbage_collector(tdbb, rpb); return true; } -#endif + purge(tdbb, rpb); // Go back to be primary record version and chase versions all over again. @@ -1696,17 +1672,14 @@ transaction->tra_flags |= TRA_perform_autocommit; } -#ifdef GARBAGE_THREAD // VIO_erase if ((tdbb->getDatabase()->dbb_flags & DBB_gc_background) && !rpb->rpb_relation->isTemporary()) { notify_garbage_collector(tdbb, rpb, transaction->tra_number); } -#endif } -#ifdef GARBAGE_THREAD void VIO_fini(thread_db* tdbb) { /************************************** @@ -1728,7 +1701,6 @@ dbb->dbb_gc_fini.enter(); } } -#endif bool VIO_garbage_collect(thread_db* tdbb, record_param* rpb, const jrd_tra* transaction) @@ -2195,7 +2167,6 @@ } -#ifdef GARBAGE_THREAD void VIO_init(thread_db* tdbb) { /************************************** @@ -2248,7 +2219,6 @@ } } } -#endif void VIO_merge_proc_sav_points(thread_db* tdbb, jrd_tra* transaction, Savepoint** sav_point_list) @@ -2658,14 +2628,12 @@ transaction->tra_flags |= TRA_perform_autocommit; } -#ifdef GARBAGE_THREAD // VIO_modify if ((tdbb->getDatabase()->dbb_flags & DBB_gc_background) && !org_rpb->rpb_relation->isTemporary()) { notify_garbage_collector(tdbb, org_rpb, transaction->tra_number); } -#endif } @@ -2792,7 +2760,7 @@ if (!record) { if (!pool) - pool = dbb->dbb_permanent; + pool = rpb->rpb_relation->rel_pool; record = rpb->rpb_record = FB_NEW_RPT(*pool, format->fmt_length) Record(*pool); } @@ -3186,12 +3154,14 @@ record_param rpb; rpb.rpb_record = NULL; - rpb.rpb_stream_flags = 0; + rpb.rpb_stream_flags = RPB_s_no_data | RPB_s_sweeper; rpb.getWindow(tdbb).win_flags = WIN_large_scan; jrd_rel* relation = 0; // wasn't initialized: memory problem in catch() part. vec<jrd_rel*>* vector = 0; + GarbageCollector* gc = dbb->dbb_garbage_collector; + try { for (size_t i = 1; (vector = attachment->att_relations) && i < vector->count(); i++) @@ -3203,11 +3173,11 @@ rpb.rpb_number.setValue(BOF_NUMBER); rpb.rpb_org_scans = relation->rel_scan_count++; ++relation->rel_sweep_count; -#ifdef GARBAGE_THREAD - if (relation->rel_garbage) { - relation->rel_garbage->clear(); + + if (gc) { + gc->sweptRelation(transaction->tra_oldest_active, relation->rel_id); } -#endif + while (VIO_next_record(tdbb, &rpb, transaction, 0, false)) { CCH_RELEASE(tdbb, &rpb.getWindow(tdbb)); @@ -4013,11 +3983,10 @@ if (!DPM_get(tdbb, rpb, LCK_write)) { -#ifdef GARBAGE_THREAD // expunge if (tdbb->getDatabase()->dbb_flags & DBB_gc_background) notify_garbage_collector(tdbb, rpb); -#endif + return; } @@ -4038,11 +4007,9 @@ if (!(rpb->rpb_flags & rpb_deleted) || rpb->rpb_transaction_nr >= transaction->tra_oldest_active) { -#ifdef GARBAGE_THREAD // expunge if (tdbb->getDatabase()->dbb_flags & DBB_gc_background) notify_garbage_collector(tdbb, rpb); -#endif CCH_RELEASE(tdbb, &rpb->getWindow(tdbb)); return; @@ -4180,7 +4147,6 @@ } -#ifdef GARBAGE_THREAD static THREAD_ENTRY_DECLARE garbage_collector(THREAD_ENTRY_PARAM arg) { /************************************** @@ -4216,27 +4182,46 @@ bool found = false, flush = false; record_param rpb; MOVE_CLEAR(&rpb, sizeof(record_param)); + rpb.getWindow(tdbb).win_flags = WIN_garbage_collector; + rpb.rpb_stream_flags = RPB_s_no_data | RPB_s_sweeper; jrd_rel* relation = NULL; jrd_tra* transaction = NULL; + RefPtr<JAttachment> jAtt(NULL); + GarbageCollector* gc = NULL; + try { // Pseudo attachment needed for lock owner identification. Jrd::Attachment* const attachment = Jrd::Attachment::create(dbb); + jAtt = attachment->att_interface = new SysAttachment(attachment); + jAtt->getMutex()->enter(); + tdbb->setAttachment(attachment); attachment->att_filename = dbb->dbb_filename; attachment->att_flags = ATT_garbage_collector; - rpb.getWindow(tdbb).win_flags = WIN_garbage_collector; + UserId user; + user.usr_user_name = "Garbage Collector"; + attachment->att_user = &user; LCK_init(tdbb, LCK_OWNER_attachment); + INI_init(tdbb); + INI_init2(tdbb); + PAG_header(tdbb, true); + PAG_attachment_id(tdbb); TRA_init(attachment); + gc = FB_NEW(*attachment->att_pool) GarbageCollector(*attachment->att_pool, dbb); + dbb->dbb_garbage_collector = gc; + + attachment->att_next = dbb->dbb_sys_attachments; + dbb->dbb_sys_attachments = attachment; + // Notify our creator that we have started dbb->dbb_flags |= DBB_garbage_collector; dbb->dbb_gc_init.release(); - } // try catch (const Firebird::Exception&) { goto gc_exit; @@ -4256,7 +4241,7 @@ dbb->dbb_flags |= DBB_gc_active; found = false; - relation = 0; + relation = NULL; // If background thread activity has been suspended because // of I/O errors then idle until the condition is cleared. @@ -4277,6 +4262,7 @@ while (dbb->dbb_flags & DBB_suspend_bgio) { + Attachment::Checkout cout(jAtt->getHandle()); dbb->dbb_gc_sem.tryEnter(10); if (!(dbb->dbb_flags & DBB_garbage_collector)) @@ -4296,108 +4282,88 @@ // Express interest in the relation to prevent it from being deleted // out from under us while garbage collection is in-progress. - vec<jrd_rel*>* vector = tdbb->getAttachment()->att_relations; - - for (ULONG id = 0; vector && id < vector->count(); ++id) + USHORT relID; + PageBitmap* gc_bitmap = NULL; + if (gc->getPageBitmap(dbb->dbb_oldest_snapshot, relID, &gc_bitmap)) { - relation = (*vector)[id]; + relation = MET_lookup_relation_id(tdbb, relID, false); + if (!relation || (relation->rel_flags & (REL_deleted | REL_deleting))) + { + delete gc_bitmap; + gc_bitmap = NULL; + gc->removeRelation(relID); + } //jrd_rel::RelPagesSnapshot pagesSnapshot(tdbb, relation); //relation->fillPagesSnapshot(pagesSnapshot); - RelationGarbage *relGarbage = - relation ? (RelationGarbage*)relation->rel_garbage : NULL; - - if (relation && (relation->rel_gc_bitmap || relGarbage) && - !(relation->rel_flags & (REL_deleted | REL_deleting))) + if (gc_bitmap) { - if (relGarbage) { - relGarbage->getGarbage(dbb->dbb_oldest_snapshot, &relation->rel_gc_bitmap); - } - ++relation->rel_sweep_count; rpb.rpb_relation = relation; - if (relation->rel_gc_bitmap) + while (gc_bitmap->getFirst()) { - while (relation->rel_gc_bitmap->getFirst()) - { - const ULONG dp_sequence = relation->rel_gc_bitmap->current(); + const ULONG dp_sequence = gc_bitmap->current(); - if (!(dbb->dbb_flags & DBB_garbage_collector)) { - --relation->rel_sweep_count; - goto gc_exit; - } + if (!(dbb->dbb_flags & DBB_garbage_collector)) { + --relation->rel_sweep_count; + goto gc_exit; + } - relation->rel_gc_bitmap->clear(dp_sequence); + gc_bitmap->clear(dp_sequence); - if (!transaction) - { - // Start a "precommitted" transaction by using read-only, - // read committed. Of particular note is the absence of a - // transaction lock which means the transaction does not - // inhibit garbage collection by its very existence. + if (!transaction) + { + // Start a "precommitted" transaction by using read-only, + // read committed. Of particular note is the absence of a + // transaction lock which means the transaction does not + // inhibit garbage collection by its very existence. - transaction = TRA_start(tdbb, sizeof(gc_tpb), gc_tpb); - tdbb->setTransaction(transaction); - } - else - { - // Refresh our notion of the oldest transactions for - // efficient garbage collection. This is very cheap. + transaction = TRA_start(tdbb, sizeof(gc_tpb), gc_tpb); + tdbb->setTransaction(transaction); + } + else + { + // Refresh our notion of the oldest transactions for + // efficient garbage collection. This is very cheap. - transaction->tra_oldest = dbb->dbb_oldest_transaction; - transaction->tra_oldest_active = dbb->dbb_oldest_snapshot; - } + transaction->tra_oldest = dbb->dbb_oldest_transaction; + transaction->tra_oldest_active = dbb->dbb_oldest_snapshot; + } - found = flush = true; - rpb.rpb_number.setValue(((SINT64) dp_sequence * dbb->dbb_max_reco... [truncated message content] |