Skip to content

Commit 85716f7

Browse files
authored
Merge pull request #7671 from FirebirdSQL/work/SortBlocksCache
Cache sort blocks by the sort owners to avoid contention in shared cache of sorts blocks.
2 parents 8e31b5d + 2db7aeb commit 85716f7

File tree

6 files changed

+71
-38
lines changed

6 files changed

+71
-38
lines changed

src/jrd/idx.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -214,16 +214,16 @@ class IndexCreateTask : public Task
214214

215215
IndexCreateTask(thread_db* tdbb, MemoryPool* pool, IndexCreation* creation) : Task(),
216216
m_pool(pool),
217+
m_dbb(tdbb->getDatabase()),
217218
m_tdbb_flags(tdbb->tdbb_flags),
218219
m_flags(0),
219220
m_creation(creation),
220-
m_sorts(*m_pool),
221+
m_sorts(*m_pool, m_dbb),
221222
m_items(*m_pool),
222223
m_stop(false),
223224
m_countPP(0),
224225
m_nextPP(0)
225226
{
226-
m_dbb = tdbb->getDatabase();
227227
Attachment* att = tdbb->getAttachment();
228228

229229
if (att->isGbak())

src/jrd/req.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -316,7 +316,7 @@ class Request : public pool_alloc<type_req>
316316
req_timeout(0),
317317
req_domain_validation(NULL),
318318
req_auto_trans(*req_pool),
319-
req_sorts(*req_pool),
319+
req_sorts(*req_pool, attachment->att_database),
320320
req_rpb(*req_pool),
321321
impureArea(*req_pool)
322322
{

src/jrd/sort.cpp

Lines changed: 59 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -68,12 +68,6 @@ const USHORT MAX_MERGE_LEVEL = 2;
6868
using namespace Jrd;
6969
using namespace Firebird;
7070

71-
void SortOwner::unlinkAll()
72-
{
73-
while (sorts.getCount())
74-
delete sorts.pop();
75-
}
76-
7771
// The sort buffer size should be just under a multiple of the
7872
// hardware memory page size to account for memory allocator
7973
// overhead. On most platforms, this saves 4KB to 8KB per sort
@@ -165,10 +159,11 @@ Sort::Sort(Database* dbb,
165159
FPTR_REJECT_DUP_CALLBACK call_back,
166160
void* user_arg,
167161
FB_UINT64 max_records)
168-
: m_dbb(dbb), m_last_record(NULL), m_next_pointer(NULL), m_records(0),
162+
: m_dbb(dbb), m_owner(owner),
163+
m_last_record(NULL), m_next_pointer(NULL), m_records(0),
169164
m_runs(NULL), m_merge(NULL), m_free_runs(NULL),
170165
m_flags(0), m_merge_pool(NULL),
171-
m_description(owner->getPool(), keys)
166+
m_description(m_owner->getPool(), keys)
172167
{
173168
/**************************************
174169
*
@@ -185,7 +180,7 @@ Sort::Sort(Database* dbb,
185180
* includes index key (which must be unique) and record numbers.
186181
*
187182
**************************************/
188-
fb_assert(owner);
183+
fb_assert(m_owner);
189184
fb_assert(unique_keys <= keys);
190185

191186
try
@@ -194,7 +189,7 @@ Sort::Sort(Database* dbb,
194189
// key description vector. Round the record length up to the next
195190
// longword, and add a longword to a pointer back to the pointer slot.
196191

197-
MemoryPool& pool = owner->getPool();
192+
MemoryPool& pool = m_owner->getPool();
198193

199194
const ULONG record_size = ROUNDUP(record_length + SIZEOF_SR_BCKPTR, FB_ALIGNMENT);
200195
m_longs = record_size >> SHIFTLONG;
@@ -248,8 +243,7 @@ Sort::Sort(Database* dbb,
248243

249244
// Link in new sort block
250245

251-
m_owner = owner;
252-
owner->linkSort(this);
246+
m_owner->linkSort(this);
253247
}
254248
catch (const BadAlloc&)
255249
{
@@ -610,15 +604,12 @@ void Sort::sort(thread_db* tdbb)
610604

611605
void Sort::allocateBuffer(MemoryPool& pool)
612606
{
613-
if (m_dbb->dbb_sort_buffers.hasData() && m_max_alloc_size <= MAX_SORT_BUFFER_SIZE)
607+
if (m_max_alloc_size <= MAX_SORT_BUFFER_SIZE)
614608
{
615-
SyncLockGuard guard(&m_dbb->dbb_sortbuf_sync, SYNC_EXCLUSIVE, "Sort::allocateBuffer");
616-
617-
if (m_dbb->dbb_sort_buffers.hasData())
609+
m_memory = m_owner->allocateBuffer();
610+
if (m_memory)
618611
{
619-
// The sort buffer cache has at least one big block, let's use it
620612
m_size_memory = MAX_SORT_BUFFER_SIZE;
621-
m_memory = m_dbb->dbb_sort_buffers.pop();
622613
m_flags |= scb_reuse_buffer;
623614
return;
624615
}
@@ -666,23 +657,14 @@ void Sort::allocateBuffer(MemoryPool& pool)
666657

667658
void Sort::releaseBuffer()
668659
{
669-
// Here we cache blocks to be reused later, but only the biggest ones
670-
671-
const size_t MAX_CACHED_SORT_BUFFERS = 8; // 1MB
672-
673-
SyncLockGuard guard(&m_dbb->dbb_sortbuf_sync, SYNC_EXCLUSIVE, "Sort::releaseBuffer");
674-
675-
if ((m_flags & scb_reuse_buffer) &&
676-
m_dbb->dbb_sort_buffers.getCount() < MAX_CACHED_SORT_BUFFERS)
660+
if (m_flags & scb_reuse_buffer)
677661
{
678662
fb_assert(m_size_memory == MAX_SORT_BUFFER_SIZE);
679-
680-
m_dbb->dbb_sort_buffers.push(m_memory);
663+
m_flags &= ~scb_reuse_buffer;
664+
m_owner->releaseBuffer(m_memory);
681665
}
682666
else
683667
delete[] m_memory;
684-
685-
m_flags &= ~scb_reuse_buffer;
686668
}
687669

688670

@@ -2181,6 +2163,53 @@ void Sort::sortRunsBySeek(int n)
21812163
}
21822164

21832165

2166+
/// class SortOwner
2167+
2168+
UCHAR* SortOwner::allocateBuffer()
2169+
{
2170+
if (buffers.hasData())
2171+
return buffers.pop();
2172+
2173+
if (dbb->dbb_sort_buffers.hasData())
2174+
{
2175+
SyncLockGuard guard(&dbb->dbb_sortbuf_sync, SYNC_EXCLUSIVE, FB_FUNCTION);
2176+
2177+
// The sort buffer cache has at least one big block, let's use it
2178+
if (dbb->dbb_sort_buffers.hasData())
2179+
return dbb->dbb_sort_buffers.pop();
2180+
}
2181+
2182+
return nullptr;
2183+
}
2184+
2185+
void SortOwner::releaseBuffer(UCHAR* memory)
2186+
{
2187+
buffers.push(memory);
2188+
}
2189+
2190+
2191+
void SortOwner::unlinkAll()
2192+
{
2193+
while (sorts.getCount())
2194+
delete sorts.pop();
2195+
2196+
if (buffers.hasData())
2197+
{
2198+
// Move cached buffers to the database level cache to be reused later by other attachments
2199+
2200+
const size_t MAX_CACHED_SORT_BUFFERS = 8; // 1MB
2201+
2202+
SyncLockGuard guard(&dbb->dbb_sortbuf_sync, SYNC_EXCLUSIVE, FB_FUNCTION);
2203+
2204+
while (buffers.hasData() && dbb->dbb_sort_buffers.getCount() < MAX_CACHED_SORT_BUFFERS)
2205+
dbb->dbb_sort_buffers.push(buffers.pop());
2206+
}
2207+
2208+
while (buffers.hasData())
2209+
delete[] buffers.pop();
2210+
}
2211+
2212+
21842213
/// class PartitionedSort
21852214

21862215

src/jrd/sort.h

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -389,8 +389,8 @@ class PartitionedSort
389389
class SortOwner
390390
{
391391
public:
392-
explicit SortOwner(MemoryPool& p)
393-
: pool(p), sorts(p)
392+
SortOwner(MemoryPool& p, Database* database)
393+
: pool(p), dbb(database), sorts(p), buffers(p)
394394
{}
395395

396396
~SortOwner()
@@ -426,9 +426,14 @@ class SortOwner
426426
return pool;
427427
}
428428

429+
UCHAR* allocateBuffer();
430+
void releaseBuffer(UCHAR*);
431+
429432
private:
430433
MemoryPool& pool;
434+
Database* const dbb;
431435
Firebird::SortedArray<Sort*> sorts;
436+
Firebird::HalfStaticArray<UCHAR*, 4> buffers;
432437
};
433438

434439
} //namespace Jrd

src/jrd/tra.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -813,8 +813,7 @@ void TRA_init(Jrd::Attachment* attachment)
813813
CHECK_DBB(dbb);
814814

815815
MemoryPool* const pool = dbb->dbb_permanent;
816-
jrd_tra* const trans = FB_NEW_POOL(*pool) jrd_tra(pool, &dbb->dbb_memory_stats, NULL, NULL);
817-
trans->tra_attachment = attachment;
816+
jrd_tra* const trans = FB_NEW_POOL(*pool) jrd_tra(pool, &dbb->dbb_memory_stats, attachment, NULL);
818817
attachment->setSysTransaction(trans);
819818
trans->tra_flags |= TRA_system | TRA_ignore_limbo;
820819
}

src/jrd/tra.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,7 @@ class jrd_tra : public pool_alloc<type_tra>
187187
tra_outer(outer),
188188
tra_snapshot_handle(0),
189189
tra_snapshot_number(0),
190-
tra_sorts(*p),
190+
tra_sorts(*p, attachment->att_database),
191191
tra_gen_ids(NULL),
192192
tra_replicator(NULL),
193193
tra_interface(NULL),

0 commit comments

Comments
 (0)