diff --git a/src/jrd/idx.cpp b/src/jrd/idx.cpp index 4d29511cc43..98448cbca64 100644 --- a/src/jrd/idx.cpp +++ b/src/jrd/idx.cpp @@ -214,16 +214,16 @@ class IndexCreateTask : public Task IndexCreateTask(thread_db* tdbb, MemoryPool* pool, IndexCreation* creation) : Task(), m_pool(pool), + m_dbb(tdbb->getDatabase()), m_tdbb_flags(tdbb->tdbb_flags), m_flags(0), m_creation(creation), - m_sorts(*m_pool), + m_sorts(*m_pool, m_dbb), m_items(*m_pool), m_stop(false), m_countPP(0), m_nextPP(0) { - m_dbb = tdbb->getDatabase(); Attachment* att = tdbb->getAttachment(); if (att->isGbak()) diff --git a/src/jrd/req.h b/src/jrd/req.h index 59a7d67b738..5ef75176866 100644 --- a/src/jrd/req.h +++ b/src/jrd/req.h @@ -316,7 +316,7 @@ class Request : public pool_alloc req_timeout(0), req_domain_validation(NULL), req_auto_trans(*req_pool), - req_sorts(*req_pool), + req_sorts(*req_pool, attachment->att_database), req_rpb(*req_pool), impureArea(*req_pool) { diff --git a/src/jrd/sort.cpp b/src/jrd/sort.cpp index 5f334323d9d..113ee6cbcf0 100644 --- a/src/jrd/sort.cpp +++ b/src/jrd/sort.cpp @@ -68,12 +68,6 @@ const USHORT MAX_MERGE_LEVEL = 2; using namespace Jrd; using namespace Firebird; -void SortOwner::unlinkAll() -{ - while (sorts.getCount()) - delete sorts.pop(); -} - // The sort buffer size should be just under a multiple of the // hardware memory page size to account for memory allocator // overhead. On most platforms, this saves 4KB to 8KB per sort @@ -165,10 +159,11 @@ Sort::Sort(Database* dbb, FPTR_REJECT_DUP_CALLBACK call_back, void* user_arg, FB_UINT64 max_records) - : m_dbb(dbb), m_last_record(NULL), m_next_pointer(NULL), m_records(0), + : m_dbb(dbb), m_owner(owner), + m_last_record(NULL), m_next_pointer(NULL), m_records(0), m_runs(NULL), m_merge(NULL), m_free_runs(NULL), m_flags(0), m_merge_pool(NULL), - m_description(owner->getPool(), keys) + m_description(m_owner->getPool(), keys) { /************************************** * @@ -185,7 +180,7 @@ Sort::Sort(Database* dbb, * includes index key (which must be unique) and record numbers. * **************************************/ - fb_assert(owner); + fb_assert(m_owner); fb_assert(unique_keys <= keys); try @@ -194,7 +189,7 @@ Sort::Sort(Database* dbb, // key description vector. Round the record length up to the next // longword, and add a longword to a pointer back to the pointer slot. - MemoryPool& pool = owner->getPool(); + MemoryPool& pool = m_owner->getPool(); const ULONG record_size = ROUNDUP(record_length + SIZEOF_SR_BCKPTR, FB_ALIGNMENT); m_longs = record_size >> SHIFTLONG; @@ -248,8 +243,7 @@ Sort::Sort(Database* dbb, // Link in new sort block - m_owner = owner; - owner->linkSort(this); + m_owner->linkSort(this); } catch (const BadAlloc&) { @@ -610,15 +604,12 @@ void Sort::sort(thread_db* tdbb) void Sort::allocateBuffer(MemoryPool& pool) { - if (m_dbb->dbb_sort_buffers.hasData() && m_max_alloc_size <= MAX_SORT_BUFFER_SIZE) + if (m_max_alloc_size <= MAX_SORT_BUFFER_SIZE) { - SyncLockGuard guard(&m_dbb->dbb_sortbuf_sync, SYNC_EXCLUSIVE, "Sort::allocateBuffer"); - - if (m_dbb->dbb_sort_buffers.hasData()) + m_memory = m_owner->allocateBuffer(); + if (m_memory) { - // The sort buffer cache has at least one big block, let's use it m_size_memory = MAX_SORT_BUFFER_SIZE; - m_memory = m_dbb->dbb_sort_buffers.pop(); m_flags |= scb_reuse_buffer; return; } @@ -666,23 +657,14 @@ void Sort::allocateBuffer(MemoryPool& pool) void Sort::releaseBuffer() { - // Here we cache blocks to be reused later, but only the biggest ones - - const size_t MAX_CACHED_SORT_BUFFERS = 8; // 1MB - - SyncLockGuard guard(&m_dbb->dbb_sortbuf_sync, SYNC_EXCLUSIVE, "Sort::releaseBuffer"); - - if ((m_flags & scb_reuse_buffer) && - m_dbb->dbb_sort_buffers.getCount() < MAX_CACHED_SORT_BUFFERS) + if (m_flags & scb_reuse_buffer) { fb_assert(m_size_memory == MAX_SORT_BUFFER_SIZE); - - m_dbb->dbb_sort_buffers.push(m_memory); + m_flags &= ~scb_reuse_buffer; + m_owner->releaseBuffer(m_memory); } else delete[] m_memory; - - m_flags &= ~scb_reuse_buffer; } @@ -2181,6 +2163,53 @@ void Sort::sortRunsBySeek(int n) } +/// class SortOwner + +UCHAR* SortOwner::allocateBuffer() +{ + if (buffers.hasData()) + return buffers.pop(); + + if (dbb->dbb_sort_buffers.hasData()) + { + SyncLockGuard guard(&dbb->dbb_sortbuf_sync, SYNC_EXCLUSIVE, FB_FUNCTION); + + // The sort buffer cache has at least one big block, let's use it + if (dbb->dbb_sort_buffers.hasData()) + return dbb->dbb_sort_buffers.pop(); + } + + return nullptr; +} + +void SortOwner::releaseBuffer(UCHAR* memory) +{ + buffers.push(memory); +} + + +void SortOwner::unlinkAll() +{ + while (sorts.getCount()) + delete sorts.pop(); + + if (buffers.hasData()) + { + // Move cached buffers to the database level cache to be reused later by other attachments + + const size_t MAX_CACHED_SORT_BUFFERS = 8; // 1MB + + SyncLockGuard guard(&dbb->dbb_sortbuf_sync, SYNC_EXCLUSIVE, FB_FUNCTION); + + while (buffers.hasData() && dbb->dbb_sort_buffers.getCount() < MAX_CACHED_SORT_BUFFERS) + dbb->dbb_sort_buffers.push(buffers.pop()); + } + + while (buffers.hasData()) + delete[] buffers.pop(); +} + + /// class PartitionedSort diff --git a/src/jrd/sort.h b/src/jrd/sort.h index 8089697f16a..0b00b9b7ed7 100644 --- a/src/jrd/sort.h +++ b/src/jrd/sort.h @@ -389,8 +389,8 @@ class PartitionedSort class SortOwner { public: - explicit SortOwner(MemoryPool& p) - : pool(p), sorts(p) + SortOwner(MemoryPool& p, Database* database) + : pool(p), dbb(database), sorts(p), buffers(p) {} ~SortOwner() @@ -426,9 +426,14 @@ class SortOwner return pool; } + UCHAR* allocateBuffer(); + void releaseBuffer(UCHAR*); + private: MemoryPool& pool; + Database* const dbb; Firebird::SortedArray sorts; + Firebird::HalfStaticArray buffers; }; } //namespace Jrd diff --git a/src/jrd/tra.cpp b/src/jrd/tra.cpp index c97d85fa398..1e6b532f87a 100644 --- a/src/jrd/tra.cpp +++ b/src/jrd/tra.cpp @@ -813,8 +813,7 @@ void TRA_init(Jrd::Attachment* attachment) CHECK_DBB(dbb); MemoryPool* const pool = dbb->dbb_permanent; - jrd_tra* const trans = FB_NEW_POOL(*pool) jrd_tra(pool, &dbb->dbb_memory_stats, NULL, NULL); - trans->tra_attachment = attachment; + jrd_tra* const trans = FB_NEW_POOL(*pool) jrd_tra(pool, &dbb->dbb_memory_stats, attachment, NULL); attachment->setSysTransaction(trans); trans->tra_flags |= TRA_system | TRA_ignore_limbo; } diff --git a/src/jrd/tra.h b/src/jrd/tra.h index cd577f94e12..1b2111c5d2d 100644 --- a/src/jrd/tra.h +++ b/src/jrd/tra.h @@ -187,7 +187,7 @@ class jrd_tra : public pool_alloc tra_outer(outer), tra_snapshot_handle(0), tra_snapshot_number(0), - tra_sorts(*p), + tra_sorts(*p, attachment->att_database), tra_gen_ids(NULL), tra_replicator(NULL), tra_interface(NULL),