This is an automated email from the ASF dual-hosted git repository.

dataroaring pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/doris.git


The following commit(s) were added to refs/heads/master by this push:
     new 2ac0f861abd [Opt](mow) Opt mow load performance and CPU usage (#55073)
2ac0f861abd is described below

commit 2ac0f861abdd5dee1f821d50e788aa3eebed8e73
Author: bobhan1 <[email protected]>
AuthorDate: Fri Sep 5 21:54:46 2025 +0800

    [Opt](mow) Opt mow load performance and CPU usage (#55073)
    
    ### What problem does this PR solve?
    
    This PR let mow load use delete bitmap cache if possible when lookup row
    key to reduce CPU usage.
    
    Add 2 configs
    
`enable_prefill_output_dbm_agg_cache_after_compaction`/`enable_prefill_all_dbm_agg_cache_after_compaction`(default
    true) to control whether to fresh delete bitmap cache on corresponding
    rowsets after compaction.
    
    ### Release note
    
    None
    
    ### Check List (For Author)
    
    - Test <!-- At least one of them must be included. -->
        - [ ] Regression test
        - [ ] Unit Test
        - [ ] Manual test (add detailed scripts or steps below)
        - [ ] No need to test or manual test. Explain why:
    - [ ] This is a refactor/code format and no logic has been changed.
            - [ ] Previous test can cover this change.
            - [ ] No code files have been changed.
            - [ ] Other reason <!-- Add your reason?  -->
    
    - Behavior changed:
        - [ ] No.
        - [ ] Yes. <!-- Explain the behavior change -->
    
    - Does this need documentation?
        - [ ] No.
    - [ ] Yes. <!-- Add document PR link here. eg:
    https://github.com/apache/doris-website/pull/1214 -->
    
    ### Check List (For Reviewer who merge this PR)
    
    - [ ] Confirm the release note
    - [ ] Confirm test cases
    - [ ] Confirm document
    - [ ] Add branch pick label <!-- Add branch pick label that this PR
    should merge into -->
---
 be/src/cloud/cloud_base_compaction.cpp             |   1 +
 be/src/cloud/cloud_cumulative_compaction.cpp       |   2 +
 be/src/cloud/cloud_full_compaction.cpp             |   1 +
 be/src/common/config.cpp                           |   3 +
 be/src/common/config.h                             |   3 +
 be/src/http/action/delete_bitmap_action.cpp        |  26 ++++
 be/src/http/action/delete_bitmap_action.h          |   3 +-
 be/src/olap/base_tablet.cpp                        |  27 ++++-
 be/src/olap/base_tablet.h                          |   3 +
 be/src/olap/compaction.cpp                         |   1 +
 be/src/olap/full_compaction.cpp                    |   2 +
 be/src/olap/lru_cache.cpp                          |  16 +++
 be/src/olap/lru_cache.h                            |   5 +
 be/src/olap/tablet_meta.cpp                        | 133 ++++++++++++++++++---
 be/src/olap/tablet_meta.h                          |   6 +-
 be/src/runtime/memory/lru_cache_policy.h           |   4 +
 be/src/service/http_service.cpp                    |  10 ++
 .../pipeline/cloud_p0/conf/be_custom.conf          |   2 +
 .../pipeline/cloud_p1/conf/be_custom.conf          |   1 +
 regression-test/pipeline/p0/conf/be.conf           |   1 +
 regression-test/pipeline/p1/conf/be.conf           |   2 +
 .../metrics_p0/test_delete_bitmap_metrics.groovy   |  31 +++++
 22 files changed, 262 insertions(+), 21 deletions(-)

diff --git a/be/src/cloud/cloud_base_compaction.cpp 
b/be/src/cloud/cloud_base_compaction.cpp
index 7c27e91007d..79ebe1b3712 100644
--- a/be/src/cloud/cloud_base_compaction.cpp
+++ b/be/src/cloud/cloud_base_compaction.cpp
@@ -435,6 +435,7 @@ Status CloudBaseCompaction::modify_rowsets() {
                                                     stats.num_rows(), 
stats.data_size());
         }
     }
+    _tablet->prefill_dbm_agg_cache_after_compaction(_output_rowset);
     return Status::OK();
 }
 
diff --git a/be/src/cloud/cloud_cumulative_compaction.cpp 
b/be/src/cloud/cloud_cumulative_compaction.cpp
index d5e6373d64a..4c587ea3bca 100644
--- a/be/src/cloud/cloud_cumulative_compaction.cpp
+++ b/be/src/cloud/cloud_cumulative_compaction.cpp
@@ -435,6 +435,8 @@ Status CloudCumulativeCompaction::modify_rowsets() {
         LOG(INFO) << "delete_expired_stale_rowsets for tablet=" << 
_tablet->tablet_id();
         _engine.tablet_mgr().vacuum_stale_rowsets(CountDownLatch(1));
     });
+
+    _tablet->prefill_dbm_agg_cache_after_compaction(_output_rowset);
     return Status::OK();
 }
 
diff --git a/be/src/cloud/cloud_full_compaction.cpp 
b/be/src/cloud/cloud_full_compaction.cpp
index 1102d218001..382360bed3a 100644
--- a/be/src/cloud/cloud_full_compaction.cpp
+++ b/be/src/cloud/cloud_full_compaction.cpp
@@ -287,6 +287,7 @@ Status CloudFullCompaction::modify_rowsets() {
                                                     stats.num_rows(), 
stats.data_size());
         }
     }
+    _tablet->prefill_dbm_agg_cache_after_compaction(_output_rowset);
     return Status::OK();
 }
 
diff --git a/be/src/common/config.cpp b/be/src/common/config.cpp
index 87739425663..f777d25c7f5 100644
--- a/be/src/common/config.cpp
+++ b/be/src/common/config.cpp
@@ -1589,6 +1589,9 @@ DEFINE_mInt32(omp_threads_limit, "8");
 // The capacity of segment partial column cache, used to cache column readers 
for each segment.
 DEFINE_mInt32(max_segment_partial_column_cache_size, "100");
 
+DEFINE_mBool(enable_prefill_output_dbm_agg_cache_after_compaction, "true");
+DEFINE_mBool(enable_prefill_all_dbm_agg_cache_after_compaction, "true");
+
 // clang-format off
 #ifdef BE_TEST
 // test s3
diff --git a/be/src/common/config.h b/be/src/common/config.h
index 8df5226ee3c..01ebefd833b 100644
--- a/be/src/common/config.h
+++ b/be/src/common/config.h
@@ -1643,6 +1643,9 @@ DECLARE_Int32(omp_threads_limit);
 // The capacity of segment partial column cache, used to cache column readers 
for each segment.
 DECLARE_mInt32(max_segment_partial_column_cache_size);
 
+DECLARE_mBool(enable_prefill_output_dbm_agg_cache_after_compaction);
+DECLARE_mBool(enable_prefill_all_dbm_agg_cache_after_compaction);
+
 #ifdef BE_TEST
 // test s3
 DECLARE_String(test_s3_resource);
diff --git a/be/src/http/action/delete_bitmap_action.cpp 
b/be/src/http/action/delete_bitmap_action.cpp
index fff120674e0..581da9204ac 100644
--- a/be/src/http/action/delete_bitmap_action.cpp
+++ b/be/src/http/action/delete_bitmap_action.cpp
@@ -198,6 +198,32 @@ Status 
DeleteBitmapAction::_handle_show_ms_delete_bitmap_count(HttpRequest* req,
     return Status::OK();
 }
 
+Status 
DeleteBitmapAction::_handle_show_agg_cache_delete_bitmap_count(HttpRequest* req,
+                                                                      
std::string* json_result) {
+    uint64_t tablet_id = 0;
+    bool verbose = false;
+    RETURN_NOT_OK_STATUS_WITH_WARN(_check_param(req, &tablet_id, &verbose), 
"check param failed");
+    BaseTabletSPtr tablet = nullptr;
+    if (config::is_cloud_mode()) {
+        tablet = 
DORIS_TRY(_engine.to_cloud().tablet_mgr().get_tablet(tablet_id));
+        DBUG_EXECUTE_IF(
+                
"DeleteBitmapAction._handle_show_local_delete_bitmap_count.vacuum_stale_rowsets",
+                { 
_engine.to_cloud().tablet_mgr().vacuum_stale_rowsets(CountDownLatch(1)); });
+    } else {
+        tablet = _engine.to_local().tablet_manager()->get_tablet(tablet_id);
+        DBUG_EXECUTE_IF(
+                
"DeleteBitmapAction._handle_show_local_delete_bitmap_count.start_delete_unused_"
+                "rowset",
+                { _engine.to_local().start_delete_unused_rowset(); });
+    }
+    if (tablet == nullptr) {
+        return Status::NotFound("Tablet not found. tablet_id={}", tablet_id);
+    }
+    auto dbm = tablet->tablet_meta()->delete_bitmap().agg_cache_snapshot();
+    _show_delete_bitmap(dbm, verbose, json_result);
+    return Status::OK();
+}
+
 void DeleteBitmapAction::handle(HttpRequest* req) {
     req->add_output_header(HttpHeaders::CONTENT_TYPE, HEADER_JSON.data());
     if (_delete_bitmap_action_type == DeleteBitmapActionType::COUNT_LOCAL) {
diff --git a/be/src/http/action/delete_bitmap_action.h 
b/be/src/http/action/delete_bitmap_action.h
index 284e8dbcf57..db3ab3bcd89 100644
--- a/be/src/http/action/delete_bitmap_action.h
+++ b/be/src/http/action/delete_bitmap_action.h
@@ -32,7 +32,7 @@ class HttpRequest;
 
 class ExecEnv;
 
-enum class DeleteBitmapActionType { COUNT_LOCAL = 1, COUNT_MS = 2 };
+enum class DeleteBitmapActionType { COUNT_LOCAL = 1, COUNT_MS = 2, 
COUNT_AGG_CACHE = 3 };
 
 /// This action is used for viewing the delete bitmap status
 class DeleteBitmapAction : public HttpHandlerWithAuth {
@@ -47,6 +47,7 @@ public:
 private:
     Status _handle_show_local_delete_bitmap_count(HttpRequest* req, 
std::string* json_result);
     Status _handle_show_ms_delete_bitmap_count(HttpRequest* req, std::string* 
json_result);
+    Status _handle_show_agg_cache_delete_bitmap_count(HttpRequest* req, 
std::string* json_result);
 
 private:
     BaseStorageEngine& _engine;
diff --git a/be/src/olap/base_tablet.cpp b/be/src/olap/base_tablet.cpp
index 1d424cbb023..11372f0a79c 100644
--- a/be/src/olap/base_tablet.cpp
+++ b/be/src/olap/base_tablet.cpp
@@ -496,7 +496,7 @@ Status BaseTablet::lookup_row_key(const Slice& encoded_key, 
TabletSchema* latest
             if (!s.ok() && !s.is<KEY_ALREADY_EXISTS>()) {
                 return s;
             }
-            if (s.ok() && tablet_delete_bitmap->contains_agg_without_cache(
+            if (s.ok() && 
tablet_delete_bitmap->contains_agg_with_cache_if_eligible(
                                   {loc.rowset_id, loc.segment_id, version}, 
loc.row_id)) {
                 // if has sequence col, we continue to compare the sequence_id 
of
                 // all rowsets, util we find an existing key.
@@ -2150,4 +2150,29 @@ int32_t BaseTablet::max_version_config() {
     return max_version;
 }
 
+void BaseTablet::prefill_dbm_agg_cache(const RowsetSharedPtr& rowset, int64_t 
version) {
+    for (std::size_t i = 0; i < rowset->num_segments(); i++) {
+        tablet_meta()->delete_bitmap().get_agg({rowset->rowset_id(), i, 
version});
+    }
+}
+
+void BaseTablet::prefill_dbm_agg_cache_after_compaction(const RowsetSharedPtr& 
output_rowset) {
+    if (keys_type() == KeysType::UNIQUE_KEYS && 
enable_unique_key_merge_on_write() &&
+        (config::enable_prefill_output_dbm_agg_cache_after_compaction ||
+         config::enable_prefill_all_dbm_agg_cache_after_compaction)) {
+        int64_t cur_max_version {-1};
+        {
+            std::shared_lock rlock(get_header_lock());
+            cur_max_version = max_version_unlocked();
+        }
+        if (config::enable_prefill_all_dbm_agg_cache_after_compaction) {
+            traverse_rowsets(
+                    [&](const RowsetSharedPtr& rs) { prefill_dbm_agg_cache(rs, 
cur_max_version); },
+                    false);
+        } else if 
(config::enable_prefill_output_dbm_agg_cache_after_compaction) {
+            prefill_dbm_agg_cache(output_rowset, cur_max_version);
+        }
+    }
+}
+
 } // namespace doris
diff --git a/be/src/olap/base_tablet.h b/be/src/olap/base_tablet.h
index 1d3eb7d5060..c33e00ba3c5 100644
--- a/be/src/olap/base_tablet.h
+++ b/be/src/olap/base_tablet.h
@@ -322,6 +322,9 @@ public:
         return Status::OK();
     }
 
+    void prefill_dbm_agg_cache(const RowsetSharedPtr& rowset, int64_t version);
+    void prefill_dbm_agg_cache_after_compaction(const RowsetSharedPtr& 
output_rowset);
+
 protected:
     // Find the missed versions until the spec_version.
     //
diff --git a/be/src/olap/compaction.cpp b/be/src/olap/compaction.cpp
index 3fbd59b41a3..31255cfb62c 100644
--- a/be/src/olap/compaction.cpp
+++ b/be/src/olap/compaction.cpp
@@ -1348,6 +1348,7 @@ Status CompactionMixin::modify_rowsets() {
     }
     
DBUG_EXECUTE_IF("CumulativeCompaction.modify_rowsets.delete_expired_stale_rowset",
                     { tablet()->delete_expired_stale_rowset(); });
+    _tablet->prefill_dbm_agg_cache_after_compaction(_output_rowset);
     return Status::OK();
 }
 
diff --git a/be/src/olap/full_compaction.cpp b/be/src/olap/full_compaction.cpp
index 2994830eb23..9f2c746ac92 100644
--- a/be/src/olap/full_compaction.cpp
+++ b/be/src/olap/full_compaction.cpp
@@ -173,6 +173,8 @@ Status FullCompaction::modify_rowsets() {
         DBUG_EXECUTE_IF("FullCompaction.modify_rowsets.sleep", { sleep(5); })
         tablet()->save_meta();
     }
+
+    _tablet->prefill_dbm_agg_cache_after_compaction(_output_rowset);
     return Status::OK();
 }
 
diff --git a/be/src/olap/lru_cache.cpp b/be/src/olap/lru_cache.cpp
index 3276b728da7..8e885f02324 100644
--- a/be/src/olap/lru_cache.cpp
+++ b/be/src/olap/lru_cache.cpp
@@ -630,6 +630,16 @@ PrunedInfo LRUCache::prune_if(CachePrunePredicate pred, 
bool lazy_mode) {
     return {pruned_count, pruned_size};
 }
 
+void LRUCache::for_each_entry(const std::function<void(const LRUHandle*)>& 
visitor) {
+    std::lock_guard l(_mutex);
+    for (LRUHandle* p = _lru_normal.next; p != &_lru_normal; p = p->next) {
+        visitor(p);
+    }
+    for (LRUHandle* p = _lru_durable.next; p != &_lru_durable; p = p->next) {
+        visitor(p);
+    }
+}
+
 void LRUCache::set_cache_value_time_extractor(CacheValueTimeExtractor 
cache_value_time_extractor) {
     _cache_value_time_extractor = cache_value_time_extractor;
 }
@@ -777,6 +787,12 @@ PrunedInfo ShardedLRUCache::prune_if(CachePrunePredicate 
pred, bool lazy_mode) {
     return pruned_info;
 }
 
+void ShardedLRUCache::for_each_entry(const std::function<void(const 
LRUHandle*)>& visitor) {
+    for (int s = 0; s < _num_shards; s++) {
+        _shards[s]->for_each_entry(visitor);
+    }
+}
+
 int64_t ShardedLRUCache::get_usage() {
     size_t total_usage = 0;
     for (int i = 0; i < _num_shards; i++) {
diff --git a/be/src/olap/lru_cache.h b/be/src/olap/lru_cache.h
index d4f8b905faa..9b0f08fb312 100644
--- a/be/src/olap/lru_cache.h
+++ b/be/src/olap/lru_cache.h
@@ -207,6 +207,8 @@ public:
     // may hold lock for a long time to execute predicate.
     virtual PrunedInfo prune_if(CachePrunePredicate pred, bool lazy_mode = 
false) { return {0, 0}; }
 
+    virtual void for_each_entry(const std::function<void(const LRUHandle*)>& 
visitor) = 0;
+
     virtual int64_t get_usage() = 0;
 
     virtual PrunedInfo set_capacity(size_t capacity) = 0;
@@ -333,6 +335,7 @@ public:
     void erase(const CacheKey& key, uint32_t hash);
     PrunedInfo prune();
     PrunedInfo prune_if(CachePrunePredicate pred, bool lazy_mode = false);
+    void for_each_entry(const std::function<void(const LRUHandle*)>& visitor);
 
     void set_cache_value_time_extractor(CacheValueTimeExtractor 
cache_value_time_extractor);
     void set_cache_value_check_timestamp(bool cache_value_check_timestamp);
@@ -406,6 +409,7 @@ public:
     uint64_t new_id() override;
     PrunedInfo prune() override;
     PrunedInfo prune_if(CachePrunePredicate pred, bool lazy_mode = false) 
override;
+    void for_each_entry(const std::function<void(const LRUHandle*)>& visitor) 
override;
     int64_t get_usage() override;
     size_t get_element_count() override;
     PrunedInfo set_capacity(size_t capacity) override;
@@ -471,6 +475,7 @@ public:
     PrunedInfo prune_if(CachePrunePredicate pred, bool lazy_mode = false) 
override {
         return {0, 0};
     };
+    void for_each_entry(const std::function<void(const LRUHandle*)>& visitor) 
override {}
     int64_t get_usage() override { return 0; };
     PrunedInfo set_capacity(size_t capacity) override { return {0, 0}; };
     size_t get_capacity() override { return 0; };
diff --git a/be/src/olap/tablet_meta.cpp b/be/src/olap/tablet_meta.cpp
index f87d5b4d661..2e23df028ff 100644
--- a/be/src/olap/tablet_meta.cpp
+++ b/be/src/olap/tablet_meta.cpp
@@ -17,6 +17,7 @@
 
 #include "olap/tablet_meta.h"
 
+#include <bvar/bvar.h>
 #include <gen_cpp/Descriptors_types.h>
 #include <gen_cpp/FrontendService_types.h>
 #include <gen_cpp/Types_types.h>
@@ -41,6 +42,7 @@
 #include "io/fs/local_file_system.h"
 #include "olap/data_dir.h"
 #include "olap/file_header.h"
+#include "olap/lru_cache.h"
 #include "olap/olap_common.h"
 #include "olap/olap_define.h"
 #include "olap/rowset/rowset.h"
@@ -64,6 +66,22 @@ namespace doris {
 #include "common/compile_check_begin.h"
 using namespace ErrorCode;
 
+bvar::Adder<uint64_t> g_contains_agg_with_cache_if_eligible_total(
+        "g_contains_agg_with_cache_if_eligible_total");
+bvar::Adder<uint64_t> g_contains_agg_with_cache_if_eligible_partial_hit(
+        "g_contains_agg_with_cache_if_eligible_partial_hit");
+bvar::Adder<uint64_t> g_contains_agg_with_cache_if_eligible_full_hit(
+        "g_contains_agg_with_cache_if_eligible_full_hit");
+bvar::Window<bvar::Adder<uint64_t>> 
g_contains_agg_with_cache_if_eligible_total_minute(
+        "g_contains_agg_with_cache_if_eligible_total_1m",
+        &g_contains_agg_with_cache_if_eligible_total, 60);
+bvar::Window<bvar::Adder<uint64_t>> 
g_contains_agg_with_cache_if_eligible_partial_hit_minute(
+        "g_contains_agg_with_cache_if_eligible_partial_hit_1m",
+        &g_contains_agg_with_cache_if_eligible_partial_hit, 60);
+bvar::Window<bvar::Adder<uint64_t>> 
g_contains_agg_with_cache_if_eligible_full_hit_minute(
+        "g_contains_agg_with_cache_if_eligible_full_hit_1m",
+        &g_contains_agg_with_cache_if_eligible_full_hit, 60);
+
 TabletMetaSharedPtr TabletMeta::create(
         const TCreateTabletReq& request, const TabletUid& tablet_uid, uint64_t 
shard_id,
         uint32_t next_unique_id,
@@ -1152,6 +1170,39 @@ bool operator!=(const TabletMeta& a, const TabletMeta& 
b) {
     return !(a == b);
 }
 
+// We cannot just copy the underlying memory to construct a string
+// due to equivalent objects may have different padding bytes.
+// Reading padding bytes is undefined behavior, neither copy nor
+// placement new will help simplify the code.
+// Refer to C11 standards §6.2.6.1/6 and §6.7.9/21 for more info.
+static std::string agg_cache_key(int64_t tablet_id, const 
DeleteBitmap::BitmapKey& bmk) {
+    std::string ret(sizeof(tablet_id) + sizeof(bmk), '\0');
+    *reinterpret_cast<int64_t*>(ret.data()) = tablet_id;
+    auto t = reinterpret_cast<DeleteBitmap::BitmapKey*>(ret.data() + 
sizeof(tablet_id));
+    std::get<RowsetId>(*t).version = std::get<RowsetId>(bmk).version;
+    std::get<RowsetId>(*t).hi = std::get<RowsetId>(bmk).hi;
+    std::get<RowsetId>(*t).mi = std::get<RowsetId>(bmk).mi;
+    std::get<RowsetId>(*t).lo = std::get<RowsetId>(bmk).lo;
+    std::get<1>(*t) = std::get<1>(bmk);
+    std::get<2>(*t) = std::get<2>(bmk);
+    return ret;
+}
+
+// decode cache key info from a agg_cache_key
+static void decode_agg_cache_key(const std::string& key_str, int64_t& 
tablet_id,
+                                 DeleteBitmap::BitmapKey& bmk) {
+    const char* ptr = key_str.data();
+    tablet_id = *reinterpret_cast<const int64_t*>(ptr);
+    ptr += sizeof(tablet_id);
+    auto* t = 
reinterpret_cast<DeleteBitmap::BitmapKey*>(const_cast<char*>(ptr));
+    std::get<RowsetId>(bmk).version = std::get<RowsetId>(*t).version;
+    std::get<RowsetId>(bmk).hi = std::get<RowsetId>(*t).hi;
+    std::get<RowsetId>(bmk).mi = std::get<RowsetId>(*t).mi;
+    std::get<RowsetId>(bmk).lo = std::get<RowsetId>(*t).lo;
+    std::get<1>(bmk) = std::get<1>(*t);
+    std::get<2>(bmk) = std::get<2>(*t);
+}
+
 DeleteBitmapAggCache::DeleteBitmapAggCache(size_t capacity)
         : LRUCachePolicy(CachePolicy::CacheType::DELETE_BITMAP_AGG_CACHE, 
capacity,
                          LRUCacheType::SIZE, 
config::delete_bitmap_agg_cache_stale_sweep_time_sec,
@@ -1165,6 +1216,22 @@ DeleteBitmapAggCache* 
DeleteBitmapAggCache::create_instance(size_t capacity) {
     return new DeleteBitmapAggCache(capacity);
 }
 
+DeleteBitmap DeleteBitmapAggCache::snapshot(int64_t tablet_id) {
+    DeleteBitmap ret(tablet_id);
+    auto collector = [&](const LRUHandle* handle) {
+        auto key = handle->key().to_string();
+        int64_t key_tablet_id;
+        DeleteBitmap::BitmapKey bmk;
+        decode_agg_cache_key(key, key_tablet_id, bmk);
+        if (key_tablet_id == tablet_id) {
+            const auto& dbm = 
reinterpret_cast<DeleteBitmapAggCache::Value*>(handle->value)->bitmap;
+            ret.set(bmk, dbm);
+        }
+    };
+    DeleteBitmapAggCache::instance()->for_each_entry(collector);
+    return ret;
+}
+
 DeleteBitmap::DeleteBitmap(int64_t tablet_id) : _tablet_id(tablet_id) {}
 
 DeleteBitmap::DeleteBitmap(const DeleteBitmap& o) {
@@ -1298,9 +1365,53 @@ uint64_t DeleteBitmap::get_size() const {
     return charge;
 }
 
-bool DeleteBitmap::contains_agg_without_cache(const BitmapKey& bmk, uint32_t 
row_id) const {
+bool DeleteBitmap::contains_agg_with_cache_if_eligible(const BitmapKey& bmk,
+                                                       uint32_t row_id) const {
+    g_contains_agg_with_cache_if_eligible_total << 1;
+    int64_t start_version {0};
+    if (config::enable_mow_get_agg_by_cache) {
+        auto deleter = [&](Cache::Handle* handle) {
+            DeleteBitmapAggCache::instance()->release(handle);
+        };
+        std::unique_ptr<Cache::Handle, decltype(deleter)> dbm_handle(nullptr, 
deleter);
+        int64_t cached_version = 0;
+        // 1. try to lookup the desired key directly
+        
dbm_handle.reset(DeleteBitmapAggCache::instance()->lookup(agg_cache_key(_tablet_id,
 bmk)));
+        if (dbm_handle != nullptr) {
+            cached_version = std::get<2>(bmk);
+        } else {
+            // 2. if not found, try to lookup with cached version
+            cached_version = _get_rowset_cache_version(bmk);
+            if (cached_version > 0) {
+                if (cached_version > std::get<2>(bmk)) {
+                    cached_version = 0;
+                } else {
+                    
dbm_handle.reset(DeleteBitmapAggCache::instance()->lookup(agg_cache_key(
+                            _tablet_id, {std::get<0>(bmk), std::get<1>(bmk), 
cached_version})));
+                }
+            }
+        }
+        if (dbm_handle != nullptr) {
+            const auto& cached_dbm =
+                    reinterpret_cast<DeleteBitmapAggCache::Value*>(
+                            
DeleteBitmapAggCache::instance()->value(dbm_handle.get()))
+                            ->bitmap;
+            if (cached_version == std::get<2>(bmk)) {
+                g_contains_agg_with_cache_if_eligible_full_hit << 1;
+            } else {
+                g_contains_agg_with_cache_if_eligible_partial_hit << 1;
+            }
+            if (cached_dbm.contains(row_id)) {
+                return true;
+            }
+            if (cached_version == std::get<2>(bmk)) {
+                return false;
+            }
+            start_version = cached_version + 1;
+        }
+    }
+    DeleteBitmap::BitmapKey start {std::get<0>(bmk), std::get<1>(bmk), 
start_version};
     std::shared_lock l(lock);
-    DeleteBitmap::BitmapKey start {std::get<0>(bmk), std::get<1>(bmk), 0};
     for (auto it = delete_bitmap.lower_bound(start); it != 
delete_bitmap.end(); ++it) {
         auto& [k, bm] = *it;
         if (std::get<0>(k) != std::get<0>(bmk) || std::get<1>(k) != 
std::get<1>(bmk) ||
@@ -1503,22 +1614,8 @@ DeleteBitmap::Version 
DeleteBitmap::_get_rowset_cache_version(const BitmapKey& b
     return 0;
 }
 
-// We cannot just copy the underlying memory to construct a string
-// due to equivalent objects may have different padding bytes.
-// Reading padding bytes is undefined behavior, neither copy nor
-// placement new will help simplify the code.
-// Refer to C11 standards §6.2.6.1/6 and §6.7.9/21 for more info.
-static std::string agg_cache_key(int64_t tablet_id, const 
DeleteBitmap::BitmapKey& bmk) {
-    std::string ret(sizeof(tablet_id) + sizeof(bmk), '\0');
-    *reinterpret_cast<int64_t*>(ret.data()) = tablet_id;
-    auto t = reinterpret_cast<DeleteBitmap::BitmapKey*>(ret.data() + 
sizeof(tablet_id));
-    std::get<RowsetId>(*t).version = std::get<RowsetId>(bmk).version;
-    std::get<RowsetId>(*t).hi = std::get<RowsetId>(bmk).hi;
-    std::get<RowsetId>(*t).mi = std::get<RowsetId>(bmk).mi;
-    std::get<RowsetId>(*t).lo = std::get<RowsetId>(bmk).lo;
-    std::get<1>(*t) = std::get<1>(bmk);
-    std::get<2>(*t) = std::get<2>(bmk);
-    return ret;
+DeleteBitmap DeleteBitmap::agg_cache_snapshot() {
+    return DeleteBitmapAggCache::instance()->snapshot(_tablet_id);
 }
 
 std::shared_ptr<roaring::Roaring> DeleteBitmap::get_agg(const BitmapKey& bmk) 
const {
diff --git a/be/src/olap/tablet_meta.h b/be/src/olap/tablet_meta.h
index c2272d3caf6..5d7690c3973 100644
--- a/be/src/olap/tablet_meta.h
+++ b/be/src/olap/tablet_meta.h
@@ -380,6 +380,8 @@ public:
 
     static DeleteBitmapAggCache* create_instance(size_t capacity);
 
+    DeleteBitmap snapshot(int64_t tablet_id);
+
     class Value : public LRUCacheValueBase {
     public:
         roaring::Roaring bitmap;
@@ -571,7 +573,7 @@ public:
      */
     bool contains_agg(const BitmapKey& bitmap, uint32_t row_id) const;
 
-    bool contains_agg_without_cache(const BitmapKey& bmk, uint32_t row_id) 
const;
+    bool contains_agg_with_cache_if_eligible(const BitmapKey& bmk, uint32_t 
row_id) const;
     /**
      * Gets aggregated delete_bitmap on rowset_id and version, the same effect:
      * `select sum(roaring::Roaring) where RowsetId=rowset_id and 
SegmentId=seg_id and Version <= version`
@@ -598,6 +600,8 @@ public:
 
     std::set<std::string> get_rowset_cache_version();
 
+    DeleteBitmap agg_cache_snapshot();
+
 private:
     DeleteBitmap::Version _get_rowset_cache_version(const BitmapKey& bmk) 
const;
 
diff --git a/be/src/runtime/memory/lru_cache_policy.h 
b/be/src/runtime/memory/lru_cache_policy.h
index 0df35c52339..7aa0b746715 100644
--- a/be/src/runtime/memory/lru_cache_policy.h
+++ b/be/src/runtime/memory/lru_cache_policy.h
@@ -131,6 +131,10 @@ public:
         return _cache->insert(key, value, charge, priority);
     }
 
+    void for_each_entry(const std::function<void(const LRUHandle*)>& visitor) {
+        _cache->for_each_entry(visitor);
+    }
+
     Cache::Handle* lookup(const CacheKey& key) { return _cache->lookup(key); }
 
     void release(Cache::Handle* handle) { _cache->release(handle); }
diff --git a/be/src/service/http_service.cpp b/be/src/service/http_service.cpp
index 43a69dcfb88..63a5ea5b8dc 100644
--- a/be/src/service/http_service.cpp
+++ b/be/src/service/http_service.cpp
@@ -412,6 +412,11 @@ void HttpService::register_local_handler(StorageEngine& 
engine) {
                                              TPrivilegeHier::GLOBAL, 
TPrivilegeType::ADMIN));
     _ev_http_server->register_handler(HttpMethod::GET, 
"/api/delete_bitmap/count_local",
                                       count_delete_bitmap_action);
+    DeleteBitmapAction* count_agg_cache_delete_bitmap_action =
+            _pool.add(new 
DeleteBitmapAction(DeleteBitmapActionType::COUNT_AGG_CACHE, _env, engine,
+                                             TPrivilegeHier::GLOBAL, 
TPrivilegeType::ADMIN));
+    _ev_http_server->register_handler(HttpMethod::GET, 
"/api/delete_bitmap/count_agg_cache",
+                                      count_agg_cache_delete_bitmap_action);
 
     CheckTabletSegmentAction* check_tablet_segment_action = _pool.add(new 
CheckTabletSegmentAction(
             _env, engine, TPrivilegeHier::GLOBAL, TPrivilegeType::ADMIN));
@@ -471,6 +476,11 @@ void 
HttpService::register_cloud_handler(CloudStorageEngine& engine) {
                                              TPrivilegeHier::GLOBAL, 
TPrivilegeType::ADMIN));
     _ev_http_server->register_handler(HttpMethod::GET, 
"/api/delete_bitmap/count_ms",
                                       count_ms_delete_bitmap_action);
+    DeleteBitmapAction* count_agg_cache_delete_bitmap_action =
+            _pool.add(new 
DeleteBitmapAction(DeleteBitmapActionType::COUNT_AGG_CACHE, _env, engine,
+                                             TPrivilegeHier::GLOBAL, 
TPrivilegeType::ADMIN));
+    _ev_http_server->register_handler(HttpMethod::GET, 
"/api/delete_bitmap/count_agg_cache",
+                                      count_agg_cache_delete_bitmap_action);
 #ifdef ENABLE_INJECTION_POINT
     InjectionPointAction* injection_point_action = _pool.add(new 
InjectionPointAction);
     _ev_http_server->register_handler(HttpMethod::GET, 
"/api/injection_point/{op}",
diff --git a/regression-test/pipeline/cloud_p0/conf/be_custom.conf 
b/regression-test/pipeline/cloud_p0/conf/be_custom.conf
index 95708e868d5..c6096a12dd1 100644
--- a/regression-test/pipeline/cloud_p0/conf/be_custom.conf
+++ b/regression-test/pipeline/cloud_p0/conf/be_custom.conf
@@ -47,3 +47,5 @@ large_cumu_compaction_task_min_thread_num=3
 # So feature has bug, so by default is false, only open it in pipeline to 
observe
 enable_parquet_page_index=true
 enable_fuzzy_mode=true
+
+enable_prefill_all_dbm_agg_cache_after_compaction=true
diff --git a/regression-test/pipeline/cloud_p1/conf/be_custom.conf 
b/regression-test/pipeline/cloud_p1/conf/be_custom.conf
index 5ea318cbefa..aed4d69efbf 100644
--- a/regression-test/pipeline/cloud_p1/conf/be_custom.conf
+++ b/regression-test/pipeline/cloud_p1/conf/be_custom.conf
@@ -36,3 +36,4 @@ enable_new_tablet_do_compaction = true
 enable_table_size_correctness_check=true
 enable_write_index_searcher_cache=true
 large_cumu_compaction_task_min_thread_num=3
+enable_prefill_all_dbm_agg_cache_after_compaction=true
diff --git a/regression-test/pipeline/p0/conf/be.conf 
b/regression-test/pipeline/p0/conf/be.conf
index a64c5aa91f3..aa533b0f89f 100644
--- a/regression-test/pipeline/p0/conf/be.conf
+++ b/regression-test/pipeline/p0/conf/be.conf
@@ -89,3 +89,4 @@ large_cumu_compaction_task_min_thread_num=3
 enable_parquet_page_index=true
 enable_graceful_exit_check=true
 
+enable_prefill_all_dbm_agg_cache_after_compaction=true
diff --git a/regression-test/pipeline/p1/conf/be.conf 
b/regression-test/pipeline/p1/conf/be.conf
index 73453ebb61a..968a8aa26a4 100644
--- a/regression-test/pipeline/p1/conf/be.conf
+++ b/regression-test/pipeline/p1/conf/be.conf
@@ -74,3 +74,5 @@ enable_batch_download = true
 # So feature has bug, so by default is false, only open it in pipeline to 
observe
 enable_parquet_page_index=true
 enable_graceful_exit_check=true
+
+enable_prefill_all_dbm_agg_cache_after_compaction=true
diff --git 
a/regression-test/suites/metrics_p0/test_delete_bitmap_metrics.groovy 
b/regression-test/suites/metrics_p0/test_delete_bitmap_metrics.groovy
index 3861586057a..2cb5b9b29bb 100644
--- a/regression-test/suites/metrics_p0/test_delete_bitmap_metrics.groovy
+++ b/regression-test/suites/metrics_p0/test_delete_bitmap_metrics.groovy
@@ -99,6 +99,27 @@ suite("test_delete_bitmap_metrics", "p0") {
         return deleteBitmapStatus
     }
 
+    def getAggCacheDeleteBitmapStatus = { be_host, be_http_port, tablet_id, 
boolean verbose=false ->
+        boolean running = true
+        StringBuilder sb = new StringBuilder();
+        sb.append("curl -X GET http://${be_host}:${be_http_port}";)
+        sb.append("/api/delete_bitmap/count_agg_cache?tablet_id=")
+        sb.append(tablet_id)
+        if (verbose) {
+            sb.append("&verbose=true")
+        }
+
+        String command = sb.toString()
+        logger.info(command)
+        def process = command.execute()
+        def code = process.waitFor()
+        def out = process.getText()
+        logger.info("Get agg cache delete bitmap count status:  =" + code + ", 
out=" + out)
+        assertEquals(code, 0)
+        def deleteBitmapStatus = parseJson(out.trim())
+        return deleteBitmapStatus
+    }
+
     String[][] backends = sql """ show backends """
     assertTrue(backends.size() > 0)
     String backendId;
@@ -186,7 +207,17 @@ suite("test_delete_bitmap_metrics", "p0") {
                 logger.info("ms_delete_bitmap_cardinality:" + 
ms_delete_bitmap_cardinality)
                 assertTrue(ms_delete_bitmap_count == 7)
                 assertTrue(ms_delete_bitmap_cardinality == 7)
+
+                def status = 
getAggCacheDeleteBitmapStatus(backendId_to_backendIP[trigger_backend_id], 
backendId_to_backendHttpPort[trigger_backend_id], tablet_id)
+                logger.info("agg cache status: ${status}")
+                assert status.delete_bitmap_count == 8
+                assert status.cardinality == 7
+                assert status.size > 0
+
+                status = 
getAggCacheDeleteBitmapStatus(backendId_to_backendIP[trigger_backend_id], 
backendId_to_backendHttpPort[trigger_backend_id], tablet_id, true)
+                logger.info("agg cache verbose status: ${status}")
             }
+
             def tablet_delete_bitmap_count = 0;
             def base_rowset_delete_bitmap_count = 0;
             int retry_time = 0;


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to