diff --git a/be/src/olap/tablet_meta.cpp b/be/src/olap/tablet_meta.cpp index c5fdb21479df0c..e83b4c697ec802 100644 --- a/be/src/olap/tablet_meta.cpp +++ b/be/src/olap/tablet_meta.cpp @@ -972,21 +972,21 @@ bool operator!=(const TabletMeta& a, const TabletMeta& b) { return !(a == b); } -DeleteBitmap::DeleteBitmap(int64_t tablet_id) : _tablet_id(tablet_id) { - // The default delete bitmap cache is set to 100MB, - // which can be insufficient and cause performance issues when the amount of user data is large. - // To mitigate the problem of an inadequate cache, - // we will take the larger of 0.5% of the total memory and 100MB as the delete bitmap cache size. - bool is_percent = false; - int64_t delete_bitmap_agg_cache_cache_limit = - ParseUtil::parse_mem_spec(config::delete_bitmap_dynamic_agg_cache_limit, - MemInfo::mem_limit(), MemInfo::physical_mem(), &is_percent); - _agg_cache.reset(new AggCache(delete_bitmap_agg_cache_cache_limit > - config::delete_bitmap_agg_cache_capacity - ? delete_bitmap_agg_cache_cache_limit - : config::delete_bitmap_agg_cache_capacity)); +DeleteBitmapAggCache::DeleteBitmapAggCache(size_t capacity) + : LRUCachePolicyTrackingManual(CachePolicy::CacheType::DELETE_BITMAP_AGG_CACHE, capacity, + LRUCacheType::SIZE, + config::delete_bitmap_agg_cache_stale_sweep_time_sec, 256) {} + +DeleteBitmapAggCache* DeleteBitmapAggCache::instance() { + return ExecEnv::GetInstance()->delete_bitmap_agg_cache(); +} + +DeleteBitmapAggCache* DeleteBitmapAggCache::create_instance(size_t capacity) { + return new DeleteBitmapAggCache(capacity); } +DeleteBitmap::DeleteBitmap(int64_t tablet_id) : _tablet_id(tablet_id) {} + DeleteBitmap::DeleteBitmap(const DeleteBitmap& o) { delete_bitmap = o.delete_bitmap; // just copy data _tablet_id = o._tablet_id; @@ -1201,16 +1201,16 @@ static std::string agg_cache_key(int64_t tablet_id, const DeleteBitmap::BitmapKe std::shared_ptr DeleteBitmap::get_agg(const BitmapKey& bmk) const { std::string key_str = agg_cache_key(_tablet_id, bmk); // Cache key container CacheKey key(key_str); - Cache::Handle* handle = _agg_cache->repr()->lookup(key); + Cache::Handle* handle = DeleteBitmapAggCache::instance()->lookup(key); - AggCache::Value* val = - handle == nullptr - ? nullptr - : reinterpret_cast(_agg_cache->repr()->value(handle)); + DeleteBitmapAggCache::Value* val = + handle == nullptr ? nullptr + : reinterpret_cast( + DeleteBitmapAggCache::instance()->value(handle)); // FIXME: do we need a mutex here to get rid of duplicated initializations // of cache entries in some cases? if (val == nullptr) { // Renew if needed, put a new Value to cache - val = new AggCache::Value(); + val = new DeleteBitmapAggCache::Value(); { std::shared_lock l(lock); DeleteBitmap::BitmapKey start {std::get<0>(bmk), std::get<1>(bmk), 0}; @@ -1223,17 +1223,16 @@ std::shared_ptr DeleteBitmap::get_agg(const BitmapKey& bmk) co val->bitmap |= bm; } } - size_t charge = val->bitmap.getSizeInBytes() + sizeof(AggCache::Value); - handle = _agg_cache->repr()->insert(key, val, charge, charge, CachePriority::NORMAL); + size_t charge = val->bitmap.getSizeInBytes() + sizeof(DeleteBitmapAggCache::Value); + handle = DeleteBitmapAggCache::instance()->insert(key, val, charge, charge, + CachePriority::NORMAL); } // It is natural for the cache to reclaim the underlying memory return std::shared_ptr( - &val->bitmap, [this, handle](...) { _agg_cache->repr()->release(handle); }); + &val->bitmap, [handle](...) { DeleteBitmapAggCache::instance()->release(handle); }); } -std::atomic DeleteBitmap::AggCache::s_repr {nullptr}; - std::string tablet_state_name(TabletState state) { switch (state) { case TABLET_NOTREADY: diff --git a/be/src/olap/tablet_meta.h b/be/src/olap/tablet_meta.h index efc4558f7bbe8e..9b089bb058415c 100644 --- a/be/src/olap/tablet_meta.h +++ b/be/src/olap/tablet_meta.h @@ -339,6 +339,20 @@ class TabletMeta : public MetadataAdder { mutable std::shared_mutex _meta_lock; }; +class DeleteBitmapAggCache : public LRUCachePolicyTrackingManual { +public: + DeleteBitmapAggCache(size_t capacity); + + static DeleteBitmapAggCache* instance(); + + static DeleteBitmapAggCache* create_instance(size_t capacity); + + class Value : public LRUCacheValueBase { + public: + roaring::Roaring bitmap; + }; +}; + /** * Wraps multiple bitmaps for recording rows (row id) that are deleted or * overwritten. For now, it's only used when unique key merge-on-write property @@ -515,45 +529,6 @@ class DeleteBitmap { const std::function& func) const; uint64_t count_key_with_rowset_id_unlocked(const RowsetId& rowset_id) const; - class AggCachePolicy : public LRUCachePolicyTrackingManual { - public: - AggCachePolicy(size_t capacity) - : LRUCachePolicyTrackingManual(CachePolicy::CacheType::DELETE_BITMAP_AGG_CACHE, - capacity, LRUCacheType::SIZE, - config::delete_bitmap_agg_cache_stale_sweep_time_sec, - 256) {} - }; - - class AggCache { - public: - class Value : public LRUCacheValueBase { - public: - roaring::Roaring bitmap; - }; - - AggCache(size_t size_in_bytes) { - static std::once_flag once; - std::call_once(once, [size_in_bytes] { - auto* tmp = new AggCachePolicy(size_in_bytes); - AggCache::s_repr.store(tmp, std::memory_order_release); - - // release the sigleton instance at program exit - std::atexit([] { - auto* ptr = AggCache::s_repr.exchange(nullptr, std::memory_order_acquire); - delete ptr; - }); - }); - - while (!s_repr.load(std::memory_order_acquire)) { - } - } - - static LRUCachePolicy* repr() { return s_repr.load(std::memory_order_acquire); } - static std::atomic s_repr; - }; - -private: - mutable std::shared_ptr _agg_cache; int64_t _tablet_id; }; diff --git a/be/src/runtime/exec_env.h b/be/src/runtime/exec_env.h index 6e97e78768b282..d427444c2f2564 100644 --- a/be/src/runtime/exec_env.h +++ b/be/src/runtime/exec_env.h @@ -112,6 +112,7 @@ class CacheManager; class HeapProfiler; class WalManager; class DNSCache; +class DeleteBitmapAggCache; inline bool k_doris_exit = false; @@ -275,6 +276,7 @@ class ExecEnv { void set_storage_engine(StorageEngine* se) { this->_storage_engine = se; } void set_cache_manager(CacheManager* cm) { this->_cache_manager = cm; } void set_tablet_schema_cache(TabletSchemaCache* c) { this->_tablet_schema_cache = c; } + void set_delete_bitmap_agg_cache(DeleteBitmapAggCache* c) { _delete_bitmap_agg_cache = c; } void set_tablet_column_object_pool(TabletColumnObjectPool* c) { this->_tablet_column_object_pool = c; } @@ -337,6 +339,8 @@ class ExecEnv { orc::MemoryPool* orc_memory_pool() { return _orc_memory_pool; } arrow::MemoryPool* arrow_memory_pool() { return _arrow_memory_pool; } + DeleteBitmapAggCache* delete_bitmap_agg_cache() { return _delete_bitmap_agg_cache; } + private: ExecEnv(); @@ -466,6 +470,7 @@ class ExecEnv { std::shared_ptr _global_block_scheduler; // used for query without workload group std::shared_ptr _without_group_block_scheduler; + DeleteBitmapAggCache* _delete_bitmap_agg_cache {nullptr}; pipeline::RuntimeFilterTimerQueue* _runtime_filter_timer_queue = nullptr; diff --git a/be/src/runtime/exec_env_init.cpp b/be/src/runtime/exec_env_init.cpp index bcb01a6336f2fa..63fafb7534fd24 100644 --- a/be/src/runtime/exec_env_init.cpp +++ b/be/src/runtime/exec_env_init.cpp @@ -46,6 +46,7 @@ #include "olap/segment_loader.h" #include "olap/storage_engine.h" #include "olap/tablet_column_object_pool.h" +#include "olap/tablet_meta.h" #include "olap/tablet_schema_cache.h" #include "olap/wal/wal_manager.h" #include "pipeline/pipeline_tracing.h" @@ -521,6 +522,16 @@ Status ExecEnv::_init_mem_env() { _orc_memory_pool = new doris::vectorized::ORCMemoryPool(); _arrow_memory_pool = new doris::vectorized::ArrowMemoryPool(); + // The default delete bitmap cache is set to 100MB, + // which can be insufficient and cause performance issues when the amount of user data is large. + // To mitigate the problem of an inadequate cache, + // we will take the larger of 0.5% of the total memory and 100MB as the delete bitmap cache size. + int64_t delete_bitmap_agg_cache_cache_limit = + ParseUtil::parse_mem_spec(config::delete_bitmap_dynamic_agg_cache_limit, + MemInfo::mem_limit(), MemInfo::physical_mem(), &is_percent); + _delete_bitmap_agg_cache = DeleteBitmapAggCache::create_instance(std::max( + delete_bitmap_agg_cache_cache_limit, config::delete_bitmap_agg_cache_capacity)); + return Status::OK(); } @@ -633,6 +644,7 @@ void ExecEnv::destroy() { // StorageEngine must be destoried before _page_no_cache_mem_tracker.reset // StorageEngine must be destoried before _cache_manager destory SAFE_DELETE(_storage_engine); + SAFE_DELETE(_delete_bitmap_agg_cache); // Free resource after threads are stopped. // Some threads are still running, like threads created by _new_load_stream_mgr ... diff --git a/be/test/testutil/run_all_tests.cpp b/be/test/testutil/run_all_tests.cpp index 272179fcb8f1bc..776b8dc243db13 100644 --- a/be/test/testutil/run_all_tests.cpp +++ b/be/test/testutil/run_all_tests.cpp @@ -27,6 +27,7 @@ #include "olap/page_cache.h" #include "olap/segment_loader.h" #include "olap/tablet_column_object_pool.h" +#include "olap/tablet_meta.h" #include "olap/tablet_schema_cache.h" #include "runtime/exec_env.h" #include "runtime/memory/cache_manager.h" @@ -57,6 +58,9 @@ int main(int argc, char** argv) { doris::ExecEnv::GetInstance()->set_tablet_schema_cache( doris::TabletSchemaCache::create_global_schema_cache( doris::config::tablet_schema_cache_capacity)); + doris::ExecEnv::GetInstance()->set_delete_bitmap_agg_cache( + doris::DeleteBitmapAggCache::create_instance( + doris::config::delete_bitmap_agg_cache_capacity)); doris::ExecEnv::GetInstance()->set_tablet_column_object_pool( doris::TabletColumnObjectPool::create_global_column_cache( doris::config::tablet_schema_cache_capacity));