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]