This is an automated email from the ASF dual-hosted git repository.
gavinchou 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 9dbb0e93b27 [fix](cloud) Retain instance tombstones after recycle
cleanup (#66870)
9dbb0e93b27 is described below
commit 9dbb0e93b27998088e6eb9afd0040758957ae0f2
Author: Yixuan Wang <[email protected]>
AuthorDate: Thu Aug 20 17:45:25 2026 +0800
[fix](cloud) Retain instance tombstones after recycle cleanup (#66870)
Related PR: https://github.com/apache/doris/pull/66519
Problem Summary:
The recycler previously removed the instance key after the recycle state
reached INSTANCE_RECYCLE_STATE_CLEANUP_COMPLETED. This made the final
recycle state unavailable and prevented successor-chain checks from
distinguishing a completed successor from a missing instance. This
change retains the deleted instance record as a tombstone, skips
completed tombstones during scanning, excludes deleted instances from
ResourceManager runtime indexes and caches, and allows predecessors to
continue once their successor has completed cleanup.
---
cloud/src/common/config.h | 1 +
cloud/src/meta-service/meta_service.cpp | 23 +++++---
cloud/src/meta-service/meta_service_resource.cpp | 31 ++++++++---
cloud/src/recycler/recycler.cpp | 28 ++++++++--
cloud/src/resource-manager/resource_manager.cpp | 33 +++++++++---
cloud/src/resource-manager/resource_manager.h | 2 +-
cloud/test/meta_service_test.cpp | 55 +++++++++++++++++++
cloud/test/recycle_versioned_keys_test.cpp | 11 +++-
cloud/test/recycler_operation_log_test.cpp | 2 +-
cloud/test/recycler_test.cpp | 68 +++++++++++++++++++++++-
cloud/test/resource_test.cpp | 44 +++++++++++++++
11 files changed, 269 insertions(+), 29 deletions(-)
diff --git a/cloud/src/common/config.h b/cloud/src/common/config.h
index 070cdd4e44e..c147f910d97 100644
--- a/cloud/src/common/config.h
+++ b/cloud/src/common/config.h
@@ -136,6 +136,7 @@ CONF_mInt32(scan_instances_interval_seconds, "60"); // 1min
CONF_mInt32(check_object_interval_seconds, "43200"); // 12hours
// enable recycler metrics statistics
CONF_Bool(enable_recycler_stats_metrics, "false");
+CONF_mBool(retain_deleted_instance_tombstone, "true");
CONF_mInt64(check_recycle_task_interval_seconds, "600"); // 10min
CONF_mInt64(recycler_sleep_before_scheduling_seconds, "60");
diff --git a/cloud/src/meta-service/meta_service.cpp
b/cloud/src/meta-service/meta_service.cpp
index 4eac97d5d57..c6aa71e38c8 100644
--- a/cloud/src/meta-service/meta_service.cpp
+++ b/cloud/src/meta-service/meta_service.cpp
@@ -120,12 +120,23 @@ std::string get_instance_id(const
std::shared_ptr<ResourceManager>& rc_mgr,
return "";
}
- // check instance_id valid by get fdb
- if (config::enable_check_instance_id &&
!rc_mgr->is_instance_id_registered(id)) {
- LOG(WARNING) << "use degraded format cloud_unique_id, but check
instance failed, "
- "cloud_unique_id="
- << cloud_unique_id;
- return "";
+ if (config::enable_check_instance_id) {
+ InstanceInfoPB instance;
+ auto [code, msg] = rc_mgr->get_instance(nullptr, id, &instance);
+ { TEST_SYNC_POINT_CALLBACK("is_instance_id_registered", &code); }
+ if (code == TxnErrorCode::TXN_KEY_NOT_FOUND) {
+ LOG(WARNING)
+ << "use degraded format cloud_unique_id, but instance
is not registered, "
+ "cloud_unique_id="
+ << cloud_unique_id;
+ return "";
+ }
+ if (instance.has_status() && instance.status() ==
InstanceInfoPB::DELETED) {
+ msg = "instance status has been set delete, plz check it,
recycle_state=" +
+ InstanceRecycleState_Name(instance.recycle_state());
+ LOG(WARNING) << msg << ", cloud_unique_id=" << cloud_unique_id;
+ return "";
+ }
}
return id;
}
diff --git a/cloud/src/meta-service/meta_service_resource.cpp
b/cloud/src/meta-service/meta_service_resource.cpp
index ecdb13a63c1..0284d4246ef 100644
--- a/cloud/src/meta-service/meta_service_resource.cpp
+++ b/cloud/src/meta-service/meta_service_resource.cpp
@@ -3554,13 +3554,30 @@ void
MetaServiceImpl::alter_cluster(google::protobuf::RpcController* controller,
if (!cloud_unique_id.empty() && instance_id.empty()) {
auto [is_degraded_format, id] =
ResourceManager::get_instance_id_by_cloud_unique_id(cloud_unique_id);
- if (config::enable_check_instance_id && is_degraded_format &&
- !resource_mgr_->is_instance_id_registered(id)) {
- msg = "use degrade cloud_unique_id, but instance_id invalid,
cloud_unique_id=" +
- cloud_unique_id;
- LOG(WARNING) << msg;
- code = MetaServiceCode::INVALID_ARGUMENT;
- return;
+ if (config::enable_check_instance_id && is_degraded_format) {
+ InstanceInfoPB instance;
+ auto [code1, get_msg] = resource_mgr_->get_instance(nullptr, id,
&instance);
+ { TEST_SYNC_POINT_CALLBACK("is_instance_id_registered", &code1); }
+ if (code1 == TxnErrorCode::TXN_KEY_NOT_FOUND) {
+ msg = "use degrade cloud_unique_id, but instance_id is not
registered, "
+ "cloud_unique_id=" +
+ cloud_unique_id;
+ LOG(WARNING) << msg;
+ code = MetaServiceCode::INVALID_ARGUMENT;
+ return;
+ }
+ if (instance.has_status() && instance.status() ==
InstanceInfoPB::DELETED) {
+ msg = "instance status has been set delete, plz check it,
recycle_state=" +
+ InstanceRecycleState_Name(instance.recycle_state());
+ LOG(WARNING) << "use degraded format cloud_unique_id, but
check instance failed, "
+ "cloud_unique_id="
+ << cloud_unique_id << " code=" << code1 << "
info=" << get_msg
+ << " status=" << instance.status() << "
recycle_state="
+ <<
InstanceRecycleState_Name(instance.recycle_state());
+ LOG(WARNING) << msg;
+ code = MetaServiceCode::INVALID_ARGUMENT;
+ return;
+ }
}
instance_id = get_instance_id(resource_mgr_, cloud_unique_id);
if (instance_id.empty()) {
diff --git a/cloud/src/recycler/recycler.cpp b/cloud/src/recycler/recycler.cpp
index eac24365ebc..4efbf55004e 100644
--- a/cloud/src/recycler/recycler.cpp
+++ b/cloud/src/recycler/recycler.cpp
@@ -849,7 +849,7 @@ int InstanceRecycler::do_recycle() {
/**
* 1. delete all remote data
* 2. delete all kv
-* 3. remove instance kv
+* 3. remove instance kv depend on config::retain_deleted_instance_tombstone
*/
int InstanceRecycler::recycle_deleted_instance() {
LOG_WARNING("begin to recycle deleted instance").tag("instance_id",
instance_id_);
@@ -858,6 +858,11 @@ int InstanceRecycler::recycle_deleted_instance() {
auto start_time = steady_clock::now();
const auto recycle_state = instance_info_.recycle_state();
+ if (config::retain_deleted_instance_tombstone &&
+ recycle_state ==
InstanceRecycleState::INSTANCE_RECYCLE_STATE_CLEANUP_COMPLETED) {
+ return 0;
+ }
+
DORIS_CLOUD_DEFER {
auto cost = duration<float>(steady_clock::now() - start_time).count();
if (ret != 0) {
@@ -998,13 +1003,26 @@ int
InstanceRecycler::recycle_deleted_instance_metadata() {
return -1;
}
+ InstanceInfoPB successor_instance;
std::string value;
err = txn->get(key, &value);
if (err == TxnErrorCode::TXN_OK) {
- LOG(INFO) << "instance successor instance is still exist, skip
deleting kv,"
- << " instance_id=" << instance_id_
- << " successor_instance_id=" <<
instance_info_.successor_instance_id();
- return 0;
+ InstanceInfoPB successor_instance;
+ if (!successor_instance.ParseFromString(value)) {
+ LOG(WARNING) << "failed to parse successor instance,
instance_id=" << instance_id_
+ << " successor_instance_id=" <<
instance_info_.successor_instance_id();
+ return -1;
+ }
+ if (!successor_instance.has_recycle_state() ||
+ successor_instance.recycle_state() !=
+
InstanceRecycleState::INSTANCE_RECYCLE_STATE_CLEANUP_COMPLETED) {
+ LOG(INFO) << "instance successor has not completed recycling,
skip deleting kv,"
+ << " instance_id=" << instance_id_
+ << " successor_instance_id=" <<
instance_info_.successor_instance_id()
+ << " successor_status=" <<
successor_instance.status()
+ << " successor_recycled_state=" <<
successor_instance.recycle_state();
+ return 0;
+ }
} else if (err != TxnErrorCode::TXN_KEY_NOT_FOUND) {
LOG(WARNING) << "failed to get successor instance, instance_id="
<< instance_id_
<< " successor_instance_id=" <<
instance_info_.successor_instance_id()
diff --git a/cloud/src/resource-manager/resource_manager.cpp
b/cloud/src/resource-manager/resource_manager.cpp
index fd634fdcff2..3c5f52a7bad 100644
--- a/cloud/src/resource-manager/resource_manager.cpp
+++ b/cloud/src/resource-manager/resource_manager.cpp
@@ -109,6 +109,9 @@ int ResourceManager::init() {
std::unique_lock l(mtx_);
for (auto& [inst_id, inst] : instances) {
+ if (inst.status() == InstanceInfoPB::DELETED) {
+ continue;
+ }
for (auto& c : inst.clusters()) {
add_cluster_to_index_no_lock(inst_id, c);
}
@@ -193,12 +196,22 @@ bool ResourceManager::validate_nodes(const ClusterPB&
cluster, std::string* err,
// check here cloud_unique_id
std::string cloud_unique_id = n.cloud_unique_id();
auto [is_degrade_format, instance_id] =
get_instance_id_by_cloud_unique_id(cloud_unique_id);
- if (config::enable_check_instance_id && is_degrade_format &&
- !is_instance_id_registered(instance_id)) {
- ss << "node=" << n.DebugString()
- << " cloud_unique_id use degrade format, but check instance
failed";
- *err = ss.str();
- return false;
+ if (config::enable_check_instance_id && is_degrade_format) {
+ InstanceInfoPB instance;
+ auto [code, msg] = get_instance(nullptr, instance_id, &instance);
+ { TEST_SYNC_POINT_CALLBACK("is_instance_id_registered", &code); }
+ if (code == TxnErrorCode::TXN_KEY_NOT_FOUND) {
+ *err = "node=" + n.DebugString() +
+ " cloud_unique_id use degrade format, but instance is
not registered";
+ LOG(WARNING) << *err << ", cloud_unique_id=" <<
cloud_unique_id;
+ return false;
+ }
+ if (instance.has_status() && instance.status() ==
InstanceInfoPB::DELETED) {
+ *err = "instance status has been set delete, plz check it,
recycle_state=" +
+ InstanceRecycleState_Name(instance.recycle_state());
+ LOG(WARNING) << *err << ", cloud_unique_id=" <<
cloud_unique_id;
+ return false;
+ }
}
if (ClusterPB::SQL == cluster.type() && n.has_edit_log_port() &&
n.edit_log_port() &&
n.has_node_type() &&
@@ -371,7 +384,7 @@ bool ResourceManager::is_instance_id_registered(const
std::string& instance_id)
LOG(WARNING) << "failed to check instance instance_id=" << instance_id
<< ", code=" << format_as(c0) << ", info=" + m0;
}
- return c0 == TxnErrorCode::TXN_OK;
+ return c0 != TxnErrorCode::TXN_KEY_NOT_FOUND;
}
/**
@@ -1429,6 +1442,12 @@ void ResourceManager::refresh_instance(const
std::string& instance_id,
}
}
+ if (instance.status() == InstanceInfoPB::DELETED) {
+ instance_multi_version_status_.erase(instance_id);
+ instance_source_snapshot_info_.erase(instance_id);
+ return;
+ }
+
// If successor_instance_id is set, it means this instance has a successor
instance,
// so we do not need to add its clusters to the index again.
if (!instance.has_successor_instance_id()) {
diff --git a/cloud/src/resource-manager/resource_manager.h
b/cloud/src/resource-manager/resource_manager.h
index aaf27b8a88d..ca33a3f0983 100644
--- a/cloud/src/resource-manager/resource_manager.h
+++ b/cloud/src/resource-manager/resource_manager.h
@@ -191,7 +191,7 @@ public:
*
* @param instance_id
*
- * @return true, instance_id in fdb kv
+ * @return true if the instance kv exists.
*/
bool is_instance_id_registered(const std::string& instance_id);
diff --git a/cloud/test/meta_service_test.cpp b/cloud/test/meta_service_test.cpp
index 22aa756309a..0e5ad0f910b 100644
--- a/cloud/test/meta_service_test.cpp
+++ b/cloud/test/meta_service_test.cpp
@@ -459,6 +459,61 @@ TEST(MetaServiceTest, GetInstanceIdTest) {
sp->disable_processing();
}
+TEST(MetaServiceTest, CheckInstanceRecycleCompletedWithRetainedKey) {
+ auto txn_kv =
std::dynamic_pointer_cast<TxnKv>(std::make_shared<MemTxnKv>());
+ ASSERT_NE(txn_kv, nullptr);
+ ASSERT_EQ(txn_kv->init(), 0);
+ auto resource_mgr = std::make_shared<ResourceManager>(txn_kv);
+ ASSERT_EQ(resource_mgr->init(), 0);
+ auto rate_limiter = std::make_shared<RateLimiter>();
+ auto snapshot_manager = std::make_shared<SnapshotManager>(txn_kv);
+ MetaServiceImpl meta_service(txn_kv, resource_mgr, rate_limiter,
snapshot_manager);
+
+ const std::string instance_id = "retained_recycle_instance";
+ InstanceInfoPB instance;
+ instance.set_instance_id(instance_id);
+ instance.set_status(InstanceInfoPB::DELETED);
+
instance.set_recycle_state(InstanceRecycleState::INSTANCE_RECYCLE_STATE_CLEANUP_COMPLETED);
+
+ std::unique_ptr<Transaction> txn;
+ ASSERT_EQ(txn_kv->create_txn(&txn), TxnErrorCode::TXN_OK);
+ txn->put(instance_key({instance_id}), instance.SerializeAsString());
+ ASSERT_EQ(txn->commit(), TxnErrorCode::TXN_OK);
+
+ bool finished = false;
+ std::string reason;
+ auto [code, msg] =
meta_service.check_instance_recycle_completed(instance_id, finished, reason);
+ ASSERT_EQ(code, MetaServiceCode::OK) << msg;
+ ASSERT_TRUE(finished);
+ ASSERT_TRUE(reason.empty());
+
+ instance.set_recycle_state(
+
InstanceRecycleState::INSTANCE_RECYCLE_STATE_METADATA_CLEANUP_PENDING);
+ ASSERT_EQ(txn_kv->create_txn(&txn), TxnErrorCode::TXN_OK);
+ txn->put(instance_key({instance_id}), instance.SerializeAsString());
+ ASSERT_EQ(txn->commit(), TxnErrorCode::TXN_OK);
+
+ finished = true;
+ reason.clear();
+ std::tie(code, msg) =
+ meta_service.check_instance_recycle_completed(instance_id,
finished, reason);
+ ASSERT_EQ(code, MetaServiceCode::OK) << msg;
+ ASSERT_FALSE(finished);
+ ASSERT_FALSE(reason.empty());
+
+ ASSERT_EQ(txn_kv->create_txn(&txn), TxnErrorCode::TXN_OK);
+ txn->remove(instance_key({instance_id}));
+ ASSERT_EQ(txn->commit(), TxnErrorCode::TXN_OK);
+
+ finished = false;
+ reason.clear();
+ std::tie(code, msg) =
+ meta_service.check_instance_recycle_completed(instance_id,
finished, reason);
+ ASSERT_EQ(code, MetaServiceCode::OK) << msg;
+ ASSERT_TRUE(finished);
+ ASSERT_NE(reason.find("does not exist"), std::string::npos);
+}
+
TEST(MetaServiceTest, CreateInstanceTest) {
auto meta_service = get_meta_service();
diff --git a/cloud/test/recycle_versioned_keys_test.cpp
b/cloud/test/recycle_versioned_keys_test.cpp
index 00b99573fad..1551f895c30 100644
--- a/cloud/test/recycle_versioned_keys_test.cpp
+++ b/cloud/test/recycle_versioned_keys_test.cpp
@@ -1894,8 +1894,17 @@ TEST(RecycleVersionedKeysTest, RecycleDeletedInstance) {
std::string instance_key_st = instance_key(instance_id);
std::string instance_key_ed = instance_key(instance_id + '\x00');
- ASSERT_EQ(count_range(txn_kv.get(), instance_key_st, instance_key_ed),
0)
+ ASSERT_EQ(count_range(txn_kv.get(), instance_key_st, instance_key_ed),
1)
<< dump_range(txn_kv.get());
+ std::unique_ptr<Transaction> instance_txn;
+ ASSERT_EQ(txn_kv->create_txn(&instance_txn), TxnErrorCode::TXN_OK);
+ std::string instance_value;
+ ASSERT_EQ(instance_txn->get(instance_key_st, &instance_value),
TxnErrorCode::TXN_OK);
+ InstanceInfoPB retained_instance;
+ ASSERT_TRUE(retained_instance.ParseFromString(instance_value));
+ ASSERT_EQ(retained_instance.status(), InstanceInfoPB::DELETED);
+ ASSERT_EQ(retained_instance.recycle_state(),
+
InstanceRecycleState::INSTANCE_RECYCLE_STATE_CLEANUP_COMPLETED);
for (int i = 1; i < rowsets.size(); ++i) {
std::unique_ptr<ListIterator> list_iter;
diff --git a/cloud/test/recycler_operation_log_test.cpp
b/cloud/test/recycler_operation_log_test.cpp
index becac15276d..a50ae4894ce 100644
--- a/cloud/test/recycler_operation_log_test.cpp
+++ b/cloud/test/recycler_operation_log_test.cpp
@@ -2582,7 +2582,7 @@ TEST(RecycleOperationLogTest, RecycleDeletedInstance) {
ASSERT_EQ(recycler.recycle_deleted_instance(), 0);
// Verify all data keys are deleted, keeping the instance status and
instance_update keys.
- ASSERT_EQ(count_range(txn_kv.get()), 1) << dump_range(txn_kv.get());
+ ASSERT_EQ(count_range(txn_kv.get()), 2) << dump_range(txn_kv.get());
}
// Test OperationLogRecycleChecker class
diff --git a/cloud/test/recycler_test.cpp b/cloud/test/recycler_test.cpp
index 65316ca06b1..c5a0a150b95 100644
--- a/cloud/test/recycler_test.cpp
+++ b/cloud/test/recycler_test.cpp
@@ -4980,7 +4980,12 @@ TEST(RecyclerTest, recycle_deleted_instance) {
std::unique_ptr<Transaction> txn;
ASSERT_EQ(TxnErrorCode::TXN_OK, txn_kv->create_txn(&txn));
std::string value;
- ASSERT_EQ(TxnErrorCode::TXN_KEY_NOT_FOUND,
txn->get(instance_key({instance_id}), &value));
+ ASSERT_EQ(TxnErrorCode::TXN_OK, txn->get(instance_key({instance_id}),
&value));
+ InstanceInfoPB retained_instance;
+ ASSERT_TRUE(retained_instance.ParseFromString(value));
+ ASSERT_EQ(retained_instance.status(), InstanceInfoPB::DELETED);
+ ASSERT_EQ(retained_instance.recycle_state(),
+
InstanceRecycleState::INSTANCE_RECYCLE_STATE_CLEANUP_COMPLETED);
}
// check if all the objects are deleted
@@ -5045,6 +5050,67 @@ TEST(RecyclerTest, recycle_deleted_instance) {
}
}
+TEST(RecyclerTest, recycle_deleted_instance_metadata_successor_state) {
+ auto run_case = [](const std::string& suffix, bool put_successor,
+ InstanceRecycleState successor_state,
+ InstanceRecycleState expected_predecessor_state,
+ bool successor_has_recycle_state = true) {
+ auto txn_kv = std::make_shared<MemTxnKv>();
+ ASSERT_EQ(txn_kv->init(), 0);
+
+ const std::string predecessor_id = "predecessor_" + suffix;
+ const std::string successor_id = "successor_" + suffix;
+
+ InstanceInfoPB predecessor;
+ predecessor.set_instance_id(predecessor_id);
+ predecessor.set_status(InstanceInfoPB::DELETED);
+ predecessor.set_recycle_state(
+
InstanceRecycleState::INSTANCE_RECYCLE_STATE_METADATA_CLEANUP_PENDING);
+ predecessor.set_successor_instance_id(successor_id);
+ put_instance_info(txn_kv.get(), predecessor);
+
+ if (put_successor) {
+ InstanceInfoPB successor;
+ successor.set_instance_id(successor_id);
+ successor.set_status(InstanceInfoPB::DELETED);
+ if (successor_has_recycle_state) {
+ successor.set_recycle_state(successor_state);
+ }
+ put_instance_info(txn_kv.get(), successor);
+ }
+
+ InstanceRecycler recycler(txn_kv, predecessor, thread_group,
+ std::make_shared<TxnLazyCommitter>(txn_kv));
+ ASSERT_EQ(recycler.recycle_deleted_instance_metadata(), 0);
+
+ std::unique_ptr<Transaction> txn;
+ ASSERT_EQ(txn_kv->create_txn(&txn), TxnErrorCode::TXN_OK);
+ std::string value;
+ ASSERT_EQ(txn->get(instance_key({predecessor_id}), &value),
TxnErrorCode::TXN_OK);
+ ASSERT_TRUE(predecessor.ParseFromString(value));
+ ASSERT_EQ(predecessor.recycle_state(), expected_predecessor_state);
+ if (put_successor) {
+ ASSERT_EQ(txn->get(instance_key({successor_id}), &value),
TxnErrorCode::TXN_OK);
+ InstanceInfoPB successor;
+ ASSERT_TRUE(successor.ParseFromString(value));
+ ASSERT_EQ(successor.has_recycle_state(),
successor_has_recycle_state);
+ }
+ };
+
+ run_case("successor_completed", true,
+ InstanceRecycleState::INSTANCE_RECYCLE_STATE_CLEANUP_COMPLETED,
+ InstanceRecycleState::INSTANCE_RECYCLE_STATE_CLEANUP_COMPLETED);
+ run_case("successor_pending", true,
+
InstanceRecycleState::INSTANCE_RECYCLE_STATE_METADATA_CLEANUP_PENDING,
+
InstanceRecycleState::INSTANCE_RECYCLE_STATE_METADATA_CLEANUP_PENDING);
+ run_case("successor_missing", false,
+
InstanceRecycleState::INSTANCE_RECYCLE_STATE_METADATA_CLEANUP_PENDING,
+ InstanceRecycleState::INSTANCE_RECYCLE_STATE_CLEANUP_COMPLETED);
+ run_case("successor_legacy_without_state", true,
+ InstanceRecycleState::INSTANCE_RECYCLE_STATE_DATA_CLEANUP_PENDING,
+
InstanceRecycleState::INSTANCE_RECYCLE_STATE_METADATA_CLEANUP_PENDING, false);
+}
+
TEST(RecyclerTest, init_deleted_instance_with_terminal_recycle_state) {
auto txn_kv =
std::dynamic_pointer_cast<TxnKv>(std::make_shared<MemTxnKv>());
ASSERT_NE(txn_kv.get(), nullptr);
diff --git a/cloud/test/resource_test.cpp b/cloud/test/resource_test.cpp
index 2c02d9bfccf..a1208dbfbac 100644
--- a/cloud/test/resource_test.cpp
+++ b/cloud/test/resource_test.cpp
@@ -409,6 +409,50 @@ TEST(ResourceTest, RestartResourceManager) {
sp->clear_all_call_backs();
}
+TEST(ResourceTest, RefreshDeletedInstanceClearsRuntimeCaches) {
+ auto txn_kv = create_txn_kv();
+ ResourceManager resource_mgr(txn_kv);
+ ASSERT_EQ(resource_mgr.init(), 0);
+
+ const std::string instance_id = "deleted_cache_instance";
+ const std::string cloud_unique_id = "deleted_cache_cloud_unique_id";
+ InstanceInfoPB instance;
+ instance.set_instance_id(instance_id);
+ instance.set_status(InstanceInfoPB::NORMAL);
+
instance.set_multi_version_status(MultiVersionStatus::MULTI_VERSION_ENABLED);
+ instance.set_source_instance_id("source_instance");
+ instance.set_source_snapshot_id("00000000000000000000");
+ auto* cluster = instance.add_clusters();
+ cluster->set_type(ClusterPB::COMPUTE);
+ cluster->set_cluster_id("cluster_id");
+ cluster->set_cluster_name("cluster_name");
+ auto* node = cluster->add_nodes();
+ node->set_cloud_unique_id(cloud_unique_id);
+ node->set_ip("127.0.0.1");
+ node->set_heartbeat_port(10000);
+
+ resource_mgr.refresh_instance(instance_id, instance);
+
+ std::vector<NodeInfo> nodes;
+ ASSERT_EQ(resource_mgr.get_node(cloud_unique_id, &nodes), "");
+ ASSERT_EQ(nodes.size(), 1);
+ ASSERT_TRUE(resource_mgr.is_version_read_enabled(instance_id));
+ std::string source_instance_id;
+ Versionstamp source_snapshot_version;
+ ASSERT_TRUE(resource_mgr.get_source_snapshot_info(instance_id,
&source_instance_id,
+
&source_snapshot_version));
+
+ instance.set_status(InstanceInfoPB::DELETED);
+ resource_mgr.refresh_instance(instance_id, instance);
+
+ nodes.clear();
+ EXPECT_EQ(resource_mgr.get_node(cloud_unique_id, &nodes), "cloud_unique_id
not found");
+ EXPECT_TRUE(nodes.empty());
+ EXPECT_FALSE(resource_mgr.is_version_read_enabled(instance_id));
+ EXPECT_FALSE(resource_mgr.get_source_snapshot_info(instance_id,
&source_instance_id,
+
&source_snapshot_version));
+}
+
// test add/drop cluster
TEST(ResourceTest, AddDropCluster) {
auto sp = SyncPoint::get_instance();
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]