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 bef8f369ad5 [fix](compaction) Make creating tablet idempotently to
keep compaction Job idempotent (#56061)
bef8f369ad5 is described below
commit bef8f369ad553c24fa9f402ad10546aa204b245f
Author: Uniqueyou <[email protected]>
AuthorDate: Tue Sep 16 14:40:56 2025 +0800
[fix](compaction) Make creating tablet idempotently to keep compaction Job
idempotent (#56061)
### What problem does this PR solve?
If rpc create_tablets is not idempotent, it will recreate tablet stats,
which is tragic for compaction task idempotence
```
if (compaction.base_compaction_cnt() < stats.base_compaction_cnt() ||
compaction.cumulative_compaction_cnt() <
stats.cumulative_compaction_cnt()) {
code = MetaServiceCode::STALE_TABLET_CACHE;
SS << "could not perform compaction on expired tablet cache."
<< " req_base_compaction_cnt=" << compaction.base_compaction_cnt()
<< ", base_compaction_cnt=" << stats.base_compaction_cnt()
<< ", req_cumulative_compaction_cnt=" <<
compaction.cumulative_compaction_cnt()
<< ", cumulative_compaction_cnt=" <<
stats.cumulative_compaction_cnt();
msg = ss.str();
return;
}
```
---
cloud/src/meta-service/meta_service.cpp | 26 ++++
cloud/src/meta-service/meta_service.h | 11 +-
cloud/test/meta_service_http_test.cpp | 33 +++++
cloud/test/meta_service_job_test.cpp | 244 +++++++++++++++++++++++++++++++-
cloud/test/meta_service_test.cpp | 39 +++++
5 files changed, 351 insertions(+), 2 deletions(-)
diff --git a/cloud/src/meta-service/meta_service.cpp
b/cloud/src/meta-service/meta_service.cpp
index 51c0a659119..6f0159832c9 100644
--- a/cloud/src/meta-service/meta_service.cpp
+++ b/cloud/src/meta-service/meta_service.cpp
@@ -733,6 +733,32 @@ void internal_create_tablet(const CreateTabletsRequest*
request, MetaServiceCode
std::string key;
std::string val;
meta_tablet_key(key_info, &key);
+
+ err = txn->get(key, &val);
+ TEST_SYNC_POINT_CALLBACK("meta_service_test:get_meta_tablet_key_error",
&err);
+ if (err == TxnErrorCode::TXN_OK) {
+ doris::TabletMetaCloudPB exists_tablet_meta;
+ if (!exists_tablet_meta.ParseFromString(val)) {
+ code = MetaServiceCode::PROTOBUF_SERIALIZE_ERR;
+ msg = fmt::format("malformed tablet meta, unable to initialize,
key={}", hex(key));
+ return;
+ }
+ if (exists_tablet_meta.tablet_id() == tablet_meta.tablet_id() &&
+ exists_tablet_meta.schema_version() ==
tablet_meta.schema_version()) {
+ // idempotent
+ code = MetaServiceCode::OK;
+ msg = fmt::format("tablet already exists, tablet_id={}
schema_version={} key={}",
+ tablet_id, tablet_meta.schema_version(),
hex(key));
+ LOG(WARNING) << msg;
+ return;
+ }
+ }
+ if (err != TxnErrorCode::TXN_KEY_NOT_FOUND) {
+ code = cast_as<ErrCategory::READ>(err);
+ msg = "failed to get tablet key, key=" + hex(key);
+ LOG(WARNING) << msg;
+ return;
+ }
if (!tablet_meta.SerializeToString(&val)) {
code = MetaServiceCode::PROTOBUF_SERIALIZE_ERR;
msg = "failed to serialize tablet meta";
diff --git a/cloud/src/meta-service/meta_service.h
b/cloud/src/meta-service/meta_service.h
index d255fcd6aca..96ee9e42fe5 100644
--- a/cloud/src/meta-service/meta_service.h
+++ b/cloud/src/meta-service/meta_service.h
@@ -994,6 +994,15 @@ private:
auto dist =
std::uniform_int_distribution(-config::idempotent_request_replay_delay_range_ms,
config::idempotent_request_replay_delay_range_ms);
int64_t sleep_ms = config::idempotent_request_replay_delay_base_ms
+ dist(rng);
+ std::string debug_string = req.ShortDebugString();
+ if constexpr (std::is_same_v<Request, GetTabletStatsRequest>) {
+ auto short_req = req;
+ if (short_req.tablet_idx_size() > 10) {
+ short_req.mutable_tablet_idx()->DeleteSubrange(10,
req.tablet_idx_size() - 10);
+ }
+ debug_string = short_req.ShortDebugString();
+
TEST_SYNC_POINT_CALLBACK("idempotent_injection_short_debug_string_for_get_stats",
&short_req);
+ }
LOG(INFO) << " request_name=" << req.GetDescriptor()->name()
<< " response_name=" << res.GetDescriptor()->name()
<< " queue_ts=" <<
duration_cast<milliseconds>(s.time_since_epoch()).count()
@@ -1001,7 +1010,7 @@ private:
<< " idempotent_request_replay_delay_base_ms=" <<
config::idempotent_request_replay_delay_base_ms
<< " idempotent_request_replay_delay_range_ms=" <<
config::idempotent_request_replay_delay_range_ms
<< " idempotent_request_replay_delay_ms=" << sleep_ms
- << " request=" << req.ShortDebugString();
+ << " request=" << debug_string;
if (sleep_ms < 0 || exclusion.count(req.GetDescriptor()->name()))
return;
brpc::Controller ctrl;
bthread_usleep(sleep_ms * 1000);
diff --git a/cloud/test/meta_service_http_test.cpp
b/cloud/test/meta_service_http_test.cpp
index 7a92402243f..302dccf7b60 100644
--- a/cloud/test/meta_service_http_test.cpp
+++ b/cloud/test/meta_service_http_test.cpp
@@ -3084,4 +3084,37 @@ TEST(MetaServiceHttpTest, VirtualClusterTest) {
} // namespace doris::cloud
}
+
+TEST(MetaServiceHttpTest, ShortGetTabletStatsDebugStringTest) {
+ config::enable_idempotent_request_injection = true;
+ auto sp = SyncPoint::get_instance();
+ sp->enable_processing();
+ DORIS_CLOUD_DEFER {
+ sp->disable_processing();
+ };
+
+ HttpContext ctx(true);
+ auto& meta_service = ctx.meta_service_;
+ constexpr auto table_id = 10001, index_id = 11001, partition_id = 12001;
+ int64_t tablet_id = 10001;
+ GetTabletStatsRequest req;
+ GetTabletStatsResponse res;
+
+ brpc::Controller cntl;
+ for (size_t i = 0; i < 50; i++) {
+ auto* idx = req.add_tablet_idx();
+ idx->set_table_id(table_id);
+ idx->set_index_id(index_id);
+ idx->set_partition_id(partition_id);
+ idx->set_tablet_id(tablet_id + i);
+ }
+
+ meta_service->get_tablet_stats(&cntl, &req, &res, nullptr);
+
+ sp->set_call_back("idempotent_injection_short_debug_string_for_get_stats",
[](auto&& args) {
+ GetTabletStatsRequest debug_req =
*try_any_cast<GetTabletStatsRequest*>(args.back());
+ ASSERT_EQ(10, debug_req.tablet_idx_size());
+ });
+}
+
} // namespace doris::cloud
diff --git a/cloud/test/meta_service_job_test.cpp
b/cloud/test/meta_service_job_test.cpp
index e53ed77fb35..b71fee9aa3f 100644
--- a/cloud/test/meta_service_job_test.cpp
+++ b/cloud/test/meta_service_job_test.cpp
@@ -1793,6 +1793,16 @@ TEST(MetaServiceJobTest,
DeleteBitmapUpdateLockCompatibilityTest) {
ASSERT_EQ(txn->commit(), TxnErrorCode::TXN_OK);
};
+ auto clear_tablets = [&](int64_t table_id, int64_t index_id, int64_t
partition_id,
+ int64_t tablet_id) {
+ std::unique_ptr<Transaction> txn;
+ ASSERT_EQ(meta_service->txn_kv()->create_txn(&txn),
TxnErrorCode::TXN_OK);
+ std::string key =
+ meta_tablet_key({instance_id, table_id, index_id,
partition_id, tablet_id});
+ txn->remove(key);
+ ASSERT_EQ(txn->commit(), TxnErrorCode::TXN_OK);
+ };
+
config::use_delete_bitmap_lock_random_version = false;
int64_t table_id = 111;
remove_delete_bitmap_lock(meta_service.get(), table_id);
@@ -1859,8 +1869,10 @@ TEST(MetaServiceJobTest,
DeleteBitmapUpdateLockCompatibilityTest) {
config::delete_bitmap_lock_v2_white_list = version4 == 1 ? "" : "*";
test_commit_compaction_job(table_id, 2, 3, tablet_id,
TabletCompactionJobPB::BASE);
ASSERT_EQ(res.status().code(), MetaServiceCode::LOCK_EXPIRED);
- clear_rowsets(table_id);
+ clear_rowsets(tablet_id);
clear_rowsets(new_tablet_id);
+ clear_tablets(table_id, 2, 3, tablet_id);
+ clear_tablets(table_id, 2, 3, new_tablet_id);
remove_delete_bitmap_lock(meta_service.get(), table_id);
}
@@ -4734,4 +4746,234 @@ TEST(MetaServiceJobTest, CancelSC) {
}
}
+TEST(MetaServiceJobTest, IdempotentCompactionJob) {
+ auto meta_service = get_meta_service();
+ // meta_service->resource_mgr().reset(); // Do not use resource manager
+
+ auto sp = SyncPoint::get_instance();
+ DORIS_CLOUD_DEFER {
+ SyncPoint::get_instance()->clear_all_call_backs();
+ };
+ sp->set_call_back("get_instance_id", [&](auto&& args) {
+ auto* ret = try_any_cast_ret<std::string>(args);
+ ret->first = instance_id;
+ ret->second = true;
+ });
+ sp->enable_processing();
+
+ brpc::Controller cntl;
+
+ auto test_commit_compaction_job = [&](int64_t table_id, int64_t index_id,
int64_t partition_id,
+ int64_t tablet_id, std::string
job_id,
+
TabletCompactionJobPB::CompactionType type) {
+ FinishTabletJobRequest req;
+ FinishTabletJobResponse res;
+
+ auto compaction = req.mutable_job()->add_compaction();
+ compaction->set_id(job_id);
+ compaction->set_initiator("ip:port");
+ req.mutable_job()->mutable_idx()->set_table_id(table_id);
+ req.mutable_job()->mutable_idx()->set_index_id(index_id);
+ req.mutable_job()->mutable_idx()->set_partition_id(partition_id);
+ req.mutable_job()->mutable_idx()->set_tablet_id(tablet_id);
+ compaction->set_base_compaction_cnt(10);
+ compaction->set_cumulative_compaction_cnt(20);
+ req.set_action(FinishTabletJobRequest::COMMIT);
+
+ auto tablet_meta_key =
+ meta_tablet_key({instance_id, table_id, index_id,
partition_id, tablet_id});
+ std::string tablet_meta_val;
+ std::unique_ptr<Transaction> txn;
+ ASSERT_EQ(meta_service->txn_kv()->create_txn(&txn),
TxnErrorCode::TXN_OK);
+ doris::TabletMetaCloudPB tablet_meta_pb;
+ ASSERT_EQ(txn->get(tablet_meta_key, &tablet_meta_val),
TxnErrorCode::TXN_OK);
+ ASSERT_TRUE(tablet_meta_pb.ParseFromString(tablet_meta_val));
+ tablet_meta_pb.set_cumulative_layer_point(50);
+ txn->put(tablet_meta_key, tablet_meta_pb.SerializeAsString());
+ ASSERT_EQ(txn->commit(), TxnErrorCode::TXN_OK);
+
+ // Create create tablet stats, compation job will will update stats
+ ASSERT_EQ(meta_service->txn_kv()->create_txn(&txn),
TxnErrorCode::TXN_OK);
+ auto tablet_stats_key =
+ stats_tablet_key({instance_id, table_id, index_id,
partition_id, tablet_id});
+ std::string tablet_stats_val;
+ TabletStatsPB tablet_stats_pb;
+ ASSERT_EQ(txn->get(tablet_stats_key, &tablet_stats_val),
TxnErrorCode::TXN_OK);
+ ASSERT_TRUE(tablet_stats_pb.ParseFromString(tablet_stats_val));
+
+ std::mt19937
rng(std::chrono::system_clock::now().time_since_epoch().count());
+ std::uniform_int_distribution<int> dist(1, 10000); // Positive numbers
+
+
compaction->set_output_cumulative_point(tablet_stats_pb.cumulative_point() +
dist(rng));
+ compaction->set_num_output_rows(dist(rng));
+ compaction->set_num_output_rowsets(dist(rng));
+ compaction->set_num_output_segments(dist(rng));
+ compaction->set_num_input_rows(dist(rng));
+ compaction->set_num_input_rowsets(dist(rng));
+ compaction->set_num_input_segments(dist(rng));
+ compaction->set_size_input_rowsets(dist(rng));
+ compaction->set_size_output_rowsets(dist(rng));
+ compaction->set_index_size_input_rowsets(dist(rng));
+ compaction->set_segment_size_output_rowsets(dist(rng));
+ compaction->set_index_size_input_rowsets(dist(rng));
+ compaction->set_segment_size_output_rowsets(dist(rng));
+ compaction->set_type(type);
+
+ tablet_stats_pb.set_cumulative_compaction_cnt(dist(rng));
+ tablet_stats_pb.set_base_compaction_cnt(dist(rng));
+
tablet_stats_pb.set_cumulative_point(tablet_meta_pb.cumulative_layer_point());
+ // MUST let data stats be larger than input data size
+ tablet_stats_pb.set_num_rows(dist(rng) + compaction->num_input_rows());
+ tablet_stats_pb.set_data_size(dist(rng) +
compaction->size_input_rowsets());
+ tablet_stats_pb.set_num_rowsets(dist(rng) +
compaction->num_input_rowsets());
+ tablet_stats_pb.set_num_segments(dist(rng) +
compaction->num_input_segments());
+ tablet_stats_pb.set_index_size(dist(rng) +
compaction->index_size_input_rowsets());
+ tablet_stats_pb.set_segment_size(dist(rng) +
compaction->segment_size_input_rowsets());
+
+ txn->put(tablet_stats_key, tablet_stats_pb.SerializeAsString());
+ ASSERT_EQ(txn->commit(), TxnErrorCode::TXN_OK);
+
+ // Provide input and output rowset info
+ int64_t input_version_start = dist(rng);
+ int64_t input_version_end = input_version_start + 100;
+ compaction->add_input_versions(input_version_start);
+ compaction->add_input_versions(input_version_end);
+ compaction->add_output_versions(input_version_end);
+ compaction->add_output_rowset_ids("output rowset id");
+
+ // Input rowsets must exist, and more than 0
+ // Check number input rowsets
+ sp->set_call_back("process_compaction_job::loop_input_done", [](auto&&
args) {
+ auto* num_input_rowsets = try_any_cast<int*>(args[0]);
+ ASSERT_EQ(*num_input_rowsets, 0); // zero existed rowsets
+ });
+
+ // Provide input rowset KVs, boundary test, 5 input rowsets
+ ASSERT_EQ(meta_service->txn_kv()->create_txn(&txn),
TxnErrorCode::TXN_OK);
+ // clang-format off
+ std::vector<std::string> input_rowset_keys = {
+ meta_rowset_key({instance_id, tablet_id, input_version_start -
1}),
+ meta_rowset_key({instance_id, tablet_id, input_version_start}),
+ meta_rowset_key({instance_id, tablet_id, input_version_start +
1}),
+ meta_rowset_key({instance_id, tablet_id, (input_version_start
+ input_version_end) / 2}),
+ meta_rowset_key({instance_id, tablet_id, input_version_end -
1}),
+ meta_rowset_key({instance_id, tablet_id, input_version_end}),
+ meta_rowset_key({instance_id, tablet_id, input_version_end +
1}),
+ };
+ // clang-format on
+ std::vector<std::unique_ptr<std::string>> input_rowset_vals;
+ for (auto& i : input_rowset_keys) {
+ doris::RowsetMetaCloudPB rs_pb;
+ rs_pb.set_rowset_id(0);
+ rs_pb.set_rowset_id_v2(hex(i));
+ input_rowset_vals.emplace_back(new
std::string(rs_pb.SerializeAsString()));
+ txn->put(i, *input_rowset_vals.back());
+ }
+ ASSERT_EQ(txn->commit(), TxnErrorCode::TXN_OK);
+
+ // Check number input rowsets
+ sp->set_call_back("process_compaction_job::loop_input_done", [](auto&&
args) {
+ auto* num_input_rowsets = try_any_cast<int*>(args[0]);
+ ASSERT_EQ(*num_input_rowsets, 5);
+ });
+
+ int64_t txn_id = dist(rng);
+ compaction->add_txn_id(txn_id);
+
+ // Provide invalid output rowset meta
+ auto tmp_rowset_key = meta_rowset_tmp_key({instance_id, txn_id,
tablet_id});
+ doris::RowsetMetaCloudPB tmp_rs_pb;
+ tmp_rs_pb.set_rowset_id(0);
+ auto tmp_rowset_val = tmp_rs_pb.SerializeAsString();
+ ASSERT_EQ(meta_service->txn_kv()->create_txn(&txn),
TxnErrorCode::TXN_OK);
+ txn->put(tmp_rowset_key, tmp_rowset_val);
+ ASSERT_EQ(txn->commit(), TxnErrorCode::TXN_OK);
+
+ // Provide txn_id in output rowset meta
+ tmp_rs_pb.set_txn_id(10086);
+ tmp_rowset_val = tmp_rs_pb.SerializeAsString();
+ ASSERT_EQ(meta_service->txn_kv()->create_txn(&txn),
TxnErrorCode::TXN_OK);
+ txn->put(tmp_rowset_key, tmp_rowset_val);
+ ASSERT_EQ(txn->commit(), TxnErrorCode::TXN_OK);
+
+
meta_service->finish_tablet_job(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);
+ tablet_stats_val.clear();
+ ASSERT_EQ(txn->get(tablet_stats_key, &tablet_stats_val),
TxnErrorCode::TXN_OK);
+ TabletStatsPB stats;
+ ASSERT_TRUE(stats.ParseFromString(tablet_stats_val));
+
+ // clang-format off
+ EXPECT_EQ(stats.base_compaction_cnt() ,
tablet_stats_pb.base_compaction_cnt() + (req.job().compaction(0).type() ==
TabletCompactionJobPB::BASE));
+ EXPECT_EQ(stats.cumulative_compaction_cnt(),
tablet_stats_pb.cumulative_compaction_cnt() + (req.job().compaction(0).type()
== TabletCompactionJobPB::CUMULATIVE));
+ EXPECT_EQ(stats.cumulative_point() , type ==
TabletCompactionJobPB::BASE ? 50 :
req.job().compaction(0).output_cumulative_point());
+ EXPECT_EQ(stats.num_rows() ,
tablet_stats_pb.num_rows() + (req.job().compaction(0).num_output_rows() -
req.job().compaction(0).num_input_rows()));
+ EXPECT_EQ(stats.data_size() ,
tablet_stats_pb.data_size() + (req.job().compaction(0).size_output_rowsets() -
req.job().compaction(0).size_input_rowsets()));
+ EXPECT_EQ(stats.num_rowsets() ,
tablet_stats_pb.num_rowsets() + (req.job().compaction(0).num_output_rowsets() -
req.job().compaction(0).num_input_rowsets()));
+ EXPECT_EQ(stats.num_segments() ,
tablet_stats_pb.num_segments() + (req.job().compaction(0).num_output_segments()
- req.job().compaction(0).num_input_segments()));
+ EXPECT_EQ(stats.index_size() ,
tablet_stats_pb.index_size() +
(req.job().compaction(0).index_size_output_rowsets() -
req.job().compaction(0).index_size_input_rowsets()));
+ EXPECT_EQ(stats.segment_size() ,
tablet_stats_pb.segment_size() +
(req.job().compaction(0).segment_size_output_rowsets() -
req.job().compaction(0).segment_size_input_rowsets()));
+ // clang-format on
+
+ // Check job removed, tablet meta updated
+ auto job_key = job_tablet_key({instance_id, table_id, index_id,
partition_id, tablet_id});
+ std::string job_val;
+ ASSERT_EQ(txn->get(job_key, &job_val), TxnErrorCode::TXN_OK);
+ TabletJobInfoPB job_pb;
+ ASSERT_TRUE(job_pb.ParseFromString(job_val));
+ ASSERT_TRUE(job_pb.compaction().empty());
+ tablet_meta_val.clear();
+
+ // Check tmp rowset removed
+ ASSERT_EQ(txn->get(tmp_rowset_key, &tmp_rowset_val),
TxnErrorCode::TXN_KEY_NOT_FOUND);
+ // Check input rowsets removed, the largest version remains
+ for (int i = 1; i < input_rowset_keys.size() - 2; ++i) {
+ std::string val;
+ EXPECT_EQ(txn->get(input_rowset_keys[i], &val),
TxnErrorCode::TXN_KEY_NOT_FOUND)
+ << hex(input_rowset_keys[i]);
+ }
+ // Check recycle rowsets added
+ for (int i = 1; i < input_rowset_vals.size() - 1; ++i) {
+ doris::RowsetMetaCloudPB rs;
+ ASSERT_TRUE(rs.ParseFromString(*input_rowset_vals[i]));
+ auto key = recycle_rowset_key({instance_id, tablet_id,
rs.rowset_id_v2()});
+ std::string val;
+ EXPECT_EQ(txn->get(key, &val), TxnErrorCode::TXN_OK) << hex(key);
+ }
+ // Check output rowset added
+ auto rowset_key = meta_rowset_key({instance_id, tablet_id,
input_version_end});
+ std::string rowset_val;
+ EXPECT_EQ(txn->get(rowset_key, &rowset_val), TxnErrorCode::TXN_OK) <<
hex(rowset_key);
+ };
+ constexpr int64_t table_id = 1;
+ constexpr int64_t index_id = 2;
+ constexpr int64_t partition_id = 3;
+ constexpr int64_t tablet_id = 4;
+ auto type = TabletCompactionJobPB::BASE;
+ std::string job_id = "job_id1234";
+
+ create_tablet(meta_service.get(), table_id, index_id, partition_id,
tablet_id, false);
+
+ {
+ StartTabletJobResponse res;
+ start_compaction_job(meta_service.get(), tablet_id, job_id, "ip:port",
9, 19,
+ TabletCompactionJobPB::BASE, res);
+ ASSERT_EQ(res.status().code(), MetaServiceCode::OK);
+ }
+
+ ASSERT_NO_FATAL_FAILURE(
+ test_commit_compaction_job(table_id, index_id, partition_id,
tablet_id, job_id, type));
+
+ create_tablet(meta_service.get(), table_id, index_id, partition_id,
tablet_id, false);
+ {
+ StartTabletJobResponse res;
+ start_compaction_job(meta_service.get(), tablet_id, job_id, "ip:port",
9, 19,
+ TabletCompactionJobPB::BASE, res);
+ ASSERT_EQ(res.status().code(), MetaServiceCode::STALE_TABLET_CACHE);
+ }
+}
+
} // namespace doris::cloud
diff --git a/cloud/test/meta_service_test.cpp b/cloud/test/meta_service_test.cpp
index 86509d1e79f..ed51b9cb46e 100644
--- a/cloud/test/meta_service_test.cpp
+++ b/cloud/test/meta_service_test.cpp
@@ -11834,4 +11834,43 @@ TEST(MetaServiceTest, SetSnapshotPropertyTest) {
}
}
+TEST(MetaServiceTest, CreateTabletIdempotentAndHandlingError) {
+ DORIS_CLOUD_DEFER {
+ SyncPoint::get_instance()->clear_all_call_backs();
+ SyncPoint::get_instance()->disable_processing();
+ };
+
+ size_t case_num = 0;
+ auto* sp = SyncPoint::get_instance();
+ sp->set_call_back("meta_service_test:get_meta_tablet_key_error",
[&case_num](auto&& args) {
+ if (++case_num == 3) {
+ auto* code = try_any_cast<TxnErrorCode*>(args[0]);
+ *code = TxnErrorCode::TXN_INVALID_DATA;
+ }
+ });
+ sp->enable_processing();
+
+ auto meta_service = get_meta_service();
+ brpc::Controller cntl;
+ CreateTabletsRequest req;
+ CreateTabletsResponse res;
+ int64_t table_id = 100;
+ int64_t index_id = 200;
+ int64_t partition_id = 300;
+ int64_t tablet_id = 400;
+ req.set_db_id(1); // default db_id
+ add_tablet(req, table_id, index_id, partition_id, tablet_id);
+ // normal create
+ meta_service->create_tablets(&cntl, &req, &res, nullptr);
+ ASSERT_EQ(res.status().code(), MetaServiceCode::OK);
+
+ // idempotent
+ meta_service->create_tablets(&cntl, &req, &res, nullptr);
+ ASSERT_EQ(res.status().code(), MetaServiceCode::OK);
+
+ // error handling
+ meta_service->create_tablets(&cntl, &req, &res, nullptr);
+ ASSERT_EQ(res.status().code(), MetaServiceCode::KV_TXN_GET_ERR);
+}
+
} // namespace doris::cloud
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]