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


##########
be/src/load/delta_writer/delta_writer.cpp:
##########
@@ -136,7 +142,14 @@ int64_t BaseDeltaWriter::table_id() const {
 
 DeltaWriter::~DeltaWriter() = default;
 
+Status BaseDeltaWriter::_get_load_cancel_status() const {
+    return _req.load_cancel_status && !_req.load_cancel_status->ok()
+                   ? _req.load_cancel_status->status()
+                   : Status::OK();
+}
+
 Status BaseDeltaWriter::init() {
+    RETURN_IF_ERROR(_get_load_cancel_status());

Review Comment:
   [P2] Recheck cancellation inside cloud rowset initialization
   
   This gate only covers entry to init(). With cloud MoW sync enabled by 
default, CloudRowsetBuilder::init() can block in sync_rowsets(); if cancel 
publishes and returns there, the same retained task then creates the writer and 
starts a separate prepare_rowset RPC without rechecking. 
CloudGroupRowsetBuilder can similarly finish the row-binlog child's prepare 
after cancellation and start the data child's sync/prepare. The existing 
post-init writer thread only gates the later memtable call, and the 
empty-rowset thread only gates prepare-to-commit, so neither prevents this 
post-cancel prepare. Existing failure exits already tolerate these partial-init 
states. Consume the copied load status at safe boundaries after sync and before 
prepare, and between group child inits, with barriers asserting no later 
prepare runs after completed cancel.



##########
be/src/load/channel/load_channel.cpp:
##########
@@ -180,6 +183,7 @@ Status 
LoadChannel::_get_tablets_channel(std::shared_ptr<BaseTabletsChannel>& ch
 
 Status LoadChannel::add_batch(const PTabletWriterAddBlockRequest& request,
                               PTabletWriterAddBlockResult* response) {
+    RETURN_IF_ERROR(cancel_status());

Review Comment:
   [P2] Recheck cancellation before acknowledging retained RPC work
   
   This is only an entry gate. An open can pass it and the child gate, then a 
concurrent cancel can remove the manager entry, publish the status, and return 
while child setup is still running; open subsequently sets _opened and returns 
OK. Non-EOS add has the same response-boundary gap, and it is stronger than an 
unavoidable final-sample race: if DeltaWriter::write() returns the shared 
cancellation, _write_block_data() converts it to tablet_errors, advances 
_next_seqs, and returns OK, so the RPC acknowledges a cancellation it actually 
observed. The existing DeltaWriter thread covers pre-operation gates after 
init/backpressure, not this parent conversion/return boundary. Please make the 
successful open/add transition coherent with the shared terminal state, 
preserve an already-observed load-wide cancellation as the RPC result, and add 
barriers proving a completed cancel cannot be followed by an OK open/add 
response.



##########
be/src/load/channel/load_channel_mgr.cpp:
##########
@@ -203,41 +233,47 @@ void LoadChannelMgr::_finish_load_channel(const UniqueId 
load_id) {
 
 Status LoadChannelMgr::cancel(const PTabletWriterCancelRequest& params) {
     UniqueId load_id(params.id());
+    const auto reason = params.has_cancel_reason() && 
!params.cancel_reason().empty()
+                                ? params.cancel_reason()
+                                : "load channel cancelled";
     std::shared_ptr<LoadChannel> cancelled_channel;
     {
         std::lock_guard<std::mutex> l(_lock);
         if (_load_channels.contains(load_id)) {
             cancelled_channel = _load_channels[load_id];
             _load_channels.erase(load_id);
         }
-        // We just need to record the first cancel msg
-        auto* existing_handle = 
_load_state_channels->lookup(load_id.to_string());
-        if (existing_handle == nullptr) {
-            if (params.has_cancel_reason() && !params.cancel_reason().empty()) 
{
-                std::unique_ptr<CacheValue> cancel_reason_ptr = 
std::make_unique<CacheValue>();
-                cancel_reason_ptr->_cancel_reason = params.cancel_reason();
-                size_t cache_capacity =
-                        cancel_reason_ptr->_cancel_reason.capacity() + 
sizeof(CacheValue);
-                auto* handle = _load_state_channels->insert(
-                        load_id.to_string(), cancel_reason_ptr.get(), 1, 
cache_capacity);
-                cancel_reason_ptr.release();
-                _load_state_channels->release(handle);
-                LOG(INFO) << fmt::format("load_id = {}, record_error reason = 
{}",
-                                         print_id(load_id), 
params.cancel_reason());
-            }
-        } else {
-            _load_state_channels->release(existing_handle);
-        }
+        _record_cancelled_load_channel(load_id, reason);

Review Comment:
   [P2] Cache the retained channel's actual first failure
   
   _cancel_load_channel() can publish failure A and pause before _lock. Public 
cancel then wins _lock, erases the same channel, and records reason B here 
before calling cancelled_channel->cancel(B). That later update loses to 
first-wins A; when the failure path resumes it sees the mapping gone and cannot 
repair the cache. Retained operations report A while late open/add reports B, 
so the manager tombstone no longer reflects the first terminal state. This is 
distinct from the existing EOS/replacement thread: exact-instance publication 
has already happened, but public cancel chooses the cache value before 
consulting it. Publish to the captured channel before selecting the cache value 
and store its effective first status while keeping the exact-instance 
transition, with a barrier test for the A-published/B-cancel ordering.



-- 
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