Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion cloud/src/recycler/recycler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1752,7 +1752,10 @@ int InstanceRecycler::abort_job_for_related_rowset(const RowsetMetaCloudPB& rows

TabletIndexPB tablet_idx;
int ret = get_tablet_idx(txn_kv_.get(), instance_id_, rowset_meta.tablet_id(), tablet_idx);
if (ret != 0) {
if (ret == 1) {
// tablet maybe recycled, directly return 0
return 0;
} else if (ret != 0) {
LOG(WARNING) << "failed to get tablet index, tablet_id=" << rowset_meta.tablet_id()
<< " instance_id=" << instance_id_ << " ret=" << ret;
return ret;
Expand Down
5 changes: 5 additions & 0 deletions cloud/src/recycler/util.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,7 @@ int lease_instance_recycle_job(TxnKv* txn_kv, std::string_view key, const std::s
return 0;
}

// ret: 0: success, 1: tablet not found, -1: failed
int get_tablet_idx(TxnKv* txn_kv, const std::string& instance_id, int64_t tablet_id,
TabletIndexPB& tablet_idx) {
std::unique_ptr<Transaction> txn;
Expand All @@ -247,6 +248,10 @@ int get_tablet_idx(TxnKv* txn_kv, const std::string& instance_id, int64_t tablet
meta_tablet_idx_key({instance_id, tablet_id}, &key);
err = txn->get(key, &val);
if (err != TxnErrorCode::TXN_OK) {
if (err == TxnErrorCode::TXN_KEY_NOT_FOUND) {
LOG(INFO) << "tablet not found, tablet_id=" << tablet_id << " key=" << hex(key);
return 1;
}
LOG(WARNING) << fmt::format("failed to get tablet_idx, err={} tablet_id={} key={}", err,
tablet_id, hex(key));
return -1;
Expand Down
46 changes: 46 additions & 0 deletions cloud/test/recycler_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8360,4 +8360,50 @@ TEST(CheckerTest, CheckCostTooMuchTime) {
ASSERT_EQ(rowset_metas.size(), NUM_BATCH_SIZE * 2);
}

TEST(RecyclerTest, abort_job_for_related_rowset_when_tablet_recycled) {
// Test case: recycle_rowsets and recycle_tablet are running in parallel.
// When recycle_tablet finishes first, the tablet might be recycled before
// abort_job_for_related_rowset is called for the rowset.
// In this case, get_tablet_idx returns 1 (tablet not found), and we should
// return 0 (success) directly without further processing.

auto txn_kv = std::make_shared<MemTxnKv>();
ASSERT_EQ(txn_kv->init(), 0);

InstanceInfoPB instance;
instance.set_instance_id(instance_id);
auto obj_info = instance.add_obj_info();
obj_info->set_id("abort_job_for_related_rowset_when_tablet_recycled");
obj_info->set_ak(config::test_s3_ak);
obj_info->set_sk(config::test_s3_sk);
obj_info->set_endpoint(config::test_s3_endpoint);
obj_info->set_region(config::test_s3_region);
obj_info->set_bucket(config::test_s3_bucket);
obj_info->set_prefix("abort_job_for_related_rowset_when_tablet_recycled");

InstanceRecycler recycler(txn_kv, instance, thread_group,
std::make_shared<TxnLazyCommitter>(txn_kv));
ASSERT_EQ(recycler.init(), 0);

// Create a schema for the rowset
doris::TabletSchemaCloudPB schema;
schema.set_schema_version(1);

constexpr int64_t index_id = 20001;
constexpr int64_t tablet_id = 20003;

// Create a rowset without creating the tablet index
// This simulates the case where the tablet has been recycled
auto rowset = create_rowset("abort_job_for_related_rowset_when_tablet_recycled", tablet_id,
index_id, 1, schema);
rowset.set_job_id("test_job_id");

// Call abort_job_for_related_rowset with a rowset whose tablet has been recycled
int ret = recycler.abort_job_for_related_rowset(rowset);

// Should return 0 (success) because tablet is already recycled
ASSERT_EQ(ret, 0)
<< "Should return 0 when tablet is already recycled (parallel recycle scenario)";
}

} // namespace doris::cloud
Loading