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

morrysnow pushed a commit to branch branch-3.1
in repository https://gitbox.apache.org/repos/asf/doris.git


The following commit(s) were added to refs/heads/branch-3.1 by this push:
     new 4c30059f3d0 branch-3.1: [Opt](mow) Opt mow load performance and CPU 
usage #55073 #55733 #55771 (#55767)
4c30059f3d0 is described below

commit 4c30059f3d0ad2754e223ad49cdb0565899d69e0
Author: bobhan1 <[email protected]>
AuthorDate: Sun Sep 14 00:22:36 2025 +0800

    branch-3.1: [Opt](mow) Opt mow load performance and CPU usage #55073 #55733 
#55771 (#55767)
    
    pick #55073 #55733 #55771
---
 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        |  34 +++++
 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                        | 138 ++++++++++++++++++---
 be/src/olap/tablet_meta.h                          |   8 +-
 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           |   2 +
 regression-test/pipeline/p1/conf/be.conf           |   2 +
 .../metrics_p0/test_delete_bitmap_metrics.groovy   |  31 +++++
 22 files changed, 278 insertions(+), 21 deletions(-)

diff --git a/be/src/cloud/cloud_base_compaction.cpp 
b/be/src/cloud/cloud_base_compaction.cpp
index 175abc04430..5e00721bfc7 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 64d63aee025..d2ea6ac0e8a 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 08e43ab2142..ac60c869154 100644
--- a/be/src/cloud/cloud_full_compaction.cpp
+++ b/be/src/cloud/cloud_full_compaction.cpp
@@ -292,6 +292,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 c2f69661741..aba7561d1a3 100644
--- a/be/src/common/config.cpp
+++ b/be/src/common/config.cpp
@@ -1564,6 +1564,9 @@ DEFINE_mInt32(max_segment_partial_column_cache_size, 
"500");
 
 DEFINE_mBool(enable_wal_tde, "false");
 
+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 8784bd71f1d..55591fc36c7 100644
--- a/be/src/common/config.h
+++ b/be/src/common/config.h
@@ -1630,6 +1630,9 @@ DECLARE_mInt32(max_segment_partial_column_cache_size);
 
 DECLARE_mBool(enable_wal_tde);
 
+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 5fc4d0f4388..9e152e5af1f 100644
--- a/be/src/http/action/delete_bitmap_action.cpp
+++ b/be/src/http/action/delete_bitmap_action.cpp
@@ -188,6 +188,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) {
@@ -206,6 +232,14 @@ void DeleteBitmapAction::handle(HttpRequest* req) {
         } else {
             HttpChannel::send_reply(req, HttpStatus::OK, json_result);
         }
+    } else if (_delete_bitmap_action_type == 
DeleteBitmapActionType::COUNT_AGG_CACHE) {
+        std::string json_result;
+        Status st = _handle_show_agg_cache_delete_bitmap_count(req, 
&json_result);
+        if (!st.ok()) {
+            HttpChannel::send_reply(req, HttpStatus::OK, st.to_json());
+        } else {
+            HttpChannel::send_reply(req, HttpStatus::OK, json_result);
+        }
     }
 }
 
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 cd22b88a4c8..b56c424348a 100644
--- a/be/src/olap/base_tablet.cpp
+++ b/be/src/olap/base_tablet.cpp
@@ -545,7 +545,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_meta->delete_bitmap()->contains_agg_without_cache(
+            if (s.ok() && 
_tablet_meta->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.
@@ -2135,4 +2135,29 @@ TabletSchemaSPtr 
BaseTablet::calculate_variant_extended_schema() const {
     return vectorized::schema_util::calculate_variant_extended_schema(rowsets, 
_max_version_schema);
 }
 
+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 38dba97829d..cb61252c6fe 100644
--- a/be/src/olap/base_tablet.h
+++ b/be/src/olap/base_tablet.h
@@ -344,6 +344,9 @@ public:
 
     Result<CaptureRowsetResult> _remote_capture_rowsets(const Version& 
version_range) const;
 
+    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 f4930c9f3da..a3ccc407078 100644
--- a/be/src/olap/compaction.cpp
+++ b/be/src/olap/compaction.cpp
@@ -1252,6 +1252,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 7d3c497f2a2..c859bc70cbd 100644
--- a/be/src/olap/full_compaction.cpp
+++ b/be/src/olap/full_compaction.cpp
@@ -178,6 +178,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 673a13b5392..0b46a2f1494 100644
--- a/be/src/olap/lru_cache.cpp
+++ b/be/src/olap/lru_cache.cpp
@@ -618,6 +618,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;
 }
@@ -764,6 +774,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 0b7da8754ff..9f4c95a4b9c 100644
--- a/be/src/olap/lru_cache.h
+++ b/be/src/olap/lru_cache.h
@@ -206,6 +206,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;
@@ -328,6 +330,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);
@@ -396,6 +399,7 @@ public:
     virtual 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;
@@ -459,6 +463,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 0a246482788..da1aae33780 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>
@@ -43,6 +44,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"
@@ -66,6 +68,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,
@@ -722,6 +740,7 @@ void TabletMeta::init_from_pb(const TabletMetaPB& 
tablet_meta_pb) {
 
     if (tablet_meta_pb.has_enable_unique_key_merge_on_write()) {
         _enable_unique_key_merge_on_write = 
tablet_meta_pb.enable_unique_key_merge_on_write();
+        _delete_bitmap->set_tablet_id(_tablet_id);
     }
 
     // init _rs_metas
@@ -1147,6 +1166,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,
@@ -1160,6 +1212,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) {
@@ -1318,9 +1386,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) ||
@@ -1479,22 +1591,12 @@ 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);
+}
+
+void DeleteBitmap::set_tablet_id(int64_t tablet_id) {
+    _tablet_id = 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 ef57add9d01..68f6d323bbc 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;
@@ -564,7 +566,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`
@@ -599,6 +601,10 @@ public:
     */
     DeleteBitmap diffset(const std::set<BitmapKey>& key_set) const;
 
+    DeleteBitmap agg_cache_snapshot();
+
+    void set_tablet_id(int64_t tablet_id);
+
 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 63b2abe2118..c06a6a03982 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 429da49dd35..3fae307b7ad 100644
--- a/be/src/service/http_service.cpp
+++ b/be/src/service/http_service.cpp
@@ -397,6 +397,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));
@@ -460,6 +465,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 024c7eb24e3..946f05cbb19 100644
--- a/regression-test/pipeline/cloud_p0/conf/be_custom.conf
+++ b/regression-test/pipeline/cloud_p0/conf/be_custom.conf
@@ -46,3 +46,5 @@ 
sys_log_verbose_modules=query_context,runtime_query_statistics_mgr
 
 # So feature has bug, so by default is false, only open it in pipeline to 
observe
 enable_parquet_page_index=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 92b32480863..307cf47a201 100644
--- a/regression-test/pipeline/cloud_p1/conf/be_custom.conf
+++ b/regression-test/pipeline/cloud_p1/conf/be_custom.conf
@@ -34,3 +34,4 @@ crash_in_memory_tracker_inaccurate = 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 0aecdd140d1..09dddd3c2d0 100644
--- a/regression-test/pipeline/p0/conf/be.conf
+++ b/regression-test/pipeline/p0/conf/be.conf
@@ -85,3 +85,5 @@ enable_graceful_exit_check=true
 enable_fetch_rowsets_from_peer_replicas = true
 
 enable_write_index_searcher_cache=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 9e82774c0df..b57c3abca74 100644
--- a/regression-test/pipeline/p1/conf/be.conf
+++ b/regression-test/pipeline/p1/conf/be.conf
@@ -70,3 +70,5 @@ large_cumu_compaction_task_min_thread_num=3
 # This 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 0f090eb14a9..11bbaad712e 100644
--- a/regression-test/suites/metrics_p0/test_delete_bitmap_metrics.groovy
+++ b/regression-test/suites/metrics_p0/test_delete_bitmap_metrics.groovy
@@ -102,6 +102,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;
@@ -190,6 +211,16 @@ suite("test_delete_bitmap_metrics", "p0") {
                 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