This is an automated email from the ASF dual-hosted git repository.
yiguolei pushed a commit to branch branch-4.1
in repository https://gitbox.apache.org/repos/asf/doris.git
The following commit(s) were added to refs/heads/branch-4.1 by this push:
new d7ada5bbccf branch-4.1: [improvement](cloud) Remove pre-rowset delete
bitmaps by key (#66598) (#67936)
d7ada5bbccf is described below
commit d7ada5bbccf853384d5674c7d2e45fe734f9f2e5
Author: meiyi <[email protected]>
AuthorDate: Tue Sep 15 12:00:37 2026 +0800
branch-4.1: [improvement](cloud) Remove pre-rowset delete bitmaps by key
(#66598) (#67936)
pick https://github.com/apache/doris/pull/66598
---
be/src/cloud/cloud_cumulative_compaction.cpp | 15 +-
be/src/cloud/cloud_meta_mgr.cpp | 27 +-
be/src/cloud/cloud_meta_mgr.h | 6 +-
be/src/cloud/cloud_tablet.cpp | 32 ++-
be/src/cloud/cloud_tablet.h | 15 +-
be/src/common/config.cpp | 6 +
be/src/common/config.h | 2 +
be/test/cloud/cloud_meta_mgr_test.cpp | 83 ++++++
be/test/cloud/cloud_tablet_test.cpp | 73 +++++
cloud/src/meta-service/meta_service.cpp | 390 ++++++++++++++++++++++---
cloud/test/meta_service_test.cpp | 413 ++++++++++++++++++++++++++-
gensrc/proto/cloud.proto | 19 ++
12 files changed, 1024 insertions(+), 57 deletions(-)
diff --git a/be/src/cloud/cloud_cumulative_compaction.cpp
b/be/src/cloud/cloud_cumulative_compaction.cpp
index cd61ea9c426..a032cfdb392 100644
--- a/be/src/cloud/cloud_cumulative_compaction.cpp
+++ b/be/src/cloud/cloud_cumulative_compaction.cpp
@@ -463,7 +463,8 @@ Status CloudCumulativeCompaction::modify_rowsets() {
}
}
// agg delete bitmap for pre rowsets
- if (config::enable_agg_and_remove_pre_rowsets_delete_bitmap &&
+ if (config::delete_bitmap_store_write_version != 2 &&
+ config::enable_agg_and_remove_pre_rowsets_delete_bitmap &&
_tablet->keys_type() == KeysType::UNIQUE_KEYS &&
_tablet->enable_unique_key_merge_on_write() && _input_rowsets.size()
!= 1) {
OlapStopWatch watch;
@@ -479,17 +480,23 @@ Status CloudCumulativeCompaction::modify_rowsets() {
std::sort(pre_rowsets.begin(), pre_rowsets.end(), Rowset::comparator);
auto pre_rowsets_delete_bitmap =
std::make_shared<DeleteBitmap>(_tablet->tablet_id());
std::map<std::string, int64_t> pre_rowset_to_versions;
+ std::unique_ptr<CloudTablet::PreRowsetDeleteBitmapStats>
pre_rowset_delete_bitmap_stats;
+ if (config::enable_remove_pre_rowsets_delete_bitmap_by_keys) {
+ pre_rowset_delete_bitmap_stats =
+
std::make_unique<CloudTablet::PreRowsetDeleteBitmapStats>();
+ }
cloud_tablet()->agg_delete_bitmap_for_compaction(
_output_rowset->start_version(),
_output_rowset->end_version(), pre_rowsets,
- pre_rowsets_delete_bitmap, pre_rowset_to_versions);
+ pre_rowsets_delete_bitmap, pre_rowset_to_versions,
+ pre_rowset_delete_bitmap_stats.get());
// update delete bitmap to ms
DBUG_EXECUTE_IF(
"CumulativeCompaction.modify_rowsets.cloud_update_delete_bitmap_without_lock.block",
DBUG_BLOCK);
auto status =
_engine.meta_mgr().cloud_update_delete_bitmap_without_lock(
*cloud_tablet(), pre_rowsets_delete_bitmap.get(),
pre_rowset_to_versions,
- cloud_tablet()->table_id(), _output_rowset->start_version(),
- _output_rowset->end_version());
+ pre_rowset_delete_bitmap_stats.get(),
cloud_tablet()->table_id(),
+ _output_rowset->start_version(),
_output_rowset->end_version());
if (!status.ok()) {
LOG(WARNING) << "failed to agg pre rowsets delete bitmap to ms.
tablet_id="
<< _tablet->tablet_id() << ", pre rowset num=" <<
pre_rowsets.size()
diff --git a/be/src/cloud/cloud_meta_mgr.cpp b/be/src/cloud/cloud_meta_mgr.cpp
index 8b4ec76b333..378f3686f3a 100644
--- a/be/src/cloud/cloud_meta_mgr.cpp
+++ b/be/src/cloud/cloud_meta_mgr.cpp
@@ -2191,8 +2191,10 @@ Status CloudMetaMgr::update_delete_bitmap(const
CloudTablet& tablet, int64_t loc
Status CloudMetaMgr::cloud_update_delete_bitmap_without_lock(
const CloudTablet& tablet, DeleteBitmap* delete_bitmap,
- std::map<std::string, int64_t>& rowset_to_versions, int64_t table_id,
- int64_t pre_rowset_agg_start_version, int64_t
pre_rowset_agg_end_version) {
+ std::map<std::string, int64_t>& rowset_to_versions,
+ const CloudTablet::PreRowsetDeleteBitmapStats*
pre_rowset_delete_bitmap_stats,
+ int64_t table_id, int64_t pre_rowset_agg_start_version,
+ int64_t pre_rowset_agg_end_version) {
if (config::delete_bitmap_store_write_version == 2) {
VLOG_DEBUG << "no need to agg delete bitmap v1 in ms because use v2";
return Status::OK();
@@ -2208,6 +2210,10 @@ Status
CloudMetaMgr::cloud_update_delete_bitmap_without_lock(
// use a fake lock id to resolve compatibility issues
req.set_lock_id(-3);
req.set_without_lock(true);
+ req.set_enable_remove_agg_pre_rowsets_delete_bitmap_by_keys(
+ config::enable_remove_agg_pre_rowsets_delete_bitmap_by_keys);
+
req.set_enable_remove_pre_rowsets_delete_bitmap_by_keys(pre_rowset_delete_bitmap_stats
!=
+ nullptr);
for (auto& [key, bitmap] : delete_bitmap->delete_bitmap) {
req.add_rowset_ids(std::get<0>(key).to_string());
req.add_segment_ids(std::get<1>(key));
@@ -2231,6 +2237,23 @@ Status
CloudMetaMgr::cloud_update_delete_bitmap_without_lock(
req.set_pre_rowset_agg_start_version(pre_rowset_agg_start_version);
req.set_pre_rowset_agg_end_version(pre_rowset_agg_end_version);
}
+ if (pre_rowset_delete_bitmap_stats != nullptr) {
+ for (const auto& [rowset_id, delete_bitmap_stats] :
*pre_rowset_delete_bitmap_stats) {
+ if (delete_bitmap_stats.empty()) {
+ continue;
+ }
+ auto* rowset_stats_pb = req.add_pre_rowset_delete_bitmap_stats();
+ rowset_stats_pb->set_rowset_id(rowset_id);
+ for (const auto& [segment_id, version, delete_bitmap_size] :
delete_bitmap_stats) {
+ auto* delete_bitmap_stat_pb =
rowset_stats_pb->add_delete_bitmap_stats();
+ delete_bitmap_stat_pb->set_segment_id(segment_id);
+ delete_bitmap_stat_pb->set_version(version);
+
delete_bitmap_stat_pb->set_delete_bitmap_size(delete_bitmap_size);
+ }
+ }
+ }
+ TEST_SYNC_POINT_RETURN_WITH_VALUE(
+
"CloudMetaMgr::cloud_update_delete_bitmap_without_lock.before_rpc",
Status::OK(), &req);
return retry_rpc(MetaServiceRPC::UPDATE_DELETE_BITMAP, req, &res,
&MetaService_Stub::update_delete_bitmap,
{
diff --git a/be/src/cloud/cloud_meta_mgr.h b/be/src/cloud/cloud_meta_mgr.h
index 50b8353b7e6..31bec1c3628 100644
--- a/be/src/cloud/cloud_meta_mgr.h
+++ b/be/src/cloud/cloud_meta_mgr.h
@@ -155,8 +155,10 @@ public:
Status cloud_update_delete_bitmap_without_lock(
const CloudTablet& tablet, DeleteBitmap* delete_bitmap,
- std::map<std::string, int64_t>& rowset_to_versions, int64_t
table_id,
- int64_t pre_rowset_agg_start_version = 0, int64_t
pre_rowset_agg_end_version = 0);
+ std::map<std::string, int64_t>& rowset_to_versions,
+ const CloudTablet::PreRowsetDeleteBitmapStats*
pre_rowset_delete_bitmap_stats,
+ int64_t table_id, int64_t pre_rowset_agg_start_version = 0,
+ int64_t pre_rowset_agg_end_version = 0);
Status get_delete_bitmap_update_lock(const CloudTablet& tablet, int64_t
lock_id,
int64_t initiator);
diff --git a/be/src/cloud/cloud_tablet.cpp b/be/src/cloud/cloud_tablet.cpp
index 271c81dd49c..3be758fefd1 100644
--- a/be/src/cloud/cloud_tablet.cpp
+++ b/be/src/cloud/cloud_tablet.cpp
@@ -1440,12 +1440,34 @@ Status CloudTablet::calc_delete_bitmap_for_compaction(
void CloudTablet::agg_delete_bitmap_for_compaction(
int64_t start_version, int64_t end_version, const
std::vector<RowsetSharedPtr>& pre_rowsets,
- DeleteBitmapPtr& new_delete_bitmap,
- std::map<std::string, int64_t>& pre_rowset_to_versions) {
- for (auto& rowset : pre_rowsets) {
+ DeleteBitmapPtr& new_delete_bitmap, std::map<std::string, int64_t>&
pre_rowset_to_versions,
+ PreRowsetDeleteBitmapStats* pre_rowset_delete_bitmap_stats) {
+ auto& delete_bitmap = tablet_meta()->delete_bitmap();
+ for (const auto& rowset : pre_rowsets) {
+ if (pre_rowset_delete_bitmap_stats != nullptr) {
+ auto& rowset_delete_bitmap_stats =
+
(*pre_rowset_delete_bitmap_stats)[rowset->rowset_id().to_string()];
+ std::shared_lock lock(delete_bitmap.lock);
+ const auto bitmap_start_version =
static_cast<DeleteBitmap::Version>(start_version);
+ const auto bitmap_end_version =
static_cast<DeleteBitmap::Version>(end_version);
+ for (uint32_t seg_id = 0; seg_id < rowset->num_segments();
++seg_id) {
+ DeleteBitmap::BitmapKey segment_start {rowset->rowset_id(),
seg_id,
+ bitmap_start_version};
+ for (auto it =
delete_bitmap.delete_bitmap.lower_bound(segment_start);
+ it != delete_bitmap.delete_bitmap.end(); ++it) {
+ const auto& [key, bitmap] = *it;
+ if (std::get<0>(key) != rowset->rowset_id() ||
std::get<1>(key) != seg_id ||
+ std::get<2>(key) >= bitmap_end_version) {
+ break;
+ }
+ rowset_delete_bitmap_stats.emplace_back(seg_id,
std::get<2>(key),
+
bitmap.getSizeInBytes());
+ }
+ }
+ }
for (uint32_t seg_id = 0; seg_id < rowset->num_segments(); ++seg_id) {
- auto d = tablet_meta()->delete_bitmap().get_agg_without_cache(
- {rowset->rowset_id(), seg_id, end_version}, start_version);
+ auto d = delete_bitmap.get_agg_without_cache({rowset->rowset_id(),
seg_id, end_version},
+ start_version);
if (d->isEmpty()) {
continue;
}
diff --git a/be/src/cloud/cloud_tablet.h b/be/src/cloud/cloud_tablet.h
index e731dc534b4..b08d39005c2 100644
--- a/be/src/cloud/cloud_tablet.h
+++ b/be/src/cloud/cloud_tablet.h
@@ -18,6 +18,7 @@
#pragma once
#include <memory>
+#include <tuple>
#include "storage/partial_update_info.h"
#include "storage/rowset/rowset.h"
@@ -76,6 +77,11 @@ struct RecycledRowsets {
class CloudTablet final : public BaseTablet {
public:
+ // rowset id -> [(segment id, version, serialized delete bitmap size)]
+ using PreRowsetDeleteBitmapStats = std::map<
+ std::string,
+ std::vector<std::tuple<DeleteBitmap::SegmentId,
DeleteBitmap::Version, size_t>>>;
+
CloudTablet(CloudStorageEngine& engine, TabletMetaSharedPtr tablet_meta);
~CloudTablet() override;
@@ -357,10 +363,11 @@ public:
// check that if the delete bitmap in delete bitmap cache has the same
cardinality with the expected_delete_bitmap's
Status check_delete_bitmap_cache(int64_t txn_id, DeleteBitmap*
expected_delete_bitmap) override;
- void agg_delete_bitmap_for_compaction(int64_t start_version, int64_t
end_version,
- const std::vector<RowsetSharedPtr>&
pre_rowsets,
- DeleteBitmapPtr& new_delete_bitmap,
- std::map<std::string, int64_t>&
pre_rowset_to_versions);
+ void agg_delete_bitmap_for_compaction(
+ int64_t start_version, int64_t end_version,
+ const std::vector<RowsetSharedPtr>& pre_rowsets, DeleteBitmapPtr&
new_delete_bitmap,
+ std::map<std::string, int64_t>& pre_rowset_to_versions,
+ PreRowsetDeleteBitmapStats* pre_rowset_delete_bitmap_stats);
bool need_remove_unused_rowsets();
diff --git a/be/src/common/config.cpp b/be/src/common/config.cpp
index 0bb1fde8678..16d41bcc3e9 100644
--- a/be/src/common/config.cpp
+++ b/be/src/common/config.cpp
@@ -1446,6 +1446,12 @@ DEFINE_mBool(enable_mow_get_agg_by_cache, "true");
DEFINE_mBool(enable_mow_get_agg_correctness_check_core, "false");
DEFINE_mBool(enable_agg_and_remove_pre_rowsets_delete_bitmap, "true");
DEFINE_mBool(enable_check_agg_and_remove_pre_rowsets_delete_bitmap, "false");
+// Remove pre-rowset delete bitmaps in [end_version, end_version] before
writing aggregated delete
+// bitmaps. True: point delete; false: range delete.
+DEFINE_mBool(enable_remove_agg_pre_rowsets_delete_bitmap_by_keys, "true");
+// Remove pre-rowset delete bitmaps in [start_version, end_version). True:
point delete; false:
+// range delete.
+DEFINE_mBool(enable_remove_pre_rowsets_delete_bitmap_by_keys, "true");
// The secure path with user files, used in the `local` table function.
DEFINE_String(user_files_secure_path, "${DORIS_HOME}");
diff --git a/be/src/common/config.h b/be/src/common/config.h
index e9f64c2c429..65ea01ae452 100644
--- a/be/src/common/config.h
+++ b/be/src/common/config.h
@@ -1508,6 +1508,8 @@ DECLARE_mBool(enable_mow_get_agg_by_cache);
DECLARE_mBool(enable_mow_get_agg_correctness_check_core);
DECLARE_mBool(enable_agg_and_remove_pre_rowsets_delete_bitmap);
DECLARE_mBool(enable_check_agg_and_remove_pre_rowsets_delete_bitmap);
+DECLARE_mBool(enable_remove_agg_pre_rowsets_delete_bitmap_by_keys);
+DECLARE_mBool(enable_remove_pre_rowsets_delete_bitmap_by_keys);
// The secure path with user files, used in the `local` table function.
DECLARE_String(user_files_secure_path);
diff --git a/be/test/cloud/cloud_meta_mgr_test.cpp
b/be/test/cloud/cloud_meta_mgr_test.cpp
index 9b10f80a218..ba27d082f97 100644
--- a/be/test/cloud/cloud_meta_mgr_test.cpp
+++ b/be/test/cloud/cloud_meta_mgr_test.cpp
@@ -29,12 +29,14 @@
#include "cloud/cloud_storage_engine.h"
#include "cloud/cloud_tablet.h"
+#include "cloud/config.h"
#include "cpp/sync_point.h"
#include "load/stream_load/stream_load_context.h"
#include "storage/olap_common.h"
#include "storage/rowset/rowset_factory.h"
#include "storage/rowset/rowset_meta.h"
#include "storage/tablet/tablet_meta.h"
+#include "util/defer_op.h"
#include "util/uid_util.h"
namespace doris {
@@ -97,6 +99,87 @@ TEST_F(CloudMetaMgrTest,
response_status_returns_undefined_without_any_code) {
EXPECT_EQ(get_response_code(status), MetaServiceCode::OK);
}
+TEST_F(CloudMetaMgrTest, PreRowsetDeleteBitmapStatsRequestEncoding) {
+ CloudStorageEngine engine(EngineOptions {});
+ CloudMetaMgr meta_mgr;
+ TabletMetaSharedPtr tablet_meta(
+ new TabletMeta(1001, 2, 15673, 15674, 4, 5, TTabletSchema(), 6,
{{7, 8}},
+ UniqueId(9, 10), TTabletType::TABLET_TYPE_DISK,
TCompressionType::LZ4F));
+ auto tablet = std::make_shared<CloudTablet>(engine,
std::make_shared<TabletMeta>(*tablet_meta));
+ DeleteBitmap delete_bitmap(tablet->tablet_id());
+ std::map<std::string, int64_t> rowset_to_versions;
+
+ int32_t old_write_version = config::delete_bitmap_store_write_version;
+ bool old_remove_agg_by_keys =
config::enable_remove_agg_pre_rowsets_delete_bitmap_by_keys;
+ config::delete_bitmap_store_write_version = 1;
+ auto* sp = SyncPoint::get_instance();
+ sp->clear_all_call_backs();
+ sp->enable_processing();
+ Defer cleanup {[&] {
+ config::delete_bitmap_store_write_version = old_write_version;
+ config::enable_remove_agg_pre_rowsets_delete_bitmap_by_keys =
old_remove_agg_by_keys;
+ sp->disable_processing();
+ sp->clear_all_call_backs();
+ }};
+
+ auto capture_request = [&](const CloudTablet::PreRowsetDeleteBitmapStats*
stats) {
+ bool called = false;
+ UpdateDeleteBitmapRequest captured_req;
+ SyncPoint::CallbackGuard guard;
+ sp->set_call_back(
+
"CloudMetaMgr::cloud_update_delete_bitmap_without_lock.before_rpc",
+ [&](auto&& args) {
+ auto* req =
try_any_cast<UpdateDeleteBitmapRequest*>(args[0]);
+ captured_req.CopyFrom(*req);
+ called = true;
+ auto* ret = try_any_cast<std::pair<Status,
bool>*>(args.back());
+ ret->first = Status::OK();
+ ret->second = true;
+ },
+ &guard);
+ auto status = meta_mgr.cloud_update_delete_bitmap_without_lock(
+ *tablet, &delete_bitmap, rowset_to_versions, stats,
tablet->table_id(), 1, 2);
+ EXPECT_TRUE(status.ok()) << status;
+ EXPECT_TRUE(called);
+ return captured_req;
+ };
+
+ config::enable_remove_agg_pre_rowsets_delete_bitmap_by_keys = false;
+ auto config_disabled_req = capture_request(nullptr);
+
EXPECT_FALSE(config_disabled_req.enable_remove_agg_pre_rowsets_delete_bitmap_by_keys());
+
EXPECT_FALSE(config_disabled_req.enable_remove_pre_rowsets_delete_bitmap_by_keys());
+ EXPECT_EQ(config_disabled_req.pre_rowset_delete_bitmap_stats_size(), 0);
+
+ CloudTablet::PreRowsetDeleteBitmapStats empty_stats;
+ empty_stats.emplace(
+ "rowset_without_delete_bitmap",
+ std::vector<std::tuple<DeleteBitmap::SegmentId,
DeleteBitmap::Version, size_t>> {});
+ empty_stats.emplace(
+ "second_rowset_without_delete_bitmap",
+ std::vector<std::tuple<DeleteBitmap::SegmentId,
DeleteBitmap::Version, size_t>> {});
+ config::enable_remove_agg_pre_rowsets_delete_bitmap_by_keys = true;
+ auto config_enabled_req = capture_request(&empty_stats);
+
EXPECT_TRUE(config_enabled_req.enable_remove_agg_pre_rowsets_delete_bitmap_by_keys());
+
EXPECT_TRUE(config_enabled_req.enable_remove_pre_rowsets_delete_bitmap_by_keys());
+ EXPECT_EQ(config_enabled_req.pre_rowset_delete_bitmap_stats_size(), 0);
+
+ using DeleteBitmapStat = std::tuple<DeleteBitmap::SegmentId,
DeleteBitmap::Version, size_t>;
+ CloudTablet::PreRowsetDeleteBitmapStats populated_stats;
+ populated_stats.emplace("rowset_with_delete_bitmap",
+ std::vector<DeleteBitmapStat> {{3, 7, 1024}, {8,
9, 2048}});
+ auto populated_stats_req = capture_request(&populated_stats);
+ ASSERT_EQ(populated_stats_req.pre_rowset_delete_bitmap_stats_size(), 1);
+ const auto& rowset_stats =
populated_stats_req.pre_rowset_delete_bitmap_stats(0);
+ EXPECT_EQ(rowset_stats.rowset_id(), "rowset_with_delete_bitmap");
+ ASSERT_EQ(rowset_stats.delete_bitmap_stats_size(), 2);
+ EXPECT_EQ(rowset_stats.delete_bitmap_stats(0).segment_id(), 3);
+ EXPECT_EQ(rowset_stats.delete_bitmap_stats(0).version(), 7);
+ EXPECT_EQ(rowset_stats.delete_bitmap_stats(0).delete_bitmap_size(), 1024);
+ EXPECT_EQ(rowset_stats.delete_bitmap_stats(1).segment_id(), 8);
+ EXPECT_EQ(rowset_stats.delete_bitmap_stats(1).version(), 9);
+ EXPECT_EQ(rowset_stats.delete_bitmap_stats(1).delete_bitmap_size(), 2048);
+}
+
static AbortTxnRequest get_abort_txn_request(CloudMetaMgr* meta_mgr, const
StreamLoadContext& ctx) {
auto* sp = SyncPoint::get_instance();
sp->clear_all_call_backs();
diff --git a/be/test/cloud/cloud_tablet_test.cpp
b/be/test/cloud/cloud_tablet_test.cpp
index 228e7421ee3..7df8ad0607b 100644
--- a/be/test/cloud/cloud_tablet_test.cpp
+++ b/be/test/cloud/cloud_tablet_test.cpp
@@ -75,6 +75,79 @@ protected:
CloudStorageEngine _engine;
};
+class CloudTabletDeleteBitmapTest : public CloudTabletWarmUpStateTest {};
+
+TEST_F(CloudTabletDeleteBitmapTest,
AggDeleteBitmapForCompactionReturnsPreRowsetStats) {
+ auto rowset1 = create_rowset(Version(1, 1), 2);
+ auto rowset2 = create_rowset(Version(2, 2));
+ auto rowset_without_delete_bitmap = create_rowset(Version(3, 3));
+ ASSERT_NE(rowset1, nullptr);
+ ASSERT_NE(rowset2, nullptr);
+ ASSERT_NE(rowset_without_delete_bitmap, nullptr);
+
+ roaring::Roaring before_range;
+ before_range.add(1);
+ roaring::Roaring at_start;
+ at_start.add(2);
+ at_start.add(3);
+ roaring::Roaring within_range;
+ within_range.add(4);
+ roaring::Roaring at_end;
+ at_end.add(5);
+ roaring::Roaring second_segment;
+ second_segment.add(6);
+ second_segment.add(7);
+ second_segment.add(8);
+ roaring::Roaring second_rowset;
+ second_rowset.add(9);
+
+ auto& delete_bitmap = _tablet->tablet_meta()->delete_bitmap();
+ delete_bitmap.set({rowset1->rowset_id(), 0, 4}, before_range);
+ delete_bitmap.set({rowset1->rowset_id(), 0, 5}, at_start);
+ delete_bitmap.set({rowset1->rowset_id(), 0, 6}, within_range);
+ delete_bitmap.set({rowset1->rowset_id(), 0, 7}, at_end);
+ delete_bitmap.set({rowset1->rowset_id(), 1, 6}, second_segment);
+ delete_bitmap.set({rowset2->rowset_id(), 0, 5}, second_rowset);
+
+ auto aggregated_delete_bitmap =
std::make_shared<DeleteBitmap>(_tablet->tablet_id());
+ std::map<std::string, int64_t> pre_rowset_to_versions;
+ CloudTablet::PreRowsetDeleteBitmapStats pre_rowset_delete_bitmap_stats;
+ _tablet->agg_delete_bitmap_for_compaction(
+ 5, 7, {rowset1, rowset2, rowset_without_delete_bitmap},
aggregated_delete_bitmap,
+ pre_rowset_to_versions, &pre_rowset_delete_bitmap_stats);
+
+ using DeleteBitmapStat = std::tuple<DeleteBitmap::SegmentId,
DeleteBitmap::Version, size_t>;
+
EXPECT_EQ(pre_rowset_delete_bitmap_stats.at(rowset1->rowset_id().to_string()),
+ (std::vector<DeleteBitmapStat> {
+ {0, 5, at_start.getSizeInBytes()},
+ {0, 6, within_range.getSizeInBytes()},
+ {1, 6, second_segment.getSizeInBytes()},
+ }));
+
EXPECT_EQ(pre_rowset_delete_bitmap_stats.at(rowset2->rowset_id().to_string()),
+ (std::vector<DeleteBitmapStat> {{0, 5,
second_rowset.getSizeInBytes()}}));
+ EXPECT_TRUE(
+
pre_rowset_delete_bitmap_stats.at(rowset_without_delete_bitmap->rowset_id().to_string())
+ .empty());
+
+ roaring::Roaring aggregated;
+ ASSERT_EQ(aggregated_delete_bitmap->get({rowset1->rowset_id(), 0, 7},
&aggregated), 0);
+ EXPECT_EQ(aggregated.cardinality(), 4);
+ ASSERT_EQ(aggregated_delete_bitmap->get({rowset1->rowset_id(), 1, 7},
&aggregated), 0);
+ EXPECT_EQ(aggregated.cardinality(), 3);
+ ASSERT_EQ(aggregated_delete_bitmap->get({rowset2->rowset_id(), 0, 7},
&aggregated), 0);
+ EXPECT_EQ(aggregated.cardinality(), 1);
+ EXPECT_EQ(pre_rowset_to_versions.at(rowset1->rowset_id().to_string()), 1);
+ EXPECT_EQ(pre_rowset_to_versions.at(rowset2->rowset_id().to_string()), 2);
+
+ auto aggregated_without_stats =
std::make_shared<DeleteBitmap>(_tablet->tablet_id());
+ std::map<std::string, int64_t> rowset_versions_without_stats;
+ _tablet->agg_delete_bitmap_for_compaction(
+ 5, 7, {rowset1, rowset2, rowset_without_delete_bitmap},
aggregated_without_stats,
+ rowset_versions_without_stats, nullptr);
+ EXPECT_EQ(aggregated_without_stats->delete_bitmap,
aggregated_delete_bitmap->delete_bitmap);
+ EXPECT_EQ(rowset_versions_without_stats, pre_rowset_to_versions);
+}
+
// Test get_rowset_warmup_state for non-existent rowset
TEST_F(CloudTabletWarmUpStateTest, TestGetRowsetWarmupStateNonExistent) {
auto rowset = create_rowset(Version(1, 1));
diff --git a/cloud/src/meta-service/meta_service.cpp
b/cloud/src/meta-service/meta_service.cpp
index 670eab8c92b..dd5dc3cd05e 100644
--- a/cloud/src/meta-service/meta_service.cpp
+++ b/cloud/src/meta-service/meta_service.cpp
@@ -3799,6 +3799,112 @@ struct UpdateDeleteBitmapTxnStats {
size_t total_txn_count = 0;
};
+static bool check_delete_bitmap_point_delete(MetaServiceCode& code,
std::string& msg,
+ std::unique_ptr<Transaction>& txn,
+ const std::string& key,
+ const UpdateDeleteBitmapRequest*
request,
+ size_t request_index, bool&
point_delete,
+ bool& delete_bitmap_exists,
+ std::optional<uint16_t>&
max_blob_sequence) {
+ point_delete =
request->enable_remove_agg_pre_rowsets_delete_bitmap_by_keys() &&
+ request->lock_id() ==
COMPACTION_WITHOUT_LOCK_DELETE_BITMAP_LOCK_ID;
+ if (!point_delete) {
+ return true;
+ }
+ std::string end_key {key};
+ encode_int64(INT64_MAX, &end_key);
+ RangeGetOptions opts;
+ opts.batch_limit = 1;
+ opts.reverse = true;
+ std::unique_ptr<RangeGetIterator> it;
+ auto err = txn->get(key, end_key, &it, opts);
+ if (err != TxnErrorCode::TXN_OK) {
+ code = cast_as<ErrCategory::READ>(err);
+ msg = fmt::format(
+ "failed to get the last delete bitmap blob key, err={},
tablet_id={}, key={}", err,
+ request->tablet_id(), hex(key));
+ return false;
+ }
+
+ delete_bitmap_exists = it->has_next();
+ max_blob_sequence.reset();
+ if (!delete_bitmap_exists) {
+ return true;
+ }
+ auto max_key = it->next().first;
+ if (max_key.size() < key.size()) [[unlikely]] {
+ code = MetaServiceCode::UNDEFINED_ERR;
+ msg = fmt::format(
+ "delete bitmap range scan returned a shorter key,
tablet_id={}, key={}, "
+ "max_key={}",
+ request->tablet_id(), hex(key), hex(max_key));
+ LOG(WARNING) << msg;
+ return false;
+ }
+ if (max_key.size() == key.size()) {
+ if (max_key != key) [[unlikely]] {
+ code = MetaServiceCode::UNDEFINED_ERR;
+ msg = fmt::format(
+ "delete bitmap range scan returned an unexpected key,
tablet_id={}, key={}, "
+ "max_key={}",
+ request->tablet_id(), hex(key), hex(max_key));
+ LOG(WARNING) << msg;
+ return false;
+ }
+ return true;
+ }
+ uint8_t blob_version = 0;
+ uint16_t sequence = 0;
+ std::vector<std::tuple<std::variant<int64_t, std::string>, int, int>> out;
+ if (!decode_blob_key(max_key, nullptr, &blob_version, &sequence, &out))
[[unlikely]] {
+ code = MetaServiceCode::UNDEFINED_ERR;
+ msg = fmt::format("failed to decode delete bitmap blob key,
tablet_id={}, key={}",
+ request->tablet_id(), hex(max_key));
+ LOG(WARNING) << msg;
+ return false;
+ }
+
+ constexpr size_t delete_bitmap_key_field_count = 7;
+ if (out.size() != delete_bitmap_key_field_count) [[unlikely]] {
+ code = MetaServiceCode::UNDEFINED_ERR;
+ msg = fmt::format(
+ "invalid delete bitmap blob origin key field count,
tablet_id={}, key={}, "
+ "field_count={}",
+ request->tablet_id(), hex(max_key), out.size());
+ LOG(WARNING) << msg;
+ return false;
+ }
+
+ const auto* rowset_id = std::get_if<std::string>(&std::get<0>(out[4]));
+ const auto* version = std::get_if<int64_t>(&std::get<0>(out[5]));
+ const auto* segment_id = std::get_if<int64_t>(&std::get<0>(out[6]));
+ if (rowset_id == nullptr || version == nullptr || segment_id == nullptr)
[[unlikely]] {
+ code = MetaServiceCode::UNDEFINED_ERR;
+ msg = fmt::format("invalid delete bitmap blob origin key fields,
tablet_id={}, key={}",
+ request->tablet_id(), hex(max_key));
+ LOG(WARNING) << msg;
+ return false;
+ }
+
+ if (*rowset_id != request->rowset_ids(request_index) ||
+ *version != request->versions(request_index) ||
+ *segment_id != request->segment_ids(request_index)) [[unlikely]] {
+ code = MetaServiceCode::UNDEFINED_ERR;
+ msg = fmt::format(
+ "unexpected delete bitmap blob origin key, tablet_id={},
key={}, rowset_id={}, "
+ "version={}, segment_id={}, expected_rowset_id={}, "
+ "expected_version={}, expected_segment_id={}",
+ request->tablet_id(), hex(max_key), *rowset_id, *version,
*segment_id,
+ request->rowset_ids(request_index),
request->versions(request_index),
+ request->segment_ids(request_index));
+ LOG(WARNING) << msg;
+ return false;
+ }
+
+ max_blob_sequence = sequence;
+ return true;
+}
+
void _write_delete_bitmap_kvs(MetaServiceCode& code, std::string& msg,
std::stringstream& ss,
std::shared_ptr<TxnKv> txn_kv,
std::unique_ptr<Transaction>& txn,
std::string& use_version, std::set<std::string>&
non_exist_rowset_ids,
@@ -3934,12 +4040,37 @@ void _write_delete_bitmap_kvs(MetaServiceCode& code,
std::string& msg, std::stri
}
// remove first
if (request->lock_id() == COMPACTION_WITHOUT_LOCK_DELETE_BITMAP_LOCK_ID) {
- auto& start_key = key;
- std::string end_key {start_key};
- encode_int64(INT64_MAX, &end_key);
- txn->remove(start_key, end_key);
- LOG(INFO) << "xxx remove delete_bitmap_key=" << hex(start_key) << "
tablet_id=" << tablet_id
- << " lock_id=" << request->lock_id() << " initiator=" <<
request->initiator();
+ bool point_delete = false;
+ bool delete_bitmap_exists = false;
+ std::optional<uint16_t> max_blob_sequence;
+ if (!check_delete_bitmap_point_delete(code, msg, txn, key, request, i,
point_delete,
+ delete_bitmap_exists,
max_blob_sequence)) {
+ return;
+ }
+ if (point_delete) {
+ if (delete_bitmap_exists) {
+ if (max_blob_sequence.has_value()) {
+ for (size_t sequence = 0; sequence <= *max_blob_sequence;
++sequence) {
+ txn->remove(encode_blob_key(key, 0, sequence));
+ }
+ } else {
+ // Compatibility with delete bitmaps written directly by
the legacy txn->put.
+ txn->remove(key);
+ }
+ LOG(INFO) << "xxx point remove delete_bitmap_key=" << hex(key)
+ << " tablet_id=" << tablet_id << " lock_id=" <<
request->lock_id()
+ << " initiator=" << request->initiator()
+ << " delete_key_count=" <<
(max_blob_sequence.value_or(0) + 1);
+ }
+ } else {
+ auto& start_key = key;
+ std::string end_key {start_key};
+ encode_int64(INT64_MAX, &end_key);
+ txn->remove(start_key, end_key);
+ LOG(INFO) << "xxx range remove delete_bitmap_key=" <<
hex(start_key)
+ << " tablet_id=" << tablet_id << " lock_id=" <<
request->lock_id()
+ << " initiator=" << request->initiator();
+ }
}
// splitting large values (>90*1000) into multiple KVs
cloud::blob_put(txn.get(), key, val, 0);
@@ -3952,6 +4083,136 @@ void _write_delete_bitmap_kvs(MetaServiceCode& code,
std::string& msg, std::stri
<< " key_size: " << key.size() << " value_size: " << val.size();
}
+static bool commit_pre_rowset_delete_bitmap_removal(
+ MetaServiceCode& code, std::string& msg, std::stringstream& ss,
+ const std::shared_ptr<TxnKv>& txn_kv, std::unique_ptr<Transaction>&
txn, KVStats& stats,
+ UpdateDeleteBitmapTxnStats& txn_stats, int64_t tablet_id, const
std::string& rowset_id) {
+ auto txn_size = txn->approximate_bytes();
+ LOG(INFO) << "commit delete bitmap point deletes before transaction size
exceeds limit, "
+ "tablet_id="
+ << tablet_id << ", rowset=" << rowset_id << ", txn_size=" <<
txn_size;
+ auto err = txn->commit();
+ TEST_SYNC_POINT_CALLBACK("update_delete_bitmap:remove_pre_rowsets:commit",
txn_size);
+ txn_stats.total_txn_put_keys += txn->num_put_keys();
+ txn_stats.total_txn_put_bytes += txn->put_bytes();
+ txn_stats.total_txn_size += txn_size;
+ txn_stats.total_txn_count++;
+ if (err != TxnErrorCode::TXN_OK) {
+ code = cast_as<ErrCategory::COMMIT>(err);
+ ss << "failed to remove pre rowsets delete bitmap, err=" << err
+ << " tablet_id=" << tablet_id << " rowset_id=" << rowset_id << "
txn_size=" << txn_size;
+ msg = ss.str();
+ g_bvar_update_delete_bitmap_fail_counter << 1;
+ return false;
+ }
+ stats.get_bytes += txn->get_bytes();
+ stats.put_bytes += txn->put_bytes();
+ stats.del_bytes += txn->delete_bytes();
+ stats.get_counter += txn->num_get_keys();
+ stats.put_counter += txn->num_put_keys();
+ stats.del_counter += txn->num_del_keys();
+ txn_stats.current_key_count = 0;
+ txn_stats.current_value_count = 0;
+ err = txn_kv->create_txn(&txn);
+ if (err != TxnErrorCode::TXN_OK) {
+ code = cast_as<ErrCategory::CREATE>(err);
+ msg = "failed to init txn when removing pre rowsets delete bitmap";
+ return false;
+ }
+ return true;
+}
+
+static bool remove_pre_rowset_delete_bitmap(
+ MetaServiceCode& code, std::string& msg, std::stringstream& ss,
+ const std::shared_ptr<TxnKv>& txn_kv, std::unique_ptr<Transaction>&
txn, KVStats& stats,
+ const UpdateDeleteBitmapRequest* request, const std::string&
instance_id,
+ const std::set<std::string>& non_exist_rowset_ids,
UpdateDeleteBitmapTxnStats& txn_stats) {
+ if (!request->has_pre_rowset_agg_start_version() ||
+ !request->has_pre_rowset_agg_end_version() ||
+ request->pre_rowset_agg_start_version() >=
request->pre_rowset_agg_end_version()) {
+ return true;
+ }
+
+ auto tablet_id = request->tablet_id();
+ if (!request->enable_remove_pre_rowsets_delete_bitmap_by_keys()) {
+ std::string pre_rowset_id;
+ for (size_t i = 0; i < request->rowset_ids_size(); ++i) {
+ if (request->rowset_ids(i) == pre_rowset_id) {
+ continue;
+ }
+ if (non_exist_rowset_ids.contains(request->rowset_ids(i))) {
+ LOG(INFO) << "skip remove pre rowsets delete bitmap,
rowset_id="
+ << request->rowset_ids(i) << " tablet_id=" <<
tablet_id
+ << " because the rowset does not exist";
+ continue;
+ }
+ pre_rowset_id = request->rowset_ids(i);
+ auto delete_bitmap_start =
+ meta_delete_bitmap_key({instance_id, tablet_id,
request->rowset_ids(i),
+
request->pre_rowset_agg_start_version(), 0});
+ auto delete_bitmap_end =
+ meta_delete_bitmap_key({instance_id, tablet_id,
request->rowset_ids(i),
+
request->pre_rowset_agg_end_version(), 0});
+ txn->remove(delete_bitmap_start, delete_bitmap_end);
+ LOG(INFO) << "remove pre rowsets delete bitmap by range,
tablet_id=" << tablet_id
+ << ", rowset=" << request->rowset_ids(i)
+ << ", start_version=" <<
request->pre_rowset_agg_start_version()
+ << ", end_version=" <<
request->pre_rowset_agg_end_version()
+ << ", start_key=" << hex(delete_bitmap_start)
+ << ", end_key=" << hex(delete_bitmap_end);
+ }
+ return true;
+ }
+
+ for (const auto& rowset_stats : request->pre_rowset_delete_bitmap_stats())
{
+ if (non_exist_rowset_ids.contains(rowset_stats.rowset_id())) {
+ LOG(INFO) << "skip remove pre rowsets delete bitmap, rowset_id="
+ << rowset_stats.rowset_id() << " tablet_id=" << tablet_id
+ << " because the rowset does not exist";
+ continue;
+ }
+ uint64_t delete_key_count = 0;
+ for (const auto& delete_bitmap_stat :
rowset_stats.delete_bitmap_stats()) {
+ DCHECK(delete_bitmap_stat.version() >=
request->pre_rowset_agg_start_version() &&
+ delete_bitmap_stat.version() <
request->pre_rowset_agg_end_version());
+ auto delete_bitmap_key = meta_delete_bitmap_key(
+ {instance_id, tablet_id, rowset_stats.rowset_id(),
delete_bitmap_stat.version(),
+ delete_bitmap_stat.segment_id()});
+ auto remove_key = [&](std::string_view key) {
+ auto txn_size = txn->approximate_bytes();
+ if (txn_size > 0 &&
+ txn_size + key.size() * 3 >
static_cast<size_t>(config::max_txn_commit_byte) &&
+ !commit_pre_rowset_delete_bitmap_removal(code, msg, ss,
txn_kv, txn, stats,
+ txn_stats,
tablet_id,
+
rowset_stats.rowset_id())) {
+ return false;
+ }
+ txn->remove(key);
+ delete_key_count++;
+ return true;
+ };
+ if (!remove_key(delete_bitmap_key)) {
+ return false;
+ }
+ auto split_key_count =
+ delete_bitmap_stat.delete_bitmap_size() /
DEFAULT_BLOB_SPLIT_SIZE +
+ (delete_bitmap_stat.delete_bitmap_size() %
DEFAULT_BLOB_SPLIT_SIZE != 0);
+ for (size_t i = 0; i < split_key_count; ++i) {
+ if (!remove_key(encode_blob_key(delete_bitmap_key, 0, i))) {
+ return false;
+ }
+ }
+ }
+ if (delete_key_count > 0) {
+ LOG(INFO) << "remove pre rowsets delete bitmap by keys,
tablet_id=" << tablet_id
+ << ", rowset=" << rowset_stats.rowset_id()
+ << ", delete_bitmap_count=" <<
rowset_stats.delete_bitmap_stats_size()
+ << ", delete_key_count=" << delete_key_count;
+ }
+ }
+ return true;
+}
+
void MetaServiceImpl::update_delete_bitmap(google::protobuf::RpcController*
controller,
const UpdateDeleteBitmapRequest*
request,
UpdateDeleteBitmapResponse*
response,
@@ -4173,35 +4434,9 @@ void
MetaServiceImpl::update_delete_bitmap(google::protobuf::RpcController* cont
if (code != MetaServiceCode::OK) return;
}
- // remove pre rowset delete bitmap
- if (request->has_pre_rowset_agg_start_version() &&
request->has_pre_rowset_agg_end_version() &&
- request->pre_rowset_agg_start_version() <
request->pre_rowset_agg_end_version()) {
- std::string pre_rowset_id = "";
- for (size_t i = 0; i < request->rowset_ids_size(); ++i) {
- if (request->rowset_ids(i) == pre_rowset_id) {
- continue;
- }
- if (non_exist_rowset_ids.contains(request->rowset_ids(i))) {
- LOG(INFO) << "skip remove pre rowsets delete bitmap,
rowset_id="
- << request->rowset_ids(i) << " tablet_id=" <<
tablet_id
- << " because the rowset does not exist";
- continue;
- }
- pre_rowset_id = request->rowset_ids(i);
- auto delete_bitmap_start =
- meta_delete_bitmap_key({instance_id, tablet_id,
request->rowset_ids(i),
-
request->pre_rowset_agg_start_version(), 0});
- auto delete_bitmap_end =
- meta_delete_bitmap_key({instance_id, tablet_id,
request->rowset_ids(i),
-
request->pre_rowset_agg_end_version(), 0});
- txn->remove(delete_bitmap_start, delete_bitmap_end);
- LOG(INFO) << "remove pre rowsets delete bitmap, tablet_id=" <<
tablet_id
- << ", rowset=" << request->rowset_ids(i)
- << ", start_version=" <<
request->pre_rowset_agg_start_version()
- << ", end_version=" <<
request->pre_rowset_agg_end_version()
- << ", start_key=" << hex(delete_bitmap_start)
- << ", end_key=" << hex(delete_bitmap_end);
- }
+ if (!remove_pre_rowset_delete_bitmap(code, msg, ss, txn_kv_, txn, stats,
request, instance_id,
+ non_exist_rowset_ids, txn_stats)) {
+ return;
}
err = txn->commit();
txn_stats.total_txn_put_keys += txn->num_put_keys();
@@ -4338,6 +4573,9 @@ void
MetaServiceImpl::get_delete_bitmap(google::protobuf::RpcController* control
std::unique_ptr<RangeGetIterator> it;
int64_t last_ver = -1;
int64_t last_seg_id = -1;
+ std::string last_delete_bitmap_first_blob_key;
+ uint16_t next_blob_sequence = 0;
+ bool skip_last_delete_bitmap = false;
int64_t round = 0;
while (it == nullptr /* may be not init */ || it->more()) {
if (test) {
@@ -4359,6 +4597,31 @@ void
MetaServiceImpl::get_delete_bitmap(google::protobuf::RpcController* control
msg = ss.str();
return;
}
+ if (!skip_last_delete_bitmap &&
!last_delete_bitmap_first_blob_key.empty()) {
+ std::string first_blob_value;
+ err = txn->get(last_delete_bitmap_first_blob_key,
&first_blob_value);
+ if (err == TxnErrorCode::TXN_KEY_NOT_FOUND) {
+ delete_bitmap_byte -=
+ response->segment_delete_bitmaps(
+
response->segment_delete_bitmaps_size() - 1)
+ .size();
+ delete_bitmap_num--;
+ response->mutable_rowset_ids()->RemoveLast();
+ response->mutable_segment_ids()->RemoveLast();
+ response->mutable_versions()->RemoveLast();
+
response->mutable_segment_delete_bitmaps()->RemoveLast();
+ skip_last_delete_bitmap = true;
+ LOG(WARNING)
+ << "skip incomplete delete bitmap whose
first blob key "
+ "disappeared after transaction retry"
+ << ", tablet_id=" << tablet_id
+ << ", rowset_id=" << rowset_ids[i] << ",
version=" << last_ver
+ << ", segment_id=" << last_seg_id;
+ } else if (err != TxnErrorCode::TXN_OK) {
+ retry++;
+ continue;
+ }
+ }
if (test) {
err = txn->get(start_key, end_key, &it, false, 2);
} else {
@@ -4384,7 +4647,15 @@ void
MetaServiceImpl::get_delete_bitmap(google::protobuf::RpcController* control
auto k1 = k;
k1.remove_prefix(1);
std::vector<std::tuple<std::variant<int64_t, std::string>,
int, int>> out;
- decode_key(&k1, &out);
+ auto decode_ret = decode_key(&k1, &out);
+ if (decode_ret != 0 || (out.size() != 7 && out.size() !=
8)) {
+ code = MetaServiceCode::KV_TXN_GET_ERR;
+ ss << "invalid delete bitmap key: " << hex(k)
+ << ", decode_ret=" << decode_ret << ",
field_count=" << out.size();
+ msg = ss.str();
+ g_bvar_get_delete_bitmap_fail_counter << 1;
+ return;
+ }
// 0x01 "meta" ${instance_id} "delete_bitmap" ${tablet_id}
// ${rowset_id0} ${version1} ${segment_id0} ->
DeleteBitmapPB
auto ver = std::get<int64_t>(std::get<0>(out[5]));
@@ -4393,15 +4664,58 @@ void
MetaServiceImpl::get_delete_bitmap(google::protobuf::RpcController* control
// FIXME: Don't expose the implementation details of
splitting large value.
// merge splitted large values (>90*1000)
if (ver != last_ver || seg_id != last_seg_id) {
+ auto sequence =
+ out.size() == 8
+ ? static_cast<uint16_t>(
+
std::get<int64_t>(std::get<0>(out[7])) & 0xffff)
+ : uint16_t {0};
+ last_ver = ver;
+ last_seg_id = seg_id;
+ last_delete_bitmap_first_blob_key.clear();
+ next_blob_sequence = static_cast<uint16_t>(sequence +
1);
+ // Key-based pre-rowset cleanup may leave an obsolete
tail if its size estimate is
+ // too small. The bitmap is already aggregated, so the
tail can be skipped and will
+ // be recycled with its rowset.
+ skip_last_delete_bitmap = sequence != 0;
+ if (skip_last_delete_bitmap) {
+ LOG(WARNING)
+ << "skip incomplete delete bitmap whose
first blob "
+ "sequence is not zero"
+ << ", tablet_id=" << tablet_id
+ << ", rowset_id=" << rowset_ids[i] << ",
version=" << ver
+ << ", segment_id=" << seg_id << ",
first_sequence=" << sequence;
+ continue;
+ }
+ if (out.size() == 8) {
+ last_delete_bitmap_first_blob_key.assign(k.data(),
k.size());
+ }
response->add_rowset_ids(rowset_ids[i]);
response->add_segment_ids(seg_id);
response->add_versions(ver);
response->add_segment_delete_bitmaps(std::string(v));
- last_ver = ver;
- last_seg_id = seg_id;
delete_bitmap_num++;
delete_bitmap_byte += v.length();
} else {
+ if (skip_last_delete_bitmap) {
+ continue;
+ }
+ auto sequence =
+ out.size() == 8
+ ? static_cast<uint16_t>(
+
std::get<int64_t>(std::get<0>(out[7])) & 0xffff)
+ : uint16_t {0};
+ if (out.size() != 8 || sequence != next_blob_sequence)
{
+ code = MetaServiceCode::KV_TXN_GET_ERR;
+ ss << "non-contiguous delete bitmap blob sequence,
tablet_id="
+ << tablet_id << ", rowset_id=" << rowset_ids[i]
+ << ", version=" << ver << ", segment_id=" <<
seg_id
+ << ", expected_sequence=" << next_blob_sequence
+ << ", actual_sequence=" << sequence;
+ msg = ss.str();
+ g_bvar_get_delete_bitmap_fail_counter << 1;
+ return;
+ }
+ next_blob_sequence++;
TEST_SYNC_POINT_CALLBACK("get_delete_bitmap_code",
&code);
if (code != MetaServiceCode::OK) {
ss << "test get get_delete_bitmap fail, code="
diff --git a/cloud/test/meta_service_test.cpp b/cloud/test/meta_service_test.cpp
index 12e31b6e8a2..1896ac01a2a 100644
--- a/cloud/test/meta_service_test.cpp
+++ b/cloud/test/meta_service_test.cpp
@@ -40,6 +40,7 @@
#include "cpp/sync_point.h"
#include "meta-service/meta_service_helper.h"
#include "meta-store/blob_message.h"
+#include "meta-store/codec.h"
#include "meta-store/document_message.h"
#include "meta-store/keys.h"
#include "meta-store/mem_txn_kv.h"
@@ -6901,6 +6902,93 @@ TEST(MetaServiceTest, UpdateDeleteBitmap) {
testUpdateDeleteBitmap(1);
}
+TEST(MetaServiceTest, UpdateDeleteBitmapPointDelete) {
+ auto meta_service = get_meta_service();
+ auto txn_kv = std::dynamic_pointer_cast<MemTxnKv>(meta_service->txn_kv());
+ ASSERT_NE(txn_kv, nullptr);
+ extern std::string get_instance_id(const std::shared_ptr<ResourceManager>&
rc_mgr,
+ const std::string& cloud_unique_id);
+ auto instance_id = get_instance_id(meta_service->resource_mgr(),
"test_cloud_unique_id");
+ auto old_max_txn_commit_byte = config::max_txn_commit_byte;
+ auto sp = SyncPoint::get_instance();
+ DORIS_CLOUD_DEFER {
+ config::max_txn_commit_byte = old_max_txn_commit_byte;
+ sp->clear_all_call_backs();
+ sp->disable_processing();
+ };
+ int split_commit_count = 0;
+ sp->set_call_back("update_delete_bitmap:commit:err", [&](auto&&) {
split_commit_count++; });
+ sp->enable_processing();
+
+ constexpr int64_t tablet_id = 3330;
+ auto replace_delete_bitmap = [&](const std::string& rowset_id, const
std::string& value,
+ MetaServiceCode expected_code =
MetaServiceCode::OK) {
+ brpc::Controller cntl;
+ UpdateDeleteBitmapRequest req;
+ UpdateDeleteBitmapResponse res;
+ req.set_cloud_unique_id("test_cloud_unique_id");
+ req.set_table_id(1120);
+ req.set_partition_id(1230);
+ req.set_without_lock(true);
+ req.set_enable_remove_agg_pre_rowsets_delete_bitmap_by_keys(true);
+ req.set_lock_id(-3);
+ req.set_initiator(tablet_id);
+ req.set_tablet_id(tablet_id);
+ req.add_rowset_ids(rowset_id);
+ req.add_segment_ids(0);
+ req.add_versions(2);
+ req.add_segment_delete_bitmaps(value);
+ meta_service->update_delete_bitmap(
+ reinterpret_cast<google::protobuf::RpcController*>(&cntl),
&req, &res, nullptr);
+ ASSERT_EQ(res.status().code(), expected_code);
+ };
+ auto put_old_delete_bitmap = [&](const std::string& key, size_t
blob_count) {
+ std::unique_ptr<Transaction> txn;
+ ASSERT_EQ(txn_kv->create_txn(&txn), TxnErrorCode::TXN_OK);
+ std::string old_value(DEFAULT_BLOB_SPLIT_SIZE * (blob_count - 1) + 1,
'a');
+ blob_put(txn.get(), key, old_value, 0);
+ ASSERT_EQ(txn->commit(), TxnErrorCode::TXN_OK);
+ };
+ auto check_delete_bitmap = [&](const std::string& key, const std::string&
expected) {
+ std::unique_ptr<Transaction> txn;
+ ASSERT_EQ(txn_kv->create_txn(&txn), TxnErrorCode::TXN_OK);
+ ValueBuf value;
+ ASSERT_EQ(blob_get(txn.get(), key, &value), TxnErrorCode::TXN_OK);
+ EXPECT_EQ(value.value(), expected);
+ };
+
+ const std::string point_rowset_id = "point_delete_rowset";
+ auto point_key = meta_delete_bitmap_key({instance_id, tablet_id,
point_rowset_id, 2, 0});
+ put_old_delete_bitmap(point_key, 4);
+ auto delete_count = txn_kv->del_count_;
+ replace_delete_bitmap(point_rowset_id, "point_replacement");
+ EXPECT_EQ(txn_kv->del_count_ - delete_count, 4);
+ EXPECT_EQ(split_commit_count, 0);
+ check_delete_bitmap(point_key, "point_replacement");
+
+ const std::string large_rowset_id = "large_point_delete_rowset";
+ auto large_key = meta_delete_bitmap_key({instance_id, tablet_id,
large_rowset_id, 2, 0});
+ put_old_delete_bitmap(large_key, 11);
+ config::max_txn_commit_byte = 1500;
+ delete_count = txn_kv->del_count_;
+ replace_delete_bitmap(large_rowset_id, "large_point_replacement");
+ EXPECT_EQ(txn_kv->del_count_ - delete_count, 11);
+ EXPECT_EQ(split_commit_count, 0);
+ check_delete_bitmap(large_key, "large_point_replacement");
+
+ const std::string invalid_rowset_id = "invalid_point_delete_rowset";
+ auto invalid_key = meta_delete_bitmap_key({instance_id, tablet_id,
invalid_rowset_id, 2, 0});
+ auto invalid_origin_key = invalid_key;
+ encode_int64(0, &invalid_origin_key);
+ {
+ std::unique_ptr<Transaction> txn;
+ ASSERT_EQ(txn_kv->create_txn(&txn), TxnErrorCode::TXN_OK);
+ txn->put(encode_blob_key(invalid_origin_key, 0, 0), "invalid");
+ ASSERT_EQ(txn->commit(), TxnErrorCode::TXN_OK);
+ }
+ replace_delete_bitmap(invalid_rowset_id, "replacement",
MetaServiceCode::UNDEFINED_ERR);
+}
+
TEST(MetaServiceTest, UpdateDeleteBitmapWithException) {
auto meta_service = get_meta_service();
brpc::Controller cntl;
@@ -6983,9 +7071,25 @@ TEST(MetaServiceTest, UpdateDeleteBitmapWithException) {
}
}
+static void put_delete_bitmap_test_rowset(MetaServiceProxy* meta_service,
+ const std::string& instance_id,
int64_t tablet_id,
+ int64_t version, const std::string&
rowset_id) {
+ std::unique_ptr<Transaction> txn;
+ ASSERT_EQ(meta_service->txn_kv()->create_txn(&txn), TxnErrorCode::TXN_OK);
+ std::string rowset_key = meta_rowset_key({instance_id, tablet_id,
version});
+ doris::RowsetMetaCloudPB rowset_meta;
+ rowset_meta.set_rowset_id(0);
+ rowset_meta.set_rowset_id_v2(rowset_id);
+ std::string rowset_value;
+ ASSERT_TRUE(rowset_meta.SerializeToString(&rowset_value));
+ txn->put(rowset_key, rowset_value);
+ ASSERT_EQ(txn->commit(), TxnErrorCode::TXN_OK);
+}
+
void update_delete_bitmap_with_remove_pre(MetaServiceProxy* meta_service,
int64_t table_id,
int64_t tablet_id, bool inject =
false,
- bool rowset_non_exist = false) {
+ bool rowset_non_exist = false,
+ bool use_delete_bitmap_stats = true)
{
// create rowset, if `rowset_non_exist` enabled, only r4 exists
{
std::unique_ptr<Transaction> txn;
@@ -7098,6 +7202,8 @@ void
update_delete_bitmap_with_remove_pre(MetaServiceProxy* meta_service, int64_
update_delete_bitmap_req.set_initiator(tablet_id);
update_delete_bitmap_req.set_pre_rowset_agg_start_version(4);
update_delete_bitmap_req.set_pre_rowset_agg_end_version(6);
+
update_delete_bitmap_req.set_enable_remove_pre_rowsets_delete_bitmap_by_keys(
+ use_delete_bitmap_stats);
std::vector<std::tuple<std::string, int64_t, int64_t, int64_t>>
new_rowset_segment_version_vector = {/* r2-0 */ {"r2", 0, 6, 2},
/* r3-0 */ {"r3", 0, 6, 3},
@@ -7113,6 +7219,21 @@ void
update_delete_bitmap_with_remove_pre(MetaServiceProxy* meta_service, int64_
update_delete_bitmap_req.add_segment_delete_bitmaps(new_large_value);
update_delete_bitmap_req.add_pre_rowset_versions(rowset_version);
}
+ if (use_delete_bitmap_stats) {
+ for (const auto& rowset : rowset_vector) {
+ auto* rowset_stats =
update_delete_bitmap_req.add_pre_rowset_delete_bitmap_stats();
+ rowset_stats->set_rowset_id(rowset);
+ for (const auto& [delete_bitmap_rowset, segment, version] :
+ rowset_segment_version_vector) {
+ if (delete_bitmap_rowset == rowset && version >= 4 && version
< 6) {
+ auto* delete_bitmap_stat =
rowset_stats->add_delete_bitmap_stats();
+ delete_bitmap_stat->set_segment_id(segment);
+ delete_bitmap_stat->set_version(version);
+
delete_bitmap_stat->set_delete_bitmap_size(large_value.size());
+ }
+ }
+ }
+ }
meta_service->update_delete_bitmap(reinterpret_cast<google::protobuf::RpcController*>(&cntl),
&update_delete_bitmap_req,
&update_delete_bitmap_res,
nullptr);
@@ -7183,11 +7304,18 @@ TEST(MetaServiceTest,
UpdateDeleteBitmapWithRemovePreDeleteBitmap) {
SyncPoint::get_instance()->clear_all_call_backs();
};
- update_delete_bitmap_with_remove_pre(meta_service.get(), 200, 202);
+ update_delete_bitmap_with_remove_pre(meta_service.get(), 200, 202, false,
false, false);
int64_t max_txn_commit_byte = config::max_txn_commit_byte;
config::max_txn_commit_byte = 1000;
+ int remove_pre_rowsets_commit_count = 0;
+ sp->set_call_back("update_delete_bitmap:remove_pre_rowsets:commit",
+ [&](auto&&) { remove_pre_rowsets_commit_count++; });
+ sp->enable_processing();
update_delete_bitmap_with_remove_pre(meta_service.get(), 300, 302);
+ EXPECT_GT(remove_pre_rowsets_commit_count, 0);
+ sp->clear_all_call_backs();
+ sp->disable_processing();
sp->set_call_back("update_delete_bitmap:commit:err", [&](auto&& args) {
auto initiator = try_any_cast<int64_t>(args[0]);
@@ -7206,6 +7334,287 @@ TEST(MetaServiceTest,
UpdateDeleteBitmapWithRemovePreDeleteBitmap) {
update_delete_bitmap_with_remove_pre(meta_service.get(), 500, 502, false,
true);
}
+TEST(MetaServiceTest, EmptyPreRowsetStatsUsesKeyRemoval) {
+ auto meta_service = get_meta_service();
+ extern std::string get_instance_id(const std::shared_ptr<ResourceManager>&
rc_mgr,
+ const std::string& cloud_unique_id);
+ auto instance_id = get_instance_id(meta_service->resource_mgr(),
"test_cloud_unique_id");
+ constexpr int64_t tablet_id = 622;
+ const std::string rowset_id = "empty_pre_rowset_stats";
+ put_delete_bitmap_test_rowset(meta_service.get(), instance_id, tablet_id,
1, rowset_id);
+
+ auto old_delete_bitmap_key = meta_delete_bitmap_key({instance_id,
tablet_id, rowset_id, 1, 0});
+ const std::string old_delete_bitmap = "old_delete_bitmap";
+ std::unique_ptr<Transaction> txn;
+ ASSERT_EQ(meta_service->txn_kv()->create_txn(&txn), TxnErrorCode::TXN_OK);
+ blob_put(txn.get(), old_delete_bitmap_key, old_delete_bitmap, 0);
+ ASSERT_EQ(txn->commit(), TxnErrorCode::TXN_OK);
+
+ brpc::Controller cntl;
+ UpdateDeleteBitmapRequest req;
+ UpdateDeleteBitmapResponse res;
+ req.set_cloud_unique_id("test_cloud_unique_id");
+ req.set_table_id(620);
+ req.set_partition_id(621);
+ req.set_tablet_id(tablet_id);
+ req.set_lock_id(-3);
+ req.set_without_lock(true);
+ req.set_initiator(tablet_id);
+ req.set_pre_rowset_agg_start_version(1);
+ req.set_pre_rowset_agg_end_version(2);
+ req.add_rowset_ids(rowset_id);
+ req.add_segment_ids(0);
+ req.add_versions(2);
+ req.add_segment_delete_bitmaps("aggregated_delete_bitmap");
+ req.add_pre_rowset_versions(1);
+ req.set_enable_remove_pre_rowsets_delete_bitmap_by_keys(true);
+
meta_service->update_delete_bitmap(reinterpret_cast<google::protobuf::RpcController*>(&cntl),
+ &req, &res, nullptr);
+
+ ASSERT_EQ(res.status().code(), MetaServiceCode::OK);
+ ASSERT_EQ(meta_service->txn_kv()->create_txn(&txn), TxnErrorCode::TXN_OK);
+ ValueBuf val;
+ ASSERT_EQ(blob_get(txn.get(), old_delete_bitmap_key, &val),
TxnErrorCode::TXN_OK);
+ EXPECT_EQ(val.value(), old_delete_bitmap);
+}
+
+TEST(MetaServiceTest,
UnderestimatedPreRowsetDeleteBitmapSizeLeavesSkippedTail) {
+ auto meta_service = get_meta_service();
+ extern std::string get_instance_id(const std::shared_ptr<ResourceManager>&
rc_mgr,
+ const std::string& cloud_unique_id);
+ auto instance_id = get_instance_id(meta_service->resource_mgr(),
"test_cloud_unique_id");
+ constexpr int64_t tablet_id = 632;
+ const std::string rowset_id = "underestimated_delete_bitmap";
+ put_delete_bitmap_test_rowset(meta_service.get(), instance_id, tablet_id,
1, rowset_id);
+
+ auto old_delete_bitmap_key = meta_delete_bitmap_key({instance_id,
tablet_id, rowset_id, 1, 0});
+ const std::string old_delete_bitmap(DEFAULT_BLOB_SPLIT_SIZE * 3 + 1, 'a');
+ std::unique_ptr<Transaction> txn;
+ ASSERT_EQ(meta_service->txn_kv()->create_txn(&txn), TxnErrorCode::TXN_OK);
+ blob_put(txn.get(), old_delete_bitmap_key, old_delete_bitmap, 0);
+ ASSERT_EQ(txn->commit(), TxnErrorCode::TXN_OK);
+
+ const std::string aggregated_delete_bitmap = "aggregated_delete_bitmap";
+ brpc::Controller update_cntl;
+ UpdateDeleteBitmapRequest update_req;
+ UpdateDeleteBitmapResponse update_res;
+ update_req.set_cloud_unique_id("test_cloud_unique_id");
+ update_req.set_table_id(630);
+ update_req.set_partition_id(631);
+ update_req.set_tablet_id(tablet_id);
+ update_req.set_lock_id(-3);
+ update_req.set_without_lock(true);
+ update_req.set_initiator(tablet_id);
+ update_req.set_pre_rowset_agg_start_version(1);
+ update_req.set_pre_rowset_agg_end_version(2);
+ update_req.add_rowset_ids(rowset_id);
+ update_req.add_segment_ids(0);
+ update_req.add_versions(2);
+ update_req.add_segment_delete_bitmaps(aggregated_delete_bitmap);
+ update_req.add_pre_rowset_versions(1);
+ update_req.set_enable_remove_pre_rowsets_delete_bitmap_by_keys(true);
+ auto* rowset_stats = update_req.add_pre_rowset_delete_bitmap_stats();
+ rowset_stats->set_rowset_id(rowset_id);
+ auto* delete_bitmap_stat = rowset_stats->add_delete_bitmap_stats();
+ delete_bitmap_stat->set_segment_id(0);
+ delete_bitmap_stat->set_version(1);
+ delete_bitmap_stat->set_delete_bitmap_size(DEFAULT_BLOB_SPLIT_SIZE);
+ meta_service->update_delete_bitmap(
+ reinterpret_cast<google::protobuf::RpcController*>(&update_cntl),
&update_req,
+ &update_res, nullptr);
+ ASSERT_EQ(update_res.status().code(), MetaServiceCode::OK);
+
+ ASSERT_EQ(meta_service->txn_kv()->create_txn(&txn), TxnErrorCode::TXN_OK);
+ std::string value;
+ EXPECT_EQ(txn->get(encode_blob_key(old_delete_bitmap_key, 0, 0), &value),
+ TxnErrorCode::TXN_KEY_NOT_FOUND);
+ EXPECT_EQ(txn->get(encode_blob_key(old_delete_bitmap_key, 0, 1), &value),
TxnErrorCode::TXN_OK);
+
+ brpc::Controller get_cntl;
+ GetDeleteBitmapRequest get_req;
+ GetDeleteBitmapResponse get_res;
+ get_req.set_cloud_unique_id("test_cloud_unique_id");
+ get_req.set_tablet_id(tablet_id);
+ get_req.add_rowset_ids(rowset_id);
+ get_req.add_begin_versions(0);
+ get_req.add_end_versions(3);
+
meta_service->get_delete_bitmap(reinterpret_cast<google::protobuf::RpcController*>(&get_cntl),
+ &get_req, &get_res, nullptr);
+
+ ASSERT_EQ(get_res.status().code(), MetaServiceCode::OK);
+ ASSERT_EQ(get_res.rowset_ids_size(), 1);
+ ASSERT_EQ(get_res.segment_ids_size(), 1);
+ ASSERT_EQ(get_res.versions_size(), 1);
+ ASSERT_EQ(get_res.segment_delete_bitmaps_size(), 1);
+ EXPECT_EQ(get_res.rowset_ids(0), rowset_id);
+ EXPECT_EQ(get_res.segment_ids(0), 0);
+ EXPECT_EQ(get_res.versions(0), 2);
+ EXPECT_EQ(get_res.segment_delete_bitmaps(0), aggregated_delete_bitmap);
+}
+
+static void test_get_delete_bitmap_during_point_cleanup(size_t
delete_bitmap_size) {
+ auto meta_service = get_meta_service();
+ auto sp = SyncPoint::get_instance();
+ DORIS_CLOUD_DEFER {
+ sp->clear_all_call_backs();
+ sp->disable_processing();
+ };
+
+ extern std::string get_instance_id(const std::shared_ptr<ResourceManager>&
rc_mgr,
+ const std::string& cloud_unique_id);
+ auto instance_id = get_instance_id(meta_service->resource_mgr(),
"test_cloud_unique_id");
+ constexpr int64_t table_id = 640;
+ constexpr int64_t partition_id = 641;
+ constexpr int64_t tablet_id = 642;
+ const std::string rowset_id = "point_cleanup_during_paginated_read";
+ put_delete_bitmap_test_rowset(meta_service.get(), instance_id, tablet_id,
1, rowset_id);
+
+ auto old_delete_bitmap_key = meta_delete_bitmap_key({instance_id,
tablet_id, rowset_id, 1, 0});
+ std::string old_delete_bitmap(DEFAULT_BLOB_SPLIT_SIZE, 'a');
+ old_delete_bitmap.append(DEFAULT_BLOB_SPLIT_SIZE, 'b');
+ old_delete_bitmap.append(DEFAULT_BLOB_SPLIT_SIZE, 'c');
+ old_delete_bitmap.push_back('d');
+ std::unique_ptr<Transaction> txn;
+ ASSERT_EQ(meta_service->txn_kv()->create_txn(&txn), TxnErrorCode::TXN_OK);
+ blob_put(txn.get(), old_delete_bitmap_key, old_delete_bitmap, 0);
+ ASSERT_EQ(txn->commit(), TxnErrorCode::TXN_OK);
+
+ const std::string aggregated_delete_bitmap = "aggregated_delete_bitmap";
+ UpdateDeleteBitmapRequest update_req;
+ update_req.set_cloud_unique_id("test_cloud_unique_id");
+ update_req.set_table_id(table_id);
+ update_req.set_partition_id(partition_id);
+ update_req.set_tablet_id(tablet_id);
+ update_req.set_lock_id(-3);
+ update_req.set_without_lock(true);
+ update_req.set_initiator(tablet_id);
+ update_req.set_pre_rowset_agg_start_version(1);
+ update_req.set_pre_rowset_agg_end_version(2);
+ update_req.add_rowset_ids(rowset_id);
+ update_req.add_segment_ids(0);
+ update_req.add_versions(2);
+ update_req.add_segment_delete_bitmaps(aggregated_delete_bitmap);
+ update_req.add_pre_rowset_versions(1);
+ update_req.set_enable_remove_pre_rowsets_delete_bitmap_by_keys(true);
+ auto* rowset_stats = update_req.add_pre_rowset_delete_bitmap_stats();
+ rowset_stats->set_rowset_id(rowset_id);
+ auto* delete_bitmap_stat = rowset_stats->add_delete_bitmap_stats();
+ delete_bitmap_stat->set_segment_id(0);
+ delete_bitmap_stat->set_version(1);
+ delete_bitmap_stat->set_delete_bitmap_size(delete_bitmap_size);
+
+ bool cleanup_done = false;
+ sp->set_call_back("get_delete_bitmap_test",
+ [&](auto&& args) { *try_any_cast<bool*>(args[0]) = true;
});
+ sp->set_call_back("get_delete_bitmap_err", [&](auto&& args) {
+ auto round = *try_any_cast<int64_t*>(args[0]);
+ if (round != 1 || cleanup_done) {
+ return;
+ }
+ cleanup_done = true;
+ brpc::Controller update_cntl;
+ UpdateDeleteBitmapResponse update_res;
+ meta_service->update_delete_bitmap(
+
reinterpret_cast<google::protobuf::RpcController*>(&update_cntl), &update_req,
+ &update_res, nullptr);
+ ASSERT_EQ(update_res.status().code(), MetaServiceCode::OK);
+ *try_any_cast<TxnErrorCode*>(args[1]) = TxnErrorCode::TXN_TOO_OLD;
+ });
+ sp->enable_processing();
+
+ brpc::Controller get_cntl;
+ GetDeleteBitmapRequest get_req;
+ GetDeleteBitmapResponse get_res;
+ get_req.set_cloud_unique_id("test_cloud_unique_id");
+ get_req.set_tablet_id(tablet_id);
+ get_req.add_rowset_ids(rowset_id);
+ get_req.add_begin_versions(0);
+ get_req.add_end_versions(3);
+
meta_service->get_delete_bitmap(reinterpret_cast<google::protobuf::RpcController*>(&get_cntl),
+ &get_req, &get_res, nullptr);
+
+ ASSERT_TRUE(cleanup_done);
+ ASSERT_EQ(get_res.status().code(), MetaServiceCode::OK);
+ ASSERT_EQ(get_res.rowset_ids_size(), 1);
+ ASSERT_EQ(get_res.segment_ids_size(), 1);
+ ASSERT_EQ(get_res.versions_size(), 1);
+ ASSERT_EQ(get_res.segment_delete_bitmaps_size(), 1);
+ EXPECT_EQ(get_res.rowset_ids(0), rowset_id);
+ EXPECT_EQ(get_res.segment_ids(0), 0);
+ EXPECT_EQ(get_res.versions(0), 2);
+ EXPECT_EQ(get_res.segment_delete_bitmaps(0), aggregated_delete_bitmap);
+}
+
+TEST(MetaServiceTest, GetDeleteBitmapSkipsPointCleanupTailAfterTxnTooOld) {
+ test_get_delete_bitmap_during_point_cleanup(DEFAULT_BLOB_SPLIT_SIZE * 3);
+}
+
+TEST(MetaServiceTest,
GetDeleteBitmapDropsPartialValueAfterAllBlobKeysAreRemoved) {
+ test_get_delete_bitmap_during_point_cleanup(DEFAULT_BLOB_SPLIT_SIZE * 3 +
1);
+}
+
+TEST(MetaServiceTest, RemovePreDeleteBitmapBatchesEachBlobKey) {
+ auto meta_service = get_meta_service();
+ auto sp = SyncPoint::get_instance();
+ int64_t old_max_txn_commit_byte = config::max_txn_commit_byte;
+ DORIS_CLOUD_DEFER {
+ config::max_txn_commit_byte = old_max_txn_commit_byte;
+ sp->clear_all_call_backs();
+ sp->disable_processing();
+ };
+
+ constexpr size_t max_txn_commit_byte = 300;
+ config::max_txn_commit_byte = max_txn_commit_byte;
+ std::vector<size_t> committed_txn_sizes;
+ sp->set_call_back("update_delete_bitmap:remove_pre_rowsets:commit",
[&](auto&& args) {
+ committed_txn_sizes.push_back(try_any_cast<size_t>(args[0]));
+ });
+ sp->enable_processing();
+
+ extern std::string get_instance_id(const std::shared_ptr<ResourceManager>&
rc_mgr,
+ const std::string& cloud_unique_id);
+ auto instance_id = get_instance_id(meta_service->resource_mgr(),
"test_cloud_unique_id");
+ constexpr int64_t tablet_id = 612;
+ const std::string rowset_id = "batch_blob_keys_rowset";
+ const std::string value(DEFAULT_BLOB_SPLIT_SIZE * 20, 'a');
+ auto delete_bitmap_key = meta_delete_bitmap_key({instance_id, tablet_id,
rowset_id, 1, 0});
+ std::unique_ptr<Transaction> txn;
+ ASSERT_EQ(meta_service->txn_kv()->create_txn(&txn), TxnErrorCode::TXN_OK);
+ blob_put(txn.get(), delete_bitmap_key, value, 0);
+ ASSERT_EQ(txn->commit(), TxnErrorCode::TXN_OK);
+
+ brpc::Controller cntl;
+ UpdateDeleteBitmapRequest req;
+ UpdateDeleteBitmapResponse res;
+ req.set_cloud_unique_id("test_cloud_unique_id");
+ req.set_table_id(610);
+ req.set_partition_id(611);
+ req.set_tablet_id(tablet_id);
+ req.set_lock_id(-3);
+ req.set_without_lock(true);
+ req.set_initiator(tablet_id);
+ req.set_pre_rowset_agg_start_version(1);
+ req.set_pre_rowset_agg_end_version(2);
+ req.set_enable_remove_pre_rowsets_delete_bitmap_by_keys(true);
+ auto* rowset_stats = req.add_pre_rowset_delete_bitmap_stats();
+ rowset_stats->set_rowset_id(rowset_id);
+ auto* delete_bitmap_stat = rowset_stats->add_delete_bitmap_stats();
+ delete_bitmap_stat->set_segment_id(0);
+ delete_bitmap_stat->set_version(1);
+ delete_bitmap_stat->set_delete_bitmap_size(value.size());
+
meta_service->update_delete_bitmap(reinterpret_cast<google::protobuf::RpcController*>(&cntl),
+ &req, &res, nullptr);
+
+ ASSERT_EQ(res.status().code(), MetaServiceCode::OK);
+ ASSERT_FALSE(committed_txn_sizes.empty());
+ for (auto txn_size : committed_txn_sizes) {
+ EXPECT_LE(txn_size, max_txn_commit_byte);
+ }
+ ASSERT_EQ(meta_service->txn_kv()->create_txn(&txn), TxnErrorCode::TXN_OK);
+ ValueBuf val;
+ EXPECT_EQ(blob_get(txn.get(), delete_bitmap_key, &val),
TxnErrorCode::TXN_KEY_NOT_FOUND);
+}
+
TEST(MetaServiceTest, GetDeleteBitmapWithIdx) {
auto meta_service = get_meta_service();
extern std::string get_instance_id(const std::shared_ptr<ResourceManager>&
rc_mgr,
diff --git a/gensrc/proto/cloud.proto b/gensrc/proto/cloud.proto
index 3e1b80a8415..030029bedf2 100644
--- a/gensrc/proto/cloud.proto
+++ b/gensrc/proto/cloud.proto
@@ -1915,6 +1915,17 @@ message DeleteBitmapStoragePB {
optional PackedSliceLocationPB packed_slice_location = 3;
}
+message PreRowsetDeleteBitmapStatsPB {
+ message DeleteBitmapStatPB {
+ optional uint32 segment_id = 1;
+ optional int64 version = 2;
+ optional uint64 delete_bitmap_size = 3;
+ }
+
+ optional string rowset_id = 1;
+ repeated DeleteBitmapStatPB delete_bitmap_stats = 2;
+}
+
message UpdateDeleteBitmapRequest {
optional string cloud_unique_id = 1; // For auth
optional int64 table_id = 2;
@@ -1940,6 +1951,14 @@ message UpdateDeleteBitmapRequest {
optional int64 pre_rowset_agg_end_version = 17;
// when update delete_bitmap of pre rowsets, check the rowset exists
repeated int64 pre_rowset_versions = 18;
+ // remove pre-rowset delete bitmaps in [end_version, end_version] before
writing aggregated
+ // delete bitmaps; true: point delete; false or unset: range delete
+ optional bool enable_remove_agg_pre_rowsets_delete_bitmap_by_keys = 19;
+ // remove pre-rowset delete bitmaps in [start_version, end_version):
+ // true: point delete; false or unset: range delete
+ optional bool enable_remove_pre_rowsets_delete_bitmap_by_keys = 20;
+ // stats of pre-rowset delete bitmaps in [start_version, end_version) used
for point delete
+ repeated PreRowsetDeleteBitmapStatsPB pre_rowset_delete_bitmap_stats = 21;
// 50-51: used for storage v2
repeated string delta_rowset_ids = 50;
repeated DeleteBitmapStoragePB delete_bitmap_storages = 51;
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]