github-actions[bot] commented on code in PR #65330:
URL: https://github.com/apache/doris/pull/65330#discussion_r3628118620


##########
cloud/src/recycler/recycler.cpp:
##########
@@ -1020,33 +1071,79 @@ int InstanceRecycler::recycle_deleted_instance() {
     std::string versioned_log_key_start = 
versioned::log_key_prefix(instance_id_);
     std::string versioned_log_key_end = versioned::log_key_prefix(instance_id_ 
+ '\x00');
     txn->remove(versioned_log_key_start, versioned_log_key_end);
-    err = txn->commit();
+
+    // Updating the recycle state also commits this transaction, making the 
metadata deletions
+    // and state transition atomic.
+    if (update_instance_recycled_state(
+                
InstanceRecycleState::INSTANCE_RECYCLE_STATE_CLEANUP_COMPLETED, txn.get()) != 
0) {
+        return -1;
+    }
+
+    return 0;
+}
+
+int InstanceRecycler::update_instance_recycled_state(InstanceRecycleState 
recycled_state) {
+    std::unique_ptr<Transaction> txn;
+    TxnErrorCode err = txn_kv_->create_txn(&txn);
     if (err != TxnErrorCode::TXN_OK) {
-        LOG(WARNING) << "failed to delete all kv, instance_id=" << 
instance_id_ << ", err=" << err;
-        ret = -1;
+        LOG(WARNING) << "failed to create txn";
+        return -1;
     }
+    return update_instance_recycled_state(recycled_state, txn.get());
+}
 
-    if (ret == 0) {
-        // remove instance kv
-        // ATTN: MUST ensure that cloud platform won't regenerate the same 
instance id
-        err = txn_kv_->create_txn(&txn);
-        if (err != TxnErrorCode::TXN_OK) {
-            LOG(WARNING) << "failed to create txn";
-            ret = -1;
-            return ret;
-        }
-        std::string key;
-        instance_key({instance_id_}, &key);
-        txn->atomic_add(system_meta_service_instance_update_key(), 1);
-        txn->remove(key);
-        err = txn->commit();
-        if (err != TxnErrorCode::TXN_OK) {
-            LOG(WARNING) << "failed to delete instance kv, instance_id=" << 
instance_id_
-                         << " err=" << err;
-            ret = -1;
-        }
+int InstanceRecycler::update_instance_recycled_state(InstanceRecycleState 
recycled_state,
+                                                     Transaction* txn) {
+    std::string key = instance_key({instance_id_});
+    std::string value;
+    TxnErrorCode err = txn->get(key, &value);
+    if (err != TxnErrorCode::TXN_OK) {
+        LOG_WARNING("failed to get instance when updating instance recycled 
state")
+                .tag("instance_id", instance_id_)
+                .tag("recycled_state", 
InstanceRecycleState_Name(recycled_state))
+                .tag("err", err);
+        return -1;
     }
-    return ret;
+
+    InstanceInfoPB instance;
+    if (!instance.ParseFromString(value)) {
+        LOG_WARNING("failed to parse InstanceInfoPB when updating instance 
recycled state")
+                .tag("instance_id", instance_id_)
+                .tag("recycled_state", 
InstanceRecycleState_Name(recycled_state));
+        return -1;
+    }
+    if (instance.status() != InstanceInfoPB::DELETED) {
+        LOG_WARNING("instance is not deleted when updating instance recycled 
state")
+                .tag("instance_id", instance_id_)
+                .tag("status", instance.status())
+                .tag("recycled_state", 
InstanceRecycleState_Name(recycled_state));
+        return -1;
+    }
+
+    instance.set_recycled_state(recycled_state);

Review Comment:
   [P2] Keep recycle progress monotonic after lease takeover. A worker can lose 
its lease while blocked in the final accessor's `delete_all()`; 
`lease_recycle_jobs()` marks it stopped, but this path does not recheck 
`stopped()` after `delete_all()` and opens this transaction afterward. If the 
new owner has already committed `CLEANUP_COMPLETED`, this fresh read sees that 
terminal PB and this assignment writes it back to `DATA_CLEANUP_COMPLETED`, so 
FDB has no overlapping conflict to reject it and `check_instance_recycled` can 
flip back to false. Require the expected old phase (`pending -> data complete`, 
`data complete -> complete`), treating an equal/later persisted state 
idempotently, and add a paused-old-worker/lease-takeover test.



##########
cloud/src/common/http_helper.cpp:
##########
@@ -424,6 +430,12 @@ const std::unordered_map<std::string_view, 
HttpHandlerInfo>& get_http_handlers()
                  {.handler = [](void* s,
                                 brpc::Controller* c) { return 
process_update_config((MS*)s, c); },
                   .role = HttpRole::BOTH}},
+                {"check_instance_recycled",
+                 {.handler =
+                          [](void* s, brpc::Controller* c) {
+                              return process_check_instance_recycled((RS*)s, 
c);

Review Comment:
   [P1] Do not dispatch this BOTH route through `RecyclerServiceImpl`. 
`MetaServiceImpl::http` accepts `HttpRole::BOTH` and passes a 
`MetaServiceImpl*` here, but this lambda casts it to the unrelated 
`RecyclerServiceImpl*`; `check_instance_recycled()` immediately reads that 
class's `txn_kv_`. The coincidentally similar first-member layout does not make 
this a valid C++ object and can trap under CFI or read the wrong member after a 
layout change. Use role-specific typed dispatchers/a common `TxnKv` helper (or 
restrict the route) and exercise both service endpoints.



##########
cloud/src/resource-manager/resource_manager.cpp:
##########
@@ -1429,6 +1432,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);

Review Comment:
   [P1] Preserve the clone source mapping until in-flight lazy commits finish. 
DROP can mark rollback successor B deleted while an eventually committed txn is 
already queued. That task retains `txn_info.versioned_read` and later builds 
`CloneChainReader(B, shared ResourceManager)`; for an inherited tablet absent 
from B it must follow B -> A@S. This erase can race the task, making the 
fallback return `KEY_NOT_FOUND` even though A's metadata is deliberately 
retained until B completes, leaving the committed txn non-visible. Drain/cancel 
those tasks explicitly or snapshot/retain the source mapping until they finish, 
with a paused lazy-commit/drop test.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


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

Reply via email to