This is an automated email from the ASF dual-hosted git repository.

w41ter 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 2b5ae860762 [feat](cloud) implement decouple_instance (#61221)
2b5ae860762 is described below

commit 2b5ae8607627778d0feaa7233b0c96fe93a6c58d
Author: walter <[email protected]>
AuthorDate: Thu Mar 12 15:25:18 2026 +0800

    [feat](cloud) implement decouple_instance (#61221)
    
    When an instance is cloned via clone_instance, it maintains references
    to the source instance and snapshot. After snapshot compaction
    completes, these references can be safely removed to decouple the cloned
    instance, making it fully independent.
    
    Usage Example:
    
    ```
    curl -X POST 
"http://ms_host:port/decouple_instance?instance_id=my_cloned_instance&token=xxx";
    ```
    
    Requirements:
      - instance_id: The ID of the cloned instance to decouple
      - The instance must have been created via clone_instance
      - The instance's snapshot_compact_status must be SNAPSHOT_COMPACT_DONE
---
 cloud/src/meta-service/meta_service_http.cpp | 12 ++++
 cloud/src/snapshot/snapshot_manager.cpp      | 93 ++++++++++++++++++++++++++++
 cloud/src/snapshot/snapshot_manager.h        |  8 +++
 3 files changed, 113 insertions(+)

diff --git a/cloud/src/meta-service/meta_service_http.cpp 
b/cloud/src/meta-service/meta_service_http.cpp
index b6e213dead6..29b4b9287ad 100644
--- a/cloud/src/meta-service/meta_service_http.cpp
+++ b/cloud/src/meta-service/meta_service_http.cpp
@@ -715,6 +715,16 @@ static HttpResponse 
process_compact_snapshot(MetaServiceImpl* service, brpc::Con
     return http_json_reply(resp.status());
 }
 
+static HttpResponse process_decouple_instance(MetaServiceImpl* service, 
brpc::Controller* ctrl) {
+    auto& uri = ctrl->http_request().uri();
+    std::string instance_id(http_query(uri, "instance_id"));
+    if (instance_id.empty()) {
+        return http_json_reply(MetaServiceCode::INVALID_ARGUMENT, "instance_id 
is empty");
+    }
+    auto [code, msg] = 
service->snapshot_manager()->decouple_instance(instance_id);
+    return http_json_reply(code, msg);
+}
+
 static HttpResponse process_set_snapshot_property(MetaServiceImpl* service,
                                                   brpc::Controller* ctrl) {
     AlterInstanceRequest req;
@@ -955,6 +965,8 @@ void 
MetaServiceImpl::http(::google::protobuf::RpcController* controller,
             {"v1/set_multi_version_status", process_set_multi_version_status},
             {"compact_snapshot", process_compact_snapshot},
             {"v1/compact_snapshot", process_compact_snapshot},
+            {"decouple_instance", process_decouple_instance},
+            {"v1/decouple_instance", process_decouple_instance},
             // misc
             {"abort_txn", process_abort_txn},
             {"abort_tablet_job", process_abort_tablet_job},
diff --git a/cloud/src/snapshot/snapshot_manager.cpp 
b/cloud/src/snapshot/snapshot_manager.cpp
index 94d1f4f9c6d..ac2b9e22d44 100644
--- a/cloud/src/snapshot/snapshot_manager.cpp
+++ b/cloud/src/snapshot/snapshot_manager.cpp
@@ -17,6 +17,10 @@
 
 #include "snapshot/snapshot_manager.h"
 
+#include <fmt/format.h>
+
+#include "common/logging.h"
+#include "meta-store/keys.h"
 #include "meta-store/versionstamp.h"
 #include "recycler/checker.h"
 #include "recycler/recycler.h"
@@ -122,6 +126,95 @@ std::pair<MetaServiceCode, std::string> 
SnapshotManager::compact_snapshot(
     return {MetaServiceCode::UNDEFINED_ERR, "Not implemented"};
 }
 
+std::pair<MetaServiceCode, std::string> 
SnapshotManager::decouple_instance(std::string_view id) {
+    std::string instance_id(id);
+    LOG_INFO("decouple_instance").tag("instance_id", instance_id);
+
+    // 1. Create transaction and get current instance info
+    std::unique_ptr<Transaction> txn;
+    TxnErrorCode err = txn_kv_->create_txn(&txn);
+    if (err != TxnErrorCode::TXN_OK) {
+        return {MetaServiceCode::KV_TXN_CREATE_ERR, "failed to create txn"};
+    }
+
+    std::string key = instance_key({instance_id});
+    std::string value;
+    err = txn->get(key, &value);
+    if (err == TxnErrorCode::TXN_KEY_NOT_FOUND) {
+        return {MetaServiceCode::CLUSTER_NOT_FOUND,
+                fmt::format("instance not found, instance_id={}", 
instance_id)};
+    } else if (err != TxnErrorCode::TXN_OK) {
+        return {MetaServiceCode::KV_TXN_GET_ERR,
+                fmt::format("failed to get instance info, instance_id={}, 
err={}", instance_id,
+                            err)};
+    }
+
+    InstanceInfoPB instance;
+    if (!instance.ParseFromString(value)) {
+        return {MetaServiceCode::PROTOBUF_PARSE_ERR, "failed to parse instance 
info"};
+    }
+
+    // 2. Check the instance was created via clone_instance
+    if (!instance.has_source_instance_id() || 
instance.source_instance_id().empty() ||
+        !instance.has_source_snapshot_id() || 
instance.source_snapshot_id().empty()) {
+        return {MetaServiceCode::INVALID_ARGUMENT,
+                fmt::format("instance {} was not a cloned instance (created 
via clone_instance)",
+                            instance_id)};
+    }
+
+    // 3. Check snapshot_compact_status is SNAPSHOT_COMPACT_DONE
+    if (instance.snapshot_compact_status() != 
SnapshotCompactStatus::SNAPSHOT_COMPACT_DONE) {
+        return {MetaServiceCode::INVALID_ARGUMENT,
+                fmt::format("instance {} snapshot_compact_status is not 
SNAPSHOT_COMPACT_DONE, "
+                            "current status={}",
+                            instance_id,
+                            
SnapshotCompactStatus_Name(instance.snapshot_compact_status()))};
+    }
+
+    // 4. Remove the snapshot reference key in the source instance
+    const std::string& source_instance_id = instance.source_instance_id();
+    const std::string& source_snapshot_id = instance.source_snapshot_id();
+
+    Versionstamp snapshot_versionstamp;
+    if (!parse_snapshot_versionstamp(source_snapshot_id, 
&snapshot_versionstamp)) {
+        return {MetaServiceCode::UNDEFINED_ERR,
+                fmt::format("failed to parse source_snapshot_id={} to 
versionstamp",
+                            source_snapshot_id)};
+    }
+
+    versioned::SnapshotReferenceKeyInfo ref_key_info {source_instance_id, 
snapshot_versionstamp,
+                                                      instance_id};
+    std::string reference_key = 
versioned::snapshot_reference_key(ref_key_info);
+    txn->remove(reference_key);
+
+    // 5. Clear source_snapshot_id and source_instance_id from the instance PB
+    instance.clear_source_snapshot_id();
+    instance.clear_source_instance_id();
+
+    // 6. Persist the updated instance
+    std::string updated_val;
+    if (!instance.SerializeToString(&updated_val)) {
+        return {MetaServiceCode::PROTOBUF_SERIALIZE_ERR,
+                fmt::format("failed to serialize updated instance, 
instance_id={}", instance_id)};
+    }
+
+    txn->atomic_add(system_meta_service_instance_update_key(), 1);
+    txn->put(key, updated_val);
+
+    err = txn->commit();
+    if (err != TxnErrorCode::TXN_OK) {
+        return {MetaServiceCode::KV_TXN_COMMIT_ERR,
+                fmt::format("failed to commit txn, instance_id={}, err={}", 
instance_id, err)};
+    }
+
+    LOG_INFO("decouple_instance completed successfully")
+            .tag("instance_id", instance_id)
+            .tag("source_instance_id", source_instance_id)
+            .tag("source_snapshot_id", source_snapshot_id);
+
+    return {MetaServiceCode::OK, ""};
+}
+
 std::pair<MetaServiceCode, std::string> 
SnapshotManager::set_multi_version_status(
         std::string_view instance_id, MultiVersionStatus multi_version_status) 
{
     return {MetaServiceCode::UNDEFINED_ERR, "Not implemented"};
diff --git a/cloud/src/snapshot/snapshot_manager.h 
b/cloud/src/snapshot/snapshot_manager.h
index 0e7ad2c12a3..29e8771c8c4 100644
--- a/cloud/src/snapshot/snapshot_manager.h
+++ b/cloud/src/snapshot/snapshot_manager.h
@@ -55,6 +55,14 @@ public:
     // Manually trigger snapshot compact for an instance.
     virtual std::pair<MetaServiceCode, std::string> 
compact_snapshot(std::string_view instance_id);
 
+    // Decouple a cloned instance from its source snapshot.
+    //
+    // It removes the snapshot reference key in the source instance, and clears
+    // source_snapshot_id and source_instance_id from the cloned instance PB.
+    // The instance must have been created via clone_instance, and its 
snapshot_compact_status
+    // must be SNAPSHOT_COMPACT_DONE.
+    std::pair<MetaServiceCode, std::string> decouple_instance(std::string_view 
instance_id);
+
     virtual std::pair<MetaServiceCode, std::string> set_multi_version_status(
             std::string_view instance_id, MultiVersionStatus 
multi_version_status);
 


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to