mirror of
https://github.com/FirebirdSQL/firebird.git
synced 2025-01-22 18:43:02 +01:00
Merge pull request #7735 from FirebirdSQL/work/AttCacheBdb
Per-attachment cache of pointers to the often used page buffers.
This commit is contained in:
commit
11ffa71b4f
@ -310,6 +310,7 @@
|
||||
<ClInclude Include="..\..\..\src\jrd\ods_proto.h" />
|
||||
<ClInclude Include="..\..\..\src\jrd\optimizer\Optimizer.h" />
|
||||
<ClInclude Include="..\..\..\src\jrd\pag.h" />
|
||||
<ClInclude Include="..\..\..\src\jrd\PageToBufferMap.h" />
|
||||
<ClInclude Include="..\..\..\src\jrd\pag_proto.h" />
|
||||
<ClInclude Include="..\..\..\src\jrd\par_proto.h" />
|
||||
<ClInclude Include="..\..\..\src\jrd\PreparedStatement.h" />
|
||||
|
@ -1085,6 +1085,7 @@
|
||||
<ClInclude Include="..\..\..\src\jrd\WorkerAttachment.h">
|
||||
<Filter>Header files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\..\src\jrd\PageToBufferMap.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="..\..\..\src\dsql\DdlNodes.epp">
|
||||
|
@ -73,6 +73,7 @@ namespace Jrd
|
||||
class jrd_file;
|
||||
class Format;
|
||||
class BufferControl;
|
||||
class PageToBufferMap;
|
||||
class SparseBitmap;
|
||||
class jrd_rel;
|
||||
class ExternalFile;
|
||||
@ -639,6 +640,8 @@ public:
|
||||
USHORT att_current_timezone;
|
||||
int att_parallel_workers;
|
||||
|
||||
PageToBufferMap* att_bdb_cache; // managed in CCH, created in att_pool, freed with it
|
||||
|
||||
Firebird::RefPtr<Firebird::IReplicatedSession> att_replicator;
|
||||
Firebird::AutoPtr<Replication::TableMatcher> att_repl_matcher;
|
||||
Firebird::Array<Applier*> att_repl_appliers;
|
||||
|
217
src/jrd/PageToBufferMap.h
Normal file
217
src/jrd/PageToBufferMap.h
Normal file
@ -0,0 +1,217 @@
|
||||
/*
|
||||
* PROGRAM: JRD Access Method
|
||||
* MODULE: PageToBufferMap.h
|
||||
* DESCRIPTION: Support of disk cache manager
|
||||
*
|
||||
* The contents of this file are subject to the Interbase 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.Inprise.com/IPL.html
|
||||
*
|
||||
* Software distributed under the License is distributed on an
|
||||
* "AS IS" basis, 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 Vladyslav Khorsun for the
|
||||
* Firebird Open Source RDBMS project.
|
||||
*
|
||||
* Copyright (c) 2023 Vladyslav Khorsun <hvlad@users.sourceforge.net>
|
||||
* and all contributors signed below.
|
||||
*
|
||||
* All Rights Reserved.
|
||||
* Contributor(s): ______________________________________.
|
||||
*/
|
||||
|
||||
#ifndef JRD_PAGE_TO_BUFFER_MAP
|
||||
#define JRD_PAGE_TO_BUFFER_MAP
|
||||
|
||||
#include "../common/classes/Hash.h"
|
||||
#include "../jrd/cch.h"
|
||||
|
||||
namespace Jrd {
|
||||
|
||||
// PageToBufferMap used to cache pointers to the often used page buffers.
|
||||
// Its purpose is to avoid more costly usage of shared hash table.
|
||||
|
||||
class PageToBufferMap
|
||||
{
|
||||
static const size_t MAP_SIZE = 64;
|
||||
|
||||
public:
|
||||
explicit PageToBufferMap(MemoryPool& pool) :
|
||||
m_map(pool)
|
||||
{
|
||||
Item* items = FB_NEW_POOL(pool) Item[MAP_SIZE];
|
||||
for (FB_SIZE_T i = 1; i < MAP_SIZE; i++)
|
||||
items[i - 1].m_next = &items[i];
|
||||
|
||||
m_free = items;
|
||||
}
|
||||
|
||||
BufferDesc* get(PageNumber page)
|
||||
{
|
||||
Item* item = m_map.lookup(page);
|
||||
|
||||
if (!item)
|
||||
return nullptr;
|
||||
|
||||
if (m_list != item)
|
||||
{
|
||||
listRemove(item);
|
||||
listInsert(item);
|
||||
}
|
||||
|
||||
return item->m_bdb;
|
||||
}
|
||||
|
||||
void put(BufferDesc* bdb)
|
||||
{
|
||||
Item* item = m_map.lookup(bdb->bdb_page);
|
||||
if (item)
|
||||
{
|
||||
if (m_list != item)
|
||||
listRemove(item);
|
||||
}
|
||||
else
|
||||
{
|
||||
item = getFreeItem();
|
||||
item->m_page = bdb->bdb_page;
|
||||
m_map.add(item);
|
||||
}
|
||||
|
||||
item->m_bdb = bdb;
|
||||
if (m_list != item)
|
||||
listInsert(item);
|
||||
}
|
||||
|
||||
void remove(PageNumber page)
|
||||
{
|
||||
Item* item = m_map.remove(page);
|
||||
|
||||
fb_assert(item);
|
||||
if (!item)
|
||||
return;
|
||||
|
||||
listRemove(item);
|
||||
|
||||
item->m_bdb = nullptr;
|
||||
item->m_next = m_free;
|
||||
m_free = item;
|
||||
}
|
||||
|
||||
private:
|
||||
struct Item;
|
||||
using HashTableType = Firebird::HashTable<Item, MAP_SIZE, PageNumber, Item, Item>;
|
||||
|
||||
struct Item : public HashTableType::Entry
|
||||
{
|
||||
PageNumber m_page;
|
||||
BufferDesc* m_bdb = nullptr;
|
||||
Item* m_next = nullptr; // LRU list support
|
||||
Item* m_prev = nullptr;
|
||||
|
||||
// KeyOfValue
|
||||
static PageNumber generate(Item& item)
|
||||
{
|
||||
return item.m_page;
|
||||
}
|
||||
|
||||
// Hash function
|
||||
static FB_SIZE_T hash(const PageNumber& value, FB_SIZE_T hashSize)
|
||||
{
|
||||
return value.getPageNum() % hashSize;
|
||||
}
|
||||
|
||||
// HashTable::Entry
|
||||
bool isEqual(const PageNumber& page) const override
|
||||
{
|
||||
return this->m_page == page;
|
||||
}
|
||||
|
||||
Item* get() override
|
||||
{
|
||||
return this;
|
||||
}
|
||||
};
|
||||
|
||||
Item* getFreeItem()
|
||||
{
|
||||
Item* item = m_free;
|
||||
if (item)
|
||||
{
|
||||
m_free = m_free->m_next;
|
||||
item->m_next = nullptr;
|
||||
return item;
|
||||
}
|
||||
|
||||
// get least recently used item from list
|
||||
fb_assert(m_list != nullptr);
|
||||
|
||||
item = m_list->m_prev;
|
||||
listRemove(item);
|
||||
|
||||
if (m_map.remove(item->m_page) != item)
|
||||
fb_assert(false);
|
||||
|
||||
item->m_bdb = nullptr;
|
||||
return item;
|
||||
}
|
||||
|
||||
|
||||
void listRemove(Item* item)
|
||||
{
|
||||
// remove item from list
|
||||
fb_assert(m_list != nullptr);
|
||||
fb_assert(item->m_next);
|
||||
fb_assert(item->m_prev);
|
||||
|
||||
if (item->m_next == item)
|
||||
{
|
||||
fb_assert(item->m_prev == item);
|
||||
fb_assert(m_list == item);
|
||||
m_list = nullptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_list == item)
|
||||
m_list = item->m_next;
|
||||
|
||||
item->m_next->m_prev = item->m_prev;
|
||||
item->m_prev->m_next = item->m_next;
|
||||
}
|
||||
|
||||
item->m_next = item->m_prev = nullptr;
|
||||
}
|
||||
|
||||
void listInsert(Item* item)
|
||||
{
|
||||
// put item at the list head
|
||||
if (m_list != nullptr)
|
||||
{
|
||||
fb_assert(m_list->m_next);
|
||||
fb_assert(m_list->m_prev);
|
||||
|
||||
item->m_next = m_list;
|
||||
item->m_prev = m_list->m_prev;
|
||||
|
||||
item->m_next->m_prev = item;
|
||||
item->m_prev->m_next = item;
|
||||
}
|
||||
else
|
||||
{
|
||||
item->m_next = item;
|
||||
item->m_prev = item;
|
||||
}
|
||||
|
||||
m_list = item;
|
||||
}
|
||||
|
||||
HashTableType m_map;
|
||||
Item* m_list = nullptr; // head of LRU list
|
||||
Item* m_free = nullptr; // unused items
|
||||
};
|
||||
|
||||
} // namespace Jrd
|
||||
|
||||
#endif // JRD_PAGE_TO_BUFFER_MAP
|
@ -62,6 +62,7 @@
|
||||
#include "../common/classes/MsgPrint.h"
|
||||
#include "../jrd/CryptoManager.h"
|
||||
#include "../common/utils_proto.h"
|
||||
#include "../jrd/PageToBufferMap.h"
|
||||
|
||||
// Use lock-free lists in hash table implementation
|
||||
#define HASH_USE_CDS_LIST
|
||||
@ -131,6 +132,7 @@ static void prefetch_init(Prefetch*, thread_db*);
|
||||
static void prefetch_io(Prefetch*, FbStatusVector *);
|
||||
static void prefetch_prologue(Prefetch*, SLONG *);
|
||||
#endif
|
||||
static void cacheBuffer(Attachment* att, BufferDesc* bdb);
|
||||
static void check_precedence(thread_db*, WIN*, PageNumber);
|
||||
static void clear_precedence(thread_db*, BufferDesc*);
|
||||
static void down_grade(thread_db*, BufferDesc*, int high = 0);
|
||||
@ -3152,6 +3154,18 @@ void BufferControl::exceptionHandler(const Firebird::Exception& ex, BcbThreadSyn
|
||||
}
|
||||
|
||||
|
||||
static void cacheBuffer(Attachment* att, BufferDesc* bdb)
|
||||
{
|
||||
if (att)
|
||||
{
|
||||
if (!att->att_bdb_cache)
|
||||
att->att_bdb_cache = FB_NEW_POOL(*att->att_pool) PageToBufferMap(*att->att_pool);
|
||||
|
||||
att->att_bdb_cache->put(bdb);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void check_precedence(thread_db* tdbb, WIN* window, PageNumber page)
|
||||
{
|
||||
/**************************************
|
||||
@ -3782,6 +3796,32 @@ static BufferDesc* get_buffer(thread_db* tdbb, const PageNumber page, SyncType s
|
||||
SET_TDBB(tdbb);
|
||||
Database* dbb = tdbb->getDatabase();
|
||||
BufferControl* bcb = dbb->dbb_bcb;
|
||||
Attachment* att = tdbb->getAttachment();
|
||||
|
||||
if (att && att->att_bdb_cache)
|
||||
{
|
||||
if (BufferDesc* bdb = att->att_bdb_cache->get(page))
|
||||
{
|
||||
if (bdb->addRef(tdbb, syncType, wait))
|
||||
{
|
||||
if (bdb->bdb_page == page)
|
||||
{
|
||||
recentlyUsed(bdb);
|
||||
tdbb->bumpStats(RuntimeStatistics::PAGE_FETCHES);
|
||||
return bdb;
|
||||
}
|
||||
|
||||
bdb->release(tdbb, true);
|
||||
att->att_bdb_cache->remove(page);
|
||||
}
|
||||
else
|
||||
{
|
||||
fb_assert(wait <= 0);
|
||||
if (bdb->bdb_page == page)
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
while (true)
|
||||
{
|
||||
@ -3811,6 +3851,7 @@ static BufferDesc* get_buffer(thread_db* tdbb, const PageNumber page, SyncType s
|
||||
{
|
||||
recentlyUsed(bdb);
|
||||
tdbb->bumpStats(RuntimeStatistics::PAGE_FETCHES);
|
||||
cacheBuffer(att, bdb);
|
||||
return bdb;
|
||||
}
|
||||
|
||||
@ -3850,6 +3891,7 @@ static BufferDesc* get_buffer(thread_db* tdbb, const PageNumber page, SyncType s
|
||||
bdb->downgrade(syncType);
|
||||
recentlyUsed(bdb);
|
||||
tdbb->bumpStats(RuntimeStatistics::PAGE_FETCHES);
|
||||
cacheBuffer(att, bdb);
|
||||
return bdb;
|
||||
}
|
||||
}
|
||||
@ -3893,6 +3935,7 @@ static BufferDesc* get_buffer(thread_db* tdbb, const PageNumber page, SyncType s
|
||||
recentlyUsed(bdb);
|
||||
}
|
||||
tdbb->bumpStats(RuntimeStatistics::PAGE_FETCHES);
|
||||
cacheBuffer(att, bdb);
|
||||
return bdb;
|
||||
}
|
||||
}
|
||||
@ -3910,6 +3953,7 @@ static BufferDesc* get_buffer(thread_db* tdbb, const PageNumber page, SyncType s
|
||||
}
|
||||
recentlyUsed(bdb2);
|
||||
tdbb->bumpStats(RuntimeStatistics::PAGE_FETCHES);
|
||||
cacheBuffer(att, bdb2);
|
||||
}
|
||||
else
|
||||
bdb2 = nullptr;
|
||||
|
Loading…
Reference in New Issue
Block a user